Merge "Improve Unit Test for V2 API"

This commit is contained in:
Zuul 2022-09-11 03:30:49 +00:00 committed by Gerrit Code Review
commit dbca617b98
21 changed files with 6410 additions and 709 deletions

View File

@ -171,7 +171,7 @@ def match_inst_subsc_filter(inst_filter, inst):
return False
if inst_filter.obj_attr_is_set('vnfInstanceNames'):
if inst.vnfInstanceNames not in inst_filter.vnfInstanceNames:
if inst.vnfInstanceName not in inst_filter.vnfInstanceNames:
return False
return True

View File

@ -77,7 +77,10 @@ class Vnfd(object):
def delete(self):
if self.csar_dir_is_tmp:
shutil.rmtree(self.csar_dir)
try:
shutil.rmtree(self.csar_dir)
except Exception:
LOG.exception("rmtree %s failed", self.csar_dir)
def get_vnfd_flavour(self, flavour_id):
if flavour_id in self.vnfd_flavours:
@ -336,6 +339,8 @@ class Vnfd(object):
def get_interface_script(self, flavour_id, operation):
vnfd = self.get_vnfd_flavour(flavour_id)
if not vnfd:
return
nodes = (vnfd.get('topology_template', {})
.get('node_templates', {}))
for node in nodes.values():

View File

