Merge "Implement SOL001 features to MgmtDriver"

This commit is contained in:
Zuul 2021-02-23 16:25:18 +00:00 committed by Gerrit Code Review
commit 22d69f971a
25 changed files with 2862 additions and 183 deletions

View File

@ -94,6 +94,7 @@ pycadf==2.7.0
pycparser==2.18
Pygments==2.2.0
pyinotify==0.9.6
PyMySQL==0.10.1
PyNaCl==1.2.1
pyOpenSSL==17.5.0
pyparsing==2.2.0

View File

@ -0,0 +1,10 @@
---
features:
- |
Enable VNF vendors to customize configuration methods
for applications via MgmtDriver. These customizations
are specified by "interface" definition in ETSI
NFV-SOL001 v2.6.1. With MgmtDriver, users can execute
preamble and postamble of the base LCM operation.
Customization of LCM itself is not supported by
MgmtDriver.

View File

@ -50,6 +50,7 @@ kubernetes>=11.0.0 # Apache-2.0
setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0 # PSF/ZPL
tooz>=1.58.0 # Apache-2.0
PyYAML>=5.1 # MIT
PyMySQL>=0.10.1 # MIT
# Glance Store
glance-store>=2.4.0 # Apache-2.0

View File

@ -61,6 +61,7 @@ tacker.tacker.vnfm.drivers =
tacker.tacker.mgmt.drivers =
noop = tacker.vnfm.mgmt_drivers.noop:VnfMgmtNoop
openwrt = tacker.vnfm.mgmt_drivers.openwrt.openwrt:VnfMgmtOpenWRT
vnflcm_noop = tacker.vnfm.mgmt_drivers.vnflcm_noop:VnflcmMgmtNoop
tacker.tacker.monitor.drivers =
ping = tacker.vnfm.monitor_drivers.ping.ping:VNFMonitorPing
http_ping = tacker.vnfm.monitor_drivers.http_ping.http_ping:VNFMonitorHTTPPing
@ -92,6 +93,7 @@ oslo.config.opts =
tacker.vnfm.monitor_drivers.ping.ping = tacker.vnfm.monitor_drivers.ping.ping:config_opts
tacker.vnfm.monitor_drivers.ceilometer.ceilometer = tacker.vnfm.monitor_drivers.ceilometer.ceilometer:config_opts
tacker.vnfm.monitor_drivers.zabbix.zabbix = tacker.vnfm.monitor_drivers.zabbix.zabbix:config_opts
tacker.vnflcm.vnflcm_drivers = tacker.vnflcm.vnflcm_drivers:config_opts
tacker.alarm_receiver = tacker.alarm_receiver:config_opts
tacker.plugins.fenix = tacker.plugins.fenix:config_opts

View File

@ -376,3 +376,33 @@ class DBAccessError(TackerException):
class SeeOther(TackerException):
code = 303
class MgmtDriverHashMatchFailure(TackerException):
message = _('The hash verification of VNF Package MgmtDriver '
'and Tacker MgmtDriver does not match.')
class MgmtDriverInconsistent(TackerException):
message = _('The %(MgmtDriver)s specified in the VNFD is inconsistent '
'with the MgmtDriver in the configuration file.')
class MgmtDriverNotFound(TackerException):
message = _('The %(param)s in the additionalParams does not exist.')
class MgmtDriverParamInvalid(TackerException):
message = _('The %(param)s in the additionalParams is invalid.')
class MgmtDriverRemoteCommandError(TackerException):
message = _('Failed to execute remote command.')
class MgmtDriverRemoteCommandTimeOut(TackerException):
message = _('The execution of the remote command timed out.')
class MgmtDriverOtherError(TackerException):
message = _('An error occurred in MgmtDriver: %(error_message)s.')

View File

@ -0,0 +1,269 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
id:
type: string
vendor:
type: string
version:
type: version
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: [ CP1, virtual_link ]
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
# supporting only 'instantiate', 'terminate', 'modify'
# not supporting LCM script, supporting only default LCM
instantiate: []
instantiate_start:
implementation: vnflcm_noop
instantiate_end:
implementation: vnflcm_noop
terminate: []
terminate_start:
implementation: vnflcm_noop
terminate_end:
implementation: vnflcm_noop
artifacts:
vnflcm_noop:
description: Management driver instantiate
type: tosca.artifacts.Implementation.Python
file: Drivers/vnflcm_noop.py
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: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 1 GB
size: 1 GB
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 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
VDU2:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU2
description: VDU2 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
requirements:
- virtual_storage: VirtualStorage
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 30 GB
rdma_enabled: true
sw_image_data:
name: VrtualStorage
version: '0.4.0'
checksum:
algorithm: sha-256
hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 2 GB
min_ram: 8192 MB
size: 2 GB
artifacts:
sw_image:
type: tosca.artifacts.nfv.SwImage
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
vnic_type: direct-physical
requirements:
- virtual_binding: VDU1
#- virtual_link: # the target node is determined in the NSD
CP2:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 1
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL2
CP3:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL2
internalVL2:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 11.11.0.0/24
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
worker_instance:
name: worker_instance_aspect
description: worker_instance scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- VDU2_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU2 ]
- VDU2_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: worker_instance
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU2 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
worker_instance:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
worker_instance:
scale_level: 2
default_level: instantiation_level_1
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
- VDU2_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 1
targets: [ VDU2 ]
- internalVL2_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL2 ]

