Support Update function of FT
Added Update Functional tests for Tacker (Victoria). Fix is also added for server shutdown since it has a case where it is stopped unsafely. Implements: blueprint support-etsi-nfv-specs Change-Id: Ic424445ec9b836d83ffe4184d5b848fd17590606
This commit is contained in:
@@ -175,6 +175,15 @@
|
||||
TACKER_HOST: "{{ hostvars['controller-tacker']['nodepool']['private_ipv4'] }}"
|
||||
TACKER_MODE: standalone
|
||||
IS_ZUUL_FT: True
|
||||
# Since a VirtualInterfaceCreateException occurs during a test,
|
||||
# the setting of network-vif-plugged is changed by the reference of
|
||||
# the following URL.
|
||||
# https://bugs.launchpad.net/heat/+bug/1694371
|
||||
devstack_local_conf:
|
||||
post-config:
|
||||
$NOVA_CONF:
|
||||
DEFAULT:
|
||||
vif_plugging_is_fatal: False
|
||||
devstack_services:
|
||||
q-agt: true
|
||||
n-api: false
|
||||
|
||||
@@ -1,35 +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}
|
||||
#
|
||||
# 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}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
heat_template_version: 2013-05-23
|
||||
description: 'Simple Base HOT for Sample VNF'
|
||||
|
||||
parameters:
|
||||
nfv:
|
||||
type: json
|
||||
|
||||
resources:
|
||||
VDU1:
|
||||
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_out:
|
||||
type: OS::Heat::ScalingPolicy
|
||||
properties:
|
||||
scaling_adjustment: 1
|
||||
auto_scaling_group_id:
|
||||
get_resource: VDU1
|
||||
adjustment_type: change_in_capacity
|
||||
VDU1_scale_in:
|
||||
type: OS::Heat::ScalingPolicy
|
||||
properties:
|
||||
scaling_adjustment: -1
|
||||
auto_scaling_group_id:
|
||||
get_resource: VDU1
|
||||
adjustment_type: change_in_capacity
|
||||
VDU2:
|
||||
type: OS::Heat::AutoScalingGroup
|
||||
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_out:
|
||||
type: OS::Heat::ScalingPolicy
|
||||
properties:
|
||||
scaling_adjustment: 1
|
||||
auto_scaling_group_id:
|
||||
get_resource: VDU2
|
||||
adjustment_type: change_in_capacity
|
||||
VDU2_scale_in:
|
||||
type: OS::Heat::ScalingPolicy
|
||||
properties:
|
||||
scaling_adjustment: -1
|
||||
auto_scaling_group_id:
|
||||
get_resource: VDU2
|
||||
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: {}
|
||||
@@ -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 }
|
||||
@@ -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: { get_param: net4 }
|
||||
VDU2_CP5:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net5 }
|
||||
@@ -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.4.0-x86_64-disk2
|
||||
version: '0.4.0'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
hash: a8dd75ecffd4cdd96072d60c2237b448e0c8b2bc94d57f10fdbc8c481d9005b8
|
||||
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.4.0-x86_64-disk
|
||||
version: '0.4.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: 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:
|
||||
worker_instance:
|
||||
name: worker_instance_aspect
|
||||
description: worker_instance 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: worker_instance
|
||||
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:
|
||||
worker_instance:
|
||||
scale_level: 0
|
||||
instantiation_level_2:
|
||||
description: Largest size
|
||||
scale_info:
|
||||
worker_instance:
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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}
|
||||
@@ -97,6 +97,7 @@ class BaseTackerTest(base.BaseTestCase):
|
||||
cls.client = cls.tackerclient()
|
||||
cls.http_client = cls.tacker_http_client()
|
||||
cls.h_client = cls.heatclient()
|
||||
cls.glance_client = cls.glanceclient()
|
||||
|
||||
@classmethod
|
||||
def get_credentials(cls):
|
||||
|
||||
@@ -18,6 +18,7 @@ import inspect
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
@@ -391,8 +392,16 @@ class FakeServerManager(SingletonMixin):
|
||||
'[Start] %s.%s()' %
|
||||
(self.__class__.__name__,
|
||||
inspect.currentframe().f_code.co_name))
|
||||
self.objHttpd = http.server.HTTPServer(
|
||||
(address, port), DummyRequestHander)
|
||||
while True:
|
||||
try:
|
||||
self.objHttpd = http.server.HTTPServer(
|
||||
(address, port), DummyRequestHander)
|
||||
except OSError:
|
||||
time.sleep(10)
|
||||
continue
|
||||
else:
|
||||
break
|
||||
self.thread_server = threading.Thread(None, self.run)
|
||||
LOG.debug(
|
||||
'[ End ] %s.%s()' %
|
||||
(self.__class__.__name__,
|
||||
@@ -401,7 +410,7 @@ class FakeServerManager(SingletonMixin):
|
||||
def start_server(self):
|
||||
"""Start server in thread."""
|
||||
LOG.debug('[START] %s()' % inspect.currentframe().f_code.co_name)
|
||||
threading.Thread(None, self.run).start()
|
||||
self.thread_server.start()
|
||||
LOG.debug('[ END ] %s()' % inspect.currentframe().f_code.co_name)
|
||||
|
||||
def run(self):
|
||||
@@ -411,10 +420,15 @@ class FakeServerManager(SingletonMixin):
|
||||
self.objHttpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
self.stop_server()
|
||||
finally:
|
||||
self.objHttpd.server_close()
|
||||
LOG.debug('[ END ] %s()' % inspect.currentframe().f_code.co_name)
|
||||
|
||||
def stop_server(self):
|
||||
"""Stop HTTP Server"""
|
||||
LOG.debug('[START] %s()' % inspect.currentframe().f_code.co_name)
|
||||
self.objHttpd.shutdown()
|
||||
thread_shutdown = threading.Thread(None, self.objHttpd.shutdown)
|
||||
thread_shutdown.daemon = True
|
||||
thread_shutdown.start()
|
||||
self.thread_server.join()
|
||||
LOG.debug('[ END ] %s()' % inspect.currentframe().f_code.co_name)
|
||||
|
||||
@@ -122,7 +122,8 @@ def _create_and_upload_vnf_package(
|
||||
vnfd_id = None
|
||||
while True:
|
||||
resp, body = tacker_client.do_request(show_url, "GET")
|
||||
if body['onboardingState'] == "ONBOARDED":
|
||||
if (200 <= resp.status_code < 300) and (
|
||||
body['onboardingState'] == "ONBOARDED"):
|
||||
vnfd_id = body['vnfdId']
|
||||
break
|
||||
|
||||
@@ -204,6 +205,8 @@ def _create_instantiate_vnf_request_body(flavour_id,
|
||||
|
||||
class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
|
||||
is_setup_error = False
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Set up test class.
|
||||
@@ -214,12 +217,6 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
FAKE_SERVER_MANAGER.prepare_http_server()
|
||||
FAKE_SERVER_MANAGER.start_server()
|
||||
|
||||
FAKE_SERVER_MANAGER.set_callback(
|
||||
'POST',
|
||||
MOCK_NOTIFY_CALLBACK_URL,
|
||||
status_code=204
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(BaseVnfLcmTest, cls).tearDownClass()
|
||||
@@ -228,6 +225,18 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
def setUp(self):
|
||||
super(BaseVnfLcmTest, self).setUp()
|
||||
|
||||
if self.is_setup_error:
|
||||
self.fail("Faild, not exists pre-registered image.")
|
||||
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
FAKE_SERVER_MANAGER.clear_history(callback_url)
|
||||
FAKE_SERVER_MANAGER.set_callback(
|
||||
'POST',
|
||||
callback_url,
|
||||
status_code=204
|
||||
)
|
||||
|
||||
self.tacker_client = base.BaseTackerTest.tacker_http_client()
|
||||
|
||||
self.base_vnf_instances_url = "/vnflcm/v1/vnf_instances"
|
||||
@@ -248,14 +257,17 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
for nw in networks.get('networks'):
|
||||
if nw['name'] == 'net0':
|
||||
self.ext_networks.append(nw['id'])
|
||||
self.ext_vl = _get_external_virtual_links(nw['id'])
|
||||
elif nw['name'] == 'net1':
|
||||
self.ext_mngd_networks.append(nw['id'])
|
||||
|
||||
# create new network.
|
||||
self.ext_networks.append(
|
||||
self._create_network("external_net"))
|
||||
self.ext_mngd_networks.append(
|
||||
self._create_network("external_managed_internal_net"))
|
||||
ext_net_id, ext_net_name = \
|
||||
self._create_network("external_net")
|
||||
self.ext_networks.append(ext_net_id)
|
||||
ext_mngd_net_id, _ = \
|
||||
self._create_network("external_managed_internal_net")
|
||||
self.ext_mngd_networks.append(ext_mngd_net_id)
|
||||
|
||||
# Create external link ports in net0
|
||||
self.ext_link_ports = list()
|
||||
@@ -265,21 +277,21 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
# Chack how many networks are created.
|
||||
networks = self.neutronclient().list_networks()
|
||||
for nw in networks.get('networks'):
|
||||
if nw['name'] not in ['net0', 'external_net']:
|
||||
continue
|
||||
if self.vim['tenant_id'] != nw['tenant_id']:
|
||||
if nw['name'] not in ['net0', ext_net_name]:
|
||||
continue
|
||||
|
||||
self.ext_networks.append(nw['id'])
|
||||
if nw['name'] == 'net0':
|
||||
self.ext_subnets.append(nw['subnets'][0])
|
||||
else:
|
||||
self.ext_subnets.append(self._create_subnet(nw))
|
||||
self.ext_link_ports.append(self._create_port(nw['id']))
|
||||
self.ext_subnets.append(self._create_subnet(nw))
|
||||
|
||||
@classmethod
|
||||
def _list_glance_image(cls, filter_name='cirros-0.4.0-x86_64-disk'):
|
||||
try:
|
||||
images = cls.glance_client.images.list()
|
||||
except Exception:
|
||||
print("glance-image does not exists.")
|
||||
print("glance-image does not exists.", flush=True)
|
||||
return []
|
||||
|
||||
if filter_name is None:
|
||||
@@ -292,7 +304,7 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
try:
|
||||
image = cls.glance_client.images.get(image_id)
|
||||
except Exception:
|
||||
print("glance-image does not exists.")
|
||||
print("glance-image does not exists.", image_id, flush=True)
|
||||
return None
|
||||
|
||||
return image
|
||||
@@ -353,6 +365,7 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
return self._create_vnf_instance_from_body(request_body)
|
||||
|
||||
def _create_vnf_instance_from_body(self, request_body):
|
||||
request_body['vnfInstanceName'] = self._testMethodName
|
||||
resp, response_body = self.http_client.do_request(
|
||||
self.base_vnf_instances_url,
|
||||
"POST",
|
||||
@@ -374,7 +387,7 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
|
||||
def _list_vnf_instance(self, **kwargs):
|
||||
resp, vnf_instances = self.http_client.do_request(
|
||||
self.base_vnf_instances_url, "GET")
|
||||
self.base_vnf_instances_url, "GET", **kwargs)
|
||||
|
||||
return resp, vnf_instances
|
||||
|
||||
@@ -418,6 +431,13 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
|
||||
return resp, body
|
||||
|
||||
def _update_vnf_instance(self, vnf_instance_id, request_body):
|
||||
url = os.path.join(self.base_vnf_instances_url, vnf_instance_id)
|
||||
resp, body = self.http_client.do_request(url, "PATCH",
|
||||
body=jsonutils.dumps(request_body))
|
||||
|
||||
return resp, body
|
||||
|
||||
def _wait_terminate_vnf_instance(self, id, timeout=None):
|
||||
start_time = int(time.time())
|
||||
|
||||
@@ -441,7 +461,6 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
try:
|
||||
stacks = self.h_client.stacks.list()
|
||||
except Exception:
|
||||
print("heat-stacks does not exists.")
|
||||
return None
|
||||
|
||||
target_stack_name = prefix_id + vnf_instance_id
|
||||
@@ -460,7 +479,6 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
resources = self.h_client.resources.list(
|
||||
stack_id, nested_depth=nested_depth)
|
||||
except Exception:
|
||||
print("heat-stacks-resources does not exists.")
|
||||
return None
|
||||
|
||||
return resources
|
||||
@@ -470,7 +488,6 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
resource = self.h_client.resources.get(
|
||||
stack_id, resource_name)
|
||||
except Exception:
|
||||
print("heat-stacks-resource does not exists.")
|
||||
return None
|
||||
|
||||
return resource
|
||||
@@ -610,15 +627,28 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
image = self._get_glance_image(glance_image_id)
|
||||
self.assertIsNone(image)
|
||||
|
||||
def _wait_lcm_done(self, expected_operation_status=None):
|
||||
def _wait_lcm_done(self,
|
||||
expected_operation_status=None,
|
||||
vnf_instance_id=None):
|
||||
start_time = int(time.time())
|
||||
while True:
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
|
||||
while True:
|
||||
actual_status = None
|
||||
vnf_lcm_op_occ_id = None
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url)
|
||||
print(
|
||||
("Wait:callback_url=<%s>, " +
|
||||
"wait_status=<%s>, " +
|
||||
"vnf_instance_id=<%s>") %
|
||||
(callback_url, expected_operation_status, vnf_instance_id),
|
||||
flush=True)
|
||||
|
||||
for res in notify_mock_responses:
|
||||
if vnf_instance_id != res.request_body.get('vnfInstanceId'):
|
||||
continue
|
||||
|
||||
if expected_operation_status is None:
|
||||
return
|
||||
@@ -631,8 +661,9 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
if ((int(time.time()) - start_time) > VNF_LCM_DONE_TIMEOUT):
|
||||
if actual_status:
|
||||
error = (
|
||||
"LCM incomplete timeout, %s is %s," +
|
||||
"expected status should be %s")
|
||||
"LCM incomplete timeout, %(vnf_lcm_op_occ_id)s" +
|
||||
" is %(actual)s," +
|
||||
"expected status should be %(expected)s")
|
||||
self.fail(
|
||||
error % {
|
||||
"vnf_lcm_op_occ_id": vnf_lcm_op_occ_id,
|
||||
@@ -669,9 +700,11 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED)
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
FAKE_SERVER_MANAGER.clear_history(MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance.get('id'))
|
||||
|
||||
self.assertEqual(1, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
notify_mock_responses[0],
|
||||
@@ -684,9 +717,11 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
self.assertEqual(404, resp.status_code)
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
FAKE_SERVER_MANAGER.clear_history(MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance_id)
|
||||
|
||||
self.assertEqual(1, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
notify_mock_responses[0],
|
||||
@@ -707,9 +742,10 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
expected_resource_status='CREATE_COMPLETE')
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
FAKE_SERVER_MANAGER.clear_history(MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance_id)
|
||||
|
||||
self.assertEqual(3, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
@@ -743,9 +779,10 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
expected_stack_status=expected_stack_status)
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
FAKE_SERVER_MANAGER.clear_history(MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance_id)
|
||||
|
||||
self.assertEqual(3, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
@@ -787,9 +824,10 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
glance_image_id_list=glance_image_id_list)
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
MOCK_NOTIFY_CALLBACK_URL)
|
||||
FAKE_SERVER_MANAGER.clear_history(MOCK_NOTIFY_CALLBACK_URL)
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance_id)
|
||||
|
||||
self.assertEqual(3, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
@@ -807,6 +845,41 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
'VnfLcmOperationOccurrenceNotification',
|
||||
'COMPLETED')
|
||||
|
||||
def assert_update_vnf(
|
||||
self,
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
expected_stack_status='CREATE_COMPLETE'):
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.assert_http_header_location_for_lcm_op_occs(resp.headers)
|
||||
|
||||
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
self.assert_vnf_state(vnf_instance)
|
||||
self.assert_instantiation_state(vnf_instance)
|
||||
|
||||
self.assert_heat_stack_status(
|
||||
vnf_instance['id'],
|
||||
expected_stack_status=expected_stack_status)
|
||||
|
||||
# FT-checkpoint: Notification
|
||||
callback_url = \
|
||||
os.path.join(MOCK_NOTIFY_CALLBACK_URL, self._testMethodName)
|
||||
notify_mock_responses = self._filter_notify_history(callback_url,
|
||||
vnf_instance_id)
|
||||
|
||||
self.assertEqual(2, len(notify_mock_responses))
|
||||
self.assert_notification_mock_response(
|
||||
notify_mock_responses[0],
|
||||
'VnfLcmOperationOccurrenceNotification',
|
||||
'PROCESSING')
|
||||
|
||||
self.assert_notification_mock_response(
|
||||
notify_mock_responses[1],
|
||||
'VnfLcmOperationOccurrenceNotification',
|
||||
'COMPLETED')
|
||||
|
||||
def assert_notification_mock_response(
|
||||
self,
|
||||
notify_mock_response,
|
||||
@@ -826,34 +899,64 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
def _create_network(self, name):
|
||||
# First, we have to check network name passed by caller is
|
||||
# already exists or not.
|
||||
netlist = self.neutronclient().list_networks(name=name)
|
||||
if netlist is not None:
|
||||
print('%s is already exist' % name)
|
||||
|
||||
# OK, we can create this.
|
||||
net = self.neutronclient().create_network({'network': {'name': name}})
|
||||
net_id = net['network']['id']
|
||||
self.addCleanup(self.neutronclient().delete_network, net_id)
|
||||
|
||||
return net_id
|
||||
try:
|
||||
uniq_name = name + '-' + uuidutils.generate_uuid()
|
||||
net = \
|
||||
self.neutronclient().create_network(
|
||||
{'network': {'name': uniq_name}})
|
||||
net_id = net['network']['id']
|
||||
self.addCleanup(self._delete_network, net_id)
|
||||
print("Create network success, %s" % uniq_name, flush=True)
|
||||
return net_id, uniq_name
|
||||
except Exception as e:
|
||||
self.fail("Failed, create network=<%s>, %s" %
|
||||
(uniq_name, e))
|
||||
|
||||
def _create_subnet(self, network):
|
||||
cidr_prefix = "22.22.{}".format(str(len(self.ext_subnets) + 1))
|
||||
body = {'subnet': {'network_id': network['id'],
|
||||
'name': "subnet-%s" % uuidutils.generate_uuid(),
|
||||
'cidr': "22.22.{}.0/24".format(str(len(self.ext_subnets) % 2)),
|
||||
'cidr': "{}.0/24".format(cidr_prefix),
|
||||
'ip_version': 4,
|
||||
'gateway_ip': '22.22.0.1',
|
||||
'gateway_ip': "{}.1".format(cidr_prefix),
|
||||
"enable_dhcp": True}}
|
||||
|
||||
subnet = self.neutronclient().create_subnet(body=body)["subnet"]
|
||||
self.addCleanup(self.neutronclient().delete_subnet, subnet['id'])
|
||||
return subnet['id']
|
||||
try:
|
||||
subnet = self.neutronclient().create_subnet(body=body)["subnet"]
|
||||
self.addCleanup(self._delete_subnet, subnet['id'])
|
||||
return subnet['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create subnet for net_id=<%s>, %s" %
|
||||
(network['id'], e))
|
||||
|
||||
def _create_port(self, network_id):
|
||||
body = {'port': {'network_id': network_id}}
|
||||
port = self.neutronclient().create_port(body=body)["port"]
|
||||
self.addCleanup(self.neutronclient().delete_port, port['id'])
|
||||
return port['id']
|
||||
try:
|
||||
port = self.neutronclient().create_port(body=body)["port"]
|
||||
self.addCleanup(self._delete_port, port['id'])
|
||||
return port['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create port for net_id=<%s>, %s" %
|
||||
(network_id, e))
|
||||
|
||||
def _delete_network(self, network_id):
|
||||
try:
|
||||
self.neutronclient().delete_network(network_id)
|
||||
except Exception:
|
||||
print("Failed, delete network.", network_id, flush=True)
|
||||
|
||||
def _delete_subnet(self, subnet_id):
|
||||
try:
|
||||
self.neutronclient().delete_subnet(subnet_id)
|
||||
except Exception:
|
||||
print("Failed, delete subnet.", subnet_id, flush=True)
|
||||
|
||||
def _delete_port(self, port_id):
|
||||
try:
|
||||
self.neutronclient().delete_port(port_id)
|
||||
except Exception:
|
||||
print("Failed, delete port.", port_id, flush=True)
|
||||
|
||||
def assert_subscription_show(self, resp, response_body):
|
||||
"""Assert that subscription informations has mandatory keys."""
|
||||
@@ -869,3 +972,12 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
self.assertIsNotNone(_links)
|
||||
self.assertIsNotNone(_links.get('self'))
|
||||
self.assertIsNotNone(_links.get('self').get('href'))
|
||||
|
||||
def _filter_notify_history(self, callback_url, vnf_instance_id):
|
||||
notify_histories = FAKE_SERVER_MANAGER.get_history(
|
||||
callback_url)
|
||||
FAKE_SERVER_MANAGER.clear_history(callback_url)
|
||||
|
||||
return [
|
||||
h for h in notify_histories
|
||||
if h.request_body.get('vnfInstanceId') == vnf_instance_id]
|
||||
|
||||
@@ -53,7 +53,7 @@ class VnfInstances:
|
||||
def make_create_request_body(vnfd_id):
|
||||
return {
|
||||
"vnfdId": vnfd_id,
|
||||
"vnfInstanceName": "helloworld3",
|
||||
"vnfInstanceName": "",
|
||||
"vnfInstanceDescription": "Sample VNF",
|
||||
"metadata": {
|
||||
"samplekey": "samplevalue"
|
||||
@@ -97,7 +97,6 @@ class VnfInstances:
|
||||
}
|
||||
ext_virtual_link_cp1 = {
|
||||
"id": uuidsentinel.evl1_id,
|
||||
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||
# set external nw_id on vim.
|
||||
"resourceId": networks_id[0],
|
||||
"extCps": [ext_vdu1_cp1, ext_vdu2_cp1],
|
||||
@@ -113,7 +112,7 @@ class VnfInstances:
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1,
|
||||
"fixedAddresses": ["22.22.2.10"],
|
||||
"subnetId": external_subnets_id[0]
|
||||
}]
|
||||
}
|
||||
@@ -129,7 +128,7 @@ class VnfInstances:
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": "1",
|
||||
"fixedAddresses": ["22.22.2.20"],
|
||||
"subnetId": external_subnets_id[1]
|
||||
}]
|
||||
}
|
||||
@@ -139,7 +138,6 @@ class VnfInstances:
|
||||
|
||||
ext_virtual_link_cp2 = {
|
||||
"id": uuidsentinel.evl2_id,
|
||||
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||
"resourceId": networks_id[1],
|
||||
"extCps": [
|
||||
ext_cps_vdu1_cp2, ext_cps_vdu2_cp2
|
||||
@@ -150,12 +148,10 @@ class VnfInstances:
|
||||
ext_mng_vtl_lnks = [{
|
||||
"id": uuidsentinel.emvl1_id,
|
||||
"vnfVirtualLinkDescId": "internalVL1",
|
||||
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||
"resourceId": ext_mngd_networks_id[0]
|
||||
}, {
|
||||
"id": uuidsentinel.emvl2_id,
|
||||
"vnfVirtualLinkDescId": "internalVL2",
|
||||
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||
"resourceId": ext_mngd_networks_id[1]
|
||||
}]
|
||||
|
||||
@@ -169,6 +165,7 @@ class VnfInstances:
|
||||
"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"
|
||||
},
|
||||
@@ -214,3 +211,31 @@ class VnfInstances:
|
||||
"samplekey": "samplevalue"
|
||||
}
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def make_update_request_body(vnfd_id=None, vnf_package_id=None):
|
||||
"""Parameter selection policy.
|
||||
|
||||
vimConnectionInfo is not set.
|
||||
|
||||
Args:
|
||||
vnfd_id (str, optional): vnfdId(2.6.1)
|
||||
vnf_package_id (str, optional): vnfPkgId(2.4.1)
|
||||
|
||||
Returns:
|
||||
dict: Request body
|
||||
"""
|
||||
data = {
|
||||
"vnfInstanceName": "helloworld3_modify",
|
||||
"vnfInstanceDescription": "Sample VNF Modify",
|
||||
"metadata": {
|
||||
"samplekey": "samplevalue_modified"
|
||||
}
|
||||
}
|
||||
|
||||
if vnfd_id:
|
||||
data["vnfdId"] = vnfd_id
|
||||
elif vnf_package_id:
|
||||
data["vnfPkgId"] = vnf_package_id
|
||||
|
||||
return data
|
||||
|
||||
@@ -11,13 +11,53 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
from oslo_utils import uuidutils
|
||||
from tacker.objects import fields
|
||||
from tacker.tests.functional.vnflcm import base as vnflcm_base
|
||||
from tacker.tests.functional.vnflcm import fake_vnflcm
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(VnfLcmWithUserDataTest, cls).setUpClass()
|
||||
images = cls._list_glance_image()
|
||||
if len(images) == 0:
|
||||
cls.is_setup_error = True
|
||||
return
|
||||
|
||||
# ModifyVNF specific image create.
|
||||
for image in images:
|
||||
specific_image_name = 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 = cls.glance_client.http_client.get(
|
||||
cls.glance_client.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)
|
||||
cls.is_setup_error = True
|
||||
return
|
||||
|
||||
def _vnf_instance_wait_until_fail_detected(self, id,
|
||||
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||
timeout=vnflcm_base.VNF_INSTANTIATE_ERROR_WAIT):
|
||||
@@ -53,6 +93,592 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
def test_inst_update_heal_term(self):
|
||||
"""Test base life cycle operations.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create subscription.
|
||||
- Get subscription informations.
|
||||
- Get list of subscriptions
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF.
|
||||
- Get list of VNF instances.
|
||||
- Get information of instantiated VNF.
|
||||
- Heal VNF.
|
||||
- Create new VNF package for update.
|
||||
- Upload new VNF package.
|
||||
- Update VNF with new package.
|
||||
- Terminate VNF.
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(
|
||||
self._delete_subscription,
|
||||
subscription_id)
|
||||
|
||||
# Subscription show
|
||||
resp, body = self._wait_show_subscription(subscription_id)
|
||||
self.assert_subscription_show(resp, body)
|
||||
|
||||
# Subscription list
|
||||
resp, _ = self._list_subscription()
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = 'functional'
|
||||
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)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Post Setting: Reserve deleting vnf package.
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance_from_body(
|
||||
fake_vnflcm.VnfInstances.make_create_request_body(vnfd_id))
|
||||
vnf_instance_id = vnf_instance['id']
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
self.assert_create_vnf(resp, vnf_instance, vnf_package_id)
|
||||
vnf_instance_name = vnf_instance['vnfInstanceName']
|
||||
self.addCleanup(
|
||||
self._delete_vnf_instance,
|
||||
vnf_instance_id)
|
||||
|
||||
# Instantiate vnf instance
|
||||
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
|
||||
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, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||
|
||||
# List vnf instance
|
||||
filter_expr = {
|
||||
'filter': "(eq,id,{});(eq,vnfInstanceName,{})".format(
|
||||
vnf_instance_id, vnf_instance_name)}
|
||||
resp, vnf_instances = self._list_vnf_instance(params=filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.assertEqual(1, len(vnf_instances))
|
||||
|
||||
# Show vnf instance
|
||||
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Update vnf (vnfdId)
|
||||
sample_name = 'functional2'
|
||||
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)
|
||||
# upload vnf package
|
||||
update_vnf_package_id, update_vnfd_id = \
|
||||
vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client,
|
||||
user_defined_data={"key": sample_name},
|
||||
temp_csar_path=tempname)
|
||||
|
||||
request_body = fake_vnflcm.VnfInstances.make_update_request_body(
|
||||
vnfd_id=update_vnfd_id)
|
||||
resp, _ = self._update_vnf_instance(vnf_instance_id, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_update_vnf(
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
after_id=request_body['vnfdId'],
|
||||
old_id=vnfd_id)
|
||||
|
||||
vnf_package_id = update_vnf_package_id
|
||||
|
||||
# Heal vnf (exists vnfc_instace_id)
|
||||
vnfc_instance_id_list = [
|
||||
vnfc.get('id') for vnfc in vnf_instance.get(
|
||||
'instantiatedVnfInfo', {}).get(
|
||||
'vnfcResourceInfo', [])]
|
||||
request_body = fake_vnflcm.VnfInstances.make_heal_request_body(
|
||||
vnfc_instance_id_list)
|
||||
resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_heal_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||
|
||||
# Terminate VNF
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
resources_list = self._get_heat_resource_list(stack.id)
|
||||
resource_name_list = [r.resource_name for r in resources_list]
|
||||
glance_image_id_list = self._get_glance_image_list_from_stack_resource(
|
||||
stack.id,
|
||||
resource_name_list)
|
||||
|
||||
terminate_req_body = fake_vnflcm.VnfInstances.make_term_request_body()
|
||||
resp, _ = self._terminate_vnf_instance(
|
||||
vnf_instance_id, terminate_req_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_terminate_vnf(
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
stack.id,
|
||||
resource_name_list,
|
||||
glance_image_id_list,
|
||||
vnf_package_id)
|
||||
|
||||
# Delete VNF
|
||||
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
self.assert_delete_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||
|
||||
# Subscription delete
|
||||
resp, response_body = self._delete_subscription(subscription_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
|
||||
resp, show_body = self._show_subscription(subscription_id)
|
||||
self.assertEqual(404, resp.status_code)
|
||||
|
||||
def test_inst_update_pkgid_heal_all(self):
|
||||
"""Test basic life cycle operations with pkg update.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create subscription.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
- Heal VNF
|
||||
- Create new VNF package for update.
|
||||
- Upload new VNF package.
|
||||
- Update VNF with new package.
|
||||
- Terminate VNF.
|
||||
- Delete VNF.
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(
|
||||
self._delete_subscription,
|
||||
subscription_id)
|
||||
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = 'functional'
|
||||
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)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Post Setting: Reserve deleting vnf package.
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance_from_body(
|
||||
fake_vnflcm.VnfInstances.make_create_request_body(vnfd_id))
|
||||
vnf_instance_id = vnf_instance['id']
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
self.assert_create_vnf(resp, vnf_instance, vnf_package_id)
|
||||
self.addCleanup(
|
||||
self._delete_vnf_instance,
|
||||
vnf_instance_id)
|
||||
|
||||
# Instantiate vnf instance
|
||||
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
|
||||
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, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||
|
||||
# Heal vnf (do not specify vnfc_instace_id)
|
||||
# pre check heat status.
|
||||
self.assert_heat_stack_status(vnf_instance_id)
|
||||
|
||||
request_body = fake_vnflcm.VnfInstances.make_heal_request_body()
|
||||
resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
|
||||
# post check heat status.
|
||||
self.assert_heal_vnf(
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
vnf_package_id,
|
||||
expected_stack_status='CREATE_COMPLETE')
|
||||
|
||||
# Update vnf (vnfPkgId)
|
||||
sample_name = 'functional2'
|
||||
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)
|
||||
# upload vnf package
|
||||
update_vnf_package_id, _ = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
request_body = fake_vnflcm.VnfInstances.make_update_request_body(
|
||||
vnf_package_id=update_vnf_package_id)
|
||||
resp, _ = self._update_vnf_instance(vnf_instance_id, request_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_update_vnf(
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
is_vnfd=False,
|
||||
after_id=request_body['vnfPkgId'],
|
||||
old_id=vnf_package_id)
|
||||
vnf_package_id = update_vnf_package_id
|
||||
|
||||
# Terminate VNF
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
resources_list = self._get_heat_resource_list(stack.id)
|
||||
resource_name_list = [r.resource_name for r in resources_list]
|
||||
glance_image_id_list = self._get_glance_image_list_from_stack_resource(
|
||||
stack.id,
|
||||
resource_name_list)
|
||||
|
||||
terminate_req_body = fake_vnflcm.VnfInstances.make_term_request_body()
|
||||
resp, _ = self._terminate_vnf_instance(
|
||||
vnf_instance_id, terminate_req_body)
|
||||
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||
self.assert_terminate_vnf(
|
||||
resp,
|
||||
vnf_instance_id,
|
||||
stack.id,
|
||||
resource_name_list,
|
||||
glance_image_id_list,
|
||||
vnf_package_id)
|
||||
|
||||
# Delete VNF
|
||||
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
self.assert_delete_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||
|
||||
# Subscription delete
|
||||
resp, response_body = self._delete_subscription(subscription_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
|
||||
def test_instantiate_vnf_basehot_invalid(self):
|
||||
"""Test instantiation operation with invalid HOT data.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "user_data_sample_basehot_invalid"
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../etc/samples/etsi/nfv",
|
||||
sample_name))
|
||||
tempname, _ = vnflcm_base._create_csar_user_data_common(
|
||||
csar_package_path)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Reserve deleting vnf package
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Settings
|
||||
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_user_data_basehot_invalid"
|
||||
add_params = {
|
||||
"lcm-operation-user-data": "./UserData/lcm_user_data.py",
|
||||
"lcm-operation-user-data-class": "SampleUserData"}
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance(vnfd_id,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
# Reserve deleting vnf instance
|
||||
self.addCleanup(self._delete_vnf_instance, vnf_instance['id'])
|
||||
|
||||
request_body = \
|
||||
vnflcm_base._create_instantiate_vnf_request_body("simple",
|
||||
vim_id=self.vim['id'],
|
||||
ext_vl=self.ext_vl,
|
||||
add_params=add_params)
|
||||
|
||||
self._instantiate_vnf_instance_fail(vnf_instance['id'], request_body)
|
||||
|
||||
def test_instantiate_vnf_userdata_timeout(self):
|
||||
"""Test instantiation operation timeout with long-running script.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "user_data_sample_userdata_timeout"
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../etc/samples/etsi/nfv",
|
||||
sample_name))
|
||||
tempname, _ = vnflcm_base._create_csar_user_data_common(
|
||||
csar_package_path)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Reserve deleting vnf package
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Settings
|
||||
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_user_data_timeout"
|
||||
add_params = {
|
||||
"lcm-operation-user-data": "./UserData/lcm_user_data_sleeping.py",
|
||||
"lcm-operation-user-data-class": "SampleUserData"}
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance(vnfd_id,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
# Reserve deleting vnf instance
|
||||
self.addCleanup(self._delete_vnf_instance, vnf_instance['id'])
|
||||
|
||||
request_body = \
|
||||
vnflcm_base._create_instantiate_vnf_request_body("simple",
|
||||
vim_id=self.vim['id'],
|
||||
ext_vl=self.ext_vl,
|
||||
add_params=add_params)
|
||||
|
||||
self._instantiate_vnf_instance_fail(vnf_instance['id'], request_body)
|
||||
|
||||
def test_instantiate_vnf_userdata_invalid_hot_param(self):
|
||||
"""Test instantiation operation with invalid HOT and user data.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "user_data_sample_userdata_invalid_hot_param"
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../etc/samples/etsi/nfv",
|
||||
sample_name))
|
||||
tempname, _ = vnflcm_base._create_csar_user_data_common(
|
||||
csar_package_path)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Reserve deleting vnf package
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Settings
|
||||
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_user_data_timeout"
|
||||
add_params = {
|
||||
"lcm-operation-user-data": "./UserData/"
|
||||
"lcm_user_data_invalid_hot_param.py",
|
||||
"lcm-operation-user-data-class": "SampleUserData"}
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance(vnfd_id,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
# Reserve deleting vnf instance
|
||||
self.addCleanup(self._delete_vnf_instance, vnf_instance['id'])
|
||||
|
||||
request_body = \
|
||||
vnflcm_base._create_instantiate_vnf_request_body("simple",
|
||||
vim_id=self.vim['id'],
|
||||
ext_vl=self.ext_vl,
|
||||
add_params=add_params)
|
||||
|
||||
self._instantiate_vnf_instance_fail(vnf_instance['id'], request_body)
|
||||
|
||||
def test_instantiate_vnf_userdata_none(self):
|
||||
"""Test instantiation operation timeout with none user data.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "user_data_sample_userdata_none"
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../etc/samples/etsi/nfv",
|
||||
sample_name))
|
||||
tempname, _ = vnflcm_base._create_csar_user_data_common(
|
||||
csar_package_path)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Reserve deleting vnf package
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Settings
|
||||
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_user_data_timeout"
|
||||
add_params = {
|
||||
"lcm-operation-user-data": "./UserData/lcm_user_data.py",
|
||||
"lcm-operation-user-data-class": "SampleUserData"}
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance(vnfd_id,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
# Reserve deleting vnf instance
|
||||
self.addCleanup(self._delete_vnf_instance, vnf_instance['id'])
|
||||
|
||||
request_body = \
|
||||
vnflcm_base._create_instantiate_vnf_request_body("simple",
|
||||
vim_id=self.vim['id'],
|
||||
ext_vl=self.ext_vl,
|
||||
add_params=add_params)
|
||||
|
||||
self._instantiate_vnf_instance_fail(vnf_instance['id'], request_body)
|
||||
|
||||
def test_instantiate_vnf_userdata_invalid_script(self):
|
||||
"""Test instantiation operation with invalid user script.
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
- Instantiate VNF
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "user_data_sample_userdata_invalid_script"
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../etc/samples/etsi/nfv",
|
||||
sample_name))
|
||||
tempname, _ = vnflcm_base._create_csar_user_data_common(
|
||||
csar_package_path)
|
||||
# upload vnf package
|
||||
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||
self.tacker_client, user_defined_data={
|
||||
"key": sample_name}, temp_csar_path=tempname)
|
||||
|
||||
# Reserve deleting vnf package
|
||||
self.addCleanup(
|
||||
vnflcm_base._delete_vnf_package,
|
||||
self.tacker_client,
|
||||
vnf_package_id)
|
||||
|
||||
# Settings
|
||||
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_user_data_timeout"
|
||||
add_params = {
|
||||
"lcm-operation-user-data": "./UserData/"
|
||||
"lcm_user_data_invalid_script.py",
|
||||
"lcm-operation-user-data-class": "SampleUserData"}
|
||||
|
||||
# Create vnf instance
|
||||
resp, vnf_instance = self._create_vnf_instance(vnfd_id,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
# Reserve deleting vnf instance
|
||||
self.addCleanup(self._delete_vnf_instance, vnf_instance['id'])
|
||||
|
||||
request_body = \
|
||||
vnflcm_base._create_instantiate_vnf_request_body("simple",
|
||||
vim_id=self.vim['id'],
|
||||
ext_vl=self.ext_vl,
|
||||
add_params=add_params)
|
||||
|
||||
self._instantiate_vnf_instance_fail(vnf_instance['id'], request_body)
|
||||
|
||||
def assert_create_vnf(self, resp, vnf_instance, vnf_pkg_id):
|
||||
super().assert_create_vnf(resp, vnf_instance)
|
||||
|
||||
@@ -112,6 +738,49 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
self.tacker_client, vnf_pkg_id)
|
||||
self.assert_vnf_package_usage_state(vnf_pkg_info)
|
||||
|
||||
def assert_update_vnf(self, resp, vnf_instance_id, is_vnfd=True,
|
||||
after_id=None, old_id=None,
|
||||
expected_stack_status='CREATE_COMPLETE'):
|
||||
"""Assert that VNF was updated.
|
||||
|
||||
This method checks if a VNF was really updated or not.
|
||||
We use the same name method of super class to check
|
||||
lifecycle event(e.g. LcmOpOccs, heat stack status).
|
||||
And then, in this method, it gets vnf package info from tacker.
|
||||
We confirm that the old package status is 'NOT_IN_USE' and also
|
||||
a new package status is the same as expected.
|
||||
|
||||
Args:
|
||||
resp (Response): Response headers for HTTP requests.
|
||||
vnf_instance_id (str): Self explanatly
|
||||
is_vnfd (bool, optional): Specify target VNF is VNFD or
|
||||
not. Defaults to True.
|
||||
after_id (str): Updated VNF id. It should be id of VNFD
|
||||
or VNF Package. Defaults to None.
|
||||
old_id (str): Present VNF id. Defaults to None.
|
||||
expected_stack_status (str, optional): The expected status
|
||||
of updated VNF. Defaults to 'CREATE_COMPLETE'.
|
||||
"""
|
||||
super().assert_update_vnf(
|
||||
resp, vnf_instance_id, expected_stack_status=expected_stack_status)
|
||||
|
||||
if is_vnfd:
|
||||
after_filter_attr = {'filter': "(eq,vnfdId,{})".format(after_id)}
|
||||
old_filter_attr = {'filter': "(eq,vnfdId,{})".format(old_id)}
|
||||
else:
|
||||
after_filter_attr = {'filter': "(eq,id,{})".format(after_id)}
|
||||
old_filter_attr = {'filter': "(eq,id,{})".format(old_id)}
|
||||
|
||||
# assert old/new package status.
|
||||
resp, after_vnf_pkg_info = vnflcm_base._list_vnf_package(
|
||||
self.tacker_client, params=after_filter_attr)
|
||||
self.assert_vnf_package_usage_state(after_vnf_pkg_info[0])
|
||||
|
||||
resp, old_vnf_pkg_info = vnflcm_base._list_vnf_package(
|
||||
self.tacker_client, params=old_filter_attr)
|
||||
self.assert_vnf_package_usage_state(old_vnf_pkg_info[0],
|
||||
expected_usage_state=fields.PackageUsageStateType.NOT_IN_USE)
|
||||
|
||||
def assert_vnf_package_usage_state(
|
||||
self,
|
||||
vnf_package_info,
|
||||
|
||||
Reference in New Issue
Block a user