Merge "FT for multi tenant policy in LCM"

This commit is contained in:
Zuul 2022-03-10 21:58:55 +00:00 committed by Gerrit Code Review
commit 61cb57a8b9
21 changed files with 1623 additions and 9 deletions

View File

@ -275,6 +275,15 @@
controller-tacker:
tox_envlist: dsvm-functional-sol-v2
- job:
name: tacker-functional-devstack-multinode-sol-multi-tenant
parent: tacker-functional-devstack-multinode-sol
description: |
Multinodes job for SOL Multi tenant devstack-based functional tests
host-vars:
controller-tacker:
tox_envlist: dsvm-functional-sol-multi-tenant
- job:
name: tacker-functional-devstack-multinode-sol-separated-nfvo
parent: tacker-functional-devstack-multinode-sol
@ -522,3 +531,4 @@
- tacker-functional-devstack-multinode-sol-kubernetes
- tacker-functional-devstack-multinode-libs-master
- tacker-functional-devstack-multinode-sol-v2
- tacker-functional-devstack-multinode-sol-multi-tenant

View File

@ -163,7 +163,7 @@ def _vnf_lcm_subscriptions_show(context, subscriptionId):
sql = text(
"select "
"t1.id,t1.callback_uri,t2.filter "
"t1.id,t1.callback_uri,t1.tenant_id,t2.filter "
"from vnf_lcm_subscriptions t1, "
"(select distinct subscription_uuid,filter from vnf_lcm_filters) t2 "
"where t1.id = t2.subscription_uuid "

View File

@ -0,0 +1,99 @@
heat_template_version: 2013-05-23
description: 'Simple Base HOT for Sample VNF'
parameters:
nfv:
type: json
resources:
VDU1_scale:
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, flavor ] }
image: { get_param: [ nfv, VDU, VirtualStorage, image ] }
zone: { get_param: [ nfv, vdu, VDU1, zone ] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }
net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 }
VDU1_scale_scale_out:
type: OS::Heat::ScalingPolicy
properties:
scaling_adjustment: 1
auto_scaling_group_id:
get_resource: VDU1_scale
adjustment_type: change_in_capacity
VDU1_scale_scale_in:
type: OS::Heat::ScalingPolicy
properties:
scaling_adjustment: -1
auto_scaling_group_id:
get_resource: VDU1_scale
adjustment_type: change_in_capacity
VDU2_scale:
type: OS::Heat::AutoScalingGroup
depends_on: VDU1_scale
properties:
min_size: 2
max_size: 2
desired_capacity: 2
resource:
type: VDU2.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU2, flavor ] }
image: { get_param: [ nfv, VDU, VDU2, image ] }
zone: { get_param: [ nfv, vdu, VDU2, zone ] }
net1: { get_param: [ nfv, CP, VDU2_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU2_CP2, network ] }
net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 }
VDU2_scale_scale_out:
type: OS::Heat::ScalingPolicy
properties:
scaling_adjustment: 1
auto_scaling_group_id:
get_resource: VDU2_scale
adjustment_type: change_in_capacity
VDU2_scale_scale_in:
type: OS::Heat::ScalingPolicy
properties:
scaling_adjustment: -1
auto_scaling_group_id:
get_resource: VDU2_scale
adjustment_type: change_in_capacity
extmanageNW_1:
type: OS::Neutron::Net
extmanageNW_2:
type: OS::Neutron::Net
internalNW_1:
type: OS::Neutron::Net
extmanageNW_1_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: extmanageNW_1
cidr: 192.168.3.0/24
extmanageNW_2_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: extmanageNW_2
cidr: 192.168.4.0/24
internalNW_1_subnet:
type: OS::Neutron::Subnet
properties:
ip_version: 4
network:
get_resource: internalNW_1
cidr: 192.168.5.0/24
outputs: {}

View File

@ -0,0 +1,72 @@
heat_template_version: 2013-05-23
description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
type: string
zone:
type: string
net1:
type: string
net2:
type: string
net3:
type: string
net4:
type: string
net5:
type: string
resources:
VDU1:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
name: VDU1
block_device_mapping_v2: [{"volume_id": { get_resource: VirtualStorage }}]
networks:
- port:
get_resource: VDU1_CP1
- port:
get_resource: VDU1_CP2
- port:
get_resource: VDU1_CP3
- port:
get_resource: VDU1_CP4
- port:
get_resource: VDU1_CP5
availability_zone: { get_param: zone }
VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
size: 1
volume_type: { get_resource: multi }
multi:
type: OS::Cinder::VolumeType
properties:
name: { get_resource: VDU1_CP1 }
metadata: { multiattach: "<is> True" }
VDU1_CP1:
type: OS::Neutron::Port
properties:
network: { get_param: net1 }
VDU1_CP2:
type: OS::Neutron::Port
properties:
network: { get_param: net2 }
VDU1_CP3:
type: OS::Neutron::Port
properties:
network: { get_param: net3 }
VDU1_CP4:
type: OS::Neutron::Port
properties:
network: { get_param: net4 }
VDU1_CP5:
type: OS::Neutron::Port
properties:
network: { get_param: net5 }

