def test_cluster_status_bad_status(self): with self.assertRaises(Exception): self.assertTrue(ClusterStatus.valid("foo", ClusterStatus.LAUNCHING)) with self.assertRaises(Exception): self.assertTrue(ClusterStatus.valid(ClusterStatus.LAUNCHING, "foo"))
def test_cluster_status_transition(self): self.assertTrue( ClusterStatus.valid_transition(ClusterStatus.CREATED, ClusterStatus.LAUNCHING)) self.assertFalse( ClusterStatus.valid_transition(ClusterStatus.ERROR, ClusterStatus.CREATED))
def provision(self, cluster, params): if not ClusterStatus.valid_transition(cluster['status'], ClusterStatus.PROVISIONING): raise RestException( 'Cluster status is %s and cannot be provisioned' % cluster['status'], code=400) body = self._get_body() provision_ssh_user = get_property('ssh.user', body) if provision_ssh_user: cluster['config'].setdefault('provision', {})['ssh'] = { 'user': provision_ssh_user } del body['ssh'] if 'spec' in body: cluster['config'].setdefault('provision', {})['spec'] \ = body['spec'] del body['spec'] cluster['config'].setdefault('provision', {})\ .setdefault('params', {}).update(body) cluster = self._model.save(cluster) return self._model.filter( self._launch_or_provision('provision', cluster), self.getCurrentUser())
def provision(self, cluster, params): if not ClusterStatus.valid_transition( cluster['status'], ClusterStatus.PROVISIONING): raise RestException( 'Cluster status is %s and cannot be provisioned' % cluster['status'], code=400) body = self._get_body() provision_ssh_user = get_property('ssh.user', body) if provision_ssh_user: cluster['config'].setdefault('provision', {})['ssh'] = { 'user': provision_ssh_user } del body['ssh'] if 'spec' in body: cluster['config'].setdefault('provision', {})['spec'] \ = body['spec'] del body['spec'] cluster['config'].setdefault('provision', {})\ .setdefault('params', {}).update(body) cluster = self._model.save(cluster) return self._model.filter( self._launch_or_provision('provision', cluster), self.getCurrentUser())
def update(self, id, params): body = getBodyJson() user = self.getCurrentUser() cluster = self._model.load(id, user=user, level=AccessType.WRITE) if not cluster: raise RestException('Cluster not found.', code=404) if 'assetstoreId' in body: cluster['assetstoreId'] = body['assetstoreId'] if 'status' in body: if ClusterStatus.valid(body['status']): cluster['status'] = body['status'] else: raise RestException('%s is not a valid cluster status' % body['status'], code=400) if 'timings' in body: if 'timings' in cluster: cluster['timings'].update(body['timings']) else: cluster['timings'] = body['timings'] if 'config' in body: # Need to check we aren't try to update immutable fields immutable_paths = ['_id', 'ssh.user'] for path in immutable_paths: if parse(path).find(body['config']): raise RestException("The '%s' field can't be updated" % path) update_dict(cluster['config'], body['config']) cluster = self._model.update_cluster(user, cluster) # Now do any updates the adapter provides adapter = get_cluster_adapter(cluster) try: adapter.update(body) # Skip adapter.update if update not defined for this adapter except (NotImplementedError, ValidationException): pass return self._model.filter(cluster, user)
def test_cluster_status_transition(self): self.assertTrue(ClusterStatus.valid_transition(ClusterStatus.CREATED, ClusterStatus.LAUNCHING)) self.assertFalse(ClusterStatus.valid_transition(ClusterStatus.ERROR, ClusterStatus.CREATED))
def test_cluster_status(self): self.assertTrue(ClusterStatus.valid(ClusterStatus.CREATED)) self.assertFalse(ClusterStatus.valid("foo"))
def __init__(self, cluster): self.cluster = cluster self._state_machine = ClusterStatus(self) self._model = self.model('cluster', 'cumulus')
class AbstractClusterAdapter(ModelImporter): """ This defines the interface to be used by all cluster adapters. """ def __init__(self, cluster): self.cluster = cluster self._state_machine = ClusterStatus(self) self._model = self.model('cluster', 'cumulus') @property def status(self): return self._state_machine.status @status.setter def status(self, status): self._state_machine.to( status, RestException( 'Cluster is in state %s and cannot transition to state %s' % (self._state_machine.status, status), code=400)) self._model.update_status(self.cluster['_id'], status) def validate(self): """ Adapters may implement this if they need to perform any validation steps whenever the cluster info is saved to the database. It should return the document with any necessary alterations in the success case, or throw an exception if validation fails. """ return self.cluster def start(self, request_body): """ Adapters may implement this if they support a start operation. """ raise ValidationException( 'This cluster type does not support a start operation') def terminate(self): """ Adapters may implement this if they support a terminate operation. """ raise ValidationException( 'This cluster type does not support a terminate operation') def update(self, request_body): """ Adapters may implement this if they support a update operation. """ raise ValidationException( 'This cluster type does not support a update operation') def delete(self): """ Adapters may implement this if they support a delete operation. """ # If an assetstore was created for this cluster then try to remove it if 'assetstoreId' in self.cluster: try: assetstore = self.model('assetstore').load( self.cluster['assetstoreId']) self.model('assetstore').remove(assetstore) except ValidationException: # If we still have files associated with the assetstore then # leave it. pass def submit_job(self, job): log_url = '%s/jobs/%s/log' % (cumulus.config.girder.baseUrl, job['_id']) girder_token = get_task_token()['_id'] cumulus.tasks.job.submit( girder_token, self._model.filter(self.cluster, getCurrentUser(), passphrase=False), job, log_url)
class AbstractClusterAdapter(ModelImporter): """ This defines the interface to be used by all cluster adapters. """ def __init__(self, cluster): self.cluster = cluster self._state_machine = ClusterStatus(self) self._model = self.model('cluster', 'cumulus') @property def status(self): return self._state_machine.status @status.setter def status(self, status): self._state_machine.to( status, RestException( 'Cluster is in state %s and cannot transition to state %s' % (self._state_machine.status, status), code=400)) self._model.update_status(self.cluster['_id'], status) def validate(self): """ Adapters may implement this if they need to perform any validation steps whenever the cluster info is saved to the database. It should return the document with any necessary alterations in the success case, or throw an exception if validation fails. """ return self.cluster def start(self, request_body): """ Adapters may implement this if they support a start operation. """ raise ValidationException( 'This cluster type does not support a start operation') def terminate(self): """ Adapters may implement this if they support a terminate operation. """ raise ValidationException( 'This cluster type does not support a terminate operation') def update(self, request_body): """ Adapters may implement this if they support a update operation. """ raise ValidationException( 'This cluster type does not support a update operation') def delete(self): """ Adapters may implement this if they support a delete operation. """ # If an assetstore was created for this cluster then try to remove it if 'assetstoreId' in self.cluster: try: assetstore = self.model('assetstore').load( self.cluster['assetstoreId']) self.model('assetstore').remove(assetstore) except ValidationException: # If we still have files associated with the assetstore then # leave it. pass def submit_job(self, job): log_url = '%s/jobs/%s/log' % (getApiUrl(), job['_id']) girder_token = get_task_token()['_id'] cumulus.tasks.job.submit( girder_token, self._model.filter(self.cluster, getCurrentUser(), passphrase=False), job, log_url)