From 1cf8ceb72e7ede41c8114994c5fc9307b7f237a1 Mon Sep 17 00:00:00 2001 From: Bharath Thiruveedula Date: Sun, 18 Dec 2016 14:18:46 +0530 Subject: [PATCH] Implement client support for NSD Change-Id: I5653f3bb627b81dfe356e2192c71b13c6cfe6924 Partially-implements: blueprint nsd-support Co-Authored-By: Dharmendra Kushwaha --- tackerclient/shell.py | 13 ++++ tackerclient/tacker/v1_0/nfvo/ns.py | 106 +++++++++++++++++++++++++++ tackerclient/tacker/v1_0/nfvo/nsd.py | 85 +++++++++++++++++++++ tackerclient/v1_0/client.py | 57 ++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 tackerclient/tacker/v1_0/nfvo/ns.py create mode 100644 tackerclient/tacker/v1_0/nfvo/nsd.py diff --git a/tackerclient/shell.py b/tackerclient/shell.py index e66053b3..76903b33 100644 --- a/tackerclient/shell.py +++ b/tackerclient/shell.py @@ -47,6 +47,8 @@ from tackerclient.common import utils from tackerclient.i18n import _ from tackerclient.tacker.v1_0.events import events from tackerclient.tacker.v1_0 import extension +from tackerclient.tacker.v1_0.nfvo import ns +from tackerclient.tacker.v1_0.nfvo import nsd from tackerclient.tacker.v1_0.nfvo import vim from tackerclient.tacker.v1_0.nfvo import vnffg from tackerclient.tacker.v1_0.nfvo import vnffgd @@ -155,6 +157,17 @@ COMMAND_V1 = { 'classifier-list': vnffg.ListFC, 'classifier-show': vnffg.ShowFC, + + 'nsd-create': nsd.CreateNSD, + 'nsd-list': nsd.ListNSD, + 'nsd-delete': nsd.DeleteNSD, + 'nsd-show': nsd.ShowNSD, + 'nsd-template-show': nsd.ShowTemplateNSD, + + 'ns-create': ns.CreateNS, + 'ns-list': ns.ListNS, + 'ns-delete': ns.DeleteNS, + 'ns-show': ns.ShowNS, } COMMANDS = {'1.0': COMMAND_V1} diff --git a/tackerclient/tacker/v1_0/nfvo/ns.py b/tackerclient/tacker/v1_0/nfvo/ns.py new file mode 100644 index 00000000..2adcbc3e --- /dev/null +++ b/tackerclient/tacker/v1_0/nfvo/ns.py @@ -0,0 +1,106 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import yaml + +from tackerclient.i18n import _ +from tackerclient.tacker import v1_0 as tackerV10 + + +_NS = 'ns' +_RESOURCE = 'resource' + + +class ListNS(tackerV10.ListCommand): + """List NS that belong to a given tenant.""" + + resource = _NS + list_columns = ['id', 'name', 'nsd_id', 'mgmt_urls', 'status'] + + +class ShowNS(tackerV10.ShowCommand): + """Show information of a given NS.""" + + resource = _NS + + +class CreateNS(tackerV10.CreateCommand): + """Create a NS.""" + + resource = _NS + remove_output_fields = ["attributes"] + + def add_known_arguments(self, parser): + parser.add_argument( + 'name', metavar='NAME', required=True, + help=_('Set a name for the NS')) + parser.add_argument( + '--description', + help=_('Set description for the NS')) + nsd_group = parser.add_mutually_exclusive_group(required=True) + nsd_group.add_argument( + '--nsd-id', + help=_('NSD ID to use as template to create NS')) + nsd_group.add_argument( + '--nsd-name', + help=_('NSD name to use as template to create NS')) + vim_group = parser.add_mutually_exclusive_group() + vim_group.add_argument( + '--vim-id', + help=_('VIM ID to use to create NS on the specified VIM')) + vim_group.add_argument( + '--vim-name', + help=_('VIM name to use to create NS on the specified VIM')) + parser.add_argument( + '--vim-region-name', + help=_('VIM Region to use to create NS on the specified VIM')) + parser.add_argument( + '--param-file', + help=_('Specify parameter yaml file')) + + def args2body(self, parsed_args): + args = {'attributes': {}} + body = {self.resource: args} + if parsed_args.vim_region_name: + args.setdefault('placement_attr', {})['region_name'] = \ + parsed_args.vim_region_name + + tacker_client = self.get_client() + tacker_client.format = parsed_args.request_format + if parsed_args.vim_name: + _id = tackerV10.find_resourceid_by_name_or_id(tacker_client, + 'vim', + parsed_args. + vim_name) + parsed_args.vim_id = _id + if parsed_args.nsd_name: + _id = tackerV10.find_resourceid_by_name_or_id(tacker_client, + 'nsd', + parsed_args. + nsd_name) + parsed_args.nsd_id = _id + if parsed_args.param_file: + with open(parsed_args.param_file) as f: + param_yaml = f.read() + args['attributes']['param_values'] = yaml.load( + param_yaml, Loader=yaml.SafeLoader) + tackerV10.update_dict(parsed_args, body[self.resource], + ['tenant_id', 'name', 'description', + 'nsd_id', 'vim_id']) + return body + + +class DeleteNS(tackerV10.DeleteCommand): + """Delete given NS(s).""" + + resource = _NS + deleted_msg = {'ns': 'delete initiated'} diff --git a/tackerclient/tacker/v1_0/nfvo/nsd.py b/tackerclient/tacker/v1_0/nfvo/nsd.py new file mode 100644 index 00000000..ca1ce654 --- /dev/null +++ b/tackerclient/tacker/v1_0/nfvo/nsd.py @@ -0,0 +1,85 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from __future__ import print_function + +import yaml + +from oslo_serialization import jsonutils + +from tackerclient.i18n import _ +from tackerclient.tacker import v1_0 as tackerV10 + +_NSD = "nsd" + + +class ListNSD(tackerV10.ListCommand): + """List NSDs that belong to a given tenant.""" + + resource = _NSD + list_columns = ['id', 'name', 'description'] + + +class ShowNSD(tackerV10.ShowCommand): + """Show information of a given NSD.""" + + resource = _NSD + + +class CreateNSD(tackerV10.CreateCommand): + """Create a NSD.""" + resource = _NSD + remove_output_fields = ["attributes"] + + def add_known_arguments(self, parser): + parser.add_argument('--nsd-file', help='Specify NSD file', + required=True) + parser.add_argument( + 'name', metavar='NAME', + help='Set a name for the NSD', required=True) + parser.add_argument( + '--description', + help='Set a description for the NSD') + + def args2body(self, parsed_args): + body = {self.resource: {}} + nsd = None + with open(parsed_args.nsd_file) as f: + nsd = yaml.safe_load(f.read()) + tackerV10.update_dict(parsed_args, body[self.resource], + ['tenant_id', 'name', 'description']) + if nsd: + body[self.resource]['attributes'] = {'nsd': nsd} + + return body + + +class DeleteNSD(tackerV10.DeleteCommand): + """Delete a given NSD.""" + resource = _NSD + + +class ShowTemplateNSD(tackerV10.ShowCommand): + """Show template of a given NSD.""" + resource = _NSD + + def run(self, parsed_args): + self.log.debug('run(%s)', parsed_args) + template = None + data = self.get_data(parsed_args) + try: + attributes_index = data[0].index('attributes') + attributes_json = data[1][attributes_index] + template = jsonutils.loads(attributes_json).get('nsd', None) + except (IndexError, TypeError, ValueError) as e: + self.log.debug('Data handling error: %s', str(e)) + print(template or _('Unable to display NSD template!')) diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index f28fb72b..6c87029a 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -362,6 +362,12 @@ class Client(ClientBase): fcs_path = '/classifiers' fc_path = '/classifiers/%s' + nsds_path = '/nsds' + nsd_path = '/nsds/%s' + + nss_path = '/nss' + ns_path = '/nss/%s' + # API has no way to report plurals, so we have to hard code them # EXTED_PLURALS = {} @@ -376,6 +382,7 @@ class Client(ClientBase): return self.get(self.extension_path % ext_alias, params=_params) _VNFD = "vnfd" + _NSD = "nsd" @APIParamsCall def list_vnfds(self, retrieve_all=True, **_params): @@ -608,3 +615,53 @@ class Client(ClientBase): @APIParamsCall def show_classifier(self, classifier, **_params): return self.get(self.fc_path % classifier, params=_params) + + @APIParamsCall + def list_nsds(self, retrieve_all=True, **_params): + nsds_dict = self.list(self._NSD + 's', + self.nsds_path, + retrieve_all, + **_params) + for nsd in nsds_dict['nsds']: + if 'description' in nsd.keys() and \ + len(nsd['description']) > DEFAULT_DESC_LENGTH: + nsd['description'] = nsd['description'][:DEFAULT_DESC_LENGTH] + nsd['description'] += '...' + return nsds_dict + + @APIParamsCall + def show_nsd(self, nsd, **_params): + return self.get(self.nsd_path % nsd, + params=_params) + + @APIParamsCall + def create_nsd(self, body): + return self.post(self.nsds_path, body) + + @APIParamsCall + def delete_nsd(self, nsd): + return self.delete(self.nsd_path % nsd) + + @APIParamsCall + def list_nss(self, retrieve_all=True, **_params): + nss = self.list('nss', self.nss_path, retrieve_all, **_params) + for ns in nss['nss']: + error_reason = ns.get('error_reason', None) + if error_reason and \ + len(error_reason) > DEFAULT_ERROR_REASON_LENGTH: + ns['error_reason'] = error_reason[ + :DEFAULT_ERROR_REASON_LENGTH] + ns['error_reason'] += '...' + return nss + + @APIParamsCall + def show_ns(self, ns, **_params): + return self.get(self.ns_path % ns, params=_params) + + @APIParamsCall + def create_ns(self, body): + return self.post(self.nss_path, body=body) + + @APIParamsCall + def delete_ns(self, ns): + return self.delete(self.ns_path % ns)