Example #1
0
    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"))
Example #2
0
    def test_cluster_status_transition(self):
        self.assertTrue(
            ClusterStatus.valid_transition(ClusterStatus.CREATED,
                                           ClusterStatus.LAUNCHING))

        self.assertFalse(
            ClusterStatus.valid_transition(ClusterStatus.ERROR,
                                           ClusterStatus.CREATED))
Example #3
0
    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())
Example #4
0
    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())
Example #5
0
    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)
Example #6
0
    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)
Example #7
0
    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"))
Example #8
0
    def test_cluster_status_transition(self):
        self.assertTrue(ClusterStatus.valid_transition(ClusterStatus.CREATED,
                                                       ClusterStatus.LAUNCHING))

        self.assertFalse(ClusterStatus.valid_transition(ClusterStatus.ERROR,
                                                        ClusterStatus.CREATED))
Example #9
0
    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)
Example #12
0
 def __init__(self, cluster):
     self.cluster = cluster
     self._state_machine = ClusterStatus(self)
     self._model = self.model('cluster', 'cumulus')
Example #13
0
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)