Merge "Support LCM operation with user data"
This commit is contained in:
commit
ffee7ed0dc
@ -108,6 +108,10 @@ class VNFNotFound(exceptions.NotFound):
|
|||||||
message = _('VNF %(vnf_id)s could not be found')
|
message = _('VNF %(vnf_id)s could not be found')
|
||||||
|
|
||||||
|
|
||||||
|
class LCMUserDataFailed(exceptions.TackerException):
|
||||||
|
message = _('LCM user data %(reason)s')
|
||||||
|
|
||||||
|
|
||||||
class ParamYAMLNotWellFormed(exceptions.InvalidInput):
|
class ParamYAMLNotWellFormed(exceptions.InvalidInput):
|
||||||
message = _("Parameter YAML not well formed - %(error_msg_details)s")
|
message = _("Parameter YAML not well formed - %(error_msg_details)s")
|
||||||
|
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Template for test _generate_hot_from_tosca().
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- sample_lcm_with_user_data_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: ntt.nslab.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: simple
|
||||||
|
requirements:
|
||||||
|
virtual_link_external: [ CP1, virtual_link ]
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: ntt.nslab.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: 1
|
||||||
|
sw_image_data:
|
||||||
|
name: Software of VDU1
|
||||||
|
version: '0.4.0'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-512
|
||||||
|
hash: 6513f21e44aa3da349f248188a44bc304a3653a04122d8fb4535423c8e1d14cd6a153f735bb0982e2161b5b5186106570c17a9e58b64dd39390617cd5a350f78
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 1 GiB
|
||||||
|
size: 1 GiB
|
||||||
|
artifacts:
|
||||||
|
sw_image:
|
||||||
|
type: tosca.artifacts.nfv.SwImage
|
||||||
|
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MiB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 1 GiB
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
@ -0,0 +1,31 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: Sample VNFD for LCM with user data
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- sample_lcm_with_user_data_types.yaml
|
||||||
|
- sample_lcm_with_user_data_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: ntt.nslab.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: { get_input: selected_flavour }
|
||||||
|
descriptor_id: eeeeeeee-ebca-4fa7-95ed-4840d70a1111
|
||||||
|
provider: NTT NS lab
|
||||||
|
product_name: Sample VNF for LCM with user data
|
||||||
|
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,53 @@
|
|||||||
|
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:
|
||||||
|
ntt.nslab.VNF:
|
||||||
|
derived_from: tosca.nodes.nfv.VNF
|
||||||
|
properties:
|
||||||
|
descriptor_id:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ eeeeeeee-ebca-4fa7-95ed-4840d70a1111 ] ]
|
||||||
|
default: eeeeeeee-ebca-4fa7-95ed-4840d70a1111
|
||||||
|
descriptor_version:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ '1.0' ] ]
|
||||||
|
default: '1.0'
|
||||||
|
provider:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'NTT NS lab' ] ]
|
||||||
|
default: 'NTT NS lab'
|
||||||
|
product_name:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'Sample VNF for LCM with user data' ] ]
|
||||||
|
default: 'Sample VNF for LCM with user data'
|
||||||
|
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_external:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
- virtual_link_internal:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
interfaces:
|
||||||
|
Vnflcm:
|
||||||
|
type: tosca.interfaces.nfv.Vnflcm
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
# flavor:
|
||||||
|
# get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# 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 tacker.vnfm.lcm_user_data.utils as UserDataUtil
|
||||||
|
|
||||||
|
from tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
# Create HOT input parameter using util functions.
|
||||||
|
initial_param_dict = UserDataUtil.create_initial_param_dict(
|
||||||
|
base_hot_dict)
|
||||||
|
|
||||||
|
vdu_flavor_dict = UserDataUtil.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
vdu_image_dict = UserDataUtil.create_vdu_image_dict(grant_info)
|
||||||
|
cpd_vl_dict = UserDataUtil.create_cpd_vl_dict(
|
||||||
|
base_hot_dict, inst_req_info)
|
||||||
|
|
||||||
|
final_param_dict = UserDataUtil.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
|
||||||
|
return final_param_dict
|
@ -0,0 +1,26 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
# return non dict value
|
||||||
|
return 'DUMMY'
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# 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 tacker.vnfm.lcm_user_data.utils as UserDataUtil
|
||||||
|
|
||||||
|
from tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
# Create HOT input parameter using util functions.
|
||||||
|
initial_param_dict = UserDataUtil.create_initial_param_dict(
|
||||||
|
base_hot_dict)
|
||||||
|
|
||||||
|
vdu_flavor_dict = UserDataUtil.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
vdu_image_dict = UserDataUtil.create_vdu_image_dict(grant_info)
|
||||||
|
cpd_vl_dict = UserDataUtil.create_cpd_vl_dict(
|
||||||
|
base_hot_dict, inst_req_info)
|
||||||
|
|
||||||
|
final_param_dict = UserDataUtil.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
|
||||||
|
return final_param_dict
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# 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 tacker.vnfm.lcm_user_data.utils as UserDataUtil
|
||||||
|
|
||||||
|
from tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
# Create HOT input parameter using util functions.
|
||||||
|
initial_param_dict = UserDataUtil.create_initial_param_dict(
|
||||||
|
base_hot_dict)
|
||||||
|
|
||||||
|
# vdu_flavor_dict = UserDataUtil.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
# vdu_image_dict = UserDataUtil.create_vdu_image_dict(grant_info)
|
||||||
|
# cpd_vl_dict = UserDataUtil.create_cpd_vl_dict(
|
||||||
|
# base_hot_dict, inst_req_info)
|
||||||
|
#
|
||||||
|
# final_param_dict = UserDataUtil.create_final_param_dict(
|
||||||
|
# initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
|
||||||
|
return initial_param_dict
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,28 @@
|
|||||||
|
#
|
||||||
|
# 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.extensions import vnfm
|
||||||
|
from tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
error_reason = _(
|
||||||
|
"invalid user data script.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,7 @@
|
|||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
Created-by: Dummy User
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Entry-Definitions: Definitions/sample_lcm_with_user_data_top.vnfd.yaml
|
||||||
|
|
||||||
|
Name: Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
Content-type: application/x-iso9066-image
|
@ -0,0 +1,51 @@
|
|||||||
|
#
|
||||||
|
# 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 time
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
import tacker.vnfm.lcm_user_data.utils as UserDataUtil
|
||||||
|
|
||||||
|
from tacker.vnfm.lcm_user_data.abstract_user_data import AbstractUserData
|
||||||
|
from tacker.vnfm.lcm_user_data.constants import USER_DATA_TIMEOUT
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SampleUserData(AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(base_hot_dict=None,
|
||||||
|
vnfd_dict=None,
|
||||||
|
inst_req_info=None,
|
||||||
|
grant_info=None):
|
||||||
|
|
||||||
|
# Sleep more than timeout.
|
||||||
|
LOG.debug('Sleep start.')
|
||||||
|
time.sleep(USER_DATA_TIMEOUT + 60)
|
||||||
|
LOG.debug('Sleep end.')
|
||||||
|
|
||||||
|
# Create HOT input parameter using util functions.
|
||||||
|
initial_param_dict = UserDataUtil.create_initial_param_dict(
|
||||||
|
base_hot_dict)
|
||||||
|
|
||||||
|
vdu_flavor_dict = UserDataUtil.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
vdu_image_dict = UserDataUtil.create_vdu_image_dict(grant_info)
|
||||||
|
cpd_vl_dict = UserDataUtil.create_cpd_vl_dict(
|
||||||
|
base_hot_dict, inst_req_info)
|
||||||
|
|
||||||
|
final_param_dict = UserDataUtil.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
|
||||||
|
return final_param_dict
|
32
tacker/tests/etc/samples/hot_lcm_user_data.yaml
Normal file
32
tacker/tests/etc/samples/hot_lcm_user_data.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Template for test _generate_hot_from_tosca().'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor:
|
||||||
|
get_resource: VDU1_flavor
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: [ nfv, VDU, VDU1, image ] }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: [ nfv, CP, CP1, network ] }
|
||||||
|
|
||||||
|
VDU1_flavor:
|
||||||
|
type: OS::Nova::Flavor
|
||||||
|
properties:
|
||||||
|
ram: { get_param: [ nfv, VDU, VDU1, flavor, ram ] }
|
||||||
|
vcpus: { get_param: [ nfv, VDU, VDU1, flavor, vcpus ] }
|
||||||
|
disk: { get_param: [ nfv, VDU, VDU1, flavor, disk ] }
|
||||||
|
|
||||||
|
outputs: {}
|
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"flavourId": "simple",
|
||||||
|
"instantiationLevelId": "instantiation_level_1",
|
||||||
|
"extVirtualLinks": [
|
||||||
|
{
|
||||||
|
"id": "ext-vl-uuid-VL1",
|
||||||
|
"resourceId": "neutron-network-uuid_VL1",
|
||||||
|
"extCps": [
|
||||||
|
{
|
||||||
|
"cpdId": "CP1",
|
||||||
|
"cpConfig": [
|
||||||
|
{
|
||||||
|
"cpProtocolData": [
|
||||||
|
{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vimConnectionInfo": [
|
||||||
|
{
|
||||||
|
"id": "vim-uuid",
|
||||||
|
"vimType": "openstack"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalParams":{
|
||||||
|
"lcm-operation-user-data":"./UserData/lcm_user_data.py",
|
||||||
|
"lcm-operation-user-data-class":"SampleUserData"
|
||||||
|
}
|
||||||
|
}
|
94
tacker/tests/etc/samples/vnfd_lcm_user_data.yaml
Normal file
94
tacker/tests/etc/samples/vnfd_lcm_user_data.yaml
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Template for test _generate_hot_from_tosca().
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- sample_lcm_with_user_data_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: ntt.nslab.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: simple
|
||||||
|
requirements:
|
||||||
|
virtual_link_external: [ CP1, virtual_link ]
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: ntt.nslab.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: 1
|
||||||
|
sw_image_data:
|
||||||
|
name: Software of VDU1
|
||||||
|
version: '0.4.0'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-256
|
||||||
|
hash: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 1 GiB
|
||||||
|
size: 1 GiB
|
||||||
|
artifacts:
|
||||||
|
sw_image:
|
||||||
|
type: tosca.artifacts.nfv.SwImage
|
||||||
|
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MiB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 1 GiB
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
@ -0,0 +1,501 @@
|
|||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
import yaml
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from tacker.objects import fields
|
||||||
|
from tacker.tests.functional import base
|
||||||
|
from tacker.tests import utils
|
||||||
|
|
||||||
|
|
||||||
|
VNF_PACKAGE_UPLOAD_TIMEOUT = 60
|
||||||
|
VNF_INSTANTIATE_TIMEOUT = 60
|
||||||
|
VNF_TERMINATE_TIMEOUT = 60
|
||||||
|
VNF_INSTANTIATE_ERROR_WAIT = 80
|
||||||
|
VNF_DELETE_COMPLETION_WAIT = 60
|
||||||
|
|
||||||
|
|
||||||
|
def _get_external_virtual_links(net0_id):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": "net0",
|
||||||
|
"resourceId": net0_id,
|
||||||
|
"extCps": [{
|
||||||
|
"cpdId": "CP1",
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _create_csar_with_unique_vnfd_id(csar_dir):
|
||||||
|
unique_id = uuidutils.generate_uuid()
|
||||||
|
tempfd, tempname = tempfile.mkstemp(suffix=".zip",
|
||||||
|
dir=os.path.dirname(csar_dir))
|
||||||
|
os.close(tempfd)
|
||||||
|
common_dir = os.path.join(csar_dir, "../common/")
|
||||||
|
ud_common_dir = os.path.join(csar_dir, "../user_data_common/")
|
||||||
|
zcsar = zipfile.ZipFile(tempname, 'w')
|
||||||
|
|
||||||
|
target_dir_list = [csar_dir, common_dir, ud_common_dir]
|
||||||
|
_write_zipfile(zcsar, unique_id, target_dir_list)
|
||||||
|
|
||||||
|
zcsar.close()
|
||||||
|
return tempname, unique_id
|
||||||
|
|
||||||
|
|
||||||
|
def _write_zipfile(zcsar, unique_id, target_dir_list):
|
||||||
|
for target_dir in target_dir_list:
|
||||||
|
for (dpath, _, fnames) in os.walk(target_dir):
|
||||||
|
if not fnames:
|
||||||
|
continue
|
||||||
|
for fname in fnames:
|
||||||
|
src_file = os.path.join(dpath, fname)
|
||||||
|
dst_file = os.path.relpath(
|
||||||
|
os.path.join(dpath, fname), target_dir)
|
||||||
|
if fname.endswith('.yaml') or fname.endswith('.yml'):
|
||||||
|
with open(src_file, 'rb') as yfile:
|
||||||
|
data = yaml.safe_load(yfile)
|
||||||
|
utils._update_unique_id_in_yaml(data, unique_id)
|
||||||
|
zcsar.writestr(dst_file, yaml.dump(
|
||||||
|
data, default_flow_style=False,
|
||||||
|
allow_unicode=True))
|
||||||
|
else:
|
||||||
|
zcsar.write(src_file, dst_file)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_and_upload_vnf_package(tacker_client, csar_package_name,
|
||||||
|
user_defined_data):
|
||||||
|
# create vnf package
|
||||||
|
body = jsonutils.dumps({"userDefinedData": user_defined_data})
|
||||||
|
resp, vnf_package = tacker_client.do_request(
|
||||||
|
'/vnfpkgm/v1/vnf_packages', "POST", body=body)
|
||||||
|
|
||||||
|
# upload vnf package
|
||||||
|
csar_package_path = \
|
||||||
|
"../../etc/samples/etsi/nfv/%s" % csar_package_name
|
||||||
|
file_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
csar_package_path))
|
||||||
|
|
||||||
|
# Generating unique vnfd id. This is required when multiple workers
|
||||||
|
# are running concurrently. The call below creates a new temporary
|
||||||
|
# CSAR with unique vnfd id.
|
||||||
|
file_path, uniqueid = _create_csar_with_unique_vnfd_id(file_path)
|
||||||
|
|
||||||
|
with open(file_path, 'rb') as file_object:
|
||||||
|
resp, resp_body = tacker_client.do_request(
|
||||||
|
'/vnfpkgm/v1/vnf_packages/{id}/package_content'.format(
|
||||||
|
id=vnf_package['id']),
|
||||||
|
"PUT", body=file_object, content_type='application/zip')
|
||||||
|
|
||||||
|
# wait for onboard
|
||||||
|
timeout = VNF_PACKAGE_UPLOAD_TIMEOUT
|
||||||
|
start_time = int(time.time())
|
||||||
|
show_url = os.path.join('/vnfpkgm/v1/vnf_packages', vnf_package['id'])
|
||||||
|
vnfd_id = None
|
||||||
|
while True:
|
||||||
|
resp, body = tacker_client.do_request(show_url, "GET")
|
||||||
|
if body['onboardingState'] == "ONBOARDED":
|
||||||
|
vnfd_id = body['vnfdId']
|
||||||
|
break
|
||||||
|
|
||||||
|
if ((int(time.time()) - start_time) > timeout):
|
||||||
|
raise Exception("Failed to onboard vnf package")
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# remove temporarily created CSAR file
|
||||||
|
os.remove(file_path)
|
||||||
|
return vnf_package['id'], vnfd_id
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmWithUserDataTest(base.BaseTackerTest):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(VnfLcmWithUserDataTest, self).setUp()
|
||||||
|
|
||||||
|
self.tacker_client = base.BaseTackerTest.tacker_http_client()
|
||||||
|
self.base_url = "/vnflcm/v1/vnf_instances"
|
||||||
|
|
||||||
|
vim_list = self.client.list_vims()
|
||||||
|
self.vim = self.get_vim(vim_list, 'VIM0')
|
||||||
|
if not self.vim:
|
||||||
|
assert False, "vim_list is Empty: Default VIM is missing"
|
||||||
|
|
||||||
|
neutron_client = self.neutronclient()
|
||||||
|
net = neutron_client.list_networks()
|
||||||
|
networks = {}
|
||||||
|
for network in net['networks']:
|
||||||
|
networks[network['name']] = network['id']
|
||||||
|
|
||||||
|
net0_id = networks.get('net0')
|
||||||
|
if not net0_id:
|
||||||
|
self.fail("net0 network is not available")
|
||||||
|
|
||||||
|
self.ext_vl = _get_external_virtual_links(net0_id)
|
||||||
|
|
||||||
|
def _create_instantiate_vnf_request_body(self, flavour_id,
|
||||||
|
instantiation_level_id=None, vim_id=None, ext_vl=None,
|
||||||
|
add_params=None):
|
||||||
|
request_body = {"flavourId": flavour_id}
|
||||||
|
|
||||||
|
if instantiation_level_id:
|
||||||
|
request_body["instantiationLevelId"] = instantiation_level_id
|
||||||
|
|
||||||
|
if ext_vl:
|
||||||
|
request_body["extVirtualLinks"] = ext_vl
|
||||||
|
|
||||||
|
if vim_id:
|
||||||
|
request_body["vimConnectionInfo"] = [
|
||||||
|
{"id": uuidutils.generate_uuid(),
|
||||||
|
"vimId": vim_id,
|
||||||
|
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2"}]
|
||||||
|
|
||||||
|
if add_params:
|
||||||
|
request_body["additionalParams"] = add_params
|
||||||
|
|
||||||
|
return request_body
|
||||||
|
|
||||||
|
def _create_vnf_instance(self, vnfd_id, vnf_instance_name=None,
|
||||||
|
vnf_instance_description=None):
|
||||||
|
request_body = {'vnfdId': vnfd_id}
|
||||||
|
if vnf_instance_name:
|
||||||
|
request_body['vnfInstanceName'] = vnf_instance_name
|
||||||
|
|
||||||
|
if vnf_instance_description:
|
||||||
|
request_body['vnfInstanceDescription'] = vnf_instance_description
|
||||||
|
|
||||||
|
resp, response_body = self.http_client.do_request(
|
||||||
|
self.base_url, "POST", body=jsonutils.dumps(request_body))
|
||||||
|
return resp, response_body
|
||||||
|
|
||||||
|
def _delete_vnf_instance(self, id):
|
||||||
|
url = os.path.join(self.base_url, id)
|
||||||
|
resp, body = self.http_client.do_request(url, "DELETE")
|
||||||
|
self.assertEqual(204, resp.status_code)
|
||||||
|
|
||||||
|
# verify vnf instance is deleted
|
||||||
|
url = os.path.join(self.base_url, id)
|
||||||
|
resp, body = self.http_client.do_request(url, "GET")
|
||||||
|
self.assertEqual(404, resp.status_code)
|
||||||
|
|
||||||
|
def _show_vnf_instance(self, id, expected_result=None):
|
||||||
|
show_url = os.path.join(self.base_url, id)
|
||||||
|
resp, vnf_instance = self.http_client.do_request(show_url, "GET")
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
if expected_result:
|
||||||
|
self.assertDictSupersetOf(expected_result, vnf_instance)
|
||||||
|
|
||||||
|
return vnf_instance
|
||||||
|
|
||||||
|
def _vnf_instance_wait(self, id,
|
||||||
|
instantiation_state=fields.VnfInstanceState.INSTANTIATED,
|
||||||
|
timeout=VNF_INSTANTIATE_TIMEOUT):
|
||||||
|
show_url = os.path.join(self.base_url, id)
|
||||||
|
start_time = int(time.time())
|
||||||
|
while True:
|
||||||
|
resp, body = self.http_client.do_request(show_url, "GET")
|
||||||
|
if body['instantiationState'] == instantiation_state:
|
||||||
|
break
|
||||||
|
|
||||||
|
if ((int(time.time()) - start_time) > timeout):
|
||||||
|
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})
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
def _vnf_instance_wait_until_fail_detected(self, id,
|
||||||
|
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||||
|
timeout=VNF_INSTANTIATE_ERROR_WAIT):
|
||||||
|
show_url = os.path.join(self.base_url, id)
|
||||||
|
|
||||||
|
time.sleep(VNF_INSTANTIATE_ERROR_WAIT)
|
||||||
|
resp, body = self.http_client.do_request(show_url, "GET")
|
||||||
|
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 _instantiate_vnf_instance(self, id, request_body):
|
||||||
|
url = os.path.join(self.base_url, id, "instantiate")
|
||||||
|
resp, body = self.http_client.do_request(url, "POST",
|
||||||
|
body=jsonutils.dumps(request_body))
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
self._vnf_instance_wait(id)
|
||||||
|
|
||||||
|
def _instantiate_vnf_instance_fail(self, id, request_body):
|
||||||
|
url = os.path.join(self.base_url, id, "instantiate")
|
||||||
|
resp, body = self.http_client.do_request(url, "POST",
|
||||||
|
body=jsonutils.dumps(request_body))
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
# Confirm that the state doesn't change from NOT_INSTANTIATED.
|
||||||
|
self._vnf_instance_wait_until_fail_detected(id)
|
||||||
|
|
||||||
|
def _terminate_vnf_instance(self, id, request_body):
|
||||||
|
url = os.path.join(self.base_url, id, "terminate")
|
||||||
|
resp, body = self.http_client.do_request(url, "POST",
|
||||||
|
body=jsonutils.dumps(request_body))
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
timeout = request_body.get('gracefulTerminationTimeout')
|
||||||
|
start_time = int(time.time())
|
||||||
|
|
||||||
|
self._vnf_instance_wait(id,
|
||||||
|
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||||
|
timeout=VNF_TERMINATE_TIMEOUT)
|
||||||
|
|
||||||
|
# If gracefulTerminationTimeout is set, check whether vnf
|
||||||
|
# instantiation_state is set to NOT_INSTANTIATED after
|
||||||
|
# gracefulTerminationTimeout seconds.
|
||||||
|
if timeout and int(time.time()) - start_time < timeout:
|
||||||
|
self.fail("Vnf is terminated before graceful termination"
|
||||||
|
"timeout period")
|
||||||
|
|
||||||
|
# wait for status completion
|
||||||
|
time.sleep(VNF_DELETE_COMPLETION_WAIT)
|
||||||
|
|
||||||
|
def _delete_vnf_package(self, vnf_package_id):
|
||||||
|
url = '/vnfpkgm/v1/vnf_packages/%s' % vnf_package_id
|
||||||
|
|
||||||
|
# Update vnf package before delete
|
||||||
|
req_body = jsonutils.dumps({"operationalState": "DISABLED"})
|
||||||
|
self.tacker_client.do_request(url, "PATCH", body=req_body)
|
||||||
|
|
||||||
|
# Delete vnf package before delete
|
||||||
|
self.tacker_client.do_request(url, "DELETE")
|
||||||
|
|
||||||
|
def test_instantiate_vnf_normal(self):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_normal"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, vnf_package_id)
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
vnf_instance_name = "vnf_with_user_data-%s" % \
|
||||||
|
uuidutils.generate_uuid()
|
||||||
|
vnf_instance_description = "vnf_with_user_data_normal"
|
||||||
|
|
||||||
|
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 = self._create_instantiate_vnf_request_body("simple",
|
||||||
|
vim_id=self.vim['id'], ext_vl=self.ext_vl, add_params=add_params)
|
||||||
|
|
||||||
|
self._instantiate_vnf_instance(vnf_instance['id'], request_body)
|
||||||
|
|
||||||
|
vnf_instance = self._show_vnf_instance(vnf_instance['id'])
|
||||||
|
vdu_count = len(vnf_instance['instantiatedVnfInfo']
|
||||||
|
['vnfcResourceInfo'])
|
||||||
|
self.assertEqual(1, vdu_count)
|
||||||
|
|
||||||
|
# Terminate vnf forcefully
|
||||||
|
terminate_req_body = {
|
||||||
|
"terminationType": fields.VnfInstanceTerminationType.FORCEFUL
|
||||||
|
}
|
||||||
|
|
||||||
|
self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body)
|
||||||
|
|
||||||
|
def test_instantiate_vnf_basehot_invalid(self):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_basehot_invalid"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, 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 = self._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):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_userdata_timeout"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, 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 = self._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):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_userdata_invalid_hot_param"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, 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 = self._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):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_userdata_none"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, 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 = self._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):
|
||||||
|
# Create vnf package
|
||||||
|
sample_name = "user_data_sample_userdata_invalid_script"
|
||||||
|
vnf_package_id, vnfd_id = _create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, sample_name, {"key": sample_name})
|
||||||
|
|
||||||
|
# Reserve deleting vnf package
|
||||||
|
self.addCleanup(self._delete_vnf_package, 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 = self._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)
|
0
tacker/tests/unit/vnflcm/vnflcm_driver/__init__.py
Normal file
0
tacker/tests/unit/vnflcm/vnflcm_driver/__init__.py
Normal file
@ -14,16 +14,20 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
|
import importlib
|
||||||
|
import json
|
||||||
import mock
|
import mock
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import yaml
|
||||||
|
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker import context
|
from tacker import context
|
||||||
from tacker.extensions import vnfm
|
from tacker.extensions import vnfm
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
from tacker.tests.common import helpers
|
from tacker.tests.common import helpers
|
||||||
|
from tacker.tests import constants
|
||||||
from tacker.tests.unit import base
|
from tacker.tests.unit import base
|
||||||
from tacker.tests.unit.db import utils
|
from tacker.tests.unit.db import utils
|
||||||
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import client
|
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import client
|
||||||
@ -46,6 +50,8 @@ class TestOpenStack(base.FixturedTestCase):
|
|||||||
self.glance_url = client.GLANCE_URL
|
self.glance_url = client.GLANCE_URL
|
||||||
self.instance_uuid = uuidsentinel.instance_id
|
self.instance_uuid = uuidsentinel.instance_id
|
||||||
self.stack_id = uuidsentinel.stack_id
|
self.stack_id = uuidsentinel.stack_id
|
||||||
|
self.auth_attr = None
|
||||||
|
self.plugin = None
|
||||||
self.json_headers = {'content-type': 'application/json',
|
self.json_headers = {'content-type': 'application/json',
|
||||||
'location': 'http://heat-api/stacks/'
|
'location': 'http://heat-api/stacks/'
|
||||||
+ self.instance_uuid + '/myStack/60f83b5e'}
|
+ self.instance_uuid + '/myStack/60f83b5e'}
|
||||||
@ -111,6 +117,438 @@ class TestOpenStack(base.FixturedTestCase):
|
|||||||
else:
|
else:
|
||||||
self.requests_mock.register_uri('PATCH', url)
|
self.requests_mock.register_uri('PATCH', url)
|
||||||
|
|
||||||
|
def _json_load(self, input_file):
|
||||||
|
json_file = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/lcm_instantiate_request/",
|
||||||
|
str(input_file)))
|
||||||
|
with open(json_file) as f:
|
||||||
|
json_dict = json.load(f)
|
||||||
|
return json_dict
|
||||||
|
|
||||||
|
def _read_file(self):
|
||||||
|
yaml_file = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/",
|
||||||
|
"hot_lcm_user_data.yaml"))
|
||||||
|
with open(yaml_file, 'r') as f:
|
||||||
|
yaml_file_dict = yaml.safe_load(f)
|
||||||
|
return yaml_file_dict
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_normal(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
vnf_resource.resource_identifier = constants.INVALID_UUID
|
||||||
|
grant_info_test = {'vdu_name': {vnf_resource}}
|
||||||
|
self.openstack.create(self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, inst_req_info=inst_req_info_test,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
base_hot_dict=base_hot_dict_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_heat_stack(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict = None
|
||||||
|
vnf_package_path = None
|
||||||
|
self.openstack.create(self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict, vnf_package_path)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_userdata_none(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# delete lcm-operation-user-data from additionalParams
|
||||||
|
del test_json['additionalParams']['lcm-operation-user-data']
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_userdataclass_none(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# delete lcm-operation-user-data-class from additionalParams
|
||||||
|
del test_json['additionalParams']['lcm-operation-user-data-class']
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_userdata_null(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# set null to setlcm-operation-user-data from additionalParams
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data'] = ''
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_userdataclass_null(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# set null to setlcm-operation-user-data-class from additionalParams
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data-class'] = ''
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_import_module_exception(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
with mock.patch.object(importlib, 'import_module') as mock_importlib:
|
||||||
|
mock_importlib.side_effect = Exception('Test Exception')
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_getattr_none(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
with mock.patch.object(importlib, 'import_module') as mock_importlib:
|
||||||
|
mock_importlib.return_value = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_missing_file(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_none"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
vnf_resource.resource_identifier = constants.INVALID_UUID
|
||||||
|
grant_info_test = {'vdu_name': {vnf_resource}}
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, inst_req_info=inst_req_info_test,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
base_hot_dict=base_hot_dict_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_return_none_dict(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_non_dict"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data'] = \
|
||||||
|
'UserData/lcm_user_data_non_dict.py'
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
vnf_resource.resource_identifier = constants.INVALID_UUID
|
||||||
|
grant_info_test = {'vdu_name': {vnf_resource}}
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, inst_req_info=inst_req_info_test,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
base_hot_dict=base_hot_dict_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_none_base_hot_dict(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
base_hot_dict_test = None
|
||||||
|
vnf_package_path_test = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_invalid_user_data(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# set dummy to setlcm-operation-user-data-class from additionalParams
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data-class'] = \
|
||||||
|
'DummyUserData'
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_invalid_user_data_class(self,
|
||||||
|
mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# set dummy to setlcm-operation-user-data-class from additionalParams
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data-class'] = \
|
||||||
|
'DummyUserData'
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
grant_info_test = None
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict_test,
|
||||||
|
vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_lcm_user_data_and_user_data_class_no_value(self,
|
||||||
|
mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# set null to setlcm-operation-user-data and
|
||||||
|
# lcm-operation-user-data-class from additionalParams
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data'] = ''
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data-class'] = ''
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = test_json['extVirtualLinks']
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
vnf_resource.resource_identifier = constants.INVALID_UUID
|
||||||
|
grant_info_test = {'vdu_name': {vnf_resource}}
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, inst_req_info=inst_req_info_test,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
base_hot_dict=base_hot_dict_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_lcm_user_data_and_user_data_class_none(self,
|
||||||
|
mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_normal"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
# delete lcm-operation-user-data and
|
||||||
|
# lcm-operation-user-data-class from additionalParams
|
||||||
|
del test_json['additionalParams']['lcm-operation-user-data']
|
||||||
|
del test_json['additionalParams']['lcm-operation-user-data-class']
|
||||||
|
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = test_json['extVirtualLinks']
|
||||||
|
base_hot_dict = None
|
||||||
|
self.assertRaises(BaseException,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_no_additionalparams(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_normal"))
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
inst_req_info_test.additional_params = None
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
base_hot_dict = None
|
||||||
|
self.assertRaises(BaseException,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, base_hot_dict,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
inst_req_info=inst_req_info_test)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
def test_create_instance_exception(self, mock_OpenstackClients_heat):
|
||||||
|
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
|
vnf['placement_attr'] = {'region_name': 'dummy_region'}
|
||||||
|
base_hot_dict_test = self._read_file()
|
||||||
|
vnf_package_path_test = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/etsi/nfv",
|
||||||
|
"user_data_sample_userdata_invalid_script"))
|
||||||
|
inst_req_info_test = type('', (), {})
|
||||||
|
test_json = self._json_load(
|
||||||
|
'instantiate_vnf_request_lcm_userdata.json')
|
||||||
|
test_json['additionalParams']['lcm-operation-user-data'] = \
|
||||||
|
'UserData/lcm_user_data_invalid_script.py'
|
||||||
|
inst_req_info_test.additional_params = test_json['additionalParams']
|
||||||
|
inst_req_info_test.ext_virtual_links = None
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
vnf_resource.resource_identifier = constants.INVALID_UUID
|
||||||
|
grant_info_test = {'vdu_name': {vnf_resource}}
|
||||||
|
self.assertRaises(vnfm.LCMUserDataFailed,
|
||||||
|
self.openstack.create,
|
||||||
|
self.plugin, self.context, vnf,
|
||||||
|
self.auth_attr, inst_req_info=inst_req_info_test,
|
||||||
|
vnf_package_path=vnf_package_path_test,
|
||||||
|
base_hot_dict=base_hot_dict_test,
|
||||||
|
grant_info=grant_info_test)
|
||||||
|
|
||||||
def test_create_wait(self):
|
def test_create_wait(self):
|
||||||
self._response_in_wait_until_stack_ready(["CREATE_IN_PROGRESS",
|
self._response_in_wait_until_stack_ready(["CREATE_IN_PROGRESS",
|
||||||
"CREATE_COMPLETE"])
|
"CREATE_COMPLETE"])
|
||||||
|
0
tacker/tests/unit/vnfm/lcm_user_data/__init__.py
Normal file
0
tacker/tests/unit/vnfm/lcm_user_data/__init__.py
Normal file
192
tacker/tests/unit/vnfm/lcm_user_data/utils/test_utils.py
Normal file
192
tacker/tests/unit/vnfm/lcm_user_data/utils/test_utils.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import testtools
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from tacker.objects import instantiate_vnf_req
|
||||||
|
from tacker.tests import constants
|
||||||
|
from tacker.vnfm.lcm_user_data import utils
|
||||||
|
|
||||||
|
default_initial_param_dict = {
|
||||||
|
'nfv': {
|
||||||
|
'VDU': {
|
||||||
|
},
|
||||||
|
'CP': {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
example_initial_param_dict = {
|
||||||
|
'nfv': {
|
||||||
|
'VDU': {
|
||||||
|
'VDU1': {},
|
||||||
|
},
|
||||||
|
'CP': {
|
||||||
|
'CP1': {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestUtils(testtools.TestCase):
|
||||||
|
|
||||||
|
def _read_file(self, input_file):
|
||||||
|
yaml_file = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
"../../../../etc/samples/",
|
||||||
|
str(input_file)))
|
||||||
|
with open(yaml_file, 'r') as f:
|
||||||
|
yaml_file_dict = yaml.safe_load(f)
|
||||||
|
return yaml_file_dict
|
||||||
|
|
||||||
|
def test_create_initial_param_dict(self):
|
||||||
|
base_hot_dict = self._read_file("hot_lcm_user_data.yaml")
|
||||||
|
initial_param_dict = utils.create_initial_param_dict(base_hot_dict)
|
||||||
|
self.assertEqual(example_initial_param_dict, initial_param_dict)
|
||||||
|
|
||||||
|
def test_create_initial_param_dict_empty_argument(self):
|
||||||
|
base_hot_dict = {}
|
||||||
|
initial_param_dict = utils.create_initial_param_dict(base_hot_dict)
|
||||||
|
self.assertEqual(default_initial_param_dict, initial_param_dict)
|
||||||
|
|
||||||
|
def test_create_final_param_dict(self):
|
||||||
|
initial_param_dict = {
|
||||||
|
'nfv': {
|
||||||
|
'CP': {
|
||||||
|
'CP1': {
|
||||||
|
'network': 'cp1_network_id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'VDU': {
|
||||||
|
'VDU1': {
|
||||||
|
'image': 'vdu1_image_uuid',
|
||||||
|
'flavor': {
|
||||||
|
'ram': 'vdu1_flavor_ram'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vdu_flavor_dict = {'VDU1': {'ram': 'vdu1_flavor_ram_change'}}
|
||||||
|
vdu_image_dict = {'VDU1': 'vdu1_image_uuid_change'}
|
||||||
|
cpd_vl_dict = {'CP1': {'cp1_network_id_change_1',
|
||||||
|
'cp1_network_id_change_2'}}
|
||||||
|
expected_final_param_dict = {
|
||||||
|
'nfv': {
|
||||||
|
'CP': {
|
||||||
|
'CP1': {
|
||||||
|
'network': {
|
||||||
|
'cp1_network_id_change_1',
|
||||||
|
'cp1_network_id_change_2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'VDU': {
|
||||||
|
'VDU1': {
|
||||||
|
'image': 'vdu1_image_uuid_change',
|
||||||
|
'flavor': {
|
||||||
|
'ram': 'vdu1_flavor_ram_change'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actual_final_param_dict = utils.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
self.assertEqual(expected_final_param_dict, actual_final_param_dict)
|
||||||
|
|
||||||
|
def test_create_final_param_dict_empty_value(self):
|
||||||
|
initial_param_dict = {'nfv': {'VDU': '', 'CP': ''}}
|
||||||
|
expected_final_param_dict = {'nfv': {'VDU': '', 'CP': ''}}
|
||||||
|
vdu_flavor_dict = {}
|
||||||
|
vdu_image_dict = {}
|
||||||
|
cpd_vl_dict = {}
|
||||||
|
actual_final_param_dict = utils.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
self.assertEqual(expected_final_param_dict, actual_final_param_dict)
|
||||||
|
|
||||||
|
def test_create_final_param_dict_empty_argument(self):
|
||||||
|
initial_param_dict = {}
|
||||||
|
expected_final_param_dict = {}
|
||||||
|
vdu_flavor_dict = {}
|
||||||
|
vdu_image_dict = {}
|
||||||
|
cpd_vl_dict = {}
|
||||||
|
actual_final_param_dict = utils.create_final_param_dict(
|
||||||
|
initial_param_dict, vdu_flavor_dict, vdu_image_dict, cpd_vl_dict)
|
||||||
|
self.assertEqual(expected_final_param_dict, actual_final_param_dict)
|
||||||
|
|
||||||
|
def test_create_vdu_flavor_dict(self):
|
||||||
|
vnfd_dict = self._read_file('vnfd_lcm_user_data.yaml')
|
||||||
|
test_vnfd_dict = {'VNF': {}, 'VDU1':
|
||||||
|
{'ram': 512, 'vcpus': 1, 'disk': 1}, 'CP1': {}}
|
||||||
|
vdu_flavor_dict = utils.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
self.assertEqual(test_vnfd_dict, vdu_flavor_dict)
|
||||||
|
|
||||||
|
def test_create_vdu_flavor_dict_empty_argument(self):
|
||||||
|
vnfd_dict = {}
|
||||||
|
vdu_flavor_dict = utils.create_vdu_flavor_dict(vnfd_dict)
|
||||||
|
self.assertEqual({}, vdu_flavor_dict)
|
||||||
|
|
||||||
|
def test_create_vdu_image_dict(self):
|
||||||
|
vnf_resource = type('', (), {})
|
||||||
|
resource_identifier = constants.INVALID_UUID
|
||||||
|
vnf_resource.resource_identifier = resource_identifier
|
||||||
|
grant_info = {'vdu_name': {vnf_resource}}
|
||||||
|
|
||||||
|
vdu_image_dict = utils.create_vdu_image_dict(grant_info)
|
||||||
|
self.assertEqual({'vdu_name': resource_identifier}, vdu_image_dict)
|
||||||
|
|
||||||
|
def test_create_vdu_image_dict_empty_argument(self):
|
||||||
|
grant_info = {}
|
||||||
|
vdu_image_dict = utils.create_vdu_image_dict(grant_info)
|
||||||
|
self.assertEqual({}, vdu_image_dict)
|
||||||
|
|
||||||
|
def test_create_cpd_vl_dict(self):
|
||||||
|
base_hot_dict = {'resources': {'dummy_cpd_id': "101010_d"}}
|
||||||
|
inst_req_info = instantiate_vnf_req.InstantiateVnfRequest()
|
||||||
|
ext_virtual_links_test_value = instantiate_vnf_req.ExtVirtualLinkData()
|
||||||
|
ext_virtual_links_test_value.resource_id = 'dummy_resource_id'
|
||||||
|
|
||||||
|
ext_virtual_links_ext_cps = []
|
||||||
|
ext_virtual_links_ext_cps_value = instantiate_vnf_req.VnfExtCpData()
|
||||||
|
ext_virtual_links_ext_cps_value.cpd_id = 'dummy_cpd_id'
|
||||||
|
ext_virtual_links_ext_cps.append(ext_virtual_links_ext_cps_value)
|
||||||
|
|
||||||
|
ext_virtual_links_test_value.ext_cps = ext_virtual_links_ext_cps
|
||||||
|
inst_req_info.ext_virtual_links.append(ext_virtual_links_test_value)
|
||||||
|
cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info)
|
||||||
|
self.assertEqual({'dummy_cpd_id': 'dummy_resource_id'}, cpd_vl_dict)
|
||||||
|
|
||||||
|
def test_create_cpd_vl_dict_no_cp_resource(self):
|
||||||
|
base_hot_dict = {'resources': {'dummy_cpd_id': "101010_d"}}
|
||||||
|
inst_req_info = instantiate_vnf_req.InstantiateVnfRequest()
|
||||||
|
ext_virtual_links_test_value = instantiate_vnf_req.ExtVirtualLinkData()
|
||||||
|
ext_virtual_links_test_value.resource_id = 'dummy_resource_id'
|
||||||
|
|
||||||
|
ext_virtual_links_ext_cps = []
|
||||||
|
ext_virtual_links_ext_cps_value = instantiate_vnf_req.VnfExtCpData()
|
||||||
|
ext_virtual_links_ext_cps_value.cpd_id = ""
|
||||||
|
ext_virtual_links_ext_cps.append(ext_virtual_links_ext_cps_value)
|
||||||
|
|
||||||
|
ext_virtual_links_test_value.ext_cps = ext_virtual_links_ext_cps
|
||||||
|
inst_req_info.ext_virtual_links.append(ext_virtual_links_test_value)
|
||||||
|
cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info)
|
||||||
|
self.assertEqual({}, cpd_vl_dict)
|
||||||
|
|
||||||
|
def test_create_cpd_vl_dict_empty_argument(self):
|
||||||
|
base_hot_dict = {}
|
||||||
|
inst_req_info = type('', (), {})
|
||||||
|
inst_req_info.ext_virtual_links = None
|
||||||
|
cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info)
|
||||||
|
self.assertEqual({}, cpd_vl_dict)
|
@ -729,3 +729,28 @@ def _convert_desired_capacity(inst_level_id, vnfd_dict, vdu):
|
|||||||
desired_capacity = initial_delta + delta_num * level_num
|
desired_capacity = initial_delta + delta_num * level_num
|
||||||
|
|
||||||
return desired_capacity
|
return desired_capacity
|
||||||
|
|
||||||
|
|
||||||
|
def _get_vnf_package_path(context, vnfd_id):
|
||||||
|
vnf_package_id = _get_vnf_package_id(context, vnfd_id)
|
||||||
|
vnf_package_base_path = cfg.CONF.vnf_package.vnf_package_csar_path
|
||||||
|
vnf_package_path = vnf_package_base_path + '/' + vnf_package_id
|
||||||
|
return vnf_package_path
|
||||||
|
|
||||||
|
|
||||||
|
def _get_base_hot_dict(context, vnfd_id):
|
||||||
|
vnf_package_id = _get_vnf_package_id(context, vnfd_id)
|
||||||
|
vnf_package_base_path = cfg.CONF.vnf_package.vnf_package_csar_path
|
||||||
|
vnf_package_csar_path = vnf_package_base_path + '/' + vnf_package_id
|
||||||
|
base_hot_dir = 'BaseHOT'
|
||||||
|
ext = [".yaml", ".yml"]
|
||||||
|
|
||||||
|
base_hot_path = vnf_package_csar_path + '/' + base_hot_dir
|
||||||
|
base_hot_dict = None
|
||||||
|
if os.path.exists(base_hot_path):
|
||||||
|
for file in os.listdir(base_hot_path):
|
||||||
|
if file.endswith(tuple(ext)):
|
||||||
|
source_file_path = os.path.join(base_hot_path, file)
|
||||||
|
base_hot_dict = yaml.safe_load(open(source_file_path))
|
||||||
|
LOG.debug("Loaded base hot: %s", base_hot_dict)
|
||||||
|
return base_hot_dict
|
||||||
|
@ -137,6 +137,12 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
instantiate_vnf_req):
|
instantiate_vnf_req):
|
||||||
vnfd_dict = vnflcm_utils._get_vnfd_dict(context, vnf_instance.vnfd_id,
|
vnfd_dict = vnflcm_utils._get_vnfd_dict(context, vnf_instance.vnfd_id,
|
||||||
instantiate_vnf_req.flavour_id)
|
instantiate_vnf_req.flavour_id)
|
||||||
|
base_hot_dict = vnflcm_utils._get_base_hot_dict(
|
||||||
|
context, vnf_instance.vnfd_id)
|
||||||
|
vnf_package_path = None
|
||||||
|
if base_hot_dict is not None:
|
||||||
|
vnf_package_path = vnflcm_utils._get_vnf_package_path(
|
||||||
|
context, vnf_instance.vnfd_id)
|
||||||
|
|
||||||
param_for_subs_map = vnflcm_utils._get_param_data(vnfd_dict,
|
param_for_subs_map = vnflcm_utils._get_param_data(vnfd_dict,
|
||||||
instantiate_vnf_req)
|
instantiate_vnf_req)
|
||||||
@ -167,6 +173,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
context=context, vnf_instance=vnf_instance,
|
context=context, vnf_instance=vnf_instance,
|
||||||
vnfd_dict=final_vnf_dict, grant_response=vnf_resources,
|
vnfd_dict=final_vnf_dict, grant_response=vnf_resources,
|
||||||
vim_connection_info=vim_connection_info,
|
vim_connection_info=vim_connection_info,
|
||||||
|
base_hot_dict=base_hot_dict,
|
||||||
|
vnf_package_path=vnf_package_path,
|
||||||
instantiate_vnf_req=instantiate_vnf_req)
|
instantiate_vnf_req=instantiate_vnf_req)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
|
@ -15,8 +15,13 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
import eventlet
|
||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
@ -31,6 +36,7 @@ from tacker.common import utils
|
|||||||
from tacker.extensions import vnflcm
|
from tacker.extensions import vnflcm
|
||||||
from tacker.extensions import vnfm
|
from tacker.extensions import vnfm
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
|
from tacker.tosca.utils import represent_odict
|
||||||
from tacker.vnfm.infra_drivers import abstract_driver
|
from tacker.vnfm.infra_drivers import abstract_driver
|
||||||
from tacker.vnfm.infra_drivers.openstack import constants as infra_cnst
|
from tacker.vnfm.infra_drivers.openstack import constants as infra_cnst
|
||||||
from tacker.vnfm.infra_drivers.openstack import glance_client as gc
|
from tacker.vnfm.infra_drivers.openstack import glance_client as gc
|
||||||
@ -38,7 +44,9 @@ from tacker.vnfm.infra_drivers.openstack import heat_client as hc
|
|||||||
from tacker.vnfm.infra_drivers.openstack import translate_template
|
from tacker.vnfm.infra_drivers.openstack import translate_template
|
||||||
from tacker.vnfm.infra_drivers.openstack import vdu
|
from tacker.vnfm.infra_drivers.openstack import vdu
|
||||||
from tacker.vnfm.infra_drivers import scale_driver
|
from tacker.vnfm.infra_drivers import scale_driver
|
||||||
|
from tacker.vnfm.lcm_user_data.constants import USER_DATA_TIMEOUT
|
||||||
|
|
||||||
|
eventlet.monkey_patch(time=True)
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -106,17 +114,140 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
|||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def create(self, plugin, context, vnf, auth_attr,
|
def create(self, plugin, context, vnf, auth_attr,
|
||||||
|
base_hot_dict=None, vnf_package_path=None,
|
||||||
inst_req_info=None, grant_info=None):
|
inst_req_info=None, grant_info=None):
|
||||||
LOG.debug('vnf %s', vnf)
|
LOG.debug('vnf %s', vnf)
|
||||||
region_name = vnf.get('placement_attr', {}).get('region_name', None)
|
region_name = vnf.get('placement_attr', {}).get('region_name', None)
|
||||||
heatclient = hc.HeatClient(auth_attr, region_name)
|
heatclient = hc.HeatClient(auth_attr, region_name)
|
||||||
|
additional_param = None
|
||||||
|
if inst_req_info is not None:
|
||||||
|
additional_param = inst_req_info.additional_params
|
||||||
|
|
||||||
|
user_data_path = None
|
||||||
|
user_data_class = None
|
||||||
|
if additional_param is not None:
|
||||||
|
LOG.debug('additional_param: %s', additional_param)
|
||||||
|
user_data_path = additional_param.get(
|
||||||
|
'lcm-operation-user-data')
|
||||||
|
user_data_class = additional_param.get(
|
||||||
|
'lcm-operation-user-data-class')
|
||||||
|
LOG.debug('UserData path: %s', user_data_path)
|
||||||
|
LOG.debug('UserData class: %s', user_data_class)
|
||||||
|
|
||||||
|
if user_data_path is not None and user_data_class is not None:
|
||||||
|
LOG.info('Execute user data and create heat-stack.')
|
||||||
|
if base_hot_dict is None:
|
||||||
|
error_reason = _("failed to get Base HOT.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
|
||||||
|
vnfd_str = vnf['vnfd']['attributes']['vnfd']
|
||||||
|
vnfd_dict = yaml.safe_load(vnfd_str)
|
||||||
|
LOG.debug('VNFD: %s', vnfd_dict)
|
||||||
|
LOG.debug('VNF package path: %s', vnf_package_path)
|
||||||
|
sys.path.append(vnf_package_path)
|
||||||
|
user_data_module = os.path.splitext(
|
||||||
|
user_data_path.lstrip('./'))[0].replace('/', '.')
|
||||||
|
LOG.debug('UserData module: %s', user_data_module)
|
||||||
|
LOG.debug('Append sys.path: %s', sys.path)
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(user_data_module)
|
||||||
|
LOG.debug('Append sys.modules: %s', sys.modules)
|
||||||
|
except Exception:
|
||||||
|
self._delete_user_data_module(user_data_module)
|
||||||
|
error_reason = _(
|
||||||
|
"failed to get UserData path based on "
|
||||||
|
"lcm-operation-user-data from additionalParams.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
finally:
|
||||||
|
sys.path.remove(vnf_package_path)
|
||||||
|
LOG.debug('Remove sys.path: %s', sys.path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
klass = getattr(module, user_data_class)
|
||||||
|
except Exception:
|
||||||
|
self._delete_user_data_module(user_data_module)
|
||||||
|
error_reason = _(
|
||||||
|
"failed to get UserData class based on "
|
||||||
|
"lcm-operation-user-data-class from additionalParams.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
|
||||||
|
# Set the timeout and execute the UserData script.
|
||||||
|
hot_param_dict = None
|
||||||
|
with eventlet.timeout.Timeout(USER_DATA_TIMEOUT, False):
|
||||||
|
try:
|
||||||
|
hot_param_dict = klass.instantiate(
|
||||||
|
base_hot_dict, vnfd_dict, inst_req_info, grant_info)
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self._delete_user_data_module(user_data_module)
|
||||||
|
|
||||||
|
if hot_param_dict is not None:
|
||||||
|
LOG.info('HOT input parameter: %s', hot_param_dict)
|
||||||
|
else:
|
||||||
|
error_reason = _(
|
||||||
|
"fails due to timeout[sec]: %s") % USER_DATA_TIMEOUT
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
if not isinstance(hot_param_dict, dict):
|
||||||
|
error_reason = _(
|
||||||
|
"return value as HOT parameter from UserData "
|
||||||
|
"is not in dict format.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
|
||||||
|
# Create heat-stack with BaseHOT and parameters
|
||||||
|
stack = self._create_stack_with_user_data(
|
||||||
|
heatclient, vnf, base_hot_dict, hot_param_dict)
|
||||||
|
|
||||||
|
elif user_data_path is None and user_data_class is None:
|
||||||
|
LOG.info('Execute heat-translator and create heat-stack.')
|
||||||
|
tth = translate_template.TOSCAToHOT(vnf, heatclient,
|
||||||
|
inst_req_info, grant_info)
|
||||||
|
tth.generate_hot()
|
||||||
|
stack = self._create_stack(heatclient, tth.vnf, tth.fields)
|
||||||
|
else:
|
||||||
|
error_reason = _(
|
||||||
|
"failed to get lcm-operation-user-data or "
|
||||||
|
"lcm-operation-user-data-class from additionalParams.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
||||||
|
|
||||||
tth = translate_template.TOSCAToHOT(vnf, heatclient,
|
|
||||||
inst_req_info, grant_info)
|
|
||||||
tth.generate_hot()
|
|
||||||
stack = self._create_stack(heatclient, tth.vnf, tth.fields)
|
|
||||||
return stack['stack']['id']
|
return stack['stack']['id']
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _delete_user_data_module(self, user_data_module):
|
||||||
|
# Delete module recursively.
|
||||||
|
mp_list = user_data_module.split('.')
|
||||||
|
while True:
|
||||||
|
del_module = '.'.join(mp_list)
|
||||||
|
print(del_module)
|
||||||
|
if del_module in sys.modules:
|
||||||
|
del sys.modules[del_module]
|
||||||
|
if len(mp_list) == 1:
|
||||||
|
break
|
||||||
|
mp_list = mp_list[0:-1]
|
||||||
|
LOG.debug('Remove sys.modules: %s', sys.modules)
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _create_stack_with_user_data(self, heatclient, vnf,
|
||||||
|
base_hot_dict, hot_param_dict):
|
||||||
|
fields = {}
|
||||||
|
fields['stack_name'] = ("vnflcm_" + vnf["id"])
|
||||||
|
fields['template'] = self._format_base_hot(base_hot_dict)
|
||||||
|
fields['parameters'] = hot_param_dict
|
||||||
|
|
||||||
|
LOG.debug('fields: %s', fields)
|
||||||
|
LOG.debug('template: %s', fields['template'])
|
||||||
|
stack = heatclient.create(fields)
|
||||||
|
|
||||||
|
return stack
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _format_base_hot(self, base_hot_dict):
|
||||||
|
yaml.SafeDumper.add_representer(OrderedDict,
|
||||||
|
lambda dumper, value: represent_odict(dumper,
|
||||||
|
u'tag:yaml.org,2002:map', value))
|
||||||
|
|
||||||
|
return yaml.safe_dump(base_hot_dict)
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def _create_stack(self, heatclient, vnf, fields):
|
def _create_stack(self, heatclient, vnf, fields):
|
||||||
if 'stack_name' not in fields:
|
if 'stack_name' not in fields:
|
||||||
@ -603,7 +734,8 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
|||||||
|
|
||||||
def instantiate_vnf(self, context, vnf_instance, vnfd_dict,
|
def instantiate_vnf(self, context, vnf_instance, vnfd_dict,
|
||||||
vim_connection_info, instantiate_vnf_req,
|
vim_connection_info, instantiate_vnf_req,
|
||||||
grant_response):
|
grant_response,
|
||||||
|
base_hot_dict=None, vnf_package_path=None):
|
||||||
access_info = vim_connection_info.access_info
|
access_info = vim_connection_info.access_info
|
||||||
region_name = access_info.get('region')
|
region_name = access_info.get('region')
|
||||||
placement_attr = vnfd_dict.get('placement_attr', {})
|
placement_attr = vnfd_dict.get('placement_attr', {})
|
||||||
@ -611,7 +743,8 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
|||||||
vnfd_dict['placement_attr'] = placement_attr
|
vnfd_dict['placement_attr'] = placement_attr
|
||||||
|
|
||||||
instance_id = self.create(None, context, vnfd_dict,
|
instance_id = self.create(None, context, vnfd_dict,
|
||||||
access_info, inst_req_info=instantiate_vnf_req,
|
access_info, base_hot_dict, vnf_package_path,
|
||||||
|
inst_req_info=instantiate_vnf_req,
|
||||||
grant_info=grant_response)
|
grant_info=grant_response)
|
||||||
vnfd_dict['instance_id'] = instance_id
|
vnfd_dict['instance_id'] = instance_id
|
||||||
return instance_id
|
return instance_id
|
||||||
|
0
tacker/vnfm/lcm_user_data/__init__.py
Normal file
0
tacker/vnfm/lcm_user_data/__init__.py
Normal file
30
tacker/vnfm/lcm_user_data/abstract_user_data.py
Normal file
30
tacker/vnfm/lcm_user_data/abstract_user_data.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#
|
||||||
|
# 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 abc
|
||||||
|
import six
|
||||||
|
|
||||||
|
from tacker.extensions import vnfm
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class AbstractUserData(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def instantiate(vnfd_dict=None,
|
||||||
|
vdu_image_dict=None,
|
||||||
|
cp_vl_dict=None):
|
||||||
|
error_reason = _(
|
||||||
|
"failed to execute UserData because not implemented.")
|
||||||
|
raise vnfm.LCMUserDataFailed(reason=error_reason)
|
14
tacker/vnfm/lcm_user_data/constants.py
Normal file
14
tacker/vnfm/lcm_user_data/constants.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
USER_DATA_TIMEOUT = 60
|
172
tacker/vnfm/lcm_user_data/utils.py
Normal file
172
tacker/vnfm/lcm_user_data/utils.py
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#
|
||||||
|
# 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 copy
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tacker.common.utils import MemoryUnit
|
||||||
|
|
||||||
|
|
||||||
|
"""Define util functions that can be used in UserData.
|
||||||
|
|
||||||
|
As for how to use the function (`create _ * _ dict`), dict can be obtained
|
||||||
|
as a return value by setting the required arguments and calling.
|
||||||
|
For detailed usage, check the docstring of each function.
|
||||||
|
|
||||||
|
NOTE: The functions defined here are limited to common and basic ones.
|
||||||
|
Please note that not all conversion logics are offered in Tacker,
|
||||||
|
different from Heat-Translator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
HOT_NOVA_SERVER = 'OS::Nova::Server'
|
||||||
|
HOT_NOVA_FLAVOR = 'OS::Nova::Flavor'
|
||||||
|
HOT_NEUTRON_PORT = 'OS::Neutron::Port'
|
||||||
|
SUPPORTED_HOT_TYPE = [HOT_NOVA_SERVER, HOT_NOVA_FLAVOR, HOT_NEUTRON_PORT]
|
||||||
|
|
||||||
|
|
||||||
|
def create_initial_param_dict(base_hot_dict):
|
||||||
|
"""Create initial dict containing information about get_param resources.
|
||||||
|
|
||||||
|
:param base_hot_dict: dict(Base HOT dict format)
|
||||||
|
:return: dict('nfv', Initial HOT resource dict)
|
||||||
|
|
||||||
|
NOTE: 'nfv' is a fixed value for 1st element.
|
||||||
|
'VDU' and 'CP' are supported for 2nd element.
|
||||||
|
3rd and 4th element are mandatory.
|
||||||
|
"""
|
||||||
|
initial_param_dict = {
|
||||||
|
'nfv': {
|
||||||
|
'VDU': {
|
||||||
|
},
|
||||||
|
'CP': {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resources = base_hot_dict.get('resources', {})
|
||||||
|
for resource_name, resource_val in resources.items():
|
||||||
|
resource_type = resource_val.get('type')
|
||||||
|
if resource_type in SUPPORTED_HOT_TYPE:
|
||||||
|
resource_props = resource_val.get('properties', {})
|
||||||
|
for prop_key, prop_val in resource_props.items():
|
||||||
|
if isinstance(prop_val, dict) and 'get_param' in prop_val:
|
||||||
|
param_list = prop_val['get_param']
|
||||||
|
if len(param_list) == 4:
|
||||||
|
resource_info = initial_param_dict.get(
|
||||||
|
param_list[0], {}).get(
|
||||||
|
param_list[1], {})
|
||||||
|
if param_list[2] not in resource_info:
|
||||||
|
resource_info[param_list[2]] = {}
|
||||||
|
|
||||||
|
LOG.info('initial_param_dict: %s', initial_param_dict)
|
||||||
|
return initial_param_dict
|
||||||
|
|
||||||
|
|
||||||
|
def create_final_param_dict(param_dict, vdu_flavor_dict,
|
||||||
|
vdu_image_dict, cpd_vl_dict):
|
||||||
|
"""Create final dict containing information about HOT input parameter.
|
||||||
|
|
||||||
|
:param param_dict: dict('nfv', Initial HOT resource dict)
|
||||||
|
:param vdu_flavor_dict: dict(VDU name, VDU flavor dict)
|
||||||
|
:param vdu_iamge_dict: dict(VDU name, Glance-image uuid)
|
||||||
|
:param cpd_vl_dict: dict(external CPD ID, Neutron-network uuid)
|
||||||
|
:return: dict('nfv', Final HOT resource dict)
|
||||||
|
"""
|
||||||
|
final_param_dict = copy.deepcopy(param_dict)
|
||||||
|
|
||||||
|
vdus = final_param_dict.get('nfv', {}).get('VDU', {})
|
||||||
|
for target_vdu in vdus:
|
||||||
|
vdus[target_vdu]['flavor'] = vdu_flavor_dict.get(target_vdu)
|
||||||
|
vdus[target_vdu]['image'] = vdu_image_dict.get(target_vdu)
|
||||||
|
|
||||||
|
cps = final_param_dict.get('nfv', {}).get('CP', {})
|
||||||
|
for target_cp in cps:
|
||||||
|
cps[target_cp]['network'] = cpd_vl_dict.get(target_cp)
|
||||||
|
|
||||||
|
LOG.info('final_param_dict: %s', final_param_dict)
|
||||||
|
return final_param_dict
|
||||||
|
|
||||||
|
|
||||||
|
def create_vdu_flavor_dict(vnfd_dict):
|
||||||
|
"""Create a dict containing information about VDU's flavor.
|
||||||
|
|
||||||
|
:param vnfd_dict: dict(VNFD dict format)
|
||||||
|
:return: dict(VDU name, VDU flavor dict)
|
||||||
|
"""
|
||||||
|
vdu_flavor_dict = {}
|
||||||
|
node_templates = vnfd_dict.get(
|
||||||
|
'topology_template', {}).get(
|
||||||
|
'node_templates', {})
|
||||||
|
|
||||||
|
for vdu_name, val in node_templates.items():
|
||||||
|
vdu_flavor_props = val.get(
|
||||||
|
'capabilities', {}).get(
|
||||||
|
'virtual_compute', {}).get('properties', {})
|
||||||
|
if vdu_flavor_props is not {}:
|
||||||
|
flavor_dict = {}
|
||||||
|
for key, val in vdu_flavor_props.items():
|
||||||
|
if key == 'virtual_cpu':
|
||||||
|
flavor_dict['vcpus'] = val['num_virtual_cpu']
|
||||||
|
elif key == 'virtual_memory':
|
||||||
|
# Convert to MiB
|
||||||
|
flavor_dict['ram'] = MemoryUnit.convert_unit_size_to_num(
|
||||||
|
val['virtual_mem_size'], 'MiB')
|
||||||
|
elif key == 'virtual_local_storage':
|
||||||
|
# Convert to GiB
|
||||||
|
flavor_dict['disk'] = MemoryUnit.convert_unit_size_to_num(
|
||||||
|
val[0]['size_of_storage'], 'GiB')
|
||||||
|
vdu_flavor_dict[vdu_name] = flavor_dict
|
||||||
|
|
||||||
|
LOG.info('vdu_flavor_dict: %s', vdu_flavor_dict)
|
||||||
|
return vdu_flavor_dict
|
||||||
|
|
||||||
|
|
||||||
|
def create_vdu_image_dict(grant_info):
|
||||||
|
"""Create a dict containing information about VDU's image.
|
||||||
|
|
||||||
|
:param grant_info: dict(Grant information format)
|
||||||
|
:return: dict(VDU name, Glance-image uuid)
|
||||||
|
"""
|
||||||
|
vdu_image_dict = {}
|
||||||
|
for vdu_name, resources in grant_info.items():
|
||||||
|
for vnf_resource in resources:
|
||||||
|
vdu_image_dict[vdu_name] = vnf_resource.resource_identifier
|
||||||
|
|
||||||
|
LOG.info('vdu_image_dict: %s', vdu_image_dict)
|
||||||
|
return vdu_image_dict
|
||||||
|
|
||||||
|
|
||||||
|
def create_cpd_vl_dict(base_hot_dict, inst_req_info):
|
||||||
|
"""Create a dict containing information about CPD and VL.
|
||||||
|
|
||||||
|
:param base_hot_dict: dict(Base HOT dict format)
|
||||||
|
:param inst_req_info: dict(Instantiation request information format)
|
||||||
|
:return: dict(external CPD ID, Neutron-network uuid)
|
||||||
|
"""
|
||||||
|
cpd_vl_dict = {}
|
||||||
|
ext_vls = inst_req_info.ext_virtual_links
|
||||||
|
if ext_vls is not None:
|
||||||
|
for ext_vl in ext_vls:
|
||||||
|
ext_cps = ext_vl.ext_cps
|
||||||
|
vl_uuid = ext_vl.resource_id
|
||||||
|
for ext_cp in ext_cps:
|
||||||
|
cp_resource = base_hot_dict['resources'].get(
|
||||||
|
ext_cp.cpd_id)
|
||||||
|
if cp_resource is None:
|
||||||
|
continue
|
||||||
|
cpd_vl_dict[ext_cp.cpd_id] = vl_uuid
|
||||||
|
|
||||||
|
LOG.info('cpd_vl_dict: %s', cpd_vl_dict)
|
||||||
|
return cpd_vl_dict
|
Loading…
Reference in New Issue
Block a user