View File

@ -0,0 +1,65 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: VNF type definition
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
node_types:
company.provider.VNF:
derived_from: tosca.nodes.nfv.VNF
properties:
id:
type: string
description: ID of this VNF
default: vnf_id
vendor:
type: string
description: name of the vendor who generate this VNF
default: vendor
version:
type: version
description: version of the software for this VNF
default: 1.0
descriptor_id:
type: string
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ]
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
descriptor_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
provider:
type: string
constraints: [ valid_values: [ 'Company' ] ]
default: 'Company'
product_name:
type: string
constraints: [ valid_values: [ 'Sample VNF' ] ]
default: 'Sample VNF'
software_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
vnfm_info:
type: list
entry_schema:
type: string
constraints: [ valid_values: [ Tacker ] ]
default: [ Tacker ]
flavour_id:
type: string
constraints: [ valid_values: [ simple ] ]
default: simple
flavour_description:
type: string
default: ""
requirements:
- virtual_link_external:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_internal:
capability: tosca.capabilities.nfv.VirtualLinkable
interfaces:
Vnflcm:
type: tosca.interfaces.nfv.Vnflcm

View File

@ -0,0 +1,68 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tacker.common import log
from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver
class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
def get_type(self):
return 'vnflcm_noop'
def get_name(self):
return 'vnflcm_noop'
def get_description(self):
return 'Tacker VNFMgmt VnflcmNoop Driver'
@log.log
def instantiate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def instantiate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_end(self, context, vnf_instance,
additional_params, **kwargs):
pass

View File

@ -0,0 +1,269 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
id:
type: string
vendor:
type: string
version:
type: version
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: [ CP1, virtual_link ]
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
# supporting only 'instantiate', 'terminate', 'modify'
# not supporting LCM script, supporting only default LCM
instantiate: []
instantiate_start:
implementation: vnflcm_noop_false
instantiate_end:
implementation: vnflcm_noop_false
terminate: []
terminate_start:
implementation: vnflcm_noop_false
terminate_end:
implementation: vnflcm_noop_false
artifacts:
vnflcm_noop:
description: Management driver instantiate
type: tosca.artifacts.Implementation.Python
file: Drivers/vnflcm_noop_false.py
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: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 1 GB
size: 1 GB
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 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
VDU2:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU2
description: VDU2 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
requirements:
- virtual_storage: VirtualStorage
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 30 GB
rdma_enabled: true
sw_image_data:
name: VrtualStorage
version: '0.4.0'
checksum:
algorithm: sha-256
hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 2 GB
min_ram: 8192 MB
size: 2 GB
artifacts:
sw_image:
type: tosca.artifacts.nfv.SwImage
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
vnic_type: direct-physical
requirements:
- virtual_binding: VDU1
#- virtual_link: # the target node is determined in the NSD
CP2:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 1
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL2
CP3:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL2
internalVL2:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 11.11.0.0/24
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
worker_instance:
name: worker_instance_aspect
description: worker_instance scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- VDU2_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU2 ]
- VDU2_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: worker_instance
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU2 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
worker_instance:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
worker_instance:
scale_level: 2
default_level: instantiation_level_1
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
- VDU2_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 1
targets: [ VDU2 ]
- internalVL2_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL2 ]

View File