@ -39,7 +39,9 @@ class TestCommontScriptUtils(base.BaseTestCase):
expected_result = {
'VDU': {
'VDU1': {'computeFlavourId': None},
'VDU1': {'computeFlavourId': None,
'desired_capacity': None,
'locationConstraints': None},
'VirtualStorage': {'vcImageId': None},
'VDU2': {'computeFlavourId': None, 'vcImageId': None}
},
@ -56,6 +58,9 @@ class TestCommontScriptUtils(base.BaseTestCase):
}
result = common_script_utils.init_nfv_dict(top_hot)
self.assertEqual(expected_result, result)
self.assertIsNone(result['CP'].get('VDU1_CP6'))
self.assertIsNone(result['CP'].get('VDU1_CP7'))
self.assertIsNone(result['CP'].get('VDU1_CP8'))
def test_get_param_flavor(self):
flavor = 'm1.large'
@ -79,6 +84,24 @@ class TestCommontScriptUtils(base.BaseTestCase):
self.vnfd_1, grant)
self.assertEqual('m1.tiny', result)
def test_get_param_flavor_no_compute_resource_flavours(self):
grant = {
'vimAssets': {
}
}
# if not exist in grant, get from VNFD
result = common_script_utils.get_param_flavor(
'VDU1', SAMPLE_FLAVOUR_ID,
self.vnfd_1, grant)
self.assertEqual('m1.tiny', result)
# if not exist in grant, get from VNFD
result = common_script_utils.get_param_flavor(
'VDU2', SAMPLE_FLAVOUR_ID,
self.vnfd_1, grant)
self.assertEqual('m1.tiny', result)
def test_get_param_image(self):
image_id = 'f30e149d-b3c7-497a-8b19-a092bc81e47b'
grant = {
@ -96,6 +119,33 @@ class TestCommontScriptUtils(base.BaseTestCase):
self.vnfd_1, grant)
self.assertEqual(image_id, result)
def test_get_param_image_no_software_images(self):
grant = {
'vimAssets': {
}
}
result = common_script_utils.get_param_image('VDU2', SAMPLE_FLAVOUR_ID,
self.vnfd_1, grant)
self.assertEqual('VDU2-image', result)
def test_get_param_image_no_match_image(self):
image_id = 'f30e149d-b3c7-497a-8b19-a092bc81e47b'
grant = {
'vimAssets': {
'softwareImages': [
{'vnfdSoftwareImageId': 'VDU3',
'vimSoftwareImageId': image_id},
{'vnfdSoftwareImageId': 'VirtualStorage',
'vimSoftwareImageId': 'image-1.0.0-x86_64-disk'}
]
}
}
result = common_script_utils.get_param_image('VDU2', SAMPLE_FLAVOUR_ID,
self.vnfd_1, grant)
self.assertEqual('VDU2-image', result)
def test_get_param_zone(self):
grant_req = {
'addResources': [
@ -118,6 +168,75 @@ class TestCommontScriptUtils(base.BaseTestCase):
result = common_script_utils.get_param_zone('VDU1', grant_req, grant)
self.assertEqual('nova', result)
def test_get_param_zone_no_zones(self):
grant_req = {
'addResources': [
{'id': 'dd60c89a-29a2-43bc-8cff-a534515523df',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU1'}
]
}
grant = {
'addResources': [
{'resourceDefinitionId':
'dd60c89a-29a2-43bc-8cff-a534515523df',
'zoneId': '717f6ae9-3094-46b6-b070-89ede8337571'}
]
}
common_script_utils.get_param_zone('VDU1', grant_req, grant)
def test_get_param_zone_no_add_resources(self):
grant_req = {
'addResources': [
{'id': 'dd60c89a-29a2-43bc-8cff-a534515523df',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU1'}
]
}
grant = {
'zones': [
{'id': '717f6ae9-3094-46b6-b070-89ede8337571',
'zoneId': 'nova'}
]
}
common_script_utils.get_param_zone('VDU1', grant_req, grant)
def test_get_param_zone_no_zone_id(self):
grant_req = {
'addResources': [
{'id': 'dd60c89a-29a2-43bc-8cff-a534515523df',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU1'},
{'id': 'e3ac628c-29a4-2878-b4a2-29aa685dcd70',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU1'},
{'id': '36628ed5-6821-6f55-8c99-cbab0890fc71',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU2'},
{'id': 'eed6860c-e9b2-ef79-5deb-89dee39785ec',
'type': 'COMPUTE', 'resourceTemplateId': 'VDU3'},
]
}
grant = {
'zones': [
{'id': '717f6ae9-3094-46b6-b070-89ede8337571',
'zoneId': 'nova'}
],
'addResources': [
{'resourceDefinitionId': 'eed6860c-e9b2-'
'ef79-5deb-89dee39785ec'},
{'resourceDefinitionId': 'e3ac628c-29a4-'
'2878-b4a2-29aa685dcd70',
'zoneId': '99171a93-d0b2-d2cd-83c1-b0694a3f771b'},
{'resourceDefinitionId': '36628ed5-6821-'
'6f55-8c99-cbab0890fc71',
'zoneId': '717f6ae9-3094-46b6-b070-89ede8337571'},
{'resourceDefinitionId': 'dd60c89a-29a2-'
'43bc-8cff-a534515523df',
'zoneId': '717f6ae9-3094-46b6-b070-89ede8337571'}
]
}
result = common_script_utils.get_param_zone('VDU1', grant_req, grant)
self.assertEqual('nova', result)
def test_get_param_capacity(self):
# test get_current_capacity at the same time
grant_req = {
@ -214,6 +333,81 @@ class TestCommontScriptUtils(base.BaseTestCase):
result = common_script_utils.get_param_fixed_ips('VDU2_CP2', {}, req)
self.assertEqual(expected_result, result)
def test_get_param_fixed_ips_other_cases(self):
ip_address = "10.10.1.101"
subnet_id = "9defebca-3e9c-4bd2-9fa0-c4210c56ece6"
ext_cp = {
"cpdId": "VDU2_CP2",
"cpConfig": {
"VDU2_CP2_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"fixedAddresses": [
ip_address
],
"subnetId": subnet_id
}
]
}
}
]
},
"VDU2_CP2_2": {
},
"VDU2_CP2_3": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET"
}
]
},
"VDU2_CP2_4": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {}
}
]
},
"VDU2_CP2_5": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4"
}
]
}
}
]
},
}
}
req = {
"extVirtualLinks": [
{
"id": "8b49f4b6-1ff9-4a03-99cf-ff445b788436",
"resourceId": "4c54f742-5f1d-4287-bb81-37bf2e6ddc3e",
"extCps": [ext_cp]
}
]
}
expected_result = [{'ip_address': ip_address, 'subnet': subnet_id}]
# no vls
common_script_utils.get_param_fixed_ips('VDU2_CP2', {}, {})
# with other cases
result = common_script_utils.get_param_fixed_ips('VDU2_CP2', {}, req)
self.assertEqual(expected_result, result)
def _inst_example_get_network_fixed_ips_from_inst(self):
ext_cp = {
"cpdId": "VDU2_CP2",

View File

@ -12,8 +12,10 @@
# 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 unittest import mock
from tacker import context
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import lcm_op_occ_utils as lcmocc_utils
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import fields
@ -2108,6 +2110,31 @@ _expected_resource_changes_change_vnfpkg = {
]
}
# lcmocc_info_example
_error = {
'status': 1,
'detail': 'error'
}
_lcmocc_modify_value = {
'id': 'test-1',
'vnfInstanceId': 'instance-1',
'operation': 'MODIFY_INFO',
'operationState': 'PROCESSING',
'isAutomaticInvocation': False,
'startTime': '2021-01-22 13:41:03+00:00'
}
_lcmocc_inst_value = {
'id': 'test-2',
'vnfInstanceId': 'instance-2',
'operation': 'INSTANTIATE',
'operationState': 'COMPLETED',
'isAutomaticInvocation': False,
'startTime': '2021-01-23 13:41:03+00:00',
'resourceChanges': _expected_resource_changes_instantiate,
'changedInfo': _expected_changedInfo
}
class TestLcmOpOccUtils(base.BaseTestCase):
@ -2312,3 +2339,149 @@ class TestLcmOpOccUtils(base.BaseTestCase):
self.assertEqual(
_expected_resource_changes_change_vnfpkg,
self._sort_resource_changes(lcmocc['resourceChanges']))
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_lcmocc(self, mock_lcmocc):
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
operation='INSTANTIATE')
expected_result = objects.VnfLcmOpOccV2(
operation='INSTANTIATE')
result = lcmocc_utils.get_lcmocc(context, 'lcmocc_id')
self.assertEqual(expected_result.operation, result.operation)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_lcmocc_error(self, mock_lcmocc):
mock_lcmocc.return_value = None
self.assertRaises(
sol_ex.VnfLcmOpOccNotFound,
lcmocc_utils.get_lcmocc, context, 'lcmocc_id')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_lcmocc_all(self, mock_lcmocc):
mock_lcmocc.return_value = [objects.VnfLcmOpOccV2(
operation='INSTANTIATE')]
expected_result = [objects.VnfLcmOpOccV2(
operation='INSTANTIATE')]
result = lcmocc_utils.get_lcmocc_all(context)
self.assertEqual(expected_result[0].operation, result[0].operation)
def test_make_lcmocc_links(self):
lcmocc = objects.VnfLcmOpOccV2(
id='test-1', vnfInstanceId='instance-1', operation='INSTANTIATE')
endpoint = 'http://127.0.0.1:9890'
expected_result = objects.VnfLcmOpOccV2_Links()
expected_result.self = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}')
expected_result.vnfInstance = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_instances/{lcmocc.vnfInstanceId}')
expected_result.retry = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/retry')
expected_result.rollback = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/rollback')
expected_result.fail = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/fail')
result = lcmocc_utils.make_lcmocc_links(lcmocc, endpoint)
self.assertEqual(expected_result.self.href, result.self.href)
self.assertEqual(expected_result.vnfInstance.href,
result.vnfInstance.href)
self.assertEqual(expected_result.retry.href, result.retry.href)
self.assertEqual(expected_result.rollback.href, result.rollback.href)
self.assertEqual(expected_result.fail.href, result.fail.href)
def test_make_lcmocc_notif_data(self):
subsc_modify = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT')
subsc_inst = objects.LccnSubscriptionV2(
id='sub-1', verbosity='FULL')
lcmocc_modify = objects.VnfLcmOpOccV2.from_dict(_lcmocc_modify_value)
lcmocc_modify.error = objects.ProblemDetails.from_dict(_error)
lcmocc_inst = objects.VnfLcmOpOccV2.from_dict(_lcmocc_inst_value)
endpoint = 'http://127.0.0.1:9890'
# execute modify lcmocc
modify_result = lcmocc_utils.make_lcmocc_notif_data(
subsc_modify, lcmocc_modify, endpoint)
# execute inst lcmocc
inst_result = lcmocc_utils.make_lcmocc_notif_data(
subsc_inst, lcmocc_inst, endpoint)
self.assertEqual('START', modify_result.notificationStatus)
self.assertEqual('error', modify_result.error.detail)
self.assertIsNotNone(inst_result.affectedVnfcs)
self.assertIsNotNone(inst_result.changedInfo)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_filter')
def test_get_inst_lcmocc(self, mock_value):
inst = objects.VnfInstanceV2(id='test-instance')
value_1 = {
'id': 'test-1',
'vnfInstanceId': 'instance-1',
'operation': 'INSTANTIATE',
'operationState': 'COMPLETED',
'startTime': '2021-01-22 13:41:03+00:00'
}
value_2 = {
'id': 'test-2',
'vnfInstanceId': 'instance-2',
'operation': 'INSTANTIATE',
'operationState': 'COMPLETED',
'startTime': '2021-01-23 13:41:03+00:00'
}
mock_value.return_value = [
objects.VnfLcmOpOccV2.from_dict(value_1),
objects.VnfLcmOpOccV2.from_dict(value_2)
]
expected_result = objects.VnfLcmOpOccV2.from_dict(value_2)
result = lcmocc_utils.get_inst_lcmocc(context, inst)
self.assertEqual(expected_result.id, result.id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_filter')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_grant_req_and_grant(self, mock_grant, mock_grant_reqs):
lcmocc_modify = objects.VnfLcmOpOccV2.from_dict(_lcmocc_modify_value)
lcmocc_inst = objects.VnfLcmOpOccV2.from_dict(_lcmocc_inst_value)
# execute modify lcmocc
modify_grant_req, modify_grant = lcmocc_utils.get_grant_req_and_grant(
context, lcmocc_modify)
self.assertIsNone(modify_grant_req)
self.assertIsNone(modify_grant)
# execute inst lcmocc
lcmocc_inst.grantId = 'grant-1'
mock_grant_reqs.return_value = [objects.GrantRequestV1(
vnfInstanceId='inst-1', vnfLcmOpOccId='lcmocc-1',
vnfdId='vnfd-1', operation='INSTANTIATE',
isAutomaticInvocation=False)]
mock_grant.return_value = objects.GrantV1(
id='grant-1', vnfInstanceId='inst-1', vnfLcmOpOccId='lcmocc-1')
inst_grant_req, inst_grant = lcmocc_utils.get_grant_req_and_grant(
context, lcmocc_inst)
self.assertEqual('inst-1', inst_grant_req.vnfInstanceId)
self.assertEqual('grant-1', inst_grant.id)
@mock.patch.object(objects.base.TackerPersistentObject,
'get_by_filter')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_grant_req_and_grant_error(self, mock_grant_reqs, mock_grant):
lcmocc_modify = objects.VnfLcmOpOccV2.from_dict(_lcmocc_modify_value)
lcmocc_inst = objects.VnfLcmOpOccV2.from_dict(_lcmocc_inst_value)
# execute modify lcmocc
modify_grant_req, modify_grant = lcmocc_utils.get_grant_req_and_grant(
context, lcmocc_modify)
self.assertIsNone(modify_grant_req)
self.assertIsNone(modify_grant)
# execute inst lcmocc
lcmocc_inst.grantId = 'grant-1'
mock_grant_reqs.return_value = None
mock_grant.return_value = objects.GrantV1(
id='grant-1', vnfInstanceId='inst-1', vnfLcmOpOccId='lcmocc-1')
self.assertRaises(
sol_ex.GrantRequestOrGrantNotFound,
lcmocc_utils.get_grant_req_and_grant, context, lcmocc_inst)

View File

@ -0,0 +1,383 @@
# Copyright (C) 2022 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 requests
from unittest import mock
from oslo_utils import uuidutils
from tacker import context
from tacker.sol_refactored.api import api_version
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import http_client
from tacker.sol_refactored.common import subscription_utils as subsc_utils
from tacker.sol_refactored import objects
from tacker.tests import base
class TestSubscriptionUtils(base.BaseTestCase):
def setUp(self):
super(TestSubscriptionUtils, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
self.context.api_version = api_version.APIVersion('2.0.0')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_subsc(self, mock_subsc):
mock_subsc.return_value = objects.LccnSubscriptionV2(id='subsc-1')
result = subsc_utils.get_subsc(context, 'subsc-1')
self.assertEqual('subsc-1', result.id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_subsc_error(self, mock_subsc):
mock_subsc.return_value = None
self.assertRaises(
sol_ex.LccnSubscriptionNotFound,
subsc_utils.get_subsc, context, 'subsc-1')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_subsc_all(self, mock_subsc):
mock_subsc.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
result = subsc_utils.get_subsc_all(context)
self.assertEqual('subsc-1', result[0].id)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_send_notification(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
notif_data_no_auth = objects.VnfLcmOperationOccurrenceNotificationV2(
id=uuidutils.generate_uuid()
)
resp_no_auth = requests.Response()
resp_no_auth.status_code = 204
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
subsc_utils.send_notification(subsc_no_auth, notif_data_no_auth)
subsc_basic_auth = objects.LccnSubscriptionV2(
id='sub-2', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback',
authentication=objects.SubscriptionAuthentication(
paramsBasic=objects.SubscriptionAuthentication_ParamsBasic(
userName='test', password='test')))
# execute basic_auth
subsc_utils.send_notification(subsc_basic_auth, notif_data_no_auth)
subsc_oauth2 = objects.LccnSubscriptionV2(
id='sub-3', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback',
authentication=objects.SubscriptionAuthentication(
paramsOauth2ClientCredentials=(
objects.SubscriptionAuthentication_ParamsOauth2(
clientId='test', clientPassword='test',
tokenEndpoint='http://127.0.0.1/token'))))
# execute oauth2
subsc_utils.send_notification(subsc_oauth2, notif_data_no_auth)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_send_notification_error_code(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
notif_data_no_auth = objects.VnfLcmOperationOccurrenceNotificationV2(
id=uuidutils.generate_uuid()
)
resp_no_auth = requests.Response()
resp_no_auth.status_code = 200
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
subsc_utils.send_notification(subsc_no_auth, notif_data_no_auth)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_send_notification_error(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
notif_data_no_auth = objects.VnfLcmOperationOccurrenceNotificationV2(
id=uuidutils.generate_uuid()
)
resp_no_auth = Exception()
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
subsc_utils.send_notification(subsc_no_auth, notif_data_no_auth)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_test_notification(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
resp_no_auth = requests.Response()
resp_no_auth.status_code = 204
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
subsc_utils.test_notification(subsc_no_auth)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_test_notification_error_code(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
resp_no_auth = requests.Response()
resp_no_auth.status_code = 200
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
self.assertRaises(sol_ex.TestNotificationFailed,
subsc_utils.test_notification, subsc_no_auth)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_test_notification_error(self, mock_resp):
subsc_no_auth = objects.LccnSubscriptionV2(
id='sub-1', verbosity='SHORT',
callbackUri='http://127.0.0.1/callback')
resp_no_auth = Exception()
mock_resp.return_value = (resp_no_auth, None)
# execute no_auth
self.assertRaises(sol_ex.TestNotificationFailed,
subsc_utils.test_notification, subsc_no_auth)
def test_match_version(self):
inst = objects.VnfInstanceV2(
id='test-instance', vnfSoftwareVersion='1.1.1', vnfdVersion='1.2')
version_mismatch = (
objects._VnfProductsFromProviders_VnfProducts_Versions(
vnfSoftwareVersion='1.1.2'))
result_1 = subsc_utils.match_version(version_mismatch, inst)
self.assertEqual(False, result_1)
version_match = (
objects._VnfProductsFromProviders_VnfProducts_Versions(
vnfSoftwareVersion='1.1.1'))
result_2 = subsc_utils.match_version(version_match, inst)
self.assertEqual(True, result_2)
version_vnfd = (
objects._VnfProductsFromProviders_VnfProducts_Versions(
vnfSoftwareVersion='1.1.1', vnfdVersions=['1.2']))
result_3 = subsc_utils.match_version(version_vnfd, inst)
self.assertEqual(True, result_3)
def test_match_products_per_provider(self):
inst = objects.VnfInstanceV2(
id='test-instance', vnfProvider='company',
vnfSoftwareVersion='1.1.1', vnfdVersion='1.2',
vnfProductName='test')
products_mismatch = objects._VnfProductsFromProviders(
vnfProvider='test')
result_1 = subsc_utils.match_products_per_provider(
products_mismatch, inst)
self.assertEqual(False, result_1)
products_vnfproducts_no_exist = objects._VnfProductsFromProviders(
vnfProvider='company')
result_2 = subsc_utils.match_products_per_provider(
products_vnfproducts_no_exist, inst)
self.assertEqual(True, result_2)
products_vnf_mismatch = objects._VnfProductsFromProviders(
vnfProvider='company', vnfProducts=[
objects._VnfProductsFromProviders_VnfProducts(
vnfProductName='error'),
objects._VnfProductsFromProviders_VnfProducts(
vnfProductName='test', versions=[
objects._VnfProductsFromProviders_VnfProducts_Versions(
vnfSoftwareVersion='1.1.2'
)])
])
result_3 = subsc_utils.match_products_per_provider(
products_vnf_mismatch, inst)
self.assertEqual(False, result_3)
products_vnf_match_with_no_versions = (
objects._VnfProductsFromProviders(
vnfProvider='company', vnfProducts=[
objects._VnfProductsFromProviders_VnfProducts(
vnfProductName='test')]))
result_4 = subsc_utils.match_products_per_provider(
products_vnf_match_with_no_versions, inst)
self.assertEqual(True, result_4)
products_vnf_match_with_versions = objects._VnfProductsFromProviders(
vnfProvider='company', vnfProducts=[
objects._VnfProductsFromProviders_VnfProducts(
vnfProductName='test', versions=[
objects._VnfProductsFromProviders_VnfProducts_Versions(
vnfSoftwareVersion='1.1.1'
)])
])
result_5 = subsc_utils.match_products_per_provider(
products_vnf_match_with_versions, inst)
self.assertEqual(True, result_5)
def test_match_inst_subsc_filter(self):
inst = objects.VnfInstanceV2(
id='test-instance', vnfProvider='company',
vnfSoftwareVersion='1.1.1', vnfdVersion='1.2',
vnfProductName='test', vnfdId='vnfdid-1',
vnfInstanceName='test')
inst_filter_mismatch_vnfdid = objects.VnfInstanceSubscriptionFilter(
vnfdIds=['error'])
result_1 = subsc_utils.match_inst_subsc_filter(
inst_filter_mismatch_vnfdid, inst)
self.assertEqual(False, result_1)
products_vnfproducts_no_exist = objects._VnfProductsFromProviders(
vnfProvider='company')
inst_filter_match_products = objects.VnfInstanceSubscriptionFilter(
vnfProductsFromProviders=[products_vnfproducts_no_exist])
result_2 = subsc_utils.match_inst_subsc_filter(
inst_filter_match_products, inst)
self.assertEqual(True, result_2)
products_mismatch = objects._VnfProductsFromProviders(
vnfProvider='test')
inst_filter_mismatch_products = objects.VnfInstanceSubscriptionFilter(
vnfProductsFromProviders=[products_mismatch])
result_3 = subsc_utils.match_inst_subsc_filter(
inst_filter_mismatch_products, inst)
self.assertEqual(False, result_3)
inst_filter_mismatch_inst_id = objects.VnfInstanceSubscriptionFilter(
vnfInstanceIds=['instanceid-2'])
result_4 = subsc_utils.match_inst_subsc_filter(
inst_filter_mismatch_inst_id, inst)
self.assertEqual(False, result_4)
inst_filter_mismatch_inst_name = objects.VnfInstanceSubscriptionFilter(
vnfInstanceNames=['instance_name-2'])
result_5 = subsc_utils.match_inst_subsc_filter(
inst_filter_mismatch_inst_name, inst)
self.assertEqual(False, result_5)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_inst_create_subscs(self, mock_subscs):
inst = objects.VnfInstanceV2(id='test-instance')
mock_subscs.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
result = subsc_utils.get_inst_create_subscs(context, inst)
self.assertEqual('subsc-1', result[0].id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_inst_delete_subscs(self, mock_subscs):
inst = objects.VnfInstanceV2(id='test-instance')
mock_subscs.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
result = subsc_utils.get_inst_delete_subscs(context, inst)
self.assertEqual('subsc-1', result[0].id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_lcmocc_subscs(self, mock_subscs):
inst = objects.VnfInstanceV2(id='test-instance')
lcmocc = objects.VnfLcmOpOccV2(operationState='COMPLETED',
operation='INSTANTIATE')
mock_subscs.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
result = subsc_utils.get_lcmocc_subscs(context, lcmocc, inst)
self.assertEqual('subsc-1', result[0].id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_matched_subscs(self, mock_subscs):
inst = objects.VnfInstanceV2(id='test-instance', vnfProvider='company')
notif_type = 'VnfLcmOperationOccurrenceNotification'
op_type = 'INSTANTIATE'
op_status = 'COMPLETED'
subscs_no_fileter = objects.LccnSubscriptionV2(id='subsc-1')
products_vnfproducts_no_exist = objects._VnfProductsFromProviders(
vnfProvider='company')
inst_filter_match_products = objects.VnfInstanceSubscriptionFilter(
vnfProductsFromProviders=[products_vnfproducts_no_exist])
subscs_filter_match = objects.LccnSubscriptionV2(
id='subsc-2',
filter=objects.LifecycleChangeNotificationsFilterV2(
vnfInstanceSubscriptionFilter=inst_filter_match_products))
products_mismatch = objects._VnfProductsFromProviders(
vnfProvider='test')
inst_filter_mismatch_products = objects.VnfInstanceSubscriptionFilter(
vnfProductsFromProviders=[products_mismatch])
subscs_filter_mismatch = objects.LccnSubscriptionV2(
id='subsc-3',
filter=objects.LifecycleChangeNotificationsFilterV2(
vnfInstanceSubscriptionFilter=inst_filter_mismatch_products))
subscs_noti_type_match = objects.LccnSubscriptionV2(
id='subsc-4', filter=objects.LifecycleChangeNotificationsFilterV2(
notificationTypes=['VnfLcmOperationOccurrenceNotification']))
subscs_noti_type_mismatch = objects.LccnSubscriptionV2(
id='subsc-5', filter=objects.LifecycleChangeNotificationsFilterV2(
notificationTypes=['VnfIdentifierCreationNotification']))
subscs_op_type_match = objects.LccnSubscriptionV2(
id='subsc-6', filter=objects.LifecycleChangeNotificationsFilterV2(
operationTypes=['INSTANTIATE']))
subscs_op_type_mismatch = objects.LccnSubscriptionV2(
id='subsc-7', filter=objects.LifecycleChangeNotificationsFilterV2(
operationTypes=['TERMINATE']))
subscs_op_status_match = objects.LccnSubscriptionV2(
id='subsc-8', filter=objects.LifecycleChangeNotificationsFilterV2(
operationStatus=['COMPLETED']))
subscs_op_status_mismatch = objects.LccnSubscriptionV2(
id='subsc-9', filter=objects.LifecycleChangeNotificationsFilterV2(
operationStatus=['FAILED_TEMP']))
mock_subscs.return_value = [
subscs_no_fileter, subscs_filter_match, subscs_filter_mismatch,
subscs_noti_type_match, subscs_noti_type_mismatch,
subscs_op_type_match, subscs_op_type_mismatch,
subscs_op_status_match, subscs_op_status_mismatch]
result = subsc_utils.get_matched_subscs(
context, inst, notif_type, op_type, op_status)
expected_ids = ['subsc-1', 'subsc-2', 'subsc-4', 'subsc-6', 'subsc-8']
result_ids = [sub.id for sub in result]
self.assertEqual(expected_ids, result_ids)
def test_make_create_inst_notif_data(self):
subsc = objects.LccnSubscriptionV2(id='subsc-1')
inst = objects.VnfInstanceV2(id='test-instance')
endpoint = 'http://127.0.0.1:9890'
result = subsc_utils.make_create_inst_notif_data(subsc, inst, endpoint)
self.assertEqual('subsc-1', result.subscriptionId)
self.assertEqual('test-instance', result.vnfInstanceId)
def test_make_delete_inst_notif_data(self):
subsc = objects.LccnSubscriptionV2(id='subsc-1')
inst = objects.VnfInstanceV2(id='test-instance')
endpoint = 'http://127.0.0.1:9890'
result = subsc_utils.make_delete_inst_notif_data(subsc, inst, endpoint)
self.assertEqual('subsc-1', result.subscriptionId)
self.assertEqual('test-instance', result.vnfInstanceId)

View File

@ -0,0 +1,114 @@
# Copyright (C) 2022 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 unittest import mock
from tacker import context
from tacker.sol_refactored.api import api_version
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vim_utils
from tacker.sol_refactored import objects
from tacker.tests import base
from tacker.vnfm import vim_client
_vim_openstack = {
"placement_attr": {
"regions": ['RegionOne']
},
"vim_auth": {
"username": "nfv_user",
"password": "devstack",
"project_name": "nfv",
"project_domain_name": "Default",
"user_domain_name": "Default",
"auth_url": "http://127.0.0.1/identity"
},
"vim_type": "openstack",
"vim_id": "openstack-1"
}
_vim_kubernetes_bearer_token = {
"placement_attr": {
"regions": ['RegionOne']
},
"vim_auth": {
"username": None,
"password": None,
"bearer_token": "test_token",
"auth_url": "https://127.0.0.1:6443",
"ssl_ca_cert": "test_ssl"
},
"vim_type": "kubernetes",
"vim_id": "kubernetes-1"
}
_vim_kubernetes_user = {
"vim_auth": {
"username": "admin",
"password": "admin",
"auth_url": "https://127.0.0.1:6443"
},
"vim_type": "kubernetes",
"vim_id": "kubernetes-2"
}
class TestVimUtils(base.BaseTestCase):
def setUp(self):
super(TestVimUtils, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
self.context.api_version = api_version.APIVersion('2.0.0')
@mock.patch.object(vim_client.VimClient, 'get_vim')
def test_get_default_vim(self, mock_vim):
mock_vim.return_value = _vim_openstack
result = vim_utils.get_default_vim(context)
self.assertEqual('openstack-1', result.vimId)
@mock.patch.object(vim_client.VimClient, 'get_vim')
def test_get_default_vim_error(self, mock_vim):
mock_vim.return_value = Exception
vim_utils.get_default_vim(context)
@mock.patch.object(vim_client.VimClient, 'get_vim')
def test_get_vim(self, mock_vim):
mock_vim.return_value = _vim_kubernetes_bearer_token
result = vim_utils.get_vim(context, 'kubernetes-1')
self.assertEqual('kubernetes-1', result.vimId)
@mock.patch.object(vim_client.VimClient, 'get_vim')
def test_get_vim_error(self, mock_vim):
mock_vim.return_value = Exception
self.assertRaises(
sol_ex.VimNotFound, vim_utils.get_vim, context, 'test')
def test_vim_to_conn_info(self):
vim_openstack = _vim_openstack
vim_kubernetes_1 = _vim_kubernetes_bearer_token
vim_kubernetes_2 = _vim_kubernetes_user
result_1 = vim_utils.vim_to_conn_info(vim_openstack)
self.assertEqual('openstack-1', result_1.vimId)
result_2 = vim_utils.vim_to_conn_info(vim_kubernetes_1)
self.assertEqual('kubernetes-1', result_2.vimId)
result_3 = vim_utils.vim_to_conn_info(vim_kubernetes_2)
self.assertEqual('kubernetes-2', result_3.vimId)
self.assertRaises(
sol_ex.SolException, vim_utils.vim_to_conn_info,
{'vim_type': 'test', 'vim_auth': 'test'})

View File

@ -12,23 +12,31 @@
# 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 unittest import mock
from tacker import context
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored import objects
from tacker.tests import base
class TestVnfInstanceUtils(base.BaseTestCase):
def setUp(self):
super(TestVnfInstanceUtils, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
def test_json_merge_patch(self):
# patch is not dict.
target = {"key1", "value1"}
target = {"key1": "value1"}
patch = "text"
result = inst_utils.json_merge_patch(target, patch)
self.assertEqual(patch, result)
# target is not dict.
target = "text"
patch = {"key1", "value1"}
patch = {"key1": "value1"}
result = inst_utils.json_merge_patch(target, patch)
self.assertEqual(patch, result)
@ -65,3 +73,24 @@ class TestVnfInstanceUtils(base.BaseTestCase):
}
result = inst_utils.json_merge_patch(target, patch)
self.assertEqual(expected_result, result)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_inst(self, mock_inst):
mock_inst.return_value = objects.VnfInstanceV2(id='inst-1')
result = inst_utils.get_inst(context, 'inst-1')
self.assertEqual('inst-1', result.id)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id')
def test_get_inst_error(self, mock_inst):
mock_inst.return_value = None
self.assertRaises(
sol_ex.VnfInstanceNotFound,
inst_utils.get_inst, context, 'inst-1')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
def test_get_inst_all(self, mock_inst):
mock_inst.return_value = [objects.VnfInstanceV2(id='inst-1')]
result = inst_utils.get_inst_all(context)
self.assertEqual('inst-1', result[0].id)

View File

@ -12,8 +12,13 @@
# 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 shutil
import tempfile
from oslo_log import log as logging
from oslo_utils import uuidutils
import yaml
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
@ -22,6 +27,7 @@ from tacker.tests import base
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
SAMPLE_FLAVOUR_ID = "simple"
LOG = logging.getLogger()
class TestVnfd(base.BaseTestCase):
@ -179,3 +185,126 @@ class TestVnfd(base.BaseTestCase):
result = self.vnfd_1.get_max_scale_level(SAMPLE_FLAVOUR_ID,
'VDU1_scale')
self.assertEqual(2, result)
def test_init_from_zip_file(self):
vnfd_id = uuidutils.generate_uuid()
tmp_dir = tempfile.mkdtemp()
cur_dir = os.path.dirname(__file__)
sample_path = os.path.join(cur_dir, "../samples/sample1")
shutil.make_archive(tmp_dir, 'zip', root_dir=sample_path)
vnfd = vnfd_utils.Vnfd(vnfd_id)
with open(f'{tmp_dir}.zip', "rb") as f:
content = f.read()
vnfd.init_from_zip_file(content)
with open(f'{sample_path}/TOSCA-Metadata/TOSCA.meta', 'r') as f:
tosca_content = yaml.safe_load(f.read())
with open(f'{sample_path}/Definitions/'
f'ut_sample1_df_simple.yaml', 'r') as f:
definition_content = yaml.safe_load(f.read())
self.assertEqual(tosca_content, vnfd.tosca_meta)
self.assertEqual(True, vnfd.csar_dir_is_tmp)
self.assertEqual(
definition_content, vnfd.definitions['ut_sample1_df_simple.yaml'])
def test_init_vnfd_error(self):
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
vnfd.csar_dir = 'test'
self.assertRaises(sol_ex.InvalidVnfdFormat, vnfd.init_vnfd)
def test_delete(self):
os.mkdir("/tmp/test")
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
vnfd.csar_dir_is_tmp = True
vnfd.csar_dir = "/tmp/test"
vnfd.delete()
result = os.path.isdir(vnfd.csar_dir)
self.assertEqual(False, result)
def test_get_vnfd_properties(self):
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
expected_result = {
'vnfConfigurableProperties': {},
'extensions': {},
'metadata': {}
}
result = vnfd.get_vnfd_properties()
self.assertEqual(expected_result, result)
def test_get_base_hot_abnormal(self):
flavour_id = 'simple'
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
vnfd.csar_dir = '/test/'
base_hot_result = vnfd.get_base_hot(flavour_id)
self.assertEqual({}, base_hot_result)
flavour_id = 'error'
base_hot_result = self.vnfd_1.get_base_hot(flavour_id)
self.assertIsNotNone(base_hot_result['template'])
def test_remove_tmp_csar_dir(self):
os.mkdir("/tmp/test")
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
tmp_dir = "/tmp/test"
vnfd.remove_tmp_csar_dir(tmp_dir)
result = os.path.isdir(tmp_dir)
self.assertEqual(False, result)
def test_remove_tmp_csar_dir_error(self):
vnfd_id = uuidutils.generate_uuid()
vnfd = vnfd_utils.Vnfd(vnfd_id)
log_name = "tacker.sol_refactored.common.vnfd_utils"
with self.assertLogs(logger=log_name, level=logging.DEBUG) as cm:
vnfd.remove_tmp_csar_dir('test')
msg = (f'ERROR:{log_name}:rmtree test failed')
self.assertIn(f'{msg}', cm.output[0].split('\n')[0])
def test_get_policy_values_by_type(self):
result = self.vnfd_1.get_policy_values_by_type(
'error', 'tosca.policies.nfv.AntiAffinityRule')
self.assertEqual('nfvi_node', result[0]['properties']['scope'])
def test_get_vdu_num_none(self):
result = self.vnfd_1.get_vdu_num('error', 'VDU1', 'default')
self.assertEqual(0, result)
def test_get_affinity_targets(self):
result = self.vnfd_1.get_affinity_targets('error')
expected_result = [(['VDU3'], 'zone')]
self.assertEqual(expected_result, result)
def test_get_interface_script_abnormal(self):
result = self.vnfd_1.get_interface_script('error', 'instantiate_start')
self.assertEqual(None, result)
result = self.vnfd_1.get_interface_script('error', 'instantiate_end')
self.assertEqual(None, result)
self.vnfd_1.get_interface_script('error', 'instantiate_end')
self.assertRaises(
sol_ex.SolHttpError422, self.vnfd_1.get_interface_script,
'error', 'terminate_start')
def test_get_scale_vdu_and_num_abnormal(self):
result = self.vnfd_1.get_scale_vdu_and_num('error', 'VDU1_scale')
self.assertEqual({}, result)
def test_get_scale_info_from_inst_level_abnormal(self):
result = self.vnfd_1.get_scale_info_from_inst_level('error', 'default')
self.assertEqual({}, result)
def test_get_max_scale_level_abnormal(self):
result = self.vnfd_1.get_max_scale_level('error', 'VDU1_scale')
self.assertEqual(0, result)
def test_get_vnf_artifact_files_manifest(self):
result = self.vnfd_1.get_vnf_artifact_files()
expected_result = ['Scripts/install.sh',
'Files/kubernetes/deployment.yaml']
self.assertEqual(expected_result, result)

View File

@ -39,8 +39,9 @@ class TestConductorV2(db_base.SqlTestCase):
self.conductor = conductor_v2.ConductorV2()
self.context = context.get_admin_context()
def _create_inst_and_lcmocc(self,
op_state=fields.LcmOperationStateType.STARTING):
def _create_inst_and_lcmocc(
self, op_state=fields.LcmOperationStateType.STARTING,
is_change_vnfpkg=False):
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
@ -65,6 +66,9 @@ class TestConductorV2(db_base.SqlTestCase):
isCancelPending=False,
operationParams=req)
if is_change_vnfpkg:
lcmocc.operation = fields.LcmOperationType.CHANGE_VNFPKG
inst.create(self.context)
lcmocc.create(self.context)
@ -530,3 +534,98 @@ class TestConductorV2(db_base.SqlTestCase):
lcmocc = lcmocc_utils.get_lcmocc(self.context, lcmocc.id)
expected = ex.make_problem_details()
self.assertEqual(expected, lcmocc.error.to_dict())
def test_start_lcm_op_abnormal(self):
# prepare
lcmocc = self._create_inst_and_lcmocc(
op_state=fields.LcmOperationStateType.PROCESSING)
result = self.conductor.start_lcm_op(self.context, lcmocc.id)
self.assertEqual(None, result)
@mock.patch.object(nfvo_client.NfvoClient, 'send_lcmocc_notification')
@mock.patch.object(nfvo_client.NfvoClient, 'get_vnfd')
@mock.patch.object(vnflcm_driver_v2.VnfLcmDriverV2, 'post_grant')
@mock.patch.object(vnflcm_driver_v2.VnfLcmDriverV2, 'process')
def test_retry_lcm_op_abnormal(self, mocked_process, mocked_post_grant,
mocked_get_vnfd, mocked_send_lcmocc_notification):
# operation state incorrect
lcmocc = self._create_inst_and_lcmocc(
op_state=fields.LcmOperationStateType.PROCESSING)
result = self.conductor.retry_lcm_op(self.context, lcmocc.id)
self.assertEqual(None, result)
# operation is change_vnfpkg
# prepare
lcmocc = self._create_inst_and_lcmocc(
op_state=fields.LcmOperationStateType.FAILED_TEMP)
lcmocc.operation = fields.LcmOperationType.CHANGE_VNFPKG
lcmocc.operationParams = objects.ChangeCurrentVnfPkgRequest(
vnfdId='test-vnfdid')
self._create_grant_req_and_grant(lcmocc)
mocked_get_vnfd.return_value = mock.Mock()
op_state = []
def _store_state(context, lcmocc, inst, endpoint):
op_state.append(lcmocc.operationState)
mocked_send_lcmocc_notification.side_effect = _store_state
# run retry_lcm_op
self.conductor.retry_lcm_op(self.context, lcmocc.id)
# check operationState transition
self.assertEqual(2, mocked_send_lcmocc_notification.call_count)
self.assertEqual(fields.LcmOperationStateType.PROCESSING, op_state[0])
self.assertEqual(fields.LcmOperationStateType.COMPLETED, op_state[1])
# check grant_req and grant are deleted
self.assertRaises(sol_ex.GrantRequestOrGrantNotFound,
lcmocc_utils.get_grant_req_and_grant, self.context, lcmocc)
@mock.patch.object(nfvo_client.NfvoClient, 'send_lcmocc_notification')
@mock.patch.object(nfvo_client.NfvoClient, 'get_vnfd')
@mock.patch.object(vnflcm_driver_v2.VnfLcmDriverV2, 'post_grant')
@mock.patch.object(vnflcm_driver_v2.VnfLcmDriverV2, 'rollback')
def test_rollback_lcm_op_abnormal(self, mocked_rollback,
mocked_post_grant, mocked_get_vnfd,
mocked_send_lcmocc_notification):
# operation state incorrect
lcmocc = self._create_inst_and_lcmocc(
op_state=fields.LcmOperationStateType.PROCESSING)
result = self.conductor.rollback_lcm_op(self.context, lcmocc.id)
self.assertEqual(None, result)
# operation is change_vnfpkg
lcmocc = self._create_inst_and_lcmocc(
op_state=fields.LcmOperationStateType.FAILED_TEMP,
is_change_vnfpkg=True)
self._create_grant_req_and_grant(lcmocc)
mocked_get_vnfd.return_value = mock.Mock()
op_state = []
def _store_state(context, lcmocc, inst, endpoint):
op_state.append(lcmocc.operationState)
mocked_send_lcmocc_notification.side_effect = _store_state
# run rollback_lcm_op
self.conductor.rollback_lcm_op(self.context, lcmocc.id)
# check operationState transition
self.assertEqual(2, mocked_send_lcmocc_notification.call_count)
self.assertEqual(fields.LcmOperationStateType.ROLLING_BACK,
op_state[0])
self.assertEqual(fields.LcmOperationStateType.ROLLED_BACK, op_state[1])
# check grant_req and grant are deleted
self.assertRaises(sol_ex.GrantRequestOrGrantNotFound,
lcmocc_utils.get_grant_req_and_grant, self.context, lcmocc)
def test_modify_vnfinfo_abnormal(self):
lcmocc = self._create_inst_and_lcmocc()
result = self.conductor.modify_vnfinfo(self.context, lcmocc.id)
self.assertEqual(None, result)

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@ from oslo_utils import uuidutils
from unittest import mock
from tacker import context
from tacker.sol_refactored.common import config
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
from tacker.sol_refactored.infra_drivers.openstack import openstack
from tacker.sol_refactored import objects
@ -35,13 +37,6 @@ SAMPLE_FLAVOUR_ID = "simple"
_vim_connection_info_example = {
"vimId": "vim_id_1",
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
# "interfaceInfo": omitted
# "accessInfo": omitted
}
_vim_connection_info_for_change_vnfpkg = {
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
"vimId": uuidutils.generate_uuid(),
"interfaceInfo": {"endpoint": "http://127.0.0.1/identity"},
"accessInfo": {
"username": "nfv_user",
@ -51,7 +46,6 @@ _vim_connection_info_for_change_vnfpkg = {
"projectDomain": "Default",
"userDomain": "Default"
}
}
_instantiate_req_example = {
@ -2639,6 +2633,110 @@ mock_resource_list_3 = {
]
}
_heat_parameters = {
'VDU': {
'VDU1': {
'desired_capacity': 1,
'computeFlavourId': 'm1.tiny',
'locationConstraints': None
},
'VirtualStorage': {
'vcImageId': 'image-1.0.0-x86_64-disk'
},
'VDU2': {
'computeFlavourId': 'm1.small',
'vcImageId': 'image-VDU2'
}
},
'CP': {
'VDU1_CP1': {
'network': 'res_id_ext_vl_1'
},
'VDU1_CP2': {
'network': 'res_id_id_ext_vl_2',
'fixed_ips': [{
'subnet': 'res_id_subnet_1'
}]
},
'VDU2_CP1': {
'network': 'res_id_ext_vl_1',
'fixed_ips': [{
'ip_address': '10.10.0.102'
}]
},
'VDU2_CP2': {
'network': 'res_id_id_ext_vl_2',
'fixed_ips': []
}
}
}
_grant_req_example = {
'operation': 'SCALE',
'removeResources': [{
'id': 'ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1',
'resource': {
'resourceId': 'res_id_VDU1_1',
'vimLevelResourceType': 'OS::Nova::Server'
}
}, {
'id': 'VDU1_CP1-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'LINKPORT',
'resourceTemplateId': 'VDU1_CP1',
'resource': {
'resourceId': 'res_id_VDU1_1_CP1',
'vimLevelResourceType': 'OS::Neutron::Port'
}
}, {
'id': 'VDU1_CP2-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'LINKPORT',
'resourceTemplateId': 'VDU1_CP2',
'resource': {
'resourceId': 'res_id_VDU1_1_CP2',
'vimLevelResourceType': 'OS::Neutron::Port'
}
}, {
'id': 'VDU1_CP3-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'LINKPORT',
'resourceTemplateId': 'VDU1_CP3',
'resource': {
'resourceId': 'res_id_VDU1_1_CP3',
'vimLevelResourceType': 'OS::Neutron::Port'
}
}, {
'id': 'VDU1_CP4-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'LINKPORT',
'resourceTemplateId': 'VDU1_CP4',
'resource': {
'resourceId': 'res_id_VDU1_1_CP4',
'vimLevelResourceType': 'OS::Neutron::Port'
}
}, {
'id': 'VDU1_CP5-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'LINKPORT',
'resourceTemplateId': 'VDU1_CP5',
'resource': {
'resourceId': 'res_id_VDU1_1_CP5',
'vimLevelResourceType': 'OS::Neutron::Port'
}
}, {
'id': 'VirtualStorage-ed52e40b-922f-4e01-bc30-d4bf80029280',
'type': 'STORAGE',
'resourceTemplateId': 'VirtualStorage',
'resource': {
'resourceId': 'res_id_VirtualStorage_1',
'vimLevelResourceType': 'OS::Cinder::Volume'
}
}],
'additionalParams': {
'key': 'value'
}
}
CONF = config.CONF
class TestOpenstack(base.BaseTestCase):
@ -2647,6 +2745,7 @@ class TestOpenstack(base.BaseTestCase):
objects.register_all()
self.driver = openstack.Openstack()
self.context = context.get_admin_context()
CONF.v2_vnfm.default_graceful_termination_timeout = 0
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "../..", "samples")
@ -2811,3 +2910,353 @@ class TestOpenstack(base.BaseTestCase):
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_change_ext_conn, result)
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_status')
@mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_instantiate(self, mock_template, mock_parameters, mock_resources,
mock_update_stack, mock_create_stack, mock_status):
# prepare
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.INSTANTIATE
)
grant = objects.GrantV1()
mock_status.return_value = (None, 'test')
mock_resources.return_value = _heat_reses_example
mock_parameters.return_value = _heat_get_parameters_example
mock_template.return_value = _heat_get_template_example
# execute
self.driver.instantiate(req, inst, grant_req, grant, self.vnfd_1)
mock_create_stack.assert_called_once()
mock_status.return_value = ('Create_Failed', 'test')
# execute
self.driver.instantiate(req, inst, grant_req, grant, self.vnfd_1)
mock_update_stack.assert_called_once()
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_status')
@mock.patch.object(openstack.heat_utils.HeatClient, 'delete_stack')
def test_instantiate_rollback(self, mock_delete_stack, mock_status):
# prepare
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.INSTANTIATE
)
grant = objects.GrantV1()
mock_status.return_value = (None, 'test')
# execute
self.driver.instantiate_rollback(
req, inst, grant_req, grant, self.vnfd_1)
mock_delete_stack.assert_not_called()
mock_status.return_value = ('Create_Failed', 'test')
# execute
self.driver.instantiate_rollback(
req, inst, grant_req, grant, self.vnfd_1)
mock_delete_stack.assert_called_once()
@mock.patch.object(openstack.heat_utils.HeatClient, 'delete_stack')
def test_terminate(self, mock_delete_stack):
# prepare
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
req = objects.TerminateVnfRequest(
terminationType='GRACEFUL', gracefulTerminationTimeout=0)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.TERMINATE
)
grant = objects.GrantV1()
# graceful
self.driver.terminate(req, inst, grant_req, grant, self.vnfd_1)
self.assertEqual(1, mock_delete_stack.call_count)
# graceful with no time
req = objects.TerminateVnfRequest(terminationType='GRACEFUL')
self.driver.terminate(req, inst, grant_req, grant, self.vnfd_1)
self.assertEqual(2, mock_delete_stack.call_count)
# forceful
req = objects.TerminateVnfRequest(terminationType='FORCEFUL')
self.driver.terminate(req, inst, grant_req, grant, self.vnfd_1)
self.assertEqual(3, mock_delete_stack.call_count)
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'mark_unhealthy')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_scale(self, mock_template, mock_unhealthy, mock_parameters,
mock_reses, mock_stack):
# prepare
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_expected_inst_info_vnfc_updated))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.SCALE
)
grant = objects.GrantV1()
mock_parameters.return_value = {'nfv': json.dumps(_heat_parameters)}
mock_template.return_value = _heat_get_template_example
# scale-out
req = objects.ScaleVnfRequest(
type='SCALE_OUT', aspectId='VDU1_scale', numberOfSteps=1)
mock_reses.return_value = _heat_reses_example
self.driver.scale(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_vnfc_updated, result)
# scale-in
req = objects.ScaleVnfRequest(
type='SCALE_IN', aspectId='VDU1_scale', numberOfSteps=1)
grant_req = objects.GrantRequestV1.from_dict(_grant_req_example)
mock_reses.return_value = _heat_reses_example
self.driver.scale(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_vnfc_updated, result)
# error
req = objects.ScaleVnfRequest(
type='SCALE_IN', aspectId='VDU1_scale', numberOfSteps=1)
grant_req = objects.GrantRequestV1.from_dict(_grant_req_example)
del inst.instantiatedVnfInfo.vnfcResourceInfo[1]['metadata'][
'parent_stack_id']
self.assertRaises(
sol_ex.UnexpectedParentResourceDefinition, self.driver.scale,
req, inst, grant_req, grant, self.vnfd_1)
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'mark_unhealthy')
def test_scale_rollback(
self, mock_unhealthy, mock_parameters,
mock_reses, mock_stack):
# prepare
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_expected_inst_info_vnfc_updated))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.SCALE
)
grant = objects.GrantV1()
mock_parameters.return_value = {'nfv': json.dumps(_heat_parameters)}
# scale-out
req = objects.ScaleVnfRequest(
type='SCALE_OUT', aspectId='VDU1_scale', numberOfSteps=1)
mock_reses.return_value = _heat_reses_example
mock_reses.return_value[13]['physical_resource_id'] = (
'res_id_VDU1_1_new')
self.driver.scale_rollback(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_vnfc_updated, result)
# error
del mock_reses.return_value[13]['parent_resource']
self.assertRaises(
sol_ex.UnexpectedParentResourceDefinition,
self.driver.scale_rollback, req, inst,
grant_req, grant, self.vnfd_1)
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_change_ext_conn(self, mock_template, mock_parameters,
mock_reses, mock_stack):
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_expected_inst_info_change_ext_conn))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_EXT_CONN
)
grant = objects.GrantV1()
req = objects.ChangeExtVnfConnectivityRequest.from_dict(
_change_ext_conn_req_example)
mock_parameters.return_value = {'nfv': json.dumps(_heat_parameters)}
mock_reses.return_value = _heat_reses_example_change_ext_conn
mock_template.return_value = _heat_get_template_example
self.driver.change_ext_conn(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_change_ext_conn, result)
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_change_ext_conn_rollback(
self, mock_template, mock_parameters, mock_reses, mock_stack):
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_expected_inst_info_change_ext_conn))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_EXT_CONN
)
grant = objects.GrantV1()
req = objects.ChangeExtVnfConnectivityRequest.from_dict(
_change_ext_conn_req_example)
mock_parameters.return_value = {'nfv': json.dumps(_heat_parameters)}
mock_reses.return_value = _heat_reses_example_change_ext_conn
mock_template.return_value = _heat_get_template_example
self.driver.change_ext_conn_rollback(
req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_change_ext_conn, result)
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'mark_unhealthy')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'delete_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_files')
def test_heal(self, mock_files, mock_template,
mock_parameters, mock_create, mock_delete,
mock_reses, mock_unhealthy, mock_update):
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_expected_inst_info_vnfc_updated))
)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.HEAL
)
grant = objects.GrantV1()
mock_parameters.return_value = {'nfv': json.dumps(_heat_parameters)}
mock_template.return_value = _heat_get_template_example
# re-create
req = objects.HealVnfRequest(
additionalParams={
"all": True
}
)
mock_reses.return_value = _heat_reses_example
self.driver.heal(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_vnfc_updated, result)
# no re-create
grant_req = objects.GrantRequestV1.from_dict(_grant_req_example)
req = objects.HealVnfRequest()
mock_reses.return_value = _heat_reses_example
self.driver.heal(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_vnfc_updated, result)

