def before(self, state): headers = state.request.headers user = headers.get('X-User') user_id = headers.get('X-User-Id') project = headers.get('X-Project-Name') project_id = headers.get('X-Project-Id') domain_id = headers.get('X-User-Domain-Id') domain_name = headers.get('X-User-Domain-Name') auth_token = headers.get('X-Storage-Token') auth_token = headers.get('X-Auth-Token', auth_token) show_deleted = headers.get('X-Show-Deleted') auth_token_info = state.request.environ.get('keystone.token_info') roles = (headers.get('X-Roles', None) and headers.get('X-Roles').split(',')) auth_url = headers.get('X-Auth-Url') if auth_url is None: importutils.import_module('keystonemiddleware.auth_token') auth_url = cfg.CONF.keystone_authtoken.auth_uri state.request.context = context.make_context( auth_token=auth_token, auth_url=auth_url, auth_token_info=auth_token_info, user=user, user_id=user_id, project=project, project_id=project_id, domain_id=domain_id, domain_name=domain_name, show_deleted=show_deleted, roles=roles)
def before(self, state): headers = state.request.headers user = headers.get('X-User') user_id = headers.get('X-User-Id') project = headers.get('X-Project-Name') project_id = headers.get('X-Project-Id') domain_id = headers.get('X-User-Domain-Id') domain_name = headers.get('X-User-Domain-Name') auth_token = headers.get('X-Storage-Token') auth_token = headers.get('X-Auth-Token', auth_token) show_deleted = headers.get('X-Show-Deleted') auth_token_info = state.request.environ.get('keystone.token_info') roles = (headers.get('X-Roles', None) and headers.get('X-Roles').split(',')) state.request.context = context.make_context( auth_token=auth_token, auth_token_info=auth_token_info, user=user, user_id=user_id, project=project, project_id=project_id, domain_id=domain_id, domain_name=domain_name, show_deleted=show_deleted, roles=roles)
def before(self, state): headers = state.request.headers user = headers.get('X-User') user_id = headers.get('X-User-Id') project = headers.get('X-Project-Name') project_id = headers.get('X-Project-Id') domain_id = headers.get('X-User-Domain-Id') domain_name = headers.get('X-User-Domain-Name') auth_token = headers.get('X-Storage-Token') auth_token = headers.get('X-Auth-Token', auth_token) show_deleted = headers.get('X-Show-Deleted') auth_token_info = state.request.environ.get('keystone.token_info') auth_url = headers.get('X-Auth-Url') if auth_url is None: importutils.import_module('keystonemiddleware.auth_token') auth_url = cfg.CONF.keystone_authtoken.auth_uri state.request.context = context.make_context( auth_token=auth_token, auth_url=auth_url, auth_token_info=auth_token_info, user=user, user_id=user_id, project=project, project_id=project_id, domain_id=domain_id, domain_name=domain_name, show_deleted=show_deleted)
def __init__(self, config, osc=None): """Constructor: the signature should be identical within the subclasses :param config: Configuration related to this plugin :type config: :py:class:`~.Struct` :param osc: An OpenStackClients instance :type osc: :py:class:`~.OpenStackClients` instance """ super(BaseStrategy, self).__init__(config) self.ctx = context.make_context() self._name = self.get_name() self._display_name = self.get_display_name() self._goal = self.get_goal() # default strategy level self._strategy_level = level.StrategyLevel.conservative self._cluster_state_collector = None # the solution given by the strategy self._solution = default.DefaultSolution(goal=self.goal, strategy=self) self._osc = osc self._collector_manager = None self._compute_model = None self._storage_model = None self._baremetal_model = None self._input_parameters = utils.Struct() self._audit_scope = None self._datasource_backend = None
def test_action_plan_init(self, m_request): m_request.context = context.make_context() act_plan_dict = api_utils.action_plan_post_data() del act_plan_dict['state'] del act_plan_dict['audit_id'] del act_plan_dict['first_action_id'] act_plan = api_action_plan.ActionPlan(**act_plan_dict) self.assertEqual(wtypes.Unset, act_plan.state)
class AuditTemplatePatchType(types.JsonPatchType): _ctx = context_utils.make_context() @staticmethod def mandatory_attrs(): return [] @staticmethod def validate(patch): if patch.path == "/goal" and patch.op != "remove": AuditTemplatePatchType._validate_goal(patch) elif patch.path == "/goal" and patch.op == "remove": raise exception.OperationNotPermitted( _("Cannot remove 'goal' attribute " "from an audit template")) if patch.path == "/strategy": AuditTemplatePatchType._validate_strategy(patch) return types.JsonPatchType.validate(patch) @staticmethod def _validate_goal(patch): patch.path = "/goal_id" goal = patch.value if goal: available_goals = objects.Goal.list(AuditTemplatePatchType._ctx) available_goal_uuids_map = {g.uuid: g for g in available_goals} available_goal_names_map = {g.name: g for g in available_goals} if goal in available_goal_uuids_map: patch.value = available_goal_uuids_map[goal].id elif goal in available_goal_names_map: patch.value = available_goal_names_map[goal].id else: raise exception.InvalidGoal(goal=goal) @staticmethod def _validate_strategy(patch): patch.path = "/strategy_id" strategy = patch.value if strategy: available_strategies = objects.Strategy.list( AuditTemplatePatchType._ctx) available_strategy_uuids_map = { s.uuid: s for s in available_strategies } available_strategy_names_map = { s.name: s for s in available_strategies } if strategy in available_strategy_uuids_map: patch.value = available_strategy_uuids_map[strategy].id elif strategy in available_strategy_names_map: patch.value = available_strategy_names_map[strategy].id else: raise exception.InvalidStrategy(strategy=strategy)
def add_checkstate_job(self): # 30 minutes interval interval = CONF.watcher_decision_engine.check_periodic_interval ap_manager = objects.action_plan.StateManager() if CONF.watcher_decision_engine.action_plan_expiry != 0: self.add_job(ap_manager.check_expired, 'interval', args=[context.make_context()], seconds=interval, next_run_time=datetime.datetime.now())
def start(self): """Start service.""" context = watcher_context.make_context(is_admin=True) self.add_job(self.get_services_status, name='service_status', trigger='interval', jobstore='default', args=[context], next_run_time=datetime.datetime.now(), seconds=CONF.periodic_interval) super(APISchedulingService, self).start()
def _get_action_plan_payload(action): action_plan = None strategy_uuid = None audit = None try: action_plan = action.action_plan audit = objects.Audit.get(wcontext.make_context(show_deleted=True), action_plan.audit_id) if audit.strategy_id: strategy_uuid = objects.Strategy.get( wcontext.make_context(show_deleted=True), audit.strategy_id).uuid except NotImplementedError: raise exception.EagerlyLoadedActionRequired(action=action.uuid) action_plan_payload = ap_notifications.TerseActionPlanPayload( action_plan=action_plan, audit_uuid=audit.uuid, strategy_uuid=strategy_uuid) return action_plan_payload
def __init__(self): self.ctx = context.make_context() self.discovered_map = None self._available_goals = None self._available_goals_map = None self._available_strategies = None self._available_strategies_map = None # This goal mapping maps stale goal IDs to the synced goal self.goal_mapping = dict() # This strategy mapping maps stale strategy IDs to the synced goal self.strategy_mapping = dict() self.stale_audit_templates_map = {}
def setUp(self): super(TestSyncer, self).setUp() self.ctx = context.make_context() # This mock simulates the strategies discovery done in discover() self.m_available_strategies = mock.Mock( return_value={ fake_strategies.FakeDummy1Strategy1.get_name(): fake_strategies.FakeDummy1Strategy1, fake_strategies.FakeDummy1Strategy2.get_name(): fake_strategies.FakeDummy1Strategy2, fake_strategies.FakeDummy2Strategy3.get_name(): fake_strategies.FakeDummy2Strategy3, fake_strategies.FakeDummy2Strategy4.get_name(): fake_strategies.FakeDummy2Strategy4, }) self.m_available_goals = mock.Mock( return_value={ fake_goals.FakeDummy1.get_name(): fake_goals.FakeDummy1, fake_goals.FakeDummy2.get_name(): fake_goals.FakeDummy2, }) self.goal1_spec = fake_goals.FakeDummy1( config=mock.Mock()).get_efficacy_specification() self.goal2_spec = fake_goals.FakeDummy2( config=mock.Mock()).get_efficacy_specification() p_goals_load = mock.patch.object( default.DefaultGoalLoader, 'load', side_effect=lambda goal: self.m_available_goals()[goal]()) p_goals = mock.patch.object(default.DefaultGoalLoader, 'list_available', self.m_available_goals) p_strategies = mock.patch.object(default.DefaultStrategyLoader, 'list_available', self.m_available_strategies) p_goals.start() p_goals_load.start() p_strategies.start() self.syncer = sync.Syncer() self.addCleanup(p_goals.stop) self.addCleanup(p_goals_load.stop) self.addCleanup(p_strategies.stop)
def sync(self): ctx = context.make_context() action_loader = default.DefaultActionLoader() available_actions = action_loader.list_available() for action_type in available_actions.keys(): load_action = action_loader.load(action_type) load_description = load_action.get_description() try: action_desc = objects.ActionDescription.get_by_type( ctx, action_type) if action_desc.description != load_description: action_desc.description = load_description action_desc.save() except exception.ActionDescriptionNotFound: obj_action_desc = objects.ActionDescription(ctx) obj_action_desc.action_type = action_type obj_action_desc.description = load_description obj_action_desc.create()
def __init__(self, url=None, engine=None, tablename='apscheduler_jobs', metadata=None, pickle_protocol=pickle.HIGHEST_PROTOCOL, tag=None): super(WatcherJobStore, self).__init__(url, engine, tablename, metadata, pickle_protocol) metadata = maybe_ref(metadata) or MetaData() self.jobs_t = Table(tablename, metadata, autoload=True, autoload_with=engine) service_ident = service.ServiceHeartbeat.get_service_name() self.tag = tag or {'host': service_ident[0], 'name': service_ident[1]} self.service_id = objects.Service.list(context=context.make_context(), filters=self.tag)[0].id
def setUp(self): super(TestSyncer, self).setUp() self.ctx = context.make_context() # This mock simulates the strategies discovery done in discover() self.m_available_strategies = mock.Mock(return_value={ fake_strategies.FakeDummy1Strategy1.get_name(): fake_strategies.FakeDummy1Strategy1, fake_strategies.FakeDummy1Strategy2.get_name(): fake_strategies.FakeDummy1Strategy2, fake_strategies.FakeDummy2Strategy3.get_name(): fake_strategies.FakeDummy2Strategy3, fake_strategies.FakeDummy2Strategy4.get_name(): fake_strategies.FakeDummy2Strategy4, }) self.m_available_goals = mock.Mock(return_value={ fake_goals.FakeDummy1.get_name(): fake_goals.FakeDummy1, fake_goals.FakeDummy2.get_name(): fake_goals.FakeDummy2, }) self.goal1_spec = fake_goals.FakeDummy1( config=mock.Mock()).get_efficacy_specification() self.goal2_spec = fake_goals.FakeDummy2( config=mock.Mock()).get_efficacy_specification() p_goals_load = mock.patch.object( default.DefaultGoalLoader, 'load', side_effect=lambda goal: self.m_available_goals()[goal]()) p_goals = mock.patch.object( default.DefaultGoalLoader, 'list_available', self.m_available_goals) p_strategies = mock.patch.object( default.DefaultStrategyLoader, 'list_available', self.m_available_strategies) p_goals.start() p_goals_load.start() p_strategies.start() self.syncer = sync.Syncer() self.addCleanup(p_goals.stop) self.addCleanup(p_goals_load.stop) self.addCleanup(p_strategies.stop)
def _get_common_payload(action_plan): audit = None strategy = None try: audit = action_plan.audit strategy = action_plan.strategy except NotImplementedError: raise exception.EagerlyLoadedActionPlanRequired( action_plan=action_plan.uuid) goal = objects.Goal.get(wcontext.make_context(show_deleted=True), audit.goal_id) audit_payload = audit_notifications.TerseAuditPayload(audit=audit, goal_uuid=goal.uuid) strategy_payload = strategy_notifications.StrategyPayload( strategy=strategy) return audit_payload, strategy_payload
def cancel_ongoing_audits(self): audit_filters = { 'audit_type': objects.audit.AuditType.ONESHOT.value, 'state': objects.audit.State.ONGOING, 'hostname': CONF.host } local_context = context.make_context() ongoing_audits = objects.Audit.list(local_context, filters=audit_filters) for audit in ongoing_audits: audit.state = objects.audit.State.CANCELLED audit.save() LOG.info( "Audit %(uuid)s has been cancelled because it was in " "%(state)s state when Decision Engine had been stopped " "on %(hostname)s host.", { 'uuid': audit.uuid, 'state': objects.audit.State.ONGOING, 'hostname': audit.hostname })
def setUp(self): super(TestSyncer, self).setUp() self.ctx = context.make_context() # This mock simulates the strategies discovery done in discover() self.m_available_strategies = mock.Mock(return_value={ fake_strategies.FakeDummy1Strategy1.get_name(): fake_strategies.FakeDummy1Strategy1, fake_strategies.FakeDummy1Strategy2.get_name(): fake_strategies.FakeDummy1Strategy2, fake_strategies.FakeDummy2Strategy3.get_name(): fake_strategies.FakeDummy2Strategy3, fake_strategies.FakeDummy2Strategy4.get_name(): fake_strategies.FakeDummy2Strategy4, }) p_strategies = mock.patch.object( default.DefaultStrategyLoader, 'list_available', self.m_available_strategies) p_strategies.start() self.syncer = sync.Syncer() self.addCleanup(p_strategies.stop)
def __init__(self): self.ctx = context.make_context() self.discovered_map = None self._available_goals = None self._available_goals_map = None self._available_strategies = None self._available_strategies_map = None self._available_scoringengines = None self._available_scoringengines_map = None # This goal mapping maps stale goal IDs to the synced goal self.goal_mapping = dict() # This strategy mapping maps stale strategy IDs to the synced goal self.strategy_mapping = dict() # Maps stale scoring engine IDs to the synced scoring engines self.se_mapping = dict() self.stale_audit_templates_map = {} self.stale_audits_map = {} self.stale_action_plans_map = {}
def __init__(self, gconfig=None, service_name=None, **kwargs): gconfig = None or {} super(ServiceHeartbeat, self).__init__(gconfig, **kwargs) ServiceHeartbeat.service_name = service_name self.context = context.make_context() self.send_beat()
def __init__(self, scope): self.ctx = context.make_context() self.scope = scope
class AuditTemplatePostType(wtypes.Base): _ctx = context_utils.make_context() name = wtypes.wsattr(wtypes.text, mandatory=True) """Name of this audit template""" description = wtypes.wsattr(wtypes.text, mandatory=False) """Short description of this audit template""" deadline = wsme.wsattr(datetime.datetime, mandatory=False) """deadline of the audit template""" extra = wtypes.wsattr({wtypes.text: types.jsontype}, mandatory=False) """The metadata of the audit template""" goal = wtypes.wsattr(wtypes.text, mandatory=True) """Goal UUID or name of the audit template""" strategy = wtypes.wsattr(wtypes.text, mandatory=False) """Strategy UUID or name of the audit template""" version = wtypes.text """Internal version of the audit template""" scope = wtypes.wsattr(types.jsontype, mandatory=False, default=[]) """Audit Scope""" def as_audit_template(self): return AuditTemplate( name=self.name, description=self.description, deadline=self.deadline, extra=self.extra, goal_id=self.goal, # Dirty trick ... goal=self.goal, strategy_id=self.strategy, # Dirty trick ... strategy_uuid=self.strategy, version=self.version, scope=self.scope, ) @staticmethod def validate(audit_template): available_goals = objects.Goal.list(AuditTemplatePostType._ctx) available_goal_uuids_map = {g.uuid: g for g in available_goals} available_goal_names_map = {g.name: g for g in available_goals} if audit_template.goal in available_goal_uuids_map: goal = available_goal_uuids_map[audit_template.goal] elif audit_template.goal in available_goal_names_map: goal = available_goal_names_map[audit_template.goal] else: raise exception.InvalidGoal(goal=audit_template.goal) common_utils.Draft4Validator( default.DefaultScope.DEFAULT_SCHEMA).validate(audit_template.scope) if audit_template.strategy: available_strategies = objects.Strategy.list( AuditTemplatePostType._ctx) available_strategies_map = { s.uuid: s for s in available_strategies} if audit_template.strategy not in available_strategies_map: raise exception.InvalidStrategy( strategy=audit_template.strategy) strategy = available_strategies_map[audit_template.strategy] # Check that the strategy we indicate is actually related to the # specified goal if strategy.goal_id != goal.id: choices = ["'%s' (%s)" % (s.uuid, s.name) for s in available_strategies] raise exception.InvalidStrategy( message=_( "'%(strategy)s' strategy does relate to the " "'%(goal)s' goal. Possible choices: %(choices)s") % dict(strategy=strategy.name, goal=goal.name, choices=", ".join(choices))) audit_template.strategy = strategy.uuid # We force the UUID so that we do not need to query the DB with the # name afterwards audit_template.goal = goal.uuid return audit_template
def __init__(self, scope, config): self.ctx = context.make_context() self.scope = scope self.config = config
class PurgeCommand(object): """Purges the DB by removing soft deleted entries The workflow for this purge is the following: # Find soft deleted objects which are expired # Find orphan objects # Find their related objects whether they are expired or not # Merge them together # If it does not exceed the limit, destroy them all """ ctx = context.make_context(show_deleted=True) def __init__(self, age_in_days=None, max_number=None, uuid=None, exclude_orphans=False, dry_run=None): self.age_in_days = age_in_days self.max_number = max_number self.uuid = uuid self.exclude_orphans = exclude_orphans self.dry_run = dry_run self._delete_up_to_max = None self._objects_map = WatcherObjectsMap() def get_expiry_date(self): if not self.age_in_days: return None today = datetime.datetime.today() expiry_date = today - datetime.timedelta(days=self.age_in_days) return expiry_date @classmethod def get_audit_template_uuid(cls, uuid_or_name): if uuid_or_name is None: return query_func = None if not utils.is_uuid_like(uuid_or_name): query_func = objects.audit_template.AuditTemplate.get_by_name else: query_func = objects.audit_template.AuditTemplate.get_by_uuid try: audit_template = query_func(cls.ctx, uuid_or_name) except Exception as exc: LOG.exception(exc) raise exception.AuditTemplateNotFound(audit_template=uuid_or_name) if not audit_template.deleted_at: raise exception.NotSoftDeletedStateError( name=_('Audit Template'), id=uuid_or_name) return audit_template.uuid def _find_audit_templates(self, filters=None): return objects.audit_template.AuditTemplate.list( self.ctx, filters=filters) def _find_audits(self, filters=None): return objects.audit.Audit.list(self.ctx, filters=filters) def _find_action_plans(self, filters=None): return objects.action_plan.ActionPlan.list(self.ctx, filters=filters) def _find_actions(self, filters=None): return objects.action.Action.list(self.ctx, filters=filters) def _find_orphans(self): orphans = WatcherObjectsMap() filters = dict(deleted=False) audit_templates = objects.audit_template.AuditTemplate.list( self.ctx, filters=filters) audits = objects.audit.Audit.list(self.ctx, filters=filters) action_plans = objects.action_plan.ActionPlan.list( self.ctx, filters=filters) actions = objects.action.Action.list(self.ctx, filters=filters) audit_template_ids = set(at.id for at in audit_templates) orphans.audits = [ audit for audit in audits if audit.audit_template_id not in audit_template_ids] # Objects with orphan parents are themselves orphans audit_ids = [audit.id for audit in (a for a in audits if a not in orphans.audits)] orphans.action_plans = [ ap for ap in action_plans if ap.audit_id not in audit_ids] # Objects with orphan parents are themselves orphans action_plan_ids = [ap.id for ap in (a for a in action_plans if a not in orphans.action_plans)] orphans.actions = [ action for action in actions if action.action_plan_id not in action_plan_ids] LOG.debug("Orphans found:\n%s", orphans) LOG.info(_LI("Orphans found:\n%s"), orphans.get_count_table()) return orphans def _find_soft_deleted_objects(self): to_be_deleted = WatcherObjectsMap() expiry_date = self.get_expiry_date() filters = dict(deleted=True) if self.uuid: filters["uuid"] = self.uuid if expiry_date: filters.update(dict(deleted_at__lt=expiry_date)) to_be_deleted.audit_templates.extend( self._find_audit_templates(filters)) to_be_deleted.audits.extend(self._find_audits(filters)) to_be_deleted.action_plans.extend(self._find_action_plans(filters)) to_be_deleted.actions.extend(self._find_actions(filters)) soft_deleted_objs = self._find_related_objects( to_be_deleted, base_filters=dict(deleted=True)) LOG.debug("Soft deleted objects:\n%s", soft_deleted_objs) return soft_deleted_objs def _find_related_objects(self, objects_map, base_filters=None): base_filters = base_filters or {} for audit_template in objects_map.audit_templates: filters = {} filters.update(base_filters) filters.update(dict(audit_template_id=audit_template.id)) related_objs = WatcherObjectsMap() related_objs.audits = self._find_audits(filters) objects_map += related_objs for audit in objects_map.audits: filters = {} filters.update(base_filters) filters.update(dict(audit_id=audit.id)) related_objs = WatcherObjectsMap() related_objs.action_plans = self._find_action_plans(filters) objects_map += related_objs for action_plan in objects_map.action_plans: filters = {} filters.update(base_filters) filters.update(dict(action_plan_id=action_plan.id)) related_objs = WatcherObjectsMap() related_objs.actions = self._find_actions(filters) objects_map += related_objs return objects_map def confirmation_prompt(self): print(self._objects_map.get_count_table()) raw_val = input( _("There are %(count)d objects set for deletion. " "Continue? [y/N]") % dict(count=len(self._objects_map))) return strutils.bool_from_string(raw_val) def delete_up_to_max_prompt(self, objects_map): print(objects_map.get_count_table()) print(_("The number of objects (%(num)s) to delete from the database " "exceeds the maximum number of objects (%(max_number)s) " "specified.") % dict(max_number=self.max_number, num=len(objects_map))) raw_val = input( _("Do you want to delete objects up to the specified maximum " "number? [y/N]")) self._delete_up_to_max = strutils.bool_from_string(raw_val) return self._delete_up_to_max def _aggregate_objects(self): """Objects aggregated on a 'per audit template' basis""" # todo: aggregate orphans as well aggregate = [] for audit_template in self._objects_map.audit_templates: related_objs = WatcherObjectsMap() related_objs.audit_templates = [audit_template] related_objs.audits = [ audit for audit in self._objects_map.audits if audit.audit_template_id == audit_template.id ] audit_ids = [audit.id for audit in related_objs.audits] related_objs.action_plans = [ action_plan for action_plan in self._objects_map.action_plans if action_plan.audit_id in audit_ids ] action_plan_ids = [ action_plan.id for action_plan in related_objs.action_plans ] related_objs.actions = [ action for action in self._objects_map.actions if action.action_plan_id in action_plan_ids ] aggregate.append(related_objs) return aggregate def _get_objects_up_to_limit(self): aggregated_objects = self._aggregate_objects() to_be_deleted_subset = WatcherObjectsMap() for aggregate in aggregated_objects: if len(aggregate) + len(to_be_deleted_subset) <= self.max_number: to_be_deleted_subset += aggregate else: break LOG.debug(to_be_deleted_subset) return to_be_deleted_subset def find_objects_to_delete(self): """Finds all the objects to be purged :returns: A mapping with all the Watcher objects to purged :rtype: :py:class:`~.WatcherObjectsMap` instance """ to_be_deleted = self._find_soft_deleted_objects() if not self.exclude_orphans: to_be_deleted += self._find_orphans() LOG.debug("Objects to be deleted:\n%s", to_be_deleted) return to_be_deleted def do_delete(self): LOG.info(_LI("Deleting...")) # Reversed to avoid errors with foreign keys for entry in reversed(list(self._objects_map)): entry.destroy() def execute(self): LOG.info(_LI("Starting purge command")) self._objects_map = self.find_objects_to_delete() if (self.max_number is not None and len(self._objects_map) > self.max_number): if self.delete_up_to_max_prompt(self._objects_map): self._objects_map = self._get_objects_up_to_limit() else: return _orphans_note = (_(" (orphans excluded)") if self.exclude_orphans else _(" (may include orphans)")) if not self.dry_run and self.confirmation_prompt(): self.do_delete() print(_("Purge results summary%s:") % _orphans_note) LOG.info(_LI("Purge results summary%s:"), _orphans_note) else: LOG.debug(self._objects_map) print(_("Here below is a table containing the objects " "that can be purged%s:") % _orphans_note) LOG.info("\n%s", self._objects_map.get_count_table()) print(self._objects_map.get_count_table()) LOG.info(_LI("Purge process completed"))
class AuditTemplatePostType(wtypes.Base): _ctx = context_utils.make_context() name = wtypes.wsattr(wtypes.text, mandatory=True) """Name of this audit template""" description = wtypes.wsattr(wtypes.text, mandatory=False) """Short description of this audit template""" goal = wtypes.wsattr(wtypes.text, mandatory=True) """Goal UUID or name of the audit template""" strategy = wtypes.wsattr(wtypes.text, mandatory=False) """Strategy UUID or name of the audit template""" scope = wtypes.wsattr(types.jsontype, mandatory=False, default=[]) """Audit Scope""" def as_audit_template(self): return AuditTemplate( name=self.name, description=self.description, goal_id=self.goal, # Dirty trick ... goal=self.goal, strategy_id=self.strategy, # Dirty trick ... strategy_uuid=self.strategy, scope=self.scope, ) @staticmethod def _build_schema(): SCHEMA = { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": { "type": "object", "properties": AuditTemplatePostType._get_schemas(), "additionalProperties": False } } return SCHEMA @staticmethod def _get_schemas(): collectors = default_loading.ClusterDataModelCollectorLoader( ).list_available() schemas = {k: c.SCHEMA for k, c in collectors.items() if hasattr(c, "SCHEMA")} return schemas @staticmethod def validate(audit_template): available_goals = objects.Goal.list(AuditTemplatePostType._ctx) available_goal_uuids_map = {g.uuid: g for g in available_goals} available_goal_names_map = {g.name: g for g in available_goals} if audit_template.goal in available_goal_uuids_map: goal = available_goal_uuids_map[audit_template.goal] elif audit_template.goal in available_goal_names_map: goal = available_goal_names_map[audit_template.goal] else: raise exception.InvalidGoal(goal=audit_template.goal) if audit_template.scope: common_utils.Draft4Validator( AuditTemplatePostType._build_schema() ).validate(audit_template.scope) include_host_aggregates = False exclude_host_aggregates = False for rule in audit_template.scope[0]['compute']: if 'host_aggregates' in rule: include_host_aggregates = True elif 'exclude' in rule: for resource in rule['exclude']: if 'host_aggregates' in resource: exclude_host_aggregates = True if include_host_aggregates and exclude_host_aggregates: raise exception.Invalid( message=_( "host_aggregates can't be " "included and excluded together")) if audit_template.strategy: available_strategies = objects.Strategy.list( AuditTemplatePostType._ctx) available_strategies_map = { s.uuid: s for s in available_strategies} if audit_template.strategy not in available_strategies_map: raise exception.InvalidStrategy( strategy=audit_template.strategy) strategy = available_strategies_map[audit_template.strategy] # Check that the strategy we indicate is actually related to the # specified goal if strategy.goal_id != goal.id: choices = ["'%s' (%s)" % (s.uuid, s.name) for s in available_strategies] raise exception.InvalidStrategy( message=_( "'%(strategy)s' strategy does relate to the " "'%(goal)s' goal. Possible choices: %(choices)s") % dict(strategy=strategy.name, goal=goal.name, choices=", ".join(choices))) audit_template.strategy = strategy.uuid # We force the UUID so that we do not need to query the DB with the # name afterwards audit_template.goal = goal.uuid return audit_template