diff --git a/tackerclient/osc/v1/vnfm/vnf.py b/tackerclient/osc/v1/vnfm/vnf.py index 5735a406..d1d78141 100644 --- a/tackerclient/osc/v1/vnfm/vnf.py +++ b/tackerclient/osc/v1/vnfm/vnf.py @@ -189,18 +189,32 @@ class DeleteVNF(command.Command): metavar="", nargs="+", help=_("VNF(s) to delete (name or ID)")) + parser.add_argument( + '--force', + default=False, + action='store_true', + help=_('Force delete VNF instance')) return parser + def args2body(self, parsed_args): + body = dict() + if parsed_args.force: + body[_VNF] = dict() + body[_VNF]['attributes'] = dict() + body[_VNF]['attributes']['force'] = True + return body + def take_action(self, parsed_args): client = self.app.client_manager.tackerclient failure = False deleted_ids = [] failed_items = {} + body = self.args2body(parsed_args) for resource_id in parsed_args.vnf: try: obj = tackerV10.find_resourceid_by_name_or_id( client, _VNF, resource_id) - client.delete_vnf(obj) + client.delete_vnf(obj, body) deleted_ids.append(resource_id) except Exception as e: failure = True diff --git a/tackerclient/tacker/v1_0/__init__.py b/tackerclient/tacker/v1_0/__init__.py index 09014cb0..4dbe01dd 100644 --- a/tackerclient/tacker/v1_0/__init__.py +++ b/tackerclient/tacker/v1_0/__init__.py @@ -520,6 +520,7 @@ class DeleteCommand(TackerCommand): 'ids', nargs='+', metavar=self.resource.upper(), help=help_str % self.resource) + self.add_known_arguments(parser) return parser def run(self, parsed_args): @@ -530,6 +531,8 @@ class DeleteCommand(TackerCommand): tacker_client.format = parsed_args.request_format obj_deleter = getattr(tacker_client, "delete_%s" % self.resource) + body = self.args2body(parsed_args) + for resource_id in parsed_args.ids: try: if self.allow_names: @@ -537,7 +540,10 @@ class DeleteCommand(TackerCommand): tacker_client, self.resource, resource_id) else: _id = resource_id - obj_deleter(_id) + if body: + obj_deleter(_id, body) + else: + obj_deleter(_id) deleted_ids.append(resource_id) except Exception as e: failure = True diff --git a/tackerclient/tacker/v1_0/vnfm/vnf.py b/tackerclient/tacker/v1_0/vnfm/vnf.py index 50b54ea1..ea984c13 100644 --- a/tackerclient/tacker/v1_0/vnfm/vnf.py +++ b/tackerclient/tacker/v1_0/vnfm/vnf.py @@ -179,8 +179,23 @@ class DeleteVNF(tackerV10.DeleteCommand): """Delete given VNF(s).""" resource = _VNF + remove_output_fields = ["attributes"] deleted_msg = {'vnf': 'delete initiated'} + def add_known_arguments(self, parser): + parser.add_argument( + '--force', + default=False, + action='store_true', + help=_('Force delete VNF instance')) + + def args2body(self, parsed_args): + body = dict() + if parsed_args.force: + body[self.resource] = dict() + body[self.resource]['attributes'] = {'force': True} + return body + class ListVNFResources(tackerV10.ListCommand): """List resources of a VNF like VDU, CP, etc.""" diff --git a/tackerclient/tests/unit/test_cli10.py b/tackerclient/tests/unit/test_cli10.py index 3e31832e..c48b22f2 100644 --- a/tackerclient/tests/unit/test_cli10.py +++ b/tackerclient/tests/unit/test_cli10.py @@ -611,10 +611,18 @@ class CLITestV10Base(testtools.TestCase): args.extend(['--request-format', self.format]) cmd_parser = cmd.get_parser("delete_" + resource) shell.run_command(cmd, cmd_parser, args) - mock_req.assert_called_once_with( - end_url(path % myid, format=self.format), 'DELETE', - body=None, - headers=test_utils.ContainsKeyValue('X-Auth-Token', TOKEN)) + if '--force' in args: + body_str = '{"' + resource + \ + '": {"attributes": {"force": true}}}' + mock_req.assert_called_once_with( + end_url(path % myid, format=self.format), 'DELETE', + body=body_str, + headers=test_utils.ContainsKeyValue('X-Auth-Token', TOKEN)) + else: + mock_req.assert_called_once_with( + end_url(path % myid, format=self.format), 'DELETE', + body=None, + headers=test_utils.ContainsKeyValue('X-Auth-Token', TOKEN)) mock_get.assert_called_once_with() _str = self.fake_stdout.make_string() msg = 'All specified %(resource)s(s) %(msg)s successfully\n' % { diff --git a/tackerclient/tests/unit/vm/test_cli10_vnf.py b/tackerclient/tests/unit/vm/test_cli10_vnf.py index 942235ca..5f52cca3 100644 --- a/tackerclient/tests/unit/vm/test_cli10_vnf.py +++ b/tackerclient/tests/unit/vm/test_cli10_vnf.py @@ -187,12 +187,18 @@ class CLITestV10VmVNFJSON(test_cli10.CLITestV10Base): [my_id, '--%s' % key, value], {key: value}) - def test_delete_vnf(self): + def test_delete_vnf_without_force(self): cmd = vnf.DeleteVNF(test_cli10.MyApp(sys.stdout), None) my_id = 'my-id' args = [my_id] self._test_delete_resource(self._RESOURCE, cmd, my_id, args) + def test_delete_vnf_with_force(self): + cmd = vnf.DeleteVNF(test_cli10.MyApp(sys.stdout), None) + my_id = 'my-id' + args = [my_id, '--force'] + self._test_delete_resource(self._RESOURCE, cmd, my_id, args) + def test_list_vnf_resources(self): cmd = vnf.ListVNFResources(test_cli10.MyApp(sys.stdout), None) base_args = [self.test_id] diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index 0a640e5c..b8cc57fe 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -438,8 +438,8 @@ class Client(ClientBase): return self.post(self.vnfs_path, body=body) @APIParamsCall - def delete_vnf(self, vnf): - return self.delete(self.vnf_path % vnf) + def delete_vnf(self, vnf, body=None): + return self.delete(self.vnf_path % vnf, body=body) @APIParamsCall def update_vnf(self, vnf, body):