def post(self, audit_p): """Create a new audit. :param audit_p: an audit within the request body. """ context = pecan.request.context policy.enforce(context, 'audit:create', action='audit:create') audit = audit_p.as_audit(context) if self.from_audits: raise exception.OperationNotPermitted if not audit._goal_uuid: raise exception.Invalid( message=_('A valid goal_id or audit_template_id ' 'must be provided')) strategy_uuid = audit.strategy_uuid no_schema = True if strategy_uuid is not None: # validate parameter when predefined strategy in audit template strategy = objects.Strategy.get(pecan.request.context, strategy_uuid) schema = strategy.parameters_spec if schema: # validate input parameter with default value feedback no_schema = False utils.StrictDefaultValidatingDraft4Validator(schema).validate( audit.parameters) if no_schema and audit.parameters: raise exception.Invalid( _('Specify parameters but no predefined ' 'strategy for audit, or no ' 'parameter spec in predefined strategy')) audit_dict = audit.as_dict() # convert local time to UTC time start_time_value = audit_dict.get('start_time') end_time_value = audit_dict.get('end_time') if start_time_value: audit_dict['start_time'] = start_time_value.replace( tzinfo=tz.tzlocal()).astimezone( tz.tzutc()).replace(tzinfo=None) if end_time_value: audit_dict['end_time'] = end_time_value.replace( tzinfo=tz.tzlocal()).astimezone( tz.tzutc()).replace(tzinfo=None) new_audit = objects.Audit(context, **audit_dict) new_audit.create() # 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: self.dc_client.trigger_audit(context, new_audit.uuid) return Audit.convert_with_links(new_audit)
def get_user(self, name_or_id): try: user = self.keystone.users.get(name_or_id) return user except ks_exceptions.NotFound: users = self.keystone.users.list(name=name_or_id) if len(users) == 0: raise exception.Invalid(message=(_("User not Found: %s") % name_or_id)) if len(users) > 1: raise exception.Invalid( message=(_("User name seems ambiguous: %s") % name_or_id)) return users[0]
def _cold_migrate(self, volume, dest_node, dest_type): if not self.cinder_util.can_cold(volume, dest_node): raise exception.Invalid( message=(_("Invalid state for cold migration"))) if dest_node: return self.cinder_util.migrate(volume, dest_node) elif dest_type: return self.cinder_util.retype(volume, dest_type) else: raise exception.Invalid( message=(_("destination host or destination type is " "required when migration type is cold")))
def get_role(self, name_or_id): try: role = self.keystone.roles.get(name_or_id) return role except ks_exceptions.NotFound: roles = self.keystone.roles.list(name=name_or_id) if len(roles) == 0: raise exception.Invalid(message=(_("Role not Found: %s") % name_or_id)) if len(roles) > 1: raise exception.Invalid( message=(_("Role name seems ambiguous: %s") % name_or_id)) return roles[0]
def get_domain(self, name_or_id): try: domain = self.keystone.domains.get(name_or_id) return domain except ks_exceptions.NotFound: domains = self.keystone.domains.list(name=name_or_id) if len(domains) == 0: raise exception.Invalid(message=(_("Domain not Found: %s") % name_or_id)) if len(domains) > 1: raise exception.Invalid( message=(_("Domain name seems ambiguous: %s") % name_or_id)) return domains[0]
def get_project(self, name_or_id): try: project = self.keystone.projects.get(name_or_id) return project except ks_exceptions.NotFound: projects = self.keystone.projects.list(name=name_or_id) if len(projects) == 0: raise exception.Invalid(message=(_("Project not Found: %s") % name_or_id)) if len(projects) > 1: raise exception.Invalid( messsage=(_("Project name seems ambiguous: %s") % name_or_id)) return projects[0]
def post(self, audit): """Create a new audit. :param audit: a audit within the request body. """ 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_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 dc_client = rpcapi.DecisionEngineAPI() dc_client.trigger_audit(context, new_audit.uuid) return Audit.convert_with_links(new_audit)
def _migrate(self, volume_id, dest_node, dest_type): try: volume = self.cinder_util.get_volume(volume_id) if self.migration_type == self.SWAP: if dest_node: LOG.warning("dest_node is ignored") return self._swap_volume(volume, dest_type) elif self.migration_type == self.RETYPE: return self.cinder_util.retype(volume, dest_type) elif self.migration_type == self.MIGRATE: return self.cinder_util.migrate(volume, dest_node) else: raise exception.Invalid( message=(_("Migration of type '%(migration_type)s' is not " "supported.") % { 'migration_type': self.migration_type })) except exception.Invalid as ei: LOG.exception(ei) return False except Exception as e: LOG.critical("Unexpected exception occurred.") LOG.exception(e) return False
def update_action_plan(self, action_plan_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing " "Action Plan.")) return self._do_update_action_plan(action_plan_id, values)
def validate(value): try: jsonutils.dumps(value, default=None) except TypeError: raise exception.Invalid(_('%s is not JSON serializable') % value) else: return value
def update_action(self, action_id, values): # NOTE(dtantsur): this can lead to very strange errors if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing Action.")) return self._do_update_action(action_id, values)
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) include_host_aggregates = False exclude_host_aggregates = False for rule in audit_template.scope: 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
def update_audit(self, audit_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing " "Audit.")) return self._do_update_audit(audit_id, values)
def update_goal(self, goal_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing Goal.")) try: return self._update(models.Goal, goal_id, values) except exception.ResourceNotFound: raise exception.GoalNotFound(goal=goal_id)
def update_strategy(self, strategy_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing Strategy.")) try: return self._update(models.Strategy, strategy_id, values) except exception.ResourceNotFound: raise exception.StrategyNotFound(strategy=strategy_id)
def update_audit(self, audit_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing " "Audit.")) try: return self._update(models.Audit, audit_id, values) except exception.ResourceNotFound: raise exception.AuditNotFound(audit=audit_id)
def update_efficacy_indicator(self, efficacy_indicator_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing " "efficacy indicator.")) try: return self._update( models.EfficacyIndicator, efficacy_indicator_id, values) except exception.ResourceNotFound: raise exception.EfficacyIndicatorNotFound( efficacy_indicator=efficacy_indicator_id)
def update_scoring_engine(self, scoring_engine_id, values): if 'uuid' in values: raise exception.Invalid( message=_("Cannot overwrite UUID for an existing " "Scoring Engine.")) try: return self._update( models.ScoringEngine, scoring_engine_id, values) except exception.ResourceNotFound: raise exception.ScoringEngineNotFound( scoring_engine=scoring_engine_id)
def retype(self, volume, dest_type): """Retype volume to dest_type with on-demand option""" volume = self.get_volume(volume) if volume.volume_type == dest_type: raise exception.Invalid( message=(_("Volume type must be different for retyping"))) source_node = getattr(volume, 'os-vol-host-attr:host') LOG.debug("Volume %s found on host '%s'.", (volume.id, source_node)) self.cinder.volumes.retype(volume, dest_type, "on-demand") return self.check_migrated(volume)
def as_audit(self, context): audit_type_values = [val.value for val in objects.audit.AuditType] if self.audit_type not in audit_type_values: raise exception.AuditTypeNotFound(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.ONESHOT.value and self.interval not in (wtypes.Unset, None)): raise exception.AuditIntervalNotAllowed(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.CONTINUOUS.value and self.interval in (wtypes.Unset, None)): raise exception.AuditIntervalNotSpecified( audit_type=self.audit_type) # If audit_template_uuid was provided, we will provide any # variables not included in the request, but not override # those variables that were included. if self.audit_template_uuid: try: audit_template = objects.AuditTemplate.get( context, self.audit_template_uuid) except exception.AuditTemplateNotFound: raise exception.Invalid( message=_('The audit template UUID or name specified is ' 'invalid')) at2a = { 'goal': 'goal_id', 'strategy': 'strategy_id', 'scope': 'scope', } to_string_fields = set(['goal', 'strategy']) for k in at2a: if not getattr(self, k): try: at_attr = getattr(audit_template, at2a[k]) if at_attr and (k in to_string_fields): at_attr = str(at_attr) setattr(self, k, at_attr) except AttributeError: pass return Audit( audit_type=self.audit_type, deadline=self.deadline, parameters=self.parameters, goal_id=self.goal, strategy_id=self.strategy, interval=self.interval, scope=self.scope, )
def migrate(self, volume, dest_node): """Migrate volume to dest_node""" volume = self.get_volume(volume) dest_backend = self.backendname_from_poolname(dest_node) dest_type = self.get_volume_type_by_backendname(dest_backend) if volume.volume_type not in dest_type: raise exception.Invalid( message=(_("Volume type must be same for migrating"))) source_node = getattr(volume, 'os-vol-host-attr:host') LOG.debug("Volume %s found on host '%s'.", (volume.id, source_node)) self.cinder.volumes.migrate_volume(volume, dest_node, False, True) return self.check_migrated(volume)
def _swap_volume(self, volume, dest_type): """Swap volume to dest_type Limitation note: only for compute libvirt driver """ if not dest_type: raise exception.Invalid( message=(_("destination type is required when " "migration type is swap"))) if not self._can_swap(volume): raise exception.Invalid( message=(_("Invalid state for swapping volume"))) user_info = { 'name': self.temp_username, 'password': self.temp_password } user = self._create_user(volume, user_info) keystone_util = keystone_helper.KeystoneHelper(osc=self.osc) try: session = keystone_util.create_session(user.id, self.temp_password) temp_cinder = self._get_cinder_client(session) # swap volume new_volume = self.cinder_util.create_volume( temp_cinder, volume, dest_type) self.nova_util.swap_volume(volume, new_volume) # delete old volume self.cinder_util.delete_volume(volume) finally: keystone_util.delete_user(user) return True
def migrate(self, destination): nova = nova_helper.NovaHelper(osc=self.osc) LOG.debug("Migrate instance %s to %s", self.instance_uuid, destination) instance = nova.find_instance(self.instance_uuid) if instance: if self.migration_type == 'live': return nova.live_migrate_instance( instance_id=self.instance_uuid, dest_hostname=destination) else: raise exception.Invalid( message=(_('Migration of type %(migration_type)s is not ' 'supported.') % { 'migration_type': self.migration_type })) else: raise exception.InstanceNotFound(name=self.instance_uuid)
def migrate(self, destination): nova = nova_helper.NovaHelper(osc=self.osc) LOG.debug("Migrate instance %s to %s", self.instance_uuid, destination) instance = nova.find_instance(self.instance_uuid) if instance: if self.migration_type == self.LIVE_MIGRATION: return self._live_migrate_instance(nova, destination) elif self.migration_type == self.COLD_MIGRATION: return self._cold_migrate_instance(nova, destination) else: raise exception.Invalid( message=(_("Migration of type '%(migration_type)s' is not " "supported.") % { 'migration_type': self.migration_type })) else: raise exception.InstanceNotFound(name=self.instance_uuid)
def _timestamps(self, start_time, end_time): def _format_timestamp(_time): if _time: if isinstance(_time, datetime.datetime): return _time.isoformat() return _time return None start_timestamp = _format_timestamp(start_time) end_timestamp = _format_timestamp(end_time) if ((start_timestamp is not None) and (end_timestamp is not None) and (timeutils.parse_isotime(start_timestamp) > timeutils.parse_isotime(end_timestamp))): raise exception.Invalid( _("Invalid query: %(start_time)s > %(end_time)s") % dict(start_time=start_timestamp, end_time=end_timestamp)) return start_timestamp, end_timestamp
def build_query(self, user_id=None, tenant_id=None, resource_id=None, user_ids=None, tenant_ids=None, resource_ids=None, start_time=None, end_time=None): """Returns query built from given parameters. This query can be then used for querying resources, meters and statistics. :param user_id: user_id, has a priority over list of ids :param tenant_id: tenant_id, has a priority over list of ids :param resource_id: resource_id, has a priority over list of ids :param user_ids: list of user_ids :param tenant_ids: list of tenant_ids :param resource_ids: list of resource_ids :param start_time: datetime from which measurements should be collected :param end_time: datetime until which measurements should be collected """ user_ids = user_ids or [] tenant_ids = tenant_ids or [] resource_ids = resource_ids or [] query = [] if user_id: user_ids = [user_id] for u_id in user_ids: query.append({"field": "user_id", "op": "eq", "value": u_id}) if tenant_id: tenant_ids = [tenant_id] for t_id in tenant_ids: query.append({"field": "project_id", "op": "eq", "value": t_id}) if resource_id: resource_ids = [resource_id] for r_id in resource_ids: query.append({"field": "resource_id", "op": "eq", "value": r_id}) start_timestamp = None end_timestamp = None if start_time: start_timestamp = start_time if isinstance(start_time, datetime.datetime): start_timestamp = start_time.isoformat() if end_time: end_timestamp = end_time if isinstance(end_time, datetime.datetime): end_timestamp = end_time.isoformat() if (start_timestamp and end_timestamp and timeutils.parse_isotime(start_timestamp) > timeutils.parse_isotime(end_timestamp)): raise exception.Invalid( _("Invalid query: %(start_time)s > %(end_time)s") % dict( start_time=start_timestamp, end_time=end_timestamp)) if start_timestamp: query.append({"field": "timestamp", "op": "ge", "value": start_timestamp}) if end_timestamp: query.append({"field": "timestamp", "op": "le", "value": end_timestamp}) return query
def validate(value): try: return strutils.bool_from_string(value, strict=True) except ValueError as e: # raise Invalid to return 400 (BadRequest) in the API raise exception.Invalid(e)
def as_audit(self, context): audit_type_values = [val.value for val in objects.audit.AuditType] if self.audit_type not in audit_type_values: raise exception.AuditTypeNotFound(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.ONESHOT.value and self.interval not in (wtypes.Unset, None)): raise exception.AuditIntervalNotAllowed(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.CONTINUOUS.value and self.interval in (wtypes.Unset, None)): raise exception.AuditIntervalNotSpecified( audit_type=self.audit_type) # If audit_template_uuid was provided, we will provide any # variables not included in the request, but not override # those variables that were included. if self.audit_template_uuid: try: audit_template = objects.AuditTemplate.get( context, self.audit_template_uuid) except exception.AuditTemplateNotFound: raise exception.Invalid( message=_('The audit template UUID or name specified is ' 'invalid')) at2a = { 'goal': 'goal_id', 'strategy': 'strategy_id', 'scope': 'scope', } to_string_fields = set(['goal', 'strategy']) for k in at2a: if not getattr(self, k): try: at_attr = getattr(audit_template, at2a[k]) if at_attr and (k in to_string_fields): at_attr = str(at_attr) setattr(self, k, at_attr) except AttributeError: pass # Note: If audit name was not provided, used a default name if not self.name: if self.strategy: strategy = objects.Strategy.get(context, self.strategy) self.name = "%s-%s" % (strategy.name, datetime.datetime.utcnow().isoformat()) elif self.audit_template_uuid: audit_template = objects.AuditTemplate.get( context, self.audit_template_uuid) self.name = "%s-%s" % (audit_template.name, datetime.datetime.utcnow().isoformat()) else: goal = objects.Goal.get(context, self.goal) self.name = "%s-%s" % (goal.name, datetime.datetime.utcnow().isoformat()) return Audit(name=self.name, audit_type=self.audit_type, parameters=self.parameters, goal_id=self.goal, strategy_id=self.strategy, interval=self.interval, scope=self.scope, auto_trigger=self.auto_trigger)
def as_audit(self, context): audit_type_values = [val.value for val in objects.audit.AuditType] if self.audit_type not in audit_type_values: raise exception.AuditTypeNotFound(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.ONESHOT.value and self.interval not in (wtypes.Unset, None)): raise exception.AuditIntervalNotAllowed(audit_type=self.audit_type) if (self.audit_type == objects.audit.AuditType.CONTINUOUS.value and self.interval in (wtypes.Unset, None)): raise exception.AuditIntervalNotSpecified( audit_type=self.audit_type) if self.audit_template_uuid and self.goal: raise exception.Invalid('Either audit_template_uuid ' 'or goal should be provided.') if (self.audit_type == objects.audit.AuditType.ONESHOT.value and (self.start_time not in (wtypes.Unset, None) or self.end_time not in (wtypes.Unset, None))): raise exception.AuditStartEndTimeNotAllowed( audit_type=self.audit_type) if not api_utils.allow_start_end_audit_time(): for field in ('start_time', 'end_time'): if getattr(self, field) not in (wsme.Unset, None): raise exception.NotAcceptable() # If audit_template_uuid was provided, we will provide any # variables not included in the request, but not override # those variables that were included. if self.audit_template_uuid: try: audit_template = objects.AuditTemplate.get( context, self.audit_template_uuid) except exception.AuditTemplateNotFound: raise exception.Invalid( message=_('The audit template UUID or name specified is ' 'invalid')) at2a = { 'goal': 'goal_id', 'strategy': 'strategy_id', 'scope': 'scope', } to_string_fields = set(['goal', 'strategy']) for k in at2a: if not getattr(self, k): try: at_attr = getattr(audit_template, at2a[k]) if at_attr and (k in to_string_fields): at_attr = str(at_attr) setattr(self, k, at_attr) except AttributeError: pass # Note: If audit name was not provided, used a default name if not self.name: if self.strategy: strategy = _get_object_by_value(context, objects.Strategy, self.strategy) self.name = "%s-%s" % (strategy.name, datetime.datetime.utcnow().isoformat()) elif self.audit_template_uuid: audit_template = objects.AuditTemplate.get( context, self.audit_template_uuid) self.name = "%s-%s" % (audit_template.name, datetime.datetime.utcnow().isoformat()) else: goal = _get_object_by_value(context, objects.Goal, self.goal) self.name = "%s-%s" % (goal.name, datetime.datetime.utcnow().isoformat()) # No more than 63 characters if len(self.name) > 63: LOG.warning("Audit: %s length exceeds 63 characters", self.name) self.name = self.name[0:63] return Audit(name=self.name, audit_type=self.audit_type, parameters=self.parameters, goal_id=self.goal, strategy_id=self.strategy, interval=self.interval, scope=self.scope, auto_trigger=self.auto_trigger, start_time=self.start_time, end_time=self.end_time)