From 5581c3513fb9c0c4a830f3a636bcd1b47aa75d68 Mon Sep 17 00:00:00 2001 From: Shubham Potale Date: Thu, 30 Jan 2020 17:19:42 +0530 Subject: [PATCH] OSC support to heal vnf Added a new command ``openstack vnflcm heal`` to heal vnf instance. Blueprint: support-etsi-nfv-specs Change-Id: I31165e1def0a53a56e1fcefd1877630712bfab5e --- setup.cfg | 1 + tackerclient/osc/v1/vnflcm/vnflcm.py | 38 ++++++++++++ tackerclient/tests/unit/osc/v1/test_vnflcm.py | 61 +++++++++++++++++++ tackerclient/v1_0/client.py | 8 +++ 4 files changed, 108 insertions(+) diff --git a/setup.cfg b/setup.cfg index 315c153a..571d038c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -89,6 +89,7 @@ openstack.tackerclient.v1 = vnflcm_instantiate = tackerclient.osc.v1.vnflcm.vnflcm:InstantiateVnfLcm vnflcm_terminate = tackerclient.osc.v1.vnflcm.vnflcm:TerminateVnfLcm vnflcm_delete = tackerclient.osc.v1.vnflcm.vnflcm:DeleteVnfLcm + vnflcm_heal = tackerclient.osc.v1.vnflcm.vnflcm:HealVnfLcm [build_releasenotes] all_files = 1 diff --git a/tackerclient/osc/v1/vnflcm/vnflcm.py b/tackerclient/osc/v1/vnflcm/vnflcm.py index c8448aeb..8a830b2e 100644 --- a/tackerclient/osc/v1/vnflcm/vnflcm.py +++ b/tackerclient/osc/v1/vnflcm/vnflcm.py @@ -225,6 +225,44 @@ class InstantiateVnfLcm(command.Command): ' accepted.') % {'id': parsed_args.vnf_instance})) +class HealVnfLcm(command.Command): + _description = _("Heal VNF Instance") + + def get_parser(self, prog_name): + parser = super(HealVnfLcm, self).get_parser(prog_name) + parser.add_argument( + _VNF_INSTANCE, + metavar="", + help=_("VNF instance ID to heal")) + parser.add_argument( + '--cause', + help=_('Specify the reason why a healing procedure is required.')) + parser.add_argument( + '--vnfc-instance', + metavar="", + nargs="+", + help=_("List of VNFC instances requiring a healing action.") + ) + return parser + + def args2body(self, parsed_args): + body = {} + if parsed_args.cause: + body['cause'] = parsed_args.cause + if parsed_args.vnfc_instance: + body['vnfcInstanceId'] = parsed_args.vnfc_instance + + return body + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + result = client.heal_vnf_instance( + parsed_args.vnf_instance, self.args2body(parsed_args)) + if not result: + print((_('Heal request for VNF Instance %(id)s has been' + ' accepted.') % {'id': parsed_args.vnf_instance})) + + class TerminateVnfLcm(command.Command): _description = _("Terminate a VNF instance") diff --git a/tackerclient/tests/unit/osc/v1/test_vnflcm.py b/tackerclient/tests/unit/osc/v1/test_vnflcm.py index dbe060e0..bcb0d171 100644 --- a/tackerclient/tests/unit/osc/v1/test_vnflcm.py +++ b/tackerclient/tests/unit/osc/v1/test_vnflcm.py @@ -274,6 +274,67 @@ class TestInstantiateVnfLcm(TestVnfLcm): self.assertIn(expected_msg, ex.message) +@ddt.ddt +class TestHealVnfLcm(TestVnfLcm): + + def setUp(self): + super(TestHealVnfLcm, self).setUp() + self.heal_vnf_lcm = vnflcm.HealVnfLcm( + self.app, self.app_args, cmd_name='vnflcm heal') + + @ddt.data((['--cause', 'test-cause', "--vnfc-instance", + 'vnfc-id-1', 'vnfc-id-2'], + [('cause', 'test-cause'), + ('vnfc_instance', ['vnfc-id-1', 'vnfc-id-2'])]), + (['--cause', 'test-cause'], + [('cause', 'test-cause')]), + (["--vnfc-instance", 'vnfc-id-1', 'vnfc-id-2'], + [('vnfc_instance', ['vnfc-id-1', 'vnfc-id-2'])]), + ([], [])) + @ddt.unpack + def test_take_action(self, arglist, verifylist): + vnf_instance = vnflcm_fakes.vnf_instance_response() + arglist.insert(0, vnf_instance['id']) + verifylist.extend([('vnf_instance', vnf_instance['id'])]) + + # command param + parsed_args = self.check_parser(self.heal_vnf_lcm, arglist, + verifylist) + + url = os.path.join(self.url, 'vnflcm/v1/vnf_instances', + vnf_instance['id'], 'heal') + self.requests_mock.register_uri( + 'POST', url, headers=self.header, json={}) + + sys.stdout = buffer = StringIO() + result_error = self.heal_vnf_lcm.take_action(parsed_args) + + self.assertIsNone(result_error) + actual_message = buffer.getvalue().strip() + + expected_message = ("Heal request for VNF Instance %s has been " + "accepted.") % vnf_instance['id'] + self.assertIn(expected_message, actual_message) + + def test_take_action_vnf_instance_not_found(self): + vnf_instance = vnflcm_fakes.vnf_instance_response() + arglist = [vnf_instance['id']] + verifylist = [('vnf_instance', vnf_instance['id'])] + + # command param + parsed_args = self.check_parser(self.heal_vnf_lcm, arglist, + verifylist) + + url = os.path.join(self.url, 'vnflcm/v1/vnf_instances', + vnf_instance['id'], 'heal') + self.requests_mock.register_uri( + 'POST', url, headers=self.header, status_code=404, json={}) + + self.assertRaises(exceptions.TackerClientException, + self.heal_vnf_lcm.take_action, + parsed_args) + + @ddt.ddt class TestTerminateVnfLcm(TestVnfLcm): diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index 6e84ca06..d8a81778 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -814,6 +814,11 @@ class VnfLCMClient(ClientBase): return self.post((self.vnf_instance_path + "/instantiate") % vnf_id, body=body) + @APIParamsCall + def heal_vnf_instance(self, vnf_id, body): + return self.post((self.vnf_instance_path + "/heal") % vnf_id, + body=body) + @APIParamsCall def terminate_vnf_instance(self, vnf_id, body): return self.post((self.vnf_instance_path + "/terminate") % vnf_id, @@ -1086,6 +1091,9 @@ class Client(object): def instantiate_vnf_instance(self, vnf_id, body): return self.vnf_lcm_client.instantiate_vnf_instance(vnf_id, body) + def heal_vnf_instance(self, vnf_id, body): + return self.vnf_lcm_client.heal_vnf_instance(vnf_id, body) + def terminate_vnf_instance(self, vnf_id, body): return self.vnf_lcm_client.terminate_vnf_instance(vnf_id, body)