Example #1
0
    def _delete_nodes(self, cluster, nodes, policy_data):
        action_name = consts.NODE_DELETE

        pd = policy_data.get('deletion', None)
        if pd is not None:
            destroy = pd.get('destroy_after_delete', True)
            if not destroy:
                action_name = consts.NODE_LEAVE

        for node_id in nodes:
            action = base.Action(self.context, action_name,
                                 name='node_delete_%s' % node_id[:8],
                                 target=node_id,
                                 cause=base.CAUSE_DERIVED)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(self.READY)

            dispatcher.notify(self.context, dispatcher.Dispatcher.NEW_ACTION,
                              None, action_id=action.id)

        if len(nodes) > 0:
            return self._wait_for_dependents()

        return self.RES_OK, ''
Example #2
0
    def _create_nodes(self, cluster, count, policy_data):
        '''Utility method for node creation.'''
        placement = policy_data.get('placement', None)

        for m in range(count):
            name = 'node-%s-%003d' % (cluster.id[:8], cluster.size + m + 1)
            node = node_mod.Node(name, cluster.profile_id, cluster.id,
                                 context=self.context)

            if placement is not None:
                # We assume placement is a list
                node.data['placement'] = placement[m]
            node.store(self.context)

            kwargs = {
                'name': 'node_create_%s' % node.id[:8],
                'target': node.id,
                'cause': base.CAUSE_DERIVED,
            }

            action = base.Action(self.context, 'NODE_CREATE', **kwargs)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(self.READY)

            dispatcher.notify(self.context, dispatcher.Dispatcher.NEW_ACTION,
                              None, action_id=action.id)

        if count > 0:
            # Wait for cluster creation to complete
            return self._wait_for_dependents()

        return self.RES_OK, ''
Example #3
0
    def do_add_nodes(self):
        """Handler for the CLUSTER_ADD_NODES action.

        :returns: A tuple containing the result and the corresponding reason.
        """
        node_ids = self.inputs.get('nodes')
        # TODO(anyone): handle placement data

        errors = []
        nodes = []
        for node_id in node_ids:
            try:
                node = node_mod.Node.load(self.context, node_id)
            except exception.NodeNotFound:
                errors.append(_('Node [%s] is not found.') % node_id)
                continue
            if node.cluster_id is not None:
                errors.append(_('Node [%(n)s] is already owned by cluster '
                                '[%(c)s].') % {'n': node_id,
                                               'c': node.cluster_id})
                continue
            if node.status != node.ACTIVE:
                errors.append(_('Node [%s] is not in ACTIVE status.'
                                ) % node_id)
                continue
            nodes.append(node)

        if len(errors) > 0:
            return self.RES_ERROR, ''.join(errors)

        reason = _('Completed adding nodes.')

        for node in nodes:
            kwargs = {
                'name': 'node_join_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'inputs': {'cluster_id': self.target},
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }
            action = base.Action(node.id, 'NODE_JOIN', **kwargs)
            action.store(self.context)
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(self.READY)
            dispatcher.start_action(action_id=action.id)

        # Wait for dependent action if any
        result, new_reason = self._wait_for_dependents()
        if result != self.RES_OK:
            reason = new_reason
        else:
            self.outputs['nodes_added'] = [node.id for node in nodes]
            for node in nodes:
                self.cluster.add_node(node)

        return result, reason
