diff --git a/doc/source/reference/api_v1.rst b/doc/source/reference/api_v1.rst index 911623b..45555b7 100644 --- a/doc/source/reference/api_v1.rst +++ b/doc/source/reference/api_v1.rst @@ -68,7 +68,7 @@ Once you have an watcher `Client`_, you can perform various tasks:: >>> watcher.action.list() # list of actions >>> watcher.action_plan.list() # list of action_plan - >>> watcher.audit.get(audit_uuid) # information about a particular audit + >>> watcher.audit.get(audit_uuid_or_name) # information about a particular audit When the `Client`_ needs to propagate an exception, it will usually raise an instance subclassed from diff --git a/watcherclient/tests/functional/v1/test_audit.py b/watcherclient/tests/functional/v1/test_audit.py index b12fa06..11b26e3 100644 --- a/watcherclient/tests/functional/v1/test_audit.py +++ b/watcherclient/tests/functional/v1/test_audit.py @@ -22,7 +22,7 @@ class AuditTests(base.TestCase): """Functional tests for audit.""" dummy_name = 'dummy' - list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy'] + list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy'] detailed_list_fields = list_fields + ['Created At', 'Updated At', 'Deleted At', 'Parameters', 'Interval', 'Audit Scope', @@ -71,7 +71,7 @@ class AuditTests(base.TestCase): class AuditActiveTests(base.TestCase): - list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy'] + list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy'] detailed_list_fields = list_fields + ['Created At', 'Updated At', 'Deleted At', 'Parameters', 'Interval', 'Audit Scope'] diff --git a/watcherclient/tests/unit/v1/test_audit_shell.py b/watcherclient/tests/unit/v1/test_audit_shell.py old mode 100644 new mode 100755 index 5afed99..f196b84 --- a/watcherclient/tests/unit/v1/test_audit_shell.py +++ b/watcherclient/tests/unit/v1/test_audit_shell.py @@ -17,7 +17,6 @@ import datetime import mock import six -from watcherclient import exceptions from watcherclient import shell from watcherclient.tests.unit.v1 import base from watcherclient import v1 as resource @@ -69,6 +68,7 @@ AUDIT_1 = { 'scope': '', 'auto_trigger': False, 'next_run_time': None, + 'name': 'my_audit1', } AUDIT_2 = { @@ -87,6 +87,7 @@ AUDIT_2 = { 'scope': '', 'auto_trigger': False, 'next_run_time': None, + 'name': 'my_audit2', } AUDIT_3 = { @@ -105,6 +106,7 @@ AUDIT_3 = { 'scope': '', 'auto_trigger': True, 'next_run_time': None, + 'name': 'my_audit3', } @@ -202,14 +204,19 @@ class AuditShellTest(base.CommandTestCase): self.m_audit_mgr.get.assert_called_once_with( '5869da81-4876-4687-a1ed-12cd64cf53d9') - def test_do_audit_show_by_not_uuid(self): - self.m_audit_mgr.get.side_effect = exceptions.HTTPNotFound + def test_do_audit_show_by_name(self): + audit = resource.Audit(mock.Mock(), AUDIT_1) + self.m_audit_mgr.get.return_value = audit exit_code, result = self.run_cmd( - 'audit show not_uuid', formatting=None) + 'audit show my_audit') - self.assertEqual(1, exit_code) - self.assertEqual('', result) + self.assertEqual(0, exit_code) + self.assertEqual( + self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS), + result) + self.m_audit_mgr.get.assert_called_once_with( + 'my_audit') def test_do_audit_delete(self): self.m_audit_mgr.delete.return_value = '' @@ -223,6 +230,18 @@ class AuditShellTest(base.CommandTestCase): self.m_audit_mgr.delete.assert_called_once_with( '5869da81-4876-4687-a1ed-12cd64cf53d9') + def test_do_audit_delete_by_name(self): + self.m_audit_mgr.delete.return_value = '' + + exit_code, result = self.run_cmd( + 'audit delete my_audit', + formatting=None) + + self.assertEqual(0, exit_code) + self.assertEqual('', result) + self.m_audit_mgr.delete.assert_called_once_with( + 'my_audit') + def test_do_audit_delete_multiple(self): self.m_audit_mgr.delete.return_value = '' @@ -238,16 +257,6 @@ class AuditShellTest(base.CommandTestCase): self.m_audit_mgr.delete.assert_any_call( '5b157edd-5a7e-4aaa-b511-f7b33ec86e9f') - def test_do_audit_delete_with_not_uuid(self): - self.m_audit_mgr.delete.return_value = '' - - exit_code, result = self.run_cmd( - 'audit delete not_uuid', - formatting=None) - - self.assertEqual(1, exit_code) - self.assertEqual('', result) - def test_do_audit_update(self): audit = resource.Audit(mock.Mock(), AUDIT_1) self.m_audit_mgr.update.return_value = audit @@ -264,14 +273,20 @@ class AuditShellTest(base.CommandTestCase): '5869da81-4876-4687-a1ed-12cd64cf53d9', [{'op': 'replace', 'path': '/state', 'value': 'PENDING'}]) - def test_do_audit_update_with_not_uuid(self): - self.m_audit_mgr.update.return_value = '' + def test_do_audit_update_by_name(self): + audit = resource.Audit(mock.Mock(), AUDIT_1) + self.m_audit_mgr.update.return_value = audit exit_code, result = self.run_cmd( - 'audit update not_uuid replace state=PENDING', formatting=None) + 'audit update my_audit replace state=PENDING') - self.assertEqual(1, exit_code) - self.assertEqual('', result) + self.assertEqual(0, exit_code) + self.assertEqual( + self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS), + result) + self.m_audit_mgr.update.assert_called_once_with( + 'my_audit', + [{'op': 'replace', 'path': '/state', 'value': 'PENDING'}]) def test_do_audit_create_with_audit_template_uuid(self): audit = resource.Audit(mock.Mock(), AUDIT_3) @@ -288,7 +303,9 @@ class AuditShellTest(base.CommandTestCase): result) self.m_audit_mgr.create.assert_called_once_with( audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2', - audit_type='ONESHOT', auto_trigger=False) + audit_type='ONESHOT', + auto_trigger=False + ) def test_do_audit_create_with_audit_template_name(self): audit = resource.Audit(mock.Mock(), AUDIT_3) @@ -305,7 +322,8 @@ class AuditShellTest(base.CommandTestCase): self.m_audit_mgr.create.assert_called_once_with( audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2', auto_trigger=False, - audit_type='ONESHOT') + audit_type='ONESHOT' + ) def test_do_audit_create_with_goal(self): audit = resource.Audit(mock.Mock(), AUDIT_1) @@ -356,7 +374,9 @@ class AuditShellTest(base.CommandTestCase): result) self.m_audit_mgr.create.assert_called_once_with( goal='fc087747-61be-4aad-8126-b701731ae836', - auto_trigger=False, audit_type='ONESHOT') + auto_trigger=False, + audit_type='ONESHOT' + ) def test_do_audit_create_with_parameter(self): audit = resource.Audit(mock.Mock(), AUDIT_1) @@ -374,7 +394,8 @@ class AuditShellTest(base.CommandTestCase): goal='fc087747-61be-4aad-8126-b701731ae836', audit_type='ONESHOT', auto_trigger=False, - parameters={'para1': 10, 'para2': 20}) + parameters={'para1': 10, 'para2': 20} + ) def test_do_audit_create_with_type_continuous(self): audit = resource.Audit(mock.Mock(), AUDIT_1) @@ -392,4 +413,25 @@ class AuditShellTest(base.CommandTestCase): goal='fc087747-61be-4aad-8126-b701731ae836', audit_type='CONTINUOUS', auto_trigger=False, - interval='3600') + interval='3600' + ) + + def test_do_audit_create_with_name(self): + audit = resource.Audit(mock.Mock(), AUDIT_1) + self.m_audit_mgr.create.return_value = audit + + exit_code, result = self.run_cmd( + 'audit create -g fc087747-61be-4aad-8126-b701731ae836 ' + '-t CONTINUOUS -i 3600 --name my_audit') + + self.assertEqual(0, exit_code) + self.assertEqual( + self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS), + result) + self.m_audit_mgr.create.assert_called_once_with( + goal='fc087747-61be-4aad-8126-b701731ae836', + audit_type='CONTINUOUS', + auto_trigger=False, + interval='3600', + name='my_audit' + ) diff --git a/watcherclient/v1/audit.py b/watcherclient/v1/audit.py index 863ff5b..81e0b5b 100644 --- a/watcherclient/v1/audit.py +++ b/watcherclient/v1/audit.py @@ -19,7 +19,8 @@ from watcherclient import exceptions as exc CREATION_ATTRIBUTES = ['audit_template_uuid', 'audit_type', 'interval', - 'parameters', 'goal', 'strategy', 'auto_trigger'] + 'parameters', 'goal', 'strategy', 'auto_trigger', + 'name'] class Audit(base.Resource): @@ -38,8 +39,7 @@ class AuditManager(base.Manager): sort_dir=None, detail=False, goal=None, strategy=None): """Retrieve a list of audit. - :param audit_template: Name of the audit - :param name: Name of the audit + :param audit_template: Name of the audit template :param limit: The maximum number of results to return per request, if: @@ -92,14 +92,14 @@ class AuditManager(base.Manager): raise exc.InvalidAttribute() return self._create(self._path(), new) - def get(self, audit_id): + def get(self, audit): try: - return self._list(self._path(audit_id))[0] + return self._list(self._path(audit))[0] except IndexError: return None - def delete(self, audit_id): - return self._delete(self._path(audit_id)) + def delete(self, audit): + return self._delete(self._path(audit)) - def update(self, audit_id, patch): - return self._update(self._path(audit_id), patch) + def update(self, audit, patch): + return self._update(self._path(audit), patch) diff --git a/watcherclient/v1/audit_shell.py b/watcherclient/v1/audit_shell.py index 6f48fb6..ce05937 100644 --- a/watcherclient/v1/audit_shell.py +++ b/watcherclient/v1/audit_shell.py @@ -31,7 +31,7 @@ class ShowAudit(command.ShowOne): parser.add_argument( 'audit', metavar='', - help=_('UUID of the audit'), + help=_('UUID or name of the audit'), ) return parser @@ -175,13 +175,19 @@ class CreateAudit(command.ShowOne): default=False, help=_('Trigger automatically action plan ' 'once audit is succeeded.')) + parser.add_argument( + '--name', + dest='name', + metavar='', + help=_('Name for this audit.')) + return parser def take_action(self, parsed_args): client = getattr(self.app.client_manager, "infra-optim") field_list = ['audit_template_uuid', 'audit_type', 'parameters', - 'interval', 'goal', 'strategy', 'auto_trigger'] + 'interval', 'goal', 'strategy', 'auto_trigger', 'name'] fields = dict((k, v) for (k, v) in vars(parsed_args).items() if k in field_list and v is not None) @@ -219,7 +225,7 @@ class UpdateAudit(command.ShowOne): parser.add_argument( 'audit', metavar='', - help=_("UUID of the audit.")) + help=_("UUID or name of the audit.")) parser.add_argument( 'op', metavar='', @@ -239,9 +245,6 @@ class UpdateAudit(command.ShowOne): def take_action(self, parsed_args): client = getattr(self.app.client_manager, "infra-optim") - if not uuidutils.is_uuid_like(parsed_args.audit): - raise exceptions.ValidationError() - patch = common_utils.args_array_to_patch( parsed_args.op, parsed_args.attributes[0], exclude_fields=['/interval']) @@ -263,7 +266,7 @@ class DeleteAudit(command.Command): 'audits', metavar='', nargs='+', - help=_('UUID of the audit'), + help=_('UUID or name of the audit'), ) return parser @@ -271,7 +274,4 @@ class DeleteAudit(command.Command): client = getattr(self.app.client_manager, "infra-optim") for audit in parsed_args.audits: - if not uuidutils.is_uuid_like(audit): - raise exceptions.ValidationError() - client.audit.delete(audit) diff --git a/watcherclient/v1/resource_fields.py b/watcherclient/v1/resource_fields.py index 7ef9802..7252411 100755 --- a/watcherclient/v1/resource_fields.py +++ b/watcherclient/v1/resource_fields.py @@ -30,20 +30,20 @@ AUDIT_TEMPLATE_SHORT_LIST_FIELDS = [ AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Goal', 'Strategy'] # Audit -AUDIT_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at', +AUDIT_FIELDS = ['uuid', 'name', 'created_at', 'updated_at', 'deleted_at', 'state', 'audit_type', 'parameters', 'interval', 'goal_name', 'strategy_name', 'scope', 'auto_trigger', 'next_run_time'] -AUDIT_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At', +AUDIT_FIELD_LABELS = ['UUID', 'Name', 'Created At', 'Updated At', 'Deleted At', 'State', 'Audit Type', 'Parameters', 'Interval', 'Goal', 'Strategy', 'Audit Scope', 'Auto Trigger', 'Next Run Time'] -AUDIT_SHORT_LIST_FIELDS = ['uuid', 'audit_type', +AUDIT_SHORT_LIST_FIELDS = ['uuid', 'name', 'audit_type', 'state', 'goal_name', 'strategy_name', 'auto_trigger'] -AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit Type', 'State', 'Goal', +AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy', 'Auto Trigger'] # Action Plan