Support for Change External VNF Connectivity
This feature will enable the client to use this API to perform the following operations: - allow client to change the external connectivity of a VNF instance - VNFM support to change port/network - VNFM also supports to change ip address/mac address/ allowed_address_pair The operations provided through additional attributes are below: - Grant(POST) - VNF instances (GET) - Individual VNF Instances (GET) - Notification Endpoint (POST) Modified .zuul.yaml to disable image_volume_cache, since cache Volume remains during Terminate implementation and responds to Heat Stack deletion failure without erasing volume type. Implements: blueprint support-change-external-connectivity Spec: https://specs.openstack.org/openstack/tacker-specs/specs/wallaby/support-change-external-VNF-connectivity-operation.html Change-Id: Ie6b8b2b46b6de24e2d2d0a8bccef87bbdfa39191
This commit is contained in:
parent
35c9eb233a
commit
b77c469939
|
@ -121,6 +121,9 @@
|
||||||
$NEUTRON_DHCP_CONF:
|
$NEUTRON_DHCP_CONF:
|
||||||
DEFAULT:
|
DEFAULT:
|
||||||
enable_isolated_metadata: True
|
enable_isolated_metadata: True
|
||||||
|
$CINDER_CONF:
|
||||||
|
lvmdriver-1:
|
||||||
|
image_volume_cache_enabled: False
|
||||||
devstack_plugins:
|
devstack_plugins:
|
||||||
heat: https://opendev.org/openstack/heat
|
heat: https://opendev.org/openstack/heat
|
||||||
networking-sfc: https://opendev.org/openstack/networking-sfc
|
networking-sfc: https://opendev.org/openstack/networking-sfc
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"extVirtualLinks": [
|
||||||
|
{
|
||||||
|
"id": "ext-vl-uuid-VL1",
|
||||||
|
"resourceId": "neutron-network-uuid_VL1",
|
||||||
|
"extCps": [
|
||||||
|
{
|
||||||
|
"cpdId": "CP1",
|
||||||
|
"cpConfig": [
|
||||||
|
{
|
||||||
|
"cpProtocolData": [
|
||||||
|
{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [
|
||||||
|
{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 1,
|
||||||
|
"subnetId": "subnet-uuid"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cpdId": "CP2",
|
||||||
|
"cpConfig": [
|
||||||
|
{
|
||||||
|
"cpProtocolData": [
|
||||||
|
{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [
|
||||||
|
{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": [
|
||||||
|
"10.0.0.1"
|
||||||
|
],
|
||||||
|
"subnetId": "subnet-uuid"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vimConnectionInfo": [
|
||||||
|
{
|
||||||
|
"id": "vim-uuid",
|
||||||
|
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||||
|
"vimConnectionId": "dummy-vimid",
|
||||||
|
"interfaceInfo": {
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2"
|
||||||
|
},
|
||||||
|
"accessInfo": {
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -674,6 +674,81 @@ Request Example
|
||||||
.. literalinclude:: samples/vnflcm/modify-vnf-instance-request.json
|
.. literalinclude:: samples/vnflcm/modify-vnf-instance-request.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
Change External VNF Connectivity
|
||||||
|
================================
|
||||||
|
|
||||||
|
.. rest_method:: POST /vnflcm/v1/vnf_instances/{vnfInstanceId}/change_ext_conn
|
||||||
|
|
||||||
|
The POST method changes the external connectivity of a VNF instance.
|
||||||
|
|
||||||
|
This task resource represents the "Change external VNF connectivity" operation.
|
||||||
|
The client can use this resource to change the external connectivity of a VNF instance.
|
||||||
|
|
||||||
|
Response Codes
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. rest_status_code:: success status.yaml
|
||||||
|
|
||||||
|
- 202
|
||||||
|
|
||||||
|
.. rest_status_code:: error status.yaml
|
||||||
|
|
||||||
|
- 400
|
||||||
|
- 401
|
||||||
|
- 403
|
||||||
|
- 404
|
||||||
|
- 409
|
||||||
|
|
||||||
|
Request Parameters
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters_vnflcm.yaml
|
||||||
|
|
||||||
|
- vnfInstanceId: vnf_instance_id
|
||||||
|
- extVirtualLinks: ext_virtual_links
|
||||||
|
- id: ext_virtual_links_id
|
||||||
|
- vimConnectionId: vim_connection_id
|
||||||
|
- resourceId: ext_virtual_links_resource_id
|
||||||
|
- extCps: ext_cps
|
||||||
|
- cpdId: cpd_id
|
||||||
|
- cpConfig: cp_config
|
||||||
|
- cpInstanceId: cp_instance_id
|
||||||
|
- linkPortId: link_port_id
|
||||||
|
- cpProtocolData: cp_protocol_data
|
||||||
|
- layerProtocol: layer_protocol
|
||||||
|
- ipOverEthernet: ip_over_ethernet
|
||||||
|
- macAddress: mac_address
|
||||||
|
- ipAddresses: ip_addresses
|
||||||
|
- type: ip_address_type
|
||||||
|
- fixedAddresses: fixed_addresses
|
||||||
|
- numDynamicAddresses: num_dynamic_addresses
|
||||||
|
- subnetId: subnet_id
|
||||||
|
- extLinkPorts: ext_link_ports
|
||||||
|
- id: ext_link_port_id
|
||||||
|
- resourceHandle: ext_link_port_resource_handle
|
||||||
|
- vimConnectionId: vim_connection_id
|
||||||
|
- resourceId: resource_handle_resource_id
|
||||||
|
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||||
|
- vimConnectionInfo: vnf_instance_vim_connection_info
|
||||||
|
- id: vim_connection_info_id
|
||||||
|
- vimId: vim_connection_info_vim_id
|
||||||
|
- vimType: vim_connection_info_vim_type
|
||||||
|
- interfaceInfo: vim_connection_info_interface_info
|
||||||
|
- endpoint: vim_connection_info_interface_info_endpoint
|
||||||
|
- accessInfo: vim_connection_info_access_info
|
||||||
|
- username: vim_connection_info_access_info_username
|
||||||
|
- password: vim_connection_info_access_info_password
|
||||||
|
- region: vim_connection_info_access_info_region
|
||||||
|
- tenant: vim_connection_info_access_info_tenant
|
||||||
|
- additionalParams: vnf_instance_additional_params
|
||||||
|
|
||||||
|
|
||||||
|
Request Example
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. literalinclude:: samples/vnflcm/change-ext-conn-request.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
Show VNF LCM operation occurrence
|
Show VNF LCM operation occurrence
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
|
|
|
@ -274,3 +274,14 @@ scale = {
|
||||||
'required': ['type', 'aspectId'],
|
'required': ['type', 'aspectId'],
|
||||||
'additionalProperties': True,
|
'additionalProperties': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
change_ext_conn = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'extVirtualLinks': _extVirtualLinkData,
|
||||||
|
'vimConnectionInfo': _vimConnectionInfo,
|
||||||
|
'additionalParams': parameter_types.keyvalue_pairs,
|
||||||
|
},
|
||||||
|
'required': ['extVirtualLinks'],
|
||||||
|
'additionalProperties': True,
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,10 @@ class ViewBuilder(base.BaseViewBuilder):
|
||||||
"heal": {
|
"heal": {
|
||||||
"href": '/vnflcm/v1/vnf_instances/%s/heal'
|
"href": '/vnflcm/v1/vnf_instances/%s/heal'
|
||||||
% vnf_instance.id
|
% vnf_instance.id
|
||||||
|
},
|
||||||
|
"changeExtConn": {
|
||||||
|
"href": '/vnflcm/v1/vnf_instances/%s/change_ext_conn'
|
||||||
|
% vnf_instance.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ from tacker.extensions import vnfm
|
||||||
from tacker import manager
|
from tacker import manager
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
from tacker.objects import fields
|
from tacker.objects import fields
|
||||||
|
from tacker.objects.fields import ErrorPoint as EP
|
||||||
from tacker.objects import vnf_lcm_op_occs as vnf_lcm_op_occs_obj
|
from tacker.objects import vnf_lcm_op_occs as vnf_lcm_op_occs_obj
|
||||||
from tacker.objects import vnf_lcm_subscriptions as subscription_obj
|
from tacker.objects import vnf_lcm_subscriptions as subscription_obj
|
||||||
from tacker.plugins.common import constants
|
from tacker.plugins.common import constants
|
||||||
|
@ -1577,6 +1578,49 @@ class VnfLcmController(wsgi.Controller):
|
||||||
vnf_lcm_subscription, cast=False)
|
vnf_lcm_subscription, cast=False)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@wsgi.response(http_client.ACCEPTED)
|
||||||
|
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN,
|
||||||
|
http_client.NOT_FOUND, http_client.CONFLICT))
|
||||||
|
@validation.schema(vnf_lcm.change_ext_conn)
|
||||||
|
def change_ext_conn(self, request, id, body):
|
||||||
|
context = request.environ['tacker.context']
|
||||||
|
context.can(vnf_lcm_policies.VNFLCM % 'change_ext_conn')
|
||||||
|
|
||||||
|
vnf = self._get_vnf(context, id)
|
||||||
|
vnf_instance = self._get_vnf_instance(context, id)
|
||||||
|
if (vnf_instance.instantiation_state !=
|
||||||
|
fields.VnfInstanceState.INSTANTIATED):
|
||||||
|
return self._make_problem_detail(
|
||||||
|
'VNF is not instantiated',
|
||||||
|
409,
|
||||||
|
title='VNF IS NOT INSTANTIATED')
|
||||||
|
vnf['before_error_point'] = EP.INITIAL
|
||||||
|
self._change_ext_conn(context, vnf_instance, vnf, body)
|
||||||
|
|
||||||
|
def _change_ext_conn(self, context, vnf_instance, vnf, request_body):
|
||||||
|
req_body = utils.convert_camelcase_to_snakecase(request_body)
|
||||||
|
change_ext_conn_req = objects.ChangeExtConnRequest.obj_from_primitive(
|
||||||
|
req_body, context)
|
||||||
|
|
||||||
|
# call notification process
|
||||||
|
if vnf['before_error_point'] == EP.INITIAL:
|
||||||
|
vnf_lcm_op_occs_id = self._notification_process(
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
fields.LcmOccsOperationType.CHANGE_EXT_CONN,
|
||||||
|
change_ext_conn_req,
|
||||||
|
request_body)
|
||||||
|
else:
|
||||||
|
vnf_lcm_op_occs_id = vnf['vnf_lcm_op_occs_id']
|
||||||
|
|
||||||
|
# Call Conductor server.
|
||||||
|
self.rpc_api.change_ext_conn(
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
|
||||||
|
|
||||||
def create_resource():
|
def create_resource():
|
||||||
return wsgi.Resource(VnfLcmController())
|
return wsgi.Resource(VnfLcmController())
|
||||||
|
|
|
@ -150,3 +150,8 @@ class VnflcmAPIRouter(wsgi.Router):
|
||||||
methods = {"GET": "list_lcm_op_occs"}
|
methods = {"GET": "list_lcm_op_occs"}
|
||||||
self._setup_route(mapper, "/vnf_lcm_op_occs",
|
self._setup_route(mapper, "/vnf_lcm_op_occs",
|
||||||
methods, controller, default_resource)
|
methods, controller, default_resource)
|
||||||
|
|
||||||
|
# {apiRoot}/vnf_instances/{vnfInstanceId}/change_ext_conn resource
|
||||||
|
methods = {"POST": "change_ext_conn"}
|
||||||
|
self._setup_route(mapper, "/vnf_instances/{id}/change_ext_conn",
|
||||||
|
methods, controller, default_resource)
|
||||||
|
|
|
@ -305,6 +305,16 @@ class VnfHealFailed(TackerException):
|
||||||
message = _("Heal Vnf failed for vnf %(id)s, error: %(error)s")
|
message = _("Heal Vnf failed for vnf %(id)s, error: %(error)s")
|
||||||
|
|
||||||
|
|
||||||
|
class VnfChangeExtConnFailed(TackerException):
|
||||||
|
message = _("Change external connectivity failed "
|
||||||
|
"for vnf %(id)s, error: %(error)s")
|
||||||
|
|
||||||
|
|
||||||
|
class VnfChangeExtConnWaitFailed(TackerException):
|
||||||
|
message = _("Change external connectivity wait failed "
|
||||||
|
"for vnf %(id)s, error: %(error)s")
|
||||||
|
|
||||||
|
|
||||||
class LockCreationFailed(TackerException):
|
class LockCreationFailed(TackerException):
|
||||||
message = _('Unable to create lock. Coordination backend not started.')
|
message = _('Unable to create lock. Coordination backend not started.')
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ from tacker.glance_store import store as glance_store
|
||||||
from tacker import manager
|
from tacker import manager
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
from tacker.objects import fields
|
from tacker.objects import fields
|
||||||
|
from tacker.objects.fields import ErrorPoint as EP
|
||||||
from tacker.objects.vnf_package import VnfPackagesList
|
from tacker.objects.vnf_package import VnfPackagesList
|
||||||
from tacker.objects import vnfd as vnfd_db
|
from tacker.objects import vnfd as vnfd_db
|
||||||
from tacker.objects import vnfd_attribute as vnfd_attribute_db
|
from tacker.objects import vnfd_attribute as vnfd_attribute_db
|
||||||
|
@ -109,7 +110,8 @@ _ACTIVE_STATUS = ('ACTIVE',)
|
||||||
_PENDING_STATUS = ('PENDING_CREATE',
|
_PENDING_STATUS = ('PENDING_CREATE',
|
||||||
'PENDING_TERMINATE',
|
'PENDING_TERMINATE',
|
||||||
'PENDING_DELETE',
|
'PENDING_DELETE',
|
||||||
'PENDING_HEAL')
|
'PENDING_HEAL',
|
||||||
|
'PENDING_CHANGE_EXT_CONN')
|
||||||
_ERROR_STATUS = ('ERROR',)
|
_ERROR_STATUS = ('ERROR',)
|
||||||
_ALL_STATUSES = _ACTIVE_STATUS + _INACTIVE_STATUS + _PENDING_STATUS + \
|
_ALL_STATUSES = _ACTIVE_STATUS + _INACTIVE_STATUS + _PENDING_STATUS + \
|
||||||
_ERROR_STATUS
|
_ERROR_STATUS
|
||||||
|
@ -781,6 +783,30 @@ class Conductor(manager.Manager):
|
||||||
format(error_msg))
|
format(error_msg))
|
||||||
raise exceptions.TackerException(message=error_msg)
|
raise exceptions.TackerException(message=error_msg)
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _update_instantiated_vnf_info_change_ext_conn(
|
||||||
|
self, context, vnf_instance, change_ext_conn_req):
|
||||||
|
try:
|
||||||
|
vim_info = vnflcm_utils._get_vim(context,
|
||||||
|
vnf_instance.vim_connection_info)
|
||||||
|
vim_connection_info = \
|
||||||
|
objects.VimConnectionInfo.obj_from_primitive(
|
||||||
|
vim_info, context)
|
||||||
|
|
||||||
|
self.vnf_manager.invoke(
|
||||||
|
vim_connection_info.vim_type, 'post_change_ext_conn_vnf',
|
||||||
|
context=context, vnf_instance=vnf_instance,
|
||||||
|
vim_connection_info=vim_connection_info)
|
||||||
|
|
||||||
|
vnflcm_utils._update_instantiated_vnf_info(
|
||||||
|
change_ext_conn_req, vnf_instance)
|
||||||
|
vnf_instance.instantiated_vnf_info.save()
|
||||||
|
except Exception as exp:
|
||||||
|
error_msg = \
|
||||||
|
"Failed to update instantiation information for vnf {}: {}".\
|
||||||
|
format(vnf_instance.id, encodeutils.exception_to_unicode(exp))
|
||||||
|
raise exceptions.TackerException(message=error_msg)
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def _add_additional_vnf_info(self, context, vnf_instance):
|
def _add_additional_vnf_info(self, context, vnf_instance):
|
||||||
'''this method adds misc info to 'vnf' table'''
|
'''this method adds misc info to 'vnf' table'''
|
||||||
|
@ -834,6 +860,104 @@ class Conductor(manager.Manager):
|
||||||
{'zip': csar_path, 'folder': csar_zip_temp_path,
|
{'zip': csar_path, 'folder': csar_zip_temp_path,
|
||||||
'uuid': vnf_pack.id})
|
'uuid': vnf_pack.id})
|
||||||
|
|
||||||
|
def _get_vnf_link_ports_by_vl(self, vnf_info, ext_vl_id,
|
||||||
|
resource_id):
|
||||||
|
results = []
|
||||||
|
vnf_vl_resource_info = vnf_info.vnf_virtual_link_resource_info
|
||||||
|
for vnf_vl_res in vnf_vl_resource_info:
|
||||||
|
if ((vnf_vl_res.vnf_virtual_link_desc_id == ext_vl_id) and
|
||||||
|
(vnf_vl_res.network_resource.resource_id != resource_id)):
|
||||||
|
results.extend(vnf_vl_res.vnf_link_ports)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def _get_vnf_link_ports_by_cp(self, vnf_info, cpd_id=None):
|
||||||
|
vnf_vl_resource_info = vnf_info.vnf_virtual_link_resource_info
|
||||||
|
vnfc_resource_info = vnf_info.vnfc_resource_info
|
||||||
|
|
||||||
|
def _get_vnf_link_port(vnf_link_port_id):
|
||||||
|
for vnf_vl_res in vnf_vl_resource_info:
|
||||||
|
for vnf_link_port in vnf_vl_res.vnf_link_ports:
|
||||||
|
if vnf_link_port.id == vnf_link_port_id:
|
||||||
|
return vnf_link_port
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for vnfc_resource in vnfc_resource_info:
|
||||||
|
for vnfc_cp_info in vnfc_resource.vnfc_cp_info:
|
||||||
|
if cpd_id == vnfc_cp_info.cpd_id:
|
||||||
|
results.append(
|
||||||
|
_get_vnf_link_port(vnfc_cp_info.vnf_link_port_id))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
@grant_error_common
|
||||||
|
def _change_ext_conn_grant(
|
||||||
|
self,
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occ_id):
|
||||||
|
if not self._get_grant_execute():
|
||||||
|
return
|
||||||
|
|
||||||
|
vnf_inf = vnf_instance.instantiated_vnf_info
|
||||||
|
|
||||||
|
def _create_linkport_rd(linkport, cpd_id):
|
||||||
|
rh = linkport.resource_handle
|
||||||
|
rd = objects.ResourceDefinition()
|
||||||
|
rd.resource = objects.ResourceHandle()
|
||||||
|
rd.id = linkport.id
|
||||||
|
rd.type = constants.TYPE_LINKPORT
|
||||||
|
rd.resource_template_id = cpd_id
|
||||||
|
rd.resource.vim_connection_id = rh.vim_connection_id
|
||||||
|
rd.resource.resource_id = rh.resource_id
|
||||||
|
rd.resource.vim_level_resource_type = rh.vim_level_resource_type
|
||||||
|
return rd
|
||||||
|
|
||||||
|
def _get_cpd_id(cp_instance_id):
|
||||||
|
vnfc_resource_info = vnf_inf.vnfc_resource_info
|
||||||
|
for vnfc_resource in vnfc_resource_info:
|
||||||
|
for vnfc_cp_info in vnfc_resource.vnfc_cp_info:
|
||||||
|
if cp_instance_id == vnfc_cp_info.id:
|
||||||
|
return vnfc_cp_info.cpd_id
|
||||||
|
|
||||||
|
update_resources = dict()
|
||||||
|
# If network resource of the VirtualLink changed, get all LinkPort
|
||||||
|
# resource related to VirtualLink
|
||||||
|
for ext_vl in change_ext_conn_req.ext_virtual_links:
|
||||||
|
nw_changed_resources = self._get_vnf_link_ports_by_vl(
|
||||||
|
vnf_inf, ext_vl.id, ext_vl.resource_id)
|
||||||
|
LOG.debug('nw_changed_resources {}'.format(nw_changed_resources))
|
||||||
|
if nw_changed_resources:
|
||||||
|
for resource in nw_changed_resources:
|
||||||
|
cpd_id = _get_cpd_id(resource.cp_instance_id)
|
||||||
|
update_resources[resource.resource_handle.resource_id] = \
|
||||||
|
_create_linkport_rd(resource, cpd_id)
|
||||||
|
continue
|
||||||
|
# If network resource of the VirtualLink does not change,
|
||||||
|
# Searching vnfc_resource_info table by the cpd_id, if found, get
|
||||||
|
# LinkPort resource corresponding the CP.
|
||||||
|
# It does not check that the CP status updated or not.
|
||||||
|
for ext_cp in ext_vl.ext_cps:
|
||||||
|
cp_changed_resources = \
|
||||||
|
self._get_vnf_link_ports_by_cp(vnf_inf, ext_cp.cpd_id)
|
||||||
|
LOG.debug('cp_changed_resources {}'.format(
|
||||||
|
cp_changed_resources))
|
||||||
|
for resource in cp_changed_resources:
|
||||||
|
update_resources[resource.resource_handle.resource_id] = \
|
||||||
|
_create_linkport_rd(resource, ext_cp.cpd_id)
|
||||||
|
|
||||||
|
update_resources_list = list(update_resources.values())
|
||||||
|
LOG.debug("Update Resources: %s", update_resources_list)
|
||||||
|
grant_request = self._make_grant_request(
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_lcm_op_occ_id,
|
||||||
|
'CHANGE_EXT_CONN',
|
||||||
|
False,
|
||||||
|
update_resources=update_resources_list)
|
||||||
|
return self._grant(context, grant_request)
|
||||||
|
|
||||||
def _grant(self, context, grant_request):
|
def _grant(self, context, grant_request):
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"grant start grant_request[%s]" %
|
"grant start grant_request[%s]" %
|
||||||
|
@ -855,7 +979,11 @@ class Conductor(manager.Manager):
|
||||||
grant_obj.remove_resources):
|
grant_obj.remove_resources):
|
||||||
msg = "grant remove resource error"
|
msg = "grant remove resource error"
|
||||||
raise exceptions.ValidationError(detail=msg)
|
raise exceptions.ValidationError(detail=msg)
|
||||||
|
if len(
|
||||||
|
grant_request.update_resources) != len(
|
||||||
|
grant_obj.update_resources):
|
||||||
|
msg = "grant update resource error"
|
||||||
|
raise exceptions.ValidationError(detail=msg)
|
||||||
self._check_res_add_remove_rsc(context, grant_request, grant_obj)
|
self._check_res_add_remove_rsc(context, grant_request, grant_obj)
|
||||||
|
|
||||||
return grant_obj
|
return grant_obj
|
||||||
|
@ -881,6 +1009,16 @@ class Conductor(manager.Manager):
|
||||||
msg = "grant remove resource error"
|
msg = "grant remove resource error"
|
||||||
raise exceptions.ValidationError(detail=msg)
|
raise exceptions.ValidationError(detail=msg)
|
||||||
|
|
||||||
|
for update_resource in grant_request.update_resources:
|
||||||
|
match_flg = False
|
||||||
|
for rsc in grant_obj.update_resources:
|
||||||
|
if update_resource.id == rsc.resource_definition_id:
|
||||||
|
match_flg = True
|
||||||
|
break
|
||||||
|
if not match_flg:
|
||||||
|
msg = "grant update resource error"
|
||||||
|
raise exceptions.ValidationError(detail=msg)
|
||||||
|
|
||||||
@grant_error_common
|
@grant_error_common
|
||||||
def _instantiate_grant(self,
|
def _instantiate_grant(self,
|
||||||
context,
|
context,
|
||||||
|
@ -1307,6 +1445,7 @@ class Conductor(manager.Manager):
|
||||||
is_automatic_invocation,
|
is_automatic_invocation,
|
||||||
add_resources=[],
|
add_resources=[],
|
||||||
remove_resources=[],
|
remove_resources=[],
|
||||||
|
update_resources=[],
|
||||||
placement_constraints=[]):
|
placement_constraints=[]):
|
||||||
grant_request = objects.GrantRequest()
|
grant_request = objects.GrantRequest()
|
||||||
grant_request.vnf_instance_id = vnf_instance.id
|
grant_request.vnf_instance_id = vnf_instance.id
|
||||||
|
@ -1330,6 +1469,8 @@ class Conductor(manager.Manager):
|
||||||
grant_request.add_resources = add_resources
|
grant_request.add_resources = add_resources
|
||||||
if remove_resources:
|
if remove_resources:
|
||||||
grant_request.remove_resources = remove_resources
|
grant_request.remove_resources = remove_resources
|
||||||
|
if update_resources:
|
||||||
|
grant_request.update_resources = update_resources
|
||||||
if placement_constraints:
|
if placement_constraints:
|
||||||
grant_request.placement_constraints = placement_constraints
|
grant_request.placement_constraints = placement_constraints
|
||||||
|
|
||||||
|
@ -1443,7 +1584,12 @@ class Conductor(manager.Manager):
|
||||||
jsonutils.dumps(affected_resources_snake_case)
|
jsonutils.dumps(affected_resources_snake_case)
|
||||||
changed_resource = objects.ResourceChanges.obj_from_primitive(
|
changed_resource = objects.ResourceChanges.obj_from_primitive(
|
||||||
resource_change_obj, context)
|
resource_change_obj, context)
|
||||||
|
changed_ext_connectivity = \
|
||||||
|
vnflcm_utils._get_changed_ext_connectivity(
|
||||||
|
old_vnf_instance=old_vnf_instance,
|
||||||
|
new_vnf_instance=vnf_instance)
|
||||||
vnf_notif.resource_changes = changed_resource
|
vnf_notif.resource_changes = changed_resource
|
||||||
|
vnf_notif.changed_ext_connectivity = changed_ext_connectivity
|
||||||
vnf_notif.save()
|
vnf_notif.save()
|
||||||
notification_data['affectedVnfcs'] = \
|
notification_data['affectedVnfcs'] = \
|
||||||
affected_resources.get('affectedVnfcs', [])
|
affected_resources.get('affectedVnfcs', [])
|
||||||
|
@ -1453,6 +1599,9 @@ class Conductor(manager.Manager):
|
||||||
affected_resources.get('affectedVirtualStorages', [])
|
affected_resources.get('affectedVirtualStorages', [])
|
||||||
notification_data['notificationStatus'] = \
|
notification_data['notificationStatus'] = \
|
||||||
fields.LcmOccsNotificationStatus.RESULT
|
fields.LcmOccsNotificationStatus.RESULT
|
||||||
|
notification_data['changedExtConnectivity'] = \
|
||||||
|
utils.convert_snakecase_to_camelcase(
|
||||||
|
[i.to_dict() for i in changed_ext_connectivity])
|
||||||
|
|
||||||
if operation_state == \
|
if operation_state == \
|
||||||
fields.LcmOccsOperationState.FAILED_TEMP \
|
fields.LcmOccsOperationState.FAILED_TEMP \
|
||||||
|
@ -2035,6 +2184,113 @@ class Conductor(manager.Manager):
|
||||||
self.vnflcm_driver.rollback_vnf(context, vnf_info,
|
self.vnflcm_driver.rollback_vnf(context, vnf_info,
|
||||||
vnf_instance, operation_params)
|
vnf_instance, operation_params)
|
||||||
|
|
||||||
|
@coordination.synchronized('{vnf_instance[id]}')
|
||||||
|
def change_ext_conn(
|
||||||
|
self,
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id):
|
||||||
|
"""Perform change external VNF connectivity operation.
|
||||||
|
|
||||||
|
This function will support changing external VNF connectivity
|
||||||
|
as defined in ETSI NFV SOL 002 and SOL 003, but now, you can
|
||||||
|
specify changing fixedAddresses or numDynamicAddresses in
|
||||||
|
ipAddresses attribute in extVirtualLinks.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
1. Get grant from NFVO(if needed).
|
||||||
|
Request grant information is made from ExtVirtualLinkData
|
||||||
|
of ChangeExtConnRequest. If ExtVirtualLinkInfo is changed
|
||||||
|
from instantiated VNF, we inform VnfLinkPortInfo related
|
||||||
|
to that ExtVirtualLinkInfo. Also, we inform VnfLinkPortInfo
|
||||||
|
related to each individual VnfExtCpInfo.
|
||||||
|
2. Call vnflcm_driver to change networks.
|
||||||
|
Invoke vnflcm_driver to perform change external VNF
|
||||||
|
connectivity.
|
||||||
|
3. Update VNF information
|
||||||
|
Update InstantiatedVnfInfo as a post-processing.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context (Context): context for security/db session.
|
||||||
|
vnf_instance (VnfInstance): Information object for VNF instance.
|
||||||
|
vnf_dict (dict): Container for error point indication.
|
||||||
|
change_ext_conn_req (ChangeExtConnRequest):
|
||||||
|
Request object of change external connectivity.
|
||||||
|
vnf_lcm_op_occs_id (uuid): self-explanatory :)
|
||||||
|
"""
|
||||||
|
if vnf_dict['before_error_point'] == EP.INITIAL:
|
||||||
|
self._change_ext_conn_grant(
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||||
|
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||||
|
self._send_lcm_op_occ_notification(
|
||||||
|
context=context,
|
||||||
|
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||||
|
old_vnf_instance=None,
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
request_obj=change_ext_conn_req,
|
||||||
|
operation=fields.LcmOccsOperationType.CHANGE_EXT_CONN
|
||||||
|
)
|
||||||
|
|
||||||
|
vnf_dict['current_error_point'] = EP.NOTIFY_PROCESSING
|
||||||
|
if vnf_dict['before_error_point'] <= EP.NOTIFY_PROCESSING:
|
||||||
|
# update vnf status to PENDING_CHANGE_EXT_CONN
|
||||||
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
|
_ACTIVE_STATUS, 'PENDING_CHANGE_EXT_CONN')
|
||||||
|
|
||||||
|
self.vnflcm_driver.change_ext_conn_vnf(
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req)
|
||||||
|
|
||||||
|
vnf_dict['current_error_point'] = EP.NOTIFY_COMPLETED
|
||||||
|
self._update_instantiated_vnf_info_change_ext_conn(
|
||||||
|
context, vnf_instance, change_ext_conn_req)
|
||||||
|
# update vnf status to ACTIVE
|
||||||
|
self._update_vnf_attributes(context, vnf_instance, vnf_dict,
|
||||||
|
_PENDING_STATUS, _ACTIVE_STATUS)
|
||||||
|
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||||
|
self._send_lcm_op_occ_notification(
|
||||||
|
context=context,
|
||||||
|
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||||
|
old_vnf_instance=old_vnf_instance,
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
request_obj=change_ext_conn_req,
|
||||||
|
operation=fields.LcmOccsOperationType.CHANGE_EXT_CONN,
|
||||||
|
operation_state=fields.LcmOccsOperationState.COMPLETED
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
# update vnf_status to 'ERROR' and create event with 'ERROR' status
|
||||||
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
|
_ALL_STATUSES, constants.ERROR, str(e))
|
||||||
|
|
||||||
|
LOG.error('Failed to execute operation. error={}'.format(e))
|
||||||
|
if vnf_dict['current_error_point'] in [EP.INTERNAL_PROCESSING,
|
||||||
|
EP.VNF_CONFIG_END]:
|
||||||
|
self._update_instantiated_vnf_info_change_ext_conn(
|
||||||
|
context, vnf_instance, change_ext_conn_req)
|
||||||
|
|
||||||
|
# update vnf_lcm_op_occs and send notification "FAILED_TEMP"
|
||||||
|
self._send_lcm_op_occ_notification(
|
||||||
|
context=context,
|
||||||
|
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||||
|
old_vnf_instance=old_vnf_instance,
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
request_obj=change_ext_conn_req,
|
||||||
|
operation=fields.LcmOccsOperationType.CHANGE_EXT_CONN,
|
||||||
|
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
||||||
|
error=str(e),
|
||||||
|
error_point=vnf_dict['current_error_point']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def init(args, **kwargs):
|
def init(args, **kwargs):
|
||||||
CONF(args=args, project='tacker',
|
CONF(args=args, project='tacker',
|
||||||
|
|
|
@ -136,3 +136,25 @@ class VNFLcmRPCAPI(object):
|
||||||
vnf_info=vnf_info,
|
vnf_info=vnf_info,
|
||||||
vnf_instance=vnf_instance,
|
vnf_instance=vnf_instance,
|
||||||
operation_params=operation_params)
|
operation_params=operation_params)
|
||||||
|
|
||||||
|
def change_ext_conn(
|
||||||
|
self,
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id,
|
||||||
|
cast=True):
|
||||||
|
serializer = objects_base.TackerObjectSerializer()
|
||||||
|
|
||||||
|
client = rpc.get_client(self.target, version_cap=None,
|
||||||
|
serializer=serializer)
|
||||||
|
cctxt = client.prepare()
|
||||||
|
rpc_method = cctxt.cast if cast else cctxt.call
|
||||||
|
return rpc_method(
|
||||||
|
context,
|
||||||
|
'change_ext_conn',
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
vnf_dict=vnf_dict,
|
||||||
|
change_ext_conn_req=change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id)
|
||||||
|
|
|
@ -87,6 +87,10 @@ class VNFHealWaitFailed(exceptions.TackerException):
|
||||||
message = _('VNF Heal %(reason)s')
|
message = _('VNF Heal %(reason)s')
|
||||||
|
|
||||||
|
|
||||||
|
class VNFChangeExtConnWaitFailed(exceptions.TackerException):
|
||||||
|
message = _('VNF ChangeExtConn %(reason)s')
|
||||||
|
|
||||||
|
|
||||||
class VNFDeleteFailed(exceptions.TackerException):
|
class VNFDeleteFailed(exceptions.TackerException):
|
||||||
message = _('%(reason)s')
|
message = _('%(reason)s')
|
||||||
|
|
||||||
|
|
|
@ -44,3 +44,4 @@ def register_all():
|
||||||
__import__('tacker.objects.grant')
|
__import__('tacker.objects.grant')
|
||||||
__import__('tacker.objects.grant_request')
|
__import__('tacker.objects.grant_request')
|
||||||
__import__('tacker.objects.vnfd_attribute')
|
__import__('tacker.objects.vnfd_attribute')
|
||||||
|
__import__('tacker.objects.change_ext_conn_req')
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# 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 import objects
|
||||||
|
from tacker.objects import base
|
||||||
|
from tacker.objects import fields
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@base.TackerObjectRegistry.register
|
||||||
|
class ChangeExtConnRequest(base.TackerObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'vim_connection_info': fields.ListOfObjectsField(
|
||||||
|
'VimConnectionInfo', nullable=True, default=[]),
|
||||||
|
'ext_virtual_links': fields.ListOfObjectsField(
|
||||||
|
'ExtVirtualLinkData', nullable=False),
|
||||||
|
'additional_params': fields.DictOfNullableField(nullable=True,
|
||||||
|
default={})
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def obj_from_primitive(cls, primitive, context):
|
||||||
|
if 'tacker_object.name' in primitive:
|
||||||
|
obj_change_ext_conn_req = super(
|
||||||
|
ChangeExtConnRequest, cls).obj_from_primitive(
|
||||||
|
primitive, context)
|
||||||
|
else:
|
||||||
|
if 'vim_connection_info' in primitive.keys():
|
||||||
|
obj_data = [objects.VimConnectionInfo._from_dict(
|
||||||
|
vim_conn) for vim_conn in primitive.get(
|
||||||
|
'vim_connection_info', [])]
|
||||||
|
primitive.update({'vim_connection_info': obj_data})
|
||||||
|
|
||||||
|
if 'ext_virtual_links' in primitive.keys():
|
||||||
|
obj_data = [objects.ExtVirtualLinkData.obj_from_primitive(
|
||||||
|
ext_vir_link, context) for ext_vir_link in primitive.get(
|
||||||
|
'ext_virtual_links', [])]
|
||||||
|
primitive.update({'ext_virtual_links': obj_data})
|
||||||
|
obj_change_ext_conn_req = ChangeExtConnRequest._from_dict(
|
||||||
|
primitive)
|
||||||
|
|
||||||
|
return obj_change_ext_conn_req
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _from_dict(cls, data_dict):
|
||||||
|
vim_connection_info = data_dict.get('vim_connection_info', [])
|
||||||
|
ext_virtual_links = data_dict.get('ext_virtual_links', [])
|
||||||
|
additional_params = data_dict.get('additional_params', {})
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
vim_connection_info=vim_connection_info,
|
||||||
|
ext_virtual_links=ext_virtual_links,
|
||||||
|
additional_params=additional_params)
|
|
@ -233,8 +233,9 @@ class LcmOccsOperationType(BaseTackerEnum):
|
||||||
TERMINATE = 'TERMINATE'
|
TERMINATE = 'TERMINATE'
|
||||||
HEAL = 'HEAL'
|
HEAL = 'HEAL'
|
||||||
SCALE = 'SCALE'
|
SCALE = 'SCALE'
|
||||||
|
CHANGE_EXT_CONN = 'CHANGE_EXT_CONN'
|
||||||
|
|
||||||
ALL = (INSTANTIATE, TERMINATE, HEAL, SCALE)
|
ALL = (INSTANTIATE, TERMINATE, HEAL, SCALE, CHANGE_EXT_CONN)
|
||||||
|
|
||||||
|
|
||||||
class LcmOccsNotificationStatus(BaseTackerEnum):
|
class LcmOccsNotificationStatus(BaseTackerEnum):
|
||||||
|
|
|
@ -33,8 +33,12 @@ class Grant(base.TackerObject):
|
||||||
'GrantInfo', nullable=True, default=[]),
|
'GrantInfo', nullable=True, default=[]),
|
||||||
'remove_resources': fields.ListOfObjectsField(
|
'remove_resources': fields.ListOfObjectsField(
|
||||||
'GrantInfo', nullable=True, default=[]),
|
'GrantInfo', nullable=True, default=[]),
|
||||||
|
'update_resources': fields.ListOfObjectsField(
|
||||||
|
'GrantInfo', nullable=True, default=[]),
|
||||||
'vim_assets': fields.ObjectField(
|
'vim_assets': fields.ObjectField(
|
||||||
'VimAssets', nullable=True)
|
'VimAssets', nullable=True),
|
||||||
|
'ext_virtual_links': fields.ListOfObjectsField(
|
||||||
|
'ExtVirtualLinkData', nullable=True, default=[]),
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -65,11 +69,20 @@ class Grant(base.TackerObject):
|
||||||
remove_rsc) for remove_rsc in primitive.get(
|
remove_rsc) for remove_rsc in primitive.get(
|
||||||
'remove_resources', [])]
|
'remove_resources', [])]
|
||||||
primitive.update({'remove_resources': obj_data})
|
primitive.update({'remove_resources': obj_data})
|
||||||
|
if 'update_resources' in primitive.keys():
|
||||||
|
obj_data = [GrantInfo._from_dict(
|
||||||
|
update_rsc) for update_rsc in primitive.get(
|
||||||
|
'update_resources', [])]
|
||||||
|
primitive.update({'update_resources': obj_data})
|
||||||
if 'vim_assets' in primitive.keys():
|
if 'vim_assets' in primitive.keys():
|
||||||
obj_data = VimAssets.obj_from_primitive(
|
obj_data = VimAssets.obj_from_primitive(
|
||||||
primitive.get('vim_assets'), context)
|
primitive.get('vim_assets'), context)
|
||||||
primitive.update({'vim_assets': obj_data})
|
primitive.update({'vim_assets': obj_data})
|
||||||
|
if 'ext_virtual_links' in primitive.keys():
|
||||||
|
obj_data = [objects.ExtVirtualLinkData.obj_from_primitive(
|
||||||
|
ext_vir_link, context) for ext_vir_link in primitive.get(
|
||||||
|
'ext_virtual_links', [])]
|
||||||
|
primitive.update({'ext_virtual_links': obj_data})
|
||||||
obj_grant = Grant._from_dict(primitive)
|
obj_grant = Grant._from_dict(primitive)
|
||||||
|
|
||||||
return obj_grant
|
return obj_grant
|
||||||
|
@ -83,7 +96,9 @@ class Grant(base.TackerObject):
|
||||||
zones = data_dict.get('zones', [])
|
zones = data_dict.get('zones', [])
|
||||||
add_resources = data_dict.get('add_resources', [])
|
add_resources = data_dict.get('add_resources', [])
|
||||||
remove_resources = data_dict.get('remove_resources', [])
|
remove_resources = data_dict.get('remove_resources', [])
|
||||||
|
update_resources = data_dict.get('update_resources', [])
|
||||||
vim_assets = data_dict.get('vim_assets')
|
vim_assets = data_dict.get('vim_assets')
|
||||||
|
ext_virtual_links = data_dict.get('ext_virtual_links', [])
|
||||||
|
|
||||||
obj = cls(
|
obj = cls(
|
||||||
id=id,
|
id=id,
|
||||||
|
@ -93,7 +108,9 @@ class Grant(base.TackerObject):
|
||||||
zones=zones,
|
zones=zones,
|
||||||
add_resources=add_resources,
|
add_resources=add_resources,
|
||||||
remove_resources=remove_resources,
|
remove_resources=remove_resources,
|
||||||
vim_assets=vim_assets)
|
update_resources=update_resources,
|
||||||
|
vim_assets=vim_assets,
|
||||||
|
ext_virtual_links=ext_virtual_links)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ class GrantRequest(base.TackerObject):
|
||||||
'ResourceDefinition', nullable=True, default=[]),
|
'ResourceDefinition', nullable=True, default=[]),
|
||||||
'remove_resources': fields.ListOfObjectsField(
|
'remove_resources': fields.ListOfObjectsField(
|
||||||
'ResourceDefinition', nullable=True, default=[]),
|
'ResourceDefinition', nullable=True, default=[]),
|
||||||
|
'update_resources': fields.ListOfObjectsField(
|
||||||
|
'ResourceDefinition', nullable=True, default=[]),
|
||||||
'placement_constraints': fields.ListOfObjectsField(
|
'placement_constraints': fields.ListOfObjectsField(
|
||||||
'PlacementConstraint', nullable=True, default=[]),
|
'PlacementConstraint', nullable=True, default=[]),
|
||||||
'_links': fields.ObjectField(
|
'_links': fields.ObjectField(
|
||||||
|
@ -57,11 +59,20 @@ class GrantRequest(base.TackerObject):
|
||||||
remove_rsc) for remove_rsc in primitive.get(
|
remove_rsc) for remove_rsc in primitive.get(
|
||||||
'remove_resources', [])]
|
'remove_resources', [])]
|
||||||
primitive.update({'add_resources': obj_data})
|
primitive.update({'add_resources': obj_data})
|
||||||
|
if 'update_resources' in primitive.keys():
|
||||||
|
obj_data = [ResourceDefinition._from_dict(
|
||||||
|
update_rsc) for update_rsc in primitive.get(
|
||||||
|
'update_resources', [])]
|
||||||
|
primitive.update({'update_resources': obj_data})
|
||||||
if 'placement_constraints' in primitive.keys():
|
if 'placement_constraints' in primitive.keys():
|
||||||
obj_data = [PlacementConstraint._from_dict(
|
obj_data = [PlacementConstraint._from_dict(
|
||||||
place) for place in primitive.get(
|
place) for place in primitive.get(
|
||||||
'placement_constraints', [])]
|
'placement_constraints', [])]
|
||||||
primitive.update({'add_resources': obj_data})
|
primitive.update({'add_resources': obj_data})
|
||||||
|
if '_links' in primitive.keys():
|
||||||
|
obj_data = Links._from_dict(
|
||||||
|
primitive.get('_links', {}))
|
||||||
|
primitive.update({'_links': obj_data})
|
||||||
obj_grant_req = GrantRequest._from_dict(primitive)
|
obj_grant_req = GrantRequest._from_dict(primitive)
|
||||||
|
|
||||||
return obj_grant_req
|
return obj_grant_req
|
||||||
|
@ -76,6 +87,7 @@ class GrantRequest(base.TackerObject):
|
||||||
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
||||||
add_resources = data_dict.get('add_resources', [])
|
add_resources = data_dict.get('add_resources', [])
|
||||||
remove_resources = data_dict.get('remove_resources', [])
|
remove_resources = data_dict.get('remove_resources', [])
|
||||||
|
update_resources = data_dict.get('update_resources', [])
|
||||||
placement_constraints = data_dict.get('placement_constraints', [])
|
placement_constraints = data_dict.get('placement_constraints', [])
|
||||||
links = data_dict.get('_links')
|
links = data_dict.get('_links')
|
||||||
|
|
||||||
|
@ -88,6 +100,7 @@ class GrantRequest(base.TackerObject):
|
||||||
is_automatic_invocation=is_automatic_invocation,
|
is_automatic_invocation=is_automatic_invocation,
|
||||||
add_resources=add_resources,
|
add_resources=add_resources,
|
||||||
remove_resources=remove_resources,
|
remove_resources=remove_resources,
|
||||||
|
update_resources=update_resources,
|
||||||
placement_constraints=placement_constraints,
|
placement_constraints=placement_constraints,
|
||||||
_links=links)
|
_links=links)
|
||||||
return obj
|
return obj
|
||||||
|
@ -112,6 +125,12 @@ class GrantRequest(base.TackerObject):
|
||||||
remove_resources_list.append(remove_resource.to_dict())
|
remove_resources_list.append(remove_resource.to_dict())
|
||||||
|
|
||||||
data.update({'remove_resources': remove_resources_list})
|
data.update({'remove_resources': remove_resources_list})
|
||||||
|
if self.update_resources:
|
||||||
|
update_resources_list = []
|
||||||
|
for update_resource in self.update_resources:
|
||||||
|
update_resources_list.append(update_resource.to_dict())
|
||||||
|
|
||||||
|
data.update({'update_resources': update_resources_list})
|
||||||
if self.placement_constraints:
|
if self.placement_constraints:
|
||||||
placement_constraints_list = []
|
placement_constraints_list = []
|
||||||
for placement_constraint in self.placement_constraints:
|
for placement_constraint in self.placement_constraints:
|
||||||
|
|
|
@ -291,7 +291,8 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
||||||
changed_ext_conn = \
|
changed_ext_conn = \
|
||||||
[objects.ExtVirtualLinkInfo.obj_from_primitive(
|
[objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||||
chg_ext_conn, context) for chg_ext_conn in
|
chg_ext_conn, context) for chg_ext_conn in
|
||||||
db_vnf_lcm_op_occ['changed_ext_connectivity']]
|
jsonutils.loads(
|
||||||
|
db_vnf_lcm_op_occ['changed_ext_connectivity'])]
|
||||||
vnf_lcm_op_occ_obj.changed_ext_connectivity = changed_ext_conn
|
vnf_lcm_op_occ_obj.changed_ext_connectivity = changed_ext_conn
|
||||||
|
|
||||||
vnf_lcm_op_occ_obj._context = context
|
vnf_lcm_op_occ_obj._context = context
|
||||||
|
|
|
@ -40,6 +40,7 @@ PENDING_SCALE_IN = "PENDING_SCALE_IN"
|
||||||
PENDING_SCALE_OUT = "PENDING_SCALE_OUT"
|
PENDING_SCALE_OUT = "PENDING_SCALE_OUT"
|
||||||
PENDING_HEAL = "PENDING_HEAL"
|
PENDING_HEAL = "PENDING_HEAL"
|
||||||
PENDING_TERMINATE = "PENDING_TERMINATE"
|
PENDING_TERMINATE = "PENDING_TERMINATE"
|
||||||
|
PENDING_CHANGE_EXT_CONN = "PENDING_CHANGE_EXT_CONN"
|
||||||
DEAD = "DEAD"
|
DEAD = "DEAD"
|
||||||
ERROR = "ERROR"
|
ERROR = "ERROR"
|
||||||
NACK = "NACK"
|
NACK = "NACK"
|
||||||
|
|
|
@ -176,6 +176,18 @@ rules = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=VNFLCM % 'change_ext_conn',
|
||||||
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
description="Change external VNF connectivity.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'POST',
|
||||||
|
'path':
|
||||||
|
'/vnflcm/v1/vnf_instances/{vnfInstanceId}/change_ext_conn'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add REST APIs for Change External VNF Connectivity.
|
||||||
|
|
|
@ -74,3 +74,17 @@ class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
|
||||||
heal_vnf_request, grant,
|
heal_vnf_request, grant,
|
||||||
grant_request, **kwargs):
|
grant_request, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_external_connectivity_start(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_external_connectivity_end(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
|
@ -9,4 +9,4 @@ Content-type: application/x-iso9066-image
|
||||||
Name: Scripts/vnflcm_noop.py
|
Name: Scripts/vnflcm_noop.py
|
||||||
Content-Type: text/x-python
|
Content-Type: text/x-python
|
||||||
Algorithm: SHA-256
|
Algorithm: SHA-256
|
||||||
Hash: 63cfaf9963680ff864981d4db809c2ec175d78054157c0bcd43ac7a85973af10
|
Hash: 950422e356c3eb6a7c92f424d975e2d3f295f480321bd91a97501045eddeab4a
|
||||||
|
|
|
@ -262,6 +262,9 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||||
self.ext_link_ports = list()
|
self.ext_link_ports = list()
|
||||||
# Create external subnet in net1
|
# Create external subnet in net1
|
||||||
self.ext_subnets = list() # Store ids for cleaning.
|
self.ext_subnets = list() # Store ids for cleaning.
|
||||||
|
# Create external networks to change.
|
||||||
|
self.changed_ext_networks = list()
|
||||||
|
self.changed_ext_subnets = list() # Store ids for cleaning.
|
||||||
|
|
||||||
networks = self.neutronclient().list_networks()
|
networks = self.neutronclient().list_networks()
|
||||||
for nw in networks.get('networks'):
|
for nw in networks.get('networks'):
|
||||||
|
@ -281,13 +284,26 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||||
ext_mngd_net_id, _ = \
|
ext_mngd_net_id, _ = \
|
||||||
self._create_network("external_managed_internal_net")
|
self._create_network("external_managed_internal_net")
|
||||||
self.ext_mngd_networks.append(ext_mngd_net_id)
|
self.ext_mngd_networks.append(ext_mngd_net_id)
|
||||||
|
changed_ext_net_id, changed_ext_net_name = \
|
||||||
|
self._create_network("changed_external_net")
|
||||||
|
self.changed_ext_networks.append(changed_ext_net_id)
|
||||||
|
|
||||||
# Chack how many networks are created.
|
# Chack how many networks are created.
|
||||||
networks = self.neutronclient().list_networks()
|
networks = self.neutronclient().list_networks()
|
||||||
for nw in networks.get('networks'):
|
for nw in networks.get('networks'):
|
||||||
if nw['name'] not in [ext_net_name]:
|
if nw['name'] not in [ext_net_name, changed_ext_net_name]:
|
||||||
continue
|
continue
|
||||||
self.ext_subnets.append(self._create_subnet(nw))
|
|
||||||
|
elif nw['name'] == ext_net_name:
|
||||||
|
self.ext_subnets.append(
|
||||||
|
self._create_subnet(nw,
|
||||||
|
cidr="22.22.1.0/24",
|
||||||
|
gateway="22.22.1.1"))
|
||||||
|
elif nw['name'] == changed_ext_net_name:
|
||||||
|
self.changed_ext_subnets.append(
|
||||||
|
self._create_subnet(nw,
|
||||||
|
cidr="22.22.2.0/24",
|
||||||
|
gateway="22.22.2.1"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _list_glance_image(cls, filter_name='cirros-0.4.0-x86_64-disk'):
|
def _list_glance_image(cls, filter_name='cirros-0.4.0-x86_64-disk'):
|
||||||
|
@ -453,6 +469,16 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||||
|
|
||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
|
def _change_ext_conn_vnf_instance(self, vnf_instance_id, request_body):
|
||||||
|
url = os.path.join(
|
||||||
|
self.base_vnf_instances_url,
|
||||||
|
vnf_instance_id,
|
||||||
|
"change_ext_conn")
|
||||||
|
resp, body = self.http_client.do_request(url, "POST",
|
||||||
|
body=jsonutils.dumps(request_body))
|
||||||
|
|
||||||
|
return resp, body
|
||||||
|
|
||||||
def _rollback_op_occs(self, vnf_lcm_op_occs_id):
|
def _rollback_op_occs(self, vnf_lcm_op_occs_id):
|
||||||
rollback_url = os.path.join(
|
rollback_url = os.path.join(
|
||||||
self.base_vnf_lcm_op_occs_url,
|
self.base_vnf_lcm_op_occs_url,
|
||||||
|
@ -1140,18 +1166,18 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||||
self.fail("Failed, create network=<%s>, %s" %
|
self.fail("Failed, create network=<%s>, %s" %
|
||||||
(uniq_name, e))
|
(uniq_name, e))
|
||||||
|
|
||||||
def _create_subnet(self, network):
|
def _create_subnet(self, network, cidr, gateway):
|
||||||
cidr_prefix = "22.22.{}".format(str(len(self.ext_subnets)))
|
|
||||||
body = {'subnet': {'network_id': network['id'],
|
body = {'subnet': {'network_id': network['id'],
|
||||||
'name': "subnet-%s" % uuidutils.generate_uuid(),
|
'name': "subnet-%s" % uuidutils.generate_uuid(),
|
||||||
'cidr': "{}.0/24".format(cidr_prefix),
|
'cidr': "{}".format(cidr),
|
||||||
'ip_version': 4,
|
'ip_version': 4,
|
||||||
'gateway_ip': "{}.1".format(cidr_prefix),
|
'gateway_ip': "{}".format(gateway),
|
||||||
"enable_dhcp": True}}
|
"enable_dhcp": True}}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subnet = self.neutronclient().create_subnet(body=body)["subnet"]
|
subnet = self.neutronclient().create_subnet(body=body)["subnet"]
|
||||||
self.addCleanup(self._delete_subnet, subnet['id'])
|
self.addCleanup(self._delete_subnet, subnet['id'])
|
||||||
|
print("Create subnet success, %s" % subnet['id'], flush=True)
|
||||||
return subnet['id']
|
return subnet['id']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.fail("Failed, create subnet for net_id=<%s>, %s" %
|
self.fail("Failed, create subnet for net_id=<%s>, %s" %
|
||||||
|
|
|
@ -40,7 +40,8 @@ class Subscription:
|
||||||
"SCALE",
|
"SCALE",
|
||||||
"TERMINATE",
|
"TERMINATE",
|
||||||
"HEAL",
|
"HEAL",
|
||||||
"MODIFY_INFO"
|
"MODIFY_INFO",
|
||||||
|
"CHANGE_EXT_CONN"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"callbackUri": callback_uri
|
"callbackUri": callback_uri
|
||||||
|
@ -373,3 +374,56 @@ class VnfInstances:
|
||||||
"samplekey": "samplevalue"
|
"samplekey": "samplevalue"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_change_ext_conn_request_body(
|
||||||
|
tenant_id,
|
||||||
|
networks_id,
|
||||||
|
external_subnets_id):
|
||||||
|
|
||||||
|
# set external subnet_id on vim.
|
||||||
|
ext_cps_vdu2_cp2 = {
|
||||||
|
"cpdId": "VDU2_CP2",
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": ["22.22.2.200"],
|
||||||
|
"subnetId": external_subnets_id[0]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
ext_virtual_link_cp2 = {
|
||||||
|
"id": uuidsentinel.evl2_id,
|
||||||
|
"resourceId": networks_id[0],
|
||||||
|
"extCps": [
|
||||||
|
ext_cps_vdu2_cp2
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"extVirtualLinks": [
|
||||||
|
ext_virtual_link_cp2
|
||||||
|
],
|
||||||
|
"vimConnectionInfo": [{
|
||||||
|
"id": uuidsentinel.vim_connection_id,
|
||||||
|
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||||
|
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||||
|
"interfaceInfo": {
|
||||||
|
"endpoint": "http://127.0.0.1/identity"
|
||||||
|
},
|
||||||
|
"accessInfo": {
|
||||||
|
"username": "nfv_user",
|
||||||
|
"region": "RegionOne",
|
||||||
|
"password": "devstack",
|
||||||
|
"tenant": tenant_id
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
|
@ -1596,6 +1596,48 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||||
expected_usage_state,
|
expected_usage_state,
|
||||||
vnf_package_info['usageState'])
|
vnf_package_info['usageState'])
|
||||||
|
|
||||||
|
def _get_fixed_ips(self, vnf_instance_id, request_body):
|
||||||
|
res_name = None
|
||||||
|
for extvirlink in request_body['extVirtualLinks']:
|
||||||
|
if 'extCps' not in extvirlink:
|
||||||
|
continue
|
||||||
|
for extcps in extvirlink['extCps']:
|
||||||
|
if 'cpdId' in extcps:
|
||||||
|
if res_name is None:
|
||||||
|
res_name = list()
|
||||||
|
res_name.append(extcps['cpdId'])
|
||||||
|
break
|
||||||
|
if res_name is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
stack = self._get_heat_stack(vnf_instance_id)
|
||||||
|
stack_id = stack.id
|
||||||
|
|
||||||
|
stack_resource = self._get_heat_resource_list(stack_id, nested_depth=2)
|
||||||
|
|
||||||
|
releations = dict()
|
||||||
|
for elmt in stack_resource:
|
||||||
|
if elmt.resource_type != 'OS::Neutron::Port':
|
||||||
|
continue
|
||||||
|
if elmt.resource_name not in res_name:
|
||||||
|
continue
|
||||||
|
releations[elmt.parent_resource] = elmt.resource_name
|
||||||
|
|
||||||
|
details = list()
|
||||||
|
for (parent_name, resource_name) in releations.items():
|
||||||
|
for elmt in stack_resource:
|
||||||
|
if parent_name != elmt.resource_name:
|
||||||
|
continue
|
||||||
|
detail_stack = self._get_heat_resource(
|
||||||
|
elmt.physical_resource_id, resource_name)
|
||||||
|
details.append(detail_stack)
|
||||||
|
|
||||||
|
ans_list = list()
|
||||||
|
for detail in details:
|
||||||
|
ans_list.append(detail.attributes['fixed_ips'])
|
||||||
|
|
||||||
|
return ans_list
|
||||||
|
|
||||||
def _assert_occ_show(self, resp, op_occs_info):
|
def _assert_occ_show(self, resp, op_occs_info):
|
||||||
self.assertEqual(200, resp.status_code)
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
@ -1684,3 +1726,146 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||||
self.assertIsNotNone(_links.get('rollback').get('href'))
|
self.assertIsNotNone(_links.get('rollback').get('href'))
|
||||||
if _links.get('grant') is not None:
|
if _links.get('grant') is not None:
|
||||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||||
|
|
||||||
|
def test_inst_chgextconn_term(self):
|
||||||
|
"""Test basic life cycle operations with sample VNFD.
|
||||||
|
|
||||||
|
In this test case, we do following steps.
|
||||||
|
- Create subscription.
|
||||||
|
- Show subscriptions.
|
||||||
|
- Get list of subscriptions.
|
||||||
|
- Create VNF package.
|
||||||
|
- Upload VNF package.
|
||||||
|
- Create VNF instance.
|
||||||
|
- Instantiate VNF.
|
||||||
|
- Get list of VNF instances.
|
||||||
|
- Get VNF informations.
|
||||||
|
- Change External VNF Connectivity.
|
||||||
|
- Get opOccs informations.
|
||||||
|
- Terminate VNF
|
||||||
|
- Delete VNF
|
||||||
|
- Delete subscription
|
||||||
|
"""
|
||||||
|
# Create subscription and register it.
|
||||||
|
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||||
|
'http://localhost:{}{}'.format(
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||||
|
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||||
|
self._testMethodName)))
|
||||||
|
resp, response_body = self._register_subscription(request_body)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
self.assert_http_header_location_for_subscription(resp.headers)
|
||||||
|
subscription_id = response_body.get('id')
|
||||||
|
self.addCleanup(
|
||||||
|
self._delete_subscription,
|
||||||
|
subscription_id)
|
||||||
|
|
||||||
|
# Subscription show
|
||||||
|
resp, body = self._wait_show_subscription(subscription_id)
|
||||||
|
self.assert_subscription_show(resp, body)
|
||||||
|
|
||||||
|
# Subscription list
|
||||||
|
resp, _ = self._list_subscription()
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# Pre Setting: Create vnf package.
|
||||||
|
sample_name = 'functional5'
|
||||||
|
csar_package_path = os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"../../../etc/samples/etsi/nfv",
|
||||||
|
sample_name))
|
||||||
|
tempname, _ = vnflcm_base._create_csar_with_unique_vnfd_id(
|
||||||
|
csar_package_path)
|
||||||
|
# upload vnf package
|
||||||
|
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
|
||||||
|
self.tacker_client, user_defined_data={
|
||||||
|
"key": sample_name}, temp_csar_path=tempname)
|
||||||
|
|
||||||
|
# Post Setting: Reserve deleting vnf package.
|
||||||
|
self.addCleanup(vnflcm_base._delete_vnf_package, self.tacker_client,
|
||||||
|
vnf_package_id)
|
||||||
|
|
||||||
|
# Create vnf instance
|
||||||
|
resp, vnf_instance = self._create_vnf_instance_from_body(
|
||||||
|
fake_vnflcm.VnfInstances.make_create_request_body(vnfd_id))
|
||||||
|
vnf_instance_id = vnf_instance['id']
|
||||||
|
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||||
|
self.assert_create_vnf(resp, vnf_instance, vnf_package_id)
|
||||||
|
vnf_instance_name = vnf_instance['vnfInstanceName']
|
||||||
|
self.addCleanup(self._delete_vnf_instance, vnf_instance_id)
|
||||||
|
|
||||||
|
# Instantiate vnf instance
|
||||||
|
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
|
||||||
|
self.vim['tenant_id'], self.ext_networks, self.ext_mngd_networks,
|
||||||
|
self.ext_link_ports, self.ext_subnets)
|
||||||
|
resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||||
|
|
||||||
|
# List vnf instance
|
||||||
|
filter_expr = {
|
||||||
|
'filter': "(eq,id,{});(eq,vnfInstanceName,{})".format(
|
||||||
|
vnf_instance_id, vnf_instance_name)}
|
||||||
|
resp, vnf_instances = self._list_vnf_instance(params=filter_expr)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertEqual(1, len(vnf_instances))
|
||||||
|
|
||||||
|
# Show vnf instance
|
||||||
|
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# Change external connectivity
|
||||||
|
request_body = \
|
||||||
|
fake_vnflcm.VnfInstances.make_change_ext_conn_request_body(
|
||||||
|
self.vim['tenant_id'], self.changed_ext_networks,
|
||||||
|
self.changed_ext_subnets)
|
||||||
|
before_fixed_ips = self._get_fixed_ips(vnf_instance_id, request_body)
|
||||||
|
resp, _ = \
|
||||||
|
self._change_ext_conn_vnf_instance(vnf_instance_id, request_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
after_fixed_ips = self._get_fixed_ips(vnf_instance_id, request_body)
|
||||||
|
self.assertNotEqual(before_fixed_ips, after_fixed_ips)
|
||||||
|
|
||||||
|
callback_url = os.path.join(
|
||||||
|
vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||||
|
self._testMethodName)
|
||||||
|
notify_mock_responses = vnflcm_base.FAKE_SERVER_MANAGER.get_history(
|
||||||
|
callback_url)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.clear_history(
|
||||||
|
callback_url)
|
||||||
|
vnflcm_op_occ_id = notify_mock_responses[0].request_body.get(
|
||||||
|
'vnfLcmOpOccId')
|
||||||
|
self.assertIsNotNone(vnflcm_op_occ_id)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.clear_history(callback_url)
|
||||||
|
|
||||||
|
# occ-show(chgextconn)
|
||||||
|
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||||
|
self._assert_occ_show(resp, op_occs_info)
|
||||||
|
|
||||||
|
# Terminate VNF
|
||||||
|
stack = self._get_heat_stack(vnf_instance_id)
|
||||||
|
resources_list = self._get_heat_resource_list(stack.id)
|
||||||
|
resource_name_list = [r.resource_name for r in resources_list]
|
||||||
|
glance_image_id_list = \
|
||||||
|
self._get_glance_image_list_from_stack_resource(
|
||||||
|
stack.id, resource_name_list)
|
||||||
|
|
||||||
|
terminate_req_body = fake_vnflcm.VnfInstances.make_term_request_body()
|
||||||
|
resp, _ = self._terminate_vnf_instance(
|
||||||
|
vnf_instance_id, terminate_req_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
self.assert_terminate_vnf(resp, vnf_instance_id, stack.id,
|
||||||
|
resource_name_list, glance_image_id_list, vnf_package_id)
|
||||||
|
|
||||||
|
# Delete VNF
|
||||||
|
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||||
|
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||||
|
self.assert_delete_vnf(resp, vnf_instance_id, vnf_package_id)
|
||||||
|
|
||||||
|
# Subscription delete
|
||||||
|
resp, response_body = self._delete_subscription(subscription_id)
|
||||||
|
self.assertEqual(204, resp.status_code)
|
||||||
|
|
||||||
|
resp, _ = self._show_subscription(subscription_id)
|
||||||
|
self.assertEqual(404, resp.status_code)
|
||||||
|
|
|
@ -76,6 +76,17 @@ class Grant:
|
||||||
|
|
||||||
return res_remove_resources
|
return res_remove_resources
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _make_update_resources(req_update_resources):
|
||||||
|
res_update_resources = []
|
||||||
|
for req_update_resource in req_update_resources:
|
||||||
|
res_update_resource = {
|
||||||
|
"resourceDefinitionId": req_update_resource['id']
|
||||||
|
}
|
||||||
|
res_update_resources.append(res_update_resource)
|
||||||
|
|
||||||
|
return res_update_resources
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _make_vim_assets(image_id, flavour_id="1"):
|
def _make_vim_assets(image_id, flavour_id="1"):
|
||||||
# set m1.tiny="1" for flavour_id
|
# set m1.tiny="1" for flavour_id
|
||||||
|
@ -203,3 +214,17 @@ class Grant:
|
||||||
request_body['removeResources'])
|
request_body['removeResources'])
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_change_ext_conn_response_body(request_body, tenant_id, image_id):
|
||||||
|
request_body = Grant._convert_body_to_dict(request_body)
|
||||||
|
res = Grant._make_response_template(request_body)
|
||||||
|
res["vimConnections"] = Grant._make_vim_connection_info(tenant_id)
|
||||||
|
res["zones"] = Grant.ZONES
|
||||||
|
if 'updateResources' in request_body.keys():
|
||||||
|
res["updateResources"] = Grant._make_update_resources(
|
||||||
|
request_body['updateResources'])
|
||||||
|
res["vimAssets"] = Grant._make_vim_assets(image_id)
|
||||||
|
res["additionalParams"] = Grant.ADDITIONAL_PARAMS
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
|
@ -23,7 +23,7 @@ from tacker.tests.functional.sol_separated_nfvo.vnflcm import fake_vnfpkgm
|
||||||
|
|
||||||
class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||||
|
|
||||||
def _register_vnf_package_mock_response(self):
|
def _register_vnf_package_mock_response(self, package_dir="functional6"):
|
||||||
"""Prepare VNF package for test.
|
"""Prepare VNF package for test.
|
||||||
|
|
||||||
Register VNF package response to fake NFVO server and Cleanups.
|
Register VNF package response to fake NFVO server and Cleanups.
|
||||||
|
@ -32,7 +32,7 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||||
Response: VNF Package information
|
Response: VNF Package information
|
||||||
"""
|
"""
|
||||||
# Pre Setting: Create vnf package.
|
# Pre Setting: Create vnf package.
|
||||||
sample_name = "functional6"
|
sample_name = package_dir
|
||||||
csar_package_path = os.path.abspath(
|
csar_package_path = os.path.abspath(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
|
@ -92,6 +92,152 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||||
|
|
||||||
return vnf_package_info
|
return vnf_package_info
|
||||||
|
|
||||||
|
def test_inst_chgextconn_term(self):
|
||||||
|
"""Test basic life cycle operations with sample VNFD with UserData.
|
||||||
|
|
||||||
|
In this test case, we do following steps.
|
||||||
|
- Create subscription.
|
||||||
|
- Create VNF instance.
|
||||||
|
- Instantiate VNF.
|
||||||
|
- List VNF instances.
|
||||||
|
- Show VNF instance.
|
||||||
|
- Change External VNF Connectivity.
|
||||||
|
- Get opOccs information.
|
||||||
|
- Terminate VNF.
|
||||||
|
- Delete VNF.
|
||||||
|
- Delete subscription.
|
||||||
|
- Show subscription.
|
||||||
|
"""
|
||||||
|
vnf_package_info = self._register_vnf_package_mock_response(
|
||||||
|
package_dir="functional5")
|
||||||
|
glance_image = self._list_glance_image()[0]
|
||||||
|
|
||||||
|
# Create subscription and register it.
|
||||||
|
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||||
|
'http://localhost:{}{}'.format(
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||||
|
os.path.join(
|
||||||
|
vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||||
|
self._testMethodName)))
|
||||||
|
resp, response_body = self._register_subscription(request_body)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
self.assert_http_header_location_for_subscription(resp.headers)
|
||||||
|
subscription_id = response_body.get('id')
|
||||||
|
self.addCleanup(self._delete_subscription, subscription_id)
|
||||||
|
|
||||||
|
# Create vnf instance
|
||||||
|
resp, vnf_instance = self._create_vnf_instance_from_body(
|
||||||
|
fake_vnflcm.VnfInstances.make_create_request_body(
|
||||||
|
vnf_package_info['vnfdId']))
|
||||||
|
vnf_instance_id = vnf_instance.get('id')
|
||||||
|
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||||
|
self._assert_create_vnf(resp, vnf_instance)
|
||||||
|
vnf_instance_name = vnf_instance['vnfInstanceName']
|
||||||
|
self.addCleanup(self._delete_vnf_instance, vnf_instance_id)
|
||||||
|
|
||||||
|
# Set Fake server response for Grant-Req(Instantiate)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.set_callback('POST',
|
||||||
|
fake_grant.Grant.GRANT_REQ_PATH, status_code=201,
|
||||||
|
callback=lambda req_headers,
|
||||||
|
req_body: fake_grant.Grant.make_inst_response_body(req_body,
|
||||||
|
self.vim['tenant_id'], glance_image.id))
|
||||||
|
|
||||||
|
# Instantiate vnf instance
|
||||||
|
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
|
||||||
|
self.vim['tenant_id'], self.ext_networks, self.ext_mngd_networks,
|
||||||
|
self.ext_link_ports, self.ext_subnets)
|
||||||
|
resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
self._assert_instantiate_vnf(resp, vnf_instance_id)
|
||||||
|
|
||||||
|
# List vnf instances
|
||||||
|
filter_expr = {
|
||||||
|
'filter': "(eq,id,{});(eq,vnfInstanceName,{})".format(
|
||||||
|
vnf_instance_id, vnf_instance_name)}
|
||||||
|
resp, vnf_instances = self._list_vnf_instance(params=filter_expr)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertEqual(1, len(vnf_instances))
|
||||||
|
|
||||||
|
# Show vnf instance
|
||||||
|
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# Set Fake server response for Grant-Req(Chnage-ext-conn)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.set_callback(
|
||||||
|
'POST',
|
||||||
|
fake_grant.Grant.GRANT_REQ_PATH,
|
||||||
|
status_code=201,
|
||||||
|
callback=lambda req_headers,
|
||||||
|
req_body: fake_grant.Grant.make_change_ext_conn_response_body(
|
||||||
|
req_body,
|
||||||
|
self.vim['tenant_id'],
|
||||||
|
glance_image.id))
|
||||||
|
|
||||||
|
# Change external connectivity
|
||||||
|
request_body = \
|
||||||
|
fake_vnflcm.VnfInstances.make_change_ext_conn_request_body(
|
||||||
|
self.vim['tenant_id'], self.changed_ext_networks,
|
||||||
|
self.changed_ext_subnets)
|
||||||
|
before_fixed_ips = self._get_fixed_ips(vnf_instance_id, request_body)
|
||||||
|
resp, _ = \
|
||||||
|
self._change_ext_conn_vnf_instance(vnf_instance_id, request_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
after_fixed_ips = self._get_fixed_ips(vnf_instance_id, request_body)
|
||||||
|
self.assertNotEqual(before_fixed_ips, after_fixed_ips)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.clear_history(
|
||||||
|
fake_grant.Grant.GRANT_REQ_PATH)
|
||||||
|
|
||||||
|
# get vnflcm_op_occ_id
|
||||||
|
callback_url = os.path.join(
|
||||||
|
vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||||
|
self._testMethodName)
|
||||||
|
notify_mock_responses = vnflcm_base.FAKE_SERVER_MANAGER.get_history(
|
||||||
|
callback_url)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.clear_history(
|
||||||
|
callback_url)
|
||||||
|
|
||||||
|
vnflcm_op_occ_id = notify_mock_responses[0].request_body.get(
|
||||||
|
'vnfLcmOpOccId')
|
||||||
|
self.assertIsNotNone(vnflcm_op_occ_id)
|
||||||
|
|
||||||
|
# occ-show(chgextconn)
|
||||||
|
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||||
|
self._assert_occ_show(resp, op_occs_info)
|
||||||
|
|
||||||
|
# Set Fake server response for Grant-Req(Terminate)
|
||||||
|
vnflcm_base.FAKE_SERVER_MANAGER.set_callback('POST',
|
||||||
|
fake_grant.Grant.GRANT_REQ_PATH, status_code=201,
|
||||||
|
callback=lambda req_headers,
|
||||||
|
req_body: fake_grant.Grant.make_term_response_body(req_body))
|
||||||
|
|
||||||
|
# Get stack informations to terminate.
|
||||||
|
stack = self._get_heat_stack(vnf_instance_id)
|
||||||
|
resources_list = self._get_heat_resource_list(stack.id)
|
||||||
|
resource_name_list = [r.resource_name for r in resources_list]
|
||||||
|
glance_image_id_list = self._get_glance_image_list_from_stack_resource(
|
||||||
|
stack.id, resource_name_list)
|
||||||
|
|
||||||
|
# Terminate VNF
|
||||||
|
terminate_req_body = fake_vnflcm.VnfInstances.make_term_request_body()
|
||||||
|
resp, _ = self._terminate_vnf_instance(vnf_instance_id,
|
||||||
|
terminate_req_body)
|
||||||
|
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
|
||||||
|
self._assert_terminate_vnf(resp, vnf_instance_id, stack.id,
|
||||||
|
resource_name_list, glance_image_id_list)
|
||||||
|
|
||||||
|
# Delete VNF
|
||||||
|
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||||
|
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||||
|
self.assert_delete_vnf(resp, vnf_instance_id)
|
||||||
|
|
||||||
|
# Delete Subscription
|
||||||
|
resp, response_body = self._delete_subscription(subscription_id)
|
||||||
|
self.assertEqual(204, resp.status_code)
|
||||||
|
|
||||||
|
# Check subscription was deleted
|
||||||
|
resp, show_body = self._show_subscription(subscription_id)
|
||||||
|
self.assertEqual(404, resp.status_code)
|
||||||
|
|
||||||
def test_inst_heal_term(self):
|
def test_inst_heal_term(self):
|
||||||
"""Test basic life cycle operations with sample VNFD with UserData.
|
"""Test basic life cycle operations with sample VNFD with UserData.
|
||||||
|
|
||||||
|
@ -315,3 +461,64 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{} {}'.format(expected_auth_type, expected_token_value),
|
'{} {}'.format(expected_auth_type, expected_token_value),
|
||||||
actual_auth)
|
actual_auth)
|
||||||
|
|
||||||
|
def _assert_occ_show(self, resp, op_occs_info):
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# Only check required parameters.
|
||||||
|
self.assertIsNotNone(op_occs_info.get('id'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('operationState'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('stateEnteredTime'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('vnfInstanceId'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('operation'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('isAutomaticInvocation'))
|
||||||
|
self.assertIsNotNone(op_occs_info.get('isCancelPending'))
|
||||||
|
|
||||||
|
_links = op_occs_info.get('_links')
|
||||||
|
self.assertIsNotNone(_links.get('self'))
|
||||||
|
self.assertIsNotNone(_links.get('self').get('href'))
|
||||||
|
self.assertIsNotNone(_links.get('vnfInstance'))
|
||||||
|
self.assertIsNotNone(_links.get('vnfInstance').get('href'))
|
||||||
|
self.assertIsNotNone(_links.get('grant'))
|
||||||
|
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||||
|
|
||||||
|
def _get_fixed_ips(self, vnf_instance_id, request_body):
|
||||||
|
res_name = None
|
||||||
|
for extvirlink in request_body['extVirtualLinks']:
|
||||||
|
if 'extCps' not in extvirlink:
|
||||||
|
continue
|
||||||
|
for extcps in extvirlink['extCps']:
|
||||||
|
if 'cpdId' in extcps:
|
||||||
|
if res_name is None:
|
||||||
|
res_name = list()
|
||||||
|
res_name.append(extcps['cpdId'])
|
||||||
|
break
|
||||||
|
self.assertTrue(res_name)
|
||||||
|
|
||||||
|
stack = self._get_heat_stack(vnf_instance_id)
|
||||||
|
stack_id = stack.id
|
||||||
|
|
||||||
|
stack_resource = self._get_heat_resource_list(stack_id, nested_depth=2)
|
||||||
|
|
||||||
|
releations = dict()
|
||||||
|
for elmt in stack_resource:
|
||||||
|
if elmt.resource_type != 'OS::Neutron::Port':
|
||||||
|
continue
|
||||||
|
if elmt.resource_name not in res_name:
|
||||||
|
continue
|
||||||
|
releations[elmt.parent_resource] = elmt.resource_name
|
||||||
|
|
||||||
|
details = list()
|
||||||
|
for (parent_name, resource_name) in releations.items():
|
||||||
|
for elmt in stack_resource:
|
||||||
|
if parent_name != elmt.resource_name:
|
||||||
|
continue
|
||||||
|
detail_stack = self._get_heat_resource(
|
||||||
|
elmt.physical_resource_id, resource_name)
|
||||||
|
details.append(detail_stack)
|
||||||
|
|
||||||
|
ans_list = list()
|
||||||
|
for detail in details:
|
||||||
|
ans_list.append(detail.attributes['fixed_ips'])
|
||||||
|
|
||||||
|
return ans_list
|
||||||
|
|
|
@ -27,6 +27,7 @@ import zipfile
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from tacker.common import utils as common_utils
|
||||||
from tacker.db.db_sqlalchemy import models
|
from tacker.db.db_sqlalchemy import models
|
||||||
from tacker.objects import scale_vnf_request
|
from tacker.objects import scale_vnf_request
|
||||||
from tacker.tests import utils
|
from tacker.tests import utils
|
||||||
|
@ -301,3 +302,250 @@ def scale_request(type, number_of_steps):
|
||||||
scale_request = scale_vnf_request.ScaleVnfRequest(**scale_request_data)
|
scale_request = scale_vnf_request.ScaleVnfRequest(**scale_request_data)
|
||||||
|
|
||||||
return scale_request
|
return scale_request
|
||||||
|
|
||||||
|
|
||||||
|
def get_instantiated_vnf_info():
|
||||||
|
vnf_info = objects.vnf_instance.VnfInstance()
|
||||||
|
|
||||||
|
def _get_instantiated_vnf_info_data():
|
||||||
|
return {
|
||||||
|
"flavour_id": "simple",
|
||||||
|
"vnf_instance_id": uuidsentinel.vnf_instance_id,
|
||||||
|
"vnf_virtual_link_resource_info":
|
||||||
|
_get_virtual_link_resource_info(),
|
||||||
|
"vnfc_resource_info": _get_vnfc_resource_info(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_virtual_link_resource_info():
|
||||||
|
return [{
|
||||||
|
"id": uuidsentinel.vnf_vl_resource_1,
|
||||||
|
"vnf_virtual_link_desc_id": uuidsentinel.ext_vl_1,
|
||||||
|
"network_resource": {
|
||||||
|
"vim_connection_id": None,
|
||||||
|
"resource_id": uuidsentinel.ext_vl_resource_1,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Net",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"vnf_link_ports": [
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_1,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl1_link_port_1,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_1,
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_2,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl1_link_port_2,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_2,
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_5,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl1_link_port_5,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_2,
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_vl_resource_2,
|
||||||
|
"vnf_virtual_link_desc_id": uuidsentinel.ext_vl_2,
|
||||||
|
"network_resource": {
|
||||||
|
"vim_connection_id": None,
|
||||||
|
"resource_id": uuidsentinel.ext_vl_resource_2,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Net",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"vnf_link_ports": [
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_3,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl2_link_port_1,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_3,
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_4,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl2_link_port_2,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_4,
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": uuidsentinel.vnf_link_port_5,
|
||||||
|
"resource_handle": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.vnf_vl2_link_port_3,
|
||||||
|
"vim_level_resource_type": "OS::Neutron::Port",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"cp_instance_id": uuidsentinel.cp_instance_5,
|
||||||
|
"deleted": False,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _get_vnfc_resource_info():
|
||||||
|
return [{
|
||||||
|
"id": uuidsentinel.vnfc_resource_1,
|
||||||
|
"vdu_id": "VDU1",
|
||||||
|
"compute_resource": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.uuid,
|
||||||
|
"vim_level_resource_type": "OS::Nova::Server",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"storage_resource_ids": [],
|
||||||
|
"vnfc_cp_info": [{
|
||||||
|
"id": uuidsentinel.cp_instance_1,
|
||||||
|
"cpd_id": "CP1",
|
||||||
|
"vnf_ext_cp_id": None,
|
||||||
|
"cp_protocol_info": [],
|
||||||
|
"vnf_link_port_id": uuidsentinel.vnf_link_port_1,
|
||||||
|
}, {
|
||||||
|
"id": uuidsentinel.cp_instance_2,
|
||||||
|
"cpd_id": "CP2",
|
||||||
|
"vnf_ext_cp_id": None,
|
||||||
|
"cp_protocol_info": [],
|
||||||
|
"vnf_link_port_id": uuidsentinel.vnf_link_port_2,
|
||||||
|
}],
|
||||||
|
"metadata": {},
|
||||||
|
}, {
|
||||||
|
"id": uuidsentinel.vnfc_resource_2,
|
||||||
|
"vdu_id": "VDU2",
|
||||||
|
"compute_resource": {
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": uuidsentinel.uuid,
|
||||||
|
"vim_level_resource_type": "OS::Nova::Server",
|
||||||
|
"deleted": False,
|
||||||
|
},
|
||||||
|
"storage_resource_ids": [],
|
||||||
|
"vnfc_cp_info": [{
|
||||||
|
"id": uuidsentinel.cp_instance_3,
|
||||||
|
"cpd_id": "CP3",
|
||||||
|
"vnf_ext_cp_id": None,
|
||||||
|
"cp_protocol_info": [],
|
||||||
|
"vnf_link_port_id": uuidsentinel.vnf_link_port_3,
|
||||||
|
}, {
|
||||||
|
"id": uuidsentinel.cp_instance_4,
|
||||||
|
"cpd_id": "CP4",
|
||||||
|
"vnf_ext_cp_id": None,
|
||||||
|
"cp_protocol_info": [],
|
||||||
|
"vnf_link_port_id": uuidsentinel.vnf_link_port_4,
|
||||||
|
}, {
|
||||||
|
"id": uuidsentinel.cp_instance_5,
|
||||||
|
"cpd_id": "CP5",
|
||||||
|
"vnf_ext_cp_id": None,
|
||||||
|
"cp_protocol_info": [],
|
||||||
|
"vnf_link_port_id": uuidsentinel.vnf_link_port_5,
|
||||||
|
}],
|
||||||
|
"metadata": {},
|
||||||
|
}]
|
||||||
|
|
||||||
|
vnf_info.instantiated_vnf_info = \
|
||||||
|
objects.InstantiatedVnfInfo.obj_from_primitive(
|
||||||
|
_get_instantiated_vnf_info_data(), None
|
||||||
|
)
|
||||||
|
return vnf_info.instantiated_vnf_info
|
||||||
|
|
||||||
|
|
||||||
|
def get_change_ext_conn_request():
|
||||||
|
change_ext_conn_req_body = {
|
||||||
|
"extVirtualLinks": [{
|
||||||
|
"id": uuidsentinel.ext_vl_1,
|
||||||
|
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||||
|
"resourceId": uuidsentinel.ext_vl_resource_3,
|
||||||
|
"extCps": [{
|
||||||
|
"cpdId": 'CP1',
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpInstanceId": uuidsentinel.uuid,
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": 'IP_OVER_ETHERNET',
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": ["10.0.0.1"],
|
||||||
|
"subnetId": uuidsentinel.uuid,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]}, {
|
||||||
|
"id": uuidsentinel.ext_vl_2,
|
||||||
|
"vimConnectionId": uuidsentinel.vim_connection_id,
|
||||||
|
"resourceId": uuidsentinel.ext_vl_resource_2,
|
||||||
|
"extCps": [{
|
||||||
|
"cpdId": 'CP3',
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpInstanceId": uuidsentinel.uuid,
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": 'IP_OVER_ETHERNET',
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": ["10.0.0.2"],
|
||||||
|
"subnetId": uuidsentinel.uuid,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]}, {
|
||||||
|
"cpdId": 'CP5',
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpInstanceId": uuidsentinel.uuid,
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": 'IP_OVER_ETHERNET',
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 1,
|
||||||
|
"subnetId": uuidsentinel.uuid,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"vimConnectionInfo": [{
|
||||||
|
"id": uuidsentinel.vim_connection_id,
|
||||||
|
"vimId": uuidsentinel.uuid,
|
||||||
|
"vimType": 'openstack',
|
||||||
|
"interfaceInfo": {"key1": 'value1', "key2": 'value2'},
|
||||||
|
"accessInfo": {"key1": 'value1', "key2": 'value2'},
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
|
||||||
|
return change_ext_conn_req_body
|
||||||
|
|
||||||
|
|
||||||
|
def get_change_ext_conn_request_obj():
|
||||||
|
"""Return ChangeExtConnRequest Object
|
||||||
|
|
||||||
|
obj_from_primitive() needs snake_case dictionary
|
||||||
|
"""
|
||||||
|
body = common_utils.convert_camelcase_to_snakecase(
|
||||||
|
get_change_ext_conn_request())
|
||||||
|
return objects.ChangeExtConnRequest.obj_from_primitive(
|
||||||
|
body, None)
|
||||||
|
|
|
@ -3019,3 +3019,435 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
||||||
vnf_data["software_version"] = vnf_data.pop("vnf_software_version")
|
vnf_data["software_version"] = vnf_data.pop("vnf_software_version")
|
||||||
vnf_data["descriptor_version"] = vnf_data.pop("vnfd_version")
|
vnf_data["descriptor_version"] = vnf_data.pop("vnfd_version")
|
||||||
return vnf_data
|
return vnf_data
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'.send_notification')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch.object(conductor_server.Conductor, "_get_grant_execute")
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_exec,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_send_notification,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 0}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
|
||||||
|
# Test condition settings.
|
||||||
|
mock_exec.return_value = False
|
||||||
|
|
||||||
|
self.conductor.change_ext_conn(
|
||||||
|
self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
mock_change_vnf_status.assert_called_with(self.context,
|
||||||
|
mock.ANY, (constants.ACTIVE,),
|
||||||
|
constants.PENDING_CHANGE_EXT_CONN)
|
||||||
|
mock_update_vnf_attributes.assert_called_with(self.context,
|
||||||
|
mock.ANY, mock.ANY, mock.ANY, (constants.ACTIVE,))
|
||||||
|
self.assertEqual(
|
||||||
|
mock_send_notification.call_args[0][1].get('operationState'),
|
||||||
|
'PROCESSING')
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'.send_notification')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
@mock.patch.object(conductor_server.Conductor, "_get_grant_execute")
|
||||||
|
@mock.patch.object(test_nfvo_client.GrantRequest, "grants")
|
||||||
|
def test_change_ext_conn_grant(
|
||||||
|
self,
|
||||||
|
mock_grants,
|
||||||
|
mock_exec,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_send_notification,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn):
|
||||||
|
cfg.CONF.set_override(
|
||||||
|
'base_url',
|
||||||
|
'http://127.0.0.1:9990/grant/v1/grants',
|
||||||
|
group='connect_grant')
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 0}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
vnf_virtual_link = (
|
||||||
|
vnf_instance.instantiated_vnf_info.vnf_virtual_link_resource_info)
|
||||||
|
|
||||||
|
# Test condition settings.
|
||||||
|
mock_exec.return_value = True
|
||||||
|
res_grant = dict()
|
||||||
|
res_grant['id'] = uuidsentinel.grant_id
|
||||||
|
res_grant['vnfInstanceId'] = vnf_instance.id
|
||||||
|
res_grant['vnfLcmOpOccId'] = vnf_lcm_op_occs_id
|
||||||
|
res_grant['updateResources'] = [
|
||||||
|
{
|
||||||
|
'resourceDefinitionId':
|
||||||
|
vnf_virtual_link[0].vnf_link_ports[0].id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'resourceDefinitionId':
|
||||||
|
vnf_virtual_link[0].vnf_link_ports[1].id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'resourceDefinitionId':
|
||||||
|
vnf_virtual_link[1].vnf_link_ports[0].id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'resourceDefinitionId':
|
||||||
|
vnf_virtual_link[1].vnf_link_ports[2].id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
mock_grants.return_value = MockResponse(json_data=res_grant)
|
||||||
|
|
||||||
|
self.conductor.change_ext_conn(
|
||||||
|
self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
mock_change_vnf_status.assert_called_with(self.context,
|
||||||
|
mock.ANY, (constants.ACTIVE,),
|
||||||
|
constants.PENDING_CHANGE_EXT_CONN)
|
||||||
|
mock_update_vnf_attributes.assert_called_with(self.context,
|
||||||
|
mock.ANY, mock.ANY, mock.ANY, (constants.ACTIVE,))
|
||||||
|
self.assertEqual(
|
||||||
|
mock_send_notification.call_args[0][1].get('operationState'),
|
||||||
|
'PROCESSING')
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'.send_notification')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch.object(conductor_server.Conductor, "_get_grant_execute")
|
||||||
|
@mock.patch.object(test_nfvo_client.GrantRequest, "grants")
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn_grant_exception_http_error(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_grants,
|
||||||
|
mock_exec,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_send_notification,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 0}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
|
||||||
|
# Test condition settings.
|
||||||
|
mock_exec.return_value = True
|
||||||
|
mock_grants.side_effect = (
|
||||||
|
requests.exceptions.HTTPError("MockException"))
|
||||||
|
|
||||||
|
self.assertRaises(requests.exceptions.HTTPError,
|
||||||
|
self.conductor.change_ext_conn,
|
||||||
|
self.context, vnf_instance, vnf_dict,
|
||||||
|
change_ext_conn_req, vnf_lcm_op_occs_id)
|
||||||
|
mock_change_vnf_status.assert_not_called()
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn.assert_not_called()
|
||||||
|
self.assertEqual(
|
||||||
|
mock_send_notification.call_args[0][1].get('operationState'),
|
||||||
|
'ROLLED_BACK')
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'.send_notification')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch.object(conductor_server.Conductor, "_get_grant_execute")
|
||||||
|
@mock.patch.object(test_nfvo_client.GrantRequest, "grants")
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn_grant_exception_validation_error(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_grants,
|
||||||
|
mock_exec,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_send_notification,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 0}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
|
||||||
|
# Test condition settings.
|
||||||
|
mock_exec.return_value = True
|
||||||
|
res_upd_resource = []
|
||||||
|
resource = {
|
||||||
|
'resourceDefinitionId': uuidsentinel.rsc_dummy,
|
||||||
|
'vimConnectionId': '1ffcd358-bee3-4bfb-bc3a-920db09f5da5',
|
||||||
|
}
|
||||||
|
res_upd_resource.append(resource)
|
||||||
|
res_grant = dict()
|
||||||
|
res_grant['id'] = uuidsentinel.grant_id
|
||||||
|
res_grant['vnfInstanceId'] = vnf_instance.id
|
||||||
|
res_grant['vnfLcmOpOccId'] = vnf_lcm_op_occs_id
|
||||||
|
res_grant['updateResources'] = []
|
||||||
|
res_grant['updateResources'].extend(res_upd_resource)
|
||||||
|
mock_grants.return_value = MockResponse(json_data=res_grant)
|
||||||
|
|
||||||
|
self.assertRaises(exceptions.ValidationError,
|
||||||
|
self.conductor.change_ext_conn,
|
||||||
|
self.context, vnf_instance, vnf_dict,
|
||||||
|
change_ext_conn_req, vnf_lcm_op_occs_id)
|
||||||
|
mock_change_vnf_status.assert_not_called()
|
||||||
|
mock_update_vnf_attributes.assert_not_called()
|
||||||
|
mock_update_instantiated_vnf_info_change_ext_conn.assert_not_called()
|
||||||
|
self.assertEqual(
|
||||||
|
mock_send_notification.call_args[0][1].get('operationState'),
|
||||||
|
'ROLLED_BACK')
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||||
|
'vnf_lcm_subscriptions_get')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._convert_desired_capacity')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn_failed_with_exception(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_log,
|
||||||
|
mock_des,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_vnf_lcm_subscriptions_get,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_update_vnf_info_change_ext_conn,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_change_vnf_status):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
mock_vnf_by_id.return_value = (
|
||||||
|
objects.VnfLcmOpOcc(context=self.context,
|
||||||
|
**lcm_op_occs_data))
|
||||||
|
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
vnf_dict = {"before_error_point": 0,
|
||||||
|
"current_error_point": 6}
|
||||||
|
m_vnf_lcm_subscriptions = (
|
||||||
|
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())])
|
||||||
|
mock_vnf_lcm_subscriptions_get.return_value = (
|
||||||
|
m_vnf_lcm_subscriptions)
|
||||||
|
mock_update_vnf_info_change_ext_conn.side_effect = Exception
|
||||||
|
self.conductor.change_ext_conn(
|
||||||
|
self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
mock_change_vnf_status.assert_called_with(self.context,
|
||||||
|
mock.ANY, mock.ANY, constants.ERROR, mock.ANY)
|
||||||
|
self.vnflcm_driver.change_ext_conn_vnf.assert_called_once_with(
|
||||||
|
self.context, vnf_instance, vnf_dict, change_ext_conn_req)
|
||||||
|
mock_update_vnf_info_change_ext_conn.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'.send_notification')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._change_ext_conn_grant')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn_retry_error_point_1(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_change_ext_conn_grant,
|
||||||
|
mock_update_vnf_info_change_ext_conn,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_send_notification):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 1}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
|
||||||
|
self.conductor.change_ext_conn(
|
||||||
|
self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
self.vnflcm_driver.change_ext_conn_vnf.assert_called_once_with(
|
||||||
|
self.context, vnf_instance, vnf_dict, change_ext_conn_req)
|
||||||
|
mock_change_vnf_status.assert_called_with(self.context,
|
||||||
|
mock.ANY, (constants.ACTIVE,),
|
||||||
|
constants.PENDING_CHANGE_EXT_CONN)
|
||||||
|
self.assertEqual(mock_change_ext_conn_grant.call_count, 0)
|
||||||
|
mock_update_vnf_attributes.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'send_notification')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
|
'_change_vnf_status')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_vnf_attributes')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._update_instantiated_vnf_info_change_ext_conn')
|
||||||
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
|
'._change_ext_conn_grant')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
|
def test_change_ext_conn_retry_error_point_7(
|
||||||
|
self,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_get_lock,
|
||||||
|
mock_save,
|
||||||
|
mock_change_ext_conn_grant,
|
||||||
|
mock_update_vnf_info_change_ext_conn,
|
||||||
|
mock_update_vnf_attributes,
|
||||||
|
mock_change_vnf_status,
|
||||||
|
mock_send_notification):
|
||||||
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
mock_vnf_by_id.return_value = objects.VnfLcmOpOcc(
|
||||||
|
context=self.context, **lcm_op_occs_data)
|
||||||
|
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
|
vnf_package_vnfd.vnfd_id)
|
||||||
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
|
**vnf_instance_data)
|
||||||
|
vnf_instance.create()
|
||||||
|
vnf_instance.instantiation_state = fields.VnfInstanceState.INSTANTIATED
|
||||||
|
vnf_instance.save()
|
||||||
|
vnf_instance.instantiated_vnf_info = fakes.get_instantiated_vnf_info()
|
||||||
|
vnf_dict = {"before_error_point": 7}
|
||||||
|
change_ext_conn_req = fakes.get_change_ext_conn_request_obj()
|
||||||
|
|
||||||
|
self.conductor.change_ext_conn(
|
||||||
|
self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req,
|
||||||
|
vnf_lcm_op_occs_id)
|
||||||
|
self.vnflcm_driver.change_ext_conn_vnf.assert_called_once_with(
|
||||||
|
self.context, vnf_instance, vnf_dict, change_ext_conn_req)
|
||||||
|
mock_change_vnf_status.assert_not_called()
|
||||||
|
self.assertEqual(mock_change_ext_conn_grant.call_count, 0)
|
||||||
|
mock_update_vnf_attributes.assert_called_once()
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from tacker import context
|
||||||
|
from tacker import objects
|
||||||
|
from tacker.tests.unit import base
|
||||||
|
from tacker.tests import uuidsentinel
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeExtConnRequestTestCase(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ChangeExtConnRequestTestCase, self).setUp()
|
||||||
|
self.context = context.get_admin_context()
|
||||||
|
|
||||||
|
def _get_change_ext_conn_request(self):
|
||||||
|
ext_vl_info = [{
|
||||||
|
"id": "external_network",
|
||||||
|
"vim_connection_id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"resource_id": "dc67ee99-e963-44e2-a152-f0fb492eae76",
|
||||||
|
"ext_cps": [{
|
||||||
|
"cpd_id": "CP1",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"mac_address": "fa:16:3e:0d:6f:71"},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP2",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"ipaddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixed_addresses": [
|
||||||
|
"10.0.0.1"],
|
||||||
|
"subnet_id":
|
||||||
|
"55f0fb3c-6a70-11eb-9439-0242ac130002"}]},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP3",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"ipaddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"num_dynamic_addresses": 1,
|
||||||
|
"subnet_id":
|
||||||
|
"3a7a37fc-6a92-11eb-9439-0242ac130002"}]},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP4",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}],
|
||||||
|
"link_port_id":
|
||||||
|
"413f4e46-21cf-41b1-be0f-de8d23f76cfe"}]}],
|
||||||
|
"ext_link_ports": [{
|
||||||
|
"id": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||||
|
"resource_handle": {
|
||||||
|
"resource_id": "67f7e772-0d31-4087-bf4c-2576fadcbdb7",
|
||||||
|
"vim_connection_id":
|
||||||
|
"6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vim_level_resource_type": "LINKPORT"}}], }]
|
||||||
|
|
||||||
|
vim_connection_info = [{
|
||||||
|
"id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vim_id": uuidsentinel.vim_id,
|
||||||
|
"vim_type": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||||
|
"interface_info": {
|
||||||
|
"endpoint": "endpoint_value"},
|
||||||
|
"access_info": {
|
||||||
|
"username": "username_value",
|
||||||
|
"password": "password_value",
|
||||||
|
"region": "region_value",
|
||||||
|
"tenant": "tenant_value"}}]
|
||||||
|
|
||||||
|
change_ext_conn_data = {
|
||||||
|
'ext_virtual_links': ext_vl_info,
|
||||||
|
'vim_connection_info': vim_connection_info,
|
||||||
|
'additional_params': {'key1': 'value1'}}
|
||||||
|
|
||||||
|
return change_ext_conn_data
|
||||||
|
|
||||||
|
def test_obj_from_primitive(self):
|
||||||
|
change_ext_conn_data = self._get_change_ext_conn_request()
|
||||||
|
change_ext_conn_req = objects.ChangeExtConnRequest.obj_from_primitive(
|
||||||
|
copy.deepcopy(change_ext_conn_data), self.context)
|
||||||
|
self._check_change_ext_conn_req(change_ext_conn_req,
|
||||||
|
change_ext_conn_data)
|
||||||
|
|
||||||
|
def _check_change_ext_conn_req(self, obj, data):
|
||||||
|
|
||||||
|
def _check_vim_connection_info(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VimConnectionInfo)
|
||||||
|
|
||||||
|
def _check_external_virtual_links(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.ExtVirtualLinkData)
|
||||||
|
self.assertEqual(obj.id, data.get('id'))
|
||||||
|
self.assertEqual(obj.vim_connection_id,
|
||||||
|
data.get('vim_connection_id'))
|
||||||
|
self.assertEqual(obj.resource_id,
|
||||||
|
data.get('resource_id'))
|
||||||
|
_check_ext_cps(obj.ext_cps,
|
||||||
|
data.get('ext_cps', []))
|
||||||
|
_check_ext_link_ports(obj.ext_link_ports,
|
||||||
|
data.get('ext_link_ports', []))
|
||||||
|
|
||||||
|
def _check_ext_cps(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VnfExtCpData)
|
||||||
|
self.assertEqual(obj.cpd_id, data.get('cpd_id'))
|
||||||
|
_check_ext_cp_config(obj.cp_config,
|
||||||
|
data.get('cp_config', []))
|
||||||
|
|
||||||
|
def _check_ext_cp_config(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VnfExtCpConfig)
|
||||||
|
self.assertEqual(obj.cp_instance_id,
|
||||||
|
data.get('cp_instance_id'))
|
||||||
|
self.assertEqual(obj.link_port_id,
|
||||||
|
data.get('link_port_id'))
|
||||||
|
_check_cp_protocol_data(obj.cp_protocol_data,
|
||||||
|
data.get('cp_protocol_data', []))
|
||||||
|
|
||||||
|
def _check_cp_protocol_data(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.CpProtocolData)
|
||||||
|
self.assertEqual(obj.layer_protocol,
|
||||||
|
data.get('layer_protocol'))
|
||||||
|
if obj.ip_over_ethernet or data.get('ip_over_ethernet', None):
|
||||||
|
_check_ip_over_ethernet(obj.ip_over_ethernet,
|
||||||
|
data.get('ip_over_ethernet', None))
|
||||||
|
|
||||||
|
def _check_ip_over_ethernet(obj, data):
|
||||||
|
self.assertIsInstance(obj, objects.IpOverEthernetAddressData)
|
||||||
|
self.assertEqual(obj.mac_address, data.get('mac_address'))
|
||||||
|
_check_ip_addresses(obj.ip_addresses,
|
||||||
|
data.get('ip_addressest', []))
|
||||||
|
|
||||||
|
def _check_ip_addresses(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.IpAddressReq)
|
||||||
|
self.assertEqual(obj.type, data.get('type'))
|
||||||
|
self.assertEqual(obj.subnet_id, data.get('subnet_id'))
|
||||||
|
self.assertEqual(obj.num_dynamic_addresses,
|
||||||
|
data.get('num_dynamic_addresses'))
|
||||||
|
|
||||||
|
def _check_ext_link_ports(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.ExtLinkPortData)
|
||||||
|
self.assertEqual(obj.id, data.get('id'))
|
||||||
|
self.assertIsInstance(obj.resource_handle,
|
||||||
|
objects.ResourceHandle)
|
||||||
|
|
||||||
|
self.assertIsInstance(obj, objects.ChangeExtConnRequest)
|
||||||
|
_check_external_virtual_links(obj.ext_virtual_links,
|
||||||
|
data.get('ext_virtual_links'))
|
||||||
|
_check_vim_connection_info(obj.vim_connection_info,
|
||||||
|
data.get('vim_connection_info'))
|
|
@ -0,0 +1,251 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from tacker import context
|
||||||
|
from tacker import objects
|
||||||
|
from tacker.tests.unit import base
|
||||||
|
from tacker.tests import uuidsentinel
|
||||||
|
|
||||||
|
|
||||||
|
class GrantTestCase(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(GrantTestCase, self).setUp()
|
||||||
|
self.context = context.get_admin_context()
|
||||||
|
|
||||||
|
def _get_grant_data(self):
|
||||||
|
vim_connection_info = [{
|
||||||
|
"id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vim_id": uuidsentinel.vim_id,
|
||||||
|
"vim_type": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||||
|
"interface_info": {
|
||||||
|
"endpoint": "endpoint_value"},
|
||||||
|
"access_info": {
|
||||||
|
"username": "username_value",
|
||||||
|
"password": "password_value",
|
||||||
|
"region": "region_value",
|
||||||
|
"tenant": "tenant_value"}}]
|
||||||
|
|
||||||
|
grant_info = [{
|
||||||
|
"resource_definition_id":
|
||||||
|
"ff150558-6f45-11eb-9439-0242ac130002"}, {
|
||||||
|
"resource_definition_id":
|
||||||
|
"030df048-6f46-11eb-9439-0242ac130002"}]
|
||||||
|
|
||||||
|
vim_compute_resource_flavour = [{
|
||||||
|
"vim_connection_id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vnfd_virtual_compute_desc_id":
|
||||||
|
"a813a1ea-6f47-11eb-9439-0242ac130002",
|
||||||
|
"vim_flavour_id": "c924aa12-b69d-41ee-91dd-7a26d92e6147"}]
|
||||||
|
|
||||||
|
vim_software_image = [{
|
||||||
|
"vim_connection_id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vnfd_software_image_id": "49597d31-0aad-4c46-865d-ed7e60b3edc7",
|
||||||
|
"vim_software_image_id": "93738ce0-3ddb-4c13-9900-62b757561edd"}]
|
||||||
|
|
||||||
|
ext_vl_info = [{
|
||||||
|
"id": "external_network",
|
||||||
|
"vim_connection_id": "6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"resource_id": "dc67ee99-e963-44e2-a152-f0fb492eae76",
|
||||||
|
"ext_cps": [{
|
||||||
|
"cpd_id": "CP1",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"mac_address": "fa:16:3e:0d:6f:71"},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP2",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"ipaddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixed_addresses": [
|
||||||
|
"10.0.0.1"],
|
||||||
|
"subnet_id":
|
||||||
|
"55f0fb3c-6a70-11eb-9439-0242ac130002"}]},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP3",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"ipaddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"num_dynamic_addresses": 1,
|
||||||
|
"subnet_id":
|
||||||
|
"3a7a37fc-6a92-11eb-9439-0242ac130002"}]},
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}]}]}, {
|
||||||
|
"cpd_id": "CP4",
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET"}],
|
||||||
|
"link_port_id":
|
||||||
|
"413f4e46-21cf-41b1-be0f-de8d23f76cfe"}]}],
|
||||||
|
"ext_link_ports": [{
|
||||||
|
"id": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||||
|
"resource_handle": {
|
||||||
|
"resource_id": "67f7e772-0d31-4087-bf4c-2576fadcbdb7",
|
||||||
|
"vim_connection_id":
|
||||||
|
"6b0ff598-60d6-49b4-a907-a1111de52d92",
|
||||||
|
"vim_level_resource_type": "LINKPORT"}}], }]
|
||||||
|
|
||||||
|
grant_data = {
|
||||||
|
"id": "3affab40-6f28-11eb-9439-0242ac130002",
|
||||||
|
"vnf_instance_id": "4d62c7c2-6f28-11eb-9439-0242ac130002",
|
||||||
|
"vnf_lcm_op_occ_id": "6e426236-6f28-11eb-9439-0242ac130002",
|
||||||
|
"vim_connections": vim_connection_info,
|
||||||
|
"update_resources": grant_info,
|
||||||
|
"vim_assets": {
|
||||||
|
"compute_resource_flavours": vim_compute_resource_flavour,
|
||||||
|
"software_images": vim_software_image,
|
||||||
|
},
|
||||||
|
"ext_virtual_links": ext_vl_info,
|
||||||
|
"additional_params": {"key1": "value1"},
|
||||||
|
"_links": {
|
||||||
|
"self": {"href": ""},
|
||||||
|
"vnf_lcm_op_occ": {"href": ""},
|
||||||
|
"vnf_instance": {"href": ""},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grant_data
|
||||||
|
|
||||||
|
def test_obj_from_primitive(self):
|
||||||
|
grant_data = self._get_grant_data()
|
||||||
|
grant = objects.Grant.obj_from_primitive(
|
||||||
|
copy.deepcopy(grant_data), self.context)
|
||||||
|
self._check_grant(grant, grant_data)
|
||||||
|
|
||||||
|
def _check_grant(self, obj, data):
|
||||||
|
|
||||||
|
def _check_vim_connection_info(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VimConnectionInfo)
|
||||||
|
|
||||||
|
def _check_update_resources(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.GrantInfo)
|
||||||
|
|
||||||
|
def _check_vim_assets(obj, data):
|
||||||
|
self.assertIsInstance(obj, objects.VimAssets)
|
||||||
|
_check_compute_resource_flavours(
|
||||||
|
obj.compute_resource_flavours,
|
||||||
|
data.get('compute_resource_flavours', []))
|
||||||
|
_check_software_images(obj.software_images,
|
||||||
|
data.get('software_images', []))
|
||||||
|
|
||||||
|
def _check_compute_resource_flavours(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj,
|
||||||
|
objects.VimComputeResourceFlavour)
|
||||||
|
self.assertEqual(obj.vim_connection_id,
|
||||||
|
data.get('vim_connection_id'))
|
||||||
|
self.assertEqual(obj.vnfd_virtual_compute_desc_id,
|
||||||
|
data.get('vnfd_virtual_compute_desc_id'))
|
||||||
|
self.assertEqual(obj.vim_flavour_id,
|
||||||
|
data.get('vim_flavour_id'))
|
||||||
|
|
||||||
|
def _check_software_images(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VimSoftwareImage)
|
||||||
|
self.assertEqual(obj.vim_connection_id,
|
||||||
|
data.get('vim_connection_id'))
|
||||||
|
self.assertEqual(obj.vnfd_software_image_id,
|
||||||
|
data.get('vnfd_software_image_id'))
|
||||||
|
self.assertEqual(obj.vim_software_image_id,
|
||||||
|
data.get('vim_software_image_id'))
|
||||||
|
|
||||||
|
def _check_external_virtual_links(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.ExtVirtualLinkData)
|
||||||
|
self.assertEqual(obj.id, data.get('id'))
|
||||||
|
self.assertEqual(obj.vim_connection_id,
|
||||||
|
data.get('vim_connection_id'))
|
||||||
|
self.assertEqual(obj.resource_id,
|
||||||
|
data.get('resource_id'))
|
||||||
|
_check_ext_cps(obj.ext_cps,
|
||||||
|
data.get('ext_cps', []))
|
||||||
|
_check_ext_link_ports(obj.ext_link_ports,
|
||||||
|
data.get('ext_link_ports', []))
|
||||||
|
|
||||||
|
def _check_ext_cps(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VnfExtCpData)
|
||||||
|
self.assertEqual(obj.cpd_id, data.get('cpd_id'))
|
||||||
|
_check_ext_cp_config(obj.cp_config,
|
||||||
|
data.get('cp_config', []))
|
||||||
|
|
||||||
|
def _check_ext_cp_config(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.VnfExtCpConfig)
|
||||||
|
self.assertEqual(obj.cp_instance_id,
|
||||||
|
data.get('cp_instance_id'))
|
||||||
|
self.assertEqual(obj.link_port_id,
|
||||||
|
data.get('link_port_id'))
|
||||||
|
_check_cp_protocol_data(obj.cp_protocol_data,
|
||||||
|
data.get('cp_protocol_data', []))
|
||||||
|
|
||||||
|
def _check_cp_protocol_data(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.CpProtocolData)
|
||||||
|
self.assertEqual(obj.layer_protocol,
|
||||||
|
data.get('layer_protocol'))
|
||||||
|
if obj.ip_over_ethernet or data.get('ip_over_ethernet', None):
|
||||||
|
_check_ip_over_ethernet(obj.ip_over_ethernet,
|
||||||
|
data.get('ip_over_ethernet', None))
|
||||||
|
|
||||||
|
def _check_ip_over_ethernet(obj, data):
|
||||||
|
self.assertIsInstance(obj, objects.IpOverEthernetAddressData)
|
||||||
|
self.assertEqual(obj.mac_address, data.get('mac_address'))
|
||||||
|
_check_ip_addresses(obj.ip_addresses,
|
||||||
|
data.get('ip_addresses', []))
|
||||||
|
|
||||||
|
def _check_ip_addresses(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.IpAddressReq)
|
||||||
|
self.assertEqual(obj.type, data.get('type'))
|
||||||
|
self.assertEqual(obj.subnet_id, data.get('subnet_id'))
|
||||||
|
self.assertEqual(obj.num_dynamic_addresses,
|
||||||
|
data.get('num_dynamic_addresses'))
|
||||||
|
|
||||||
|
def _check_ext_link_ports(_obj, _data):
|
||||||
|
self.assertEqual(len(_obj), len(_data))
|
||||||
|
for obj, data in zip(_obj, _data):
|
||||||
|
self.assertIsInstance(obj, objects.ExtLinkPortData)
|
||||||
|
self.assertEqual(obj.id, data.get('id'))
|
||||||
|
self.assertIsInstance(obj.resource_handle,
|
||||||
|
objects.ResourceHandle)
|
||||||
|
|
||||||
|
self.assertIsInstance(obj, objects.Grant)
|
||||||
|
self.assertEqual(obj.id, data.get('id'))
|
||||||
|
self.assertEqual(obj.vnf_instance_id, data.get('vnf_instance_id'))
|
||||||
|
self.assertEqual(obj.vnf_lcm_op_occ_id, data.get('vnf_lcm_op_occ_id'))
|
||||||
|
_check_vim_connection_info(obj.vim_connections,
|
||||||
|
data.get('vim_connections'))
|
||||||
|
_check_update_resources(obj.update_resources,
|
||||||
|
data.get('update_resources'))
|
||||||
|
_check_vim_assets(obj.vim_assets,
|
||||||
|
data.get('vim_assets', None))
|
||||||
|
_check_external_virtual_links(obj.ext_virtual_links,
|
||||||
|
data.get('ext_virtual_links'))
|
|
@ -20,9 +20,11 @@ import os
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from tacker.api.vnflcm.v1.router import VnflcmAPIRouter
|
from tacker.api.vnflcm.v1.router import VnflcmAPIRouter
|
||||||
|
from tacker.common import utils
|
||||||
from tacker import context
|
from tacker import context
|
||||||
from tacker.db.db_sqlalchemy import models
|
from tacker.db.db_sqlalchemy import models
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
|
from tacker.objects.change_ext_conn_req import ChangeExtConnRequest
|
||||||
from tacker.objects import fields
|
from tacker.objects import fields
|
||||||
from tacker.objects.instantiate_vnf_req import ExtManagedVirtualLinkData
|
from tacker.objects.instantiate_vnf_req import ExtManagedVirtualLinkData
|
||||||
from tacker.objects.instantiate_vnf_req import ExtVirtualLinkData
|
from tacker.objects.instantiate_vnf_req import ExtVirtualLinkData
|
||||||
|
@ -229,7 +231,10 @@ def _instantiated_vnf_links(vnf_instance_id):
|
||||||
"terminate": {"href": "/vnflcm/v1/vnf_instances/%s/terminate" %
|
"terminate": {"href": "/vnflcm/v1/vnf_instances/%s/terminate" %
|
||||||
vnf_instance_id},
|
vnf_instance_id},
|
||||||
"heal": {"href": "/vnflcm/v1/vnf_instances/%s/heal" %
|
"heal": {"href": "/vnflcm/v1/vnf_instances/%s/heal" %
|
||||||
vnf_instance_id}}
|
vnf_instance_id},
|
||||||
|
"changeExtConn": {"href":
|
||||||
|
"/vnflcm/v1/vnf_instances/%s/change_ext_conn" %
|
||||||
|
vnf_instance_id}}
|
||||||
|
|
||||||
return links
|
return links
|
||||||
|
|
||||||
|
@ -1598,3 +1603,62 @@ def return_vnf_lcm_opoccs_list():
|
||||||
obj = objects.VnfLcmOpOcc(**vnf_lcm_op_occs)
|
obj = objects.VnfLcmOpOcc(**vnf_lcm_op_occs)
|
||||||
|
|
||||||
return [obj]
|
return [obj]
|
||||||
|
|
||||||
|
|
||||||
|
def get_change_ext_conn_request_body():
|
||||||
|
change_ext_conn_req_body = {
|
||||||
|
"extVirtualLinks": [{
|
||||||
|
"id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa',
|
||||||
|
"vimConnectionId": '2b3beeff-d4a1-4dc7-a1f8-066f92cfcb75',
|
||||||
|
"resourceId": 'e08f5e67-55de-4c4a-815b-cf3f1e2bae04',
|
||||||
|
"extCps": [{
|
||||||
|
"cpdId": 'VDU2_CP2',
|
||||||
|
"cpConfig": [{
|
||||||
|
"cpInstanceId": '924d0ea7-786d-468b-bf45-65bfd483ee79',
|
||||||
|
"linkPortId": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa',
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": 'IP_OVER_ETHERNET',
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"macAddress":
|
||||||
|
'fa:16:3e:11:11:11',
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": ["22.22.1.20"],
|
||||||
|
"subnetId":
|
||||||
|
'497b7a75-6c10-4a74-85fa-83d498da2501'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"extLinkPorts": [{
|
||||||
|
"id": 'decd78d2-993c-4112-9a8f-1ad54cade4d7',
|
||||||
|
"resourceHandle": {
|
||||||
|
"resourceId": 'cb602960-05ee-4e03-8fe2-ea0b64e08332',
|
||||||
|
"vimConnectionId": '2b3beeff-d4a1-4dc7-a1f8-066f92cfcb75',
|
||||||
|
"vimLevelResourceType":
|
||||||
|
'f8c35bd0-4d67-4436-9f11-14b8a84c92aa',
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"vimConnectionInfo": [{
|
||||||
|
"id": '2b3beeff-d4a1-4dc7-a1f8-066f92cfcb75',
|
||||||
|
"vimId": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa',
|
||||||
|
"vimType": 'openstack',
|
||||||
|
"interfaceInfo": {"key1": 'value1', "key2": 'value2'},
|
||||||
|
"accessInfo": {"key1": 'value1', "key2": 'value2'}
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
return change_ext_conn_req_body
|
||||||
|
|
||||||
|
|
||||||
|
def get_change_ext_conn_request_obj():
|
||||||
|
"""Return ChangeExtConnRequest Object
|
||||||
|
|
||||||
|
obj_from_primitive() needs snake_case dictionary
|
||||||
|
"""
|
||||||
|
body = utils.convert_camelcase_to_snakecase(
|
||||||
|
get_change_ext_conn_request_body())
|
||||||
|
return ChangeExtConnRequest.obj_from_primitive(
|
||||||
|
body, context)
|
||||||
|
|
|
@ -3554,3 +3554,152 @@ class TestController(base.TestCase):
|
||||||
|
|
||||||
mock_lcm_get_by_id.assert_called_once()
|
mock_lcm_get_by_id.assert_called_once()
|
||||||
mock_vnf_get_by_id.assert_called_once()
|
mock_vnf_get_by_id.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM':
|
||||||
|
test_nfvo_plugin.FakeVNFMPlugin()})
|
||||||
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
|
'VnfLcmController._notification_process')
|
||||||
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
|
'VnfLcmController._get_vnf')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "change_ext_conn")
|
||||||
|
def test_change_ext_conn(self, mock_rpc, mock_save,
|
||||||
|
mock_vnf_by_id, mock_get_vnf,
|
||||||
|
mock_notification_process,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
vnf_instance_obj = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||||
|
mock_get_vnf.return_value = \
|
||||||
|
self._get_dummy_vnf(vnf_id=vnf_instance_obj.id, status='ACTIVE')
|
||||||
|
|
||||||
|
body = fakes.get_change_ext_conn_request_body()
|
||||||
|
req = fake_request.HTTPRequest.blank(
|
||||||
|
'/vnf_instances/%s/change_ext_conn' % uuidsentinel.vnf_instance_id)
|
||||||
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.method = 'POST'
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.ACCEPTED, resp.status_code)
|
||||||
|
mock_rpc.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM':
|
||||||
|
test_nfvo_plugin.FakeVNFMPlugin()})
|
||||||
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
|
'VnfLcmController._get_vnf')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||||
|
def test_change_ext_conn_incorrect_instantiated_state(
|
||||||
|
self, mock_vnf_by_id, mock_get_vnf,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
vnf_instance_obj = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.NOT_INSTANTIATED)
|
||||||
|
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||||
|
|
||||||
|
body = fakes.get_change_ext_conn_request_body()
|
||||||
|
req = fake_request.HTTPRequest.blank(
|
||||||
|
'/vnf_instances/%s/change_ext_conn' % uuidsentinel.vnf_instance_id)
|
||||||
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.method = 'POST'
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||||
|
expected_msg = ("VNF is not instantiated")
|
||||||
|
self.assertEqual(expected_msg, resp.json['detail'])
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM':
|
||||||
|
test_nfvo_plugin.FakeVNFMPlugin()})
|
||||||
|
@ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH', 'GET')
|
||||||
|
def test_change_ext_conn_invalid_http_method(self, method,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
body = {}
|
||||||
|
req = fake_request.HTTPRequest.blank(
|
||||||
|
'/vnf_instances/%s/change_ext_conn' % uuidsentinel.vnf_instance_id)
|
||||||
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.method = method
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM':
|
||||||
|
test_nfvo_plugin.FakeVNFMPlugin()})
|
||||||
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
|
'VnfLcmController._notification_process')
|
||||||
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
|
'VnfLcmController._get_vnf')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "change_ext_conn")
|
||||||
|
@ddt.data(
|
||||||
|
{
|
||||||
|
"type": "IPV4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IPV4",
|
||||||
|
"fixedAddresses": ["22.22.1.20"],
|
||||||
|
"numDynamicAddresses": 1,
|
||||||
|
"subnetId": '497b7a75-6c10-4a74-85fa-83d498da2501',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 0,
|
||||||
|
"subnetId": '497b7a75-6c10-4a74-85fa-83d498da2501',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_change_ext_conn_with_invalid_requests(
|
||||||
|
self,
|
||||||
|
ip_address,
|
||||||
|
mock_rpc,
|
||||||
|
mock_save,
|
||||||
|
mock_vnf_by_id,
|
||||||
|
mock_get_vnf,
|
||||||
|
mock_notification_process,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
vnf_instance_obj = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||||
|
mock_get_vnf.return_value = \
|
||||||
|
self._get_dummy_vnf(vnf_id=vnf_instance_obj.id, status='ACTIVE')
|
||||||
|
|
||||||
|
body = fakes.get_change_ext_conn_request_body()
|
||||||
|
body['extVirtualLinks'][0]['extCps'][0]['cpConfig'][0][
|
||||||
|
'cpProtocolData'][0]['ipOverEthernet'][
|
||||||
|
'ipAddresses'] = [ip_address]
|
||||||
|
req = fake_request.HTTPRequest.blank(
|
||||||
|
'/vnf_instances/%s/change_ext_conn' % uuidsentinel.vnf_instance_id)
|
||||||
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.method = 'POST'
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
resp.status_code, http_client.BAD_REQUEST)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM':
|
||||||
|
test_nfvo_plugin.FakeVNFMPlugin()})
|
||||||
|
def test_change_ext_conn_with_invalid_uuid(self, mock_get_service_plugins):
|
||||||
|
body = fakes.get_change_ext_conn_request_body()
|
||||||
|
req = fake_request.HTTPRequest.blank(
|
||||||
|
'/vnf_instances/%s/change_ext_conn' % constants.INVALID_UUID)
|
||||||
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.method = 'POST'
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||||
|
self.assertEqual(
|
||||||
|
"Can not find requested vnf: %s" % constants.INVALID_UUID,
|
||||||
|
resp.json['itemNotFound']['message'])
|
||||||
|
|
|
@ -136,6 +136,14 @@ class FakeDriverManager(mock.Mock):
|
||||||
raise InfraDriverException("post_heal_vnf failed")
|
raise InfraDriverException("post_heal_vnf failed")
|
||||||
if 'get_rollback_ids' in args:
|
if 'get_rollback_ids' in args:
|
||||||
return [], [], ""
|
return [], [], ""
|
||||||
|
if 'change_ext_conn_vnf' in args:
|
||||||
|
if self.fail_method_name and \
|
||||||
|
self.fail_method_name == 'change_ext_conn_vnf':
|
||||||
|
raise InfraDriverException("change_ext_conn_vnf failed")
|
||||||
|
elif 'change_ext_conn_vnf_wait' in args:
|
||||||
|
if self.fail_method_name and \
|
||||||
|
self.fail_method_name == 'change_ext_conn_vnf_wait':
|
||||||
|
raise InfraDriverException("change_ext_conn_vnf_wait failed")
|
||||||
|
|
||||||
|
|
||||||
class FakeVimClient(mock.Mock):
|
class FakeVimClient(mock.Mock):
|
||||||
|
@ -2900,3 +2908,348 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
||||||
vnf_instance,
|
vnf_instance,
|
||||||
operation_params)
|
operation_params)
|
||||||
self.assertEqual(1, mock_lcm_save.call_count)
|
self.assertEqual(1, mock_lcm_save.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf(self, mock_vnf_interfaces, mock_vnfd_dict,
|
||||||
|
mock_log, mock_save, mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 0, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
||||||
|
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_fail(self, mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict, mock_log, mock_save, mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 0, 'grant': None}
|
||||||
|
|
||||||
|
self._mock_vnf_manager(fail_method_name='change_ext_conn_vnf')
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
self.assertRaises(exceptions.VnfChangeExtConnFailed,
|
||||||
|
driver.change_ext_conn_vnf, self.context, vnf_instance,
|
||||||
|
vnf_dict, change_ext_conn_vnf_req)
|
||||||
|
self.assertEqual(2, self._vnf_manager.invoke.call_count)
|
||||||
|
|
||||||
|
self.assertEqual(fields.VnfInstanceTaskState.ERROR,
|
||||||
|
vnf_instance.task_state)
|
||||||
|
expected_msg = ("Failed to change external connectivity "
|
||||||
|
"vnf %(id)s in infra driver. "
|
||||||
|
"Error: %(error)s")
|
||||||
|
mock_log.error.assert_called_with(expected_msg,
|
||||||
|
{'id': vnf_instance.id, 'error': 'change_ext_conn_vnf failed'})
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_wait_fail(self, mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict, mock_log, mock_save, mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 0, 'grant': None}
|
||||||
|
|
||||||
|
vnf_instance.instantiated_vnf_info.instance_id =\
|
||||||
|
uuidsentinel.instance_id
|
||||||
|
self._mock_vnf_manager(fail_method_name='change_ext_conn_vnf_wait')
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
self.assertRaises(exceptions.VnfChangeExtConnWaitFailed,
|
||||||
|
driver.change_ext_conn_vnf, self.context, vnf_instance,
|
||||||
|
vnf_dict, change_ext_conn_vnf_req)
|
||||||
|
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
fields.VnfInstanceTaskState.ERROR,
|
||||||
|
vnf_instance.task_state)
|
||||||
|
expected_msg = ('Failed to update vnf %(id)s resources for '
|
||||||
|
'instance %(instance)s. Error: %(error)s')
|
||||||
|
mock_log.error.assert_called_with(expected_msg,
|
||||||
|
{'id': vnf_instance.id,
|
||||||
|
'instance': vnf_instance.instantiated_vnf_info.instance_id,
|
||||||
|
'error': 'change_ext_conn_vnf_wait failed'})
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_retry_error_point_2(
|
||||||
|
self,
|
||||||
|
mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_log,
|
||||||
|
mock_save,
|
||||||
|
mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 2, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
|
||||||
|
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_retry_error_point_3(
|
||||||
|
self,
|
||||||
|
mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_log,
|
||||||
|
mock_save,
|
||||||
|
mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 3, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
|
||||||
|
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_retry_error_point_4(
|
||||||
|
self,
|
||||||
|
mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_log,
|
||||||
|
mock_save,
|
||||||
|
mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 4, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
|
||||||
|
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_retry_error_point_5(
|
||||||
|
self,
|
||||||
|
mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_log,
|
||||||
|
mock_save,
|
||||||
|
mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 5, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
|
||||||
|
self.assertEqual(1, self._vnf_manager.invoke.call_count)
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
||||||
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
|
@mock.patch.object(VnfLcmDriver,
|
||||||
|
'_init_mgmt_driver_hash')
|
||||||
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
|
@mock.patch('tacker.vnflcm.utils._get_vnfd_dict')
|
||||||
|
@mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.'
|
||||||
|
'_load_vnf_interface')
|
||||||
|
def test_change_ext_conn_vnf_retry_error_point_6(
|
||||||
|
self,
|
||||||
|
mock_vnf_interfaces,
|
||||||
|
mock_vnfd_dict,
|
||||||
|
mock_log,
|
||||||
|
mock_save,
|
||||||
|
mock_init_hash,
|
||||||
|
mock_get_service_plugins):
|
||||||
|
mock_init_hash.return_value = {
|
||||||
|
"vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859"
|
||||||
|
"b18d663b127100eb72b19eecd7ed51"
|
||||||
|
}
|
||||||
|
mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces()
|
||||||
|
change_ext_conn_vnf_req = objects.ChangeExtConnRequest(
|
||||||
|
vim_connection_info=[],
|
||||||
|
ext_virtual_links=[],
|
||||||
|
additional_params={})
|
||||||
|
|
||||||
|
vnf_instance = fakes.return_vnf_instance(
|
||||||
|
fields.VnfInstanceState.INSTANTIATED)
|
||||||
|
vnf_dict = {'before_error_point': 6, 'grant': None}
|
||||||
|
self._mock_vnf_manager()
|
||||||
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
driver.change_ext_conn_vnf(self.context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_vnf_req)
|
||||||
|
|
||||||
|
self.assertEqual(1, self._vnf_manager.invoke.call_count)
|
||||||
|
self.assertEqual(None, vnf_instance.task_state)
|
||||||
|
expected_msg = ("Request received for changing external "
|
||||||
|
"connectivity vnf '%s' is completed successfully")
|
||||||
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
|
vnf_instance.id)
|
||||||
|
|
|
@ -220,16 +220,84 @@ def get_vnfc_resource_info(vdu_id="VDU1", storage_resource_ids=None,
|
||||||
return vnfc_resource_info
|
return vnfc_resource_info
|
||||||
|
|
||||||
|
|
||||||
|
def _get_ext_link_port(ext_vl_port_id, cp_instance_id,
|
||||||
|
set_resource_id=False):
|
||||||
|
if set_resource_id:
|
||||||
|
resource_id = uuidsentinel.ext_virtual_link_port_resource_id
|
||||||
|
else:
|
||||||
|
resource_id = ""
|
||||||
|
|
||||||
|
resource_handle = objects.ResourceHandle(
|
||||||
|
resource_id=resource_id,
|
||||||
|
vim_level_resource_type="OS::Neutron::Port")
|
||||||
|
|
||||||
|
ext_vl_port = objects.ExtLinkPortInfo(
|
||||||
|
id=ext_vl_port_id, cp_instance_id=cp_instance_id,
|
||||||
|
resource_handle=resource_handle)
|
||||||
|
|
||||||
|
return ext_vl_port
|
||||||
|
|
||||||
|
|
||||||
|
def get_ext_virtual_link_info(ext_virtual_link_id, desc_id="externalVL1",
|
||||||
|
set_resource_id=True):
|
||||||
|
|
||||||
|
network_resource = objects.ResourceHandle(
|
||||||
|
resource_id=uuidsentinel.virtual_link_resource_id,
|
||||||
|
vim_level_resource_type="OS::Neutron::Network")
|
||||||
|
|
||||||
|
ext_vl_link_port = _get_ext_link_port(
|
||||||
|
uuidsentinel.ext_vl_port_id,
|
||||||
|
cp_instance_id=uuidsentinel.cp_instance_id,
|
||||||
|
set_resource_id=set_resource_id)
|
||||||
|
|
||||||
|
ext_vl_info = objects.ExtVirtualLinkInfo(
|
||||||
|
id=uuidsentinel.ext_virtual_link_id,
|
||||||
|
resource_handle=network_resource,
|
||||||
|
ext_link_ports=[ext_vl_link_port])
|
||||||
|
|
||||||
|
return ext_vl_info
|
||||||
|
|
||||||
|
|
||||||
|
def get_ext_cp_info(ext_cp_id, cpd_id='VDU1_CP1', ip_addresses=[]):
|
||||||
|
|
||||||
|
ip_over_ethernet = objects.IpOverEthernetAddressInfo(
|
||||||
|
ip_addresses=ip_addresses)
|
||||||
|
|
||||||
|
cp_protocol_info = objects.CpProtocolInfo(
|
||||||
|
layer_protocol="IP_OVER_ETHERNET",
|
||||||
|
ip_over_ethernet=ip_over_ethernet)
|
||||||
|
|
||||||
|
ext_cp_info = objects.VnfExtCpInfo(
|
||||||
|
id=ext_cp_id,
|
||||||
|
cpd_id=cpd_id,
|
||||||
|
cp_protocol_info=[cp_protocol_info])
|
||||||
|
|
||||||
|
return ext_cp_info
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip_address(ip_type='IPV4', subnet_id=None, is_dynamic=False,
|
||||||
|
addresses=[]):
|
||||||
|
ip_address = objects.IpAddress(type=ip_type,
|
||||||
|
subnet_id=subnet_id,
|
||||||
|
is_dynamic=is_dynamic,
|
||||||
|
addresses=addresses)
|
||||||
|
return ip_address
|
||||||
|
|
||||||
|
|
||||||
def get_vnf_instantiated_info(flavour_id='simple',
|
def get_vnf_instantiated_info(flavour_id='simple',
|
||||||
instantiation_level_id=None, vnfc_resource_info=None,
|
instantiation_level_id=None, vnfc_resource_info=None,
|
||||||
virtual_storage_resource_info=None,
|
virtual_storage_resource_info=None,
|
||||||
vnf_virtual_link_resource_info=None,
|
vnf_virtual_link_resource_info=None,
|
||||||
ext_managed_virtual_link_info=None):
|
ext_managed_virtual_link_info=None,
|
||||||
|
ext_virtual_link_info=None,
|
||||||
|
ext_cp_info=None):
|
||||||
|
|
||||||
vnfc_resource_info = vnfc_resource_info or []
|
vnfc_resource_info = vnfc_resource_info or []
|
||||||
vnf_virtual_link_resource_info = vnf_virtual_link_resource_info or []
|
vnf_virtual_link_resource_info = vnf_virtual_link_resource_info or []
|
||||||
virtual_storage_resource_info = virtual_storage_resource_info or []
|
virtual_storage_resource_info = virtual_storage_resource_info or []
|
||||||
ext_managed_virtual_link_info = ext_managed_virtual_link_info or []
|
ext_managed_virtual_link_info = ext_managed_virtual_link_info or []
|
||||||
|
ext_virtual_link_info = ext_virtual_link_info or []
|
||||||
|
ext_cp_info = ext_cp_info or []
|
||||||
|
|
||||||
inst_vnf_info = objects.InstantiatedVnfInfo(flavour_id=flavour_id,
|
inst_vnf_info = objects.InstantiatedVnfInfo(flavour_id=flavour_id,
|
||||||
instantiation_level_id=instantiation_level_id,
|
instantiation_level_id=instantiation_level_id,
|
||||||
|
@ -237,7 +305,9 @@ def get_vnf_instantiated_info(flavour_id='simple',
|
||||||
vnfc_resource_info=vnfc_resource_info,
|
vnfc_resource_info=vnfc_resource_info,
|
||||||
vnf_virtual_link_resource_info=vnf_virtual_link_resource_info,
|
vnf_virtual_link_resource_info=vnf_virtual_link_resource_info,
|
||||||
virtual_storage_resource_info=virtual_storage_resource_info,
|
virtual_storage_resource_info=virtual_storage_resource_info,
|
||||||
ext_managed_virtual_link_info=ext_managed_virtual_link_info)
|
ext_managed_virtual_link_info=ext_managed_virtual_link_info,
|
||||||
|
ext_virtual_link_info=ext_virtual_link_info,
|
||||||
|
ext_cp_info=ext_cp_info)
|
||||||
|
|
||||||
return inst_vnf_info
|
return inst_vnf_info
|
||||||
|
|
||||||
|
@ -332,6 +402,162 @@ def get_grant_response_dict():
|
||||||
return grant_response_dict
|
return grant_response_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_change_ext_conn_request():
|
||||||
|
|
||||||
|
def _get_ip_addresses(_type='IPV4', fixed_addrs=[], subnet_id=None):
|
||||||
|
if fixed_addrs and subnet_id:
|
||||||
|
return [{
|
||||||
|
"type": _type,
|
||||||
|
"fixed_addresses": fixed_addrs,
|
||||||
|
"subnet_id": subnet_id,
|
||||||
|
}]
|
||||||
|
elif fixed_addrs and not subnet_id:
|
||||||
|
return [{
|
||||||
|
"type": _type,
|
||||||
|
"fixed_addresses": fixed_addrs,
|
||||||
|
}]
|
||||||
|
elif not fixed_addrs and subnet_id:
|
||||||
|
return [{
|
||||||
|
"type": _type,
|
||||||
|
"num_dynamic_addresses": 1,
|
||||||
|
"subnet_id": subnet_id,
|
||||||
|
}]
|
||||||
|
elif not fixed_addrs and not subnet_id:
|
||||||
|
return [{
|
||||||
|
"type": _type,
|
||||||
|
"num_dynamic_addresses": 1,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _get_ext_cp_info(cpd_id, ip_address):
|
||||||
|
return {
|
||||||
|
"cpd_id": cpd_id,
|
||||||
|
"cp_config": [{
|
||||||
|
"cp_protocol_data": [{
|
||||||
|
"layer_protocol": "IP_OVER_ETHERNET",
|
||||||
|
"ip_over_ethernet": {
|
||||||
|
"ip_addresses": ip_address
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_request():
|
||||||
|
ext_vl_info = [{
|
||||||
|
"id": "external_network_1",
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": "nw-resource-id-1",
|
||||||
|
"ext_cps": [
|
||||||
|
_get_ext_cp_info('VDU1_CP1',
|
||||||
|
_get_ip_addresses(fixed_addrs=["20.0.0.1"])),
|
||||||
|
_get_ext_cp_info('VDU1_CP2',
|
||||||
|
_get_ip_addresses(
|
||||||
|
fixed_addrs=["30.0.0.2"],
|
||||||
|
subnet_id="changed-subnet-id-1")),
|
||||||
|
_get_ext_cp_info('VDU1_CP3',
|
||||||
|
_get_ip_addresses(fixed_addrs=["10.0.0.1"])),
|
||||||
|
]}, {
|
||||||
|
"id": "external_network_2",
|
||||||
|
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||||
|
"resource_id": "changed-nw-resource-id-2",
|
||||||
|
"ext_cps": [
|
||||||
|
_get_ext_cp_info('VDU2_CP1',
|
||||||
|
_get_ip_addresses(
|
||||||
|
subnet_id="changed-subnet-id-2")),
|
||||||
|
_get_ext_cp_info('VDU2_CP2', _get_ip_addresses())
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
vim_connection_info = [{
|
||||||
|
"id": uuidsentinel.vim_connection_id,
|
||||||
|
"vim_id": uuidsentinel.vim_id,
|
||||||
|
"vim_type": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||||
|
"interface_info": {
|
||||||
|
"endpoint": "endpoint_value"},
|
||||||
|
"access_info": {
|
||||||
|
"username": "username_value",
|
||||||
|
"password": "password_value",
|
||||||
|
"region": "region_value",
|
||||||
|
"tenant": "tenant_value"}}]
|
||||||
|
|
||||||
|
change_ext_conn_data = {
|
||||||
|
'ext_virtual_links': ext_vl_info,
|
||||||
|
'vim_connection_info': vim_connection_info,
|
||||||
|
'additional_params': {'key1': 'value1'}}
|
||||||
|
|
||||||
|
return change_ext_conn_data
|
||||||
|
|
||||||
|
change_ext_conn_data = _get_request()
|
||||||
|
change_ext_conn_req = objects.ChangeExtConnRequest.obj_from_primitive(
|
||||||
|
change_ext_conn_data, None)
|
||||||
|
|
||||||
|
return change_ext_conn_req
|
||||||
|
|
||||||
|
|
||||||
|
def get_original_stack_param():
|
||||||
|
stack_param = \
|
||||||
|
{'nfv': {
|
||||||
|
'VDU': {
|
||||||
|
'VDU1': {'flavor': 'm1.tiny', 'image': 'None'},
|
||||||
|
'VirtualStorage': {
|
||||||
|
'flavor': 'None',
|
||||||
|
'image': 'cirros-0.4.0-x86_64-disk'},
|
||||||
|
'VDU2': {
|
||||||
|
'flavor': 'm1.tiny',
|
||||||
|
'image': 'cirros-0.4.0-x86_64-disk'}},
|
||||||
|
'CP': {
|
||||||
|
'VDU1_CP1': {
|
||||||
|
'network': 'nw-resource-id-1',
|
||||||
|
'fixed_ips': [{'ip_address': '10.0.0.1'}]},
|
||||||
|
'VDU1_CP2': {
|
||||||
|
'network': 'nw-resource-id-1',
|
||||||
|
'fixed_ips': [{
|
||||||
|
'ip_address': '10.0.0.2',
|
||||||
|
'subnet': 'subnet-id-2'}]},
|
||||||
|
'VDU2_CP1': {
|
||||||
|
'network': 'nw-resource-id-2',
|
||||||
|
'fixed_ips': [{
|
||||||
|
'subnet': 'subnet-id-2'}]},
|
||||||
|
'VDU2_CP2': {'network': 'nw-resource-id-2'}}}}
|
||||||
|
return stack_param
|
||||||
|
|
||||||
|
|
||||||
|
def get_expect_stack_param():
|
||||||
|
stack_param = \
|
||||||
|
{'nfv': {
|
||||||
|
'VDU': {
|
||||||
|
'VDU1': {'flavor': 'm1.tiny', 'image': 'None'},
|
||||||
|
'VirtualStorage': {
|
||||||
|
'flavor': 'None',
|
||||||
|
'image': 'cirros-0.4.0-x86_64-disk'},
|
||||||
|
'VDU2': {
|
||||||
|
'flavor': 'm1.tiny',
|
||||||
|
'image': 'cirros-0.4.0-x86_64-disk'}},
|
||||||
|
'CP': {
|
||||||
|
'VDU1_CP1': {
|
||||||
|
'network': 'nw-resource-id-1',
|
||||||
|
'fixed_ips': [{'ip_address': '20.0.0.1'}]},
|
||||||
|
'VDU1_CP2': {
|
||||||
|
'network': 'nw-resource-id-1',
|
||||||
|
'fixed_ips': [{
|
||||||
|
'ip_address': '30.0.0.2',
|
||||||
|
'subnet': 'changed-subnet-id-1'}]},
|
||||||
|
'VDU2_CP1': {
|
||||||
|
'network': 'changed-nw-resource-id-2',
|
||||||
|
'fixed_ips': [{
|
||||||
|
'subnet': 'changed-subnet-id-2'}]},
|
||||||
|
'VDU2_CP2': {'network': 'changed-nw-resource-id-2'}}}}
|
||||||
|
|
||||||
|
return stack_param
|
||||||
|
|
||||||
|
|
||||||
|
def get_vnf_attribute_dict():
|
||||||
|
vnf_attribute_dict = dict()
|
||||||
|
vnf_attribute_dict.update(
|
||||||
|
{'stack_param': str(get_original_stack_param())})
|
||||||
|
|
||||||
|
return vnf_attribute_dict
|
||||||
|
|
||||||
|
|
||||||
def get_lcm_op_occs_object(operation="INSTANTIATE",
|
def get_lcm_op_occs_object(operation="INSTANTIATE",
|
||||||
error_point=0):
|
error_point=0):
|
||||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc(
|
vnf_lcm_op_occs = objects.VnfLcmOpOcc(
|
||||||
|
|
|
@ -2178,3 +2178,126 @@ class TestOpenStack(base.FixturedTestCase):
|
||||||
None, self.context, vnf_dict, 'SP1', None, None)
|
None, self.context, vnf_dict, 'SP1', None, None)
|
||||||
|
|
||||||
self.assertEqual('30435eb8-1472-4cbc-abbe-00b395165ce7', grp_id)
|
self.assertEqual('30435eb8-1472-4cbc-abbe-00b395165ce7', grp_id)
|
||||||
|
|
||||||
|
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||||
|
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
|
||||||
|
def test_change_ext_conn_vnf(self,
|
||||||
|
mock_get_base_hot_dict,
|
||||||
|
mock_mock_OpenstackClients_heat):
|
||||||
|
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||||
|
|
||||||
|
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||||
|
instantiated_vnf_info=inst_vnf_info)
|
||||||
|
|
||||||
|
nested_hot_dict = {'parameters': {'vnf': 'test'}}
|
||||||
|
mock_get_base_hot_dict.return_value = \
|
||||||
|
self._read_file(), nested_hot_dict
|
||||||
|
|
||||||
|
vnf_dict['vnfd'] = fd_utils.get_vnfd_dict()
|
||||||
|
vnf_dict['attributes'] = fd_utils.get_vnf_attribute_dict()
|
||||||
|
|
||||||
|
vim_connection_info = fd_utils.get_vim_connection_info_object()
|
||||||
|
change_ext_conn_request = fd_utils.get_change_ext_conn_request()
|
||||||
|
|
||||||
|
self.openstack.change_ext_conn_vnf(
|
||||||
|
self.context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_request)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(fd_utils.get_expect_stack_param()),
|
||||||
|
vnf_dict['attributes']['stack_param'])
|
||||||
|
|
||||||
|
def test_change_ext_conn_vnf_wait(self):
|
||||||
|
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||||
|
|
||||||
|
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||||
|
instantiated_vnf_info=inst_vnf_info)
|
||||||
|
|
||||||
|
vim_connection_info = fd_utils.get_vim_connection_info_object()
|
||||||
|
|
||||||
|
# Mock various heat APIs that will be called by heatclient
|
||||||
|
# during the process of change_ext_conn_vnf_wait.
|
||||||
|
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS",
|
||||||
|
"UPDATE_COMPLETE"])
|
||||||
|
|
||||||
|
stack = self.openstack.change_ext_conn_vnf_wait(
|
||||||
|
self.context, vnf_instance, vim_connection_info)
|
||||||
|
self.assertEqual('UPDATE_COMPLETE', stack.stack_status)
|
||||||
|
|
||||||
|
def test_change_ext_conn_vnf_wait_fail(self):
|
||||||
|
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||||
|
|
||||||
|
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||||
|
instantiated_vnf_info=inst_vnf_info)
|
||||||
|
|
||||||
|
vim_connection_info = fd_utils.get_vim_connection_info_object()
|
||||||
|
|
||||||
|
# Mock various heat APIs that will be called by heatclient
|
||||||
|
# during the process of change_ext_conn_vnf_wait.
|
||||||
|
self._response_in_wait_until_stack_ready(["UPDATE_IN_PROGRESS"])
|
||||||
|
self.openstack.STACK_RETRIES = 1
|
||||||
|
result = self.assertRaises(vnfm.VNFChangeExtConnWaitFailed,
|
||||||
|
self.openstack.change_ext_conn_vnf_wait, self.context,
|
||||||
|
vnf_instance, vim_connection_info)
|
||||||
|
|
||||||
|
expected_msg = ("VNF ChangeExtConn action is not completed within 10 "
|
||||||
|
"seconds ""on stack %s") % inst_vnf_info.instance_id
|
||||||
|
self.assertIn(expected_msg, str(result))
|
||||||
|
|
||||||
|
def test_post_change_ext_conn_vnf(self):
|
||||||
|
v_s_resource_info = fd_utils.get_virtual_storage_resource_info(
|
||||||
|
desc_id="storage1", set_resource_id=False)
|
||||||
|
|
||||||
|
storage_resource_ids = [v_s_resource_info.id]
|
||||||
|
vnfc_resource_info = fd_utils.get_vnfc_resource_info(vdu_id="VDU_VNF",
|
||||||
|
storage_resource_ids=storage_resource_ids, set_resource_id=False)
|
||||||
|
|
||||||
|
v_l_resource_info = fd_utils.get_virtual_link_resource_info(
|
||||||
|
vnfc_resource_info.vnfc_cp_info[0].vnf_link_port_id,
|
||||||
|
vnfc_resource_info.vnfc_cp_info[0].id)
|
||||||
|
|
||||||
|
inst_vnf_info = fd_utils.get_vnf_instantiated_info(
|
||||||
|
virtual_storage_resource_info=[v_s_resource_info],
|
||||||
|
vnf_virtual_link_resource_info=[v_l_resource_info],
|
||||||
|
vnfc_resource_info=[vnfc_resource_info])
|
||||||
|
|
||||||
|
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||||
|
instantiated_vnf_info=inst_vnf_info)
|
||||||
|
|
||||||
|
vim_connection_info = fd_utils.get_vim_connection_info_object()
|
||||||
|
resources = [{'resource_name': vnfc_resource_info.vdu_id,
|
||||||
|
'resource_type': vnfc_resource_info.compute_resource.
|
||||||
|
vim_level_resource_type,
|
||||||
|
'physical_resource_id': uuidsentinel.vdu_resource_id},
|
||||||
|
{'resource_name': v_s_resource_info.virtual_storage_desc_id,
|
||||||
|
'resource_type': v_s_resource_info.storage_resource.
|
||||||
|
vim_level_resource_type,
|
||||||
|
'physical_resource_id': uuidsentinel.storage_resource_id},
|
||||||
|
{'resource_name': vnfc_resource_info.vnfc_cp_info[0].cpd_id,
|
||||||
|
'resource_type': inst_vnf_info.vnf_virtual_link_resource_info[0].
|
||||||
|
vnf_link_ports[0].resource_handle.vim_level_resource_type,
|
||||||
|
'physical_resource_id': uuidsentinel.cp1_resource_id}]
|
||||||
|
|
||||||
|
self._responses_in_stack_list(inst_vnf_info.instance_id,
|
||||||
|
resources=resources)
|
||||||
|
self.openstack.post_change_ext_conn_vnf(
|
||||||
|
self.context, vnf_instance, vim_connection_info)
|
||||||
|
self.assertEqual(vnf_instance.instantiated_vnf_info.
|
||||||
|
vnfc_resource_info[0].metadata['stack_id'],
|
||||||
|
inst_vnf_info.instance_id)
|
||||||
|
|
||||||
|
# Check if vnfc resource "VDU_VNF" is set with resource_id
|
||||||
|
self.assertEqual(uuidsentinel.vdu_resource_id,
|
||||||
|
vnf_instance.instantiated_vnf_info.vnfc_resource_info[0].
|
||||||
|
compute_resource.resource_id)
|
||||||
|
|
||||||
|
# Check if virtual storage resource "storage1" is set with resource_id
|
||||||
|
self.assertEqual(uuidsentinel.storage_resource_id,
|
||||||
|
vnf_instance.instantiated_vnf_info.
|
||||||
|
virtual_storage_resource_info[0].storage_resource.resource_id)
|
||||||
|
|
||||||
|
# Check if virtual link port "CP1" is set with resource_id
|
||||||
|
self.assertEqual(uuidsentinel.cp1_resource_id,
|
||||||
|
vnf_instance.instantiated_vnf_info.
|
||||||
|
vnf_virtual_link_resource_info[0].vnf_link_ports[0].
|
||||||
|
resource_handle.resource_id)
|
||||||
|
|
|
@ -562,6 +562,22 @@ def _build_instantiated_vnf_info(vnfd_dict, instantiate_vnf_req,
|
||||||
vnf_instance.instantiated_vnf_info = inst_vnf_info
|
vnf_instance.instantiated_vnf_info = inst_vnf_info
|
||||||
|
|
||||||
|
|
||||||
|
def _update_instantiated_vnf_info(change_ext_conn_req, vnf_instance):
|
||||||
|
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
||||||
|
tmp_insta_vnf_info = copy.deepcopy(inst_vnf_info)
|
||||||
|
|
||||||
|
inst_vnf_info.ext_cp_info = _update_ext_cp_info(change_ext_conn_req,
|
||||||
|
inst_vnf_info=tmp_insta_vnf_info)
|
||||||
|
inst_vnf_info.ext_virtual_link_info = _update_ext_virtual_link_info(
|
||||||
|
change_ext_conn_req, inst_vnf_info=tmp_insta_vnf_info)
|
||||||
|
|
||||||
|
inst_vnf_info.vnf_virtual_link_resource_info = \
|
||||||
|
_update_vnf_virtual_link_resource_info(change_ext_conn_req,
|
||||||
|
inst_vnf_info)
|
||||||
|
|
||||||
|
vnf_instance.instantiated_vnf_info = inst_vnf_info
|
||||||
|
|
||||||
|
|
||||||
def _get_compute_nodes(vnfd_dict, instantiate_vnf_req):
|
def _get_compute_nodes(vnfd_dict, instantiate_vnf_req):
|
||||||
"""Read the node templates and prepare VDU data in below format
|
"""Read the node templates and prepare VDU data in below format
|
||||||
|
|
||||||
|
@ -729,6 +745,40 @@ def _build_vnf_virtual_link_resource_info(node_templates, instantiate_vnf_req,
|
||||||
return virtual_link_resource_info_list
|
return virtual_link_resource_info_list
|
||||||
|
|
||||||
|
|
||||||
|
def _update_vnf_virtual_link_resource_info(change_ext_conn_req,
|
||||||
|
inst_vnf_info):
|
||||||
|
def _update(change_ext_conn_req, vnf_vl_resource_info):
|
||||||
|
for ext_virtual_link in change_ext_conn_req.ext_virtual_links:
|
||||||
|
if (ext_virtual_link.id ==
|
||||||
|
vnf_vl_resource_info.vnf_virtual_link_desc_id):
|
||||||
|
res_handle = objects.ResourceHandle()
|
||||||
|
res_handle.resource_id = ext_virtual_link.resource_id
|
||||||
|
nw_res = vnf_vl_resource_info.network_resource
|
||||||
|
res_handle.vim_connection_id = nw_res.vim_connection_id
|
||||||
|
res_handle.vim_level_resource_type = \
|
||||||
|
nw_res.vim_level_resource_type
|
||||||
|
new_vnf_vl_resource_info = \
|
||||||
|
objects.VnfVirtualLinkResourceInfo(
|
||||||
|
id=vnf_vl_resource_info.id,
|
||||||
|
vnf_virtual_link_desc_id=vnf_vl_resource_info.
|
||||||
|
vnf_virtual_link_desc_id,
|
||||||
|
network_resource=res_handle,
|
||||||
|
vnf_link_ports=vnf_vl_resource_info.vnf_link_ports)
|
||||||
|
return new_vnf_vl_resource_info
|
||||||
|
return None
|
||||||
|
|
||||||
|
vnf_virtual_link_resource_list = []
|
||||||
|
for vnf_vl_res_info in inst_vnf_info.vnf_virtual_link_resource_info:
|
||||||
|
updated_vnf_vl_res_info = \
|
||||||
|
_update(change_ext_conn_req, vnf_vl_res_info)
|
||||||
|
if updated_vnf_vl_res_info:
|
||||||
|
vnf_virtual_link_resource_list.append(updated_vnf_vl_res_info)
|
||||||
|
else:
|
||||||
|
vnf_virtual_link_resource_list.append(vnf_vl_res_info)
|
||||||
|
|
||||||
|
return vnf_virtual_link_resource_list
|
||||||
|
|
||||||
|
|
||||||
def _build_vnf_cp_info(instantiate_vnf_req, cp_list):
|
def _build_vnf_cp_info(instantiate_vnf_req, cp_list):
|
||||||
vnfc_cp_info_list = []
|
vnfc_cp_info_list = []
|
||||||
|
|
||||||
|
@ -831,6 +881,34 @@ def _set_ext_cp_info(instantiate_vnf_req, inst_vnf_info=None):
|
||||||
return ext_cp_info_list
|
return ext_cp_info_list
|
||||||
|
|
||||||
|
|
||||||
|
def _update_ext_cp_info(change_ext_conn_req, inst_vnf_info):
|
||||||
|
|
||||||
|
def _update(change_ext_conn_req, ext_cp_info):
|
||||||
|
for ext_virt_link in change_ext_conn_req.ext_virtual_links:
|
||||||
|
if not ext_virt_link.ext_cps:
|
||||||
|
continue
|
||||||
|
for ext_cp in ext_virt_link.ext_cps:
|
||||||
|
if ext_cp.cpd_id == ext_cp_info.cpd_id:
|
||||||
|
new_ext_cp_info = objects.VnfExtCpInfo(
|
||||||
|
id=ext_cp_info.id,
|
||||||
|
cpd_id=ext_cp.cpd_id,
|
||||||
|
cp_protocol_info=_set_cp_protocol_info(ext_cp),
|
||||||
|
associated_vnfc_cp_id=ext_cp_info.
|
||||||
|
associated_vnfc_cp_id)
|
||||||
|
return new_ext_cp_info
|
||||||
|
return None
|
||||||
|
|
||||||
|
ext_cp_info_list = []
|
||||||
|
for ext_cp_info in inst_vnf_info.ext_cp_info:
|
||||||
|
updated_ext_cp_info = _update(change_ext_conn_req, ext_cp_info)
|
||||||
|
if updated_ext_cp_info:
|
||||||
|
ext_cp_info_list.append(updated_ext_cp_info)
|
||||||
|
else:
|
||||||
|
ext_cp_info_list.append(ext_cp_info)
|
||||||
|
|
||||||
|
return ext_cp_info_list
|
||||||
|
|
||||||
|
|
||||||
def _get_ext_link_port_id(ext_virtual_link, cpd_id):
|
def _get_ext_link_port_id(ext_virtual_link, cpd_id):
|
||||||
if not ext_virtual_link.ext_link_ports:
|
if not ext_virtual_link.ext_link_ports:
|
||||||
return
|
return
|
||||||
|
@ -926,6 +1004,38 @@ def _set_ext_virtual_link_info(instantiate_vnf_req, ext_cp_info):
|
||||||
return ext_virtual_link_list
|
return ext_virtual_link_list
|
||||||
|
|
||||||
|
|
||||||
|
def _update_ext_virtual_link_info(change_ext_conn_req, inst_vnf_info):
|
||||||
|
|
||||||
|
def _update(change_ext_conn_req, ext_virtual_link_info):
|
||||||
|
for ext_virtual_link in change_ext_conn_req.ext_virtual_links:
|
||||||
|
if ext_virtual_link.id == ext_virtual_link_info.id:
|
||||||
|
res_handle = objects.ResourceHandle()
|
||||||
|
res_handle.resource_id = ext_virtual_link.resource_id
|
||||||
|
new_ext_virtual_link_info = objects.ExtVirtualLinkInfo(
|
||||||
|
id=ext_virtual_link_info.id,
|
||||||
|
resource_handle=res_handle,
|
||||||
|
ext_link_ports=ext_virtual_link_info.ext_link_ports)
|
||||||
|
res_handle.vim_connection_id = \
|
||||||
|
ext_virtual_link_info.resource_handle.vim_connection_id
|
||||||
|
new_ext_virtual_link_info = objects.ExtVirtualLinkInfo(
|
||||||
|
id=ext_virtual_link_info.id,
|
||||||
|
resource_handle=res_handle,
|
||||||
|
ext_link_ports=ext_virtual_link_info.ext_link_ports)
|
||||||
|
return new_ext_virtual_link_info
|
||||||
|
return None
|
||||||
|
|
||||||
|
ext_virtual_link_list = []
|
||||||
|
for ext_virtual_link_info in inst_vnf_info.ext_virtual_link_info:
|
||||||
|
updated_ext_virtual_link_info = \
|
||||||
|
_update(change_ext_conn_req, ext_virtual_link_info)
|
||||||
|
if updated_ext_virtual_link_info:
|
||||||
|
ext_virtual_link_list.append(updated_ext_virtual_link_info)
|
||||||
|
else:
|
||||||
|
ext_virtual_link_list.append(ext_virtual_link_info)
|
||||||
|
|
||||||
|
return ext_virtual_link_list
|
||||||
|
|
||||||
|
|
||||||
def _set_ext_link_port(ext_virtual_links, ext_cp_info):
|
def _set_ext_link_port(ext_virtual_links, ext_cp_info):
|
||||||
ext_link_port_list = []
|
ext_link_port_list = []
|
||||||
|
|
||||||
|
@ -1152,3 +1262,54 @@ def get_target_vdu_def_dict(extract_policy_infos, aspect_id, tosca):
|
||||||
vdu_def_dict[node_name] = node_value
|
vdu_def_dict[node_name] = node_value
|
||||||
|
|
||||||
return vdu_def_dict
|
return vdu_def_dict
|
||||||
|
|
||||||
|
|
||||||
|
def _get_changed_ext_connectivity(
|
||||||
|
old_vnf_instance=None, new_vnf_instance=None):
|
||||||
|
|
||||||
|
changed_ext_connectivities = []
|
||||||
|
if not old_vnf_instance or not new_vnf_instance:
|
||||||
|
return changed_ext_connectivities
|
||||||
|
|
||||||
|
old_vnf_vl_res_info = \
|
||||||
|
old_vnf_instance.instantiated_vnf_info.\
|
||||||
|
vnf_virtual_link_resource_info
|
||||||
|
new_vnf_vl_res_info = \
|
||||||
|
new_vnf_instance.instantiated_vnf_info.\
|
||||||
|
vnf_virtual_link_resource_info
|
||||||
|
|
||||||
|
def _compare_vnf_link_ports(old_vnf_link_ports,
|
||||||
|
new_vnf_link_ports):
|
||||||
|
differed_vnf_link_ports = []
|
||||||
|
for old_vnf_link_port in old_vnf_link_ports:
|
||||||
|
for new_vnf_link_port in new_vnf_link_ports:
|
||||||
|
if old_vnf_link_port.id == new_vnf_link_port.id:
|
||||||
|
if (old_vnf_link_port.resource_handle.resource_id !=
|
||||||
|
new_vnf_link_port.resource_handle.resource_id):
|
||||||
|
differed_vnf_link_ports.append(new_vnf_link_port)
|
||||||
|
return differed_vnf_link_ports
|
||||||
|
|
||||||
|
for old_vl_res in old_vnf_vl_res_info:
|
||||||
|
for new_vl_res in new_vnf_vl_res_info:
|
||||||
|
if old_vl_res.id == new_vl_res.id:
|
||||||
|
changed_ext_connectivity = objects.ExtVirtualLinkInfo(
|
||||||
|
id=new_vl_res.id,
|
||||||
|
resource_handle=new_vl_res.network_resource,
|
||||||
|
ext_link_ports=[])
|
||||||
|
differed_vnf_link_ports = _compare_vnf_link_ports(
|
||||||
|
old_vl_res.vnf_link_ports,
|
||||||
|
new_vl_res.vnf_link_ports)
|
||||||
|
for link_port in differed_vnf_link_ports:
|
||||||
|
changed_ext_link_port = objects.ExtLinkPortInfo(
|
||||||
|
id=link_port.id,
|
||||||
|
resource_handle=link_port.resource_handle,
|
||||||
|
cp_instance_id=link_port.cp_instance_id)
|
||||||
|
changed_ext_connectivity.ext_link_ports.\
|
||||||
|
append(changed_ext_link_port)
|
||||||
|
if changed_ext_connectivity.ext_link_ports:
|
||||||
|
changed_ext_connectivities.append(
|
||||||
|
changed_ext_connectivity)
|
||||||
|
|
||||||
|
LOG.debug('changed_ext_connectivities: {}'.format(
|
||||||
|
changed_ext_connectivities))
|
||||||
|
return changed_ext_connectivities
|
||||||
|
|
|
@ -1742,3 +1742,101 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
||||||
vnf_instance,
|
vnf_instance,
|
||||||
operation_params,
|
operation_params,
|
||||||
vim_connection_info)
|
vim_connection_info)
|
||||||
|
|
||||||
|
def _change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req):
|
||||||
|
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
||||||
|
try:
|
||||||
|
self._vnf_manager.invoke(
|
||||||
|
vim_connection_info.vim_type, 'change_ext_conn_vnf',
|
||||||
|
context=context, vnf_instance=vnf_instance, vnf_dict=vnf_dict,
|
||||||
|
vim_connection_info=vim_connection_info,
|
||||||
|
change_ext_conn_req=change_ext_conn_req)
|
||||||
|
except Exception as exp:
|
||||||
|
with excutils.save_and_reraise_exception() as exc_ctxt:
|
||||||
|
exc_ctxt.reraise = False
|
||||||
|
LOG.error("Failed to change external connectivity "
|
||||||
|
"vnf %(id)s in infra driver. "
|
||||||
|
"Error: %(error)s", {"id": vnf_instance.id, "error":
|
||||||
|
encodeutils.exception_to_unicode(exp)})
|
||||||
|
raise exceptions.VnfChangeExtConnFailed(id=vnf_instance.id,
|
||||||
|
error=encodeutils.exception_to_unicode(exp))
|
||||||
|
vnf_dict['current_error_point'] = fields.ErrorPoint.POST_VIM_CONTROL
|
||||||
|
try:
|
||||||
|
self._vnf_manager.invoke(
|
||||||
|
vim_connection_info.vim_type, 'change_ext_conn_vnf_wait',
|
||||||
|
context=context, vnf_instance=vnf_instance,
|
||||||
|
vim_connection_info=vim_connection_info)
|
||||||
|
except Exception as exp:
|
||||||
|
LOG.error("Failed to update vnf %(id)s resources for instance "
|
||||||
|
"%(instance)s. Error: %(error)s",
|
||||||
|
{'id': vnf_instance.id, 'instance':
|
||||||
|
inst_vnf_info.instance_id, 'error':
|
||||||
|
encodeutils.exception_to_unicode(exp)})
|
||||||
|
raise exceptions.VnfChangeExtConnWaitFailed(
|
||||||
|
id=vnf_instance.id,
|
||||||
|
error=encodeutils.exception_to_unicode(exp))
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
@revert_to_error_task_state
|
||||||
|
def change_ext_conn_vnf(
|
||||||
|
self,
|
||||||
|
context,
|
||||||
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
|
change_ext_conn_req):
|
||||||
|
LOG.info("Request received for changing external connectivity "
|
||||||
|
"vnf '%s'", vnf_instance.id)
|
||||||
|
|
||||||
|
vnfd_dict = vnflcm_utils._get_vnfd_dict(
|
||||||
|
context, vnf_instance.vnfd_id,
|
||||||
|
vnf_instance.instantiated_vnf_info.flavour_id)
|
||||||
|
|
||||||
|
vnf_dict['current_error_point'] = EP.VNF_CONFIG_START
|
||||||
|
if vnf_dict['before_error_point'] <= EP.VNF_CONFIG_START:
|
||||||
|
# TODO(esto-aln): grant_request here is planned to pass
|
||||||
|
# as a parameter, however due to grant_request are not
|
||||||
|
# passed from conductor to vnflcm_driver, thus we put Null
|
||||||
|
# value to grant and grant_reqeust temporary.
|
||||||
|
# This part will be updated in next release.
|
||||||
|
self._mgmt_manager.invoke(
|
||||||
|
self._load_vnf_interface(
|
||||||
|
context, 'change_external_connectivity_start',
|
||||||
|
vnf_instance, vnfd_dict),
|
||||||
|
'change_external_connectivity_start', context=context,
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
change_ext_conn_request=change_ext_conn_req,
|
||||||
|
grant=vnf_dict.get('grant'), grant_request=None)
|
||||||
|
|
||||||
|
vnf_dict['current_error_point'] = EP.PRE_VIM_CONTROL
|
||||||
|
if vnf_dict['before_error_point'] <= EP.POST_VIM_CONTROL:
|
||||||
|
vim_info = vnflcm_utils._get_vim(context,
|
||||||
|
vnf_instance.vim_connection_info)
|
||||||
|
|
||||||
|
vim_connection_info = \
|
||||||
|
objects.VimConnectionInfo.obj_from_primitive(
|
||||||
|
vim_info, context)
|
||||||
|
|
||||||
|
self._change_ext_conn_vnf(context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req)
|
||||||
|
|
||||||
|
# Since there is no processing corresponding to
|
||||||
|
# EP.INTERNAL_PROCESSING, it transitions to EP.VNF_CONFIG_END.
|
||||||
|
vnf_dict['current_error_point'] = EP.VNF_CONFIG_END
|
||||||
|
if vnf_dict['before_error_point'] <= EP.VNF_CONFIG_END:
|
||||||
|
# TODO(esto-aln): grant_request here is planned to pass
|
||||||
|
# as a parameter, however due to grant_request are not
|
||||||
|
# passed from conductor to vnflcm_driver, thus we put Null
|
||||||
|
# value to grant and grant_reqeust temporary.
|
||||||
|
# This part will be updated in next release.
|
||||||
|
self._mgmt_manager.invoke(
|
||||||
|
self._load_vnf_interface(
|
||||||
|
context, 'change_external_connectivity_end',
|
||||||
|
vnf_instance, vnfd_dict),
|
||||||
|
'change_external_connectivity_end', context=context,
|
||||||
|
vnf_instance=vnf_instance,
|
||||||
|
change_ext_conn_request=change_ext_conn_req,
|
||||||
|
grant=vnf_dict.get('grant'), grant_request=None)
|
||||||
|
|
||||||
|
LOG.info("Request received for changing external connectivity "
|
||||||
|
"vnf '%s' is completed successfully", vnf_instance.id)
|
||||||
|
|
|
@ -131,3 +131,35 @@ class VnfAbstractDriver(extensions.PluginInterface, metaclass=abc.ABCMeta):
|
||||||
parameters passed in the heal request
|
parameters passed in the heal request
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req):
|
||||||
|
"""Change external VNF connectivity
|
||||||
|
|
||||||
|
:param context: A RequestContext
|
||||||
|
:param vnf_instance: tacker.objects.VnfInstance to be changed
|
||||||
|
:param vnf_dict:
|
||||||
|
:param vim_connection_info: Credentials to initialize Vim connection
|
||||||
|
:param change_ext_conn_req: tacker.objects.ChangeExtconnRequest object
|
||||||
|
containing parameters passed in the
|
||||||
|
change_ext_conn request
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_ext_conn_vnf_wait(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
"""Check vnf external connnectivity is changed successfully"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def post_change_ext_conn_vnf(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
"""Update resource information for each external VL/LINKPORT resources
|
||||||
|
|
||||||
|
:param context: A RequestContext
|
||||||
|
:param vnf_instance: tacker.objects.VnfInstance to be changed
|
||||||
|
:param vim_connection_info: Credentials to initialize Vim connection
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
|
@ -2030,6 +2030,18 @@ class Kubernetes(abstract_driver.VnfAbstractDriver,
|
||||||
finally:
|
finally:
|
||||||
self.clean_authenticate_vim(auth_cred, file_descriptor)
|
self.clean_authenticate_vim(auth_cred, file_descriptor)
|
||||||
|
|
||||||
|
def change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def change_ext_conn_vnf_wait(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def post_change_ext_conn_vnf(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def get_scale_ids(self,
|
def get_scale_ids(self,
|
||||||
plugin,
|
plugin,
|
||||||
context,
|
context,
|
||||||
|
|
|
@ -104,3 +104,15 @@ class VnfNoop(abstract_driver.VnfAbstractDriver):
|
||||||
def post_heal_vnf(self, context, vnf_instance, vim_connection_info,
|
def post_heal_vnf(self, context, vnf_instance, vim_connection_info,
|
||||||
heal_vnf_request):
|
heal_vnf_request):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def change_ext_conn_vnf_wait(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_change_ext_conn_vnf(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
pass
|
||||||
|
|
|
@ -996,21 +996,6 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||||
vnfd_dict['instance_id'] = instance_id
|
vnfd_dict['instance_id'] = instance_id
|
||||||
return instance_id
|
return instance_id
|
||||||
|
|
||||||
@log.log
|
|
||||||
def post_vnf_instantiation(self, context, vnf_instance,
|
|
||||||
vim_connection_info, instantiate_vnf_req):
|
|
||||||
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
|
||||||
access_info = vim_connection_info.access_info
|
|
||||||
|
|
||||||
heatclient = hc.HeatClient(access_info,
|
|
||||||
region_name=access_info.get('region'))
|
|
||||||
stack_resources = self._get_stack_resources(
|
|
||||||
inst_vnf_info.instance_id, heatclient)
|
|
||||||
|
|
||||||
self._update_vnfc_resources(vnf_instance, stack_resources,
|
|
||||||
vim_connection_info)
|
|
||||||
self._update_vnfc_info(vnf_instance)
|
|
||||||
|
|
||||||
def _update_resource_handle(self, vnf_instance, resource_handle,
|
def _update_resource_handle(self, vnf_instance, resource_handle,
|
||||||
stack_resources, resource_name,
|
stack_resources, resource_name,
|
||||||
vim_connection_info):
|
vim_connection_info):
|
||||||
|
@ -2033,3 +2018,101 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||||
return_rs_list = before_rs_list
|
return_rs_list = before_rs_list
|
||||||
|
|
||||||
return return_list, return_rs_list, grp.physical_resource_id
|
return return_list, return_rs_list, grp.physical_resource_id
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
|
vim_connection_info, change_ext_conn_req):
|
||||||
|
|
||||||
|
base_hot_dict, nested_hot_dict = \
|
||||||
|
vnflcm_utils.get_base_nest_hot_dict(
|
||||||
|
context,
|
||||||
|
vnf_instance.instantiated_vnf_info.flavour_id,
|
||||||
|
vnf_instance.vnfd_id)
|
||||||
|
stack_param = yaml.safe_load(
|
||||||
|
vnf_dict['attributes']['stack_param'])
|
||||||
|
|
||||||
|
LOG.debug('before stack_param: {}'.format(stack_param))
|
||||||
|
cp_param = stack_param['nfv']['CP']
|
||||||
|
|
||||||
|
for ext_virtual_link in change_ext_conn_req.ext_virtual_links:
|
||||||
|
for ext_cp in ext_virtual_link.ext_cps:
|
||||||
|
if ext_cp.cpd_id not in cp_param.keys():
|
||||||
|
continue
|
||||||
|
cpd_id = ext_cp.cpd_id
|
||||||
|
network = cp_param[cpd_id].get('network', None)
|
||||||
|
if network and network != ext_virtual_link.resource_id:
|
||||||
|
cp_param[cpd_id].update(
|
||||||
|
dict(network=ext_virtual_link.resource_id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
ip_addr = ext_cp.cp_config[0].cp_protocol_data[0].\
|
||||||
|
ip_over_ethernet.ip_addresses[0]
|
||||||
|
except IndexError:
|
||||||
|
# If the element under ext_cp does not exist,
|
||||||
|
# and ip_addresses cannot get, do nothing
|
||||||
|
continue
|
||||||
|
|
||||||
|
fixed_ips = dict()
|
||||||
|
updated_fixed_ips = []
|
||||||
|
if ip_addr.fixed_addresses:
|
||||||
|
for address in ip_addr.fixed_addresses:
|
||||||
|
fixed_ips = dict(ip_address=address)
|
||||||
|
if ip_addr.subnet_id:
|
||||||
|
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||||
|
updated_fixed_ips.append(fixed_ips)
|
||||||
|
elif ip_addr.num_dynamic_addresses > 0:
|
||||||
|
if ip_addr.subnet_id:
|
||||||
|
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||||
|
updated_fixed_ips.append(fixed_ips)
|
||||||
|
if updated_fixed_ips:
|
||||||
|
cp_param[cpd_id].update(
|
||||||
|
dict(fixed_ips=updated_fixed_ips))
|
||||||
|
|
||||||
|
LOG.debug('after stack_param: {}'.format(stack_param))
|
||||||
|
|
||||||
|
access_info = vim_connection_info.access_info
|
||||||
|
heatclient = hc.HeatClient(access_info,
|
||||||
|
region_name=access_info.get('region'))
|
||||||
|
|
||||||
|
# Update heat-stack with BaseHOT and parameters
|
||||||
|
self._update_stack_with_user_data(
|
||||||
|
heatclient, vnf_instance, base_hot_dict, nested_hot_dict,
|
||||||
|
stack_param, vnf_instance.instantiated_vnf_info.instance_id)
|
||||||
|
vnf_dict['attributes'].update({'stack_param': str(stack_param)})
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_ext_conn_vnf_wait(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
access_info = vim_connection_info.access_info
|
||||||
|
region_name = access_info.get('region')
|
||||||
|
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
||||||
|
stack = self._wait_until_stack_ready(inst_vnf_info.instance_id,
|
||||||
|
access_info, infra_cnst.STACK_UPDATE_IN_PROGRESS,
|
||||||
|
infra_cnst.STACK_UPDATE_COMPLETE,
|
||||||
|
vnfm.VNFChangeExtConnWaitFailed,
|
||||||
|
region_name=region_name)
|
||||||
|
return stack
|
||||||
|
|
||||||
|
def _update_vnfc_resources_and_info(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
||||||
|
access_info = vim_connection_info.access_info
|
||||||
|
heatclient = hc.HeatClient(access_info,
|
||||||
|
region_name=access_info.get('region'))
|
||||||
|
stack_resources = self._get_stack_resources(
|
||||||
|
inst_vnf_info.instance_id, heatclient)
|
||||||
|
self._update_vnfc_resources(vnf_instance, stack_resources,
|
||||||
|
vim_connection_info)
|
||||||
|
self._update_vnfc_info(vnf_instance)
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def post_vnf_instantiation(self, context, vnf_instance,
|
||||||
|
vim_connection_info, instantiate_vnf_req):
|
||||||
|
self._update_vnfc_resources_and_info(
|
||||||
|
context, vnf_instance, vim_connection_info)
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def post_change_ext_conn_vnf(self, context, vnf_instance,
|
||||||
|
vim_connection_info):
|
||||||
|
self._update_vnfc_resources_and_info(
|
||||||
|
context, vnf_instance, vim_connection_info)
|
||||||
|
|
|
@ -83,3 +83,17 @@ class VnflcmMgmtAbstractDriver(metaclass=abc.ABCMeta):
|
||||||
heal_vnf_request, grant,
|
heal_vnf_request, grant,
|
||||||
grant_request, **kwargs):
|
grant_request, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_external_connectivity_start(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_external_connectivity_end(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
|
@ -74,3 +74,17 @@ class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
|
||||||
heal_vnf_request, grant,
|
heal_vnf_request, grant,
|
||||||
grant_request, **kwargs):
|
grant_request, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_external_connectivity_start(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def change_external_connectivity_end(
|
||||||
|
self, context, vnf_instance,
|
||||||
|
change_ext_conn_request, grant,
|
||||||
|
grant_request, **kwargs):
|
||||||
|
pass
|
||||||
|
|
Loading…
Reference in New Issue