Example #4
0
    def do_add_nodes(self, cluster, policy_data):
        nodes = self.inputs.get('nodes')

        # NOTE: node states might have changed before we lock the cluster
        failures = {}
        for node_id in nodes:
            try:
                node = node_mod.Node.load(self.context, node_id)
            except exception.NodeNotFound:
                failures[node_id] = 'Node not found'
                continue

            if node.cluster_id == cluster.id:
                nodes.remove(node_id)
                continue

            if node.cluster_id is not None:
                failures[node_id] = _('Node already owned by cluster '
                                      '%s') % node.cluster_id
                continue
            if node.status != node_mod.Node.ACTIVE:
                failures[node_id] = _('Node not in ACTIVE status')
                continue

            # check profile type matching
            node_profile_type = node.rt['profile'].type
            cluster_profile_type = cluster.rt['profile'].type
            if node_profile_type != cluster_profile_type:
                failures[node.id] = 'Profile type does not match'
                continue

        if len(failures) > 0:
            return self.RES_ERROR, str(failures)

        reason = 'Completed adding nodes'
        if len(nodes) == 0:
            return self.RES_OK, reason

        for node_id in nodes:
            action = base.Action(self.context, 'NODE_JOIN',
                                 name='node_join_%s' % node.id[:8],
                                 target=node.id,
                                 cause=base.CAUSE_DERIVED,
                                 inputs={'cluster_id': cluster.id})
            action.store(self.context)
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(self.READY)
            dispatcher.notify(self.context, dispatcher.Dispatcher.NEW_ACTION,
                              None, action_id=action.id)

        # Wait for dependent action if any
        result, new_reason = self._wait_for_dependents()
        if result != self.RES_OK:
            reason = new_reason
        return result, reason
Example #5
0
    def do_update(self):
        """Handler for CLUSTER_UPDATE action.

        :returns: A tuple consisting the result and the corresponding reason.
        """
        res = self.cluster.do_update(self.context)
        if not res:
            reason = _('Cluster update failed.')
            self.cluster.set_status(self.context, self.cluster.ERROR, reason)
            return self.RES_ERROR, reason

        profile_id = self.inputs.get('new_profile_id')

        for node in self.cluster.nodes:
            kwargs = {
                'name': 'node_update_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'inputs': {
                    'new_profile_id': profile_id,
                },
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }
            action = base.Action(node.id, 'NODE_UPDATE', **kwargs)
            action.store(self.context)

            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)
            dispatcher.start_action(action_id=action.id)

        # Wait for nodes to complete update
        if len(self.cluster.nodes) > 0:
            result, new_reason = self._wait_for_dependents()

            if result != self.RES_OK:
                self.cluster.set_status(self.context, self.cluster.WARNING,
                                        new_reason)
                return result, new_reason

        reason = _('Cluster update completed.')
        self.cluster.set_status(self.context,
                                self.cluster.ACTIVE,
                                reason,
                                profile_id=profile_id)
        return self.RES_OK, reason
Example #6
0
    def do_update(self):
        """Handler for CLUSTER_UPDATE action.

        :returns: A tuple consisting the result and the corresponding reason.
        """
        res = self.cluster.do_update(self.context)
        if not res:
            reason = _('Cluster update failed.')
            self.cluster.set_status(self.context, self.cluster.ERROR, reason)
            return self.RES_ERROR, reason

        profile_id = self.inputs.get('new_profile_id')

        for node in self.cluster.nodes:
            kwargs = {
                'name': 'node_update_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'inputs': {
                    'new_profile_id': profile_id,
                },
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }
            action = base.Action(node.id, 'NODE_UPDATE', **kwargs)
            action.store(self.context)

            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)
            dispatcher.start_action(action_id=action.id)

        # Wait for nodes to complete update
        if len(self.cluster.nodes) > 0:
            result, new_reason = self._wait_for_dependents()

            if result != self.RES_OK:
                self.cluster.set_status(self.context, self.cluster.WARNING,
                                        new_reason)
                return result, new_reason

        reason = _('Cluster update completed.')
        self.cluster.set_status(self.context, self.cluster.ACTIVE, reason,
                                profile_id=profile_id)
        return self.RES_OK, reason
Example #7
0
    def do_update(self, cluster, policy_data):
        reason = 'Cluster update succeeded'
        new_profile_id = self.inputs.get('new_profile_id')
        res = cluster.do_update(self.context, profile_id=new_profile_id)
        if not res:
            reason = 'Cluster object cannot be updated.'
            # Reset status to active
            cluster.set_status(cluster.ACTIVE, reason)
            return self.RES_ERROR

        # Create NodeActions for all nodes
        node_list = cluster.get_nodes()
        for node_id in node_list:
            kwargs = {
                'name': 'node_update_%s' % node_id[:8],
                'target': node_id,
                'cause': base.CAUSE_DERIVED,
                'inputs': {
                    'new_profile_id': new_profile_id,
                }
            }
            action = base.Action(self.context, 'NODE_UPDATE', **kwargs)
            action.store(self.context)

            db_api.action_add_dependency(action, self)
            action.set_status(self.READY)
            dispatcher.notify(self.context, dispatcher.Dispatcher.NEW_ACTION,
                              None, action_id=action.id)

        # Wait for cluster updating complete
        result = self.RES_OK
        if cluster.size > 0:
            result, reason = self._wait_for_dependents()

        if result == self.RES_OK:
            cluster.set_status(self.context, cluster.ACTIVE, reason)

        return result, reason