View File

@ -0,0 +1,61 @@
heat_template_version: 2013-05-23
description: 'VDU2 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
type: string
zone:
type: string
net1:
type: string
net2:
type: string
net3:
type: string
net4:
type: string
net5:
type: string
resources:
VDU2:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
name: VDU2
image: { get_param: image }
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
availability_zone: { get_param: zone }
VDU2_CP1:
type: OS::Neutron::Port
properties:
network: { get_param: net1 }
VDU2_CP2:
type: OS::Neutron::Port
properties:
network: { get_param: net2 }
VDU2_CP3:
type: OS::Neutron::Port
properties:
network: { get_param: net3 }
VDU2_CP4:
type: OS::Neutron::Port
properties:
network: errornetwork
VDU2_CP5:
type: OS::Neutron::Port
properties:
network: errornetwork

View File

@ -0,0 +1,403 @@
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
- helloworld3_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: simple
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:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
instantiate: []
instantiate_start: []
instantiate_end: []
terminate: []
terminate_start: []
terminate_end: []
modify_information: []
modify_information_start: []
modify_information_end: []
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
VDU2:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU2
description: VDU2 compute node
vdu_profile:
min_number_of_instances: 2
max_number_of_instances: 2
sw_image_data:
name: cirros-0.5.2-x86_64-disk
version: '0.5.2'
checksum:
algorithm: sha-256
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
container_format: bare
disk_format: qcow2
min_disk: 0 GB
min_ram: 256 MB
size: 12 GB
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
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 1 GB
rdma_enabled: true
sw_image_data:
name: cirros-0.5.2-x86_64-disk
version: '0.5.2'
checksum:
algorithm: sha-256
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
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: 33.33.0.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: 33.34.0.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: 33.35.0.0/24
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
VDU1_scale:
name: VDU1_scale
description: VDU1 scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- VDU1_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU1 ]
- VDU2_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 2
targets: [ VDU2 ]
- VDU1_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: VDU1_scale
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU1 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
VDU1_scale:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
VDU1_scale:
scale_level: 2
default_level: instantiation_level_1
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
- VDU2_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 2
instantiation_level_2:
number_of_instances: 2
targets: [ VDU2 ]
- internalVL1_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL1 ]
- internalVL2_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL2 ]
- internalVL3_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL3 ]
- policy_antiaffinity_vdu1:
type: tosca.policies.nfv.AntiAffinityRule
targets: [ VDU1 ]
properties:
scope: zone
- policy_antiaffinity_vdu2:
type: tosca.policies.nfv.AntiAffinityRule
targets: [ VDU2 ]
properties:
scope: zone

View File

@ -0,0 +1,31 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
- helloworld3_df_simple.yaml
topology_template:
inputs:
selected_flavour:
type: string
description: VNF deployment flavour selected by the consumer. It is provided in the API
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_id: { get_input: selected_flavour }
descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
provider: Company
product_name: Sample VNF
software_version: '1.0'
descriptor_version: '1.0'
vnfm_info:
- Tacker
requirements:
#- virtual_link_external # mapped in lower-level templates
#- virtual_link_internal # mapped in lower-level templates

View File

@ -0,0 +1,55 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: VNF type definition
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
node_types:
company.provider.VNF:
derived_from: tosca.nodes.nfv.VNF
properties:
descriptor_id:
type: string
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ]
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
descriptor_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
provider:
type: string
constraints: [ valid_values: [ 'Company' ] ]
default: 'Company'
product_name:
type: string
constraints: [ valid_values: [ 'Sample VNF' ] ]
default: 'Sample VNF'
software_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
vnfm_info:
type: list
entry_schema:
type: string
constraints: [ valid_values: [ Tacker ] ]
default: [ Tacker ]
flavour_id:
type: string
constraints: [ valid_values: [ simple ] ]
default: simple
flavour_description:
type: string
default: "falvour"
requirements:
- virtual_link_external1:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_external2:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_internal:
capability: tosca.capabilities.nfv.VirtualLinkable
interfaces:
Vnflcm:
type: tosca.interfaces.nfv.Vnflcm

View File

@ -0,0 +1,4 @@
TOSCA-Meta-File-Version: 1.0
CSAR-Version: 1.1
Created-by: Onboarding portal
Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml

View File