@ -0,0 +1,88 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver
LOG = logging.getLogger(__name__)
class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
def get_type(self):
return 'vnflcm_noop'
def get_name(self):
return 'vnflcm_noop'
def get_description(self):
return 'Tacker VNFMgmt VnflcmNoop Driver'
def instantiate_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('instantiate_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def instantiate_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('instantiate_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def terminate_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('terminate_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def terminate_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('terminate_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def scale_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('scale_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def scale_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('scale_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def heal_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('heal_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def heal_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('heal_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass

View File

@ -0,0 +1,269 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
id:
type: string
vendor:
type: string
version:
type: version
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: [ CP1, virtual_link ]
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
# supporting only 'instantiate', 'terminate', 'modify'
# not supporting LCM script, supporting only default LCM
instantiate: []
instantiate_start:
implementation: vnflcm_noop
instantiate_end:
implementation: vnflcm_noop
terminate: []
terminate_start:
implementation: vnflcm_noop
terminate_end:
implementation: vnflcm_noop
artifacts:
vnflcm_noop:
description: Management driver instantiate
type: tosca.artifacts.Implementation.Python
file: Drivers/vnflcm_noop.py
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: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 1 GB
size: 1 GB
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 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
VDU2:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU2
description: VDU2 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
requirements:
- virtual_storage: VirtualStorage
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 30 GB
rdma_enabled: true
sw_image_data:
name: VrtualStorage
version: '0.4.0'
checksum:
algorithm: sha-256
hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 2 GB
min_ram: 8192 MB
size: 2 GB
artifacts:
sw_image:
type: tosca.artifacts.nfv.SwImage
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
vnic_type: direct-physical
requirements:
- virtual_binding: VDU1
#- virtual_link: # the target node is determined in the NSD
CP2:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 1
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL2
CP3:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU2
- virtual_link: internalVL2
internalVL2:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 11.11.0.0/24
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
worker_instance:
name: worker_instance_aspect
description: worker_instance scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- VDU2_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU2 ]
- VDU2_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: worker_instance
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU2 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
worker_instance:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
worker_instance:
scale_level: 2
default_level: instantiation_level_1
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
- VDU2_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 1
targets: [ VDU2 ]
- internalVL2_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL2 ]

View File

@ -0,0 +1,81 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver
LOG = logging.getLogger(__name__)
class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
# instantiate start
def instantiate_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('instantiate_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def instantiate_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('instantiate_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def terminate_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('terminate_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def terminate_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('terminate_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def scale_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('scale_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def scale_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('scale_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def heal_start(self, vnf_instance, additional_params, **kwargs):
LOG.debug('heal_start %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass
def heal_end(self, vnf_instance, additional_params, **kwargs):
LOG.debug('heal_end %(vnf_instance)s '
'%(additional_params)s %(kwargs)s',
{'vnf_instance': vnf_instance,
'additional_params': additional_params, 'kwargs': kwargs})
pass

View File

@ -0,0 +1,206 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: [ CP1, virtual_link ]
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
instantiate: []
terminate: []
terminate_start: []
terminate_end: []
instantiate_start:
implementation: vnflcm_noop
instantiate_end:
implementation: vnflcm_noop
artifacts:
vnflcm_noop:
description: Management driver for vnflcm_noop
type: tosca.artifacts.Implementation.Python
file: Scripts/vnflcm_noop.py
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 3 GB
requirements:
- virtual_storage: VirtualStorage
VirtualStorage:
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
properties:
virtual_block_storage_data:
size_of_storage: 3 GB
rdma_enabled: true
sw_image_data:
name: VirtualStorage
version: '0.4.0'
checksum:
algorithm: sha-512
hash: 6513f21e44aa3da349f248188a44bc304a3653a04122d8fb4535423c8e1d14cd6a153f735bb0982e2161b5b5186106570c17a9e58b64dd39390617cd5a350f78
container_format: bare
disk_format: qcow2
min_disk: 2 GB
min_ram: 256 MB
size: 1 GB
artifacts:
sw_image:
type: tosca.artifacts.nfv.SwImage
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 2
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL1
internalVL1:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 33.33.0.0/24
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
worker_instance:
name: worker_instance_aspect
description: worker_instance scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- VDU1_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU1 ]
- VDU1_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: worker_instance
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU1 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
worker_instance:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
worker_instance:
scale_level: 2
default_level: instantiation_level_1
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
- VDU1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 1
targets: [ VDU1 ]
- internalVL1_instantiation_levels:
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
properties:
levels:
instantiation_level_1:
bitrate_requirements:
root: 1048576
leaf: 1048576
instantiation_level_2:
bitrate_requirements:
root: 1048576
leaf: 1048576
targets: [ internalVL1 ]

View File

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

View File

@ -0,0 +1,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:
company.provider.VNF:
derived_from: tosca.nodes.nfv.VNF
properties:
descriptor_id:
type: string
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ]
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
descriptor_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
provider:
type: string
constraints: [ valid_values: [ 'Company' ] ]
default: 'Company'
product_name:
type: string
constraints: [ valid_values: [ 'Sample VNF' ] ]
default: 'Sample VNF'
software_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
vnfm_info:
type: list
entry_schema:
type: string
constraints: [ valid_values: [ Tacker ] ]
default: [ Tacker ]
flavour_id:
type: string
constraints: [ valid_values: [ simple ] ]
default: simple
flavour_description:
type: string
default: "falvour"
requirements:
- virtual_link_external:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_internal:
capability: tosca.capabilities.nfv.VirtualLinkable
interfaces:
Vnflcm:
type: tosca.interfaces.nfv.Vnflcm

View File

@ -0,0 +1,68 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tacker.common import log
from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver
class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
def get_type(self):
return 'vnflcm_noop'
def get_name(self):
return 'vnflcm_noop'
def get_description(self):
return 'Tacker VNFMgmt VnflcmNoop Driver'
@log.log
def instantiate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def instantiate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_end(self, context, vnf_instance,
additional_params, **kwargs):
pass

View File

@ -0,0 +1,12 @@
TOSCA-Meta-File-Version: 1.0
Created-by: dummy_user
CSAR-Version: 1.1
Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml
Name: Files/images/cirros-0.4.0-x86_64-disk.img
Content-type: application/x-iso9066-image
Name: Scripts/vnflcm_noop.py
Content-Type: text/x-python
Algorithm: SHA-256
Hash: ffea638bfdbde3fb01f191bbe75b031859b18d663b127100eb72b19eecd7ed51

View File

@ -0,0 +1,294 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import time
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from sqlalchemy import desc
from sqlalchemy.orm import joinedload
from tacker.common import exceptions
from tacker import context as t_context
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.objects import fields
from tacker.tests.functional import base
from tacker.tests import utils
VNF_PACKAGE_UPLOAD_TIMEOUT = 300
VNF_INSTANTIATE_TIMEOUT = 600
VNF_TERMINATE_TIMEOUT = 600
VNF_HEAL_TIMEOUT = 600
RETRY_WAIT_TIME = 5
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 = utils.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 VnfLcmTest(base.BaseTackerTest):
@classmethod
def setUpClass(cls):
cls.tacker_client = base.BaseTackerTest.tacker_http_client()
cls.vnf_package, cls.vnfd_id = \
_create_and_upload_vnf_package(
cls.tacker_client, "test_inst_terminate_vnf_with_vnflcmnoop",
{"key": "file_functional"})
super(VnfLcmTest, cls).setUpClass()
@classmethod
def tearDownClass(cls):
# Update vnf package operational state to DISABLED
update_req_body = jsonutils.dumps({
"operationalState": "DISABLED"})
base_path = "/vnfpkgm/v1/vnf_packages"
for package_id in [cls.vnf_package]:
resp, resp_body = cls.tacker_client.do_request(
'{base_path}/{id}'.format(id=package_id,
base_path=base_path),
"PATCH", content_type='application/json',
body=update_req_body)
# Delete vnf package
url = '/vnfpkgm/v1/vnf_packages/%s' % package_id
cls.tacker_client.do_request(url, "DELETE")
super(VnfLcmTest, cls).tearDownClass()
def setUp(self):
super(VnfLcmTest, self).setUp()
self.base_url = "/vnflcm/v1/vnf_instances"
self.context = t_context.get_admin_context()
vim_list = self.client.list_vims()
if not vim_list:
self.skipTest("Vims are not configured")
vim_id = 'VIM0'
vim = self.get_vim(vim_list, vim_id)
if not vim:
self.skipTest("Openstack VIM '%s' is missing" % vim_id)
self.vim_id = vim['id']
def _instantiate_vnf_instance_request(
self, flavour_id, vim_id=None, additional_param=None):
request_body = {"flavourId": flavour_id}
if vim_id:
request_body["vimConnectionInfo"] = [
{"id": uuidutils.generate_uuid(),
"vimId": vim_id,
"vimType": "openstack"}]
if additional_param:
request_body["additionalParams"] = additional_param
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_wait_vnf_instance(self, id):
timeout = VNF_TERMINATE_TIMEOUT
url = os.path.join(self.base_url, id)
start_time = int(time.time())
while True:
resp, body = self.http_client.do_request(url, "DELETE")
if 204 == resp.status_code:
break
if ((int(time.time()) - start_time) > timeout):
error = "Failed to delete vnf instance %s"
self.fail(error % id)
time.sleep(RETRY_WAIT_TIME)
def _delete_vnf_instance(self, id):
self._delete_wait_vnf_instance(id)
# 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(RETRY_WAIT_TIME)
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 _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")
@db_api.context_manager.reader
def _vnf_notify_get_by_id(self, context, vnf_instance_id,
columns_to_join=None):
query = api.model_query(
context, models.VnfLcmOpOccs,
read_deleted="no", project_only=True).filter_by(
vnf_instance_id=vnf_instance_id).order_by(
desc("created_at"))
if columns_to_join:
for column in columns_to_join:
query = query.options(joinedload(column))
result = query.first()
if not result:
raise exceptions.VnfInstanceNotFound(id=vnf_instance_id)
return result
def test_instantiate_terminate_vnf_with_vnflcmnoop(self):
# create vnf instance
vnf_instance_name = "vnf_with_instantiation_level-%s" % \
uuidutils.generate_uuid()
vnf_instance_description = "vnf with instantiation level 1"
resp, vnf_instance = self._create_vnf_instance(
self.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)
# instantiate vnf instance
request_body = self._instantiate_vnf_instance_request(
"simple", vim_id=self.vim_id)
self._instantiate_vnf_instance(vnf_instance['id'], request_body)
time.sleep(20)
# show vnf instance
vnf_instance = self._show_vnf_instance(vnf_instance['id'])
self.assertEqual(vnf_instance['instantiationState'], 'INSTANTIATED')
vnflcm_op_occ_ins = self._vnf_notify_get_by_id(
self.context, vnf_instance['id'], columns_to_join=None)
self.assertEqual(vnflcm_op_occ_ins.operation_state, 'COMPLETED')
self.assertEqual(vnflcm_op_occ_ins.operation, 'INSTANTIATE')
time.sleep(20)
# terminate vnf instance
terminate_req_body = {
"terminationType": fields.VnfInstanceTerminationType.FORCEFUL,
}
self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body)
time.sleep(20)
vnflcm_op_occ_term = self._vnf_notify_get_by_id(
self.context, vnf_instance['id'], columns_to_join=None)
self.assertEqual(vnflcm_op_occ_term.operation_state, 'COMPLETED')
self.assertEqual(vnflcm_op_occ_term.operation, 'TERMINATE')
# delete vnf instance
self._delete_vnf_instance(vnf_instance['id'])

View File

@ -39,6 +39,11 @@ import tacker.conf
CONF = tacker.conf.CONF
def return_vnf_interfaces():
vnf_interface = 'vnflcm_noop'
return vnf_interface
def return_default_vim():
default_vim = {
'vim_auth': {

View File

@ -0,0 +1,248 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import fixtures
import os
import shutil
from oslo_config import cfg
from oslo_utils import uuidutils
from tacker.common import exceptions
from tacker import context
from tacker.manager import TackerManager
from tacker import objects
from tacker.tests.unit.db import base as db_base
from tacker.tests.unit.nfvo.test_nfvo_plugin import FakeVNFMPlugin
from tacker.tests.unit.vnflcm import fakes
from tacker.tests import utils as test_utils
from tacker.tests import uuidsentinel
from tacker.vnflcm import vnflcm_driver
from tacker.vnflcm.vnflcm_driver import VnfLcmDriver
from unittest import mock
vnf_dict = {
'id': uuidutils.generate_uuid(),
'mgmt_ip_address': '{"VDU1": "a.b.c.d"}',
'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff',
'instance_id': 'a737497c-761c-11e5-89c3-9cb6541d805d',
'vnfd': {
'attributes': {
'heat_template': {
'resources': {
'VDU1': {
'properties': {
'networks': [{'port': {'get_resource': 'CP1'}}]}
}
}
}
}
}
}
class InfraDriverException(Exception):
pass
class FakeDriverManager(mock.Mock):
def __init__(self, fail_method_name=None, vnf_resource_count=1):
super(FakeDriverManager, self).__init__()
self.fail_method_name = fail_method_name
self.vnf_resource_count = vnf_resource_count
def invoke(self, *args, **kwargs):
if 'pre_instantiation_vnf' in args:
vnf_resource_list = [fakes.return_vnf_resource() for index in
range(self.vnf_resource_count)]
return {'node_name': vnf_resource_list}
if 'instantiate_vnf' in args:
if self.fail_method_name and \
self.fail_method_name == 'instantiate_vnf':
raise InfraDriverException("instantiate_vnf failed")
instance_id = uuidsentinel.instance_id
vnfd_dict = kwargs.get('vnfd_dict')
vnfd_dict['instance_id'] = instance_id
return instance_id
if 'create_wait' in args:
if self.fail_method_name and \
self.fail_method_name == 'create_wait':
raise InfraDriverException("create_wait failed")
elif 'post_vnf_instantiation' in args:
pass
if 'mgmt-drivers-custom' in args:
if self.fail_method_name and \
self.fail_method_name == 'mgmt-drivers-custom':
raise InfraDriverException("mgmt-drivers-custom failed")
class FakeVimClient(mock.Mock):
pass
class FakeTackerManager(mock.MagicMock):
pass
class MgmtVnfLcmDriverTest(db_base.SqlTestCase):
def setUp(self):
super(MgmtVnfLcmDriverTest, self).setUp()
self.addCleanup(mock.patch.stopall)
self.context = context.get_admin_context()
self._mock_vim_client()
self._stub_get_vim()
self.temp_dir = self.useFixture(fixtures.TempDir()).path
def _mock_vnf_manager(self, fail_method_name=None, vnf_resource_count=1):
self._vnf_manager = mock.Mock(wraps=FakeDriverManager(
fail_method_name=fail_method_name,
vnf_resource_count=vnf_resource_count))
self._vnf_manager.__contains__ = mock.Mock(
return_value=True)
fake_vnf_manager = mock.Mock()
fake_vnf_manager.return_value = self._vnf_manager
self._mock(
'tacker.common.driver_manager.DriverManager', fake_vnf_manager)
def _mock_vim_client(self):
self.vim_client = mock.Mock(wraps=FakeVimClient())
fake_vim_client = mock.Mock()
fake_vim_client.return_value = self.vim_client
self._mock(
'tacker.vnfm.vim_client.VimClient', fake_vim_client)
def _stub_get_vim(self):
vim_obj = {'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff',
'vim_name': 'fake_vim', 'vim_auth':
{'auth_url': 'http://localhost/identity', 'password':
'test_pw', 'username': 'test_user', 'project_name':
'test_project'}, 'vim_type': 'openstack'}
self.vim_client.get_vim.return_value = vim_obj
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(VnfLcmDriver, '_init_mgmt_driver_hash')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf(self, mock_vnf_instance_save,
mock_vnf_package_vnfd, mock_create,
mock_get_service_plugins, mock_init_hash,
mock_final_vnf_dict):
mock_init_hash.return_value = {
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
"b18d663b127100eb72b19eecd7ed51"
}
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
instantiate_vnf_req_dict = fakes.get_dummy_instantiate_vnf_request()
instantiate_vnf_req_obj = \
objects.InstantiateVnfRequest.obj_from_primitive(
instantiate_vnf_req_dict, self.context)
vnf_instance_obj = fakes.return_vnf_instance()
fake_csar = os.path.join(self.temp_dir, vnf_package_id)
cfg.CONF.set_override('vnf_package_csar_path', self.temp_dir,
group='vnf_package')
test_utils.copy_csar_files(fake_csar, "refactor_mgmt_driver1")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}}
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual(1, mock_vnf_instance_save.call_count)
self.assertEqual(5, self._vnf_manager.invoke.call_count)
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(VnfLcmDriver, '_init_mgmt_driver_hash')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_py_name_false(
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create, mock_get_service_plugins, mock_init_hash,
mock_final_vnf_dict):
mock_init_hash.return_value = {
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
"b18d663b127100eb72b19eecd7ed51"
}
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
instantiate_vnf_req_dict = fakes.get_dummy_instantiate_vnf_request()
instantiate_vnf_req_obj = \
objects.InstantiateVnfRequest.obj_from_primitive(
instantiate_vnf_req_dict, self.context)
vnf_instance_obj = fakes.return_vnf_instance()
fake_csar = os.path.join(self.temp_dir, vnf_package_id)
cfg.CONF.set_override('vnf_package_csar_path', self.temp_dir,
group='vnf_package')
test_utils.copy_csar_files(fake_csar, "refactor_mgmt_driver2")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}}
self.assertRaises(exceptions.MgmtDriverInconsistent,
driver.instantiate_vnf, self.context,
vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(VnfLcmDriver, '_init_mgmt_driver_hash')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_py_hash_false(
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create, mock_get_service_plugins, mock_init_hash,
mock_final_vnf_dict):
mock_init_hash.return_value = {
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
"b18d663b127100eb72b19eecd7ed51"
}
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
instantiate_vnf_req_dict = fakes.get_dummy_instantiate_vnf_request()
instantiate_vnf_req_obj = \
objects.InstantiateVnfRequest.obj_from_primitive(
instantiate_vnf_req_dict, self.context)
vnf_instance_obj = fakes.return_vnf_instance()
fake_csar = os.path.join(self.temp_dir, vnf_package_id)
cfg.CONF.set_override('vnf_package_csar_path', self.temp_dir,
group='vnf_package')
test_utils.copy_csar_files(fake_csar, "refactor_mgmt_driver3")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}}
self.assertRaises(exceptions.MgmtDriverHashMatchFailure,
driver.instantiate_vnf, self.context,
vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
shutil.rmtree(fake_csar)

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,9 @@
import copy
from datetime import datetime
import functools
import hashlib
import inspect
import os
import re
import time
import traceback
@ -28,10 +30,9 @@ from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import excutils
from tacker.common import log
from tacker.common import driver_manager
from tacker.common import exceptions
from tacker.common import log
from tacker.common import safe_utils
from tacker.common import utils
from tacker.conductor.conductorrpc import vnf_lcm_rpc
@ -40,10 +41,10 @@ from tacker import objects
from tacker.objects import fields
from tacker.vnflcm import abstract_driver
from tacker.vnflcm import utils as vnflcm_utils
from tacker.vnfm.mgmt_drivers import constants as mgmt_constants
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
DEFAULT_VNFLCM_MGMT_DRIVER = "vnflcm_noop"
@utils.expects_func_args('vnf_info', 'vnf_instance', 'scale_vnf_request')
@ -281,7 +282,24 @@ def revert_to_error_rollback(function):
return decorated_function
def config_opts():
return [('tacker', VnfLcmDriver.OPTS)]
class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
OPTS = [
cfg.ListOpt(
'vnflcm_infra_driver', default=['openstack', 'kubernetes'],
help=_('Hosting vnf drivers tacker plugin will use')
),
cfg.ListOpt(
'vnflcm_mgmt_driver', default=[DEFAULT_VNFLCM_MGMT_DRIVER],
help=_('MGMT driver to communicate with '
'Hosting VNF/logical service '
'instance tacker plugin will use')
)
]
cfg.CONF.register_opts(OPTS, 'tacker')
def __init__(self):
super(VnfLcmDriver, self).__init__()
@ -289,7 +307,18 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
self._vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
self._vnf_manager = driver_manager.DriverManager(
'tacker.tacker.vnfm.drivers',
cfg.CONF.tacker.infra_driver)
cfg.CONF.tacker.vnflcm_infra_driver)
self._mgmt_manager = driver_manager.DriverManager(
'tacker.tacker.mgmt.drivers', cfg.CONF.tacker.vnflcm_mgmt_driver)
self._mgmt_driver_hash = self._init_mgmt_driver_hash()
def _init_mgmt_driver_hash(self):
driver_hash = {}
for mgmt_driver in cfg.CONF.tacker.vnflcm_mgmt_driver:
path = inspect.getfile(self._mgmt_manager[mgmt_driver].__class__)
driver_hash[mgmt_driver] = self._get_file_hash(path)
return driver_hash
def _vnf_instance_update(self, context, vnf_instance, **kwargs):
"""Update vnf instance in the database using kwargs as value."""
@ -377,6 +406,57 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
id=vnf_instance.id,
error=encodeutils.exception_to_unicode(exp))
def _get_file_hash(self, path):
hash_obj = hashlib.sha256()
with open(path) as f:
hash_obj.update(f.read().encode('utf-8'))
return hash_obj.hexdigest()
def _check_mgmt_driver(self, artifact_mgmt_driver, artifacts_value,
vnf_package_path):
# check implementation and artifacts exist in cfg.CONF.tacker
if artifact_mgmt_driver not in self._mgmt_driver_hash:
LOG.error('The {} specified in the VNFD '
'is inconsistent with the MgmtDriver in '
'the configuration file.'.format(artifact_mgmt_driver))
raise exceptions.MgmtDriverInconsistent(
MgmtDriver=artifact_mgmt_driver)
# check file content
pkg_mgmt_driver_path = os.path.join(vnf_package_path,
artifacts_value[artifact_mgmt_driver]['file'])
pkg_mgmt_driver_hash = self._get_file_hash(pkg_mgmt_driver_path)
if pkg_mgmt_driver_hash == \
self._mgmt_driver_hash[artifact_mgmt_driver]:
return artifact_mgmt_driver
else:
LOG.error('The hash verification of VNF Package MgmtDriver '
'and Tacker MgmtDriver does not match.')
raise exceptions.MgmtDriverHashMatchFailure()
def _load_vnf_interface(self, context, method_name,
vnf_instance, vnfd_dict):
VNF_value = vnfd_dict['topology_template']['node_templates']['VNF']
tacker_mgmt_driver = DEFAULT_VNFLCM_MGMT_DRIVER
interfaces_vnflcm_value = \
VNF_value.get('interfaces', {}).get('Vnflcm', {})
if not interfaces_vnflcm_value:
return tacker_mgmt_driver
artifacts_value = VNF_value.get('artifacts')
if not artifacts_value:
return tacker_mgmt_driver
vnf_package_path = vnflcm_utils._get_vnf_package_path(
context, vnf_instance.vnfd_id)
if interfaces_vnflcm_value.get(method_name):
artifact_mgmt_driver = interfaces_vnflcm_value.get(
method_name).get('implementation')
if artifact_mgmt_driver:
tacker_mgmt_driver = self._check_mgmt_driver(
artifact_mgmt_driver, artifacts_value, vnf_package_path)
return tacker_mgmt_driver
@log.log
def instantiate_vnf(self, context, vnf_instance, vnf_dict,
instantiate_vnf_req):
@ -394,9 +474,26 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id, instantiate_vnf_req.flavour_id)
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'instantiate_start', vnf_instance, vnfd_dict),
'instantiate_start', context=context,
vnf_instance=vnf_instance,
additional_params=instantiate_vnf_req.additional_params)
self._instantiate_vnf(context, vnf_instance, vnf_dict,
vim_connection_info, instantiate_vnf_req)
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'instantiate_end', vnf_instance, vnfd_dict),
'instantiate_end', context=context,
vnf_instance=vnf_instance,
additional_params=instantiate_vnf_req.additional_params)
@log.log
@revert_to_error_task_state
def terminate_vnf(self, context, vnf_instance, terminate_vnf_req):
@ -407,6 +504,16 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'terminate_start', vnf_instance, vnfd_dict),
'terminate_start', context=context,
vnf_instance=vnf_instance,
additional_params=terminate_vnf_req.additional_params)
LOG.info("Terminating vnf %s", vnf_instance.id)
try:
self._delete_vnf_instance_resources(context, vnf_instance,
@ -422,6 +529,12 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
LOG.error("Unable to terminate vnf '%s' instance. "
"Error: %s", vnf_instance.id,
encodeutils.exception_to_unicode(exp))
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'terminate_end', vnf_instance, vnfd_dict),
'terminate_end', context=context,
vnf_instance=vnf_instance,
additional_params=terminate_vnf_req.additional_params)
def _delete_vnf_instance_resources(self, context, vnf_instance,
vim_connection_info, terminate_vnf_req=None,
@ -578,6 +691,17 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'heal_start', vnf_instance, vnfd_dict),
'heal_start', context=context,
vnf_instance=vnf_instance,
additional_params=heal_vnf_request.additional_params)
if not heal_vnf_request.vnfc_instance_id:
self._respawn_vnf(context, vnf_instance, vnf_dict,
vim_connection_info, heal_vnf_request)
@ -587,6 +711,12 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
LOG.info("Request received for healing vnf '%s' is completed "
"successfully", vnf_instance.id)
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'heal_end', vnf_instance, vnfd_dict),
'heal_end', context=context,
vnf_instance=vnf_instance,
additional_params=heal_vnf_request.additional_params)
def _scale_vnf_pre(self, context, vnf_info, vnf_instance,
scale_vnf_request, vim_connection_info):
@ -600,15 +730,10 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
grp_id = None
vnf_info['policy_name'] = scale_vnf_request.aspect_id
if scale_vnf_request.type == 'SCALE_IN':
vnfd_yaml = vnf_info['vnfd']['attributes'].get(
'vnfd_' + vnf_instance.instantiated_vnf_info.flavour_id, '')
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces']['Vnflcm']['scale_start']:
vnf_info['vnfd']['mgmt_driver'] = \
vnf_node['interfaces']['Vnflcm']['scale_start']
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
vnf_info['action'] = 'in'
scale_id_list, scale_name_list, grp_id, res_num = \
self._vnf_manager.invoke(
@ -627,21 +752,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vnf_info['res_num'] = res_num
# mgmt_driver pre
if len(scale_id_list) != 0 and vnf_info['vnfd'].get('mgmt_driver'):
if len(scale_id_list) > 1:
stack_value = []
stack_value = scale_id_list
else:
stack_value = scale_id_list[0]
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_SCALE_IN_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info},
mgmt_constants.KEY_SCALE:
stack_value,
}
self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs)
if len(scale_id_list) != 0:
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'scale_start', vnf_instance, vnfd_dict),
'scale_start', context=context,
vnf_instance=vnf_instance,
additional_params=scale_vnf_request.additional_params)
else:
vnf_info['action'] = 'out'
scale_id_list = self._vnf_manager.invoke(
@ -672,18 +789,10 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vnf_lcm_op_occ = vnf_info['vnf_lcm_op_occ']
vnf_lcm_op_occ.error_point = 6
if scale_vnf_request.type == 'SCALE_OUT':
vnfd_yaml =\
vnf_info['vnfd']['attributes'].\
get('vnfd_' + vnf_instance.instantiated_vnf_info.flavour_id,
'')
vnf_info['policy_name'] = scale_vnf_request.aspect_id
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces']['Vnflcm']['scale_end']:
vnf_info['vnfd']['mgmt_driver'] = \
vnf_node['interfaces']['Vnflcm']['scale_end']
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
scale_id_after = self._vnf_manager.invoke(
vim_connection_info.vim_type,
'get_scale_ids',
@ -696,21 +805,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
id_list = []
id_list = list(set(scale_id_after) - set(scale_id_list))
vnf_info['res_num'] = len(scale_id_after)
if len(id_list) != 0 and vnf_info['vnfd'].get('mgmt_driver'):
if len(id_list) > 1:
stack_value = []
stack_value = id_list
else:
stack_value = id_list[0]
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_SCALE_OUT_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info},
mgmt_constants.KEY_SCALE:
stack_value,
}
self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs)
if len(id_list) != 0:
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'scale_end', vnf_instance, vnfd_dict),
'scale_end', context=context,
vnf_instance=vnf_instance,
additional_params=scale_vnf_request.additional_params)
vnf_lcm_op_occ.error_point = 7
vnf_instance.instantiated_vnf_info.scale_level =\
vnf_info['after_scale_level']
@ -1214,57 +1315,32 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
)
if vnf_lcm_op_occs.error_point == 7:
if vnf_lcm_op_occs.operation == 'SCALE':
vnfd_yaml = vnf_info['vnfd']['attributes'].\
get('vnfd_' +
vnf_instance.instantiated_vnf_info.flavour_id, '')
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces'].get('Vnflcm'):
if vnf_node['interfaces']['Vnflcm'].get('scale_start'):
vnf_info['vnfd']['mgmt_driver'] = \
vnf_node['interfaces']['Vnflcm']['scale_start']
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
vnf_info['action'] = 'in'
if len(scale_id_list) != 0 and vnf_info['vnfd'].get(
'mgmt_driver'):
if len(scale_id_list) > 1:
stack_value = []
stack_value = scale_id_list
else:
stack_value = scale_id_list[0]
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_SCALE_IN_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info},
mgmt_constants.KEY_SCALE:
stack_value,
}
self._rollback_mgmt_call(context, vnf_info, kwargs)
if len(scale_id_list) != 0:
self._mgmt_manager.invoke(
self._load_vnf_interface(context, 'scale_start',
vnf_instance, vnfd_dict),
'scale_start', context=context,
vnf_instance=vnf_instance,
additional_params=scale_vnf_request.additional_params)
else:
vnfd_yaml = vnf_info['vnfd']['attributes'].\
get('vnfd_' +
vnf_instance.instantiated_vnf_info.flavour_id, '')
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces'].get('Vnflcm'):
if vnf_node['interfaces']['Vnflcm'].get(
'termination_start'):
vnf_info['vnfd']['mgmt_driver'] = vnf_node[
'interfaces']['Vnflcm']['termination_start']
if len(scale_id_list) != 0 and vnf_info['vnfd'].get(
'mgmt_driver'):
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_DELETE_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info}
}
self._rollback_mgmt_call(context, vnf_info, kwargs)
vnfd_dict = vnflcm_utils._get_vnfd_dict(
context, vnf_instance.vnfd_id,
vnf_instance.instantiated_vnf_info.flavour_id)
if len(scale_id_list) != 0:
self._mgmt_manager.invoke(
self._load_vnf_interface(
context, 'terminate_start',
vnf_instance, vnfd_dict),
'terminate_start', context=context,
vnf_instance=vnf_instance,
additional_params=scale_vnf_request.additional_params)
vnf_lcm_op_occs.error_point = 6
return scale_name_list, grp_id
@ -1336,9 +1412,6 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
def _update_vnf_rollback_status_err(self, context, vnf_info):
self._vnfm_plugin.update_vnf_rollback_status_err(context, vnf_info)
def _rollback_mgmt_call(self, context, vnf_info, kwargs):
self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs)
def _rollback_vnf_post(
self,
context,

View File

@ -0,0 +1,77 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
class VnflcmMgmtAbstractDriver(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get_type(self):
"""Return one of predefined type of the hosting vnf drivers."""
pass
@abc.abstractmethod
def get_name(self):
"""Return a symbolic name for the service VM plugin."""
pass
@abc.abstractmethod
def get_description(self):
pass
@abc.abstractmethod
def instantiate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def instantiate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def terminate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def terminate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def scale_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def scale_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def heal_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@abc.abstractmethod
def heal_end(self, context, vnf_instance,
additional_params, **kwargs):
pass

View File

@ -0,0 +1,68 @@
# Copyright (C) 2020 FUJITSU
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tacker.common import log
from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver
class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
def get_type(self):
return 'vnflcm_noop'
def get_name(self):
return 'vnflcm_noop'
def get_description(self):
return 'Tacker VNFMgmt VnflcmNoop Driver'
@log.log
def instantiate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def instantiate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def terminate_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def scale_end(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_start(self, context, vnf_instance,
additional_params, **kwargs):
pass
@log.log
def heal_end(self, context, vnf_instance,
additional_params, **kwargs):
pass

View File

@ -20,3 +20,4 @@ WebTest>=2.0.27 # MIT
python-barbicanclient>=4.5.2 # Apache-2.0
python-blazarclient>=1.0.1 # Apache-2.0
requests-mock>=1.2.0 # Apache-2.0
PyMySQL>=0.10.1 # MIT