diff --git a/lower-constraints.txt b/lower-constraints.txt index ff6d9b90..da5af261 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -3,6 +3,7 @@ Babel==2.3.4 cliff==2.8.0 cmd2==0.8.0 coverage==4.0 +ddt==1.0.1 debtcollector==1.2.0 decorator==3.4.0 deprecation==1.0 @@ -49,6 +50,7 @@ python-subunit==1.0.0 pytz==2013.6 PyYAML==3.12 requests==2.14.2 +requests-mock==1.2.0 requestsexceptions==1.2.0 rfc3986==0.3.1 simplejson==3.5.1 diff --git a/setup.cfg b/setup.cfg index b7d701aa..6d9aaf1c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -80,6 +80,7 @@ openstack.tackerclient.v1 = vnf_classifier_show = tackerclient.osc.v1.nfvo.vnffg:ShowFC vnf_chain_list = tackerclient.osc.v1.nfvo.vnffg:ListSFC vnf_chain_show = tackerclient.osc.v1.nfvo.vnffg:ShowSFC + vnf_package_create = tackerclient.osc.v1.vnfpkgm.vnf_package:CreateVnfPackage [build_releasenotes] diff --git a/tackerclient/osc/v1/vnfpkgm/__init__.py b/tackerclient/osc/v1/vnfpkgm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tackerclient/osc/v1/vnfpkgm/vnf_package.py b/tackerclient/osc/v1/vnfpkgm/vnf_package.py new file mode 100644 index 00000000..ce88f369 --- /dev/null +++ b/tackerclient/osc/v1/vnfpkgm/vnf_package.py @@ -0,0 +1,71 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# 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 logging + +from osc_lib.cli import parseractions +from osc_lib.command import command +from osc_lib import utils + +from tackerclient.i18n import _ +from tackerclient.osc import sdk_utils + +LOG = logging.getLogger(__name__) + +_mixed_case_fields = ('onboardingState', 'operationalState', + 'usageState', 'userDefinedData') + + +def _get_columns(item): + column_map = { + '_links': 'Links', + 'onboardingState': 'Onboarding State', + 'operationalState': 'Operational State', + 'usageState': 'Usage State', + 'userDefinedData': 'User Defined Data', + 'id': 'ID' + } + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map) + + +class CreateVnfPackage(command.ShowOne): + _description = _("Create a new VNF Package") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(CreateVnfPackage, self).get_parser(prog_name) + 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 args2body(self, parsed_args): + body = {} + if parsed_args.user_data: + body["userDefinedData"] = parsed_args.user_data + return body + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + vnf_package = client.create_vnf_package(self.args2body(parsed_args)) + display_columns, columns = _get_columns(vnf_package) + data = utils.get_item_properties( + sdk_utils.DictModel(vnf_package), + columns, mixed_case_fields=_mixed_case_fields) + return (display_columns, data) diff --git a/tackerclient/tests/unit/osc/__init__.py b/tackerclient/tests/unit/osc/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tackerclient/tests/unit/osc/base.py b/tackerclient/tests/unit/osc/base.py new file mode 100644 index 00000000..d7a12ced --- /dev/null +++ b/tackerclient/tests/unit/osc/base.py @@ -0,0 +1,48 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# 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 mock +from requests_mock.contrib import fixture as requests_mock_fixture +import testtools + + +class FixturedTestCase(testtools.TestCase): + client_fixture_class = None + + def setUp(self): + super(FixturedTestCase, self).setUp() + self.app = mock.MagicMock() + if self.client_fixture_class: + self.requests_mock = self.useFixture(requests_mock_fixture. + Fixture()) + fix = self.client_fixture_class(self.requests_mock) + self.cs = self.useFixture(fix).client + + def check_parser(self, cmd, args, verify_args): + cmd_parser = cmd.get_parser('check_parser') + try: + parsed_args = cmd_parser.parse_args(args) + except SystemExit: + raise ParserException + for av in verify_args: + attr, value = av + if attr: + self.assertIn(attr, parsed_args) + self.assertEqual(getattr(parsed_args, attr), value) + return parsed_args + + +class ParserException(Exception): + pass diff --git a/tackerclient/tests/unit/osc/v1/__init__.py b/tackerclient/tests/unit/osc/v1/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tackerclient/tests/unit/osc/v1/fixture_data/__init__.py b/tackerclient/tests/unit/osc/v1/fixture_data/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tackerclient/tests/unit/osc/v1/fixture_data/client.py b/tackerclient/tests/unit/osc/v1/fixture_data/client.py new file mode 100644 index 00000000..d179d81e --- /dev/null +++ b/tackerclient/tests/unit/osc/v1/fixture_data/client.py @@ -0,0 +1,60 @@ +# Copyright 2019 NTT DATA +# +# 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 fixtures +from keystoneauth1 import fixture +from keystoneauth1 import loading +from keystoneauth1 import session + +from tackerclient.v1_0 import client as proxy_client + +IDENTITY_URL = 'http://identityserver:5000/v3' +TACKER_URL = 'http://nfv-orchestration' + + +class ClientFixture(fixtures.Fixture): + + def __init__(self, requests_mock, identity_url=IDENTITY_URL): + super(ClientFixture, self).__init__() + self.identity_url = identity_url + self.client = None + self.token = fixture.V2Token() + self.token.set_scope() + self.requests_mock = requests_mock + self.discovery = fixture.V2Discovery(href=self.identity_url) + s = self.token.add_service('nfv-orchestration') + s.add_endpoint(TACKER_URL) + + def setUp(self): + super(ClientFixture, self).setUp() + auth_url = '%s/tokens' % self.identity_url + headers = {'X-Content-Type': 'application/json'} + self.requests_mock.post(auth_url, json=self.token, headers=headers) + self.requests_mock.get(self.identity_url, json=self.discovery, + headers=headers) + self.client = self.new_client() + + def new_client(self): + self.session = session.Session() + loader = loading.get_plugin_loader('password') + self.session.auth = loader.load_from_options( + auth_url=self.identity_url, username='xx', password='xx') + + return proxy_client.Client(service_type='nfv-orchestration', + interface='public', + endpoint_type='public', + region_name='RegionOne', + auth_url=self.identity_url, + token=self.token.token_id, + endpoint_url=TACKER_URL) diff --git a/tackerclient/tests/unit/osc/v1/test_vnf_package.py b/tackerclient/tests/unit/osc/v1/test_vnf_package.py new file mode 100644 index 00000000..33cedea1 --- /dev/null +++ b/tackerclient/tests/unit/osc/v1/test_vnf_package.py @@ -0,0 +1,70 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# 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 ddt +import mock + +from tackerclient.osc.v1.vnfpkgm import vnf_package +from tackerclient.tests.unit.osc import base +from tackerclient.tests.unit.osc.v1.fixture_data import client +from tackerclient.tests.unit.osc.v1 import vnf_package_fakes + + +class TestVnfPackage(base.FixturedTestCase): + client_fixture_class = client.ClientFixture + + def setUp(self): + super(TestVnfPackage, self).setUp() + self.url = client.TACKER_URL + self.app = mock.Mock() + self.app_args = mock.Mock() + self.client_manager = self.cs + self.app.client_manager.tackerclient = self.client_manager + + +@ddt.ddt +class TestCreateVnfPackage(TestVnfPackage): + + columns = ('ID', 'Links', 'Onboarding State', 'Operational State', + 'Usage State', 'User Defined Data') + + def setUp(self): + super(TestCreateVnfPackage, self).setUp() + self.create_vnf_package = vnf_package.CreateVnfPackage( + self.app, self.app_args, cmd_name='vnf package create') + + @ddt.data((["--user-data", 'Test_key=Test_value'], + [('user_data', {'Test_key': 'Test_value'})]), + ([], [])) + @ddt.unpack + def test_take_action(self, arglist, verifylist): + # command param + parsed_args = self.check_parser(self.create_vnf_package, arglist, + verifylist) + header = {'content-type': 'application/json'} + + if arglist: + json = vnf_package_fakes.vnf_package_obj( + attrs={'userDefinedData': {'Test_key': 'Test_value'}}) + else: + json = vnf_package_fakes.vnf_package_obj() + self.requests_mock.register_uri( + 'POST', self.url + '/vnfpkgm/v1/vnf_packages', + json=json, headers=header) + + columns, data = (self.create_vnf_package.take_action(parsed_args)) + self.assertEqual(self.columns, columns) + self.assertItemsEqual(vnf_package_fakes.get_vnf_package_data(json), + data) diff --git a/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py new file mode 100644 index 00000000..f765d9ec --- /dev/null +++ b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py @@ -0,0 +1,58 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# 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. + + +def vnf_package_obj(attrs=None): + """Create a fake vnf package. + + :param Dictionary attrs: + A dictionary with all attributes + :return: + A FakeVnfPackage dict + """ + attrs = attrs or {} + + # Set default attributes. + fake_vnf_package = {"id": "60a6ac16-b50d-4e92-964b-b3cf98c7cf5c", + "_links": {"self": {"href": "string"}, + "vnfd": {"href": "string"}, + "packageContent": {"href": "string"} + }, + "onboardingState": "CREATED", + "operationalState": "DISABLED", + "usageState": "NOT_IN_USE", + "userDefinedData": None} + + # Overwrite default attributes. + fake_vnf_package.update(attrs) + return fake_vnf_package + + +def get_vnf_package_data(vnf_package=None): + """Get the vnf package data from a FakeVnfPackage dict object. + + :param vnf_package: + A FakeVnfPackage dict object + :return: + A tuple which may include the following values: + (u"packageContent='{'href': 'string'}', self='{'href': 'string'}', + vnfd='{'href': 'string'}'", '60a6ac16-b50d-4e92-964b-b3cf98c7cf5c', + 'CREATED', 'DISABLED', 'NOT_IN_USE', u"Test_key='Test_value'") + """ + data_list = [] + if vnf_package is not None: + for x in sorted(vnf_package.keys()): + data_list.append(vnf_package[x]) + return tuple(data_list) diff --git a/tackerclient/tests/unit/test_cli10.py b/tackerclient/tests/unit/test_cli10.py index c48b22f2..2b3595e2 100644 --- a/tackerclient/tests/unit/test_cli10.py +++ b/tackerclient/tests/unit/test_cli10.py @@ -192,9 +192,9 @@ class CLITestV10Base(testtools.TestCase): def setUp(self, plurals={}): """Prepare the test environment.""" super(CLITestV10Base, self).setUp() - client.Client.EXTED_PLURALS.update(constants.PLURALS) - client.Client.EXTED_PLURALS.update(plurals) - self.metadata = {'plurals': client.Client.EXTED_PLURALS, + client.LegacyClient.EXTED_PLURALS.update(constants.PLURALS) + client.LegacyClient.EXTED_PLURALS.update(plurals) + self.metadata = {'plurals': client.LegacyClient.EXTED_PLURALS, 'xmlns': constants.XML_NS_V10, constants.EXT_NS: {'prefix': 'http://xxxx.yy.com'}} @@ -207,7 +207,8 @@ class CLITestV10Base(testtools.TestCase): self.useFixture(fixtures.MonkeyPatch( 'tackerclient.tacker.v1_0.find_resourceid_by_id', self._find_resourceid)) - self.client = client.Client(token=TOKEN, endpoint_url=self.endurl) + self.client = client.LegacyClient(token=TOKEN, + endpoint_url=self.endurl) @mock.patch.object(TackerCommand, 'get_client') def _test_create_resource(self, resource, cmd, @@ -685,7 +686,7 @@ class ClientV1TestJson(CLITestV10Base): error = self.assertRaises(exceptions.TackerClientException, self.client.do_request, 'PUT', '/test', body='', params=params) - self.assertEqual("An error", str(error)) + self.assertEqual("400-tackerFault", str(error)) class CLITestV10ExceptionHandler(CLITestV10Base): @@ -779,11 +780,11 @@ class CLITestV10ExceptionHandler(CLITestV10Base): error_content = {'message': 'This is an error message'} self._test_exception_handler_v10( exceptions.TackerClientException, 500, - expected_msg='This is an error message', + expected_msg='500-tackerFault', error_content=error_content) def test_exception_handler_v10_error_dict_not_contain_message(self): - error_content = {'error': 'This is an error message'} + error_content = 'tackerFault' expected_msg = '%s-%s' % (500, error_content) self._test_exception_handler_v10( exceptions.TackerClientException, 500, diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index fbf13720..1f65796b 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -31,6 +31,18 @@ from tackerclient.i18n import _ _logger = logging.getLogger(__name__) DEFAULT_DESC_LENGTH = 25 DEFAULT_ERROR_REASON_LENGTH = 100 +STATUS_CODE_MAP = { + 400: "badRequest", + 401: "unauthorized", + 403: "forbidden", + 404: "itemNotFound", + 405: "badMethod", + 409: "conflictingRequest", + 413: "overLimit", + 415: "badMediaType", + 429: "overLimit", + 501: "notImplemented", + 503: "serviceUnavailable"} def exception_handler_v10(status_code, error_content): @@ -45,6 +57,9 @@ def exception_handler_v10(status_code, error_content): error_dict = None if isinstance(error_content, dict): error_dict = error_content.get('TackerError') + if not error_dict: + error_content = error_content.get(STATUS_CODE_MAP.get(status_code), + 'tackerFault') # Find real error type bad_tacker_error_flag = False if error_dict: @@ -141,17 +156,6 @@ class ClientBase(object): :param session: Keystone client auth session to use. (optional) :param auth: Keystone auth plugin to use. (optional) - Example:: - - from tackerclient.v1_0 import client - tacker = client.Client(username=USER, - password=PASS, - tenant_name=TENANT_NAME, - auth_url=KEYSTONE_URL) - - nets = tacker.list_networks() - ... - """ # API has no way to report plurals, so we have to hard code them @@ -182,15 +186,19 @@ class ClientBase(object): # Raise the appropriate exception exception_handler_v10(status_code, des_error_body) - def do_request(self, method, action, body=None, headers=None, params=None): - # Add format and tenant_id + def build_action(self, action): action += ".%s" % self.format action = self.action_prefix + action + return action + + def do_request(self, method, action, body=None, headers=None, params=None): + action = self.build_action(action) + # Add format and tenant_id if type(params) is dict and params: params = utils.safe_encode_dict(params) action += '?' + urlparse.urlencode(params, doseq=1) - if body: + if body or body == {}: body = self.serialize(body) resp, replybody = self.httpclient.do_request( @@ -329,7 +337,7 @@ class ClientBase(object): break -class Client(ClientBase): +class LegacyClient(ClientBase): extensions_path = "/extensions" extension_path = "/extensions/%s" @@ -708,3 +716,232 @@ class Client(ClientBase): @APIParamsCall def delete_clustermember(self, clustermember): return self.delete(self.cluster_member_path % clustermember) + + +class VnfPackageClient(ClientBase): + """Client for vnfpackage APIs. + + Purpose of this class is to create required request url for vnfpackage + APIs. + """ + + vnfpackages_path = '/vnfpkgm/v1/vnf_packages' + + def build_action(self, action): + return action + + @APIParamsCall + def create_vnf_package(self, body): + return self.post(self.vnfpackages_path, body=body) + + +class Client(object): + """Unified interface to interact with multiple applications of tacker service. + + This class is a single entry point to interact with legacy tacker apis and + vnf packages apis. + + Example:: + + from tackerclient.v1_0 import client + tacker = client.Client(username=USER, + password=PASS, + tenant_name=TENANT_NAME, + auth_url=KEYSTONE_URL) + + vnf_package = tacker.create_vnf_package(...) + nsd = tacker.create_nsd(...) + + """ + + def __init__(self, **kwargs): + self.vnf_package_client = VnfPackageClient(**kwargs) + self.legacy_client = LegacyClient(**kwargs) + + # LegacyClient methods + + def list_extensions(self, **_params): + return self.legacy_client.list_extensions(**_params) + + def show_extension(self, ext_alias, **_params): + """Fetch a list of all exts on server side.""" + return self.legacy_client.show_extension(ext_alias, **_params) + + def list_vnfds(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnfds(retrieve_all=retrieve_all, + **_params) + + def show_vnfd(self, vnfd, **_params): + return self.legacy_client.show_vnfd(vnfd, **_params) + + def create_vnfd(self, body): + return self.legacy_client.create_vnfd(body) + + def delete_vnfd(self, vnfd): + return self.legacy_client.delete_vnfd(vnfd) + + def list_vnfs(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnfs(retrieve_all=retrieve_all, + **_params) + + def show_vnf(self, vnf, **_params): + return self.legacy_client.show_vnf(vnf, **_params) + + def create_vnf(self, body): + return self.legacy_client.create_vnf(body) + + def delete_vnf(self, vnf, body=None): + return self.legacy_client.delete_vnf(vnf, body=body) + + def update_vnf(self, vnf, body): + return self.legacy_client.update_vnf(vnf, body) + + def list_vnf_resources(self, vnf, retrieve_all=True, **_params): + return self.legacy_client.list_vnf_resources( + vnf, retrieve_all=retrieve_all, **_params) + + def scale_vnf(self, vnf, body=None): + return self.legacy_client.scale_vnf(vnf, body=body) + + def show_vim(self, vim, **_params): + return self.legacy_client.show_vim(vim, **_params) + + def create_vim(self, body): + return self.legacy_client.create_vim(body) + + def delete_vim(self, vim): + return self.legacy_client.delete_vim(vim) + + def update_vim(self, vim, body): + return self.legacy_client.update_vim(vim, body) + + def list_vims(self, retrieve_all=True, **_params): + return self.legacy_client.list_vims(retrieve_all=retrieve_all, + **_params) + + def list_events(self, retrieve_all=True, **_params): + return self.legacy_client.list_events(retrieve_all=retrieve_all, + **_params) + + def list_vnf_events(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnf_events( + retrieve_all=retrieve_all, **_params) + + def list_vnfd_events(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnfd_events( + retrieve_all=retrieve_all, **_params) + + def list_vim_events(self, retrieve_all=True, **_params): + return self.legacy_client.list_vim_events( + retrieve_all=retrieve_all, **_params) + + def show_event(self, event_id, **_params): + return self.legacy_client.show_event(event_id, **_params) + + def create_vnffgd(self, body): + return self.legacy_client.create_vnffgd(body) + + def list_vnffgds(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnffgds(retrieve_all=retrieve_all, + **_params) + + def show_vnffgd(self, vnffgd, **_params): + return self.legacy_client.show_vnffgd(vnffgd, **_params) + + def delete_vnffgd(self, vnffgd): + return self.legacy_client.delete_vnffgd(vnffgd) + + def list_vnffgs(self, retrieve_all=True, **_params): + return self.legacy_client.list_vnffgs(retrieve_all=retrieve_all, + **_params) + + def show_vnffg(self, vnffg, **_params): + return self.legacy_client.show_vnffg(vnffg, **_params) + + def create_vnffg(self, body): + return self.legacy_client.create_vnffg(body) + + def delete_vnffg(self, vnffg): + return self.legacy_client.delete_vnffg(vnffg) + + def update_vnffg(self, vnffg, body): + return self.legacy_client.update_vnffg(vnffg, body) + + def list_sfcs(self, retrieve_all=True, **_params): + return self.legacy_client.list_sfcs(retrieve_all=retrieve_all, + **_params) + + def show_sfc(self, chain, **_params): + return self.legacy_client.show_sfc(chain, **_params) + + def list_nfps(self, retrieve_all=True, **_params): + return self.legacy_client.list_nfps(retrieve_all=retrieve_all, + **_params) + + def show_nfp(self, nfp, **_params): + return self.legacy_client.show_nfp(nfp, **_params) + + def list_classifiers(self, retrieve_all=True, **_params): + return self.legacy_client.list_classifiers( + retrieve_all=retrieve_all, **_params) + + def show_classifier(self, classifier, **_params): + return self.legacy_client.show_classifier(classifier, **_params) + + def list_nsds(self, retrieve_all=True, **_params): + return self.legacy_client.list_nsds(retrieve_all=retrieve_all, + **_params) + + def show_nsd(self, nsd, **_params): + return self.legacy_client.show_nsd(nsd, **_params) + + def create_nsd(self, body): + return self.legacy_client.create_nsd(body) + + def delete_nsd(self, nsd): + return self.legacy_client.delete_nsd(nsd) + + def list_nss(self, retrieve_all=True, **_params): + return self.legacy_client.list_nss(retrieve_all=retrieve_all, + **_params) + + def show_ns(self, ns, **_params): + return self.legacy_client.show_ns(ns, **_params) + + def create_ns(self, body): + return self.legacy_client.create_ns(body) + + def delete_ns(self, ns): + return self.legacy_client.delete_ns(ns) + + def create_cluster(self, body=None): + return self.legacy_client.create_cluster(body=body) + + def list_clusters(self, retrieve_all=True, **_params): + return self.legacy_client.list_clusters(retrieve_all=retrieve_all, + **_params) + + def show_cluster(self, cluster, **_params): + return self.legacy_client.show_cluster(cluster, **_params) + + def delete_cluster(self, cluster): + return self.legacy_client.delete_cluster(cluster) + + def create_clustermember(self, body=None): + return self.legacy_client.create_clustermember(body=body) + + def list_clustermembers(self, retrieve_all=True, **_params): + return self.legacy_client.list_clustermembers( + retrieve_all=retrieve_all, **_params) + + def show_clustermember(self, clustermember, **_params): + return self.legacy_client.show_clustermember(clustermember, + **_params) + + def delete_clustermember(self, clustermember): + return self.legacy_client.delete_clustermember(clustermember) + + # VnfPackageClient methods + + def create_vnf_package(self, body): + return self.vnf_package_client.create_vnf_package(body) diff --git a/test-requirements.txt b/test-requirements.txt index f71d60b6..07659205 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,8 +4,10 @@ hacking>=1.1.0,<1.2.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 +ddt>=1.0.1 # MIT fixtures>=3.0.0 # Apache-2.0/BSD python-subunit>=1.0.0 # Apache-2.0/BSD +requests-mock>=1.2.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0 testtools>=2.2.0 # MIT mock>=2.0.0 # BSD