示例#1
0
    def patch(self, audit, patch):
        """Update an existing audit.

        :param audit: UUID or name of an audit.
        :param patch: a json PATCH document to apply to this audit.
        """
        if self.from_audits:
            raise exception.OperationNotPermitted

        context = pecan.request.context
        audit_to_update = api_utils.get_resource('Audit', audit, eager=True)
        policy.enforce(context,
                       'audit:update',
                       audit_to_update,
                       action='audit:update')

        try:
            audit_dict = audit_to_update.as_dict()

            initial_state = audit_dict['state']
            new_state = api_utils.get_patch_value(patch, 'state')
            if not api_utils.check_audit_state_transition(
                    patch, initial_state):
                error_message = _("State transition not allowed: "
                                  "(%(initial_state)s -> %(new_state)s)")
                raise exception.PatchError(
                    patch=patch,
                    reason=error_message %
                    dict(initial_state=initial_state, new_state=new_state))

            patch_path = api_utils.get_patch_key(patch, 'path')
            if patch_path in ('start_time', 'end_time'):
                patch_value = api_utils.get_patch_value(patch, patch_path)
                # convert string format to UTC time
                new_patch_value = wutils.parse_isodatetime(
                    patch_value).replace(tzinfo=tz.tzlocal()).astimezone(
                        tz.tzutc()).replace(tzinfo=None)
                api_utils.set_patch_value(patch, patch_path, new_patch_value)

            audit = Audit(**api_utils.apply_jsonpatch(audit_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Audit.fields:
            try:
                patch_val = getattr(audit, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if audit_to_update[field] != patch_val:
                audit_to_update[field] = patch_val

        audit_to_update.save()
        return Audit.convert_with_links(audit_to_update)
示例#2
0
    def patch(self, audit_uuid, patch):
        """Update an existing audit.

        :param audit_uuid: UUID of a audit.
        :param patch: a json PATCH document to apply to this audit.
        """
        if self.from_audits:
            raise exception.OperationNotPermitted

        context = pecan.request.context
        audit_to_update = api_utils.get_resource('Audit',
                                                 audit_uuid,
                                                 eager=True)
        policy.enforce(context,
                       'audit:update',
                       audit_to_update,
                       action='audit:update')

        try:
            audit_dict = audit_to_update.as_dict()
            audit = Audit(**api_utils.apply_jsonpatch(audit_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        initial_state = audit_dict['state']
        new_state = api_utils.get_patch_value(patch, 'state')
        allowed_states = ALLOWED_AUDIT_TRANSITIONS.get(initial_state, [])
        if new_state is not None and new_state not in allowed_states:
            error_message = _("State transition not allowed: "
                              "(%(initial_state)s -> %(new_state)s)")
            raise exception.PatchError(
                patch=patch,
                reason=error_message %
                dict(initial_state=initial_state, new_state=new_state))

        # Update only the fields that have changed
        for field in objects.Audit.fields:
            try:
                patch_val = getattr(audit, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if audit_to_update[field] != patch_val:
                audit_to_update[field] = patch_val

        audit_to_update.save()
        return Audit.convert_with_links(audit_to_update)
示例#3
0
    def patch(self, action_uuid, patch):
        """Update an existing action.

        :param action_uuid: UUID of a action.
        :param patch: a json PATCH document to apply to this action.
        """
        # FIXME: blueprint edit-action-plan-flow
        raise exception.OperationNotPermitted(
            _("Cannot modify an action directly"))

        if self.from_actions:
            raise exception.OperationNotPermitted

        action_to_update = objects.Action.get_by_uuid(pecan.request.context,
                                                      action_uuid)
        try:
            action_dict = action_to_update.as_dict()
            action = Action(**api_utils.apply_jsonpatch(action_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Action.fields:
            try:
                patch_val = getattr(action, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if action_to_update[field] != patch_val:
                action_to_update[field] = patch_val

        action_to_update.save()
        return Action.convert_with_links(action_to_update)
示例#4
0
 def validate(patch):
     serialized_patch = {'path': patch.path, 'op': patch.op}
     if patch.path in AuditPatchType.mandatory_attrs():
         msg = _("%(field)s can't be updated.")
         raise exception.PatchError(patch=serialized_patch,
                                    reason=msg % dict(field=patch.path))
     return types.JsonPatchType.validate(patch)
示例#5
0
    def patch(self, audit_uuid, patch):
        """Update an existing audit.

        :param audit_uuid: UUID of a audit.
        :param patch: a json PATCH document to apply to this audit.
        """
        if self.from_audits:
            raise exception.OperationNotPermitted

        audit_to_update = objects.Audit.get_by_uuid(pecan.request.context,
                                                    audit_uuid)
        try:
            audit_dict = audit_to_update.as_dict()
            audit = Audit(**api_utils.apply_jsonpatch(audit_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Audit.fields:
            try:
                patch_val = getattr(audit, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if audit_to_update[field] != patch_val:
                audit_to_update[field] = patch_val

        audit_to_update.save()
        return Audit.convert_with_links(audit_to_update)
示例#6
0
 def _validate_state(patch):
     serialized_patch = {'path': patch.path, 'op': patch.op}
     if patch.value is not wtypes.Unset:
         serialized_patch['value'] = patch.value
     # todo: use state machines to handle state transitions
     state_value = patch.value
     if state_value and not hasattr(ap_objects.State, state_value):
         msg = _("Invalid state: %(state)s")
         raise exception.PatchError(patch=serialized_patch,
                                    reason=msg % dict(state=state_value))
示例#7
0
    def validate(patch):
        def is_new_state_none(p):
            return p.path == '/state' and p.op == 'replace' and p.value is None

        serialized_patch = {
            'path': patch.path,
            'op': patch.op,
            'value': patch.value
        }
        if (patch.path in AuditPatchType.mandatory_attrs()
                or is_new_state_none(patch)):
            msg = _("%(field)s can't be updated.")
            raise exception.PatchError(patch=serialized_patch,
                                       reason=msg % dict(field=patch.path))
        return types.JsonPatchType.validate(patch)
示例#8
0
    def patch(self, audit_template, patch):
        """Update an existing audit template.

        :param audit template_uuid: UUID of a audit template.
        :param patch: a json PATCH document to apply to this audit template.
        """
        if self.from_audit_templates:
            raise exception.OperationNotPermitted

        context = pecan.request.context
        audit_template_to_update = api_utils.get_resource('AuditTemplate',
                                                          audit_template)
        policy.enforce(context, 'audit_template:update',
                       audit_template_to_update,
                       action='audit_template:update')

        if common_utils.is_uuid_like(audit_template):
            audit_template_to_update = objects.AuditTemplate.get_by_uuid(
                pecan.request.context,
                audit_template)
        else:
            audit_template_to_update = objects.AuditTemplate.get_by_name(
                pecan.request.context,
                audit_template)

        try:
            audit_template_dict = audit_template_to_update.as_dict()
            audit_template = AuditTemplate(**api_utils.apply_jsonpatch(
                audit_template_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.AuditTemplate.fields:
            try:
                patch_val = getattr(audit_template, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if audit_template_to_update[field] != patch_val:
                audit_template_to_update[field] = patch_val

        audit_template_to_update.save()
        return AuditTemplate.convert_with_links(audit_template_to_update)
示例#9
0
    def patch(self, action_plan_uuid, patch):
        """Update an existing action plan.

        :param action_plan_uuid: UUID of a action plan.
        :param patch: a json PATCH document to apply to this action plan.
        """
        if self.from_actionsPlans:
            raise exception.OperationNotPermitted

        context = pecan.request.context
        action_plan_to_update = api_utils.get_resource('ActionPlan',
                                                       action_plan_uuid,
                                                       eager=True)
        policy.enforce(context,
                       'action_plan:update',
                       action_plan_to_update,
                       action='action_plan:update')

        try:
            action_plan_dict = action_plan_to_update.as_dict()
            action_plan = ActionPlan(
                **api_utils.apply_jsonpatch(action_plan_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        launch_action_plan = False
        cancel_action_plan = False

        # transitions that are allowed via PATCH
        allowed_patch_transitions = [
            (ap_objects.State.RECOMMENDED, ap_objects.State.PENDING),
            (ap_objects.State.RECOMMENDED, ap_objects.State.CANCELLED),
            (ap_objects.State.ONGOING, ap_objects.State.CANCELLING),
            (ap_objects.State.PENDING, ap_objects.State.CANCELLED),
        ]

        # todo: improve this in blueprint watcher-api-validation
        if hasattr(action_plan, 'state'):
            transition = (action_plan_to_update.state, action_plan.state)
            if transition not in allowed_patch_transitions:
                error_message = _("State transition not allowed: "
                                  "(%(initial_state)s -> %(new_state)s)")
                raise exception.PatchError(
                    patch=patch,
                    reason=error_message %
                    dict(initial_state=action_plan_to_update.state,
                         new_state=action_plan.state))

            if action_plan.state == ap_objects.State.PENDING:
                launch_action_plan = True
            if action_plan.state == ap_objects.State.CANCELLED:
                cancel_action_plan = True

        # Update only the fields that have changed
        for field in objects.ActionPlan.fields:
            try:
                patch_val = getattr(action_plan, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if action_plan_to_update[field] != patch_val:
                action_plan_to_update[field] = patch_val

            if (field == 'state'
                    and patch_val == objects.action_plan.State.PENDING):
                launch_action_plan = True

        action_plan_to_update.save()

        # NOTE: if action plan is cancelled from pending or recommended
        # state update action state here only
        if cancel_action_plan:
            filters = {'action_plan_uuid': action_plan.uuid}
            actions = objects.Action.list(pecan.request.context,
                                          filters=filters,
                                          eager=True)
            for a in actions:
                a.state = objects.action.State.CANCELLED
                a.save()

        if launch_action_plan:
            self.applier_client.launch_action_plan(pecan.request.context,
                                                   action_plan.uuid)

        action_plan_to_update = objects.ActionPlan.get_by_uuid(
            pecan.request.context, action_plan_uuid)
        return ActionPlan.convert_with_links(action_plan_to_update)
示例#10
0
    def patch(self, action_plan_uuid, patch):
        """Update an existing action plan.

        :param action_plan_uuid: UUID of a action plan.
        :param patch: a json PATCH document to apply to this action plan.
        """
        launch_action_plan = True
        if self.from_actionsPlans:
            raise exception.OperationNotPermitted

        action_plan_to_update = objects.ActionPlan.get_by_uuid(
            pecan.request.context, action_plan_uuid)
        try:
            action_plan_dict = action_plan_to_update.as_dict()
            action_plan = ActionPlan(
                **api_utils.apply_jsonpatch(action_plan_dict, patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        launch_action_plan = False

        # transitions that are allowed via PATCH
        allowed_patch_transitions = [
            (ap_objects.State.RECOMMENDED, ap_objects.State.TRIGGERED),
            (ap_objects.State.RECOMMENDED, ap_objects.State.CANCELLED),
            (ap_objects.State.ONGOING, ap_objects.State.CANCELLED),
            (ap_objects.State.TRIGGERED, ap_objects.State.CANCELLED),
        ]

        # todo: improve this in blueprint watcher-api-validation
        if hasattr(action_plan, 'state'):
            transition = (action_plan_to_update.state, action_plan.state)
            if transition not in allowed_patch_transitions:
                error_message = _("State transition not allowed: "
                                  "(%(initial_state)s -> %(new_state)s)")
                raise exception.PatchError(
                    patch=patch,
                    reason=error_message %
                    dict(initial_state=action_plan_to_update.state,
                         new_state=action_plan.state))

            if action_plan.state == ap_objects.State.TRIGGERED:
                launch_action_plan = True

        # Update only the fields that have changed
        for field in objects.ActionPlan.fields:
            try:
                patch_val = getattr(action_plan, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if action_plan_to_update[field] != patch_val:
                action_plan_to_update[field] = patch_val

            if (field == 'state'
                    and patch_val == objects.action_plan.State.TRIGGERED):
                launch_action_plan = True

        action_plan_to_update.save()

        if launch_action_plan:
            applier_client = rpcapi.ApplierAPI()
            applier_client.launch_action_plan(pecan.request.context,
                                              action_plan.uuid)

        action_plan_to_update = objects.ActionPlan.get_by_uuid(
            pecan.request.context, action_plan_uuid)
        return ActionPlan.convert_with_links(action_plan_to_update)