From e3e5ba85abf6f29bc6a3b1f10ae94ade96041901 Mon Sep 17 00:00:00 2001 From: mounikasreeram Date: Tue, 12 Dec 2017 12:18:40 +0530 Subject: [PATCH] Add 'name' argument to 'Sync template' feature. At a single request more than one job is performing using 'Sync template' feature. To identify all the jobs performed at a single request, introduced 'name' argument in sync template feature. 'Sync list and Sync show' features formats are modified for better understanding. Added test-cases for the same. Depends-On: Change-Id: I95c7662958d2e59f867d2f1b6e912a4fe9036550 --- README.rst | 8 +- kingbirdclient/api/base.py | 9 +- kingbirdclient/api/v1/sync_manager.py | 7 +- kingbirdclient/commands/v1/sync_manager.py | 48 ++++++-- kingbirdclient/shell.py | 2 +- kingbirdclient/tests/v1/test_sync_manager.py | 118 ++++++++++++------- 6 files changed, 132 insertions(+), 60 deletions(-) diff --git a/README.rst b/README.rst index 74a9582..8c5c730 100644 --- a/README.rst +++ b/README.rst @@ -92,9 +92,9 @@ Eg:: resources: - fake_resource_1 - fake_resource_2 - source_region: + source: - fake_source_region - target_region: + target: - fake_target_region_1 - fake_target_region_2 @@ -111,8 +111,8 @@ Eg:: "fake_resource_1", "fake_resource_2" ], - "source_region":["fake_source_region"], - "target_region":["fake_target_region_1","fake_target_region_2"] + "source":["fake_source_region"], + "target":["fake_target_region_1","fake_target_region_2"] } ] } diff --git a/kingbirdclient/api/base.py b/kingbirdclient/api/base.py index cee24da..b3c38fa 100644 --- a/kingbirdclient/api/base.py +++ b/kingbirdclient/api/base.py @@ -83,7 +83,8 @@ class ResourceManager(object): json_object = json_response_key['job_status'] resource = [] resource.append(self.resource_class( - self, id=json_object['id'], + self, name=json_object['name'], + id=json_object['id'], status=json_object['status'], created_at=json_object['created_at'])) return resource @@ -97,7 +98,8 @@ class ResourceManager(object): resource = [] for json_object in json_objects: resource.append(self.resource_class( - self, id=json_object['id'], + self, name=json_object['name'], + id=json_object['id'], status=json_object['sync_status'], created_at=json_object['created_at'], updated_at=json_object['updated_at'])) @@ -112,7 +114,8 @@ class ResourceManager(object): resource = [] for json_object in json_objects: resource.append(self.resource_class( - self, resource_name=json_object['resource'], + self, id=json_object['id'], + resource_name=json_object['resource'], source_region=json_object['source_region'], target_region=json_object['target_region'], resource_type=json_object['resource_type'], diff --git a/kingbirdclient/api/v1/sync_manager.py b/kingbirdclient/api/v1/sync_manager.py index 6fcdffb..d916981 100644 --- a/kingbirdclient/api/v1/sync_manager.py +++ b/kingbirdclient/api/v1/sync_manager.py @@ -21,8 +21,9 @@ class Resource(base.Resource): def __init__(self, manager, status, created_at, updated_at=None, resource_type=None, target_region=None, - source_region=None, id=None, resource_name=None,): + source_region=None, name=None, id=None, resource_name=None,): self.manager = manager + self.name = name self.id = id self.source_region = source_region self.target_region = target_region @@ -50,9 +51,9 @@ class SyncManager(base.ResourceManager): url = '/%s/os-sync/%s' % (tenant, action) return self._resource_sync_list(url) - def sync_job_detail(self, job_id): + def sync_job_detail(self, job): tenant = self.http_client.project_id - url = '/%s/os-sync/%s' % (tenant, job_id) + url = '/%s/os-sync/%s' % (tenant, job) return self._resource_sync_detail(url) def delete_sync_job(self, job_id): diff --git a/kingbirdclient/commands/v1/sync_manager.py b/kingbirdclient/commands/v1/sync_manager.py index e5c7d7f..2567fb1 100644 --- a/kingbirdclient/commands/v1/sync_manager.py +++ b/kingbirdclient/commands/v1/sync_manager.py @@ -23,6 +23,7 @@ from kingbirdclient import exceptions def format(resources=None): columns = ( + 'NAME', 'ID', 'STATUS', 'CREATED_AT', @@ -31,6 +32,7 @@ def format(resources=None): if resources: data = ( + resources.name, resources.id, resources.status, resources.created_at, @@ -45,6 +47,7 @@ def format(resources=None): def detail_format(resources=None): columns = ( + 'ID', 'RESOURCE', 'SOURCE_REGION', 'TARGET_REGION', @@ -56,6 +59,7 @@ def detail_format(resources=None): if resources: data = ( + resources.id, resources.resource_name, resources.source_region, resources.target_region, @@ -91,6 +95,26 @@ def sync_format(resources=None): return columns, data +def template_sync_format(resources=None): + columns = ( + 'NAME', + 'STATUS', + 'CREATED_AT', + ) + + if resources: + data = ( + resources.name, + resources.status, + resources.created_at, + ) + + else: + data = (tuple('' for _ in range(len(columns))),) + + return columns, data + + class ResourceSync(base.KingbirdLister): """Sync Resources from One region to other.""" @@ -149,7 +173,7 @@ class TemplateResourceSync(base.KingbirdLister): """Sync multiple resource-types to multiple regions.""" def _get_format_function(self): - return sync_format + return template_sync_format def get_parser(self, parsed_args): parser = super(TemplateResourceSync, self).get_parser(parsed_args) @@ -160,12 +184,18 @@ class TemplateResourceSync(base.KingbirdLister): help='Specify the name of an input file in .yaml/.yml/.json.' ) + parser.add_argument( + '--name', + required=True, + help='Name of the job.' + ) return parser def _get_resources(self, parsed_args): kingbird_client = self.app.client_manager.sync_engine kwargs = dict() sync_template = parsed_args.template + kwargs['name'] = parsed_args.name if sync_template.endswith('.yaml') or sync_template.endswith('.yml') \ or sync_template.endswith('.json'): try: @@ -181,16 +211,16 @@ class TemplateResourceSync(base.KingbirdLister): raise exceptions.TemplateError( 'Provide a template with a valid extension(.yaml/.yml/.json)') for iteration in data['Sync']: - if 'source_region' not in iteration: + if 'source' not in iteration: raise exceptions.TemplateError( 'source_region parameter is missing in template') - if not iteration['source_region']: + if not iteration['source']: raise exceptions.TemplateError( 'source_region parameter value is missing') - if 'target_region' not in iteration: + if 'target' not in iteration: raise exceptions.TemplateError( 'target_region parameter is missing in template') - if not iteration['target_region']: + if not iteration['target']: raise exceptions.TemplateError( 'target_region parameter value is missing') if 'resource_type' not in iteration: @@ -247,16 +277,16 @@ class SyncShow(base.KingbirdLister): parser = super(SyncShow, self).get_parser(parsed_args) parser.add_argument( - 'job_id', - help='ID of Job to view the details.' + 'job', + help='ID/Name of the job to view the details.' ) return parser def _get_resources(self, parsed_args): - job_id = parsed_args.job_id + job = parsed_args.job kingbird_client = self.app.client_manager.sync_engine - return kingbird_client.sync_manager.sync_job_detail(job_id) + return kingbird_client.sync_manager.sync_job_detail(job) class SyncDelete(command.Command): diff --git a/kingbirdclient/shell.py b/kingbirdclient/shell.py index 4662a46..c51d011 100644 --- a/kingbirdclient/shell.py +++ b/kingbirdclient/shell.py @@ -13,7 +13,7 @@ # limitations under the License. """ -Command-line interface to the Kingbird APIs +Command-line interface to the Kingbird APIs. """ import logging diff --git a/kingbirdclient/tests/v1/test_sync_manager.py b/kingbirdclient/tests/v1/test_sync_manager.py index 1f69f80..b90ccf0 100644 --- a/kingbirdclient/tests/v1/test_sync_manager.py +++ b/kingbirdclient/tests/v1/test_sync_manager.py @@ -31,22 +31,23 @@ FAKE_RESOURCE = 'fake_item' FAKE_SOURCE_REGION = 'fake_region_1' FAKE_TARGET_REGION = 'fake_region_2' FAKE_RESOURCE_TYPE = 'fake_resource' +FAKE_NAME = 'fake_name' tempdef = """Sync: - resource_type: fake_resource_type resources: - fake_resource_1 - fake_resource_2 - source_region: + source: - fake_source_region - target_region: + target: - fake_target_region_1 - fake_target_region_2 """ RESOURCE_TYPE_INDEX = tempdef.index('resource_type:') RESOURCE_INDEX = tempdef.index('resources:') -SOURCE_INDEX = tempdef.index('source_region:') -TARGET_INDEX = tempdef.index('target_region:') +SOURCE_INDEX = tempdef.index('source:') +TARGET_INDEX = tempdef.index('target:') tempdefjson = """{ "Sync": [ @@ -56,18 +57,19 @@ tempdefjson = """{ "fake_resource_1", "fake_resource_2" ], - "source_region":["fake_source_region"], - "target_region":["fake_target_region_1","fake_target_region_2"] + "source":["fake_source_region"], + "target":["fake_target_region_1","fake_target_region_2"] } ] } """ RESOURCE_TYPE_INDEX_JSON = tempdefjson.index('"resource_type"') RESOURCE_INDEX_JSON = tempdefjson.index('"resources"') -SOURCE_INDEX_JSON = tempdefjson.index('"source_region"') +SOURCE_INDEX_JSON = tempdefjson.index('"source"') TARGET_INDEX_JSON = tempdefjson.index(",", SOURCE_INDEX_JSON) RESOURCE_DICT = { + 'NAME': FAKE_NAME, 'ID': ID, 'STATUS': FAKE_STATUS, 'CREATED_AT': TIME_NOW, @@ -75,23 +77,27 @@ RESOURCE_DICT = { } ACTIVE_RESOURCE_DICT = { + 'NAME': FAKE_NAME, 'ID': ID, 'STATUS': ACTIVE_FAKE_STATUS, 'CREATED_AT': TIME_NOW, 'UPDATED_AT': TIME_NOW } -SYNCMANAGER = sm.Resource(mock, id=RESOURCE_DICT['ID'], +SYNCMANAGER = sm.Resource(mock, name=FAKE_NAME, + id=RESOURCE_DICT['ID'], status=RESOURCE_DICT['STATUS'], created_at=RESOURCE_DICT['CREATED_AT'], updated_at=RESOURCE_DICT['UPDATED_AT']) -ACTIVE_SYNCMANAGER = sm.Resource(mock, id=ACTIVE_RESOURCE_DICT['ID'], +ACTIVE_SYNCMANAGER = sm.Resource(mock, name=FAKE_NAME, + id=ACTIVE_RESOURCE_DICT['ID'], status=ACTIVE_RESOURCE_DICT['STATUS'], created_at=ACTIVE_RESOURCE_DICT['CREATED_AT'], updated_at=ACTIVE_RESOURCE_DICT['UPDATED_AT']) DETAIL_RESOURCE_DICT = { + 'ID': ID, 'RESOURCE': FAKE_RESOURCE, 'SOURCE_REGION': FAKE_SOURCE_REGION, 'TARGET_REGION': FAKE_TARGET_REGION, @@ -102,7 +108,8 @@ DETAIL_RESOURCE_DICT = { } DETAIL_RESOURCEMANAGER = sm.Resource( - mock, resource_name=DETAIL_RESOURCE_DICT['RESOURCE'], + mock, id=DETAIL_RESOURCE_DICT['ID'], + resource_name=DETAIL_RESOURCE_DICT['RESOURCE'], source_region=DETAIL_RESOURCE_DICT['SOURCE_REGION'], target_region=DETAIL_RESOURCE_DICT['TARGET_REGION'], resource_type=DETAIL_RESOURCE_DICT['RESOURCE_TYPE'], @@ -114,6 +121,11 @@ SYNC_RESOURCEMANAGER = sm.Resource(mock, id=RESOURCE_DICT['ID'], status=RESOURCE_DICT['STATUS'], created_at=RESOURCE_DICT['CREATED_AT']) +TEMPLATE_SYNC_RESOURCEMANAGER = sm.Resource(mock, name=RESOURCE_DICT['NAME'], + status=RESOURCE_DICT['STATUS'], + created_at=RESOURCE_DICT[ + 'CREATED_AT']) + class TestCLISyncManagerV1(base.BaseCommandTest): """Testcases for sync command.""" @@ -121,20 +133,21 @@ class TestCLISyncManagerV1(base.BaseCommandTest): def test_sync_jobs_list(self): self.client.sync_manager.list_sync_jobs.return_value = [SYNCMANAGER] actual_call = self.call(sync_cmd.SyncList) - self.assertEqual([(ID, FAKE_STATUS, TIME_NOW, TIME_NOW)], + self.assertEqual([(FAKE_NAME, ID, FAKE_STATUS, TIME_NOW, TIME_NOW)], actual_call[1]) def test_negative_sync_jobs_list(self): self.client.sync_manager.list_sync_jobs.return_value = [] actual_call = self.call(sync_cmd.SyncList) - self.assertEqual((('', '', '', ''),), + self.assertEqual((('', '', '', '', ''),), actual_call[1]) def test_active_sync_jobs_list(self): self.client.sync_manager.list_sync_jobs.\ return_value = [ACTIVE_SYNCMANAGER] actual_call = self.call(sync_cmd.SyncList, app_args=['--active']) - self.assertEqual([(ID, ACTIVE_FAKE_STATUS, TIME_NOW, TIME_NOW)], + self.assertEqual([(FAKE_NAME, ID, ACTIVE_FAKE_STATUS, + TIME_NOW, TIME_NOW)], actual_call[1]) def test_active_sync_jobs_negative(self): @@ -157,21 +170,21 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises(SystemExit, self.call, sync_cmd.SyncDelete, app_args=[]) - def test_detail_sync_job_with_job_id(self): + def test_detail_sync_job_with_job(self): self.client.sync_manager.sync_job_detail.\ return_value = [DETAIL_RESOURCEMANAGER] actual_call = self.call(sync_cmd.SyncShow, app_args=[ID]) - self.assertEqual([(FAKE_RESOURCE, FAKE_SOURCE_REGION, + self.assertEqual([(ID, FAKE_RESOURCE, FAKE_SOURCE_REGION, FAKE_TARGET_REGION, FAKE_RESOURCE_TYPE, FAKE_STATUS, TIME_NOW, TIME_NOW)], actual_call[1]) def test_detail_sync_job_negative(self): self.client.sync_manager.sync_job_detail.return_value = [] actual_call = self.call(sync_cmd.SyncShow, app_args=[ID]) - self.assertEqual((('', '', '', '', + self.assertEqual((('', '', '', '', '', '', '', ''),), actual_call[1]) - def test_detail_sync_job_without_job_id(self): + def test_detail_sync_job_without_job(self): self.assertRaises(SystemExit, self.call, sync_cmd.SyncShow, app_args=[]) @@ -182,8 +195,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): sync_cmd.ResourceSync, app_args=[ '--resource_type', FAKE_RESOURCE_TYPE, '--resources', FAKE_RESOURCE, - '--source', FAKE_SOURCE_REGION, '--target', - FAKE_TARGET_REGION]) + '--source', FAKE_SOURCE_REGION, + '--target', FAKE_TARGET_REGION]) self.assertEqual([(ID, FAKE_STATUS, TIME_NOW)], actual_call[1]) def test_resource_sync_without_resources(self): @@ -239,11 +252,12 @@ class TestCLISyncManagerV1(base.BaseCommandTest): f.write(tempdef) f.close() self.client.sync_manager.sync_resources.\ - return_value = [SYNC_RESOURCEMANAGER] + return_value = [TEMPLATE_SYNC_RESOURCEMANAGER] actual_call = self.call( sync_cmd.TemplateResourceSync, app_args=[ - '--template', 'test_template.yaml']) - self.assertEqual([(ID, FAKE_STATUS, TIME_NOW)], actual_call[1]) + '--template', 'test_template.yaml', + '--name', FAKE_NAME]) + self.assertEqual([(FAKE_NAME, FAKE_STATUS, TIME_NOW)], actual_call[1]) os.remove("test_template.yaml") def test_template_resource_sync_with_template_yml(self): @@ -251,11 +265,12 @@ class TestCLISyncManagerV1(base.BaseCommandTest): f.write(tempdef) f.close() self.client.sync_manager.sync_resources.\ - return_value = [SYNC_RESOURCEMANAGER] + return_value = [TEMPLATE_SYNC_RESOURCEMANAGER] actual_call = self.call( sync_cmd.TemplateResourceSync, app_args=[ - '--template', 'test_template.yml']) - self.assertEqual([(ID, FAKE_STATUS, TIME_NOW)], actual_call[1]) + '--template', 'test_template.yml', + '--name', FAKE_NAME]) + self.assertEqual([(FAKE_NAME, FAKE_STATUS, TIME_NOW)], actual_call[1]) os.remove("test_template.yml") def test_template_resource_sync_with_template_json(self): @@ -263,24 +278,40 @@ class TestCLISyncManagerV1(base.BaseCommandTest): f.write(tempdefjson) f.close() self.client.sync_manager.sync_resources.\ - return_value = [SYNC_RESOURCEMANAGER] + return_value = [TEMPLATE_SYNC_RESOURCEMANAGER] actual_call = self.call( sync_cmd.TemplateResourceSync, app_args=[ - '--template', 'test_template.json']) - self.assertEqual([(ID, FAKE_STATUS, TIME_NOW)], actual_call[1]) + '--template', 'test_template.json', + '--name', FAKE_NAME]) + self.assertEqual([(FAKE_NAME, FAKE_STATUS, TIME_NOW)], actual_call[1]) os.remove("test_template.json") - def test_template_resource_sync_without_template(self): + def test_template_resource_sync_without_arguments(self): self.client.sync_manager.sync_resources.\ return_value = [SYNC_RESOURCEMANAGER] self.assertRaises( SystemExit, self.call, sync_cmd.TemplateResourceSync, app_args=[]) + def test_template_resource_sync_without_template(self): + self.client.sync_manager.sync_resources.\ + return_value = [SYNC_RESOURCEMANAGER] + self.assertRaises( + SystemExit, self.call, sync_cmd.TemplateResourceSync, + app_args=['--name', FAKE_NAME]) + + def test_template_resource_sync_without_name(self): + self.client.sync_manager.sync_resources.\ + return_value = [SYNC_RESOURCEMANAGER] + self.assertRaises( + SystemExit, self.call, sync_cmd.TemplateResourceSync, app_args=[ + '--template', 'test_template.yaml']) + def test_template_resource_sync_invalid_extension(self): self.assertRaises( exceptions.TemplateError, self.call, - sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_template.yzx']) + sync_cmd.TemplateResourceSync, app_args=[ + '--template', 'test_template.yzx', + '--name', 'FAKE_NAME']) def test_template_resource_sync_source_missing_yaml(self): temp = tempdef.replace(tempdef[SOURCE_INDEX:TARGET_INDEX], "") @@ -290,7 +321,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_source_missing_template.yaml']) + app_args=['--template', 'test_source_missing_template.yaml', + '--name', FAKE_NAME]) os.remove("test_source_missing_template.yaml") def test_template_resource_sync_target_missing_yaml(self): @@ -301,7 +333,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_target_missing_template.yaml']) + app_args=['--template', 'test_target_missing_template.yaml', + '--name', FAKE_NAME]) os.remove("test_target_missing_template.yaml") def test_template_resource_sync_resource_type_missing_yaml(self): @@ -313,7 +346,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, app_args=['--template', - 'test_resource_type_missing_template.yaml']) + 'test_resource_type_missing_template.yaml', + '--name', FAKE_NAME]) os.remove("test_resource_type_missing_template.yaml") def test_template_resource_sync_resources_missing_yaml(self): @@ -324,7 +358,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_resource_missing_template.yaml']) + app_args=['--template', 'test_resource_missing_template.yaml', + '--name', FAKE_NAME]) os.remove("test_resource_missing_template.yaml") def test_template_resource_sync_source_missing_json(self): @@ -336,8 +371,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', - 'test_source_missing_template.json']) + app_args=['--template', 'test_source_missing_template.json', + '--name', FAKE_NAME]) os.remove("test_source_missing_template.json") def test_template_resource_sync_target_missing_json(self): @@ -349,7 +384,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_target_missing_template.json']) + app_args=['--template', 'test_target_missing_template.json', + '--name', FAKE_NAME]) os.remove("test_target_missing_template.json") def test_template_resource_sync_resource_type_missing_json(self): @@ -362,7 +398,8 @@ class TestCLISyncManagerV1(base.BaseCommandTest): exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, app_args=['--template', - 'test_resource_type_missing_template.json']) + 'test_resource_type_missing_template.json', + '--name', FAKE_NAME]) os.remove("test_resource_type_missing_template.json") def test_template_resource_sync_resources_missing_json(self): @@ -374,5 +411,6 @@ class TestCLISyncManagerV1(base.BaseCommandTest): self.assertRaises( exceptions.TemplateError, self.call, sync_cmd.TemplateResourceSync, - app_args=['--template', 'test_resource_missing_template.json']) + app_args=['--template', 'test_resource_missing_template.json', + '--name', FAKE_NAME]) os.remove("test_resource_missing_template.json")