From 8b45c8082b297ffb0aafc6575440747c1382158d Mon Sep 17 00:00:00 2001 From: Yi Feng Date: Tue, 7 Feb 2023 10:15:51 +0900 Subject: [PATCH] Add support cnf auto scale via threshold interface Add the Performance Management Threshold CLI to support AutoScale. The Performance Management Threshold API is based on ETSI NFV-SOL 002 v3.3.1 and ETSI NFV-SOL 003 v3.3.1, which is Version "2.0.0" API of Tacker. Implements: blueprint support-auto-lcm Change-Id: Idd313d6abe47dfa41fc86ddc614d00f99f3fc3b2 --- doc/source/cli/commands.rst | 5 + setup.cfg | 5 + tackerclient/osc/utils.py | 29 ++ tackerclient/osc/v1/vnflcm/vnflcm.py | 41 +- tackerclient/osc/v1/vnflcm/vnflcm_subsc.py | 27 +- tackerclient/osc/v2/vnffm/vnffm_sub.py | 30 +- .../create_vnf_pm_threshold_param_sample.json | 40 ++ .../update_vnf_pm_threshold_param_sample.json | 27 ++ tackerclient/osc/v2/vnfpm/vnfpm_job.py | 32 +- tackerclient/osc/v2/vnfpm/vnfpm_threshold.py | 216 ++++++++++ tackerclient/tests/unit/osc/v1/test_vnflcm.py | 24 +- tackerclient/tests/unit/osc/v2/test_vnflcm.py | 6 +- .../tests/unit/osc/v2/test_vnfpm_threshold.py | 398 ++++++++++++++++++ .../unit/osc/v2/vnfpm_threshold_fakes.py | 111 +++++ tackerclient/v1_0/client.py | 48 +++ 15 files changed, 907 insertions(+), 132 deletions(-) create mode 100644 tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_threshold_param_sample.json create mode 100644 tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_threshold_param_sample.json create mode 100644 tackerclient/osc/v2/vnfpm/vnfpm_threshold.py create mode 100644 tackerclient/tests/unit/osc/v2/test_vnfpm_threshold.py create mode 100644 tackerclient/tests/unit/osc/v2/vnfpm_threshold_fakes.py diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst index 4d6aba49..e3c41f5e 100644 --- a/doc/source/cli/commands.rst +++ b/doc/source/cli/commands.rst @@ -110,3 +110,8 @@ of individual command can be referred by **openstack help **. openstack vnfpm job update Update PM job. openstack vnfpm job delete Delete PM job. openstack vnfpm report show Show PM report. + openstack vnfpm threshold create Create PM threshold. + openstack vnfpm threshold list List PM threshold. + openstack vnfpm threshold show Show PM threshold. + openstack vnfpm threshold update Update PM threshold. + openstack vnfpm threshold delete Delete PM threshold. diff --git a/setup.cfg b/setup.cfg index 015e0bbc..a5bc1b3e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -137,6 +137,11 @@ openstack.tackerclient.v2 = vnfpm_job_update = tackerclient.osc.v2.vnfpm.vnfpm_job:UpdateVnfPmJob vnfpm_job_delete = tackerclient.osc.v2.vnfpm.vnfpm_job:DeleteVnfPmJob vnfpm_report_show = tackerclient.osc.v2.vnfpm.vnfpm_report:ShowVnfPmReport + vnfpm_threshold_create = tackerclient.osc.v2.vnfpm.vnfpm_threshold:CreateVnfPmThreshold + vnfpm_threshold_list = tackerclient.osc.v2.vnfpm.vnfpm_threshold:ListVnfPmThreshold + vnfpm_threshold_show = tackerclient.osc.v2.vnfpm.vnfpm_threshold:ShowVnfPmThreshold + vnfpm_threshold_update = tackerclient.osc.v2.vnfpm.vnfpm_threshold:UpdateVnfPmThreshold + vnfpm_threshold_delete = tackerclient.osc.v2.vnfpm.vnfpm_threshold:DeleteVnfPmThreshold vnffm_alarm_list = tackerclient.osc.v2.vnffm.vnffm_alarm:ListVnfFmAlarm vnffm_alarm_show = tackerclient.osc.v2.vnffm.vnffm_alarm:ShowVnfFmAlarm vnffm_alarm_update = tackerclient.osc.v2.vnffm.vnffm_alarm:UpdateVnfFmAlarm diff --git a/tackerclient/osc/utils.py b/tackerclient/osc/utils.py index 205e271b..8ebf3248 100644 --- a/tackerclient/osc/utils.py +++ b/tackerclient/osc/utils.py @@ -20,7 +20,9 @@ Stuffs specific to tackerclient OSC plugin should not be added to this module. They should go to tackerclient.osc.v1.utils. """ +import json import operator +import os from cliff import columns as cliff_columns from keystoneclient import exceptions as identity_exc @@ -29,6 +31,7 @@ from keystoneclient.v3 import projects from osc_lib import utils from oslo_serialization import jsonutils +from tackerclient.common import exceptions from tackerclient.i18n import _ @@ -212,3 +215,29 @@ class FormatComplexDataColumn(cliff_columns.FormattableColumn): def human_readable(self): return format_dict_with_indention(self._value) + + +def jsonfile2body(file_path): + + if file_path is None: + msg = _("File %s does not exist") + reason = msg % file_path + raise exceptions.InvalidInput(reason=reason) + + if os.access(file_path, os.R_OK) is False: + msg = _("User does not have read privileges to it") + raise exceptions.InvalidInput(reason=msg) + + try: + with open(file_path) as f: + body = json.load(f) + except (IOError, ValueError) as ex: + msg = _("Failed to load parameter file. Error: %s") + reason = msg % ex + raise exceptions.InvalidInput(reason=reason) + + if not body: + reason = _('The parameter file is empty') + raise exceptions.EmptyInput(reason=reason) + + return body diff --git a/tackerclient/osc/v1/vnflcm/vnflcm.py b/tackerclient/osc/v1/vnflcm/vnflcm.py index 2517860e..53e6053d 100644 --- a/tackerclient/osc/v1/vnflcm/vnflcm.py +++ b/tackerclient/osc/v1/vnflcm/vnflcm.py @@ -13,9 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -import json import logging -import os import time from osc_lib.command import command @@ -113,7 +111,7 @@ class CreateVnfLcm(command.ShowOne): body = {} if file_path: - return jsonfile2body(file_path) + return tacker_osc_utils.jsonfile2body(file_path) body['vnfdId'] = parsed_args.vnfd_id @@ -184,29 +182,6 @@ class ListVnfLcm(command.Lister): ) for s in vnf_instances)) -def jsonfile2body(file_path): - - if file_path is not None and os.access(file_path, os.R_OK) is False: - msg = _("File %s does not exist or user does not have read " - "privileges to it") - reason = msg % file_path - raise exceptions.InvalidInput(reason=reason) - - try: - with open(file_path) as f: - body = json.load(f) - except (IOError, ValueError) as ex: - msg = _("Failed to load parameter file. Error: %s") - reason = msg % ex - raise exceptions.InvalidInput(reason=reason) - - if not body: - reason = _('The parameter file is empty') - raise exceptions.InvalidInput(reason=reason) - - return body - - class InstantiateVnfLcm(command.Command): _description = _("Instantiate a VNF Instance") @@ -226,7 +201,7 @@ class InstantiateVnfLcm(command.Command): def take_action(self, parsed_args): client = self.app.client_manager.tackerclient result = client.instantiate_vnf_instance( - parsed_args.vnf_instance, jsonfile2body( + parsed_args.vnf_instance, tacker_osc_utils.jsonfile2body( parsed_args.instantiation_request_file)) if not result: print((_('Instantiate request for VNF Instance %(id)s has been' @@ -271,7 +246,8 @@ class HealVnfLcm(command.Command): if parsed_args.vnfc_instance: body['vnfcInstanceId'] = parsed_args.vnfc_instance if parsed_args.additional_param_file: - body.update(jsonfile2body(parsed_args.additional_param_file)) + body.update(tacker_osc_utils.jsonfile2body( + parsed_args.additional_param_file)) return body @@ -461,7 +437,7 @@ class UpdateVnfLcm(command.Command): body = {} if file_path: - return jsonfile2body(file_path) + return tacker_osc_utils.jsonfile2body(file_path) return body @@ -535,7 +511,8 @@ class ScaleVnfLcm(command.Command): body['numberOfSteps'] = parsed_args.number_of_steps if parsed_args.additional_param_file: - body.update(jsonfile2body(parsed_args.additional_param_file)) + body.update(tacker_osc_utils.jsonfile2body( + parsed_args.additional_param_file)) return body @@ -574,7 +551,7 @@ class ChangeExtConnVnfLcm(command.Command): def take_action(self, parsed_args): client = self.app.client_manager.tackerclient result = client.change_ext_conn_vnf_instance( - parsed_args.vnf_instance, jsonfile2body( + parsed_args.vnf_instance, tacker_osc_utils.jsonfile2body( parsed_args.request_file)) if not result: print((_('Change External VNF Connectivity for VNF Instance %s ' @@ -601,7 +578,7 @@ class ChangeVnfPkgVnfLcm(command.Command): 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.vnf_instance, tacker_osc_utils.jsonfile2body( parsed_args.request_file)) if not result: print((_('Change Current VNF Package for VNF Instance %s ' diff --git a/tackerclient/osc/v1/vnflcm/vnflcm_subsc.py b/tackerclient/osc/v1/vnflcm/vnflcm_subsc.py index d429141f..847bac74 100644 --- a/tackerclient/osc/v1/vnflcm/vnflcm_subsc.py +++ b/tackerclient/osc/v1/vnflcm/vnflcm_subsc.py @@ -13,9 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -import json import logging -import os from osc_lib.command import command from osc_lib import utils @@ -49,29 +47,6 @@ def _get_columns(lccn_subsc_obj): column_map) -def jsonfile2body(file_path): - - if file_path is not None and os.access(file_path, os.R_OK) is False: - msg = _("File %s does not exist or user does not have read " - "privileges to it") - reason = msg % file_path - raise exceptions.InvalidInput(reason=reason) - - try: - with open(file_path) as f: - body = json.load(f) - except (IOError, ValueError) as ex: - msg = _("Failed to load parameter file. Error: %s") - reason = msg % ex - raise exceptions.InvalidInput(reason=reason) - - if not body: - reason = _('The parameter file is empty') - raise exceptions.InvalidInput(reason=reason) - - return body - - class CreateLccnSubscription(command.ShowOne): _description = _("Create a new Lccn Subscription") @@ -86,7 +61,7 @@ class CreateLccnSubscription(command.ShowOne): def take_action(self, parsed_args): client = self.app.client_manager.tackerclient subsc = client.create_lccn_subscription( - jsonfile2body(parsed_args.create_request_file)) + tacker_osc_utils.jsonfile2body(parsed_args.create_request_file)) display_columns, columns = _get_columns(subsc) data = utils.get_item_properties(sdk_utils.DictModel(subsc), columns, formatters=_FORMATTERS, diff --git a/tackerclient/osc/v2/vnffm/vnffm_sub.py b/tackerclient/osc/v2/vnffm/vnffm_sub.py index 5fcb9bb0..bc2e18a6 100644 --- a/tackerclient/osc/v2/vnffm/vnffm_sub.py +++ b/tackerclient/osc/v2/vnffm/vnffm_sub.py @@ -13,9 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -import json import logging -import os from osc_lib.command import command from osc_lib import utils @@ -56,32 +54,6 @@ def _get_columns(vnffm_sub_obj): vnffm_sub_obj, column_map) -def jsonfile2body(file_path): - - if file_path is None: - msg = _("File %s does not exist") - reason = msg % file_path - raise exceptions.InvalidInput(reason=reason) - - if os.access(file_path, os.R_OK) is False: - msg = _("User does not have read privileges to it") - raise exceptions.InvalidInput(reason=msg) - - try: - with open(file_path) as f: - body = json.load(f) - except (IOError, ValueError) as ex: - msg = _("Failed to load parameter file. Error: %s") - reason = msg % ex - raise exceptions.InvalidInput(reason=reason) - - if not body: - reason = _('The parameter file is empty') - raise exceptions.EmptyInput(reason=reason) - - return body - - class CreateVnfFmSub(command.ShowOne): _description = _("Create a new VNF FM subscription") @@ -97,7 +69,7 @@ class CreateVnfFmSub(command.ShowOne): def take_action(self, parsed_args): client = self.app.client_manager.tackerclient vnf_fm_sub = client.create_vnf_fm_sub( - jsonfile2body(parsed_args.request_file)) + tacker_osc_utils.jsonfile2body(parsed_args.request_file)) display_columns, columns = _get_columns(vnf_fm_sub) data = utils.get_item_properties( sdk_utils.DictModel(vnf_fm_sub), columns, diff --git a/tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_threshold_param_sample.json b/tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_threshold_param_sample.json new file mode 100644 index 00000000..2a227b0c --- /dev/null +++ b/tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_threshold_param_sample.json @@ -0,0 +1,40 @@ +{ + "objectType": "Vnfc", + "objectInstanceId": "object-instance-id-1", + "subObjectInstanceIds": [ + "sub-object-instance-id-2" + ], + "criteria": { + "performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1", + "thresholdType": "SIMPLE", + "simpleThresholdDetails": { + "thresholdValue": 400.5, + "hysteresis": 10.3 + } + }, + "callbackUri": "/nfvo/notify/threshold", + "authentication": { + "authType": [ + "BASIC", + "OAUTH2_CLIENT_CREDENTIALS", + "OAUTH2_CLIENT_CERT" + ], + "paramsBasic": { + "userName": "nfvo", + "password": "nfvopwd" + }, + "paramsOauth2ClientCredentials": { + "clientId": "auth_user_name", + "clientPassword": "auth_password", + "tokenEndpoint": "token_endpoint" + }, + "paramsOauth2ClientCert": { + "clientId": "test", + "certificateRef": { + "type": "x5t#256", + "value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e" + }, + "tokenEndpoint": "http://127.0.0.1/token" + } + } +} diff --git a/tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_threshold_param_sample.json b/tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_threshold_param_sample.json new file mode 100644 index 00000000..81ddd682 --- /dev/null +++ b/tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_threshold_param_sample.json @@ -0,0 +1,27 @@ +{ + "callbackUri": "/nfvo/notify/threshold", + "authentication": { + "authType": [ + "BASIC", + "OAUTH2_CLIENT_CREDENTIALS", + "OAUTH2_CLIENT_CERT" + ], + "paramsBasic": { + "userName": "nfvo", + "password": "nfvopwd" + }, + "paramsOauth2ClientCredentials": { + "clientId": "auth_user_name", + "clientPassword": "auth_password", + "tokenEndpoint": "token_endpoint" + }, + "paramsOauth2ClientCert": { + "clientId": "test", + "certificateRef": { + "type": "x5t#256", + "value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e" + }, + "tokenEndpoint": "http://127.0.0.1/token" + } + } +} diff --git a/tackerclient/osc/v2/vnfpm/vnfpm_job.py b/tackerclient/osc/v2/vnfpm/vnfpm_job.py index ff9c8334..d7eae498 100644 --- a/tackerclient/osc/v2/vnfpm/vnfpm_job.py +++ b/tackerclient/osc/v2/vnfpm/vnfpm_job.py @@ -13,9 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -import json import logging -import os from functools import reduce from osc_lib.command import command @@ -78,32 +76,6 @@ def _get_columns(vnfpm_job_obj, action=None): vnfpm_job_obj, column_map) -def jsonfile2body(file_path): - - if file_path is None: - msg = _("File %s does not exist") - reason = msg % file_path - raise exceptions.InvalidInput(reason=reason) - - if os.access(file_path, os.R_OK) is False: - msg = _("User does not have read privileges to it") - raise exceptions.InvalidInput(reason=msg) - - try: - with open(file_path) as f: - body = json.load(f) - except (IOError, ValueError) as ex: - msg = _("Failed to load parameter file. Error: %s") - reason = msg % ex - raise exceptions.InvalidInput(reason=reason) - - if not body: - reason = _('The parameter file is empty') - raise exceptions.EmptyInput(reason=reason) - - return body - - class CreateVnfPmJob(command.ShowOne): _description = _("Create a new VNF PM job") @@ -119,7 +91,7 @@ class CreateVnfPmJob(command.ShowOne): def take_action(self, parsed_args): client = self.app.client_manager.tackerclient vnf_pm_job = client.create_vnf_pm_job( - jsonfile2body(parsed_args.request_file)) + tacker_osc_utils.jsonfile2body(parsed_args.request_file)) display_columns, columns = _get_columns(vnf_pm_job) data = utils.get_item_properties( sdk_utils.DictModel(vnf_pm_job), columns, @@ -284,7 +256,7 @@ class UpdateVnfPmJob(command.ShowOne): client = self.app.client_manager.tackerclient updated_values = client.update_vnf_pm_job( parsed_args.vnf_pm_job_id, - jsonfile2body(parsed_args.request_file)) + tacker_osc_utils.jsonfile2body(parsed_args.request_file)) display_columns, columns = _get_columns(updated_values, 'update') data = utils.get_item_properties( sdk_utils.DictModel(updated_values), diff --git a/tackerclient/osc/v2/vnfpm/vnfpm_threshold.py b/tackerclient/osc/v2/vnfpm/vnfpm_threshold.py new file mode 100644 index 00000000..57c71a8e --- /dev/null +++ b/tackerclient/osc/v2/vnfpm/vnfpm_threshold.py @@ -0,0 +1,216 @@ +# Copyright (C) 2023 Fujitsu +# 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.command import command +from osc_lib import utils + +from tackerclient.common import exceptions +from tackerclient.i18n import _ +from tackerclient.osc import sdk_utils +from tackerclient.osc import utils as tacker_osc_utils + +LOG = logging.getLogger(__name__) + +_ATTR_MAP = ( + ('id', 'ID', tacker_osc_utils.LIST_BOTH), + ('objectType', 'Object Type', tacker_osc_utils.LIST_BOTH), + ('_links', 'Links', tacker_osc_utils.LIST_BOTH) +) + +_FORMATTERS = { + 'subObjectInstanceIds': tacker_osc_utils.FormatComplexDataColumn, + 'criteria': tacker_osc_utils.FormatComplexDataColumn, + '_links': tacker_osc_utils.FormatComplexDataColumn +} + +_MIXED_CASE_FIELDS = ( + 'objectType', 'objectInstanceId', 'subObjectInstanceIds', 'callbackUri' +) + +_MIXED_CASE_FIELDS_UPDATE = ( + 'callbackUri' +) + +_VNF_PM_THRESHOLD_ID = 'vnf_pm_threshold_id' + + +def _get_columns(vnf_pm_threshold, action=None): + if action == 'update': + column_map = { + 'callbackUri': 'Callback Uri' + } + else: + column_map = { + 'id': 'ID', + 'objectType': 'Object Type', + 'objectInstanceId': 'Object Instance Id', + 'subObjectInstanceIds': 'Sub Object Instance Ids', + 'criteria': 'Criteria', + 'callbackUri': 'Callback Uri', + '_links': 'Links' + } + return sdk_utils.get_osc_show_columns_for_sdk_resource( + vnf_pm_threshold, column_map) + + +class CreateVnfPmThreshold(command.ShowOne): + _description = _("Create a new VNF PM threshold") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(CreateVnfPmThreshold, self).get_parser(prog_name) + parser.add_argument( + 'request_file', + metavar="", + help=_('Specify create VNF PM threshold request ' + 'parameters in a json file.')) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + vnf_pm_threshold = client.create_vnf_pm_threshold( + tacker_osc_utils.jsonfile2body(parsed_args.request_file)) + display_columns, columns = _get_columns(vnf_pm_threshold) + data = utils.get_item_properties( + sdk_utils.DictModel(vnf_pm_threshold), columns, + formatters=_FORMATTERS, mixed_case_fields=_MIXED_CASE_FIELDS) + return (display_columns, data) + + +class ListVnfPmThreshold(command.Lister): + _description = _("List VNF PM thresholds") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(ListVnfPmThreshold, self).get_parser(prog_name) + parser.add_argument( + "--filter", + metavar="", + help=_("Attribute-based-filtering parameters"), + ) + return parser + + def take_action(self, parsed_args): + _params = {} + + if parsed_args.filter: + _params['filter'] = parsed_args.filter + + client = self.app.client_manager.tackerclient + data = client.list_vnf_pm_thresholds(**_params) + headers, columns = tacker_osc_utils.get_column_definitions( + _ATTR_MAP, long_listing=True) + return (headers, + (utils.get_dict_properties( + s, columns, formatters=_FORMATTERS, + mixed_case_fields=_MIXED_CASE_FIELDS, + ) for s in data['vnf_pm_thresholds'])) + + +class ShowVnfPmThreshold(command.ShowOne): + _description = _("Display VNF PM threshold details") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(ShowVnfPmThreshold, self).get_parser(prog_name) + parser.add_argument( + _VNF_PM_THRESHOLD_ID, + metavar="", + help=_("VNF PM threshold ID to display")) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + obj = client.show_vnf_pm_threshold(parsed_args.vnf_pm_threshold_id) + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties( + sdk_utils.DictModel(obj), columns, + mixed_case_fields=_MIXED_CASE_FIELDS, + formatters=_FORMATTERS) + return (display_columns, data) + + +class UpdateVnfPmThreshold(command.ShowOne): + _description = _("Update information about an individual VNF PM threshold") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(UpdateVnfPmThreshold, self).get_parser(prog_name) + parser.add_argument( + _VNF_PM_THRESHOLD_ID, + metavar="", + help=_("VNF PM threshold ID to update.") + ) + parser.add_argument( + 'request_file', + metavar="", + help=_('Specify update PM threshold request ' + 'parameters in a json file.')) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.tackerclient + updated_values = client.update_vnf_pm_threshold( + parsed_args.vnf_pm_threshold_id, + tacker_osc_utils.jsonfile2body(parsed_args.request_file)) + display_columns, columns = _get_columns(updated_values, 'update') + data = utils.get_item_properties( + sdk_utils.DictModel(updated_values), columns, + mixed_case_fields=_MIXED_CASE_FIELDS_UPDATE) + return (display_columns, data) + + +class DeleteVnfPmThreshold(command.Command): + _description = _("Delete VNF PM threshold") + + def get_parser(self, prog_name): + LOG.debug('get_parser(%s)', prog_name) + parser = super(DeleteVnfPmThreshold, self).get_parser(prog_name) + parser.add_argument( + _VNF_PM_THRESHOLD_ID, + metavar="", + nargs="+", + help=_("VNF PM threshold ID(s) to delete")) + return parser + + def take_action(self, parsed_args): + error_count = 0 + client = self.app.client_manager.tackerclient + vnf_pm_threshold_ids = parsed_args.vnf_pm_threshold_id + + for threshold_id in vnf_pm_threshold_ids: + try: + client.delete_vnf_pm_threshold(threshold_id) + except Exception as e: + error_count += 1 + LOG.error(_("Failed to delete VNF PM threshold with " + "ID '%(threshold_id)s': %(e)s"), + {'threshold_id': threshold_id, 'e': e}) + + total = len(vnf_pm_threshold_ids) + if error_count > 0: + msg = (_("Failed to delete %(error_count)s of %(total)s " + "VNF PM thresholds.") % + {'error_count': error_count, 'total': total}) + raise exceptions.CommandError(message=msg) + + if total > 1: + print(_('All specified VNF PM thresholds are deleted ' + 'successfully')) + return + print(_("VNF PM threshold '%s' deleted " + "successfully") % vnf_pm_threshold_ids[0]) diff --git a/tackerclient/tests/unit/osc/v1/test_vnflcm.py b/tackerclient/tests/unit/osc/v1/test_vnflcm.py index b08dbb1b..d5798fed 100644 --- a/tackerclient/tests/unit/osc/v1/test_vnflcm.py +++ b/tackerclient/tests/unit/osc/v1/test_vnflcm.py @@ -297,9 +297,9 @@ class TestInstantiateVnfLcm(TestVnfLcm): self.instantiate_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)) + expected_msg = ("Invalid input: " + "User does not have read privileges to it") + self.assertEqual(expected_msg, str(ex)) @mock.patch("os.open") @mock.patch("os.access") @@ -403,9 +403,9 @@ class TestHealVnfLcm(TestVnfLcm): ex = self.assertRaises(exceptions.InvalidInput, self.heal_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)) + expected_msg = ("Invalid input: " + "User does not have read privileges to it") + self.assertEqual(expected_msg, str(ex)) @ddt.ddt @@ -774,9 +774,9 @@ class TestScaleVnfLcm(TestVnfLcm): ex = self.assertRaises(exceptions.InvalidInput, self.scale_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)) + expected_msg = ("Invalid input: " + "User does not have read privileges to it") + self.assertEqual(expected_msg, str(ex)) @ddt.data('SCALE_IN', 'SCALE_OUT') def test_take_action_vnf_instance_not_found(self, scale_type): @@ -888,9 +888,9 @@ class TestChangeExtConnVnfLcm(TestVnfLcm): self.change_ext_conn_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)) + expected_msg = ("Invalid input: " + "User does not have read privileges to it") + self.assertEqual(expected_msg, str(ex)) @mock.patch("os.open") @mock.patch("os.access") diff --git a/tackerclient/tests/unit/osc/v2/test_vnflcm.py b/tackerclient/tests/unit/osc/v2/test_vnflcm.py index 825b9b37..f19d31e0 100644 --- a/tackerclient/tests/unit/osc/v2/test_vnflcm.py +++ b/tackerclient/tests/unit/osc/v2/test_vnflcm.py @@ -121,9 +121,9 @@ class TestChangeVnfPkgVnfLcm(test_vnflcm.TestVnfLcm): 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)) + expected_msg = ("Invalid input: " + "User does not have read privileges to it") + self.assertEqual(expected_msg, str(ex)) @mock.patch("os.open") @mock.patch("os.access") diff --git a/tackerclient/tests/unit/osc/v2/test_vnfpm_threshold.py b/tackerclient/tests/unit/osc/v2/test_vnfpm_threshold.py new file mode 100644 index 00000000..53cc8270 --- /dev/null +++ b/tackerclient/tests/unit/osc/v2/test_vnfpm_threshold.py @@ -0,0 +1,398 @@ +# Copyright (C) 2023 Fujitsu +# 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 os +import sys + +from io import StringIO +from oslo_utils.fixture import uuidsentinel +from unittest import mock + +from tackerclient.common import exceptions +from tackerclient.osc import utils as tacker_osc_utils +from tackerclient.osc.v2.vnfpm import vnfpm_threshold +from tackerclient.tests.unit.osc import base +from tackerclient.tests.unit.osc.v1.fixture_data import client +from tackerclient.tests.unit.osc.v2 import vnfpm_threshold_fakes + + +class TestVnfPmThreshold(base.FixturedTestCase): + client_fixture_class = client.ClientFixture + + def setUp(self): + super(TestVnfPmThreshold, self).setUp() + self.url = client.TACKER_URL + self.header = {'content-type': 'application/json'} + self.app = mock.Mock() + self.app_args = mock.Mock() + self.client_manager = self.cs + self.app.client_manager.tackerclient = self.client_manager + + +def _get_columns_vnfpm_threshold(action=None): + if action == 'update': + columns = ['Callback Uri'] + else: + columns = ['ID', 'Object Type', 'Object Instance Id', + 'Sub Object Instance Ids', 'Criteria', 'Callback Uri', + 'Links'] + if action == 'list': + columns = [ + 'ID', 'Object Type', 'Links' + ] + return columns + + +@ddt.ddt +class TestCreateVnfPmThreshold(TestVnfPmThreshold): + + def setUp(self): + super(TestCreateVnfPmThreshold, self).setUp() + self.create_vnf_pm_threshold = vnfpm_threshold.CreateVnfPmThreshold( + self.app, self.app_args, cmd_name='vnfpm threshold create') + + def test_create_no_args(self): + self.assertRaises(base.ParserException, self.check_parser, + self.create_vnf_pm_threshold, [], []) + + @ddt.unpack + def test_take_action(self): + param_file = ("./tackerclient/osc/v2/vnfpm/samples/" + "create_vnf_pm_threshold_param_sample.json") + + arg_list = [param_file] + verify_list = [('request_file', param_file)] + + parsed_args = self.check_parser(self.create_vnf_pm_threshold, arg_list, + verify_list) + + response_json = vnfpm_threshold_fakes.vnf_pm_threshold_response() + self.requests_mock.register_uri( + 'POST', os.path.join(self.url, 'vnfpm/v2/thresholds'), + json=response_json, headers=self.header) + + actual_columns, data = ( + self.create_vnf_pm_threshold.take_action(parsed_args)) + self.assertCountEqual(_get_columns_vnfpm_threshold(), + actual_columns) + + _, attributes = vnfpm_threshold._get_columns(response_json) + expected_data = vnfpm_threshold_fakes.get_vnfpm_threshold_data( + response_json, columns=attributes) + self.assertListItemsEqual(expected_data, data) + + +@ddt.ddt +class TestListVnfPmThreshold(TestVnfPmThreshold): + + def setUp(self): + super(TestListVnfPmThreshold, self).setUp() + self.list_vnf_pm_thresholds = vnfpm_threshold.ListVnfPmThreshold( + self.app, self.app_args, cmd_name='vnfpm threshold list') + + def test_take_action(self): + vnf_pm_threshold_objs = vnfpm_threshold_fakes.create_vnf_pm_thresholds( + count=3) + parsed_args = self.check_parser(self.list_vnf_pm_thresholds, [], []) + self.requests_mock.register_uri( + 'GET', + os.path.join(self.url, 'vnfpm/v2/thresholds'), + json=vnf_pm_threshold_objs, headers=self.header) + + actual_columns, data = self.list_vnf_pm_thresholds.take_action( + parsed_args) + + _, columns = tacker_osc_utils.get_column_definitions( + vnfpm_threshold._ATTR_MAP, long_listing=True) + + expected_data = [] + for vnf_pm_threshold_obj_idx in vnf_pm_threshold_objs: + expected_data.append( + vnfpm_threshold_fakes.get_vnfpm_threshold_data( + vnf_pm_threshold_obj_idx, columns=columns)) + + self.assertCountEqual(_get_columns_vnfpm_threshold(action='list'), + actual_columns) + self.assertCountEqual(expected_data, list(data)) + + def test_take_action_with_filter(self): + vnf_pm_threshold_objs = vnfpm_threshold_fakes.create_vnf_pm_thresholds( + count=3) + parsed_args = self.check_parser( + self.list_vnf_pm_thresholds, + ["--filter", '(eq,perceivedSeverity,WARNING)'], + [('filter', '(eq,perceivedSeverity,WARNING)')]) + self.requests_mock.register_uri( + 'GET', os.path.join( + self.url, + 'vnfpm/v2/thresholds?filter=(eq,perceivedSeverity,WARNING)'), + json=vnf_pm_threshold_objs, headers=self.header) + + actual_columns, data = self.list_vnf_pm_thresholds.take_action( + parsed_args) + + _, columns = tacker_osc_utils.get_column_definitions( + vnfpm_threshold._ATTR_MAP, long_listing=True) + + expected_data = [] + for vnf_pm_threshold_obj_idx in vnf_pm_threshold_objs: + expected_data.append( + vnfpm_threshold_fakes.get_vnfpm_threshold_data( + vnf_pm_threshold_obj_idx, columns=columns)) + + self.assertCountEqual(_get_columns_vnfpm_threshold(action='list'), + actual_columns) + self.assertListItemsEqual(expected_data, list(data)) + + def test_take_action_with_incorrect_filter(self): + parsed_args = self.check_parser( + self.list_vnf_pm_thresholds, + ["--filter", '(perceivedSeverity)'], + [('filter', '(perceivedSeverity)')]) + + url = os.path.join( + self.url, 'vnfpm/v2/thresholds?filter=(perceivedSeverity)') + + self.requests_mock.register_uri( + 'GET', url, headers=self.header, status_code=400, json={}) + + self.assertRaises(exceptions.TackerClientException, + self.list_vnf_pm_thresholds.take_action, + parsed_args) + + def test_take_action_internal_server_error(self): + parsed_args = self.check_parser( + self.list_vnf_pm_thresholds, + ["--filter", '(eq,perceivedSeverity,WARNING)'], + [('filter', '(eq,perceivedSeverity,WARNING)')]) + + url = os.path.join( + self.url, + 'vnfpm/v2/thresholds?filter=(eq,perceivedSeverity,WARNING)') + + self.requests_mock.register_uri( + 'GET', url, headers=self.header, status_code=500, json={}) + + self.assertRaises(exceptions.TackerClientException, + self.list_vnf_pm_thresholds.take_action, + parsed_args) + + +class TestShowVnfPmThreshold(TestVnfPmThreshold): + + def setUp(self): + super(TestShowVnfPmThreshold, self).setUp() + self.show_vnf_pm_thresholds = vnfpm_threshold.ShowVnfPmThreshold( + self.app, self.app_args, cmd_name='vnfpm threshold show') + + def test_take_action(self): + vnfpm_threshold_obj = vnfpm_threshold_fakes.vnf_pm_threshold_response() + + arg_list = [vnfpm_threshold_obj['id']] + verify_list = [('vnf_pm_threshold_id', vnfpm_threshold_obj['id'])] + + # command param + parsed_args = self.check_parser( + self.show_vnf_pm_thresholds, arg_list, verify_list) + url = os.path.join( + self.url, 'vnfpm/v2/thresholds', vnfpm_threshold_obj['id']) + + self.requests_mock.register_uri( + 'GET', url, headers=self.header, json=vnfpm_threshold_obj) + + columns, data = (self.show_vnf_pm_thresholds.take_action(parsed_args)) + + self.assertCountEqual(_get_columns_vnfpm_threshold('show'), columns) + + _, attributes = vnfpm_threshold._get_columns(vnfpm_threshold_obj) + self.assertListItemsEqual( + vnfpm_threshold_fakes.get_vnfpm_threshold_data( + vnfpm_threshold_obj, columns=attributes), data) + + def test_take_action_vnf_pm_threshold_id_not_found(self): + arg_list = [uuidsentinel.vnf_pm_threshold_id] + verify_list = [('vnf_pm_threshold_id', + uuidsentinel.vnf_pm_threshold_id)] + + # command param + parsed_args = self.check_parser( + self.show_vnf_pm_thresholds, arg_list, verify_list) + + url = os.path.join( + self.url, 'vnfpm/v2/thresholds', + uuidsentinel.vnf_pm_threshold_id) + self.requests_mock.register_uri( + 'GET', url, headers=self.header, status_code=404, json={}) + + self.assertRaises(exceptions.TackerClientException, + self.show_vnf_pm_thresholds.take_action, + parsed_args) + + def test_take_action_internal_server_error(self): + arg_list = [uuidsentinel.vnf_pm_threshold_id] + verify_list = [('vnf_pm_threshold_id', + uuidsentinel.vnf_pm_threshold_id)] + + # command param + parsed_args = self.check_parser( + self.show_vnf_pm_thresholds, arg_list, verify_list) + + url = os.path.join( + self.url, 'vnfpm/v2/thresholds', + uuidsentinel.vnf_pm_threshold_id) + self.requests_mock.register_uri( + 'GET', url, headers=self.header, status_code=500, json={}) + + self.assertRaises(exceptions.TackerClientException, + self.show_vnf_pm_thresholds.take_action, + parsed_args) + + +@ddt.ddt +class TestUpdateVnfPmThreshold(TestVnfPmThreshold): + + def setUp(self): + super(TestUpdateVnfPmThreshold, self).setUp() + self.update_vnf_pm_threshold = vnfpm_threshold.UpdateVnfPmThreshold( + self.app, self.app_args, cmd_name='vnfpm threshold update') + + def test_take_action(self): + param_file = ("./tackerclient/osc/v2/vnfpm/samples/" + "update_vnf_pm_threshold_param_sample.json") + arg_list = [uuidsentinel.vnf_pm_threshold_id, param_file] + verify_list = [ + ('vnf_pm_threshold_id', uuidsentinel.vnf_pm_threshold_id), + ('request_file', param_file) + ] + vnfpm_threshold_obj = vnfpm_threshold_fakes.vnf_pm_threshold_response( + None, 'update') + + # command param + parsed_args = self.check_parser( + self.update_vnf_pm_threshold, arg_list, verify_list) + url = os.path.join( + self.url, 'vnfpm/v2/thresholds', + uuidsentinel.vnf_pm_threshold_id) + self.requests_mock.register_uri( + 'PATCH', url, headers=self.header, json=vnfpm_threshold_obj) + + actual_columns, data = ( + self.update_vnf_pm_threshold.take_action(parsed_args)) + expected_columns = _get_columns_vnfpm_threshold(action='update') + self.assertCountEqual(expected_columns, actual_columns) + + _, columns = vnfpm_threshold._get_columns( + vnfpm_threshold_obj, action='update') + expected_data = vnfpm_threshold_fakes.get_vnfpm_threshold_data( + vnfpm_threshold_obj, columns=columns) + self.assertEqual(expected_data, data) + + def test_take_action_vnf_pm_threshold_id_not_found(self): + param_file = ("./tackerclient/osc/v2/vnfpm/samples/" + "update_vnf_pm_threshold_param_sample.json") + arg_list = [uuidsentinel.vnf_pm_threshold_id, param_file] + verify_list = [ + ('vnf_pm_threshold_id', uuidsentinel.vnf_pm_threshold_id), + ('request_file', param_file) + ] + + # command param + parsed_args = self.check_parser( + self.update_vnf_pm_threshold, arg_list, verify_list) + url = os.path.join( + self.url, 'vnfpm/v2/thresholds', + uuidsentinel.vnf_pm_threshold_id) + self.requests_mock.register_uri( + 'PATCH', url, headers=self.header, status_code=404, json={}) + self.assertRaises(exceptions.TackerClientException, + self.update_vnf_pm_threshold.take_action, + parsed_args) + + +class TestDeleteVnfPmThreshold(TestVnfPmThreshold): + + def setUp(self): + super(TestDeleteVnfPmThreshold, self).setUp() + self.delete_vnf_pm_threshold = vnfpm_threshold.DeleteVnfPmThreshold( + self.app, self.app_args, cmd_name='vnfpm threshold delete') + + # Vnf Pm threshold to delete + self.vnf_pm_thresholds = ( + vnfpm_threshold_fakes.create_vnf_pm_thresholds(count=3)) + + def _mock_request_url_for_delete(self, index): + url = os.path.join(self.url, 'vnfpm/v2/thresholds', + self.vnf_pm_thresholds[index]['id']) + + self.requests_mock.register_uri('DELETE', url, + headers=self.header, json={}) + + def test_delete_one_vnf_pm_threshold(self): + arg_list = [self.vnf_pm_thresholds[0]['id']] + verify_list = [('vnf_pm_threshold_id', + [self.vnf_pm_thresholds[0]['id']])] + + parsed_args = self.check_parser(self.delete_vnf_pm_threshold, arg_list, + verify_list) + + self._mock_request_url_for_delete(0) + sys.stdout = buffer = StringIO() + result = self.delete_vnf_pm_threshold.take_action(parsed_args) + self.assertIsNone(result) + self.assertEqual( + (f"VNF PM threshold '{self.vnf_pm_thresholds[0]['id']}' " + f"deleted successfully"), buffer.getvalue().strip()) + + def test_delete_multiple_vnf_pm_threshold(self): + arg_list = [] + for obj in self.vnf_pm_thresholds: + arg_list.append(obj['id']) + verify_list = [('vnf_pm_threshold_id', arg_list)] + parsed_args = self.check_parser(self.delete_vnf_pm_threshold, arg_list, + verify_list) + for i in range(0, len(self.vnf_pm_thresholds)): + self._mock_request_url_for_delete(i) + sys.stdout = buffer = StringIO() + result = self.delete_vnf_pm_threshold.take_action(parsed_args) + self.assertIsNone(result) + self.assertEqual('All specified VNF PM thresholds are deleted ' + 'successfully', buffer.getvalue().strip()) + + def test_delete_multiple_vnf_pm_threshold_exception(self): + arg_list = [ + self.vnf_pm_thresholds[0]['id'], + 'xxxx-yyyy-zzzz', + self.vnf_pm_thresholds[1]['id'], + ] + verify_list = [('vnf_pm_threshold_id', arg_list)] + parsed_args = self.check_parser(self.delete_vnf_pm_threshold, + arg_list, verify_list) + + self._mock_request_url_for_delete(0) + + url = os.path.join(self.url, 'vnfpm/v2/thresholds', + 'xxxx-yyyy-zzzz') + self.requests_mock.register_uri( + 'GET', url, exc=exceptions.ConnectionFailed) + + self._mock_request_url_for_delete(1) + exception = self.assertRaises(exceptions.CommandError, + self.delete_vnf_pm_threshold.take_action, + parsed_args) + + self.assertEqual( + f'Failed to delete 1 of {len(self.vnf_pm_thresholds)} ' + 'VNF PM thresholds.', exception.message) diff --git a/tackerclient/tests/unit/osc/v2/vnfpm_threshold_fakes.py b/tackerclient/tests/unit/osc/v2/vnfpm_threshold_fakes.py new file mode 100644 index 00000000..ac2567ea --- /dev/null +++ b/tackerclient/tests/unit/osc/v2/vnfpm_threshold_fakes.py @@ -0,0 +1,111 @@ +# Copyright (C) 2023 Fujitsu +# 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. + +from oslo_utils import uuidutils + +from tackerclient.osc import utils as tacker_osc_utils + + +def create_vnf_pm_thresholds(count=2): + """Create multiple fake vnf pm thresholds. + + :param int count: + The number of vnf_pm_thresholds to fake + :return: + A list of fake vnf pm thresholds dictionary + """ + vnf_pm_thresholds = [] + for _ in range(0, count): + unique_id = uuidutils.generate_uuid() + vnf_pm_thresholds.append(vnf_pm_threshold_response( + attrs={'id': unique_id})) + return vnf_pm_thresholds + + +def vnf_pm_threshold_response(attrs=None, action=None): + """Create a fake vnf pm threshold. + + :param Dictionary attrs: + A dictionary with all attributes + :param String action: + The operation performed on threshold + :return: + A pm threshold dict + """ + if action == 'update': + fake_vnf_pm_threshold = { + "callbackUri": "/nfvo/notify/threshold", + } + return fake_vnf_pm_threshold + + attrs = attrs or {} + # Set default attributes. + fake_vnf_pm_threshold = { + "id": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d", + "objectType": "Vnfc", + "objectInstanceId": "object-instance-id-1", + "subObjectInstanceIds": [ + "sub-object-instance-id-2" + ], + "criteria": { + "performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1", + "thresholdType": "SIMPLE", + "simpleThresholdDetails": { + "thresholdValue": 500.5, + "hysteresis": 10.5 + } + }, + "callbackUri": "/nfvo/notify/threshold", + "_links": { + "self": { + "href": "/vnfpm/v2/thresholds/" + "78a39661-60a8-4824-b989-88c1b0c3534a" + }, + "object": { + "href": "/vnflcm/v1/vnf_instances/" + "0e5f3086-4e79-47ed-a694-54c29155fa26" + } + } + } + + # Overwrite default attributes. + fake_vnf_pm_threshold.update(attrs) + + return fake_vnf_pm_threshold + + +def get_vnfpm_threshold_data(vnf_pm_threshold, columns=None): + """Get the vnfpm threshold. + + :param Dictionary vnf_pm_threshold: + A dictionary with vnf_pm_threshold + :param List columns: + A list of column names + :return: + A tuple object sorted based on the name of the columns. + """ + complex_attributes = ['subObjectInstanceIds', + 'criteria', '_links', 'authentication'] + + for attribute in complex_attributes: + if vnf_pm_threshold.get(attribute): + vnf_pm_threshold.update( + {attribute: tacker_osc_utils.FormatComplexDataColumn( + vnf_pm_threshold[attribute])}) + + # return the list of data as per column order + if columns is None: + columns = sorted(vnf_pm_threshold.keys()) + return tuple([vnf_pm_threshold[key] for key in columns]) diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index 289359ae..77a384d1 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -1104,6 +1104,8 @@ class VnfPMClient(ClientBase): vnf_pm_jobs_path = '/vnfpm/v2/pm_jobs' vnf_pm_job_path = '/vnfpm/v2/pm_jobs/%s' vnf_pm_reports_path = '/vnfpm/v2/pm_jobs/%(job_id)s/reports/%(report_id)s' + vnf_pm_thresholds_path = '/vnfpm/v2/thresholds' + vnf_pm_threshold_path = '/vnfpm/v2/thresholds/%s' def build_action(self, action): return action @@ -1143,6 +1145,35 @@ class VnfPMClient(ClientBase): 'job_id': vnf_pm_job_id, 'report_id': vnf_pm_report_id }, headers=self.headers) + @APIParamsCall + def create_vnf_pm_threshold(self, body): + return self.post( + self.vnf_pm_thresholds_path, body=body, headers=self.headers) + + @APIParamsCall + def list_vnf_pm_thresholds(self, retrieve_all=True, **_params): + return self.list( + "vnf_pm_thresholds", self.vnf_pm_thresholds_path, retrieve_all, + headers=self.headers, **_params) + + @APIParamsCall + def show_vnf_pm_threshold(self, vnf_pm_threshold_id): + return self.get( + self.vnf_pm_threshold_path % vnf_pm_threshold_id, + headers=self.headers) + + @APIParamsCall + def update_vnf_pm_threshold(self, vnf_pm_threshold_id, body): + return self.patch( + self.vnf_pm_threshold_path % vnf_pm_threshold_id, body=body, + headers=self.headers) + + @APIParamsCall + def delete_vnf_pm_threshold(self, vnf_pm_threshold_id): + return self.delete( + self.vnf_pm_threshold_path % vnf_pm_threshold_id, + headers=self.headers) + class Client(object): """Unified interface to interact with multiple applications of tacker service. @@ -1527,3 +1558,20 @@ class Client(object): def show_vnf_pm_report(self, vnf_pm_job_id, vnf_pm_report_id): return self.vnf_pm_client.show_vnf_pm_report( vnf_pm_job_id, vnf_pm_report_id) + + def create_vnf_pm_threshold(self, body): + return self.vnf_pm_client.create_vnf_pm_threshold(body) + + def list_vnf_pm_thresholds(self, retrieve_all=True, **_params): + return self.vnf_pm_client.list_vnf_pm_thresholds( + retrieve_all=retrieve_all, **_params) + + def show_vnf_pm_threshold(self, vnf_pm_threshold_id): + return self.vnf_pm_client.show_vnf_pm_threshold(vnf_pm_threshold_id) + + def update_vnf_pm_threshold(self, vnf_pm_threshold_id, body): + return self.vnf_pm_client.update_vnf_pm_threshold( + vnf_pm_threshold_id, body) + + def delete_vnf_pm_threshold(self, vnf_pm_threshold_id): + return self.vnf_pm_client.delete_vnf_pm_threshold(vnf_pm_threshold_id)