Add vnflcm subscriptions APIs
This patch supports CLI of vnflcm subscriptions APIs. They are as follows. * vnflcm subsc create * vnflcm subsc delete * vnflcm subsc list * vnflcm subsc show The output message of "vnflcm delete" was also modified to match "vnflcm subsc delete". Implements: blueprint support-nfv-solv3-subscriptions Implements: blueprint support-etsi-nfv-specs Change-Id: I9a839a3d131afc80fec0c2bbaa30443798117e0d
This commit is contained in:
@@ -103,6 +103,10 @@ openstack.tackerclient.v1 =
|
|||||||
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
|
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
|
||||||
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
|
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
|
||||||
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
|
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
|
||||||
|
vnflcm_subsc_create = tackerclient.osc.v1.vnflcm.vnflcm_subsc:CreateLccnSubscription
|
||||||
|
vnflcm_subsc_delete = tackerclient.osc.v1.vnflcm.vnflcm_subsc:DeleteLccnSubscription
|
||||||
|
vnflcm_subsc_list = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ListLccnSubscription
|
||||||
|
vnflcm_subsc_show = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ShowLccnSubscription
|
||||||
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
|
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
|
||||||
openstack.tackerclient.v2 =
|
openstack.tackerclient.v2 =
|
||||||
vnflcm_create = tackerclient.osc.v1.vnflcm.vnflcm:CreateVnfLcm
|
vnflcm_create = tackerclient.osc.v1.vnflcm.vnflcm:CreateVnfLcm
|
||||||
@@ -121,4 +125,8 @@ openstack.tackerclient.v2 =
|
|||||||
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
|
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
|
||||||
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
|
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
|
||||||
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
|
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
|
||||||
|
vnflcm_subsc_create = tackerclient.osc.v1.vnflcm.vnflcm_subsc:CreateLccnSubscription
|
||||||
|
vnflcm_subsc_delete = tackerclient.osc.v1.vnflcm.vnflcm_subsc:DeleteLccnSubscription
|
||||||
|
vnflcm_subsc_list = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ListLccnSubscription
|
||||||
|
vnflcm_subsc_show = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ShowLccnSubscription
|
||||||
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
|
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
|
||||||
|
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
"filter": {
|
||||||
|
"vnfInstanceSubscriptionFilter": {
|
||||||
|
"vnfdIds": [
|
||||||
|
"dummy-vnfdId-1",
|
||||||
|
"dummy-vnfdId-2"
|
||||||
|
],
|
||||||
|
"vnfProductsFromProviders": [
|
||||||
|
{
|
||||||
|
"vnfProvider": "dummy-vnfProvider-1",
|
||||||
|
"vnfProducts": [
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-1-1",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-1-2",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProvider": "dummy-vnfProvider-2",
|
||||||
|
"vnfProducts": [
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-2-1",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-2-2",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vnfInstanceIds": [
|
||||||
|
"dummy-vnfInstanceId-1",
|
||||||
|
"dummy-vnfInstanceId-2"
|
||||||
|
],
|
||||||
|
"vnfInstanceNames": [
|
||||||
|
"dummy-vnfInstanceName-1",
|
||||||
|
"dummy-vnfInstanceName-2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notificationTypes": [
|
||||||
|
"VnfLcmOperationOccurrenceNotification",
|
||||||
|
"VnfIdentifierCreationNotification",
|
||||||
|
"VnfIdentifierDeletionNotification"
|
||||||
|
],
|
||||||
|
"operationTypes": [
|
||||||
|
"INSTANTIATE",
|
||||||
|
"SCALE",
|
||||||
|
"TERMINATE",
|
||||||
|
"HEAL",
|
||||||
|
"MODIFY_INFO",
|
||||||
|
"CHANGE_EXT_CONN"
|
||||||
|
],
|
||||||
|
"operationStates": [
|
||||||
|
"COMPLETED",
|
||||||
|
"FAILED",
|
||||||
|
"FAILED_TEMP",
|
||||||
|
"PROCESSING",
|
||||||
|
"ROLLING_BACK",
|
||||||
|
"ROLLED_BACK",
|
||||||
|
"STARTING"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"callbackUri": "http://localhost:9990/notification/callback/test",
|
||||||
|
"authentication": {
|
||||||
|
"authType": [
|
||||||
|
"BASIC"
|
||||||
|
],
|
||||||
|
"paramsBasic": {
|
||||||
|
"password": "test_pass",
|
||||||
|
"userName": "test_user"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -347,7 +347,7 @@ class TerminateVnfLcm(command.Command):
|
|||||||
|
|
||||||
result = client.delete_vnf_instance(parsed_args.vnf_instance)
|
result = client.delete_vnf_instance(parsed_args.vnf_instance)
|
||||||
if not result:
|
if not result:
|
||||||
print(_("VNF Instance '%(id)s' deleted successfully") %
|
print(_("VNF Instance '%(id)s' is deleted successfully") %
|
||||||
{'id': parsed_args.vnf_instance})
|
{'id': parsed_args.vnf_instance})
|
||||||
|
|
||||||
def _wait_until_vnf_is_terminated(self, client, vnf_instance_id,
|
def _wait_until_vnf_is_terminated(self, client, vnf_instance_id,
|
||||||
@@ -420,7 +420,7 @@ class DeleteVnfLcm(command.Command):
|
|||||||
print(_('All specified vnf instances are deleted '
|
print(_('All specified vnf instances are deleted '
|
||||||
'successfully'))
|
'successfully'))
|
||||||
else:
|
else:
|
||||||
print(_("Vnf instance '%s' deleted "
|
print(_("Vnf instance '%s' is deleted "
|
||||||
"successfully") % vnf_instances[0])
|
"successfully") % vnf_instances[0])
|
||||||
|
|
||||||
|
|
||||||
|
206
tackerclient/osc/v1/vnflcm/vnflcm_subsc.py
Normal file
206
tackerclient/osc/v1/vnflcm/vnflcm_subsc.py
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# 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 json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
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__)
|
||||||
|
|
||||||
|
_LCCN_SUBSCRIPTION_ID = 'subscription_id'
|
||||||
|
|
||||||
|
_MIXED_CASE_FIELDS = ['filter', 'callbackUri']
|
||||||
|
|
||||||
|
_FORMATTERS = {
|
||||||
|
'filter': tacker_osc_utils.FormatComplexDataColumn,
|
||||||
|
'_links': tacker_osc_utils.FormatComplexDataColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_columns(lccn_subsc_obj):
|
||||||
|
|
||||||
|
column_map = {
|
||||||
|
'id': 'ID',
|
||||||
|
'filter': 'Filter',
|
||||||
|
'callbackUri': 'Callback URI',
|
||||||
|
'_links': 'Links'
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdk_utils.get_osc_show_columns_for_sdk_resource(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")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(CreateLccnSubscription, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'create_request_file',
|
||||||
|
metavar="<param-file>",
|
||||||
|
help=_('Specify create request parameters in a json file.'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
client = self.app.client_manager.tackerclient
|
||||||
|
subsc = client.create_lccn_subscription(
|
||||||
|
jsonfile2body(parsed_args.create_request_file))
|
||||||
|
display_columns, columns = _get_columns(subsc)
|
||||||
|
data = utils.get_item_properties(sdk_utils.DictModel(subsc),
|
||||||
|
columns, formatters=_FORMATTERS,
|
||||||
|
mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||||
|
return (display_columns, data)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteLccnSubscription(command.Command):
|
||||||
|
_description = _("Delete Lccn Subscription(s)")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(DeleteLccnSubscription, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
_LCCN_SUBSCRIPTION_ID,
|
||||||
|
metavar="<subscription-id>",
|
||||||
|
nargs="+",
|
||||||
|
help=_("Lccn Subscription ID(s) to delete"))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
error_count = 0
|
||||||
|
client = self.app.client_manager.tackerclient
|
||||||
|
lccn_subscriptions = parsed_args.subscription_id
|
||||||
|
for lccn_subscription in lccn_subscriptions:
|
||||||
|
try:
|
||||||
|
client.delete_lccn_subscription(lccn_subscription)
|
||||||
|
except Exception as e:
|
||||||
|
error_count += 1
|
||||||
|
LOG.error(_("Failed to delete Lccn Subscription with "
|
||||||
|
"ID '%(subsc)s': %(e)s"),
|
||||||
|
{'subsc': lccn_subscription, 'e': e})
|
||||||
|
|
||||||
|
total = len(lccn_subscriptions)
|
||||||
|
if (error_count > 0):
|
||||||
|
msg = (_("Failed to delete %(error_count)s of %(total)s "
|
||||||
|
"Lccn Subscriptions.") % {'error_count': error_count,
|
||||||
|
'total': total})
|
||||||
|
raise exceptions.CommandError(message=msg)
|
||||||
|
else:
|
||||||
|
if total > 1:
|
||||||
|
print(_('All specified Lccn Subscriptions are deleted '
|
||||||
|
'successfully'))
|
||||||
|
else:
|
||||||
|
print(_("Lccn Subscription '%s' is deleted "
|
||||||
|
"successfully") % lccn_subscriptions[0])
|
||||||
|
|
||||||
|
|
||||||
|
class ListLccnSubscription(command.Lister):
|
||||||
|
_description = _("List Lccn Subscriptions")
|
||||||
|
|
||||||
|
def get_parser(self, program_name):
|
||||||
|
parser = super(ListLccnSubscription, self).get_parser(program_name)
|
||||||
|
parser.add_argument(
|
||||||
|
"--filter",
|
||||||
|
metavar="<filter>",
|
||||||
|
help=_("Attribute-based-filtering parameters"),
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def get_attributes(self, exclude=None):
|
||||||
|
fields = [
|
||||||
|
{
|
||||||
|
"key": "id",
|
||||||
|
"value": "ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "callbackUri",
|
||||||
|
"value": "Callback URI"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
attributes = []
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
attributes.extend([(field['key'], field['value'],
|
||||||
|
tacker_osc_utils.LIST_BOTH)])
|
||||||
|
return tuple(attributes)
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if parsed_args.filter:
|
||||||
|
params['filter'] = parsed_args.filter
|
||||||
|
|
||||||
|
client = self.app.client_manager.tackerclient
|
||||||
|
subscriptions = client.list_lccn_subscriptions(**params)
|
||||||
|
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||||
|
self.get_attributes(), long_listing=True)
|
||||||
|
|
||||||
|
dictionary_properties = (utils.get_dict_properties(
|
||||||
|
s, columns, mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||||
|
for s in subscriptions
|
||||||
|
)
|
||||||
|
|
||||||
|
return (headers, dictionary_properties)
|
||||||
|
|
||||||
|
|
||||||
|
class ShowLccnSubscription(command.ShowOne):
|
||||||
|
_description = _("Display Lccn Subscription details")
|
||||||
|
|
||||||
|
def get_parser(self, program_name):
|
||||||
|
parser = super(ShowLccnSubscription, self).get_parser(program_name)
|
||||||
|
parser.add_argument(
|
||||||
|
_LCCN_SUBSCRIPTION_ID,
|
||||||
|
metavar="<subscription-id>",
|
||||||
|
help=_('Lccn Subscription ID to display'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
client = self.app.client_manager.tackerclient
|
||||||
|
obj = client.show_lccn_subscription(parsed_args.subscription_id)
|
||||||
|
display_columns, columns = _get_columns(obj)
|
||||||
|
data = utils.get_item_properties(
|
||||||
|
sdk_utils.DictModel(obj),
|
||||||
|
columns, formatters=_FORMATTERS,
|
||||||
|
mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||||
|
return (display_columns, data)
|
@@ -420,7 +420,7 @@ class TestTerminateVnfLcm(TestVnfLcm):
|
|||||||
self.assertIn(expected_message, actual_message)
|
self.assertIn(expected_message, actual_message)
|
||||||
|
|
||||||
if delete_vnf:
|
if delete_vnf:
|
||||||
expected_message = ("VNF Instance '%s' deleted successfully"
|
expected_message = ("VNF Instance '%s' is deleted successfully"
|
||||||
% vnf_instance['id'])
|
% vnf_instance['id'])
|
||||||
self.assertIn(expected_message, actual_message)
|
self.assertIn(expected_message, actual_message)
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ class TestDeleteVnfLcm(TestVnfLcm):
|
|||||||
sys.stdout = buffer = StringIO()
|
sys.stdout = buffer = StringIO()
|
||||||
result = self.delete_vnf_instance.take_action(parsed_args)
|
result = self.delete_vnf_instance.take_action(parsed_args)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
self.assertEqual(("Vnf instance '%s' deleted successfully")
|
self.assertEqual(("Vnf instance '%s' is deleted successfully")
|
||||||
% self.vnf_instances[0]['id'],
|
% self.vnf_instances[0]['id'],
|
||||||
buffer.getvalue().strip())
|
buffer.getvalue().strip())
|
||||||
|
|
||||||
|
209
tackerclient/tests/unit/osc/v1/test_vnflcm_subsc.py
Normal file
209
tackerclient/tests/unit/osc/v1/test_vnflcm_subsc.py
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# 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 os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
from tackerclient.common import exceptions
|
||||||
|
from tackerclient.osc import utils as tacker_osc_utils
|
||||||
|
from tackerclient.osc.v1.vnflcm import vnflcm_subsc
|
||||||
|
from tackerclient.tests.unit.osc import base
|
||||||
|
from tackerclient.tests.unit.osc.v1 import test_vnflcm
|
||||||
|
from tackerclient.tests.unit.osc.v1 import vnflcm_subsc_fakes
|
||||||
|
|
||||||
|
|
||||||
|
def _get_columns_vnflcm_subsc(action=None):
|
||||||
|
columns = ['ID', 'Filter', 'Callback URI', 'Links']
|
||||||
|
if action == 'list':
|
||||||
|
columns = [ele for ele in columns if ele not in
|
||||||
|
['Filter', 'Links']]
|
||||||
|
return columns
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateLccnSubscription(test_vnflcm.TestVnfLcm):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestCreateLccnSubscription, self).setUp()
|
||||||
|
self.create_subscription = vnflcm_subsc.CreateLccnSubscription(
|
||||||
|
self.app, self.app_args, cmd_name='vnflcm subsc create')
|
||||||
|
|
||||||
|
def test_create_no_args(self):
|
||||||
|
self.assertRaises(base.ParserException, self.check_parser,
|
||||||
|
self.create_subscription, [], [])
|
||||||
|
|
||||||
|
def test_take_action(self):
|
||||||
|
subscription = vnflcm_subsc_fakes.lccn_subsc_response()
|
||||||
|
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
|
||||||
|
"create_lccn_subscription_param_sample.json")
|
||||||
|
|
||||||
|
arglist = [sample_param_file]
|
||||||
|
verifylist = [('create_request_file', sample_param_file)]
|
||||||
|
|
||||||
|
# command param
|
||||||
|
parsed_args = self.check_parser(self.create_subscription,
|
||||||
|
arglist, verifylist)
|
||||||
|
|
||||||
|
self.requests_mock.register_uri(
|
||||||
|
'POST', os.path.join(self.url, 'vnflcm/v1/subscriptions'),
|
||||||
|
json=subscription, headers=self.header)
|
||||||
|
|
||||||
|
actual_columns, data = (self.create_subscription.take_action(
|
||||||
|
parsed_args))
|
||||||
|
|
||||||
|
headers, attributes = vnflcm_subsc._get_columns(subscription)
|
||||||
|
|
||||||
|
self.assertCountEqual(_get_columns_vnflcm_subsc(),
|
||||||
|
actual_columns)
|
||||||
|
self.assertListItemsEqual(vnflcm_subsc_fakes.get_subscription_data(
|
||||||
|
subscription, columns=attributes), data)
|
||||||
|
|
||||||
|
|
||||||
|
class TestListLccnSubscription(test_vnflcm.TestVnfLcm):
|
||||||
|
|
||||||
|
subscriptions = vnflcm_subsc_fakes.create_subscriptions(count=3)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListLccnSubscription, self).setUp()
|
||||||
|
self.list_subscription = vnflcm_subsc.ListLccnSubscription(
|
||||||
|
self.app, self.app_args, cmd_name='vnflcm subsc list')
|
||||||
|
|
||||||
|
def test_take_action(self):
|
||||||
|
parsed_args = self.check_parser(self.list_subscription, [], [])
|
||||||
|
self.requests_mock.register_uri(
|
||||||
|
'GET', os.path.join(self.url, 'vnflcm/v1/subscriptions'),
|
||||||
|
json=self.subscriptions, headers=self.header)
|
||||||
|
actual_columns, data = self.list_subscription.take_action(parsed_args)
|
||||||
|
|
||||||
|
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||||
|
self.list_subscription.get_attributes(), long_listing=True)
|
||||||
|
|
||||||
|
expected_data = []
|
||||||
|
for subscription_obj in self.subscriptions:
|
||||||
|
expected_data.append(vnflcm_subsc_fakes.get_subscription_data(
|
||||||
|
subscription_obj, columns=columns, list_action=True))
|
||||||
|
|
||||||
|
self.assertCountEqual(_get_columns_vnflcm_subsc(action='list'),
|
||||||
|
actual_columns)
|
||||||
|
self.assertCountEqual(expected_data, list(data))
|
||||||
|
|
||||||
|
|
||||||
|
class TestShowLccnSubscription(test_vnflcm.TestVnfLcm):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestShowLccnSubscription, self).setUp()
|
||||||
|
self.show_subscription = vnflcm_subsc.ShowLccnSubscription(
|
||||||
|
self.app, self.app_args, cmd_name='vnflcm subsc show')
|
||||||
|
|
||||||
|
def test_take_action(self):
|
||||||
|
subscription = vnflcm_subsc_fakes.lccn_subsc_response()
|
||||||
|
|
||||||
|
arglist = [subscription['id']]
|
||||||
|
verifylist = [('subscription_id', subscription['id'])]
|
||||||
|
|
||||||
|
# command param
|
||||||
|
parsed_args = self.check_parser(self.show_subscription, arglist,
|
||||||
|
verifylist)
|
||||||
|
|
||||||
|
self.requests_mock.register_uri(
|
||||||
|
'GET', os.path.join(self.url, 'vnflcm/v1/subscriptions',
|
||||||
|
subscription['id']),
|
||||||
|
json=subscription, headers=self.header)
|
||||||
|
|
||||||
|
columns, data = (self.show_subscription.take_action(parsed_args))
|
||||||
|
self.assertCountEqual(_get_columns_vnflcm_subsc(),
|
||||||
|
columns)
|
||||||
|
headers, attributes = vnflcm_subsc._get_columns(subscription)
|
||||||
|
self.assertListItemsEqual(
|
||||||
|
vnflcm_subsc_fakes.get_subscription_data(subscription,
|
||||||
|
columns=attributes),
|
||||||
|
data)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDeleteLccnSubscription(test_vnflcm.TestVnfLcm):
|
||||||
|
|
||||||
|
subscriptions = vnflcm_subsc_fakes.create_subscriptions(count=3)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDeleteLccnSubscription, self).setUp()
|
||||||
|
self.delete_subscription = vnflcm_subsc.DeleteLccnSubscription(
|
||||||
|
self.app, self.app_args, cmd_name='vnflcm subsc delete')
|
||||||
|
|
||||||
|
def _mock_request_url_for_delete(self, subsc_index):
|
||||||
|
url = os.path.join(self.url, 'vnflcm/v1/subscriptions',
|
||||||
|
self.subscriptions[subsc_index]['id'])
|
||||||
|
|
||||||
|
json = self.subscriptions[subsc_index]
|
||||||
|
|
||||||
|
self.requests_mock.register_uri('GET', url, json=json,
|
||||||
|
headers=self.header)
|
||||||
|
self.requests_mock.register_uri('DELETE', url,
|
||||||
|
headers=self.header, json={})
|
||||||
|
|
||||||
|
def test_delete_one_subscription(self):
|
||||||
|
arglist = [self.subscriptions[0]['id']]
|
||||||
|
verifylist = [('subscription_id',
|
||||||
|
[self.subscriptions[0]['id']])]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.delete_subscription,
|
||||||
|
arglist, verifylist)
|
||||||
|
|
||||||
|
self._mock_request_url_for_delete(0)
|
||||||
|
sys.stdout = buffer = StringIO()
|
||||||
|
result = self.delete_subscription.take_action(parsed_args)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
self.assertEqual(("Lccn Subscription '%s' is deleted successfully")
|
||||||
|
% self.subscriptions[0]['id'],
|
||||||
|
buffer.getvalue().strip())
|
||||||
|
|
||||||
|
def test_delete_multiple_subscription(self):
|
||||||
|
arglist = []
|
||||||
|
for subscription in self.subscriptions:
|
||||||
|
arglist.append(subscription['id'])
|
||||||
|
verifylist = [('subscription_id', arglist)]
|
||||||
|
parsed_args = self.check_parser(self.delete_subscription,
|
||||||
|
arglist, verifylist)
|
||||||
|
for i in range(0, 3):
|
||||||
|
self._mock_request_url_for_delete(i)
|
||||||
|
sys.stdout = buffer = StringIO()
|
||||||
|
result = self.delete_subscription.take_action(parsed_args)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
self.assertEqual('All specified Lccn Subscriptions are deleted '
|
||||||
|
'successfully', buffer.getvalue().strip())
|
||||||
|
|
||||||
|
def test_delete_multiple_subscription_exception(self):
|
||||||
|
arglist = [
|
||||||
|
self.subscriptions[0]['id'],
|
||||||
|
'xxxx-yyyy-zzzz',
|
||||||
|
self.subscriptions[1]['id'],
|
||||||
|
]
|
||||||
|
verifylist = [('subscription_id', arglist)]
|
||||||
|
parsed_args = self.check_parser(self.delete_subscription,
|
||||||
|
arglist, verifylist)
|
||||||
|
|
||||||
|
self._mock_request_url_for_delete(0)
|
||||||
|
|
||||||
|
url = os.path.join(self.url, 'vnflcm/v1/subscriptions',
|
||||||
|
'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_subscription.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
self.assertEqual('Failed to delete 1 of 3 Lccn Subscriptions.',
|
||||||
|
exception.message)
|
190
tackerclient/tests/unit/osc/v1/vnflcm_subsc_fakes.py
Normal file
190
tackerclient/tests/unit/osc/v1/vnflcm_subsc_fakes.py
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# 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.fixture import uuidsentinel
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
from tackerclient.osc import utils as tacker_osc_utils
|
||||||
|
|
||||||
|
|
||||||
|
def lccn_subsc_response(attrs=None):
|
||||||
|
"""Create a fake subscription.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:return:
|
||||||
|
A subscription dict
|
||||||
|
"""
|
||||||
|
attrs = attrs or {}
|
||||||
|
id = uuidsentinel.lccn_subsc_id
|
||||||
|
|
||||||
|
# Set default attributes.
|
||||||
|
dummy_subscription = {
|
||||||
|
"id": id,
|
||||||
|
"filter": {
|
||||||
|
"vnfInstanceSubscriptionFilter": {
|
||||||
|
"vnfdIds": [
|
||||||
|
"dummy-vnfdId-1",
|
||||||
|
"dummy-vnfdId-2"
|
||||||
|
],
|
||||||
|
"vnfProductsFromProviders": [
|
||||||
|
{
|
||||||
|
"vnfProvider": "dummy-vnfProvider-1",
|
||||||
|
"vnfProducts": [
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-1-1",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-1-2",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProvider": "dummy-vnfProvider-2",
|
||||||
|
"vnfProducts": [
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-2-1",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfProductName": "dummy-vnfProductName-2-2",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.0",
|
||||||
|
"vnfdVersions": ["1.0", "2.0"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vnfSoftwareVersion": "1.1",
|
||||||
|
"vnfdVersions": ["1.1", "2.1"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vnfInstanceIds": [
|
||||||
|
"dummy-vnfInstanceId-1",
|
||||||
|
"dummy-vnfInstanceId-2"
|
||||||
|
],
|
||||||
|
"vnfInstanceNames": [
|
||||||
|
"dummy-vnfInstanceName-1",
|
||||||
|
"dummy-vnfInstanceName-2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notificationTypes": [
|
||||||
|
"VnfLcmOperationOccurrenceNotification",
|
||||||
|
"VnfIdentifierCreationNotification",
|
||||||
|
"VnfIdentifierDeletionNotification"
|
||||||
|
],
|
||||||
|
"operationTypes": [
|
||||||
|
"INSTANTIATE",
|
||||||
|
"SCALE",
|
||||||
|
"TERMINATE",
|
||||||
|
"HEAL",
|
||||||
|
"MODIFY_INFO",
|
||||||
|
"CHANGE_EXT_CONN"
|
||||||
|
],
|
||||||
|
"operationStates": [
|
||||||
|
"COMPLETED",
|
||||||
|
"FAILED",
|
||||||
|
"FAILED_TEMP",
|
||||||
|
"PROCESSING",
|
||||||
|
"ROLLING_BACK",
|
||||||
|
"ROLLED_BACK",
|
||||||
|
"STARTING"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"callbackUri": "http://localhost:9990/notification/callback/test",
|
||||||
|
"_links": {
|
||||||
|
"self": {
|
||||||
|
"href": "http://127.0.0.1:9890/vnflcm/v2/subscriptions/" + id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes.
|
||||||
|
dummy_subscription.update(attrs)
|
||||||
|
|
||||||
|
return dummy_subscription
|
||||||
|
|
||||||
|
|
||||||
|
def get_subscription_data(subscription, list_action=False, columns=None):
|
||||||
|
"""Get the subscription data.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
A tuple object sorted based on the name of the columns.
|
||||||
|
"""
|
||||||
|
complex_attributes = ['filter', '_links']
|
||||||
|
for attribute in complex_attributes:
|
||||||
|
if subscription.get(attribute):
|
||||||
|
subscription.update(
|
||||||
|
{attribute: tacker_osc_utils.FormatComplexDataColumn(
|
||||||
|
subscription[attribute])})
|
||||||
|
|
||||||
|
if list_action:
|
||||||
|
for item in ['filter', '_links']:
|
||||||
|
subscription.pop(item)
|
||||||
|
|
||||||
|
# return the list of data as per column order
|
||||||
|
if columns:
|
||||||
|
return tuple([subscription[key] for key in columns])
|
||||||
|
|
||||||
|
return tuple([subscription[key] for key in sorted(
|
||||||
|
subscription.keys())])
|
||||||
|
|
||||||
|
|
||||||
|
def create_subscriptions(count=2):
|
||||||
|
"""Create multiple fake subscriptions.
|
||||||
|
|
||||||
|
:param count: The number of subscriptions to fake
|
||||||
|
:return:
|
||||||
|
A list of fake subscriptions dictionary
|
||||||
|
"""
|
||||||
|
uri = "http://localhost:9990/notification/callback/"
|
||||||
|
subscriptions = []
|
||||||
|
for i in range(0, count):
|
||||||
|
unique_id = uuidutils.generate_uuid()
|
||||||
|
subscriptions.append(lccn_subsc_response(
|
||||||
|
attrs={'id': unique_id,
|
||||||
|
'callbackUri': uri + str(i)}))
|
||||||
|
return subscriptions
|
@@ -895,6 +895,10 @@ class VnfLCMClient(ClientBase):
|
|||||||
'/vnflcm/{}/vnf_lcm_op_occs'.format(sol_api_version))
|
'/vnflcm/{}/vnf_lcm_op_occs'.format(sol_api_version))
|
||||||
self.vnf_lcm_op_occs_path = (
|
self.vnf_lcm_op_occs_path = (
|
||||||
'/vnflcm/{}/vnf_lcm_op_occs/%s'.format(sol_api_version))
|
'/vnflcm/{}/vnf_lcm_op_occs/%s'.format(sol_api_version))
|
||||||
|
self.lccn_subscriptions_path = (
|
||||||
|
'/vnflcm/{}/subscriptions'.format(sol_api_version))
|
||||||
|
self.lccn_subscription_path = (
|
||||||
|
'/vnflcm/{}/subscriptions/%s'.format(sol_api_version))
|
||||||
|
|
||||||
def build_action(self, action):
|
def build_action(self, action):
|
||||||
return action
|
return action
|
||||||
@@ -992,6 +996,28 @@ class VnfLCMClient(ClientBase):
|
|||||||
return self.get(self.vnf_lcm_op_occs_path % occ_id,
|
return self.get(self.vnf_lcm_op_occs_path % occ_id,
|
||||||
headers=self.headers)
|
headers=self.headers)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_lccn_subscription(self, body):
|
||||||
|
return self.post(self.lccn_subscriptions_path, body=body,
|
||||||
|
headers=self.headers)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_lccn_subscription(self, subsc_id):
|
||||||
|
return self.delete(self.lccn_subscription_path % subsc_id,
|
||||||
|
headers=self.headers)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_lccn_subscriptions(self, retrieve_all=True, **_params):
|
||||||
|
subscriptions = self.list(None, self.lccn_subscriptions_path,
|
||||||
|
retrieve_all, headers=self.headers,
|
||||||
|
**_params)
|
||||||
|
return subscriptions
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_lccn_subscription(self, subsc_id):
|
||||||
|
return self.get(self.lccn_subscription_path % subsc_id,
|
||||||
|
headers=self.headers)
|
||||||
|
|
||||||
@APIParamsCall
|
@APIParamsCall
|
||||||
def show_vnf_lcm_versions(self, major_version):
|
def show_vnf_lcm_versions(self, major_version):
|
||||||
if major_version is None:
|
if major_version is None:
|
||||||
@@ -1324,5 +1350,18 @@ class Client(object):
|
|||||||
def show_vnf_lcm_op_occs(self, occ_id):
|
def show_vnf_lcm_op_occs(self, occ_id):
|
||||||
return self.vnf_lcm_client.show_vnf_lcm_op_occs(occ_id)
|
return self.vnf_lcm_client.show_vnf_lcm_op_occs(occ_id)
|
||||||
|
|
||||||
|
def create_lccn_subscription(self, body):
|
||||||
|
return self.vnf_lcm_client.create_lccn_subscription(body)
|
||||||
|
|
||||||
|
def delete_lccn_subscription(self, subsc_id):
|
||||||
|
return self.vnf_lcm_client.delete_lccn_subscription(subsc_id)
|
||||||
|
|
||||||
|
def list_lccn_subscriptions(self, retrieve_all=True, **_params):
|
||||||
|
return self.vnf_lcm_client.list_lccn_subscriptions(
|
||||||
|
retrieve_all=retrieve_all, **_params)
|
||||||
|
|
||||||
|
def show_lccn_subscription(self, subsc_id):
|
||||||
|
return self.vnf_lcm_client.show_lccn_subscription(subsc_id)
|
||||||
|
|
||||||
def show_vnf_lcm_versions(self, major_version):
|
def show_vnf_lcm_versions(self, major_version):
|
||||||
return self.vnf_lcm_client.show_vnf_lcm_versions(major_version)
|
return self.vnf_lcm_client.show_vnf_lcm_versions(major_version)
|
||||||
|
Reference in New Issue
Block a user