From d7d56cbd79ce6f8cfb8ac60255b4cb2f89b2ff0d Mon Sep 17 00:00:00 2001 From: suzhengwei Date: Mon, 19 Jun 2017 18:57:44 +0800 Subject: [PATCH] add name for audit, changes for watcher api/db Change-Id: Ibe04f5375d741d15999fde6faf767f15311c6351 Implements:blueprint add-name-for-audit --- watcher/api/controllers/v1/audit.py | 52 ++++++++++++++----- watcher/common/exception.py | 2 +- watcher/db/api.py | 10 ++++ .../3cfc94cecf4e_add_name_for_audit.py | 22 ++++++++ watcher/db/sqlalchemy/api.py | 14 ++++- watcher/db/sqlalchemy/models.py | 2 + watcher/objects/audit.py | 23 +++++++- watcher/tests/api/v1/test_actions.py | 3 +- watcher/tests/api/v1/test_actions_plans.py | 36 ++++++------- watcher/tests/api/v1/test_audits.py | 41 +++++++++------ watcher/tests/db/test_audit.py | 39 +++++++++++--- watcher/tests/db/test_purge.py | 25 ++++++--- watcher/tests/db/utils.py | 1 + .../audit/test_audit_handlers.py | 1 + .../strategy/context/test_strategy_context.py | 4 +- watcher/tests/decision_engine/test_sync.py | 12 ++--- watcher/tests/objects/test_objects.py | 2 +- 17 files changed, 215 insertions(+), 74 deletions(-) create mode 100644 watcher/db/sqlalchemy/alembic/versions/3cfc94cecf4e_add_name_for_audit.py diff --git a/watcher/api/controllers/v1/audit.py b/watcher/api/controllers/v1/audit.py index f654c63cf..7a247dc11 100644 --- a/watcher/api/controllers/v1/audit.py +++ b/watcher/api/controllers/v1/audit.py @@ -52,6 +52,8 @@ from watcher import objects class AuditPostType(wtypes.Base): + name = wtypes.wsattr(wtypes.text, mandatory=False) + audit_template_uuid = wtypes.wsattr(types.uuid, mandatory=False) goal = wtypes.wsattr(wtypes.text, mandatory=False) @@ -111,7 +113,25 @@ class AuditPostType(wtypes.Base): 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, @@ -233,6 +253,9 @@ class Audit(base.APIBase): uuid = types.uuid """Unique UUID for this audit""" + name = wtypes.text + """Name of this audit""" + audit_type = wtypes.text """Type of this audit""" @@ -301,7 +324,7 @@ class Audit(base.APIBase): @staticmethod def _convert_with_links(audit, url, expand=True): if not expand: - audit.unset_fields_except(['uuid', 'audit_type', 'state', + audit.unset_fields_except(['uuid', 'name', 'audit_type', 'state', 'goal_uuid', 'interval', 'scope', 'strategy_uuid', 'goal_name', 'strategy_name', 'auto_trigger', @@ -324,6 +347,7 @@ class Audit(base.APIBase): @classmethod def sample(cls, expand=True): sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', + name='My Audit', audit_type='ONESHOT', state='PENDING', created_at=datetime.datetime.utcnow(), @@ -483,17 +507,17 @@ class AuditsController(rest.RestController): resource_url, goal=goal) - @wsme_pecan.wsexpose(Audit, types.uuid) - def get_one(self, audit_uuid): + @wsme_pecan.wsexpose(Audit, wtypes.text) + def get_one(self, audit): """Retrieve information about the given audit. - :param audit_uuid: UUID of a audit. + :param audit_uuid: UUID or name of an audit. """ if self.from_audits: raise exception.OperationNotPermitted context = pecan.request.context - rpc_audit = api_utils.get_resource('Audit', audit_uuid) + rpc_audit = api_utils.get_resource('Audit', audit) policy.enforce(context, 'audit:get', rpc_audit, action='audit:get') return Audit.convert_with_links(rpc_audit) @@ -551,11 +575,11 @@ class AuditsController(rest.RestController): return Audit.convert_with_links(new_audit) @wsme.validate(types.uuid, [AuditPatchType]) - @wsme_pecan.wsexpose(Audit, types.uuid, body=[AuditPatchType]) - def patch(self, audit_uuid, patch): + @wsme_pecan.wsexpose(Audit, wtypes.text, body=[AuditPatchType]) + def patch(self, audit, patch): """Update an existing audit. - :param audit_uuid: UUID of a audit. + :param auditd: UUID or name of a audit. :param patch: a json PATCH document to apply to this audit. """ if self.from_audits: @@ -563,7 +587,7 @@ class AuditsController(rest.RestController): context = pecan.request.context audit_to_update = api_utils.get_resource( - 'Audit', audit_uuid, eager=True) + 'Audit', audit, eager=True) policy.enforce(context, 'audit:update', audit_to_update, action='audit:update') @@ -600,15 +624,15 @@ class AuditsController(rest.RestController): audit_to_update.save() return Audit.convert_with_links(audit_to_update) - @wsme_pecan.wsexpose(None, types.uuid, status_code=204) - def delete(self, audit_uuid): - """Delete a audit. + @wsme_pecan.wsexpose(None, wtypes.text, status_code=204) + def delete(self, audit): + """Delete an audit. - :param audit_uuid: UUID of a audit. + :param audit: UUID or name of an audit. """ context = pecan.request.context audit_to_delete = api_utils.get_resource( - 'Audit', audit_uuid, eager=True) + 'Audit', audit, eager=True) policy.enforce(context, 'audit:update', audit_to_delete, action='audit:update') diff --git a/watcher/common/exception.py b/watcher/common/exception.py index dabfae897..f26d2b15a 100644 --- a/watcher/common/exception.py +++ b/watcher/common/exception.py @@ -249,7 +249,7 @@ class AuditNotFound(ResourceNotFound): class AuditAlreadyExists(Conflict): - msg_fmt = _("An audit with UUID %(uuid)s already exists") + msg_fmt = _("An audit with UUID or name %(audit)s already exists") class AuditIntervalNotSpecified(Invalid): diff --git a/watcher/db/api.py b/watcher/db/api.py index eb0749365..a823f6450 100644 --- a/watcher/db/api.py +++ b/watcher/db/api.py @@ -401,6 +401,16 @@ class BaseConnection(object): :raises: :py:class:`~.AuditNotFound` """ + def get_audit_by_name(self, context, audit_name, eager=False): + """Return an audit. + + :param context: The security context + :param audit_name: The name of an audit. + :param eager: If True, also loads One-to-X data (Default: False) + :returns: An audit. + :raises: :py:class:`~.AuditNotFound` + """ + @abc.abstractmethod def destroy_audit(self, audit_id): """Destroy an audit and all associated action plans. diff --git a/watcher/db/sqlalchemy/alembic/versions/3cfc94cecf4e_add_name_for_audit.py b/watcher/db/sqlalchemy/alembic/versions/3cfc94cecf4e_add_name_for_audit.py new file mode 100644 index 000000000..825cda3a9 --- /dev/null +++ b/watcher/db/sqlalchemy/alembic/versions/3cfc94cecf4e_add_name_for_audit.py @@ -0,0 +1,22 @@ +"""add name for audit + +Revision ID: 3cfc94cecf4e +Revises: d098df6021e2 +Create Date: 2017-07-19 15:44:57.661099 + +""" + +# revision identifiers, used by Alembic. +revision = '3cfc94cecf4e' +down_revision = 'd09a5945e4a0' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('audits', sa.Column('name', sa.String(length=63), nullable=True)) + + +def downgrade(): + op.drop_column('audits', 'name') diff --git a/watcher/db/sqlalchemy/api.py b/watcher/db/sqlalchemy/api.py index d14e27da7..66cfaec6d 100644 --- a/watcher/db/sqlalchemy/api.py +++ b/watcher/db/sqlalchemy/api.py @@ -659,6 +659,14 @@ class Connection(api.BaseConnection): if not values.get('uuid'): values['uuid'] = utils.generate_uuid() + query = model_query(models.Audit) + query = query.filter_by(name=values.get('name'), + deleted_at=None) + + if len(query.all()) > 0: + raise exception.AuditAlreadyExists( + audit=values['name']) + if values.get('state') is None: values['state'] = objects.audit.State.PENDING @@ -668,7 +676,7 @@ class Connection(api.BaseConnection): try: audit = self._create(models.Audit, values) except db_exc.DBDuplicateEntry: - raise exception.AuditAlreadyExists(uuid=values['uuid']) + raise exception.AuditAlreadyExists(audit=values['uuid']) return audit def _get_audit(self, context, fieldname, value, eager): @@ -686,6 +694,10 @@ class Connection(api.BaseConnection): return self._get_audit( context, fieldname="uuid", value=audit_uuid, eager=eager) + def get_audit_by_name(self, context, audit_name, eager=False): + return self._get_audit( + context, fieldname="name", value=audit_name, eager=eager) + def destroy_audit(self, audit_id): def is_audit_referenced(session, audit_id): """Checks whether the audit is referenced by action_plan(s).""" diff --git a/watcher/db/sqlalchemy/models.py b/watcher/db/sqlalchemy/models.py index 7ad0c16a9..e7066c806 100644 --- a/watcher/db/sqlalchemy/models.py +++ b/watcher/db/sqlalchemy/models.py @@ -166,10 +166,12 @@ class Audit(Base): __tablename__ = 'audits' __table_args__ = ( UniqueConstraint('uuid', name='uniq_audits0uuid'), + UniqueConstraint('name', 'deleted', name='uniq_audits0name'), table_args() ) id = Column(Integer, primary_key=True, autoincrement=True) uuid = Column(String(36)) + name = Column(String(63), nullable=True) audit_type = Column(String(20)) state = Column(String(20), nullable=True) parameters = Column(JSONEncodedDict, nullable=True) diff --git a/watcher/objects/audit.py b/watcher/objects/audit.py index d0a1c100e..8c5652f35 100644 --- a/watcher/objects/audit.py +++ b/watcher/objects/audit.py @@ -86,13 +86,15 @@ class Audit(base.WatcherPersistentObject, base.WatcherObject, # Version 1.2: Added 'auto_trigger' boolean field # Version 1.3: Added 'next_run_time' DateTime field, # 'interval' type has been changed from Integer to String - VERSION = '1.3' + # Version 1.4: Added 'name' string field + VERSION = '1.4' dbapi = db_api.get_instance() fields = { 'id': wfields.IntegerField(), 'uuid': wfields.UUIDField(), + 'name': wfields.StringField(), 'audit_type': wfields.StringField(), 'state': wfields.StringField(), 'parameters': wfields.FlexibleDictField(nullable=True), @@ -204,6 +206,25 @@ class Audit(base.WatcherPersistentObject, base.WatcherObject, audit = cls._from_db_object(cls(context), db_audit, eager=eager) return audit + @base.remotable_classmethod + def get_by_name(cls, context, name, eager=False): + """Find an audit based on name and return a :class:`Audit` object. + + :param context: Security context. NOTE: This should only + be used internally by the indirection_api. + Unfortunately, RPC requires context as the first + argument, even though we don't use it. + A context should be set when instantiating the + object, e.g.: Audit(context) + :param name: the name of an audit. + :param eager: Load object fields if True (Default: False) + :returns: a :class:`Audit` object. + """ + + db_audit = cls.dbapi.get_audit_by_name(context, name, eager=eager) + audit = cls._from_db_object(cls(context), db_audit, eager=eager) + return audit + @base.remotable_classmethod def list(cls, context, limit=None, marker=None, filters=None, sort_key=None, sort_dir=None, eager=False): diff --git a/watcher/tests/api/v1/test_actions.py b/watcher/tests/api/v1/test_actions.py index ca5881f7c..282bdd70d 100644 --- a/watcher/tests/api/v1/test_actions.py +++ b/watcher/tests/api/v1/test_actions.py @@ -169,7 +169,8 @@ class TestListAction(api_base.FunctionalTest): action_list.append(action.uuid) audit2 = obj_utils.create_test_audit( - self.context, id=2, uuid=utils.generate_uuid()) + self.context, id=2, uuid=utils.generate_uuid(), + name='My Audit {0}'.format(2)) action_plan_2 = obj_utils.create_test_action_plan( self.context, uuid=utils.generate_uuid(), diff --git a/watcher/tests/api/v1/test_actions_plans.py b/watcher/tests/api/v1/test_actions_plans.py index b41743710..0f5d5d4ef 100644 --- a/watcher/tests/api/v1/test_actions_plans.py +++ b/watcher/tests/api/v1/test_actions_plans.py @@ -128,12 +128,12 @@ class TestListActionPlan(api_base.FunctionalTest): def test_many_with_soft_deleted_audit_uuid(self): action_plan_list = [] - audit1 = obj_utils.create_test_audit(self.context, - id=2, - uuid=utils.generate_uuid()) - audit2 = obj_utils.create_test_audit(self.context, - id=3, - uuid=utils.generate_uuid()) + audit1 = obj_utils.create_test_audit( + self.context, id=2, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(2)) + audit2 = obj_utils.create_test_audit( + self.context, id=3, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(3)) for id_ in range(0, 2): action_plan = obj_utils.create_test_action_plan( @@ -163,9 +163,9 @@ class TestListActionPlan(api_base.FunctionalTest): def test_many_with_audit_uuid(self): action_plan_list = [] - audit = obj_utils.create_test_audit(self.context, - id=2, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=2, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(2)) for id_ in range(2, 5): action_plan = obj_utils.create_test_action_plan( self.context, id=id_, uuid=utils.generate_uuid(), @@ -178,18 +178,18 @@ class TestListActionPlan(api_base.FunctionalTest): def test_many_with_audit_uuid_filter(self): action_plan_list1 = [] - audit1 = obj_utils.create_test_audit(self.context, - id=2, - uuid=utils.generate_uuid()) + audit1 = obj_utils.create_test_audit( + self.context, id=2, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(2)) for id_ in range(2, 5): action_plan = obj_utils.create_test_action_plan( self.context, id=id_, uuid=utils.generate_uuid(), audit_id=audit1.id) action_plan_list1.append(action_plan.uuid) - audit2 = obj_utils.create_test_audit(self.context, - id=3, - uuid=utils.generate_uuid()) + audit2 = obj_utils.create_test_audit( + self.context, id=3, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(3)) action_plan_list2 = [] for id_ in [5, 6, 7]: action_plan = obj_utils.create_test_action_plan( @@ -237,9 +237,9 @@ class TestListActionPlan(api_base.FunctionalTest): def test_many_with_sort_key_audit_uuid(self): audit_list = [] for id_ in range(2, 5): - audit = obj_utils.create_test_audit(self.context, - id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) obj_utils.create_test_action_plan( self.context, id=id_, uuid=utils.generate_uuid(), audit_id=audit.id) diff --git a/watcher/tests/api/v1/test_audits.py b/watcher/tests/api/v1/test_audits.py index b26f62cd1..8dfa10402 100644 --- a/watcher/tests/api/v1/test_audits.py +++ b/watcher/tests/api/v1/test_audits.py @@ -154,8 +154,9 @@ class TestListAudit(api_base.FunctionalTest): def test_many(self): audit_list = [] for id_ in range(5): - audit = obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) audit_list.append(audit.uuid) response = self.get_json('/audits') self.assertEqual(len(audit_list), len(response['audits'])) @@ -165,12 +166,14 @@ class TestListAudit(api_base.FunctionalTest): def test_many_without_soft_deleted(self): audit_list = [] for id_ in [1, 2, 3]: - audit = obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) audit_list.append(audit.uuid) for id_ in [4, 5]: - audit = obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) audit.soft_delete() response = self.get_json('/audits') self.assertEqual(3, len(response['audits'])) @@ -180,12 +183,14 @@ class TestListAudit(api_base.FunctionalTest): def test_many_with_soft_deleted(self): audit_list = [] for id_ in [1, 2, 3]: - audit = obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) audit_list.append(audit.uuid) for id_ in [4, 5]: - audit = obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + audit = obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) audit.soft_delete() audit_list.append(audit.uuid) response = self.get_json('/audits', @@ -203,7 +208,7 @@ class TestListAudit(api_base.FunctionalTest): uuid=utils.generate_uuid()) obj_utils.create_test_audit( self.context, id=id_, uuid=utils.generate_uuid(), - goal_id=goal.id) + goal_id=goal.id, name='My Audit {0}'.format(id_)) goal_list.append(goal.uuid) response = self.get_json('/audits/?sort_key=goal_uuid') @@ -214,7 +219,9 @@ class TestListAudit(api_base.FunctionalTest): def test_links(self): uuid = utils.generate_uuid() - obj_utils.create_test_audit(self.context, id=1, uuid=uuid) + obj_utils.create_test_audit( + self.context, id=1, uuid=uuid, + name='My Audit {0}'.format(1)) response = self.get_json('/audits/%s' % uuid) self.assertIn('links', response.keys()) self.assertEqual(2, len(response['links'])) @@ -225,8 +232,9 @@ class TestListAudit(api_base.FunctionalTest): def test_collection_links(self): for id_ in range(5): - obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) response = self.get_json('/audits/?limit=3') self.assertEqual(3, len(response['audits'])) @@ -236,8 +244,9 @@ class TestListAudit(api_base.FunctionalTest): def test_collection_links_default_limit(self): cfg.CONF.set_override('max_limit', 3, 'api') for id_ in range(5): - obj_utils.create_test_audit(self.context, id=id_, - uuid=utils.generate_uuid()) + obj_utils.create_test_audit( + self.context, id=id_, + uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_)) response = self.get_json('/audits') self.assertEqual(3, len(response['audits'])) diff --git a/watcher/tests/db/test_audit.py b/watcher/tests/db/test_audit.py index 1b467bad5..9ec564949 100644 --- a/watcher/tests/db/test_audit.py +++ b/watcher/tests/db/test_audit.py @@ -38,25 +38,31 @@ class TestDbAuditFilters(base.DbTestCase): def _data_setup(self): self.audit_template_name = "Audit Template" + gen_name = lambda: "Audit %s" % w_utils.generate_uuid() + self.audit1_name = gen_name() + self.audit2_name = gen_name() + self.audit3_name = gen_name() + self.audit4_name = gen_name() self.audit_template = utils.create_test_audit_template( name=self.audit_template_name, id=1, uuid=None) with freezegun.freeze_time(self.FAKE_TODAY): self.audit1 = utils.create_test_audit( - audit_template_id=self.audit_template.id, id=1, uuid=None) + audit_template_id=self.audit_template.id, id=1, uuid=None, + name=self.audit1_name) with freezegun.freeze_time(self.FAKE_OLD_DATE): self.audit2 = utils.create_test_audit( audit_template_id=self.audit_template.id, id=2, uuid=None, - state=objects.audit.State.FAILED) + name=self.audit2_name, state=objects.audit.State.FAILED) with freezegun.freeze_time(self.FAKE_OLDER_DATE): self.audit3 = utils.create_test_audit( audit_template_id=self.audit_template.id, id=3, uuid=None, - state=objects.audit.State.CANCELLED) + name=self.audit3_name, state=objects.audit.State.CANCELLED) with freezegun.freeze_time(self.FAKE_OLDER_DATE): self.audit4 = utils.create_test_audit( audit_template_id=self.audit_template.id, id=4, uuid=None, - state=objects.audit.State.SUSPENDED) + name=self.audit4_name, state=objects.audit.State.SUSPENDED) def _soft_delete_audits(self): with freezegun.freeze_time(self.FAKE_TODAY): @@ -266,8 +272,9 @@ class DbAuditTestCase(base.DbTestCase): def test_get_audit_list(self): uuids = [] - for _ in range(1, 4): - audit = utils.create_test_audit(uuid=w_utils.generate_uuid()) + for id_ in range(1, 4): + audit = utils.create_test_audit(uuid=w_utils.generate_uuid(), + name='My Audit {0}'.format(id_)) uuids.append(six.text_type(audit['uuid'])) audits = self.dbapi.get_audit_list(self.context) audit_uuids = [a.uuid for a in audits] @@ -286,6 +293,7 @@ class DbAuditTestCase(base.DbTestCase): for i in range(1, 4): audit = utils.create_test_audit( id=i, uuid=w_utils.generate_uuid(), + name='My Audit {0}'.format(i), goal_id=goal.id, strategy_id=strategy.id) uuids.append(six.text_type(audit['uuid'])) audits = self.dbapi.get_audit_list(self.context, eager=True) @@ -300,6 +308,7 @@ class DbAuditTestCase(base.DbTestCase): id=1, audit_type=objects.audit.AuditType.ONESHOT.value, uuid=w_utils.generate_uuid(), + name='My Audit {0}'.format(1), state=objects.audit.State.ONGOING) audit2 = self._create_test_audit( id=2, @@ -389,3 +398,21 @@ class DbAuditTestCase(base.DbTestCase): self.assertEqual(audit['id'], action_plan.audit_id) self.assertRaises(exception.AuditReferenced, self.dbapi.destroy_audit, audit['id']) + + def test_create_audit_already_exists(self): + uuid = w_utils.generate_uuid() + self._create_test_audit(id=1, uuid=uuid) + self.assertRaises(exception.AuditAlreadyExists, + self._create_test_audit, + id=2, uuid=uuid) + + def test_create_same_name_audit(self): + audit = utils.create_test_audit( + uuid=w_utils.generate_uuid(), + name='my_audit') + self.assertEqual(audit['uuid'], audit.uuid) + self.assertRaises( + exception.AuditAlreadyExists, + utils.create_test_audit, + uuid=w_utils.generate_uuid(), + name='my_audit') diff --git a/watcher/tests/db/test_purge.py b/watcher/tests/db/test_purge.py index 5a0dde7e4..beecde3ea 100644 --- a/watcher/tests/db/test_purge.py +++ b/watcher/tests/db/test_purge.py @@ -100,6 +100,13 @@ class TestPurgeCommand(base.DbTestCase): self.audit_template3_name = self.generate_unique_name( prefix="Audit Template 3 ") + self.audit1_name = self.generate_unique_name( + prefix="Audit 1 ") + self.audit2_name = self.generate_unique_name( + prefix="Audit 2 ") + self.audit3_name = self.generate_unique_name( + prefix="Audit 3 ") + with freezegun.freeze_time(self.expired_date): self.goal1 = obj_utils.create_test_goal( self.context, id=self._generate_id(), @@ -154,15 +161,15 @@ class TestPurgeCommand(base.DbTestCase): with freezegun.freeze_time(self.expired_date): self.audit1 = obj_utils.create_test_audit( self.context, id=self._generate_id(), - uuid=utils.generate_uuid(), + uuid=utils.generate_uuid(), name=self.audit1_name, goal_id=self.goal1.id, strategy_id=self.strategy1.id) self.audit2 = obj_utils.create_test_audit( self.context, id=self._generate_id(), - uuid=utils.generate_uuid(), + uuid=utils.generate_uuid(), name=self.audit2_name, goal_id=self.goal2.id, strategy_id=self.strategy2.id) self.audit3 = obj_utils.create_test_audit( self.context, id=self._generate_id(), - uuid=utils.generate_uuid(), + uuid=utils.generate_uuid(), name=self.audit3_name, goal_id=self.goal3.id, strategy_id=self.strategy3.id) self.audit1.soft_delete() @@ -272,7 +279,8 @@ class TestPurgeCommand(base.DbTestCase): audit4 = obj_utils.create_test_audit( self.context, audit_template_id=audit_template4.id, strategy_id=self.strategy1.id, id=self._generate_id(), - uuid=utils.generate_uuid()) + uuid=utils.generate_uuid(), + name=self.generate_unique_name(prefix="Audit 4 ")) action_plan4 = obj_utils.create_test_action_plan( self.context, id=self._generate_id(), uuid=utils.generate_uuid(), @@ -290,7 +298,8 @@ class TestPurgeCommand(base.DbTestCase): audit5 = obj_utils.create_test_audit( self.context, audit_template_id=audit_template5.id, strategy_id=self.strategy1.id, id=self._generate_id(), - uuid=utils.generate_uuid()) + uuid=utils.generate_uuid(), + name=self.generate_unique_name(prefix="Audit 5 ")) action_plan5 = obj_utils.create_test_action_plan( self.context, id=self._generate_id(), uuid=utils.generate_uuid(), @@ -369,7 +378,8 @@ class TestPurgeCommand(base.DbTestCase): audit4 = obj_utils.create_test_audit( self.context, id=self._generate_id(), uuid=utils.generate_uuid(), - audit_template_id=audit_template4.id) + audit_template_id=audit_template4.id, + name=self.generate_unique_name(prefix="Audit 4 ")) action_plan4 = obj_utils.create_test_action_plan( self.context, id=self._generate_id(), uuid=utils.generate_uuid(), @@ -387,7 +397,8 @@ class TestPurgeCommand(base.DbTestCase): audit5 = obj_utils.create_test_audit( self.context, audit_template_id=audit_template5.id, strategy_id=self.strategy1.id, id=self._generate_id(), - uuid=utils.generate_uuid()) + uuid=utils.generate_uuid(), + name=self.generate_unique_name(prefix="Audit 5 ")) action_plan5 = obj_utils.create_test_action_plan( self.context, id=self._generate_id(), uuid=utils.generate_uuid(), diff --git a/watcher/tests/db/utils.py b/watcher/tests/db/utils.py index 435e9d30e..ae1ab7968 100644 --- a/watcher/tests/db/utils.py +++ b/watcher/tests/db/utils.py @@ -83,6 +83,7 @@ def get_test_audit(**kwargs): audit_data = { 'id': kwargs.get('id', 1), 'uuid': kwargs.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'), + 'name': kwargs.get('name', 'My Audit'), 'audit_type': kwargs.get('audit_type', 'ONESHOT'), 'state': kwargs.get('state', objects.audit.State.PENDING), 'created_at': kwargs.get('created_at'), diff --git a/watcher/tests/decision_engine/audit/test_audit_handlers.py b/watcher/tests/decision_engine/audit/test_audit_handlers.py index 80ea326de..ace94ee25 100644 --- a/watcher/tests/decision_engine/audit/test_audit_handlers.py +++ b/watcher/tests/decision_engine/audit/test_audit_handlers.py @@ -232,6 +232,7 @@ class TestContinuousAuditHandler(base.DbTestCase): obj_utils.create_test_audit( self.context, id=id_, + name='My Audit {0}'.format(id_), uuid=uuidutils.generate_uuid(), audit_template_id=audit_template.id, goal_id=self.goal.id, diff --git a/watcher/tests/decision_engine/strategy/context/test_strategy_context.py b/watcher/tests/decision_engine/strategy/context/test_strategy_context.py index b6b5c805f..e3827eba5 100644 --- a/watcher/tests/decision_engine/strategy/context/test_strategy_context.py +++ b/watcher/tests/decision_engine/strategy/context/test_strategy_context.py @@ -61,7 +61,7 @@ class TestStrategyContext(base.DbTestCase): audit = obj_utils.create_test_audit( self.context, - id=2, + id=2, name='My Audit {0}'.format(2), goal_id=goal.id, strategy_id=strategy.id, uuid=utils.generate_uuid(), @@ -89,7 +89,7 @@ class TestStrategyContext(base.DbTestCase): audit = obj_utils.create_test_audit( self.context, - id=2, + id=2, name='My Audit {0}'.format(2), strategy_id=strategy.id, uuid=utils.generate_uuid(), ) diff --git a/watcher/tests/decision_engine/test_sync.py b/watcher/tests/decision_engine/test_sync.py index 7c9a038e0..3e60ee2ba 100644 --- a/watcher/tests/decision_engine/test_sync.py +++ b/watcher/tests/decision_engine/test_sync.py @@ -327,21 +327,21 @@ class TestSyncer(base.DbTestCase): # Should stay unmodified after sync() audit1 = objects.Audit( - self.ctx, id=1, uuid=utils.generate_uuid(), + self.ctx, id=1, uuid=utils.generate_uuid(), name='audit_1', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal1.id, strategy_id=strategy1.id, auto_trigger=False) # Should be modified by the sync() because its associated goal # has been modified (compared to the defined fake goals) audit2 = objects.Audit( - self.ctx, id=2, uuid=utils.generate_uuid(), + self.ctx, id=2, uuid=utils.generate_uuid(), name='audit_2', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal2.id, strategy_id=strategy2.id, auto_trigger=False) # Should be modified by the sync() because its associated strategy # has been modified (compared to the defined fake strategies) audit3 = objects.Audit( - self.ctx, id=3, uuid=utils.generate_uuid(), + self.ctx, id=3, uuid=utils.generate_uuid(), name='audit_3', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal1.id, strategy_id=strategy3.id, auto_trigger=False) @@ -349,7 +349,7 @@ class TestSyncer(base.DbTestCase): # strategy should be modified (compared to the defined fake # goals/strategies) audit4 = objects.Audit( - self.ctx, id=4, uuid=utils.generate_uuid(), + self.ctx, id=4, uuid=utils.generate_uuid(), name='audit_4', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal2.id, strategy_id=strategy4.id, auto_trigger=False) @@ -553,13 +553,13 @@ class TestSyncer(base.DbTestCase): # Should stay unmodified after sync() audit1 = objects.Audit( - self.ctx, id=1, uuid=utils.generate_uuid(), + self.ctx, id=1, uuid=utils.generate_uuid(), name='audit_1', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal1.id, strategy_id=strategy1.id, auto_trigger=False) # Stale after syncing because the goal has been soft deleted audit2 = objects.Audit( - self.ctx, id=2, uuid=utils.generate_uuid(), + self.ctx, id=2, uuid=utils.generate_uuid(), name='audit_2', audit_type=objects.audit.AuditType.ONESHOT.value, state=objects.audit.State.PENDING, goal_id=goal2.id, strategy_id=strategy2.id, auto_trigger=False) diff --git a/watcher/tests/objects/test_objects.py b/watcher/tests/objects/test_objects.py index 50dd62045..5c5b07893 100644 --- a/watcher/tests/objects/test_objects.py +++ b/watcher/tests/objects/test_objects.py @@ -412,7 +412,7 @@ expected_object_fingerprints = { 'Goal': '1.0-93881622db05e7b67a65ca885b4a022e', 'Strategy': '1.1-73f164491bdd4c034f48083a51bdeb7b', 'AuditTemplate': '1.1-b291973ffc5efa2c61b24fe34fdccc0b', - 'Audit': '1.3-f47ffb1ee79d8248eb991674bda565ce', + 'Audit': '1.4-f5f27510b8090bce7d1fb45416d58ff1', 'ActionPlan': '2.0-394f1abbf5d73d7b6675a118fe1a0284', 'Action': '2.0-1dd4959a7e7ac30c62ef170fe08dd935', 'EfficacyIndicator': '1.0-655b71234a82bc7478aff964639c4bb0',