Merge "Add strategy_id & goal_id fields in audit template"

This commit is contained in:
Jenkins
2016-05-11 15:32:10 +00:00
committed by Gerrit Code Review
20 changed files with 614 additions and 341 deletions

View File

@@ -23,8 +23,6 @@ from watcher._i18n import _
from watcher.api import acl from watcher.api import acl
from watcher.api import config as api_config from watcher.api import config as api_config
from watcher.api import middleware from watcher.api import middleware
from watcher.decision_engine.strategy.selection import default \
as strategy_selector
# Register options for the service # Register options for the service
API_SERVICE_OPTS = [ API_SERVICE_OPTS = [
@@ -61,7 +59,6 @@ opt_group = cfg.OptGroup(name='api',
CONF.register_group(opt_group) CONF.register_group(opt_group)
CONF.register_opts(API_SERVICE_OPTS, opt_group) CONF.register_opts(API_SERVICE_OPTS, opt_group)
CONF.register_opts(strategy_selector.WATCHER_GOALS_OPTS)
def get_pecan_config(): def get_pecan_config():

View File

@@ -50,42 +50,146 @@ provided as a list of key-value pairs.
import datetime import datetime
from oslo_config import cfg
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan import wsmeext.pecan as wsme_pecan
from watcher._i18n import _
from watcher.api.controllers import base from watcher.api.controllers import base
from watcher.api.controllers import link from watcher.api.controllers import link
from watcher.api.controllers.v1 import collection from watcher.api.controllers.v1 import collection
from watcher.api.controllers.v1 import types from watcher.api.controllers.v1 import types
from watcher.api.controllers.v1 import utils as api_utils from watcher.api.controllers.v1 import utils as api_utils
from watcher.common import context as context_utils
from watcher.common import exception from watcher.common import exception
from watcher.common import utils as common_utils from watcher.common import utils as common_utils
from watcher import objects from watcher import objects
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"""
host_aggregate = wsme.wsattr(wtypes.IntegerType(minimum=1),
mandatory=False)
"""ID of the Nova host aggregate targeted by the audit template"""
extra = wtypes.wsattr({wtypes.text: types.jsontype}, mandatory=False)
"""The metadata of the audit template"""
goal_uuid = wtypes.wsattr(types.uuid, mandatory=True)
"""Goal UUID of the audit template"""
strategy_uuid = wsme.wsattr(types.uuid, mandatory=False)
"""Strategy UUID of the audit template"""
version = wtypes.text
"""Internal version of the audit template"""
def as_audit_template(self):
related_strategy_uuid = self.strategy_uuid or None
return AuditTemplate(
name=self.name,
description=self.description,
deadline=self.deadline,
host_aggregate=self.host_aggregate,
extra=self.extra,
goal_id=self.goal_uuid, # Dirty trick ...
goal_uuid=self.goal_uuid,
strategy_id=related_strategy_uuid, # Dirty trick ...
strategy_uuid=related_strategy_uuid,
version=self.version,
)
@staticmethod
def validate(audit_template):
available_goals = objects.Goal.list(AuditTemplatePostType._ctx)
available_goals_map = {g.uuid: g for g in available_goals}
if audit_template.goal_uuid not in available_goals_map:
raise exception.InvalidGoal(goal=audit_template.goal_uuid)
if audit_template.strategy_uuid:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)
available_strategies_map = {
s.uuid: s for s in available_strategies}
if audit_template.strategy_uuid not in available_strategies_map:
raise exception.InvalidStrategy(
strategy=audit_template.strategy_uuid)
goal = available_goals_map[audit_template.goal_uuid]
strategy = available_strategies_map[audit_template.strategy_uuid]
# 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)))
return audit_template
class AuditTemplatePatchType(types.JsonPatchType): class AuditTemplatePatchType(types.JsonPatchType):
_ctx = context_utils.make_context()
@staticmethod @staticmethod
def mandatory_attrs(): def mandatory_attrs():
return [] return []
@staticmethod @staticmethod
def validate(patch): def validate(patch):
if patch.path == "/goal": if patch.path == "/goal_uuid" and patch.op != "remove":
AuditTemplatePatchType._validate_goal(patch) AuditTemplatePatchType._validate_goal(patch)
elif patch.path == "/goal_uuid" and patch.op == "remove":
raise exception.OperationNotPermitted(
_("Cannot remove 'goal_uuid' attribute "
"from an audit template"))
if patch.path == "/strategy_uuid":
AuditTemplatePatchType._validate_strategy(patch)
return types.JsonPatchType.validate(patch) return types.JsonPatchType.validate(patch)
@staticmethod @staticmethod
def _validate_goal(patch): def _validate_goal(patch):
serialized_patch = {'path': patch.path, 'op': patch.op} patch.path = "/goal_id"
if patch.value is not wsme.Unset: goal_uuid = patch.value
serialized_patch['value'] = patch.value
new_goal = patch.value if goal_uuid:
if new_goal and new_goal not in cfg.CONF.watcher_goals.goals.keys(): available_goals = objects.Goal.list(
raise exception.InvalidGoal(goal=new_goal) AuditTemplatePatchType._ctx)
available_goals_map = {g.uuid: g for g in available_goals}
if goal_uuid not in available_goals_map:
raise exception.InvalidGoal(goal=goal_uuid)
patch.value = available_goals_map[goal_uuid].id
@staticmethod
def _validate_strategy(patch):
patch.path = "/strategy_id"
strategy_uuid = patch.value
if strategy_uuid:
available_strategies = objects.Strategy.list(
AuditTemplatePatchType._ctx)
available_strategies_map = {
s.uuid: s for s in available_strategies}
if strategy_uuid not in available_strategies_map:
raise exception.InvalidStrategy(strategy=strategy_uuid)
patch.value = available_strategies_map[strategy_uuid].id
class AuditTemplate(base.APIBase): class AuditTemplate(base.APIBase):
@@ -96,6 +200,65 @@ class AuditTemplate(base.APIBase):
audit template. audit template.
""" """
_goal_uuid = None
_strategy_uuid = None
def _get_goal(self, value):
if value == wtypes.Unset:
return None
goal = None
try:
if (common_utils.is_uuid_like(value) or
common_utils.is_int_like(value)):
goal = objects.Goal.get(
pecan.request.context, value)
else:
goal = objects.Goal.get_by_name(
pecan.request.context, value)
except exception.GoalNotFound:
pass
if goal:
self.goal_id = goal.id
return goal
def _get_strategy(self, value):
if value == wtypes.Unset:
return None
strategy = None
try:
if (common_utils.is_uuid_like(value) or
common_utils.is_int_like(value)):
strategy = objects.Strategy.get(
pecan.request.context, value)
else:
strategy = objects.Strategy.get_by_name(
pecan.request.context, value)
except exception.StrategyNotFound:
pass
if strategy:
self.strategy_id = strategy.id
return strategy
def _get_goal_uuid(self):
return self._goal_uuid
def _set_goal_uuid(self, value):
if value and self._goal_uuid != value:
self._goal_uuid = None
goal = self._get_goal(value)
if goal:
self._goal_uuid = goal.uuid
def _get_strategy_uuid(self):
return self._strategy_uuid
def _set_strategy_uuid(self, value):
if value and self._strategy_uuid != value:
self._strategy_uuid = None
strategy = self._get_strategy(value)
if strategy:
self._strategy_uuid = strategy.uuid
uuid = wtypes.wsattr(types.uuid, readonly=True) uuid = wtypes.wsattr(types.uuid, readonly=True)
"""Unique UUID for this audit template""" """Unique UUID for this audit template"""
@@ -114,8 +277,13 @@ class AuditTemplate(base.APIBase):
extra = {wtypes.text: types.jsontype} extra = {wtypes.text: types.jsontype}
"""The metadata of the audit template""" """The metadata of the audit template"""
goal = wtypes.text goal_uuid = wsme.wsproperty(
"""Goal type of the audit template""" wtypes.text, _get_goal_uuid, _set_goal_uuid, mandatory=True)
"""Goal UUID of the audit template"""
strategy_uuid = wsme.wsproperty(
wtypes.text, _get_strategy_uuid, _set_strategy_uuid, mandatory=False)
"""Strategy UUID the audit template"""
version = wtypes.text version = wtypes.text
"""Internal version of the audit template""" """Internal version of the audit template"""
@@ -128,20 +296,38 @@ class AuditTemplate(base.APIBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(AuditTemplate, self).__init__() super(AuditTemplate, self).__init__()
self.fields = [] self.fields = []
for field in objects.AuditTemplate.fields: fields = list(objects.AuditTemplate.fields)
for k in fields:
# Skip fields we do not expose. # Skip fields we do not expose.
if not hasattr(self, field): if not hasattr(self, k):
continue continue
self.fields.append(field) self.fields.append(k)
setattr(self, field, kwargs.get(field, wtypes.Unset)) setattr(self, k, kwargs.get(k, wtypes.Unset))
self.fields.append('goal_id')
self.fields.append('strategy_id')
# goal_uuid & strategy_uuid are not part of
# objects.AuditTemplate.fields because they're API-only attributes.
self.fields.append('goal_uuid')
self.fields.append('strategy_uuid')
setattr(self, 'goal_uuid', kwargs.get('goal_id', wtypes.Unset))
setattr(self, 'strategy_uuid',
kwargs.get('strategy_id', wtypes.Unset))
@staticmethod @staticmethod
def _convert_with_links(audit_template, url, expand=True): def _convert_with_links(audit_template, url, expand=True):
if not expand: if not expand:
audit_template.unset_fields_except(['uuid', 'name', audit_template.unset_fields_except(
'host_aggregate', 'goal']) ['uuid', 'name', 'host_aggregate',
'goal_uuid', 'strategy_uuid'])
# The numeric ID should not be exposed to
# the user, it's internal only.
audit_template.goal_id = wtypes.Unset
audit_template.strategy_id = wtypes.Unset
audit_template.links = [link.Link.make_link('self', url, audit_template.links = [link.Link.make_link('self', url,
'audit_templates', 'audit_templates',
@@ -149,8 +335,7 @@ class AuditTemplate(base.APIBase):
link.Link.make_link('bookmark', url, link.Link.make_link('bookmark', url,
'audit_templates', 'audit_templates',
audit_template.uuid, audit_template.uuid,
bookmark=True) bookmark=True)]
]
return audit_template return audit_template
@classmethod @classmethod
@@ -165,19 +350,14 @@ class AuditTemplate(base.APIBase):
name='My Audit Template', name='My Audit Template',
description='Description of my audit template', description='Description of my audit template',
host_aggregate=5, host_aggregate=5,
goal='DUMMY', goal_uuid='83e44733-b640-40e2-8d8a-7dd3be7134e6',
strategy_uuid='367d826e-b6a4-4b70-bc44-c3f6fe1c9986',
extra={'automatic': True}, extra={'automatic': True},
created_at=datetime.datetime.utcnow(), created_at=datetime.datetime.utcnow(),
deleted_at=None, deleted_at=None,
updated_at=datetime.datetime.utcnow()) updated_at=datetime.datetime.utcnow())
return cls._convert_with_links(sample, 'http://localhost:9322', expand) return cls._convert_with_links(sample, 'http://localhost:9322', expand)
@staticmethod
def validate(audit_template):
if audit_template.goal not in cfg.CONF.watcher_goals.goals.keys():
raise exception.InvalidGoal(audit_template.goal)
return audit_template
class AuditTemplateCollection(collection.Collection): class AuditTemplateCollection(collection.Collection):
"""API representation of a collection of audit templates.""" """API representation of a collection of audit templates."""
@@ -192,12 +372,12 @@ class AuditTemplateCollection(collection.Collection):
@staticmethod @staticmethod
def convert_with_links(rpc_audit_templates, limit, url=None, expand=False, def convert_with_links(rpc_audit_templates, limit, url=None, expand=False,
**kwargs): **kwargs):
collection = AuditTemplateCollection() at_collection = AuditTemplateCollection()
collection.audit_templates = \ at_collection.audit_templates = [
[AuditTemplate.convert_with_links(p, expand) AuditTemplate.convert_with_links(p, expand)
for p in rpc_audit_templates] for p in rpc_audit_templates]
collection.next = collection.get_next(limit, url=url, **kwargs) at_collection.next = at_collection.get_next(limit, url=url, **kwargs)
return collection return at_collection
@classmethod @classmethod
def sample(cls): def sample(cls):
@@ -223,7 +403,8 @@ class AuditTemplatesController(rest.RestController):
sort_key, sort_dir, expand=False, sort_key, sort_dir, expand=False,
resource_url=None): resource_url=None):
api_utils.validate_search_filters( api_utils.validate_search_filters(
filters, objects.audit_template.AuditTemplate.fields.keys()) filters, list(objects.audit_template.AuditTemplate.fields.keys()) +
["goal_uuid", "strategy_uuid"])
limit = api_utils.validate_limit(limit) limit = api_utils.validate_limit(limit)
api_utils.validate_sort_dir(sort_dir) api_utils.validate_sort_dir(sort_dir)
@@ -247,30 +428,33 @@ class AuditTemplatesController(rest.RestController):
sort_key=sort_key, sort_key=sort_key,
sort_dir=sort_dir) sort_dir=sort_dir)
@wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text, @wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, types.uuid,
types.uuid, int, wtypes.text, wtypes.text) types.uuid, int, wtypes.text, wtypes.text)
def get_all(self, goal=None, marker=None, limit=None, def get_all(self, goal_uuid=None, strategy_uuid=None, marker=None,
sort_key='id', sort_dir='asc'): limit=None, sort_key='id', sort_dir='asc'):
"""Retrieve a list of audit templates. """Retrieve a list of audit templates.
:param goal: goal name to filter by (case sensitive) :param goal_uuid: goal UUID to filter by
:param strategy_uuid: strategy UUID to filter by
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id. :param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc. :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
""" """
filters = api_utils.as_filters_dict(goal=goal) filters = api_utils.as_filters_dict(goal_uuid=goal_uuid,
strategy_uuid=strategy_uuid)
return self._get_audit_templates_collection( return self._get_audit_templates_collection(
filters, marker, limit, sort_key, sort_dir) filters, marker, limit, sort_key, sort_dir)
@wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text, types.uuid, int, @wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, types.uuid,
wtypes.text, wtypes.text) types.uuid, int, wtypes.text, wtypes.text)
def detail(self, goal=None, marker=None, limit=None, def detail(self, goal_uuid=None, strategy_uuid=None, marker=None,
sort_key='id', sort_dir='asc'): limit=None, sort_key='id', sort_dir='asc'):
"""Retrieve a list of audit templates with detail. """Retrieve a list of audit templates with detail.
:param goal: goal name to filter by (case sensitive) :param goal_uuid: goal UUID to filter by
:param strategy_uuid: strategy UUID to filter by
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id. :param sort_key: column to sort results by. Default: id.
@@ -281,7 +465,8 @@ class AuditTemplatesController(rest.RestController):
if parent != "audit_templates": if parent != "audit_templates":
raise exception.HTTPNotFound raise exception.HTTPNotFound
filters = api_utils.as_filters_dict(goal=goal) filters = api_utils.as_filters_dict(goal_uuid=goal_uuid,
strategy_uuid=strategy_uuid)
expand = True expand = True
resource_url = '/'.join(['audit_templates', 'detail']) resource_url = '/'.join(['audit_templates', 'detail'])
@@ -309,19 +494,21 @@ class AuditTemplatesController(rest.RestController):
return AuditTemplate.convert_with_links(rpc_audit_template) return AuditTemplate.convert_with_links(rpc_audit_template)
@wsme.validate(types.uuid, AuditTemplate) @wsme.validate(types.uuid, AuditTemplatePostType)
@wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplate, status_code=201) @wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplatePostType,
def post(self, audit_template): status_code=201)
def post(self, audit_template_postdata):
"""Create a new audit template. """Create a new audit template.
:param audit template: a audit template within the request body. :param audit_template_postdata: the audit template POST data
from the request body.
""" """
if self.from_audit_templates: if self.from_audit_templates:
raise exception.OperationNotPermitted raise exception.OperationNotPermitted
audit_template_dict = audit_template.as_dict()
context = pecan.request.context 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, new_audit_template = objects.AuditTemplate(context,
**audit_template_dict) **audit_template_dict)
new_audit_template.create(context) new_audit_template.create(context)

View File

@@ -154,6 +154,10 @@ class InvalidGoal(Invalid):
msg_fmt = _("Goal %(goal)s is invalid") msg_fmt = _("Goal %(goal)s is invalid")
class InvalidStrategy(Invalid):
msg_fmt = _("Strategy %(strategy)s is invalid")
class InvalidUUID(Invalid): class InvalidUUID(Invalid):
msg_fmt = _("Expected a uuid but received %(uuid)s") msg_fmt = _("Expected a uuid but received %(uuid)s")

View File

@@ -289,23 +289,18 @@ class Connection(api.BaseConnection):
def _add_audit_templates_filters(self, query, filters): def _add_audit_templates_filters(self, query, filters):
if filters is None: if filters is None:
filters = [] filters = {}
if 'uuid' in filters: plain_fields = ['uuid', 'name', 'host_aggregate',
query = query.filter_by(uuid=filters['uuid']) 'goal_id', 'strategy_id']
if 'name' in filters: join_fieldmap = {
query = query.filter_by(name=filters['name']) 'goal_uuid': ("uuid", models.Goal),
if 'host_aggregate' in filters: 'strategy_uuid': ("uuid", models.Strategy),
query = query.filter_by(host_aggregate=filters['host_aggregate']) }
if 'goal' in filters:
query = query.filter_by(goal=filters['goal'])
query = self.__add_soft_delete_mixin_filters( return self._add_filters(
query, filters, models.AuditTemplate) query=query, model=models.AuditTemplate, filters=filters,
query = self.__add_timestamp_mixin_filters( plain_fields=plain_fields, join_fieldmap=join_fieldmap)
query, filters, models.AuditTemplate)
return query
def _add_audits_filters(self, query, filters): def _add_audits_filters(self, query, filters):
if filters is None: if filters is None:
@@ -522,7 +517,7 @@ class Connection(api.BaseConnection):
try: try:
self._soft_delete(models.Strategy, strategy_id) self._soft_delete(models.Strategy, strategy_id)
except exception.ResourceNotFound: except exception.ResourceNotFound:
raise exception.GoalNotFound(strategy=strategy_id) raise exception.StrategyNotFound(strategy=strategy_id)
# ### AUDIT TEMPLATES ### # # ### AUDIT TEMPLATES ### #
@@ -558,98 +553,50 @@ class Connection(api.BaseConnection):
name=values['name']) name=values['name'])
return audit_template return audit_template
def get_audit_template_by_id(self, context, audit_template_id): def _get_audit_template(self, context, fieldname, value):
query = model_query(models.AuditTemplate)
query = query.filter_by(id=audit_template_id)
try: try:
audit_template = query.one() return self._get(context, model=models.AuditTemplate,
if not context.show_deleted: fieldname=fieldname, value=value)
if audit_template.deleted_at is not None: except exception.ResourceNotFound:
raise exception.AuditTemplateNotFound( raise exception.AuditTemplateNotFound(audit_template=value)
audit_template=audit_template_id)
return audit_template def get_audit_template_by_id(self, context, audit_template_id):
except exc.NoResultFound: return self._get_audit_template(
raise exception.AuditTemplateNotFound( context, fieldname="id", value=audit_template_id)
audit_template=audit_template_id)
def get_audit_template_by_uuid(self, context, audit_template_uuid): def get_audit_template_by_uuid(self, context, audit_template_uuid):
query = model_query(models.AuditTemplate) return self._get_audit_template(
query = query.filter_by(uuid=audit_template_uuid) context, fieldname="uuid", value=audit_template_uuid)
try:
audit_template = query.one()
if not context.show_deleted:
if audit_template.deleted_at is not None:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_uuid)
return audit_template
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_uuid)
def get_audit_template_by_name(self, context, audit_template_name): def get_audit_template_by_name(self, context, audit_template_name):
query = model_query(models.AuditTemplate) return self._get_audit_template(
query = query.filter_by(name=audit_template_name, context, fieldname="name", value=audit_template_name)
deleted_at=None)
try:
return query.one()
except exc.MultipleResultsFound:
raise exception.Conflict(
_('Multiple audit templates exist with the same name.'
' Please use the audit template uuid instead'))
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_name)
def destroy_audit_template(self, audit_template_id): def destroy_audit_template(self, audit_template_id):
session = get_session() try:
with session.begin(): return self._destroy(models.AuditTemplate, audit_template_id)
query = model_query(models.AuditTemplate, session=session) except exception.ResourceNotFound:
query = add_identity_filter(query, audit_template_id) raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
try:
query.one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
query.delete()
def update_audit_template(self, audit_template_id, values): def update_audit_template(self, audit_template_id, values):
if 'uuid' in values: if 'uuid' in values:
raise exception.Invalid( raise exception.Invalid(
message=_("Cannot overwrite UUID for an existing " message=_("Cannot overwrite UUID for an existing "
"Audit Template.")) "Audit Template."))
try:
return self._do_update_audit_template(audit_template_id, values) return self._update(
models.AuditTemplate, audit_template_id, values)
def _do_update_audit_template(self, audit_template_id, values): except exception.ResourceNotFound:
session = get_session() raise exception.AuditTemplateNotFound(
with session.begin(): audit_template=audit_template_id)
query = model_query(models.AuditTemplate, session=session)
query = add_identity_filter(query, audit_template_id)
try:
ref = query.with_lockmode('update').one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
ref.update(values)
return ref
def soft_delete_audit_template(self, audit_template_id): def soft_delete_audit_template(self, audit_template_id):
session = get_session() try:
with session.begin(): self._soft_delete(models.AuditTemplate, audit_template_id)
query = model_query(models.AuditTemplate, session=session) except exception.ResourceNotFound:
query = add_identity_filter(query, audit_template_id) raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
try:
query.one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
query.soft_delete()
# ### AUDITS ### # # ### AUDITS ### #

View File

@@ -152,7 +152,8 @@ class AuditTemplate(Base):
name = Column(String(63), nullable=True) name = Column(String(63), nullable=True)
description = Column(String(255), nullable=True) description = Column(String(255), nullable=True)
host_aggregate = Column(Integer, nullable=True) host_aggregate = Column(Integer, nullable=True)
goal = Column(String(63), nullable=True) goal_id = Column(Integer, ForeignKey('goals.id'), nullable=False)
strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=True)
extra = Column(JSONEncodedDict) extra = Column(JSONEncodedDict)
version = Column(String(15), nullable=True) version = Column(String(15), nullable=True)

View File

@@ -52,8 +52,8 @@ class DefaultStrategyContext(base.BaseStrategyContext):
cluster_data_model = collector_manager.get_latest_cluster_data_model() cluster_data_model = collector_manager.get_latest_cluster_data_model()
strategy_selector = default.DefaultStrategySelector( strategy_selector = default.DefaultStrategySelector(
goal_name=objects.Goal.get_by_name( goal_name=objects.Goal.get_by_id(
request_context, audit_template.goal).name, request_context, audit_template.goal_id).name,
strategy_name=None, strategy_name=None,
osc=osc) osc=osc)

View File

@@ -65,7 +65,8 @@ class AuditTemplate(base.WatcherObject):
'uuid': obj_utils.str_or_none, 'uuid': obj_utils.str_or_none,
'name': obj_utils.str_or_none, 'name': obj_utils.str_or_none,
'description': obj_utils.str_or_none, 'description': obj_utils.str_or_none,
'goal': obj_utils.str_or_none, 'goal_id': obj_utils.int_or_none,
'strategy_id': obj_utils.int_or_none,
'host_aggregate': obj_utils.int_or_none, 'host_aggregate': obj_utils.int_or_none,
'extra': obj_utils.dict_or_none, 'extra': obj_utils.dict_or_none,
'version': obj_utils.str_or_none, 'version': obj_utils.str_or_none,
@@ -83,8 +84,7 @@ class AuditTemplate(base.WatcherObject):
@staticmethod @staticmethod
def _from_db_object_list(db_objects, cls, context): def _from_db_object_list(db_objects, cls, context):
"""Converts a list of database entities to a list of formal objects.""" """Converts a list of database entities to a list of formal objects."""
return \ return [AuditTemplate._from_db_object(cls(context), obj)
[AuditTemplate._from_db_object(cls(context), obj)
for obj in db_objects] for obj in db_objects]
@classmethod @classmethod

View File

@@ -21,18 +21,30 @@ from wsme import types as wtypes
from watcher.api.controllers.v1 import audit_template as api_audit_template from watcher.api.controllers.v1 import audit_template as api_audit_template
from watcher.common import exception from watcher.common import exception
from watcher.common import utils from watcher.common import utils
from watcher.db import api as db_api
from watcher import objects from watcher import objects
from watcher.tests.api import base as api_base from watcher.tests.api import base as api_base
from watcher.tests.api import utils as api_utils from watcher.tests.api import utils as api_utils
from watcher.tests import base from watcher.tests import base
from watcher.tests.db import utils as db_utils
from watcher.tests.objects import utils as obj_utils from watcher.tests.objects import utils as obj_utils
def post_get_test_audit_template(**kw):
audit_template = api_utils.audit_template_post_data(**kw)
goal = db_utils.get_test_goal()
strategy = db_utils.get_test_strategy(goal_id=goal['id'])
del audit_template['uuid']
del audit_template['goal_id']
del audit_template['strategy_id']
audit_template['goal_uuid'] = kw.get('goal_uuid', goal['uuid'])
audit_template['strategy_uuid'] = kw.get('strategy_uuid', strategy['uuid'])
return audit_template
class TestAuditTemplateObject(base.TestCase): class TestAuditTemplateObject(base.TestCase):
def test_audit_template_init(self): def test_audit_template_init(self):
audit_template_dict = api_utils.audit_template_post_data() audit_template_dict = post_get_test_audit_template()
del audit_template_dict['name'] del audit_template_dict['name']
audit_template = api_audit_template.AuditTemplate( audit_template = api_audit_template.AuditTemplate(
**audit_template_dict) **audit_template_dict)
@@ -41,12 +53,21 @@ class TestAuditTemplateObject(base.TestCase):
class TestListAuditTemplate(api_base.FunctionalTest): class TestListAuditTemplate(api_base.FunctionalTest):
def setUp(self):
super(self.__class__, self).setUp()
self.fake_goal1 = obj_utils.get_test_goal(
self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1")
self.fake_goal2 = obj_utils.get_test_goal(
self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2")
self.fake_goal1.create()
self.fake_goal2.create()
def test_empty(self): def test_empty(self):
response = self.get_json('/audit_templates') response = self.get_json('/audit_templates')
self.assertEqual([], response['audit_templates']) self.assertEqual([], response['audit_templates'])
def _assert_audit_template_fields(self, audit_template): def _assert_audit_template_fields(self, audit_template):
audit_template_fields = ['name', 'goal', 'host_aggregate'] audit_template_fields = ['name', 'goal_uuid', 'host_aggregate']
for field in audit_template_fields: for field in audit_template_fields:
self.assertIn(field, audit_template) self.assertIn(field, audit_template)
@@ -57,7 +78,7 @@ class TestListAuditTemplate(api_base.FunctionalTest):
response['audit_templates'][0]["uuid"]) response['audit_templates'][0]["uuid"])
self._assert_audit_template_fields(response['audit_templates'][0]) self._assert_audit_template_fields(response['audit_templates'][0])
def test_one_soft_deleted(self): def test_get_one_soft_deleted_ok(self):
audit_template = obj_utils.create_test_audit_template(self.context) audit_template = obj_utils.create_test_audit_template(self.context)
audit_template.soft_delete() audit_template.soft_delete()
response = self.get_json('/audit_templates', response = self.get_json('/audit_templates',
@@ -208,23 +229,21 @@ class TestListAuditTemplate(api_base.FunctionalTest):
next_marker = response['audit_templates'][-1]['uuid'] next_marker = response['audit_templates'][-1]['uuid']
self.assertIn(next_marker, response['next']) self.assertIn(next_marker, response['next'])
def test_filter_by_goal(self): def test_filter_by_goal_uuid(self):
cfg.CONF.set_override('goals', {"DUMMY": "DUMMY", "BASIC": "BASIC"}, for id_ in range(1, 3):
group='watcher_goals', enforce_type=True)
for id_ in range(2):
obj_utils.create_test_audit_template( obj_utils.create_test_audit_template(
self.context, id=id_, uuid=utils.generate_uuid(), self.context, id=id_, uuid=utils.generate_uuid(),
name='My Audit Template {0}'.format(id_), name='My Audit Template {0}'.format(id_),
goal="DUMMY") goal_id=self.fake_goal1.id)
for id_ in range(2, 5): for id_ in range(3, 6):
obj_utils.create_test_audit_template( obj_utils.create_test_audit_template(
self.context, id=id_, uuid=utils.generate_uuid(), self.context, id=id_, uuid=utils.generate_uuid(),
name='My Audit Template {0}'.format(id_), name='My Audit Template {0}'.format(id_),
goal="BASIC") goal_id=self.fake_goal2.id)
response = self.get_json('/audit_templates?goal=BASIC') response = self.get_json(
'/audit_templates?goal_uuid=%s' % self.fake_goal2.uuid)
self.assertEqual(3, len(response['audit_templates'])) self.assertEqual(3, len(response['audit_templates']))
@@ -233,63 +252,66 @@ class TestPatch(api_base.FunctionalTest):
def setUp(self): def setUp(self):
super(TestPatch, self).setUp() super(TestPatch, self).setUp()
self.audit_template = obj_utils.create_test_audit_template( self.audit_template = obj_utils.create_test_audit_template(
self.context) self.context, strategy_id=None)
p = mock.patch.object(db_api.BaseConnection, 'update_audit_template') self.fake_goal1 = obj_utils.get_test_goal(
self.mock_audit_template_update = p.start() self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1")
self.mock_audit_template_update.side_effect = \ self.fake_goal2 = obj_utils.get_test_goal(
self._simulate_rpc_audit_template_update self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2")
cfg.CONF.set_override('goals', {"DUMMY": "DUMMY", "BASIC": "BASIC"}, self.fake_goal1.create()
group='watcher_goals', enforce_type=True) self.fake_goal2.create()
self.addCleanup(p.stop) self.fake_strategy1 = obj_utils.get_test_strategy(
self.context, id=1, uuid=utils.generate_uuid(), name="STRATEGY_1",
goal_id=self.fake_goal1.id)
self.fake_strategy2 = obj_utils.get_test_strategy(
self.context, id=2, uuid=utils.generate_uuid(), name="STRATEGY_2",
goal_id=self.fake_goal2.id)
self.fake_strategy1.create()
self.fake_strategy2.create()
def _simulate_rpc_audit_template_update(self, audit_template): @mock.patch.object(timeutils, 'utcnow')
audit_template.save() def test_replace_goal_uuid(self, mock_utcnow):
return audit_template
@mock.patch('oslo_utils.timeutils.utcnow')
def test_replace_ok(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0) test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time mock_utcnow.return_value = test_time
new_goal = "BASIC" new_goal_uuid = self.fake_goal2.uuid
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid) '/audit_templates/%s' % self.audit_template.uuid)
self.assertNotEqual(new_goal, response['goal']) self.assertNotEqual(new_goal_uuid, response['goal_uuid'])
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid, '/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/goal', 'value': new_goal, [{'path': '/goal_uuid', 'value': new_goal_uuid,
'op': 'replace'}]) 'op': 'replace'}])
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_code) self.assertEqual(200, response.status_code)
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid) '/audit_templates/%s' % self.audit_template.uuid)
self.assertEqual(new_goal, response['goal']) self.assertEqual(new_goal_uuid, response['goal_uuid'])
return_updated_at = timeutils.parse_isotime( return_updated_at = timeutils.parse_isotime(
response['updated_at']).replace(tzinfo=None) response['updated_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_updated_at) self.assertEqual(test_time, return_updated_at)
@mock.patch('oslo_utils.timeutils.utcnow') @mock.patch.object(timeutils, 'utcnow')
def test_replace_ok_by_name(self, mock_utcnow): def test_replace_goal_uuid_by_name(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0) test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time mock_utcnow.return_value = test_time
new_goal = 'BASIC' new_goal_uuid = self.fake_goal2.uuid
response = self.get_json(urlparse.quote( response = self.get_json(urlparse.quote(
'/audit_templates/%s' % self.audit_template.name)) '/audit_templates/%s' % self.audit_template.name))
self.assertNotEqual(new_goal, response['goal']) self.assertNotEqual(new_goal_uuid, response['goal_uuid'])
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % self.audit_template.name, '/audit_templates/%s' % self.audit_template.name,
[{'path': '/goal', 'value': new_goal, [{'path': '/goal_uuid', 'value': new_goal_uuid,
'op': 'replace'}]) 'op': 'replace'}])
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_code) self.assertEqual(200, response.status_code)
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.name) '/audit_templates/%s' % self.audit_template.name)
self.assertEqual(new_goal, response['goal']) self.assertEqual(new_goal_uuid, response['goal_uuid'])
return_updated_at = timeutils.parse_isotime( return_updated_at = timeutils.parse_isotime(
response['updated_at']).replace(tzinfo=None) response['updated_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_updated_at) self.assertEqual(test_time, return_updated_at)
@@ -297,8 +319,8 @@ class TestPatch(api_base.FunctionalTest):
def test_replace_non_existent_audit_template(self): def test_replace_non_existent_audit_template(self):
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % utils.generate_uuid(), '/audit_templates/%s' % utils.generate_uuid(),
[{'path': '/goal', 'value': 'DUMMY', [{'path': '/goal_uuid', 'value': self.fake_goal1.uuid,
'op': 'replace'}], 'op': 'replace'}],
expect_errors=True) expect_errors=True)
self.assertEqual(404, response.status_int) self.assertEqual(404, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@@ -312,23 +334,61 @@ class TestPatch(api_base.FunctionalTest):
) as cn_mock: ) as cn_mock:
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid, '/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/goal', 'value': 'INVALID_GOAL', [{'path': '/goal_uuid', 'value': utils.generate_uuid(),
'op': 'replace'}], 'op': 'replace'}],
expect_errors=True) expect_errors=True)
self.assertEqual(400, response.status_int) self.assertEqual(400, response.status_int)
assert not cn_mock.called assert not cn_mock.called
def test_add_ok(self): def test_add_goal_uuid(self):
new_goal = 'DUMMY'
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid, '/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/goal', 'value': new_goal, 'op': 'add'}]) [{'path': '/goal_uuid',
'value': self.fake_goal2.uuid,
'op': 'add'}])
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_int) self.assertEqual(200, response.status_int)
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid) '/audit_templates/%s' % self.audit_template.uuid)
self.assertEqual(new_goal, response['goal']) self.assertEqual(self.fake_goal2.uuid, response['goal_uuid'])
def test_add_strategy_uuid(self):
response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/strategy_uuid',
'value': self.fake_strategy1.uuid,
'op': 'add'}])
self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_int)
response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid)
self.assertEqual(self.fake_strategy1.uuid, response['strategy_uuid'])
def test_replace_strategy_uuid(self):
response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/strategy_uuid',
'value': self.fake_strategy2['uuid'],
'op': 'replace'}])
self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_int)
response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid)
self.assertEqual(
self.fake_strategy2['uuid'], response['strategy_uuid'])
def test_replace_invalid_strategy(self):
response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/strategy_uuid',
'value': utils.generate_uuid(), # Does not exist
'op': 'replace'}], expect_errors=True)
self.assertEqual('application/json', response.content_type)
self.assertEqual(400, response.status_int)
self.assertTrue(response.json['error_message'])
def test_add_non_existent_property(self): def test_add_non_existent_property(self):
response = self.patch_json( response = self.patch_json(
@@ -339,20 +399,34 @@ class TestPatch(api_base.FunctionalTest):
self.assertEqual(400, response.status_int) self.assertEqual(400, response.status_int)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
def test_remove_ok(self): def test_remove_strategy(self):
audit_template = obj_utils.create_test_audit_template(
self.context, uuid=utils.generate_uuid(),
name="AT_%s" % utils.generate_uuid(),
goal_id=self.fake_goal1.id,
strategy_id=self.fake_strategy1.id)
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid) '/audit_templates/%s' % audit_template.uuid)
self.assertIsNotNone(response['goal']) self.assertIsNotNone(response['strategy_uuid'])
response = self.patch_json( response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid, '/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/goal', 'op': 'remove'}]) [{'path': '/strategy_uuid', 'op': 'remove'}])
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(200, response.status_code) self.assertEqual(200, response.status_code)
def test_remove_goal(self):
response = self.get_json( response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid) '/audit_templates/%s' % self.audit_template.uuid)
self.assertIsNone(response['goal']) self.assertIsNotNone(response['goal_uuid'])
response = self.patch_json(
'/audit_templates/%s' % self.audit_template.uuid,
[{'path': '/goal_uuid', 'op': 'remove'}],
expect_errors=True)
self.assertEqual(403, response.status_code)
self.assertEqual('application/json', response.content_type)
self.assertTrue(response.json['error_message'])
def test_remove_uuid(self): def test_remove_uuid(self):
response = self.patch_json( response = self.patch_json(
@@ -377,22 +451,29 @@ class TestPost(api_base.FunctionalTest):
def setUp(self): def setUp(self):
super(TestPost, self).setUp() super(TestPost, self).setUp()
p = mock.patch.object(db_api.BaseConnection, 'create_audit_template')
self.mock_create_audit_template = p.start()
self.mock_create_audit_template.side_effect = (
self._simulate_rpc_audit_template_create)
self.addCleanup(p.stop)
def _simulate_rpc_audit_template_create(self, audit_template): self.fake_goal1 = obj_utils.get_test_goal(
audit_template.create() self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1")
return audit_template self.fake_goal2 = obj_utils.get_test_goal(
self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2")
self.fake_goal1.create()
self.fake_goal2.create()
self.fake_strategy1 = obj_utils.get_test_strategy(
self.context, id=1, uuid=utils.generate_uuid(), name="STRATEGY_1",
goal_id=self.fake_goal1.id)
self.fake_strategy2 = obj_utils.get_test_strategy(
self.context, id=2, uuid=utils.generate_uuid(), name="STRATEGY_2",
goal_id=self.fake_goal2.id)
self.fake_strategy1.create()
self.fake_strategy2.create()
@mock.patch('oslo_utils.timeutils.utcnow') @mock.patch.object(timeutils, 'utcnow')
def test_create_audit_template(self, mock_utcnow): def test_create_audit_template(self, mock_utcnow):
audit_template_dict = api_utils.audit_template_post_data() audit_template_dict = post_get_test_audit_template(
goal_uuid=self.fake_goal1.uuid,
strategy_uuid=self.fake_strategy1.uuid)
test_time = datetime.datetime(2000, 1, 1, 0, 0) test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time mock_utcnow.return_value = test_time
del audit_template_dict['uuid']
response = self.post_json('/audit_templates', audit_template_dict) response = self.post_json('/audit_templates', audit_template_dict)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@@ -403,36 +484,37 @@ class TestPost(api_base.FunctionalTest):
'/v1/audit_templates/%s' % response.json['uuid'] '/v1/audit_templates/%s' % response.json['uuid']
self.assertEqual(urlparse.urlparse(response.location).path, self.assertEqual(urlparse.urlparse(response.location).path,
expected_location) expected_location)
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
self.assertNotIn('updated_at', response.json.keys) self.assertNotIn('updated_at', response.json.keys)
self.assertNotIn('deleted_at', response.json.keys) self.assertNotIn('deleted_at', response.json.keys)
self.assertEqual(self.fake_goal1.uuid, response.json['goal_uuid'])
self.assertEqual(self.fake_strategy1.uuid,
response.json['strategy_uuid'])
return_created_at = timeutils.parse_isotime( return_created_at = timeutils.parse_isotime(
response.json['created_at']).replace(tzinfo=None) response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at) self.assertEqual(test_time, return_created_at)
def test_create_audit_template_doesnt_contain_id(self): def test_create_audit_template_does_autogenerate_id(self):
audit_template_dict = post_get_test_audit_template(
goal_uuid=self.fake_goal1.uuid, strategy_uuid=None)
with mock.patch.object( with mock.patch.object(
self.dbapi, self.dbapi,
'create_audit_template', 'create_audit_template',
wraps=self.dbapi.create_audit_template wraps=self.dbapi.create_audit_template
) as cn_mock: ) as cn_mock:
audit_template_dict = api_utils.audit_template_post_data(
goal='DUMMY')
del audit_template_dict['uuid']
response = self.post_json('/audit_templates', audit_template_dict) response = self.post_json('/audit_templates', audit_template_dict)
self.assertEqual(audit_template_dict['goal'], self.assertEqual(audit_template_dict['goal_uuid'],
response.json['goal']) response.json['goal_uuid'])
cn_mock.assert_called_once_with(mock.ANY) # Check that 'id' is not in first arg of positional args
# Check that 'id' is not in first arg of positional args self.assertNotIn('id', cn_mock.call_args[0][0])
self.assertNotIn('id', cn_mock.call_args[0][0])
def test_create_audit_template_generate_uuid(self): def test_create_audit_template_generate_uuid(self):
audit_template_dict = api_utils.audit_template_post_data() audit_template_dict = post_get_test_audit_template(
del audit_template_dict['uuid'] goal_uuid=self.fake_goal1.uuid, strategy_uuid=None)
response = self.post_json('/audit_templates', audit_template_dict) response = self.post_json('/audit_templates', audit_template_dict)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int) self.assertEqual(201, response.status_int)
self.assertEqual(audit_template_dict['goal'], response.json['goal'])
self.assertTrue(utils.is_uuid_like(response.json['uuid'])) self.assertTrue(utils.is_uuid_like(response.json['uuid']))
def test_create_audit_template_with_invalid_goal(self): def test_create_audit_template_with_invalid_goal(self):
@@ -441,8 +523,36 @@ class TestPost(api_base.FunctionalTest):
'create_audit_template', 'create_audit_template',
wraps=self.dbapi.create_audit_template wraps=self.dbapi.create_audit_template
) as cn_mock: ) as cn_mock:
audit_template_dict = api_utils.audit_template_post_data( audit_template_dict = post_get_test_audit_template(
goal='INVALID_GOAL') goal_uuid=utils.generate_uuid())
response = self.post_json('/audit_templates',
audit_template_dict, expect_errors=True)
self.assertEqual(400, response.status_int)
assert not cn_mock.called
def test_create_audit_template_with_invalid_strategy(self):
with mock.patch.object(
self.dbapi,
'create_audit_template',
wraps=self.dbapi.create_audit_template
) as cn_mock:
audit_template_dict = post_get_test_audit_template(
goal_uuid=self.fake_goal1['uuid'],
strategy_uuid=utils.generate_uuid())
response = self.post_json('/audit_templates',
audit_template_dict, expect_errors=True)
self.assertEqual(400, response.status_int)
assert not cn_mock.called
def test_create_audit_template_with_unrelated_strategy(self):
with mock.patch.object(
self.dbapi,
'create_audit_template',
wraps=self.dbapi.create_audit_template
) as cn_mock:
audit_template_dict = post_get_test_audit_template(
goal_uuid=self.fake_goal1['uuid'],
strategy_uuid=self.fake_strategy2['uuid'])
response = self.post_json('/audit_templates', response = self.post_json('/audit_templates',
audit_template_dict, expect_errors=True) audit_template_dict, expect_errors=True)
self.assertEqual(400, response.status_int) self.assertEqual(400, response.status_int)
@@ -454,8 +564,7 @@ class TestPost(api_base.FunctionalTest):
'create_audit_template', 'create_audit_template',
wraps=self.dbapi.create_audit_template wraps=self.dbapi.create_audit_template
) as cn_mock: ) as cn_mock:
audit_template_dict = api_utils.audit_template_post_data() audit_template_dict = post_get_test_audit_template()
response = self.post_json('/audit_templates', audit_template_dict, response = self.post_json('/audit_templates', audit_template_dict,
expect_errors=True) expect_errors=True)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@@ -469,54 +578,53 @@ class TestDelete(api_base.FunctionalTest):
super(TestDelete, self).setUp() super(TestDelete, self).setUp()
self.audit_template = obj_utils.create_test_audit_template( self.audit_template = obj_utils.create_test_audit_template(
self.context) self.context)
p = mock.patch.object(db_api.BaseConnection, 'update_audit_template')
self.mock_audit_template_update = p.start()
self.mock_audit_template_update.side_effect = \
self._simulate_rpc_audit_template_update
self.addCleanup(p.stop)
def _simulate_rpc_audit_template_update(self, audit_template): @mock.patch.object(timeutils, 'utcnow')
audit_template.save()
return audit_template
@mock.patch('oslo_utils.timeutils.utcnow')
def test_delete_audit_template_by_uuid(self, mock_utcnow): def test_delete_audit_template_by_uuid(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
self.delete('/audit_templates/%s' % self.audit_template.uuid)
response = self.get_json(
'/audit_templates/%s' % self.audit_template.uuid,
expect_errors=True)
# self.assertEqual(404, response.status_int)
self.assertEqual('application/json', response.content_type)
self.assertTrue(response.json['error_message'])
self.context.show_deleted = True
audit_template = objects.AuditTemplate.get_by_uuid(
self.context, self.audit_template.uuid)
return_deleted_at = timeutils.strtime(audit_template['deleted_at'])
self.assertEqual(timeutils.strtime(test_time), return_deleted_at)
@mock.patch('oslo_utils.timeutils.utcnow')
def test_delete_audit_template_by_name(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0) test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time mock_utcnow.return_value = test_time
self.delete(urlparse.quote('/audit_templates/%s' % self.delete(urlparse.quote('/audit_templates/%s' %
self.audit_template.name)) self.audit_template.uuid))
response = self.get_json(urlparse.quote( response = self.get_json(
'/audit_templates/%s' % self.audit_template.name), urlparse.quote('/audit_templates/%s' % self.audit_template.uuid),
expect_errors=True) expect_errors=True)
self.assertEqual(404, response.status_int) self.assertEqual(404, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
self.assertRaises(exception.AuditTemplateNotFound,
objects.AuditTemplate.get_by_uuid,
self.context,
self.audit_template.uuid)
self.context.show_deleted = True self.context.show_deleted = True
at = objects.AuditTemplate.get_by_uuid(self.context,
self.audit_template.uuid)
self.assertEqual(self.audit_template.name, at.name)
@mock.patch.object(timeutils, 'utcnow')
def test_delete_audit_template_by_name(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
self.delete(urlparse.quote('/audit_templates/%s' %
self.audit_template.name))
response = self.get_json(
urlparse.quote('/audit_templates/%s' % self.audit_template.name),
expect_errors=True)
self.assertEqual(404, response.status_int)
self.assertEqual('application/json', response.content_type)
self.assertTrue(response.json['error_message'])
self.assertRaises(exception.AuditTemplateNotFound, self.assertRaises(exception.AuditTemplateNotFound,
objects.AuditTemplate.get_by_name, objects.AuditTemplate.get_by_name,
self.context, self.context,
self.audit_template.name) self.audit_template.name)
self.context.show_deleted = True
at = objects.AuditTemplate.get_by_name(self.context,
self.audit_template.name)
self.assertEqual(self.audit_template.uuid, at.uuid)
def test_delete_audit_template_not_found(self): def test_delete_audit_template_not_found(self):
uuid = utils.generate_uuid() uuid = utils.generate_uuid()
response = self.delete( response = self.delete(

View File

@@ -30,7 +30,8 @@ class SqlAlchemyCustomTypesTestCase(base.DbTestCase):
def test_JSONEncodedDict_default_value(self): def test_JSONEncodedDict_default_value(self):
# Create audit_template w/o extra # Create audit_template w/o extra
audit_template1_id = w_utils.generate_uuid() audit_template1_id = w_utils.generate_uuid()
self.dbapi.create_audit_template({'uuid': audit_template1_id}) self.dbapi.create_audit_template({'uuid': audit_template1_id,
'goal_id': "DUMMY"})
audit_template1 = sa_api.model_query(models.AuditTemplate) \ audit_template1 = sa_api.model_query(models.AuditTemplate) \
.filter_by(uuid=audit_template1_id).one() .filter_by(uuid=audit_template1_id).one()
self.assertEqual({}, audit_template1.extra) self.assertEqual({}, audit_template1.extra)
@@ -39,6 +40,7 @@ class SqlAlchemyCustomTypesTestCase(base.DbTestCase):
# Create audit_template with extra # Create audit_template with extra
audit_template2_id = w_utils.generate_uuid() audit_template2_id = w_utils.generate_uuid()
self.dbapi.create_audit_template({'uuid': audit_template2_id, self.dbapi.create_audit_template({'uuid': audit_template2_id,
'goal_id': "DUMMY",
'extra': {'bar': 'foo'}}) 'extra': {'bar': 'foo'}})
audit_template2 = sa_api.model_query(models.AuditTemplate) \ audit_template2 = sa_api.model_query(models.AuditTemplate) \
.filter_by(uuid=audit_template2_id).one() .filter_by(uuid=audit_template2_id).one()
@@ -48,24 +50,3 @@ class SqlAlchemyCustomTypesTestCase(base.DbTestCase):
self.assertRaises(db_exc.DBError, self.assertRaises(db_exc.DBError,
self.dbapi.create_audit_template, self.dbapi.create_audit_template,
{'extra': ['this is not a dict']}) {'extra': ['this is not a dict']})
# def test_JSONEncodedList_default_value(self):
# # Create audit_template w/o images
# audit_template1_id = w_utils.generate_uuid()
# self.dbapi.create_audit_template({'uuid': audit_template1_id})
# audit_template1 = sa_api.model_query(models.AuditTemplate) \
# .filter_by(uuid=audit_template1_id).one()
# self.assertEqual([], audit_template1.images)
# # Create audit_template with images
# audit_template2_id = w_utils.generate_uuid()
# self.dbapi.create_audit_template({'uuid': audit_template2_id,
# 'images': ['myimage1', 'myimage2']})
# audit_template2 = sa_api.model_query(models.AuditTemplate) \
# .filter_by(uuid=audit_template2_id).one()
# self.assertEqual(['myimage1', 'myimage2'], audit_template2.images)
# def test_JSONEncodedList_type_check(self):
# self.assertRaises(db_exc.DBError,
# self.dbapi.create_audit_template,
# {'images': {'this is not a list': 'test'}})

View File

@@ -21,7 +21,8 @@ def get_test_audit_template(**kwargs):
return { return {
'id': kwargs.get('id', 1), 'id': kwargs.get('id', 1),
'uuid': kwargs.get('uuid', 'e74c40e0-d825-11e2-a28f-0800200c9a66'), 'uuid': kwargs.get('uuid', 'e74c40e0-d825-11e2-a28f-0800200c9a66'),
'goal': kwargs.get('goal', 'DUMMY'), 'goal_id': kwargs.get('goal_id', 1),
'strategy_id': kwargs.get('strategy_id', None),
'name': kwargs.get('name', 'My Audit Template'), 'name': kwargs.get('name', 'My Audit Template'),
'description': kwargs.get('description', 'Desc. Of My Audit Template'), 'description': kwargs.get('description', 'Desc. Of My Audit Template'),
'extra': kwargs.get('extra', {'automatic': False}), 'extra': kwargs.get('extra', {'automatic': False}),

View File

@@ -14,10 +14,9 @@
# under the License. # under the License.
import mock import mock
from testtools.matchers import HasLength
from watcher.common import exception from watcher.common import exception
# from watcher.common import utils as w_utils from watcher.common import utils as w_utils
from watcher import objects from watcher import objects
from watcher.tests.db import base from watcher.tests.db import base
from watcher.tests.db import utils from watcher.tests.db import utils
@@ -28,6 +27,10 @@ class TestAuditTemplateObject(base.DbTestCase):
def setUp(self): def setUp(self):
super(TestAuditTemplateObject, self).setUp() super(TestAuditTemplateObject, self).setUp()
self.fake_audit_template = utils.get_test_audit_template() self.fake_audit_template = utils.get_test_audit_template()
self.fake_goal1 = utils.create_test_goal(
id=1, uuid=w_utils.generate_uuid(), name="DUMMY")
self.fake_goal2 = utils.create_test_goal(
id=2, uuid=w_utils.generate_uuid(), name="BALANCE_LOAD")
def test_get_by_id(self): def test_get_by_id(self):
audit_template_id = self.fake_audit_template['id'] audit_template_id = self.fake_audit_template['id']
@@ -71,7 +74,7 @@ class TestAuditTemplateObject(base.DbTestCase):
mock_get_list.return_value = [self.fake_audit_template] mock_get_list.return_value = [self.fake_audit_template]
audit_templates = objects.AuditTemplate.list(self.context) audit_templates = objects.AuditTemplate.list(self.context)
self.assertEqual(1, mock_get_list.call_count) self.assertEqual(1, mock_get_list.call_count)
self.assertThat(audit_templates, HasLength(1)) self.assertEqual(1, len(audit_templates))
self.assertIsInstance(audit_templates[0], objects.AuditTemplate) self.assertIsInstance(audit_templates[0], objects.AuditTemplate)
self.assertEqual(self.context, audit_templates[0]._context) self.assertEqual(self.context, audit_templates[0]._context)
@@ -112,29 +115,29 @@ class TestAuditTemplateObject(base.DbTestCase):
as mock_update_audit_template: as mock_update_audit_template:
audit_template = objects.AuditTemplate.get_by_uuid( audit_template = objects.AuditTemplate.get_by_uuid(
self.context, uuid) self.context, uuid)
audit_template.goal = 'DUMMY' audit_template.goal_id = self.fake_goal1.id
audit_template.save() audit_template.save()
mock_get_audit_template.assert_called_once_with( mock_get_audit_template.assert_called_once_with(
self.context, uuid) self.context, uuid)
mock_update_audit_template.assert_called_once_with( mock_update_audit_template.assert_called_once_with(
uuid, {'goal': 'DUMMY'}) uuid, {'goal_id': self.fake_goal1.id})
self.assertEqual(self.context, audit_template._context) self.assertEqual(self.context, audit_template._context)
def test_refresh(self): def test_refresh(self):
uuid = self.fake_audit_template['uuid'] uuid = self.fake_audit_template['uuid']
returns = [dict(self.fake_audit_template, returns = [dict(self.fake_audit_template,
goal="DUMMY"), goal_id=self.fake_goal1.id),
dict(self.fake_audit_template, goal="BALANCE_LOAD")] dict(self.fake_audit_template, goal_id=self.fake_goal2.id)]
expected = [mock.call(self.context, uuid), expected = [mock.call(self.context, uuid),
mock.call(self.context, uuid)] mock.call(self.context, uuid)]
with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid',
side_effect=returns, side_effect=returns,
autospec=True) as mock_get_audit_template: autospec=True) as mock_get_audit_template:
audit_template = objects.AuditTemplate.get(self.context, uuid) audit_template = objects.AuditTemplate.get(self.context, uuid)
self.assertEqual("DUMMY", audit_template.goal) self.assertEqual(1, audit_template.goal_id)
audit_template.refresh() audit_template.refresh()
self.assertEqual("BALANCE_LOAD", audit_template.goal) self.assertEqual(2, audit_template.goal_id)
self.assertEqual(expected, mock_get_audit_template.call_args_list) self.assertEqual(expected, mock_get_audit_template.call_args_list)
self.assertEqual(self.context, audit_template._context) self.assertEqual(self.context, audit_template._context)

View File

@@ -61,8 +61,10 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient):
:param name: The name of the audit template. Default: My Audit Template :param name: The name of the audit template. Default: My Audit Template
:param description: The description of the audit template. :param description: The description of the audit template.
Default: AT Description Default: AT Description
:param goal: The goal associated within the audit template. :param goal_uuid: The related Goal UUID associated.
Default: DUMMY Default: None
:param strategy_uuid: The related Strategy UUID associated.
Default: None
:param host_aggregate: ID of the host aggregate targeted by :param host_aggregate: ID of the host aggregate targeted by
this audit template. Default: 1 this audit template. Default: 1
:param extra: IMetadata associated to this audit template. :param extra: IMetadata associated to this audit template.
@@ -77,8 +79,9 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient):
audit_template = { audit_template = {
'name': parameters.get('name', unique_name), 'name': parameters.get('name', unique_name),
'description': parameters.get('description', ''), 'description': parameters.get('description'),
'goal': parameters.get('goal', 'DUMMY'), 'goal_uuid': parameters.get('goal_uuid'),
'strategy_uuid': parameters.get('strategy_uuid'),
'host_aggregate': parameters.get('host_aggregate', 1), 'host_aggregate': parameters.get('host_aggregate', 1),
'extra': parameters.get('extra', {}), 'extra': parameters.get('extra', {}),
} }

View File

@@ -114,15 +114,18 @@ class BaseInfraOptimTest(test.BaseTestCase):
# ### AUDIT TEMPLATES ### # # ### AUDIT TEMPLATES ### #
@classmethod @classmethod
def create_audit_template(cls, name=None, description=None, goal=None, def create_audit_template(cls, goal_uuid, name=None, description=None,
host_aggregate=None, extra=None): strategy_uuid=None, host_aggregate=None,
extra=None):
"""Wrapper utility for creating a test audit template """Wrapper utility for creating a test audit template
:param goal_uuid: The goal UUID related to the audit template.
Default: DUMMY
:param name: The name of the audit template. Default: My Audit Template :param name: The name of the audit template. Default: My Audit Template
:param description: The description of the audit template. :param description: The description of the audit template.
Default: AT Description Default: AT Description
:param goal: The goal associated within the audit template. :param strategy_uuid: The strategy UUID related to the audit template.
Default: DUMMY Default: dummy
:param host_aggregate: ID of the host aggregate targeted by :param host_aggregate: ID of the host aggregate targeted by
this audit template. Default: 1 this audit template. Default: 1
:param extra: IMetadata associated to this audit template. :param extra: IMetadata associated to this audit template.
@@ -132,8 +135,9 @@ class BaseInfraOptimTest(test.BaseTestCase):
description = description or data_utils.rand_name( description = description or data_utils.rand_name(
'test-audit_template') 'test-audit_template')
resp, body = cls.client.create_audit_template( resp, body = cls.client.create_audit_template(
name=name, description=description, goal=goal, name=name, description=description, goal_uuid=goal_uuid,
host_aggregate=host_aggregate, extra=extra) strategy_uuid=strategy_uuid, host_aggregate=host_aggregate,
extra=extra)
cls.created_audit_templates.add(body['uuid']) cls.created_audit_templates.add(body['uuid'])

View File

@@ -30,7 +30,8 @@ class TestShowListAction(base.BaseInfraOptimTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
super(TestShowListAction, cls).resource_setup() super(TestShowListAction, cls).resource_setup()
_, cls.audit_template = cls.create_audit_template() _, cls.goal = cls.client.show_goal("DUMMY")
_, cls.audit_template = cls.create_audit_template(cls.goal['uuid'])
_, cls.audit = cls.create_audit(cls.audit_template['uuid']) _, cls.audit = cls.create_audit(cls.audit_template['uuid'])
assert test.call_until_true( assert test.call_until_true(

View File

@@ -29,7 +29,8 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_action_plan(self): def test_create_action_plan(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
_, audit = self.create_audit(audit_template['uuid']) _, audit = self.create_audit(audit_template['uuid'])
self.assertTrue(test.call_until_true( self.assertTrue(test.call_until_true(
@@ -48,7 +49,8 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_delete_action_plan(self): def test_delete_action_plan(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
_, audit = self.create_audit(audit_template['uuid']) _, audit = self.create_audit(audit_template['uuid'])
self.assertTrue(test.call_until_true( self.assertTrue(test.call_until_true(
@@ -69,7 +71,8 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_execute_dummy_action_plan(self): def test_execute_dummy_action_plan(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
_, audit = self.create_audit(audit_template['uuid']) _, audit = self.create_audit(audit_template['uuid'])
self.assertTrue(test.call_until_true( self.assertTrue(test.call_until_true(
@@ -107,7 +110,8 @@ class TestShowListActionPlan(base.BaseInfraOptimTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
super(TestShowListActionPlan, cls).resource_setup() super(TestShowListActionPlan, cls).resource_setup()
_, cls.audit_template = cls.create_audit_template() _, cls.goal = cls.client.show_goal("DUMMY")
_, cls.audit_template = cls.create_audit_template(cls.goal['uuid'])
_, cls.audit = cls.create_audit(cls.audit_template['uuid']) _, cls.audit = cls.create_audit(cls.audit_template['uuid'])
assert test.call_until_true( assert test.call_until_true(

View File

@@ -33,7 +33,8 @@ class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_oneshot(self): def test_create_audit_oneshot(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
audit_params = dict( audit_params = dict(
audit_template_uuid=audit_template['uuid'], audit_template_uuid=audit_template['uuid'],
@@ -48,7 +49,8 @@ class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_continuous(self): def test_create_audit_continuous(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
audit_params = dict( audit_params = dict(
audit_template_uuid=audit_template['uuid'], audit_template_uuid=audit_template['uuid'],
@@ -73,7 +75,8 @@ class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_with_invalid_state(self): def test_create_audit_with_invalid_state(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
audit_params = dict( audit_params = dict(
audit_template_uuid=audit_template['uuid'], audit_template_uuid=audit_template['uuid'],
@@ -85,7 +88,8 @@ class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_with_no_state(self): def test_create_audit_with_no_state(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
audit_params = dict( audit_params = dict(
audit_template_uuid=audit_template['uuid'], audit_template_uuid=audit_template['uuid'],
@@ -104,7 +108,8 @@ class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_delete_audit(self): def test_delete_audit(self):
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
_, body = self.create_audit(audit_template['uuid']) _, body = self.create_audit(audit_template['uuid'])
audit_uuid = body['uuid'] audit_uuid = body['uuid']
@@ -123,7 +128,8 @@ class TestShowListAudit(base.BaseInfraOptimTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
super(TestShowListAudit, cls).resource_setup() super(TestShowListAudit, cls).resource_setup()
_, cls.audit_template = cls.create_audit_template() _, cls.goal = cls.client.show_goal("DUMMY")
_, cls.audit_template = cls.create_audit_template(cls.goal['uuid'])
_, cls.audit = cls.create_audit(cls.audit_template['uuid']) _, cls.audit = cls.create_audit(cls.audit_template['uuid'])
def assert_expected(self, expected, actual, def assert_expected(self, expected, actual,

View File

@@ -29,10 +29,12 @@ class TestCreateDeleteAuditTemplate(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_template(self): def test_create_audit_template(self):
_, goal = self.client.show_goal("DUMMY")
params = {'name': 'my at name %s' % uuid.uuid4(), params = {'name': 'my at name %s' % uuid.uuid4(),
'description': 'my at description', 'description': 'my at description',
'host_aggregate': 12, 'host_aggregate': 12,
'goal': 'DUMMY', 'goal_uuid': goal['uuid'],
'extra': {'str': 'value', 'int': 123, 'float': 0.123, 'extra': {'str': 'value', 'int': 123, 'float': 0.123,
'bool': True, 'list': [1, 2, 3], 'bool': True, 'list': [1, 2, 3],
'dict': {'foo': 'bar'}}} 'dict': {'foo': 'bar'}}}
@@ -45,11 +47,13 @@ class TestCreateDeleteAuditTemplate(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_create_audit_template_unicode_description(self): def test_create_audit_template_unicode_description(self):
_, goal = self.client.show_goal("DUMMY")
# Use a unicode string for testing: # Use a unicode string for testing:
params = {'name': 'my at name %s' % uuid.uuid4(), params = {'name': 'my at name %s' % uuid.uuid4(),
'description': 'my àt déscrïptïôn', 'description': 'my àt déscrïptïôn',
'host_aggregate': 12, 'host_aggregate': 12,
'goal': 'DUMMY', 'goal_uuid': goal['uuid'],
'extra': {'foo': 'bar'}} 'extra': {'foo': 'bar'}}
_, body = self.create_audit_template(**params) _, body = self.create_audit_template(**params)
@@ -60,7 +64,8 @@ class TestCreateDeleteAuditTemplate(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_delete_audit_template(self): def test_delete_audit_template(self):
_, body = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, body = self.create_audit_template(goal_uuid=goal['uuid'])
audit_uuid = body['uuid'] audit_uuid = body['uuid']
self.delete_audit_template(audit_uuid) self.delete_audit_template(audit_uuid)
@@ -75,7 +80,10 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
@classmethod @classmethod
def resource_setup(cls): def resource_setup(cls):
super(TestAuditTemplate, cls).resource_setup() super(TestAuditTemplate, cls).resource_setup()
_, cls.audit_template = cls.create_audit_template() _, cls.goal = cls.client.show_goal("DUMMY")
_, cls.strategy = cls.client.show_strategy("dummy")
_, cls.audit_template = cls.create_audit_template(
goal_uuid=cls.goal['uuid'], strategy_uuid=cls.strategy['uuid'])
@test.attr(type='smoke') @test.attr(type='smoke')
def test_show_audit_template(self): def test_show_audit_template(self):
@@ -85,9 +93,18 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
self.assert_expected(self.audit_template, audit_template) self.assert_expected(self.audit_template, audit_template)
@test.attr(type='smoke') @test.attr(type='smoke')
def test_filter_audit_template_by_goal(self): def test_filter_audit_template_by_goal_uuid(self):
_, audit_templates = self.client.list_audit_templates( _, audit_templates = self.client.list_audit_templates(
goal=self.audit_template['goal']) goal_uuid=self.audit_template['goal_uuid'])
audit_template_uuids = [
at["uuid"] for at in audit_templates['audit_templates']]
self.assertIn(self.audit_template['uuid'], audit_template_uuids)
@test.attr(type='smoke')
def test_filter_audit_template_by_strategy_uuid(self):
_, audit_templates = self.client.list_audit_templates(
strategy_uuid=self.audit_template['strategy_uuid'])
audit_template_uuids = [ audit_template_uuids = [
at["uuid"] for at in audit_templates['audit_templates']] at["uuid"] for at in audit_templates['audit_templates']]
@@ -116,7 +133,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
def test_list_with_limit(self): def test_list_with_limit(self):
# We create 3 extra audit templates to exceed the limit we fix # We create 3 extra audit templates to exceed the limit we fix
for _ in range(3): for _ in range(3):
self.create_audit_template() self.create_audit_template(self.goal['uuid'])
_, body = self.client.list_audit_templates(limit=3) _, body = self.client.list_audit_templates(limit=3)
@@ -126,10 +143,13 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
@test.attr(type='smoke') @test.attr(type='smoke')
def test_update_audit_template_replace(self): def test_update_audit_template_replace(self):
_, new_goal = self.client.show_goal("SERVER_CONSOLIDATION")
_, new_strategy = self.client.show_strategy("basic")
params = {'name': 'my at name %s' % uuid.uuid4(), params = {'name': 'my at name %s' % uuid.uuid4(),
'description': 'my at description', 'description': 'my at description',
'host_aggregate': 12, 'host_aggregate': 12,
'goal': 'DUMMY', 'goal_uuid': self.goal['uuid'],
'extra': {'key1': 'value1', 'key2': 'value2'}} 'extra': {'key1': 'value1', 'key2': 'value2'}}
_, body = self.create_audit_template(**params) _, body = self.create_audit_template(**params)
@@ -137,7 +157,6 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
new_name = 'my at new name %s' % uuid.uuid4() new_name = 'my at new name %s' % uuid.uuid4()
new_description = 'my new at description' new_description = 'my new at description'
new_host_aggregate = 10 new_host_aggregate = 10
new_goal = 'SERVER_CONSOLIDATION'
new_extra = {'key1': 'new-value1', 'key2': 'new-value2'} new_extra = {'key1': 'new-value1', 'key2': 'new-value2'}
patch = [{'path': '/name', patch = [{'path': '/name',
@@ -149,9 +168,12 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
{'path': '/host_aggregate', {'path': '/host_aggregate',
'op': 'replace', 'op': 'replace',
'value': new_host_aggregate}, 'value': new_host_aggregate},
{'path': '/goal', {'path': '/goal_uuid',
'op': 'replace', 'op': 'replace',
'value': new_goal}, 'value': new_goal['uuid']},
{'path': '/strategy_uuid',
'op': 'replace',
'value': new_strategy['uuid']},
{'path': '/extra/key1', {'path': '/extra/key1',
'op': 'replace', 'op': 'replace',
'value': new_extra['key1']}, 'value': new_extra['key1']},
@@ -165,19 +187,19 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
self.assertEqual(new_name, body['name']) self.assertEqual(new_name, body['name'])
self.assertEqual(new_description, body['description']) self.assertEqual(new_description, body['description'])
self.assertEqual(new_host_aggregate, body['host_aggregate']) self.assertEqual(new_host_aggregate, body['host_aggregate'])
self.assertEqual(new_goal, body['goal']) self.assertEqual(new_goal['uuid'], body['goal_uuid'])
self.assertEqual(new_strategy['uuid'], body['strategy_uuid'])
self.assertEqual(new_extra, body['extra']) self.assertEqual(new_extra, body['extra'])
@test.attr(type='smoke') @test.attr(type='smoke')
def test_update_audit_template_remove(self): def test_update_audit_template_remove(self):
extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
description = 'my at description' description = 'my at description'
goal = 'DUMMY'
name = 'my at name %s' % uuid.uuid4() name = 'my at name %s' % uuid.uuid4()
params = {'name': name, params = {'name': name,
'description': description, 'description': description,
'host_aggregate': 12, 'host_aggregate': 12,
'goal': goal, 'goal_uuid': self.goal['uuid'],
'extra': extra} 'extra': extra}
_, audit_template = self.create_audit_template(**params) _, audit_template = self.create_audit_template(**params)
@@ -208,14 +230,14 @@ class TestAuditTemplate(base.BaseInfraOptimTest):
# Assert nothing else was changed # Assert nothing else was changed
self.assertEqual(name, body['name']) self.assertEqual(name, body['name'])
self.assertEqual(description, body['description']) self.assertEqual(description, body['description'])
self.assertEqual(goal, body['goal']) self.assertEqual(self.goal['uuid'], body['goal_uuid'])
@test.attr(type='smoke') @test.attr(type='smoke')
def test_update_audit_template_add(self): def test_update_audit_template_add(self):
params = {'name': 'my at name %s' % uuid.uuid4(), params = {'name': 'my at name %s' % uuid.uuid4(),
'description': 'my at description', 'description': 'my at description',
'host_aggregate': 12, 'host_aggregate': 12,
'goal': 'DUMMY'} 'goal_uuid': self.goal['uuid']}
_, body = self.create_audit_template(**params) _, body = self.create_audit_template(**params)

View File

@@ -73,27 +73,30 @@ class BaseInfraOptimScenarioTest(manager.ScenarioTest):
# ### AUDIT TEMPLATES ### # # ### AUDIT TEMPLATES ### #
def create_audit_template(self, name=None, description=None, goal=None, def create_audit_template(self, goal_uuid, name=None, description=None,
host_aggregate=None, extra=None): strategy_uuid=None, host_aggregate=None,
extra=None):
"""Wrapper utility for creating a test audit template """Wrapper utility for creating a test audit template
:param goal_uuid: The goal UUID related to the audit template.
Default: DUMMY
:param name: The name of the audit template. Default: My Audit Template :param name: The name of the audit template. Default: My Audit Template
:param description: The description of the audit template. :param description: The description of the audit template.
Default: AT Description Default: AT Description
:param goal: The goal associated within the audit template. :param strategy_uuid: The strategy UUID related to the audit template.
Default: DUMMY Default: dummy
:param host_aggregate: ID of the host aggregate targeted by :param host_aggregate: ID of the host aggregate targeted by
this audit template. Default: 1 this audit template. Default: 1
:param extra: IMetadata associated to this audit template. :param extra: IMetadata associated to this audit template.
Default: {} Default: {}
:return: A tuple with The HTTP response and its body :return: A tuple with The HTTP response and its body
""" """
description = description or data_utils.rand_name( description = description or data_utils.rand_name(
'test-audit_template') 'test-audit_template')
resp, body = self.client.create_audit_template( resp, body = self.client.create_audit_template(
name=name, description=description, goal=goal, name=name, description=description, goal_uuid=goal_uuid,
host_aggregate=host_aggregate, extra=extra) strategy_uuid=strategy_uuid, host_aggregate=host_aggregate,
extra=extra)
self.addCleanup( self.addCleanup(
self.delete_audit_template, self.delete_audit_template,

View File

@@ -108,8 +108,8 @@ class TestExecuteBasicStrategy(base.BaseInfraOptimScenarioTest):
""" """
self.addCleanup(self.rollback_compute_nodes_status) self.addCleanup(self.rollback_compute_nodes_status)
self._create_one_instance_per_host() self._create_one_instance_per_host()
_, goal = self.client.show_goal(self.BASIC_GOAL)
_, audit_template = self.create_audit_template(goal=self.BASIC_GOAL) _, audit_template = self.create_audit_template(goal['uuid'])
_, audit = self.create_audit(audit_template['uuid']) _, audit = self.create_audit(audit_template['uuid'])
self.assertTrue(test.call_until_true( self.assertTrue(test.call_until_true(

View File

@@ -37,7 +37,8 @@ class TestExecuteDummyStrategy(base.BaseInfraOptimScenarioTest):
- run the action plan - run the action plan
- get results and make sure it succeeded - get results and make sure it succeeded
""" """
_, audit_template = self.create_audit_template() _, goal = self.client.show_goal("DUMMY")
_, audit_template = self.create_audit_template(goal['uuid'])
_, audit = self.create_audit(audit_template['uuid']) _, audit = self.create_audit(audit_template['uuid'])
self.assertTrue(test.call_until_true( self.assertTrue(test.call_until_true(