Support LCM operation with user data
Implement new method of VNF lifecycle management using LCM operation user data. Change-Id: Ib2fbe341b5d26758f0b48dc19e3e05810c2c830f Blueprint: support-etsi-nfv-specschanges/12/710012/14
parent
428096a247
commit
62813239e1
|
@ -108,6 +108,10 @@ class VNFNotFound(exceptions.NotFound):
|
|||
message = _('VNF %(vnf_id)s could not be found')
|
||||
|
||||
|
||||
class LCMUserDataFailed(exceptions.TackerException):
|
||||
message = _('LCM user data %(reason)s')
|
||||
|
||||
|
||||
class ParamYAMLNotWellFormed(exceptions.InvalidInput):
|
||||
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
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -14,16 +14,20 @@
|
|||
# under the License.
|
||||
|
||||
import ddt
|
||||
import importlib
|
||||
import json
|
||||
import mock
|
||||
import os
|
||||
import requests
|
||||
import tempfile
|
||||
import yaml
|
||||
|
||||
from tacker.common import exceptions
|
||||
from tacker import context
|
||||
from tacker.extensions import vnfm
|
||||
from tacker import objects
|
||||
from tacker.tests.common import helpers
|
||||
from tacker.tests import constants
|
||||
from tacker.tests.unit import base
|
||||
from tacker.tests.unit.db import utils
|
||||
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.instance_uuid = uuidsentinel.instance_id
|
||||
self.stack_id = uuidsentinel.stack_id
|
||||
self.auth_attr = None
|
||||
self.plugin = None
|
||||
self.json_headers = {'content-type': 'application/json',
|
||||
'location': 'http://heat-api/stacks/'
|
||||
+ self.instance_uuid + '/myStack/60f83b5e'}
|
||||
|
@ -111,6 +117,438 @@ class TestOpenStack(base.FixturedTestCase):
|
|||
else:
|
||||
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,
|
||||