def detail(self, goal=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of strategies with detail. :param goal: goal UUID or name to filter by. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'strategy:detail', action='strategy:detail') # NOTE(lucasagomes): /detail should only work agaist collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "strategies": raise exception.HTTPNotFound expand = True resource_url = '/'.join(['strategies', 'detail']) filters = {} if goal: if common_utils.is_uuid_like(goal): filters['goal_uuid'] = goal else: filters['goal_name'] = goal return self._get_strategies_collection( filters, marker, limit, sort_key, sort_dir, expand, resource_url)
def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc', action_plan_uuid=None, audit_uuid=None): """Retrieve a list of actions with detail. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. :param action_plan_uuid: Optional UUID of an action plan, to get only actions for that action plan. :param audit_uuid: Optional UUID of an audit, to get only actions for that audit. """ context = pecan.request.context policy.enforce(context, 'action:detail', action='action:detail') # NOTE(lucasagomes): /detail should only work agaist collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "actions": raise exception.HTTPNotFound if action_plan_uuid and audit_uuid: raise exception.ActionFilterCombinationProhibited expand = True resource_url = '/'.join(['actions', 'detail']) return self._get_actions_collection( marker, limit, sort_key, sort_dir, expand, resource_url, action_plan_uuid=action_plan_uuid, audit_uuid=audit_uuid)
def get_all(self, goal=None, strategy=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audit templates. :param goal: goal UUID or name to filter by :param strategy: strategy UUID or name to filter by :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'audit_template:get_all', action='audit_template:get_all') filters = {} if goal: if common_utils.is_uuid_like(goal): filters['goal_uuid'] = goal else: filters['goal_name'] = goal if strategy: if common_utils.is_uuid_like(strategy): filters['strategy_uuid'] = strategy else: filters['strategy_name'] = strategy return self._get_audit_templates_collection( filters, marker, limit, sort_key, sort_dir)
def delete(self, audit_uuid): """Delete a audit. :param audit_uuid: UUID of a audit. """ context = pecan.request.context audit_to_delete = api_utils.get_resource('Audit', audit_uuid) policy.enforce(context, 'audit:update', audit_to_delete, action='audit:update') audit_to_delete.soft_delete()
def delete(self, action_plan_uuid): """Delete an action plan. :param action_plan_uuid: UUID of a action. """ context = pecan.request.context action_plan = api_utils.get_resource('ActionPlan', action_plan_uuid) policy.enforce(context, 'action_plan:delete', action_plan, action='action_plan:delete') action_plan.soft_delete()
def post(self, audit_p): """Create a new audit. :param audit_p: a audit within the request body. """ context = pecan.request.context policy.enforce(context, 'audit:create', action='audit:create') audit = audit_p.as_audit() if self.from_audits: raise exception.OperationNotPermitted if not audit._audit_template_uuid: raise exception.Invalid( message=_('The audit template UUID or name specified is ' 'invalid')) audit_template = objects.AuditTemplate.get(pecan.request.context, audit._audit_template_uuid) strategy_id = audit_template.strategy_id no_schema = True if strategy_id is not None: # validate parameter when predefined strategy in audit template strategy = objects.Strategy.get(pecan.request.context, strategy_id) schema = strategy.parameters_spec if schema: # validate input parameter with default value feedback no_schema = False utils.DefaultValidatingDraft4Validator(schema).validate( audit.parameters) if no_schema and audit.parameters: raise exception.Invalid(_('Specify parameters but no predefined ' 'strategy for audit template, or no ' 'parameter spec in predefined strategy')) audit_dict = audit.as_dict() context = pecan.request.context new_audit = objects.Audit(context, **audit_dict) new_audit.create(context) # Set the HTTP Location Header pecan.response.location = link.build_url('audits', new_audit.uuid) # trigger decision-engine to run the audit if new_audit.audit_type == objects.audit.AuditType.ONESHOT.value: dc_client = rpcapi.DecisionEngineAPI() dc_client.trigger_audit(context, new_audit.uuid) return Audit.convert_with_links(new_audit)
def get_one(self, audit_uuid): """Retrieve information about the given audit. :param audit_uuid: UUID of a audit. """ if self.from_audits: raise exception.OperationNotPermitted context = pecan.request.context rpc_audit = api_utils.get_resource('Audit', audit_uuid) policy.enforce(context, 'audit:get', rpc_audit, action='audit:get') return Audit.convert_with_links(rpc_audit)
def delete(self, audit_template): """Delete a audit template. :param audit template_uuid: UUID or name of an audit template. """ context = pecan.request.context audit_template_to_delete = api_utils.get_resource('AuditTemplate', audit_template) policy.enforce(context, 'audit_template:update', audit_template_to_delete, action='audit_template:update') audit_template_to_delete.soft_delete()
def get_one(self, action_uuid): """Retrieve information about the given action. :param action_uuid: UUID of a action. """ if self.from_actions: raise exception.OperationNotPermitted context = pecan.request.context action = api_utils.get_resource('Action', action_uuid) policy.enforce(context, 'action:get', action, action='action:get') return Action.convert_with_links(action)
def get_one(self, strategy): """Retrieve information about the given strategy. :param strategy: UUID or name of the strategy. """ if self.from_strategies: raise exception.OperationNotPermitted context = pecan.request.context rpc_strategy = api_utils.get_resource('Strategy', strategy) policy.enforce(context, 'strategy:get', rpc_strategy, action='strategy:get') return Strategy.convert_with_links(rpc_strategy)
def get_one(self, audit_template): """Retrieve information about the given audit template. :param audit audit_template: UUID or name of an audit template. """ if self.from_audit_templates: raise exception.OperationNotPermitted context = pecan.request.context rpc_audit_template = api_utils.get_resource('AuditTemplate', audit_template) policy.enforce(context, 'audit_template:get', rpc_audit_template, action='audit_template:get') return AuditTemplate.convert_with_links(rpc_audit_template)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of Scoring Engines. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: name. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'scoring_engine:get_all', action='scoring_engine:get_all') return self._get_scoring_engines_collection( marker, limit, sort_key, sort_dir)
def get_one(self, scoring_engine): """Retrieve information about the given Scoring Engine. :param scoring_engine_name: The name of the Scoring Engine. """ context = pecan.request.context policy.enforce(context, 'scoring_engine:get', action='scoring_engine:get') if self.from_scoring_engines: raise exception.OperationNotPermitted rpc_scoring_engine = api_utils.get_resource( 'ScoringEngine', scoring_engine) return ScoringEngine.convert_with_links(rpc_scoring_engine)
def get_all(self, audit_template=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audits. :param audit_template: Optional UUID or name of an audit :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. template, to get only audits for that audit template. """ context = pecan.request.context policy.enforce(context, 'audit:get_all', action='audit:get_all') return self._get_audits_collection(marker, limit, sort_key, sort_dir, audit_template=audit_template)
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)
def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of Scoring Engines with detail. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: name. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'scoring_engine:detail', action='scoring_engine:detail') parent = pecan.request.path.split('/')[:-1][-1] if parent != "scoring_engines": raise exception.HTTPNotFound expand = True resource_url = '/'.join(['scoring_engines', 'detail']) return self._get_scoring_engines_collection( marker, limit, sort_key, sort_dir, expand, resource_url)
def detail(self, goal=None, strategy=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audit templates with detail. :param goal: goal UUID or name to filter by :param strategy: strategy UUID or name to filter by :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'audit_template:detail', action='audit_template:detail') # NOTE(lucasagomes): /detail should only work agaist collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "audit_templates": raise exception.HTTPNotFound filters = {} if goal: if common_utils.is_uuid_like(goal): filters['goal_uuid'] = goal else: filters['goal_name'] = goal if strategy: if common_utils.is_uuid_like(strategy): filters['strategy_uuid'] = strategy else: filters['strategy_name'] = strategy expand = True resource_url = '/'.join(['audit_templates', 'detail']) return self._get_audit_templates_collection(filters, marker, limit, sort_key, sort_dir, expand, resource_url)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc', goal=None, strategy=None, host_aggregate=None): """Retrieve a list of audits. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. id. :param goal: goal UUID or name to filter by :param strategy: strategy UUID or name to filter by :param host_aggregate: Optional host_aggregate """ context = pecan.request.context policy.enforce(context, 'audit:get_all', action='audit:get_all') return self._get_audits_collection(marker, limit, sort_key, sort_dir, goal=goal, strategy=strategy, host_aggregate=host_aggregate)
def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc', audit_uuid=None, strategy=None): """Retrieve a list of action_plans with detail. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. :param audit_uuid: Optional UUID of an audit, to get only actions for that audit. :param strategy: strategy UUID or name to filter by """ context = pecan.request.context policy.enforce(context, 'action_plan:detail', action='action_plan:detail') # NOTE(lucasagomes): /detail should only work agaist collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "action_plans": raise exception.HTTPNotFound expand = True resource_url = '/'.join(['action_plans', 'detail']) return self._get_action_plans_collection(marker, limit, sort_key, sort_dir, expand, resource_url, audit_uuid=audit_uuid, strategy=strategy)
def post(self, audit_template_postdata): """Create a new audit template. :param audit_template_postdata: the audit template POST data from the request body. """ if self.from_audit_templates: raise exception.OperationNotPermitted context = pecan.request.context policy.enforce(context, 'audit_template:create', action='audit_template:create') context = pecan.request.context audit_template = audit_template_postdata.as_audit_template() audit_template_dict = audit_template.as_dict() new_audit_template = objects.AuditTemplate(context, **audit_template_dict) new_audit_template.create(context) # Set the HTTP Location Header pecan.response.location = link.build_url('audit_templates', new_audit_template.uuid) return AuditTemplate.convert_with_links(new_audit_template)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc', action_plan_uuid=None, audit_uuid=None): """Retrieve a list of actions. :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. :param action_plan_uuid: Optional UUID of an action plan, to get only actions for that action plan. :param audit_uuid: Optional UUID of an audit, to get only actions for that audit. """ context = pecan.request.context policy.enforce(context, 'action:get_all', action='action:get_all') if action_plan_uuid and audit_uuid: raise exception.ActionFilterCombinationProhibited return self._get_actions_collection( marker, limit, sort_key, sort_dir, action_plan_uuid=action_plan_uuid, audit_uuid=audit_uuid)
def detail(self, audit_template=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audits with detail. :param audit_template: Optional UUID or name of an audit :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ context = pecan.request.context policy.enforce(context, 'audit:detail', action='audit:detail') # NOTE(lucasagomes): /detail should only work agaist collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "audits": raise exception.HTTPNotFound expand = True resource_url = '/'.join(['audits', 'detail']) return self._get_audits_collection(marker, limit, sort_key, sort_dir, expand, resource_url, audit_template=audit_template)
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)
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 context = pecan.request.context action_plan_to_update = api_utils.get_resource('ActionPlan', action_plan_uuid) 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 # 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.CANCELLED), (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 # 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() 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)