Example #8
0
    def _delete_nodes(self, nodes):
        action_name = consts.NODE_DELETE

        pd = self.data.get('deletion', None)
        if pd is not None:
            destroy = pd.get('destroy_after_delete', True)
            if not destroy:
                action_name = consts.NODE_LEAVE

        for node_id in nodes:
            kwargs = {
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
                'name': 'node_delete_%s' % node_id[:8],
                'cause': base.CAUSE_DERIVED
            }
            action = base.Action(node_id, action_name, **kwargs)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)

            dispatcher.start_action(action_id=action.id)

        if len(nodes) > 0:
            res, reason = self._wait_for_dependents()
            if res == self.RES_OK:
                # TODO(anyone): avoid passing nodes in this way.
                self.data['nodes'] = nodes
                for node_id in nodes:
                    self.cluster.remove_node(node_id)

            return res, reason

        return self.RES_OK, ''
Example #9
0
    def do_update(self):
        profile_id = self.inputs.get('new_profile_id')

        for node in self.cluster.nodes:
            kwargs = {
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
                'name': 'node_update_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'inputs': {
                    'new_profile_id': profile_id,
                }
            }
            action = base.Action(node.id, 'NODE_UPDATE', **kwargs)
            action.store(self.context)

            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)
            dispatcher.start_action(action_id=action.id)

        # Wait for nodes to complete update
        result = self.RES_OK
        reason = _('Cluster update completed.')
        if len(self.cluster.nodes) > 0:
            result, new_reason = self._wait_for_dependents()

            if result != self.RES_OK:
                return result, new_reason

        # TODO(anyone): this seems an overhead
        self.cluster.profile_id = profile_id
        self.cluster.store(self.context)

        self.cluster.set_status(self.context, self.cluster.ACTIVE, reason)
        return self.RES_OK, reason
Example #10
0
    def _delete_nodes(self, node_ids):
        action_name = consts.NODE_DELETE

        pd = self.data.get('deletion', None)
        if pd is not None:
            destroy = pd.get('destroy_after_delete', True)
            if not destroy:
                action_name = consts.NODE_LEAVE

        for node_id in node_ids:
            kwargs = {
                'name': 'node_delete_%s' % node_id[:8],
                'cause': base.CAUSE_DERIVED,
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }
            action = base.Action(node_id, action_name, **kwargs)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)

            dispatcher.start_action(action_id=action.id)

        if len(node_ids) > 0:
            res, reason = self._wait_for_dependents()
            if res == self.RES_OK:
                self.outputs['nodes_removed'] = node_ids
                for node_id in node_ids:
                    self.cluster.remove_node(node_id)

            return res, reason

        return self.RES_OK, ''
Example #11
0
    def _create_nodes(self, count):
        """Utility method for node creation.

        :param count: Number of nodes to create.
        :returns: A tuple comprised of the result and reason.
        """

        if count == 0:
            return self.RES_OK, ''

        placement = self.data.get('placement', None)

        nodes = []
        for m in range(count):
            index = db_api.cluster_next_index(self.context, self.cluster.id)
            kwargs = {
                'index': index,
                'metadata': {},
                'user': self.cluster.user,
                'project': self.cluster.project,
                'domain': self.cluster.domain,
            }
            if placement is not None:
                # We assume placement is a list
                kwargs['data'] = {'placement': placement[m]}

            name = 'node-%s-%003d' % (self.cluster.id[:8], index)
            node = node_mod.Node(name, self.cluster.profile_id,
                                 self.cluster.id, context=self.context,
                                 **kwargs)
            node.store(self.context)
            nodes.append(node)

            kwargs = {
                'name': 'node_create_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }

            action = base.Action(node.id, 'NODE_CREATE', **kwargs)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)

            dispatcher.start_action(action_id=action.id)

        if count > 0:
            # Wait for cluster creation to complete
            res, reason = self._wait_for_dependents()
            if res == self.RES_OK:
                self.outputs['nodes_added'] = [n.id for n in nodes]
                for node in nodes:
                    self.cluster.add_node(node)

            return res, reason

        return self.RES_OK, ''