View File

@ -0,0 +1,763 @@
# Copyright (C) 2022 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 os
from oslo_utils import uuidutils
from tacker import context
from tacker.sol_refactored.api import api_version
from tacker.sol_refactored.infra_drivers.openstack import userdata_default
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import fields
from tacker.tests import base
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
# InstantiateVnfRequest example
_ext_vl_1 = {
"id": uuidutils.generate_uuid(),
"resourceId": 'net0_id',
"extCps": [
{
"cpdId": "VDU1_CP1",
"cpConfig": {
"VDU1_CP1_1": {
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"numDynamicAddresses": 1}]}}]}
}
},
{
"cpdId": "VDU2_CP1",
"cpConfig": {
"VDU2_CP1_1": {
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["10.10.0.101"]}]}}]}
}
}
],
}
_ext_vl_2 = {
"id": uuidutils.generate_uuid(),
"resourceId": 'net1_id',
"extCps": [
{
"cpdId": "VDU1_CP2",
"cpConfig": {
"VDU1_CP2_1": {
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"numDynamicAddresses": 1,
"subnetId": 'subnet1_id'}]}}]}
}
},
{
"cpdId": "VDU2_CP2",
"cpConfig": {
"VDU2_CP2_1": {
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["10.10.1.101"],
"subnetId": 'subnet1_id'}]}}]}
}
}
]
}
_inst_req_example = {
"flavourId": "simple",
"instantiationLevelId": "instantiation_level_2",
"extVirtualLinks": [
_ext_vl_1,
_ext_vl_2
],
"extManagedVirtualLinks": [
{
"id": uuidutils.generate_uuid(),
"vnfVirtualLinkDescId": "internalVL1",
"resourceId": 'net_mgmt_id'
},
],
"vimConnectionInfo": {
"vim1": {
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
"vimId": uuidutils.generate_uuid(),
"interfaceInfo": {"endpoint": "http://localhost/identity/v3"},
"accessInfo": {
"username": "nfv_user",
"region": "RegionOne",
"password": "devstack",
"project": "nfv",
"projectDomain": "Default",
"userDomain": "Default"
}
}
}
}
_scale_req_example = {
'type': 'SCALE_OUT',
'aspectId': 'VDU1_scale',
'numberOfSteps': 1
}
_change_ext_conn_req_example = {
"extVirtualLinks": [
{
"id": "id_ext_vl_3",
"resourceId": "res_id_ext_vl_3",
"extCps": [
{
"cpdId": "VDU2_CP1",
"cpConfig": {
"VDU2_CP1_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"fixedAddresses": [
"20.10.0.102"
]
}
]
}
}
]
}
}
}
]
},
{
"id": "id_ext_vl_4",
"resourceId": "res_id_id_ext_vl_4",
"extCps": [
{
"cpdId": "VDU1_CP2",
"cpConfig": {
"VDU1_CP2_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"numDynamicAddresses": 1,
"subnetId": "res_id_subnet_4"
}
]
}
}
]
}
}
},
{
"cpdId": "VDU2_CP2",
"cpConfig": {
"VDU2_CP2_1": {
"linkPortId": "link_port_id_VDU2_CP2_modified"
}
}
}
],
"extLinkPorts": [
{
"id": "link_port_id_VDU2_CP2_modified",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP2_modified"
}
}
]
}
]
}
_inst_info_example = {
"flavourId": "simple",
"vnfState": "STARTED",
'scaleStatus': [],
"extCpInfo": [
{
"id": "90561570-264c-4472-b84f-1fff98513475",
"cpdId": "VDU2_CP1",
"cpConfigId": "VDU2_CP1_1",
"extLinkPortId": "ac27c99b-73c8-4e91-b730-90deade72af4",
"associatedVnfcCpId": "be955786-a0c7-4b61-8cd8-9bb8bcb1c6e3"
},
{
"id": "f9f4b4b2-50e2-4c73-b89b-e0665e65ffbe",
"cpdId": "VDU2_CP2",
"cpConfigId": "VDU2_CP2_1",
"extLinkPortId": "12567a13-9fbd-4803-ad9f-d94ced266cd8",
"associatedVnfcCpId": "c54fa2fc-185a-49a7-bb89-f30f7c3be6a4"
},
{
"id": "05474d0b-a1f7-4be5-b57e-ef6873e1f3b6",
"cpdId": "VDU1_CP2",
"cpConfigId": "VDU1_CP2_1",
"extLinkPortId": "aa6646da-2e59-4de9-9b72-c62e7c4d9142",
"associatedVnfcCpId": "fdbb289f-87c8-40d0-bf06-da07b41ba124"
},
{
"id": "42ede9a6-c2b8-4c0d-a337-26342ffb236c",
"cpdId": "VDU1_CP1",
"cpConfigId": "VDU1_CP1_1",
"extLinkPortId": "efd0eb4e-4e55-4ac8-8b9b-403ec79faf2d",
"associatedVnfcCpId": "235f920c-8b49-4894-9c36-73f5a3b9f74d"
},
{
"id": "4f0ab1ad-b7de-482f-a69b-1093c71d2ceb",
"cpdId": "VDU1_CP2",
"cpConfigId": "VDU1_CP2_1",
"extLinkPortId": "a6c4c043-e082-4873-a871-02467af66224",
"associatedVnfcCpId": "e23d970d-9ea9-4c26-9d67-8f244383ea3c"
},
{
"id": "7a7fa30f-a303-4856-bc8b-b836cb682892",
"cpdId": "VDU1_CP1",
"cpConfigId": "VDU1_CP1_1",
"extLinkPortId": "f58df4d9-08ff-41b7-ab73-95ebfb8103c4",
"associatedVnfcCpId": "259c5895-7be6-4bed-8a94-221c41b3d08f"
}
],
"extVirtualLinkInfo": [
{
"id": "137bdf0b-835c-43f0-b0d2-5c002599118a",
"resourceHandle": {
"resourceId": "6f97f400-2861-482a-ba78-65b652aaf8fc"
},
"extLinkPorts": [
{
"id": "ac27c99b-73c8-4e91-b730-90deade72af4",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "90561570-264c-4472-b84f-1fff98513475"
},
{
"id": "efd0eb4e-4e55-4ac8-8b9b-403ec79faf2d",
"resourceHandle": {
"resourceId": "res_id_VDU1_1_CP1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "42ede9a6-c2b8-4c0d-a337-26342ffb236c"
},
{
"id": "f58df4d9-08ff-41b7-ab73-95ebfb8103c4",
"resourceHandle": {
"resourceId": "res_id_VDU1_2_CP1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "7a7fa30f-a303-4856-bc8b-b836cb682892"
}
],
"currentVnfExtCpData": [
{
"cpdId": "VDU2_CP1",
"cpConfig": {
"VDU2_CP2_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"fixedAddresses": [
'10.10.0.2'
],
"subnetId": 'test'
}
]
}
}
]
}
}
}
]
},
{
"id": "d8141a5a-6b6e-4dab-9bf5-158f23a617d7",
"resourceHandle": {
"resourceId": "02bc95e0-3d43-4d11-83b8-f7b15d8661a9"
},
"extLinkPorts": [
{
"id": "12567a13-9fbd-4803-ad9f-d94ced266cd8",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP2",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "f9f4b4b2-50e2-4c73-b89b-e0665e65ffbe"
},
{
"id": "aa6646da-2e59-4de9-9b72-c62e7c4d9142",
"resourceHandle": {
"resourceId": "res_id_VDU1_1_CP2",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "05474d0b-a1f7-4be5-b57e-ef6873e1f3b6"
},
{
"id": "a6c4c043-e082-4873-a871-02467af66224",
"resourceHandle": {
"resourceId": "res_id_VDU1_2_CP2",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "4f0ab1ad-b7de-482f-a69b-1093c71d2ceb"
}
],
"currentVnfExtCpData": [
{
"cpdId": "VDU1_CP2",
"cpConfig": {
"VDU1_CP2_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"fixedAddresses": [
'10.10.0.3'
],
"subnetId": 'test'
}
]
}
}
]
}
}
},
{
"cpdId": "VDU2_CP2",
"cpConfig": {
"VDU2_CP2_1": {
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"fixedAddresses": [
'10.10.0.4'
],
"subnetId": 'test'
}
]
}
}
]
}
}
},
]
}
],
"extManagedVirtualLinkInfo": [
{
"id": "bad53df7-f1fa-482d-91b1-caec382aeec2",
"vnfVirtualLinkDescId": "internalVL1",
"networkResource": {
"resourceId": "56730009-169c-4f96-8141-828acf1ee067"
},
"vnfLinkPorts": [
{
"id": "74f387fe-6355-4af3-adc7-cdb507d5fa5f",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP3",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "5b0b336b-c207-4fa8-8b41-a5ad87d85cd0",
"cpInstanceType": "VNFC_CP"
},
{
"id": "4064ec55-b862-4527-a911-8752d3aa765a",
"resourceHandle": {
"resourceId": "res_id_VDU1_1_CP3",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "b0732fb7-a42a-4077-aebc-d22b67b64f13",
"cpInstanceType": "VNFC_CP"
},
{
"id": "f3c9e62d-0f31-4a36-bd99-eecd8def0871",
"resourceHandle": {
"resourceId": "res_id_VDU1_2_CP3",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "9c65f67e-feb2-447c-b0e7-a4f896185b4f",
"cpInstanceType": "VNFC_CP"
}
]
}
],
"vnfcResourceInfo": [
{
"id": "vnfc_res_info_id_VDU2",
"vduId": "VDU2",
"computeResource": {
"resourceId": "res_id_VDU2",
"vimLevelResourceType": "OS::Nova::Server"
},
"vnfcCpInfo": [
{
"id": "be955786-a0c7-4b61-8cd8-9bb8bcb1c6e3",
"cpdId": "VDU2_CP1",
"vnfExtCpId": "90561570-264c-4472-b84f-1fff98513475"
},
{
"id": "c54fa2fc-185a-49a7-bb89-f30f7c3be6a4",
"cpdId": "VDU2_CP2",
"vnfExtCpId": "f9f4b4b2-50e2-4c73-b89b-e0665e65ffbe"
},
{
"id": "5b0b336b-c207-4fa8-8b41-a5ad87d85cd0",
"cpdId": "VDU2_CP3",
"vnfLinkPortId": "74f387fe-6355-4af3-adc7-cdb507d5fa5f"
},
{
"id": "2cb2b3a8-a7a0-41da-b3b8-4b82f576b090",
"cpdId": "VDU2_CP4",
"vnfLinkPortId": "8e01813f-35fc-4a35-8f64-0da08a45ea21"
},
{
"id": "39a7d895-3b19-4330-b6ec-ae3557ea9c01",
"cpdId": "VDU2_CP5",
"vnfLinkPortId": "4dd7cadd-b9a1-484f-b2f2-1ff50ef0d90f"
},
{
"id": "315a938a-b194-0c20-6398-ba92cce39c18",
"cpdId": "VDU2_CP6",
"vnfLinkPortId": "6dafdda1-db6c-492e-6dc2-4e5d323d6f98"
}
]
},
{
"id": "vnfc_res_info_id_VDU1_1",
"vduId": "VDU1",
"computeResource": {
"resourceId": "res_id_VDU1_1",
"vimLevelResourceType": "OS::Nova::Server"
},
"storageResourceIds": ["2135b13c-e630-4700-8f8d-85b6e48f7871"],
"vnfcCpInfo": [
{
"id": "235f920c-8b49-4894-9c36-73f5a3b9f74d",
"cpdId": "VDU1_CP1",
"vnfExtCpId": "42ede9a6-c2b8-4c0d-a337-26342ffb236c"
},
{
"id": "fdbb289f-87c8-40d0-bf06-da07b41ba124",
"cpdId": "VDU1_CP2",
"vnfExtCpId": "05474d0b-a1f7-4be5-b57e-ef6873e1f3b6"
},
{
"id": "b0732fb7-a42a-4077-aebc-d22b67b64f13",
"cpdId": "VDU1_CP3",
"vnfLinkPortId": "4064ec55-b862-4527-a911-8752d3aa765a"
},
{
"id": "a49f8fb8-6fd9-4e9f-a6dd-0d268e51c83c",
"cpdId": "VDU1_CP4",
"vnfLinkPortId": "1666a0f7-6a34-474e-87a2-07fb0c30ecdb"
},
{
"id": "33194d65-ecd6-48d9-8ef7-c15ce9fef46c",
"cpdId": "VDU1_CP5",
"vnfLinkPortId": "ace663cd-431b-402a-b2ae-d0824c996edb"
}
]
},
{
"id": "vnfc_res_info_id_VDU1_2",
"vduId": "VDU1",
"computeResource": {
"resourceId": "res_id_VDU1_2",
"vimLevelResourceType": "OS::Nova::Server"
},
"storageResourceIds": ["739f7012-7973-485b-b34f-b006bc336150"],
"vnfcCpInfo": [
{
"id": "259c5895-7be6-4bed-8a94-221c41b3d08f",
"cpdId": "VDU1_CP1",
# when extLinkPorts of extVirtualLinks specified, there is
# no vnfExtCpId nor vnfLinkPortId.
},
{
"id": "e23d970d-9ea9-4c26-9d67-8f244383ea3c",
"cpdId": "VDU1_CP2",
"vnfExtCpId": "4f0ab1ad-b7de-482f-a69b-1093c71d2ceb"
},
{
"id": "9c65f67e-feb2-447c-b0e7-a4f896185b4f",
"cpdId": "VDU1_CP3",
"vnfLinkPortId": "f3c9e62d-0f31-4a36-bd99-eecd8def0871"
},
{
"id": "0716ac20-612a-4ac2-8c87-d83be31dd4b5",
"cpdId": "VDU1_CP4",
"vnfLinkPortId": "bce3159b-caca-45b7-8bb7-88015e951e56"
},
{
"id": "c9112298-61eb-4bba-b285-ed3419593b1b",
"cpdId": "VDU1_CP5",
"vnfLinkPortId": "e0f98917-70ff-4f79-8747-9d7fc22827a4"
}
]
},
{
"id": "vnfc_res_no_cp_info",
"vduId": "VDU1",
"computeResource": {
"resourceId": "res_id_VDU1_3",
"vimLevelResourceType": "OS::Nova::Server"
}
}
],
"vnfVirtualLinkResourceInfo": [
{
"id": "18bd0111-d5e1-4aa3-b2d8-5b89833c6351",
"vnfVirtualLinkDescId": "internalVL3",
"networkResource": {
"resourceId": "res_id_internalVL3",
"vimLevelResourceType": "OS::Neutron::Net"
},
"vnfLinkPorts": [
{
"id": "4dd7cadd-b9a1-484f-b2f2-1ff50ef0d90f",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP5",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "39a7d895-3b19-4330-b6ec-ae3557ea9c01",
"cpInstanceType": "VNFC_CP"
},
{
"id": "ace663cd-431b-402a-b2ae-d0824c996edb",
"resourceHandle": {
"resourceId": "res_id_VDU1_1_CP5",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "33194d65-ecd6-48d9-8ef7-c15ce9fef46c",
"cpInstanceType": "VNFC_CP"
},
{
"id": "e0f98917-70ff-4f79-8747-9d7fc22827a4",
"resourceHandle": {
"resourceId": "res_id_VDU1_2_CP5",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "c9112298-61eb-4bba-b285-ed3419593b1b",
"cpInstanceType": "VNFC_CP"
}
]
},
{
"id": "047aa313-b591-4529-aa98-cb8ce2b82e28",
"vnfVirtualLinkDescId": "internalVL2",
"networkResource": {
"resourceId": "res_id_internalVL2",
"vimLevelResourceType": "OS::Neutron::Net"
},
"vnfLinkPorts": [
{
"id": "8e01813f-35fc-4a35-8f64-0da08a45ea21",
"resourceHandle": {
"resourceId": "res_id_VDU2_CP4",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "2cb2b3a8-a7a0-41da-b3b8-4b82f576b090",
"cpInstanceType": "VNFC_CP"
},
{
"id": "1666a0f7-6a34-474e-87a2-07fb0c30ecdb",
"resourceHandle": {
"resourceId": "res_id_VDU1_1_CP4",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "a49f8fb8-6fd9-4e9f-a6dd-0d268e51c83c",
"cpInstanceType": "VNFC_CP"
},
{
"id": "bce3159b-caca-45b7-8bb7-88015e951e56",
"resourceHandle": {
"resourceId": "res_id_VDU1_2_CP4",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "0716ac20-612a-4ac2-8c87-d83be31dd4b5",
"cpInstanceType": "VNFC_CP"
}
]
}
],
"virtualStorageResourceInfo": [
{
"id": "2135b13c-e630-4700-8f8d-85b6e48f7871",
"virtualStorageDescId": "VirtualStorage",
"storageResource": {
"resourceId": "res_id_VirtualStorage_1",
"vimLevelResourceType": "OS::Cinder::Volume"
}
},
{
"id": "739f7012-7973-485b-b34f-b006bc336150",
"virtualStorageDescId": "VirtualStorage",
"storageResource": {
"resourceId": "res_id_VirtualStorage_2",
"vimLevelResourceType": "OS::Cinder::Volume"
}
}
],
"vnfcInfo": [
{
"id": "VDU2-vnfc_res_info_id_VDU2",
"vduId": "VDU2",
"vnfcResourceInfoId": "vnfc_res_info_id_VDU2",
"vnfcState": "STARTED"
},
{
"id": "VDU1-vnfc_res_info_id_VDU1_1",
"vduId": "VDU1",
"vnfcResourceInfoId": "vnfc_res_info_id_VDU1_1",
"vnfcState": "STARTED"
},
{
"id": "VDU1-vnfc_res_info_id_VDU1_2",
"vduId": "VDU1",
"vnfcResourceInfoId": "vnfc_res_info_id_VDU1_2",
"vnfcState": "STARTED"
}
]
}
_vnf_instance_example = {
"id": uuidutils.generate_uuid(),
"vnfdId": SAMPLE_VNFD_ID,
"vnfProvider": "provider",
"vnfProductName": "product name",
"vnfSoftwareVersion": "software version",
"vnfdVersion": "vnfd version",
"instantiationState": "NOT_INSTANTIATED",
"vimConnectionInfo": _inst_req_example['vimConnectionInfo']
}
class TestUserdataDefault(base.BaseTestCase):
def setUp(self):
super(TestUserdataDefault, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
self.context.api_version = api_version.APIVersion('2.0.0')
self.grant = {}
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "../..", "samples")
self.tmp_csar_dir = os.path.join(sample_dir, "sample1")
self.userdata_default = userdata_default.DefaultUserData()
def test_instantiate(self):
req = _inst_req_example
req['additionalParams'] = {"nfv": "req"}
inst = _vnf_instance_example
grant_req = {
"operation": fields.LcmOperationType.INSTANTIATE
}
self.grant['additionalParams'] = {"nfv": "grant"}
result = self.userdata_default.instantiate(
req, inst, grant_req, self.grant, self.tmp_csar_dir)
self.assertIsNotNone(result['template'])
self.assertIsNotNone(result['parameters'])
self.assertNotIn('req', result['parameters']['nfv'])
self.assertIn('grant', result['parameters']['nfv'])
self.assertIsNotNone(result['files'])
def test_scale(self):
req = _scale_req_example
inst = _vnf_instance_example
inst['instantiationState'] = 'INSTANTIATED'
inst['instantiatedVnfInfo'] = _inst_info_example
grant_req = {
"operation": fields.LcmOperationType.SCALE
}
result = self.userdata_default.scale(
req, inst, grant_req, self.grant, self.tmp_csar_dir)
self.assertIn('VDU1', result['parameters']['nfv']['VDU'])
def test_scale_rollback(self):
req = _scale_req_example
inst = _vnf_instance_example
inst['instantiationState'] = 'INSTANTIATED'
inst['instantiatedVnfInfo'] = _inst_info_example
grant_req = {
"operation": fields.LcmOperationType.SCALE
}
result = self.userdata_default.scale_rollback(
req, inst, grant_req, self.grant, self.tmp_csar_dir)
self.assertIn('VDU1', result['parameters']['nfv']['VDU'])
def test_change_ext_conn(self):
req = _change_ext_conn_req_example
inst = _vnf_instance_example
inst['instantiationState'] = 'INSTANTIATED'
inst['instantiatedVnfInfo'] = _inst_info_example
grant_req = {
"operation": fields.LcmOperationType.CHANGE_EXT_CONN
}
result = self.userdata_default.change_ext_conn(
req, inst, grant_req, self.grant, self.tmp_csar_dir)
self.assertIn('VDU1_CP2', result['parameters']['nfv']['CP'])
self.assertIn('VDU2_CP1', result['parameters']['nfv']['CP'])
self.assertIn('VDU2_CP2', result['parameters']['nfv']['CP'])
def test_change_ext_conn_rollback(self):
req = _change_ext_conn_req_example
inst = _vnf_instance_example
inst['instantiationState'] = 'INSTANTIATED'
inst['instantiatedVnfInfo'] = _inst_info_example
grant_req = {
"operation": fields.LcmOperationType.CHANGE_EXT_CONN
}
result = self.userdata_default.change_ext_conn_rollback(
req, inst, grant_req, self.grant, self.tmp_csar_dir)
self.assertIn('VDU1_CP2', result['parameters']['nfv']['CP'])
self.assertIn('VDU2_CP1', result['parameters']['nfv']['CP'])
self.assertIn('VDU2_CP2', result['parameters']['nfv']['CP'])
def test_heal(self):
result = self.userdata_default.heal(None, None, None, None, None)
self.assertEqual({}, result['parameters']['nfv'])

View File

@ -0,0 +1,749 @@
# Copyright (C) 2022 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 datetime import datetime
import os
from unittest import mock
from oslo_utils import uuidutils
from tacker import context
from tacker.objects import vnf_package
from tacker.objects import vnf_package_vnfd
from tacker.sol_refactored.api import api_version
from tacker.sol_refactored.common import config
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import lcm_op_occ_utils as lcmocc_utils
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored.nfvo import glance_utils
from tacker.sol_refactored.nfvo import local_nfvo
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import fields
from tacker.tests import base
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
SAMPLE_VNFPKG_ID = "d04753f1-493e-17dc-e4a9-65f73b3ccc24"
_inst_grant_req_example = {
"vnfInstanceId": "2d004394-d0f0-406d-845a-2b148f91039a",
"vnfLcmOpOccId": "34da9ba7-6ab1-4d8d-a68a-68892e56642c",
"vnfdId": "b1bb0ce7-ebca-4fa7-95ed-4840d7000000",
"flavourId": "simple",
"operation": "INSTANTIATE",
"isAutomaticInvocation": False,
"instantiationLevelId": "instantiation_level_2",
"addResources": [{
"id": "6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "COMPUTE",
"resourceTemplateId": "VDU2"
}, {
"id": "VDU2_CP5-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP5"
}, {
"id": "VDU2_CP2-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP2"
}, {
"id": "VDU2_CP1-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP1"
}, {
"id": "VDU2_CP3-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP3"
}, {
"id": "VDU2_CP4-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP4"
}, {
"id": "a411a968-c00b-4d46-8553-a37f3537391e",
"type": "VL",
"resourceTemplateId": "internalVL2"
}, {
"id": "f06ba7cf-f5af-4856-8d3a-56b331d1b9a5",
"type": "VL",
"resourceTemplateId": "internalVL3"
}],
"placementConstraints": [{
"affinityOrAntiAffinity": "ANTI_AFFINITY",
"scope": "NFVI_NODE",
"resource": [{
"idType": "GRANT",
"resourceId": "6396a2a1-7e36-49bd-8fff-2d46394a6b29"
}, {
"idType": "GRANT",
"resourceId": "39e0af93-aba5-4a15-9231-cdaa4149738e"
}, {
"idType": "GRANT",
"resourceId": "8a3ab83f-187c-4feb-b1b5-a6bf587130fa"
}, {
"idType": "GRANT",
"resourceId": "3f2385fa-3f13-436d-b93a-47c62ef237e0"
}]
}],
"_links": {
"vnfLcmOpOcc": {
"href": "http://127.0.0.1:9890/vnflcm/v2/vnf_lcm_op_occs/"
"34da9ba7-6ab1-4d8d-a68a-68892e56642c"
},
"vnfInstance": {
"href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/"
"2d004394-d0f0-406d-845a-2b148f91039a"
}
}
}
_inst_req_example = {
"vimConnectionInfo": {
"vim1": {
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
"vimId": uuidutils.generate_uuid(),
"interfaceInfo": {"endpoint": "http://localhost/identity/v3"},
"accessInfo": {
"username": "nfv_user",
"region": "RegionOne",
"password": "devstack",
"project": "nfv",
"projectDomain": "Default",
"userDomain": "Default"
}
}
}
}
_change_vnfkg_grant_req_example = {
'vnfInstanceId': '5eb4b136-6dac-4af1-b880-4e5eea6ec358',
'vnfLcmOpOccId': '4ed07654-d459-4ae7-85c5-bed63c563646',
'vnfdId': '1440b128-be42-4eed-9c4b-7df4b59c35d2',
'dstVnfdId': 'b1bb0ce7-ebca-4fa7-95ed-4840d7000000',
'flavourId': 'simple',
'operation': 'CHANGE_VNFPKG',
'isAutomaticInvocation': False,
'addResources': [{
'id': 'aab5201a-7516-41d9-9bf3-6a2579df7004',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU2'
}, {
'id': '36027157-a86b-4294-95e8-4ebd4bd91abf',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1'
}, {
'id': 'VirtualStorage-36027157-a86b-4294-95e8-4ebd4bd91abf',
'type': 'STORAGE',
'resourceTemplateId': 'VirtualStorage'
}, {
'id': 'cf40bb5a-046d-4113-b69b-9e34878ba781',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1'
}, {
'id': 'VirtualStorage-cf40bb5a-046d-4113-b69b-9e34878ba781',
'type': 'STORAGE',
'resourceTemplateId': 'VirtualStorage'
}, {
'id': '7c093596-c98c-40a0-b2cb-f0c30ce6fb87',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1'
}],
'removeResources': [{
'id': '0c8c248d-69cd-4dde-8b75-9791a02899c8',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU2',
'resource': {
'resourceId': 'res_id_VDU2',
'vimLevelResourceType': 'OS::Nova::Server'
}
}, {
'id': '374dfdae-6add-4a96-a37f-95b8e1b3f79b',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1',
'resource': {
'resourceId': 'res_id_VDU1_1',
'vimLevelResourceType': 'OS::Nova::Server'
}
}, {
'id': 'VirtualStorage-374dfdae-6add-4a96-a37f-95b8e1b3f79b',
'type': 'STORAGE',
'resourceTemplateId': 'VirtualStorage',
'resource': {
'resourceId': 'res_id_VirtualStorage_1',
'vimLevelResourceType': 'OS::Cinder::Volume'
}
}, {
'id': '4e601248-185f-4405-91bb-ea579c1b866b',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1',
'resource': {
'resourceId': 'res_id_VDU1_2',
'vimLevelResourceType': 'OS::Nova::Server'
}
}, {
'id': 'VirtualStorage-4e601248-185f-4405-91bb-ea579c1b866b',
'type': 'STORAGE',
'resourceTemplateId': 'VirtualStorage',
'resource': {
'resourceId': 'res_id_VirtualStorage_2',
'vimLevelResourceType': 'OS::Cinder::Volume'
}
}, {
'id': 'cd8bee39-a7b1-4652-8de4-56f5863c9157',
'type': 'COMPUTE',
'resourceTemplateId': 'VDU1',
'resource': {
'resourceId': 'res_id_VDU1_3',
'vimLevelResourceType': 'OS::Nova::Server'
}
}],
'_links': {
'vnfLcmOpOcc': {
'href': 'http://127.0.0.1:9890/vnflcm/v2/vnf_lcm_op_occs/'
'4ed07654-d459-4ae7-85c5-bed63c563646'
},
'vnfInstance': {
'href': 'http://127.0.0.1:9890/vnflcm/v2/vnf_instances/'
'5eb4b136-6dac-4af1-b880-4e5eea6ec358'
}
}
}
_change_vnfpkg_example = {
"vnfdId": '61723406-6634-2fc0-060a-0b11104d2667',
"additionalParams": {
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py",
"vdu_params": [{
"vdu_id": "VDU1",
"old_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
"new_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
}]
}
}
CONF = config.CONF
class TestLocalNfvo(base.BaseTestCase):
def setUp(self):
super(TestLocalNfvo, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
CONF.vnf_package.vnf_package_csar_path = (
'/opt/stack/data/tacker/vnfpackage/')
self.context.api_version = api_version.APIVersion('2.0.0')
self.local_nfvo = local_nfvo.LocalNfvo()
def _get_vnfpkg_or_vnfd(
self, type, state=fields.PackageOnboardingStateType.ONBOARDED):
if type == 'vnfd':
return vnf_package_vnfd.VnfPackageVnfd(
id=uuidutils.generate_uuid(),
package_uuid=SAMPLE_VNFPKG_ID, vnfd_id=SAMPLE_VNFD_ID,
vnf_provider='provider', vnf_product_name='product',
vnf_software_version='2.0', vnfd_version='3.3.1')
else:
return vnf_package.VnfPackage(
id=SAMPLE_VNFPKG_ID,
onboarding_state=state,
operational_state=fields.PackageOperationalStateType.DISABLED)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'get_by_id')
def test_onboarded_show(self, mock_vnfpackage, mock_vnfd):
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_vnfpackage.return_value = self._get_vnfpkg_or_vnfd('vnfpkg')
result = self.local_nfvo.onboarded_show(self.context, SAMPLE_VNFD_ID)
self.assertEqual(SAMPLE_VNFPKG_ID, result.id)
self.assertEqual(SAMPLE_VNFD_ID, result.vnfdId)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'get_by_id')
def test_onboarded_show_vnfpackage_error(self, mock_vnfpackage, mock_vnfd):
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
self.assertRaises(
sol_ex.VnfdIdNotFound, self.local_nfvo.onboarded_show,
self.context, SAMPLE_VNFD_ID)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'get_by_id')
def test_onboarded_show_error(self, mock_vnfpackage, mock_vnfd):
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_vnfpackage.return_value = self._get_vnfpkg_or_vnfd(
'vnfpkg', fields.PackageOnboardingStateType.CREATED)
self.assertRaises(
sol_ex.VnfdIdNotFound, self.local_nfvo.onboarded_show,
self.context, SAMPLE_VNFD_ID)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(os.path, 'isdir')
def test_get_csar_dir(self, mock_isdir, mock_vnfd):
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_isdir.return_value = True
result = self.local_nfvo.get_csar_dir(self.context, SAMPLE_VNFD_ID)
self.assertEqual(
f'/opt/stack/data/tacker/vnfpackage/{SAMPLE_VNFPKG_ID}', result)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_get_csar_dir_vnfd_error(self, mock_vnfd):
self.assertRaises(
sol_ex.VnfdIdNotFound, self.local_nfvo.get_csar_dir,
self.context, SAMPLE_VNFD_ID)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(os.path, 'isdir')
def test_get_csar_dir_path_error(self, mock_isdir, mock_vnfd):
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_isdir.return_value = False
self.assertRaises(
sol_ex.VnfdIdNotFound, self.local_nfvo.get_csar_dir,
self.context, SAMPLE_VNFD_ID)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
def test_get_vnfd(self, mock_dir):
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
result = self.local_nfvo.get_vnfd(self.context, SAMPLE_VNFD_ID)
self.assertEqual(SAMPLE_VNFD_ID, result.vnfd_id)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
def test_instantiate_grant(self, mock_image, mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.InstantiateVnfRequest.from_dict(_inst_req_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
# only set used members in the method
operation=fields.LcmOperationType.INSTANTIATE,
operationParams=req)
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)
self.local_nfvo.instantiate_grant(self.context, grant_req, grant_res)
result = grant_res.to_dict()
self.assertIsNotNone(result['addResources'])
self.assertEqual(mock_image.return_value.id, result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(local_nfvo.LocalNfvo, '_get_vim_info')
def test_instantiate_grant_no_vim_info(self, mock_vim_info, mock_dir):
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
mock_vim_info.return_value = None
self.assertRaises(
sol_ex.LocalNfvoGrantFailed, self.local_nfvo.instantiate_grant,
self.context, grant_req, grant_res)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
def test_instantiate_grant_no_image(
self, mock_image, mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.InstantiateVnfRequest.from_dict(_inst_req_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
# only set used members in the method
operation=fields.LcmOperationType.INSTANTIATE,
operationParams=req)
mock_image.return_value = Exception()
self.assertRaises(
sol_ex.LocalNfvoGrantFailed, self.local_nfvo.instantiate_grant,
self.context, grant_req, grant_res)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_change_vnfpkg_grant(self, mock_inst, mock_image,
mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
operation=fields.LcmOperationType.CHANGE_VNFPKG,
operationParams=req)
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)
req = objects.InstantiateVnfRequest.from_dict(
_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
mock_inst.return_value = inst
self.local_nfvo.change_vnfpkg_grant(self.context, grant_req, grant_res)
result = grant_res.to_dict()
self.assertEqual(mock_image.return_value.id, result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(local_nfvo.LocalNfvo, '_get_vim_info')
def test_change_vnfpkg_grant_no_vim_info(self, mock_vim_info, mock_dir):
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
mock_vim_info.return_value = None
self.assertRaises(
sol_ex.LocalNfvoGrantFailed, self.local_nfvo.change_vnfpkg_grant,
self.context, grant_req, grant_res)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_change_vnfpkg_grant_no_image(self, mock_inst, mock_image,
mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
grant_res = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=grant_req.vnfInstanceId,
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
operation=fields.LcmOperationType.CHANGE_VNFPKG,
operationParams=req)
req = objects.InstantiateVnfRequest.from_dict(
_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
mock_inst.return_value = inst
mock_image.return_value = Exception()
self.assertRaises(
sol_ex.LocalNfvoGrantFailed, self.local_nfvo.change_vnfpkg_grant,
self.context, grant_req, grant_res)
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_grant(self, mock_inst, mock_image, mock_lcmocc, mock_dir):
# instantiate
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.InstantiateVnfRequest.from_dict(_inst_req_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
# only set used members in the method
operation=fields.LcmOperationType.INSTANTIATE,
operationParams=req)
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)
grant_res = self.local_nfvo.grant(self.context, grant_req)
result = grant_res.to_dict()
self.assertIsNotNone(result['addResources'])
self.assertEqual(mock_image.return_value.id, result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
# change_vnfpkg
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
cur_dir = os.path.dirname(__file__)
sample_dir = os.path.join(cur_dir, "..", "samples")
mock_dir.return_value = os.path.join(sample_dir, "sample1")
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
operation=fields.LcmOperationType.CHANGE_VNFPKG,
operationParams=req
)
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)
req = objects.InstantiateVnfRequest.from_dict(
_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
mock_inst.return_value = inst
grant_res = self.local_nfvo.grant(self.context, grant_req)
result = grant_res.to_dict()
self.assertEqual(mock_image.return_value.id, result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'save')
def test_recv_inst_create_notification(
self, mock_save, mock_vnfpackage, mock_vnfd):
req = objects.InstantiateVnfRequest.from_dict(
_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='NOT_INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_vnfpackage.return_value = self._get_vnfpkg_or_vnfd('vnfpkg')
self.local_nfvo.recv_inst_create_notification(self.context, inst)
@mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.base.TackerPersistentObject, 'get_by_filter')
def test_recv_inst_delete_notification(
self, mock_inst, mock_save, mock_vnfpackage, mock_vnfd):
req = objects.InstantiateVnfRequest.from_dict(
_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req.vimConnectionInfo
)
mock_inst.return_value = None
mock_vnfd.return_value = self._get_vnfpkg_or_vnfd('vnfd')
mock_vnfpackage.return_value = self._get_vnfpkg_or_vnfd('vnfpkg')
self.local_nfvo.recv_inst_delete_notification(self.context, inst)
@mock.patch.object(local_nfvo.LocalNfvo, '_glance_delete_images')
@mock.patch.object(local_nfvo.LocalNfvo, '_update_vnf_pkg_usage_state')
def test_recv_lcmocc_notification(self, mock_delete_image, mock_update):
# terminate-processing
req_inst = objects.InstantiateVnfRequest.from_dict(_inst_req_example)
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED',
vimConnectionInfo=req_inst.vimConnectionInfo,
)
req = objects.TerminateVnfRequest(terminationType='FORCEFUL')
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.PROCESSING,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.TERMINATE,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)
# terminate-failed_temp
lcmocc.operationState = fields.LcmOperationStateType.FAILED_TEMP
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)
# terminate-completed
self.local_nfvo.inst_vim_info = {
inst.id: req_inst.vimConnectionInfo['vim1']
}
lcmocc.operationState = fields.LcmOperationStateType.COMPLETED
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)
# change_vnfpkg-processing
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.PROCESSING,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.CHANGE_VNFPKG,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)
# change_vnfpkg-failed_temp
lcmocc.operationState = fields.LcmOperationStateType.FAILED_TEMP
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)
# change_vnfpkg-completed
self.local_nfvo.inst_vnfd_id = {inst.id: req.vnfdId}
lcmocc.operationState = fields.LcmOperationStateType.COMPLETED
self.local_nfvo.recv_lcmocc_notification(self.context, lcmocc, inst)

View File

@ -0,0 +1,421 @@
# Copyright (C) 2022 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 requests
from unittest import mock
from oslo_utils import uuidutils
from tacker import context
from tacker.sol_refactored.api import api_version
from tacker.sol_refactored.common import config
from tacker.sol_refactored.common import http_client
from tacker.sol_refactored.common import subscription_utils as subsc_utils
from tacker.sol_refactored.common import vnfd_utils
from tacker.sol_refactored.nfvo import local_nfvo
from tacker.sol_refactored.nfvo import nfvo_client
from tacker.sol_refactored import objects
from tacker.tests import base
CONF = config.CONF
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
_vnfpkg_body_example = {
"id": uuidutils.generate_uuid(),
"vnfdId": SAMPLE_VNFD_ID,
"vnfProvider": "Company",
"vnfProductName": "Sample VNF",
"vnfSoftwareVersion": "1.0",
"vnfdVersion": "1.0",
"onboardingState": "ONBOARDED",
"operationalState": "ENABLED",
"usageState": "NOT_IN_USE"
}
_grant_res = {
'id': 'b94d05c9-eb45-4855-9132-20e1d3e7cecf',
'vnfInstanceId': '2d004394-d0f0-406d-845a-2b148f91039a',
'vnfLcmOpOccId': '34da9ba7-6ab1-4d8d-a68a-68892e56642c',
'zones': [{
'id': 'b4eba78c-e957-4e66-8bd7-14822f954413',
'zoneId': 'nova'
}],
'addResources': [{
'resourceDefinitionId': '6396a2a1-7e36-49bd-8fff-2d46394a6b29',
'zoneId': 'b4eba78c-e957-4e66-8bd7-14822f954413'
}, {
'resourceDefinitionId': 'VDU1_CP1-6396a2a1-7e36-49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': 'VDU1_CP2-6396a2a1-7e36-49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': 'VDU1_CP3-6396a2a1-7e36-49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': 'VDU1_CP5-6396a2a1-7e36-49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': 'VDU1_CP4-6396a2a1-7e36-49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': 'VirtualStorage-6396a2a1-7e36-'
'49bd-8fff-2d46394a6b29'
}, {
'resourceDefinitionId': '39e0af93-aba5-4a15-9231-cdaa4149738e',
'zoneId': 'b4eba78c-e957-4e66-8bd7-14822f954413'
}, {
'resourceDefinitionId': 'VDU1_CP1-39e0af93-aba5-4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': 'VDU1_CP2-39e0af93-aba5-4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': 'VDU1_CP3-39e0af93-aba5-4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': 'VDU1_CP5-39e0af93-aba5-4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': 'VDU1_CP4-39e0af93-aba5-4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': 'VirtualStorage-39e0af93-aba5-'
'4a15-9231-cdaa4149738e'
}, {
'resourceDefinitionId': '8a3ab83f-187c-4feb-b1b5-a6bf587130fa',
'zoneId': 'b4eba78c-e957-4e66-8bd7-14822f954413'
}, {
'resourceDefinitionId': 'VDU1_CP1-8a3ab83f-187c-4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': 'VDU1_CP2-8a3ab83f-187c-4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': 'VDU1_CP3-8a3ab83f-187c-4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': 'VDU1_CP5-8a3ab83f-187c-4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': 'VDU1_CP4-8a3ab83f-187c-4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': 'VirtualStorage-8a3ab83f-187c-'
'4feb-b1b5-a6bf587130fa'
}, {
'resourceDefinitionId': '3f2385fa-3f13-436d-b93a-47c62ef237e0',
'zoneId': 'b4eba78c-e957-4e66-8bd7-14822f954413'
}, {
'resourceDefinitionId': 'VDU2_CP5-3f2385fa-3f13-436d-b93a-47c62ef237e0'
}, {
'resourceDefinitionId': 'VDU2_CP2-3f2385fa-3f13-436d-b93a-47c62ef237e0'
}, {
'resourceDefinitionId': 'VDU2_CP1-3f2385fa-3f13-436d-b93a-47c62ef237e0'
}, {
'resourceDefinitionId': 'VDU2_CP3-3f2385fa-3f13-436d-b93a-47c62ef237e0'
}, {
'resourceDefinitionId': 'VDU2_CP4-3f2385fa-3f13-436d-b93a-47c62ef237e0'
}, {
'resourceDefinitionId': 'a411a968-c00b-4d46-8553-a37f3537391e'
}, {
'resourceDefinitionId': 'f06ba7cf-f5af-4856-8d3a-56b331d1b9a5'
}],
'vimAssets': {
'softwareImages': [{
'vnfdSoftwareImageId': 'VDU2',
'vimSoftwareImageId': '44fd5841-ce98-4d54-a828-6ef51f941c8a'
}, {
'vnfdSoftwareImageId': 'VirtualStorage',
'vimSoftwareImageId': 'image-1.0.0-x86_64-disk'
}]
}
}
_inst_grant_req_example = {
"vnfInstanceId": "2d004394-d0f0-406d-845a-2b148f91039a",
"vnfLcmOpOccId": "34da9ba7-6ab1-4d8d-a68a-68892e56642c",
"vnfdId": "b1bb0ce7-ebca-4fa7-95ed-4840d7000000",
"flavourId": "simple",
"operation": "INSTANTIATE",
"isAutomaticInvocation": False,
"instantiationLevelId": "instantiation_level_2",
"addResources": [{
"id": "6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-6396a2a1-7e36-49bd-8fff-2d46394a6b29",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-39e0af93-aba5-4a15-9231-cdaa4149738e",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "COMPUTE",
"resourceTemplateId": "VDU1"
}, {
"id": "VDU1_CP1-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP1"
}, {
"id": "VDU1_CP2-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP2"
}, {
"id": "VDU1_CP3-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP3"
}, {
"id": "VDU1_CP5-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP5"
}, {
"id": "VDU1_CP4-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "LINKPORT",
"resourceTemplateId": "VDU1_CP4"
}, {
"id": "VirtualStorage-8a3ab83f-187c-4feb-b1b5-a6bf587130fa",
"type": "STORAGE",
"resourceTemplateId": "VirtualStorage"
}, {
"id": "3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "COMPUTE",
"resourceTemplateId": "VDU2"
}, {
"id": "VDU2_CP5-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP5"
}, {
"id": "VDU2_CP2-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP2"
}, {
"id": "VDU2_CP1-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP1"
}, {
"id": "VDU2_CP3-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP3"
}, {
"id": "VDU2_CP4-3f2385fa-3f13-436d-b93a-47c62ef237e0",
"type": "LINKPORT",
"resourceTemplateId": "VDU2_CP4"
}, {
"id": "a411a968-c00b-4d46-8553-a37f3537391e",
"type": "VL",
"resourceTemplateId": "internalVL2"
}, {
"id": "f06ba7cf-f5af-4856-8d3a-56b331d1b9a5",
"type": "VL",
"resourceTemplateId": "internalVL3"
}],
"placementConstraints": [{
"affinityOrAntiAffinity": "ANTI_AFFINITY",
"scope": "NFVI_NODE",
"resource": [{
"idType": "GRANT",
"resourceId": "6396a2a1-7e36-49bd-8fff-2d46394a6b29"
}, {
"idType": "GRANT",
"resourceId": "39e0af93-aba5-4a15-9231-cdaa4149738e"
}, {
"idType": "GRANT",
"resourceId": "8a3ab83f-187c-4feb-b1b5-a6bf587130fa"
}, {
"idType": "GRANT",
"resourceId": "3f2385fa-3f13-436d-b93a-47c62ef237e0"
}]
}],
"_links": {
"vnfLcmOpOcc": {
"href": "http://127.0.0.1:9890/vnflcm/v2/vnf_lcm_op_occs/"
"34da9ba7-6ab1-4d8d-a68a-68892e56642c"
},
"vnfInstance": {
"href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/"
"2d004394-d0f0-406d-845a-2b148f91039a"
}
}
}
_lcmocc_inst_value = {
'id': 'test-1',
'vnfInstanceId': 'instance-1',
'operation': 'INSTANTIATE',
'operationState': 'COMPLETED',
'isAutomaticInvocation': False,
'startTime': '2021-01-23 13:41:03+00:00'
}
class TestNfvoClient(base.BaseTestCase):
def setUp(self):
super(TestNfvoClient, self).setUp()
objects.register_all()
self.context = context.get_admin_context()
CONF.vnf_package.vnf_package_csar_path = (
'/opt/stack/data/tacker/vnfpackage/')
self.context.api_version = api_version.APIVersion('2.0.0')
self.nfvo_client = nfvo_client.NfvoClient()
self.nfvo_client.endpoint = 'http://127.0.0.1:9990'
auth_handle = http_client.OAuth2AuthHandle(
self.nfvo_client.endpoint,
'http://127.0.0.1:9990/token',
'test',
'test'
)
self.nfvo_client.client = http_client.HttpClient(auth_handle)
self.nfvo_client.grant_api_version = '1.4.0'
self.nfvo_client.vnfpkgm_api_version = '2.1.0'
@mock.patch.object(local_nfvo.LocalNfvo, 'onboarded_show')
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_get_vnf_package_info_vnfd(
self, mock_request, mock_onboarded_show):
# local nfvo
self.nfvo_client.is_local = True
mock_onboarded_show.return_value = vnfd_utils.Vnfd(
vnfd_id=SAMPLE_VNFD_ID)
result = self.nfvo_client.get_vnf_package_info_vnfd(
self.context, SAMPLE_VNFD_ID)
self.assertEqual(SAMPLE_VNFD_ID, result.vnfd_id)
# external nfvo
self.nfvo_client.is_local = False
mock_request.return_value = (requests.Response(), _vnfpkg_body_example)
result = self.nfvo_client.get_vnf_package_info_vnfd(
self.context, SAMPLE_VNFD_ID)
self.assertEqual(SAMPLE_VNFD_ID, result.vnfdId)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_onboarded_show_vnfd(self, mock_request):
# local nfvo
self.nfvo_client.is_local = True
result = self.nfvo_client.onboarded_show_vnfd(
self.context, SAMPLE_VNFD_ID)
self.assertIsNone(result)
# external nfvo
self.nfvo_client.is_local = False
mock_request.return_value = (requests.Response(), 'test')
result = self.nfvo_client.onboarded_show_vnfd(
self.context, SAMPLE_VNFD_ID)
self.assertEqual('test', result)
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_onboarded_package_content(self, mock_request):
# local nfvo
self.nfvo_client.is_local = True
result = self.nfvo_client.onboarded_package_content(
self.context, SAMPLE_VNFD_ID)
self.assertIsNone(result)
# external nfvo
self.nfvo_client.is_local = False
mock_request.return_value = (requests.Response(), 'test')
result = self.nfvo_client.onboarded_package_content(
self.context, SAMPLE_VNFD_ID)
self.assertEqual('test', result)
@mock.patch.object(local_nfvo.LocalNfvo, 'grant')
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_grant(self, mock_request, mock_grant):
# local nfvo
self.nfvo_client.is_local = True
mock_grant.return_value = objects.GrantV1.from_dict(_grant_res)
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
grant_res = self.nfvo_client.grant(self.context, grant_req)
result = grant_res.to_dict()
self.assertIsNotNone(result['addResources'])
self.assertEqual('44fd5841-ce98-4d54-a828-6ef51f941c8a', result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
# external nfvo
self.nfvo_client.is_local = False
mock_request.return_value = (requests.Response(), _grant_res)
grant_res = self.nfvo_client.grant(self.context, grant_req)
result = grant_res.to_dict()
self.assertIsNotNone(result['addResources'])
self.assertEqual('44fd5841-ce98-4d54-a828-6ef51f941c8a', result[
'vimAssets']['softwareImages'][0]['vimSoftwareImageId'])
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
@mock.patch.object(subsc_utils, 'send_notification')
@mock.patch.object(local_nfvo.LocalNfvo, 'recv_inst_create_notification')
def test_send_inst_create_notification(
self, mock_recv, mock_send, mock_subscs):
self.nfvo_client.is_local = True
inst = objects.VnfInstanceV2(id='test-instance')
mock_subscs.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
self.nfvo_client.send_inst_create_notification(
self.context, inst, 'http://127.0.0.1:9890')
self.assertEqual(1, mock_recv.call_count)
self.assertEqual(1, mock_send.call_count)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
@mock.patch.object(subsc_utils, 'send_notification')
@mock.patch.object(local_nfvo.LocalNfvo, 'recv_inst_delete_notification')
def test_send_inst_delete_notification(
self, mock_recv, mock_send, mock_subscs):
self.nfvo_client.is_local = True
inst = objects.VnfInstanceV2(id='test-instance')
mock_subscs.return_value = [objects.LccnSubscriptionV2(id='subsc-1')]
self.nfvo_client.send_inst_delete_notification(
self.context, inst, 'http://127.0.0.1:9890')
self.assertEqual(1, mock_recv.call_count)
self.assertEqual(1, mock_send.call_count)
@mock.patch.object(objects.base.TackerPersistentObject, 'get_all')
@mock.patch.object(subsc_utils, 'send_notification')
@mock.patch.object(local_nfvo.LocalNfvo, 'recv_lcmocc_notification')
def test_send_lcmocc_notification(self, mock_recv, mock_send, mock_subscs):
inst = objects.VnfInstanceV2(id='test-instance')
lcmocc = objects.VnfLcmOpOccV2.from_dict(_lcmocc_inst_value)
mock_subscs.return_value = [objects.LccnSubscriptionV2(
id='subsc-1', verbosity='FULL')]
self.nfvo_client.send_lcmocc_notification(
self.context, lcmocc, inst, 'http://127.0.0.1:9890')
self.assertEqual(1, mock_recv.call_count)
self.assertEqual(1, mock_send.call_count)

View File

@ -0,0 +1,122 @@
heat_template_version: 2013-05-23
description: 'Simple Base HOT for Sample VNF'
parameters:
nfv:
type: json
resources:
VDU1_scale_group:
type: OS::Heat::AutoScalingGroup
properties:
min_size: 1
max_size: 3
desired_capacity: 1
resource:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VirtualStorage, vcImageId ] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet ]}
net3: { get_resource: internalVL1 }
net4: { get_resource: internalVL2 }
net5: { get_resource: internalVL3 }
net6: { get_param: { nfv, CP, VDU1_CP6, network } }
net7: { get_param: [ nfv, CP, VDU1_CP7 ] }
net8: { get_param: [ nfv_1, CP, VDU1_CP8, network ] }
affinity: { get_resource: nfvi_node_affinity }
VDU2:
type: OS::Nova::Server
properties:
flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU2, vcImageId] }
networks:
- port:
get_resource: VDU2_CP1
- port:
get_resource: VDU2_CP2
- port:
get_resource: VDU2_CP3
- port:
get_resource: VDU2_CP4
- port:
get_resource: VDU2_CP5
scheduler_hints:
group: {get_resource: nfvi_node_affinity }
# extVL with FixedIP
VDU2_CP1:
type: OS::Neutron::Port
properties:
network: { get_param: [ nfv, CP, VDU2_CP1, network ] }
fixed_ips:
- ip_address: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, ip_address]}
# extvVL with FixedIP and Subnet
VDU2_CP2:
type: OS::Neutron::Port
properties:
network: { get_param: [ nfv, CP, VDU2_CP2, network ] }
fixed_ips:
- ip_address: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, ip_address]}
subnet: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, subnet]}
VDU2_CP3:
type: OS::Neutron::Port
properties:
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
network: { get_resource: internalVL1 }
VDU2_CP4:
type: OS::Neutron::Port
properties:
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
network: { get_resource: internalVL2 }
VDU2_CP5:
type: OS::Neutron::Port
properties:
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
network: { get_resource: internalVL3 }
# delete the following lines when extmanagedVLs are specified in instantiatevnfrequest
internalVL1:
type: OS::Neutron::Net
internalVL2:
type: OS::Neutron::Net
internalVL3:
type: OS::Neutron::Net
internalVL1_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: internalVL1
cidr: 192.168.3.0/24
internalVL2_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: internalVL2
cidr: 192.168.4.0/24
internalVL3_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: internalVL3
cidr: 192.168.5.0/24
nfvi_node_affinity:
type: OS::Nova::ServerGroup
properties:
name: nfvi_node_affinity
policies: [ 'affinity' ]
outputs: {}

