From af4d8343ad8badb0ac9f95dc987e3bf1223a6202 Mon Sep 17 00:00:00 2001 From: Shubham Potale Date: Mon, 23 Dec 2019 19:30:37 +0530 Subject: [PATCH] Add command for update vnf package API Added command support for updating vnf package. Please see results here:- http://paste.openstack.org/show/788463 Change-Id: I0cd32d531db569b7013332fcfaaaefde403e7aed Implements: bp enhance-vnf-package-support-part1 --- setup.cfg | 1 + tackerclient/osc/sdk_utils.py | 10 +++ tackerclient/osc/v1/vnfpkgm/vnf_package.py | 61 +++++++++++++++++ .../tests/unit/osc/v1/test_vnf_package.py | 68 ++++++++++++++++++- .../tests/unit/osc/v1/vnf_package_fakes.py | 13 ++++ tackerclient/v1_0/client.py | 11 +++ 6 files changed, 162 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index a9962d2f..dded90e2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -82,6 +82,7 @@ openstack.tackerclient.v1 = vnf_package_show = tackerclient.osc.v1.vnfpkgm.vnf_package:ShowVnfPackage vnf_package_upload = tackerclient.osc.v1.vnfpkgm.vnf_package:UploadVnfPackage vnf_package_delete = tackerclient.osc.v1.vnfpkgm.vnf_package:DeleteVnfPackage + vnf_package_update = tackerclient.osc.v1.vnfpkgm.vnf_package:UpdateVnfPackage vnflcm_create = tackerclient.osc.v1.vnflcm.vnflcm:CreateVnfLcm vnflcm_show = tackerclient.osc.v1.vnflcm.vnflcm:ShowVnfLcm vnflcm_list = tackerclient.osc.v1.vnflcm.vnflcm:ListVnfLcm diff --git a/tackerclient/osc/sdk_utils.py b/tackerclient/osc/sdk_utils.py index 5d969bde..ff2d570c 100644 --- a/tackerclient/osc/sdk_utils.py +++ b/tackerclient/osc/sdk_utils.py @@ -10,6 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. +import sys + +from oslo_utils import encodeutils + def get_osc_show_columns_for_sdk_resource( sdk_resource, @@ -100,3 +104,9 @@ class DictModel(dict): def __str__(self): pairs = ['%s=%s' % (k, v) for k, v in self.items()] return ', '.join(sorted(pairs)) + + +def exit(msg=None, exit_code=1): + if msg: + print(encodeutils.safe_decode(msg)) + sys.exit(exit_code) diff --git a/tackerclient/osc/v1/vnfpkgm/vnf_package.py b/tackerclient/osc/v1/vnfpkgm/vnf_package.py index 18d7cfb5..7301eb54 100644 --- a/tackerclient/osc/v1/vnfpkgm/vnf_package.py +++ b/tackerclient/osc/v1/vnfpkgm/vnf_package.py @@ -256,3 +256,64 @@ class DeleteVnfPackage(command.Command): print((_('All specified %(resource)s(s) deleted successfully') % {'resource': self.resource})) return + + +class UpdateVnfPackage(command.ShowOne): + _description = _("Update information about an individual VNF package") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(UpdateVnfPackage, self).get_parser(prog_name) + parser.add_argument( + 'vnf_package', + metavar="", + help=_("VNF package ID") + ) + parser.add_argument( + '--operational-state', + metavar="", + choices=['ENABLED', 'DISABLED'], + help=_("Change the operational state of VNF Package, Valid values" + " are 'ENABLED' or 'DISABLED'.") + ) + parser.add_argument( + '--user-data', + metavar='', + action=parseractions.KeyValueAction, + help=_('User defined data for the VNF package ' + '(repeat option to set multiple user defined data)'), + ) + return parser + + def get_columns(self, updated_values): + column_map = {} + if updated_values.get('userDefinedData'): + column_map.update({'userDefinedData': 'User Defined Data'}) + + if updated_values.get('operationalState'): + column_map.update({'operationalState': 'Operational State'}) + + return sdk_utils.get_osc_show_columns_for_sdk_resource(updated_values, + column_map) + + def args2body(self, parsed_args): + body = {} + if not parsed_args.user_data and not parsed_args.operational_state: + msg = ('Provide at least one of the argument from "--user-data"' + ' or "--operational-state"') + sdk_utils.exit(msg) + if parsed_args.user_data: + body["userDefinedData"] = parsed_args.user_data + if parsed_args.operational_state: + body["operationalState"] = parsed_args.operational_state + return body + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + updated_values = client.update_vnf_package( + parsed_args.vnf_package, self.args2body(parsed_args)) + display_columns, columns = self.get_columns(updated_values) + data = utils.get_item_properties( + sdk_utils.DictModel(updated_values), + columns, mixed_case_fields=_mixed_case_fields) + return (display_columns, data) diff --git a/tackerclient/tests/unit/osc/v1/test_vnf_package.py b/tackerclient/tests/unit/osc/v1/test_vnf_package.py index e06f86c0..10b91f77 100644 --- a/tackerclient/tests/unit/osc/v1/test_vnf_package.py +++ b/tackerclient/tests/unit/osc/v1/test_vnf_package.py @@ -39,8 +39,16 @@ def _create_zip(): def _get_columns_vnf_package(action='list', vnf_package_obj=None): - columns = ['ID', 'Onboarding State', 'Operational State', 'Usage State', - 'User Defined Data', 'VNF Product Name'] + columns = [] + if action == 'update': + if vnf_package_obj.get('userDefinedData'): + columns.extend(['User Defined Data']) + if vnf_package_obj.get('operationalState'): + columns.extend(['Operational State']) + return columns + + columns.extend(['ID', 'Onboarding State', 'Operational State', + 'Usage State', 'User Defined Data', 'VNF Product Name']) if action in ['show', 'create']: if vnf_package_obj and vnf_package_obj[ @@ -357,3 +365,59 @@ class TestUploadVnfPackage(TestVnfPackage): self.assertEqual(error_message, exception.message) # Delete temporary folder shutil.rmtree(temp_dir) + + +@ddt.ddt +class TestUpdateVnfPackage(TestVnfPackage): + + def setUp(self): + super(TestUpdateVnfPackage, self).setUp() + self.update_vnf_package = vnf_package.UpdateVnfPackage( + self.app, self.app_args, cmd_name='vnf package update') + + @ddt.data((["--user-data", 'Test_key=Test_value', + "--operational-state", 'DISABLED'], + [('user_data', {'Test_key': 'Test_value'}), + ('operational_state', 'DISABLED')]), + (["--user-data", 'Test_key=Test_value'], + [('user_data', {'Test_key': 'Test_value'})]), + (["--operational-state", 'DISABLED'], + [('operational_state', 'DISABLED')])) + @ddt.unpack + def test_take_action(self, arglist, verifylist): + vnf_package_obj = vnf_package_fakes.vnf_package_obj( + onboarded_state=True) + arglist.append(vnf_package_obj['id']) + verifylist.append(('vnf_package', vnf_package_obj['id'])) + + parsed_args = self.check_parser(self.update_vnf_package, arglist, + verifylist) + url = os.path.join(self.url, 'vnfpkgm/v1/vnf_packages', + vnf_package_obj['id']) + fake_response = vnf_package_fakes.get_fake_update_vnf_package_obj( + arglist) + self.requests_mock.register_uri('PATCH', url, + json=fake_response, + headers=self.header) + + columns, data = self.update_vnf_package.take_action(parsed_args) + self.assertItemsEqual(_get_columns_vnf_package( + vnf_package_obj=fake_response, action='update'), columns) + self.assertItemsEqual( + vnf_package_fakes.get_vnf_package_data(fake_response), data) + + def test_update_no_options(self): + self.assertRaises(base.ParserException, self.check_parser, + self.update_vnf_package, [], []) + + def test_update_without_user_data_and_operational_state(self): + vnf_package_obj = vnf_package_fakes.vnf_package_obj( + onboarded_state=True) + arglist = [vnf_package_obj['id']] + + verifylist = [('vnf_package', vnf_package_obj['id'])] + + parsed_args = self.check_parser(self.update_vnf_package, arglist, + verifylist) + self.assertRaises(SystemExit, self.update_vnf_package.take_action, + parsed_args) diff --git a/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py index 4ff95349..978a4b3a 100644 --- a/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py +++ b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py @@ -126,3 +126,16 @@ def create_vnf_packages(count=2): unique_id = uuidutils.generate_uuid() vnf_packages.append(vnf_package_obj(attrs={'id': unique_id})) return {'vnf_packages': vnf_packages} + + +def get_fake_update_vnf_package_obj(arglist): + fake_update_vnf_package_dict = {} + if '--user-data' in arglist: + fake_update_vnf_package_dict.update( + {"userDefinedData": {'Test_key': 'Test_value'}}) + if '--operational-state' in arglist: + fake_update_vnf_package_dict.update({ + "operationalState": "DISABLED", + }) + + return fake_update_vnf_package_dict diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index d8a81778..03ef44f5 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -313,6 +313,10 @@ class ClientBase(object): return self.retry_request("PUT", action, body=body, headers=headers, params=params) + def patch(self, action, body=None, headers=None, params=None): + return self.retry_request("PATCH", action, body=body, + headers=headers, params=params) + def list(self, collection, path, retrieve_all=True, **params): if retrieve_all: res = [] @@ -781,6 +785,10 @@ class VnfPackageClient(ClientBase): base_path=self.vnfpackages_path), body=file_data) + @APIParamsCall + def update_vnf_package(self, vnf_package, body): + return self.patch(self.vnfpackage_path % vnf_package, body=body) + class VnfLCMClient(ClientBase): """Client for vnflcm APIs. @@ -1099,3 +1107,6 @@ class Client(object): def delete_vnf_instance(self, vnf_id): return self.vnf_lcm_client.delete_vnf_instance(vnf_id) + + def update_vnf_package(self, vnf_package, body): + return self.vnf_package_client.update_vnf_package(vnf_package, body)