Example #12
0
    def do_add_nodes(self):
        """Handler for the CLUSTER_ADD_NODES action.

        :returns: A tuple containing the result and the corresponding reason.
        """
        node_ids = self.inputs.get('nodes')
        # TODO(anyone): handle placement data

        errors = []
        nodes = []
        for node_id in node_ids:
            try:
                node = node_mod.Node.load(self.context, node_id)
            except exception.NodeNotFound:
                errors.append(_('Node [%s] is not found.') % node_id)
                continue

            if node.cluster_id == self.cluster.id:
                node_ids.remove(node_id)
                continue

            if node.cluster_id is not None:
                errors.append(
                    _('Node [%(n)s] is already owned by cluster '
                      '[%(c)s].') % {
                          'n': node_id,
                          'c': node.cluster_id
                      })
                continue
            if node.status != node.ACTIVE:
                errors.append(
                    _('Node [%s] is not in ACTIVE status.') % node_id)
                continue
            nodes.append(node)

        if len(errors) > 0:
            return self.RES_ERROR, ''.join(errors)

        reason = _('Completed adding nodes.')
        if len(node_ids) == 0:
            return self.RES_OK, reason

        for node_id in node_ids:
            kwargs = {
                'name': 'node_join_%s' % node_id[:8],
                'cause': base.CAUSE_DERIVED,
                'inputs': {
                    'cluster_id': self.target
                },
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }
            action = base.Action(node_id, 'NODE_JOIN', **kwargs)
            action.store(self.context)
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(self.READY)
            dispatcher.start_action(action_id=action.id)

        # Wait for dependent action if any
        result, new_reason = self._wait_for_dependents()
        if result != self.RES_OK:
            reason = new_reason
        else:
            self.outputs['nodes_added'] = node_ids
            for node in nodes:
                self.cluster.add_node(node)

        return result, reason
Example #13
0
    def _create_nodes(self, count):
        """Utility method for node creation.

        :param count: Number of nodes to create.
        :returns: A tuple comprised of the result and reason.
        """

        if count == 0:
            return self.RES_OK, ''

        placement = self.data.get('placement', None)

        nodes = []
        for m in range(count):
            index = db_api.cluster_next_index(self.context, self.cluster.id)
            kwargs = {
                'index': index,
                'metadata': {},
                'user': self.cluster.user,
                'project': self.cluster.project,
                'domain': self.cluster.domain,
            }
            if placement is not None:
                # We assume placement is a list
                kwargs['data'] = {'placement': placement[m]}

            name = 'node-%s-%003d' % (self.cluster.id[:8], index)
            node = node_mod.Node(name,
                                 self.cluster.profile_id,
                                 self.cluster.id,
                                 context=self.context,
                                 **kwargs)
            node.store(self.context)
            nodes.append(node)

            kwargs = {
                'name': 'node_create_%s' % node.id[:8],
                'cause': base.CAUSE_DERIVED,
                'user': self.context.user,
                'project': self.context.project,
                'domain': self.context.domain,
            }

            action = base.Action(node.id, 'NODE_CREATE', **kwargs)
            action.store(self.context)

            # Build dependency and make the new action ready
            db_api.action_add_dependency(self.context, action.id, self.id)
            action.set_status(action.READY)

            dispatcher.start_action(action_id=action.id)

        if count > 0:
            # Wait for cluster creation to complete
            res, reason = self._wait_for_dependents()
            if res == self.RES_OK:
                self.outputs['nodes_added'] = [n.id for n in nodes]
                for node in nodes:
                    self.cluster.add_node(node)

            return res, reason

        return self.RES_OK, ''