View File

@ -11,18 +11,22 @@ resources:
properties:
min_size: 1
max_size: 3
desired_capacity: 1
desired_capacity: { get_param: [ nfv, VDU, VDU1, desired_capacity ] }
resource:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VirtualStorage, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet ]}
net3: { get_resource: internalVL1 }
net4: { get_resource: internalVL2 }
net5: { get_resource: internalVL3 }
net6: { get_param: { nfv, CP, VDU1_CP6, network } }
net7: { get_param: [ nfv, CP, VDU1_CP7 ] }
net8: { get_param: [ nfv_1, CP, VDU1_CP8, network ] }
affinity: { get_resource: nfvi_node_affinity }
VDU2:

View File

@ -0,0 +1,310 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- v2_sample2_types.yaml
topology_template:
inputs:
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: error
requirements:
virtual_link_external1_1: [ VDU1_CP1, virtual_link ]
virtual_link_external1_2: [ VDU2_CP1, virtual_link ]
virtual_link_external2_1: [ VDU1_CP2, virtual_link ]
virtual_link_external2_2: [ VDU2_CP2, virtual_link ]
node_templates:
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
requested_additional_capabilities:
properties:
requested_additional_capability_name: m1.tiny
support_mandatory: true
target_performance_parameters:
entry_schema: test
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 3 GB
requirements:
- virtual_storage: VirtualStorage
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
instantiate_start:
implementation:
instantiate_end:
implementation: sample-script
terminate_start:
implementation: error-script
terminate_end:
implementation: sample-script
scale_start: [ ]
artifacts:
sample-script:
description: Sample script
type: tosca.artifacts.Implementation.Python
file:
error-script:
description: Sample script
type: tosca.artifacts.Implementation.Error
file: 'test/sample_script.sh'
VDU2:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
requested_additional_capabilities:
properties:
requested_additional_capability_name: m1.tiny
support_mandatory: true
target_performance_parameters:
entry_schema: test
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 3 GB
requirements:
- virtual_storage: VirtualStorage-2
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 1gb GB
rdma_enabled: true
VirtualStorage-2:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 1gb GB
rdma_enabled: true
sw_image_data:
name: image-1.0.0-x86_64-disk
version: '1.0.0'
checksum:
algorithm: sha-256
hash: a8dd75ecffd4cdd96072d60c2237b448e0c8b2bc94d57f10fdbc8c481d9005b8
container_format: bare
disk_format: qcow2
min_disk: 0 GB
min_ram: 256 MB
size: 12 GB
VDU1_CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
requirements:
- virtual_binding: VDU1
VDU1_CP2:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 1
requirements:
- virtual_binding: VDU1
VDU1_CP3:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL1
VDU1_CP4:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 3
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL2
VDU1_CP5:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 4
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL3
VDU2_CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
requirements:
- virtual_binding: VDU2
VDU2_CP2:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 1
requirements:
- virtual_binding: VDU2
VDU2_CP3:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL1
VDU2_CP4:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 3
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL2
VDU2_CP5:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 4
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL3
internalVL1:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: External Managed Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 192.168.3.0/24
internalVL2:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: External Managed Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 192.168.4.0/24
internalVL3:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 192.168.5.0/24
groups:
affinityOrAntiAffinityGroup1:
type: tosca.groups.nfv.PlacementGroup
members: [ VDU1, VDU2 ]
policies:
policy_antiaffinity_group:
type: tosca.policies.nfv.AntiAffinityRule
targets: [ affinityOrAntiAffinityGroup1 ]
properties:
scope: nfvi_node
policy_affinity_group:
type: tosca.policies.nfv.AffinityRule
targets: [ affinityOrAntiAffinityGroup1 ]
properties:
scope: error
policy_affinity_group_2:
type: tosca.policies.nfv.AffinityRule
targets: [VDU3]
properties:
scope: zone

View File

@ -2,3 +2,4 @@ TOSCA-Meta-File-Version: 1.0
CSAR-Version: 1.1
Created-by: Onboarding portal
Entry-Definitions: Definitions/v2_sample2_top.vnfd.yaml
ETSI-Entry-Manifest: manifest.mf

View File

@ -0,0 +1,7 @@
Source: Scripts/install.sh
Algorithm: SHA-256
Hash: 27bbdb25d8f4ed6d07d6f6581b86515e8b2f0059b236ef7b6f50d6674b34f02a
Source: Files/kubernetes/deployment.yaml
Algorithm: SHA-256
Hash: e23cc3433835cea32ce790b4823313dc6d0744dce02e27b1b339c87ee993b8c2