Support ChangeVNFPackage command in tackerclient
Add ``openstack vnflcm change_vnfpkg`` to python-tackerclient. This command can execute change current vnf package operation [1]. [1] https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_NFV-SOL003v030301p.pdf Implements: blueprint upgrade-vnf-package Change-Id: I0d9c88147dee3a273cb27224db6be6c91cf7fe55
This commit is contained in:
		| @@ -110,6 +110,7 @@ openstack.tackerclient.v2 = | ||||
|      vnflcm_list = tackerclient.osc.v1.vnflcm.vnflcm:ListVnfLcm | ||||
|      vnflcm_instantiate = tackerclient.osc.v1.vnflcm.vnflcm:InstantiateVnfLcm | ||||
|      vnflcm_terminate = tackerclient.osc.v1.vnflcm.vnflcm:TerminateVnfLcm | ||||
|      vnflcm_change-vnfpkg = tackerclient.osc.v1.vnflcm.vnflcm:ChangeVnfPkgVnfLcm | ||||
|      vnflcm_delete = tackerclient.osc.v1.vnflcm.vnflcm:DeleteVnfLcm | ||||
|      vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp | ||||
|      vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp | ||||
|   | ||||
| @@ -207,6 +207,10 @@ class InvalidInput(TackerClientException): | ||||
|     message = _("Invalid input: %(reason)s") | ||||
|  | ||||
|  | ||||
| class UnsupportedCommandVersion(TackerClientException): | ||||
|     message = _("This command is not supported in version %(version)s") | ||||
|  | ||||
|  | ||||
| # Command line exceptions | ||||
|  | ||||
| class TackerCLIError(TackerException): | ||||
|   | ||||
| @@ -566,3 +566,30 @@ class ChangeExtConnVnfLcm(command.Command): | ||||
|         if not result: | ||||
|             print((_('Change External VNF Connectivity for VNF Instance %s ' | ||||
|                      'has been accepted.') % parsed_args.vnf_instance)) | ||||
|  | ||||
|  | ||||
| class ChangeVnfPkgVnfLcm(command.Command): | ||||
|     _description = _("Change Current VNF Package") | ||||
|  | ||||
|     def get_parser(self, prog_name): | ||||
|         parser = super(ChangeVnfPkgVnfLcm, self).get_parser(prog_name) | ||||
|         parser.add_argument( | ||||
|             _VNF_INSTANCE, | ||||
|             metavar="<vnf-instance>", | ||||
|             help=_("VNF instance ID to Change Current VNF Package")) | ||||
|         parser.add_argument( | ||||
|             'request_file', | ||||
|             metavar="<param-file>", | ||||
|             help=_("Specify change-vnfpkg request parameters " | ||||
|                    "in a json file.")) | ||||
|  | ||||
|         return parser | ||||
|  | ||||
|     def take_action(self, parsed_args): | ||||
|         client = self.app.client_manager.tackerclient | ||||
|         result = client.change_vnfpkg_vnf_instance( | ||||
|             parsed_args.vnf_instance, jsonfile2body( | ||||
|                 parsed_args.request_file)) | ||||
|         if not result: | ||||
|             print((_('Change Current VNF Package for VNF Instance %s ' | ||||
|                      'has been accepted.') % parsed_args.vnf_instance)) | ||||
|   | ||||
| @@ -0,0 +1,36 @@ | ||||
| { | ||||
|     "vnfdId": "c6595341-a5bb-8246-53c4-7aeb843d60c5", | ||||
|     "additionalParams": { | ||||
|         "upgrade_type": "RollingUpdate", | ||||
|         "lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py", | ||||
|         "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", | ||||
|         "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py", | ||||
|         "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", | ||||
|         "vdu_params": [{ | ||||
|             "vduId": "VDU1", | ||||
|             "old_vnfc_param": { | ||||
|                 "cp_name": "VDU1_CP1", | ||||
|                 "username": "ubuntu", | ||||
|                 "password": "ubuntu" | ||||
|             }, | ||||
|             "new_vnfc_param": { | ||||
|                 "cp_name": "VDU1_CP1", | ||||
|                 "username": "ubuntu", | ||||
|                 "password": "ubuntu" | ||||
|             } | ||||
|         }, { | ||||
|             "vduId": "VDU2", | ||||
|             "old_vnfc_param": { | ||||
|                 "cp_name": "VDU2_CP1", | ||||
|                 "username": "ubuntu", | ||||
|                 "password": "ubuntu" | ||||
|             }, | ||||
|             "new_vnfc_param": { | ||||
|                 "cp_name": "VDU2_CP1", | ||||
|                 "username": "ubuntu", | ||||
|                 "password": "ubuntu" | ||||
|             } | ||||
|         }] | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -850,6 +850,40 @@ class TestChangeExtConnVnfLcm(TestVnfLcm): | ||||
|         self.assertIn(expected_msg, str(ex)) | ||||
|  | ||||
|  | ||||
| class TestChangeVnfPkgVnfLcm(TestVnfLcm): | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(TestChangeVnfPkgVnfLcm, self).setUp() | ||||
|         self.change_vnfpkg_vnf_lcm = vnflcm.ChangeVnfPkgVnfLcm( | ||||
|             self.app, self.app_args, | ||||
|             cmd_name='vnflcm change-vnfpkg') | ||||
|  | ||||
|     def test_take_action_with_v1_version(self): | ||||
|         vnf_instance = vnflcm_fakes.vnf_instance_response() | ||||
|         sample_param_file = ("./tackerclient/osc/v2/vnflcm/samples/" | ||||
|                              "change_vnfpkg_vnf_instance_param_sample.json") | ||||
|         arglist = [vnf_instance['id'], sample_param_file] | ||||
|         verifylist = [('vnf_instance', vnf_instance['id']), | ||||
|                       ('request_file', sample_param_file)] | ||||
|  | ||||
|         # command param | ||||
|         parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm, | ||||
|                                         arglist, | ||||
|                                         verifylist) | ||||
|  | ||||
|         url = os.path.join(self.url, 'vnflcm/v1/vnf_instances', | ||||
|                            vnf_instance['id'], 'change_vnfpkg') | ||||
|         self.requests_mock.register_uri( | ||||
|             'POST', url, headers=self.header, status_code=400, json={}) | ||||
|  | ||||
|         ex = self.assertRaises(exceptions.UnsupportedCommandVersion, | ||||
|                                self.change_vnfpkg_vnf_lcm.take_action, | ||||
|                                parsed_args) | ||||
|  | ||||
|         expected_msg = "This command is not supported in version 1" | ||||
|         self.assertEqual(expected_msg, str(ex)) | ||||
|  | ||||
|  | ||||
| class TestVnfLcmV1(base.FixturedTestCase): | ||||
|     client_fixture_class = client.ClientFixture | ||||
|     api_version = '1' | ||||
|   | ||||
| @@ -13,8 +13,18 @@ | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| from io import StringIO | ||||
| import os | ||||
| import sys | ||||
| from unittest import mock | ||||
|  | ||||
| from tackerclient.common import exceptions | ||||
| from tackerclient.osc.v1.vnflcm import vnflcm | ||||
| from tackerclient.tests.unit.osc import base | ||||
| from tackerclient.tests.unit.osc.v1.fixture_data import client | ||||
| from tackerclient.tests.unit.osc.v1 import test_vnflcm | ||||
| from tackerclient.tests.unit.osc.v1 import vnflcm_fakes | ||||
| from tackerclient.v1_0 import client as proxy_client | ||||
|  | ||||
|  | ||||
| class TestVnfLcmV2(base.FixturedTestCase): | ||||
| @@ -30,3 +40,112 @@ class TestVnfLcmV2(base.FixturedTestCase): | ||||
|         self.assertEqual(self.cs.vnf_lcm_client.vnf_instances_path, | ||||
|                          '/vnflcm/v2/vnf_instances') | ||||
|         # check of other paths is omitted. | ||||
|  | ||||
|  | ||||
| class TestChangeVnfPkgVnfLcm(test_vnflcm.TestVnfLcm): | ||||
|     api_version = '2' | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(TestChangeVnfPkgVnfLcm, self).setUp() | ||||
|         self.change_vnfpkg_vnf_lcm = vnflcm.ChangeVnfPkgVnfLcm( | ||||
|             self.app, self.app_args, | ||||
|             cmd_name='vnflcm change-vnfpkg') | ||||
|  | ||||
|     def test_take_action(self): | ||||
|         vnf_instance = vnflcm_fakes.vnf_instance_response() | ||||
|         sample_param_file = ("./tackerclient/osc/v2/vnflcm/samples/" | ||||
|                              "change_vnfpkg_vnf_instance_param_sample.json") | ||||
|  | ||||
|         arglist = [vnf_instance['id'], sample_param_file] | ||||
|         verifylist = [('vnf_instance', vnf_instance['id']), | ||||
|                       ('request_file', sample_param_file)] | ||||
|  | ||||
|         # command param | ||||
|         parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm, | ||||
|                                         arglist, | ||||
|                                         verifylist) | ||||
|  | ||||
|         url = os.path.join(self.url, 'vnflcm/v2/vnf_instances', | ||||
|                            vnf_instance['id'], 'change_vnfpkg') | ||||
|         self.requests_mock.register_uri( | ||||
|             'POST', url, headers=self.header, json={}) | ||||
|  | ||||
|         sys.stdout = buffer = StringIO() | ||||
|         with mock.patch.object(proxy_client.ClientBase, | ||||
|                                '_handle_fault_response') as m: | ||||
|             self.change_vnfpkg_vnf_lcm.take_action(parsed_args) | ||||
|             # check no fault response is received | ||||
|             self.assertNotCalled(m) | ||||
|             self.assertEqual( | ||||
|                 ('Change Current VNF Package for VNF Instance {0} ' | ||||
|                  'has been accepted.'.format(vnf_instance['id'])), | ||||
|                 buffer.getvalue().strip()) | ||||
|  | ||||
|     def test_take_action_vnf_instance_not_found(self): | ||||
|         vnf_instance = vnflcm_fakes.vnf_instance_response() | ||||
|         sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/" | ||||
|                              "change_vnfpkg_vnf_instance_param_sample.json") | ||||
|         arglist = [vnf_instance['id'], sample_param_file] | ||||
|         verifylist = [('vnf_instance', vnf_instance['id']), | ||||
|                       ('request_file', sample_param_file)] | ||||
|  | ||||
|         # command param | ||||
|         parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm, | ||||
|                                         arglist, | ||||
|                                         verifylist) | ||||
|  | ||||
|         url = os.path.join(self.url, 'vnflcm/v2/vnf_instances', | ||||
|                            vnf_instance['id'], 'change_vnfpkg') | ||||
|         self.requests_mock.register_uri( | ||||
|             'POST', url, headers=self.header, status_code=404, json={}) | ||||
|  | ||||
|         self.assertRaises(exceptions.TackerClientException, | ||||
|                           self.change_vnfpkg_vnf_lcm.take_action, | ||||
|                           parsed_args) | ||||
|  | ||||
|     def test_take_action_param_file_not_exists(self): | ||||
|         vnf_instance = vnflcm_fakes.vnf_instance_response() | ||||
|         sample_param_file = "./not_exists.json" | ||||
|         arglist = [vnf_instance['id'], sample_param_file] | ||||
|         verifylist = [('vnf_instance', vnf_instance['id']), | ||||
|                       ('request_file', sample_param_file)] | ||||
|  | ||||
|         # command param | ||||
|         parsed_args = self.check_parser( | ||||
|             self.change_vnfpkg_vnf_lcm, | ||||
|             arglist, | ||||
|             verifylist) | ||||
|  | ||||
|         ex = self.assertRaises( | ||||
|             exceptions.InvalidInput, | ||||
|             self.change_vnfpkg_vnf_lcm.take_action, | ||||
|             parsed_args) | ||||
|  | ||||
|         expected_msg = ("Invalid input: File %s does not exist " | ||||
|                         "or user does not have read privileges to it") | ||||
|         self.assertEqual(expected_msg % sample_param_file, str(ex)) | ||||
|  | ||||
|     @mock.patch("os.open") | ||||
|     @mock.patch("os.access") | ||||
|     def test_take_action_invalid_format_param_file(self, mock_access, | ||||
|                                                    mock_open): | ||||
|         vnf_instance = vnflcm_fakes.vnf_instance_response() | ||||
|         sample_param_file = "./invalid_param_file.json" | ||||
|         arglist = [vnf_instance['id'], sample_param_file] | ||||
|         verifylist = [('vnf_instance', vnf_instance['id']), | ||||
|                       ('request_file', sample_param_file)] | ||||
|  | ||||
|         mock_open.return_value = "invalid_json_data" | ||||
|         mock_access.return_value = True | ||||
|         # command param | ||||
|         parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm, | ||||
|                                         arglist, | ||||
|                                         verifylist) | ||||
|  | ||||
|         ex = self.assertRaises( | ||||
|             exceptions.InvalidInput, | ||||
|             self.change_vnfpkg_vnf_lcm.take_action, | ||||
|             parsed_args) | ||||
|  | ||||
|         expected_msg = "Failed to load parameter file." | ||||
|         self.assertIn(expected_msg, str(ex)) | ||||
|   | ||||
| @@ -966,6 +966,15 @@ class VnfLCMClient(ClientBase): | ||||
|         return self.post((self.vnf_instance_path + "/change_ext_conn") % | ||||
|                          vnf_id, body=body, headers=self.headers) | ||||
|  | ||||
|     @APIParamsCall | ||||
|     def change_vnfpkg_vnf_instance(self, vnf_id, body): | ||||
|         # NOTE: it is only supported by V2-API. | ||||
|         if self.vnf_instance_path.split('/')[2] == 'v2': | ||||
|             return self.post((self.vnf_instance_path + "/change_vnfpkg") % | ||||
|                              vnf_id, body=body, headers=self.headers) | ||||
|         else: | ||||
|             raise exceptions.UnsupportedCommandVersion(version='1') | ||||
|  | ||||
|     @APIParamsCall | ||||
|     def retry_vnf_instance(self, occ_id): | ||||
|         return self.post((self.vnf_lcm_op_occs_path + "/retry") % occ_id, | ||||
| @@ -1272,6 +1281,9 @@ class Client(object): | ||||
|     def change_ext_conn_vnf_instance(self, vnf_id, body): | ||||
|         return self.vnf_lcm_client.change_ext_conn_vnf_instance(vnf_id, body) | ||||
|  | ||||
|     def change_vnfpkg_vnf_instance(self, vnf_id, body): | ||||
|         return self.vnf_lcm_client.change_vnfpkg_vnf_instance(vnf_id, body) | ||||
|  | ||||
|     def delete_vnf_instance(self, vnf_id): | ||||
|         return self.vnf_lcm_client.delete_vnf_instance(vnf_id) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Yi Feng
					Yi Feng