@ -0,0 +1,35 @@
#
# 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 tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
import tacker.vnfm.lcm_user_data.utils as UserDataUtil
class SampleUserData(AbstractUserData):
@staticmethod
def instantiate(base_hot_dict=None,
vnfd_dict=None,
inst_req_info=None,
grant_info=None):
api_param = UserDataUtil.get_diff_base_hot_param_from_api(
base_hot_dict, inst_req_info)
initial_param_dict = \
UserDataUtil.create_initial_param_server_port_dict(
base_hot_dict)
vdu_flavor_dict = \
UserDataUtil.create_vdu_flavor_capability_name_dict(vnfd_dict)
vdu_image_dict = UserDataUtil.create_sw_image_dict(vnfd_dict)
cpd_vl_dict = UserDataUtil.create_network_dict(
inst_req_info, initial_param_dict)
final_param_dict = UserDataUtil.create_final_param_dict(
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
return {**final_param_dict, **api_param}

View File

@ -454,10 +454,12 @@ class BaseTackerTest(base.BaseTestCase):
return vnf_instance, tosca_dict
def _list_op_occs(self, filter_string=''):
def _list_op_occs(self, filter_string='', http_client=None):
if http_client is None:
http_client = self.http_client
show_url = os.path.join(
self.base_vnf_lcm_op_occs_url)
resp, response_body = self.http_client.do_request(
resp, response_body = http_client.do_request(
show_url + filter_string, "GET")
return resp, response_body

View File

@ -206,6 +206,8 @@ class FakeServerManager(object):
"""Manager class to manage dummy server setting and control"""
SERVER_PORT = 9990
SERVER_PORT_T1 = 9995
SERVER_PORT_T2 = 9996
SERVER_INVOKE_CHECK_INTERVAL = 10
def __init__(self):

View File

@ -209,6 +209,12 @@ def _create_instantiate_vnf_request_body(flavour_id,
class BaseVnfLcmTest(base.BaseTackerTest):
is_setup_error = False
# NOTE: If prepare_fake_server is set(by default) then this base
# class will prepare(create and start) the fake http server which
# takes time and can add up more time in gate CI. Any child class
# can set it false. For example, BaseVnfLcmMultiTenantTest which
# create their own servers for two different tenants.
prepare_fake_server = True
@classmethod
def setUpClass(cls):
@ -217,12 +223,14 @@ class BaseVnfLcmTest(base.BaseTackerTest):
we set up fake NFVO server for test at here.
'''
super(BaseVnfLcmTest, cls).setUpClass()
if cls.prepare_fake_server:
cls._prepare_start_fake_server(FAKE_SERVER_MANAGER,
FAKE_SERVER_PORT)
@classmethod
def tearDownClass(cls):
super(BaseVnfLcmTest, cls).tearDownClass()
if cls.prepare_fake_server:
FAKE_SERVER_MANAGER.stop_server()
def setUp(self):
@ -231,8 +239,8 @@ class BaseVnfLcmTest(base.BaseTackerTest):
if self.is_setup_error:
self.fail("Faild, not exists pre-registered image.")
callback_url = os.path.join(
MOCK_NOTIFY_CALLBACK_URL,
if self.prepare_fake_server:
callback_url = os.path.join(MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
self._clear_history_and_set_callback(FAKE_SERVER_MANAGER,
callback_url)

View File

@ -0,0 +1,118 @@
#
# 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 tacker.tests.functional import base
from tacker.tests.functional.common.fake_server import FakeServerManager
from tacker.tests.functional.sol.vnflcm import base as vnflcm_base
FAKE_SERVER_MANAGER_T1 = FakeServerManager()
FAKE_SERVER_PORT_T1 = 9995
FAKE_SERVER_MANAGER_T2 = FakeServerManager()
FAKE_SERVER_PORT_T2 = 9996
class BaseVnfLcmMultiTenantTest(vnflcm_base.BaseVnfLcmTest):
prepare_fake_server = False
@classmethod
def setUpClass(cls):
super(BaseVnfLcmMultiTenantTest, cls).setUpClass()
result = cls.get_openstack_client_session(
vim_conf_file='local-tenant1-vim.yaml')
cls.client_tenant1 = result.get('client')
cls.http_client_tenant1 = result.get('http_client')
cls.h_client_tenant1 = result.get('h_client')
cls.glance_client_tenant1 = result.get('glance_client')
result = cls.get_openstack_client_session(
vim_conf_file='local-tenant2-vim.yaml')
cls.client_tenant2 = result.get('client')
cls.http_client_tenant2 = result.get('http_client')
cls.h_client_tenant2 = result.get('h_client')
cls.glance_client_tenant2 = result.get('glance_client')
cls.tacker_client_t1 = base.BaseTackerTest.tacker_http_client(
'local-tenant1-vim.yaml')
cls.tacker_client_t2 = base.BaseTackerTest.tacker_http_client(
'local-tenant2-vim.yaml')
# Set up fake NFVO server for tenant1 and tenant2
cls.servers = {FAKE_SERVER_PORT_T1: FAKE_SERVER_MANAGER_T1,
FAKE_SERVER_PORT_T2: FAKE_SERVER_MANAGER_T2}
# NOTE: Create both server in parallel, otherwise they can
# cause (especially server start) job timeout.
for port, manager in cls.servers.items():
cls._prepare_start_fake_server(manager, port)
@classmethod
def tearDownClass(cls):
super(BaseVnfLcmMultiTenantTest, cls).tearDownClass()
for _, manager in cls.servers.items():
manager.stop_server()
def setUp(self):
super(BaseVnfLcmMultiTenantTest, self).setUp()
self.base_url = "/vnfpkgm/v1/vnf_packages"
callback_url = os.path.join(
vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
self._clear_history_and_set_callback(FAKE_SERVER_MANAGER_T1,
callback_url)
self._clear_history_and_set_callback(FAKE_SERVER_MANAGER_T2,
callback_url)
vim_list = self.client.list_vims()
self.vim_tenant1 = self.get_vim(vim_list, 'VIM_TEST')
if not self.vim_tenant1:
assert False, "vim_list is Empty: Tenant VIM is missing"
self.vim_tenant2 = self.get_vim(vim_list, 'VIM_DEMO')
if not self.vim_tenant2:
assert False, "vim_list is Empty: Tenant VIM is missing"
result = self._create_network_settings()
self.ext_networks_tenant1 = result.get('ext_networks')
self.ext_vl_tenant1 = result.get('ext_vl')
self.ext_mngd_networks_tenant1 = result.get('ext_mngd_networks')
self.ext_link_ports_tenant1 = result.get('ext_link_ports')
self.ext_subnets_tenant1 = result.get('ext_subnets')
self.changed_ext_networks_tenant1 = result.get(
'changed_ext_networks')
self.changed_ext_subnets_tenant1 = result.get(
'changed_ext_subnets')
result = self._create_network_settings()
self.ext_networks_tenant2 = result.get('ext_networks')
self.ext_vl_tenant2 = result.get('ext_vl')
self.ext_mngd_networks_tenant2 = result.get('ext_mngd_networks')
self.ext_link_ports_tenant2 = result.get('ext_link_ports')
self.ext_subnets_tenant2 = result.get('ext_subnets')
self.changed_ext_networks_tenant2 = result.get(
'changed_ext_networks')
self.changed_ext_subnets_tenant2 = result.get(
'changed_ext_subnets')
@classmethod
def get_openstack_client_session(cls, vim_conf_file):
client = base.BaseTackerTest.tackerclient(vim_conf_file)
http_client = base.BaseTackerTest.tacker_http_client(vim_conf_file)
h_client = base.BaseTackerTest.heatclient(vim_conf_file)
glance_client = base.BaseTackerTest.glanceclient(vim_conf_file)
return {'client': client,
'http_client': http_client,
'h_client': h_client,
'glance_client': glance_client}

View File

@ -0,0 +1,252 @@
#
# 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 tacker.tests import uuidsentinel
class Subscription:
@staticmethod
def make_create_request_body(callback_uri):
"""Parameter selection policy.
Set all Notification types and all life cycle types for filter.
Specify OAuth2 for authentication do not set authentication.
Args:
callback_uri (str): Notification URI.
Returns:
dict: Request body
"""
return {
"filter": {
"vnfInstanceSubscriptionFilter": {
"vnfdIds": ["b1bb0ce7-ebca-4fa7-95ed-4840d7000000"],
"vnfProductsFromProviders": [{
"vnfProvider": "Company",
"vnfProducts": [
{
"vnfProductName": "Sample VNF",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0"]
}
]
}
]
}]
},
"notificationTypes": [
"VnfLcmOperationOccurrenceNotification",
"VnfIdentifierCreationNotification",
"VnfIdentifierDeletionNotification"
],
"operationTypes": [
"INSTANTIATE",
"SCALE",
"TERMINATE",
"HEAL",
"MODIFY_INFO",
"CHANGE_EXT_CONN"
],
"operationStates": ["STARTING"]
},
"callbackUri": callback_uri
}
ext_vdu1_cp1 = {
"cpdId": "VDU1_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp1_id
}],
}
ext_vdu2_cp1 = {
"cpdId": "VDU2_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp2_id
}]
}
def _set_ext_link_port1(external_ports_id):
ext_link_port1 = {
"id": uuidsentinel.elp1_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[0]
}
}
return ext_link_port1
def _set_ext_link_port2(external_ports_id):
ext_link_port2 = {
"id": uuidsentinel.elp2_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[1]
}
}
return ext_link_port2
def _set_ext_virtual_link_cp1(networks_id, external_ports_id):
ext_virtual_link_cp1 = {
"id": uuidsentinel.evl1_id,
"resourceId": networks_id[0],
"vimConnectionId": uuidsentinel.vim_connection_id,
"extCps": [ext_vdu1_cp1, ext_vdu2_cp1],
"extLinkPorts": [
_set_ext_link_port1(external_ports_id),
_set_ext_link_port2(external_ports_id)]
}
return ext_virtual_link_cp1
def _set_ext_cps_vdu1_cp2(external_subnets_id):
ext_cps_vdu1_cp2 = {
"cpdId": "VDU1_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.1.10"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu1_cp2
def _set_ext_cps_vdu2_cp2(external_subnets_id):
ext_cps_vdu2_cp2 = {
"cpdId": "VDU2_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.1.20"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu2_cp2
def _set_ext_virtual_link_cp2(networks_id, external_subnets_id):
ext_virtual_link_cp2 = {
"id": uuidsentinel.evl2_id,
"resourceId": networks_id[1],
"vimConnectionId": uuidsentinel.vim_connection_id,
"extCps": [
_set_ext_cps_vdu1_cp2(external_subnets_id),
_set_ext_cps_vdu2_cp2(external_subnets_id)
]
}
return ext_virtual_link_cp2
def _set_ext_mng_vtl_lnks(ext_mngd_networks_id):
ext_mng_vtl_lnks = [{
"id": uuidsentinel.emvl1_id,
"vnfVirtualLinkDescId": "internalVL1",
"resourceId": ext_mngd_networks_id[0]
}, {
"id": uuidsentinel.emvl2_id,
"vnfVirtualLinkDescId": "internalVL2",
"resourceId": ext_mngd_networks_id[1]
}]
return ext_mng_vtl_lnks
class VnfInstances:
@staticmethod
def make_create_request_body(vnfd_id):
return {
"vnfdId": vnfd_id,
"vnfInstanceName": "",
"vnfInstanceDescription": "Sample VNF",
"metadata": {
"samplekey": "samplevalue"
}
}
@staticmethod
def make_inst_request_body(
user_name,
tenant_id,
networks_id,
ext_mngd_networks_id,
external_ports_id,
external_subnets_id):
data = {
"flavourId": "simple",
"instantiationLevelId": "instantiation_level_1",
"extVirtualLinks": [
_set_ext_virtual_link_cp1(
networks_id, external_ports_id),
_set_ext_virtual_link_cp2(
networks_id, external_subnets_id)
],
"extManagedVirtualLinks": _set_ext_mng_vtl_lnks(
ext_mngd_networks_id),
"vimConnectionInfo": [{
"id": uuidsentinel.vim_connection_id,
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
"vimConnectionId": uuidsentinel.vim_connection_id,
"interfaceInfo": {
"endpoint": "http://127.0.0.1/identity"
},
"accessInfo": {
"username": user_name,
"region": "RegionOne",
"password": "devstack",
"tenant": tenant_id
}
}],
"additionalParams": {
"lcm-operation-user-data": "./UserData/lcm_user_data.py",
"lcm-operation-user-data-class": "SampleUserData"
}
}
return data
@staticmethod
def make_term_request_body():
"""Parameter selection policy.
As all parameters are set, GRACEFUL is specified for terminationType.
(to specify gracefulTerminationTimeout)
Returns:
dict: Request body
"""
return {
"terminationType": "GRACEFUL",
"gracefulTerminationTimeout": 1,
"additionalParams": {
"samplekey": "samplevalue"
}
}

View File

@ -0,0 +1,455 @@
#
# 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_serialization import jsonutils
from tacker.objects import fields
from tacker.tests.functional.sol.vnflcm import base as vnflcm_base
from tacker.tests.functional.sol_multi_tenant.vnflcm import base
from tacker.tests.functional.sol_multi_tenant.vnflcm import fake_vnflcm
import tempfile
import time
class VnfLcmWithMultiTenant(base.BaseVnfLcmMultiTenantTest):
VNF_PACKAGE_DELETE_TIMEOUT = 120
@classmethod
def setUpClass(cls):
super(VnfLcmWithMultiTenant, cls).setUpClass()
# ModifyVNF specific image create.
is_setup_error_tenant1 = cls._modify_vnf_specific_image_create(
cls.glance_client_tenant1)
if is_setup_error_tenant1:
cls.is_setup_error = True
return
is_setup_error_tenant2 = cls._modify_vnf_specific_image_create(
cls.glance_client_tenant2)
if is_setup_error_tenant2:
cls.is_setup_error = True
return
@classmethod
def _modify_vnf_specific_image_create(cls, glance_clt):
is_setup_error = False
images = cls._list_glance_image()
if len(images) == 0:
is_setup_error = True
return is_setup_error
for image in images:
specific_image_name = f'{image.name}{2}'
image_data = {
"min_disk": image.min_disk,
"min_ram": image.min_ram,
"disk_format": image.disk_format,
"container_format": image.container_format,
"visibility": image.visibility,
"name": specific_image_name}
try:
images = cls._list_glance_image(specific_image_name)
if len(images) == 1:
break
_, body = glance_clt.http_client.get(
f'{glance_clt.http_client.get_endpoint()}{image.file}')
with tempfile.TemporaryFile('w+b') as f:
for content in body:
f.write(content)
cls._create_glance_image(image_data, f.read())
except Exception as e:
print("Fail, Modify-VNF specific image create.", e, flush=True)
is_setup_error = True
return is_setup_error
return is_setup_error
def _wait_show_subscription(self, subscription_id, tacker_client):
# wait for subscription creation
timeout = vnflcm_base.VNF_SUBSCRIPTION_TIMEOUT
start_time = int(time.time())
while True:
resp, body = self._show_subscription(subscription_id,
tacker_client)
if resp.ok or resp.status_code == 404:
return resp, body
if ((int(time.time()) - start_time) > timeout):
if resp:
resp.raise_for_status()
raise TimeoutError("Failed to show_subscription")
time.sleep(1)
def _delete_vnf_package(self, package_uuid, http_client):
url = os.path.join(self.base_url, package_uuid)
resp, _ = http_client.do_request(url, "DELETE")
self.assertEqual(204, resp.status_code)
def _wait_for_delete(self, package_uuid, http_client):
show_url = os.path.join(self.base_url, package_uuid)
timeout = self.VNF_PACKAGE_DELETE_TIMEOUT
start_time = int(time.time())
while True:
resp, body = http_client.do_request(show_url, "GET")
if (404 == resp.status_code):
return resp, body
if (int(time.time()) - start_time) > timeout:
raise Exception("Failed to delete package")
time.sleep(1)
def _disable_operational_state(self, package_uuid, http_client):
update_req_body = jsonutils.dumps({
"operationalState": "DISABLED"})
resp, _ = http_client.do_request(
'{base_path}/{id}'.format(id=package_uuid,
base_path=self.base_url),
"PATCH", content_type='application/json',
body=update_req_body)
self.assertEqual(200, resp.status_code)
def assert_vnf_package_usage_state(
self,
vnf_package_info,
expected_usage_state=fields.PackageUsageStateType.IN_USE):
self.assertEqual(
expected_usage_state,
vnf_package_info['usageState'])
def assert_create_vnf(self, resp, vnf_instance, vnf_pkg_id,
tacker_client, fake_server_manager):
super().assert_create_vnf(resp, vnf_instance,
fake_server_manager)
resp, vnf_pkg_info = vnflcm_base._show_vnf_package(
tacker_client, vnf_pkg_id)
self.assert_vnf_package_usage_state(vnf_pkg_info)
def _vnf_instance_wait_until_fail_detected(self, id,
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
timeout=vnflcm_base.VNF_INSTANTIATE_ERROR_WAIT):
time.sleep(timeout)
_, body = self._show_vnf_instance(id)
if body['instantiationState'] != instantiation_state:
error = ("Vnf instance %(id)s status is %(current)s, "
"expected status should be %(expected)s")
self.fail(error % {"id": id,
"current": body['instantiationState'],
"expected": instantiation_state})
def test_subscription_functionality(self):
"""Test subscription operations with member role users.
In this test case, we do following steps.
Note: User A belongs to Tenant 1(t1).
User B belongs to Tenant 2(t2).
- Create subscription.
- User A registers Subscription A(Notification Server A).
- User B registers Subscription B(Notification Server B).
- Show Subscription
- User A only gets information about Subscription A.
- User B only gets information about Subscription B.
- List Subscription
- User A gets subscription list and confirms only
Subscription A is output.
- User B gets subscription list and confirms only
Subscription B is output.
- Delete Subscription
- User A deletes Subscription A.
- User B deletes Subscription B.
TODO(manpreetk): Only positive test cases are validated in
Y-release.
Negative test cases
- User A fails to delete Subscription B.
- User B fails to delete Subscription A.
Validation of negative test cases would require design changes
in Fake NFVO server, which could be implemented in the upcoming
cycle.
"""
# Create subscription
# User A registers Subscription A.
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
req_body = fake_vnflcm.Subscription.make_create_request_body(
'http://localhost:{}{}'.format(
base.FAKE_SERVER_MANAGER_T1.SERVER_PORT_T1,
callback_url))
resp_t1, resp_body_t1 = self._register_subscription(req_body,
self.http_client_tenant1)
self.assertEqual(201, resp_t1.status_code)
self.assert_http_header_location_for_subscription(
resp_t1.headers)
self.assert_notification_get(callback_url,
base.FAKE_SERVER_MANAGER_T1)
subscription_id_t1 = resp_body_t1.get('id')
# User B registers Subscription B
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
req_body_t2 = fake_vnflcm.Subscription.make_create_request_body(
'http://localhost:{}{}'.format(
base.FAKE_SERVER_MANAGER_T2.SERVER_PORT_T2,
callback_url))
resp_t2, resp_body_t2 = self._register_subscription(
req_body_t2, self.http_client_tenant2)
self.assertEqual(201, resp_t2.status_code)
self.assert_http_header_location_for_subscription(
resp_t2.headers)
self.assert_notification_get(callback_url,
base.FAKE_SERVER_MANAGER_T2)
subscription_id_t2 = resp_body_t2.get('id')
# Show Subscription
# User A gets information for Subscription A
resp_t1, resp_body_show_t1 = self._wait_show_subscription(
subscription_id_t1, self.tacker_client_t1)
self.assert_subscription_show(resp_t1, resp_body_show_t1)
# User B gets information for Subscription B
resp_t2, resp_body_show_t2 = self._wait_show_subscription(
subscription_id_t2, self.tacker_client_t2)
self.assert_subscription_show(resp_t2, resp_body_show_t2)
# List Subscription
# User A gets subscription list
resp, _ = self._list_subscription(self.tacker_client_t1)
self.assertEqual(200, resp_t1.status_code)
# Confirm subscription A
filter_expr = {
'filter': "filter=(eq,id,{})".format(
resp_body_show_t1.get('id'))}
resp, subscription_body_t1 = self._list_subscription_filter(
self.http_client_tenant1,
params=filter_expr)
self.assertEqual(200, resp.status_code)
self.assertEqual(1, len(subscription_body_t1))
# User B gets subscription list
resp_t2, _ = self._list_subscription(
self.tacker_client_t2)
self.assertEqual(200, resp_t2.status_code)
# Confirm subscription B
filter_expr = {
'filter': "filter=(eq,id,{})".format(
resp_body_show_t2.get('id'))}
resp, subscription_body_t2 = self._list_subscription_filter(
self.http_client_tenant2,
params=filter_expr)
self.assertEqual(200, resp.status_code)
self.assertEqual(1, len(subscription_body_t2))
# Delete subscription
# User A deletes Subscription A
self.addCleanup(self._delete_subscription,
subscription_id_t1, self.tacker_client_t1)
# User B deletes Subscription B
self.addCleanup(self._delete_subscription,
subscription_id_t2, self.tacker_client_t2)
def test_vnf_package_functionality(self):
"""Test VNF package operations with member role users.
In this test case, we do following steps.
Note: User A belongs to Tenant 1.
User B belongs to Tenant 2.
- Create and Upload VNF Package
- User A creates VNF Package A.
- User A uploads VNF Package A.
- User B creates VNF Package B.
- User B uploads VNF Package B.
- List VNF Package
- User A gets VNF package list and confirms only
VNF Package A is output.
- User B gets VNF package list and confirms only
VNF Package B is output.
- Show VNF Package
- User A only gets information about VNF Package A.
- User B only gets information about VNF Package B.
- Delete VNF Package
- User A deletes VNF Package A.
- User B deletes VNF Package B.
TODO(manpreetk): Only positive test cases are validated in
Y-release.
Negative test cases
- User A fails to delete VNF Package B.
- User B fails to delete VNF Package A.
Validation of negative test cases would require design changes
in Fake NFVO server, which could be implemented in the upcoming
cycle.
"""
# Create and Upload VNF Package
# User A creates VNF Package A
sample_name = 'mt_functional1'
csar_package_path = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"../../../etc/samples/etsi/nfv",
sample_name))
tempname, _ = vnflcm_base._create_csar_with_unique_vnfd_id(
csar_package_path)
# User A uploads VNF Package A
vnf_pkg_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
self.tacker_client_t1, user_defined_data={
"key": sample_name}, temp_csar_path=tempname)
# User B creates VNF Package B
sample_name_t2 = 'mt_functional1'
csar_package_path_t2 = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"../../../etc/samples/etsi/nfv",
sample_name_t2))
tempname_t2, _ = vnflcm_base._create_csar_with_unique_vnfd_id(
csar_package_path_t2)
# User B uploads VNF Package B
vnf_pkg_id2, vnfd_id2 = vnflcm_base._create_and_upload_vnf_package(
self.tacker_client_t2, user_defined_data={
"key": sample_name_t2}, temp_csar_path=tempname_t2)
# List VNF Package
# User A gets VNF package list and confirms only VNF Package A
# is output.
resp, body = self.http_client_tenant1.do_request(
self.base_url, "GET")
self.assertEqual(200, resp.status_code)
package_id = [obj['id'] for obj in body]
self.assertIn(vnf_pkg_id, package_id)
# User B gets VNF package list and confirms only VNF Package B
# is output.
resp_t2, body_t2 = self.http_client_tenant2.do_request(
self.base_url, "GET")
self.assertEqual(200, resp_t2.status_code)
package_id = [obj['id'] for obj in body_t2]
self.assertIn(vnf_pkg_id2, package_id)
# Show VNF Package
# User A only gets information about VNF Package A
show_url = os.path.join(self.base_url, vnf_pkg_id)
resp, body = self.http_client_tenant1.do_request(
show_url, "GET")
self.assertEqual(200, resp.status_code)
# User B only gets information about VNF Package B
show_url_t2 = os.path.join(self.base_url, vnf_pkg_id2)
resp_t2, body_t2 = self.http_client_tenant2.do_request(
show_url_t2, "GET")
self.assertEqual(200, resp_t2.status_code)
# Delete VNF Package
# User A deletes VNF Package A
self._disable_operational_state(vnf_pkg_id,
self.http_client_tenant1)
self._delete_vnf_package(vnf_pkg_id, self.http_client_tenant1)
self._wait_for_delete(vnf_pkg_id, self.http_client_tenant1)
# User B deletes VNF Package B
self._disable_operational_state(vnf_pkg_id2,
self.http_client_tenant2)
self._delete_vnf_package(vnf_pkg_id2, self.http_client_tenant2)
self._wait_for_delete(vnf_pkg_id2, self.http_client_tenant2)
def test_vnf_instantiation_by_vim_of_different_tenant_and_role(self):
"""Test VNF instantiation by VIM of differnt tenant.
In this test case, we do following steps.
Note: User A is an admin role user belongs to Tenant 1.
User B is a non-admin role user belongs to Tenant 2.
- Create VNF Instance
- User B creates VNF Instance B using VNF Package B.
- Instantiate VNF
- User A fails to instantiates VNF Instance B, both
VNF and VIM belong to different tenant.
"""
# Pre-Setting
# User B registers Subscription B.
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
req_body_t2 = fake_vnflcm.Subscription.make_create_request_body(
'http://localhost:{}{}'.format(
base.FAKE_SERVER_MANAGER_T2.SERVER_PORT_T2,
callback_url))
resp_t2, resp_body_t2 = self._register_subscription(
req_body_t2, self.http_client_tenant2)
self.assertEqual(201, resp_t2.status_code)
self.assert_http_header_location_for_subscription(
resp_t2.headers)
self.assert_notification_get(callback_url,
base.FAKE_SERVER_MANAGER_T2)
subscription_id_t2 = resp_body_t2.get('id')
self.addCleanup(
self._delete_subscription,
subscription_id_t2,
self.tacker_client_t2)
# Create and Upload VNF Package
# User B creates VNF Package B
sample_name_t2 = 'mt_functional1'
csar_package_path_t2 = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"../../../etc/samples/etsi/nfv",
sample_name_t2))
tempname_t2, _ = vnflcm_base._create_csar_with_unique_vnfd_id(
csar_package_path_t2)
# User B uploads VNF Package B
vnf_pkg_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
self.tacker_client_t2, user_defined_data={
"key": sample_name_t2}, temp_csar_path=tempname_t2)
# Post Setting: Reserve deleting VNF package.
self.addCleanup(vnflcm_base._delete_vnf_package,
self.tacker_client_t2, vnf_pkg_id)
# Create VNF Instance
# User B creates VNF Instance B using VNF Package B
resp_t2, vnf_instance_t2 = self._create_vnf_instance_from_body(
fake_vnflcm.VnfInstances.make_create_request_body(vnfd_id),
self.http_client_tenant2)
vnf_instance_id_t2 = vnf_instance_t2.get('id')
self._wait_lcm_done(vnf_instance_id=vnf_instance_id_t2,
fake_server_manager=base.FAKE_SERVER_MANAGER_T2)
self.assert_create_vnf(resp_t2, vnf_instance_t2,
vnf_pkg_id,
self.tacker_client_t2,
base.FAKE_SERVER_MANAGER_T2)
# Instantiate VNF instance
# User A fails to instantiate VNF Instance B as both VIM and VNF
# belongs to differernt tenants
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
'nfv_user',
self.vim['tenant_id'], self.ext_networks,
self.ext_mngd_networks,
self.ext_link_ports, self.ext_subnets)
resp, _ = self._instantiate_vnf_instance(vnf_instance_id_t2,
request_body, self.http_client)
self.assertEqual(202, resp.status_code)
self._vnf_instance_wait_until_fail_detected(vnf_instance_id_t2)

View File

@ -88,6 +88,7 @@ auth_url: "${VIMC_ENDPOINT}"
username: "${VIMC_OS_USER}"
password: "${VIMC_OS_PASSWORD}"
project_name: "${VIMC_PROJ}"
domain_name: "${VIMC_OS_PROJ_DOMAIN}"
project_domain_name: "${VIMC_OS_PROJ_DOMAIN}"
user_domain_name: "${VIMC_OS_USER_DOMAIN}"
cert_verify: "${_cert_verify}"

View File

@ -61,6 +61,12 @@ setenv = {[testenv]setenv}
commands =
stestr --test-path=./tacker/tests/functional/sol_v2 run --slowest --concurrency 1 {posargs}
[testenv:dsvm-functional-sol-multi-tenant]
setenv = {[testenv]setenv}
commands =
stestr --test-path=./tacker/tests/functional/sol_multi_tenant run --slowest --concurrency 1 {posargs}
[testenv:debug]
commands = oslo_debug_helper {posargs}