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:
|
||||
DEFAULT:
|
||||
enable_isolated_metadata: True
|
||||
$CINDER_CONF:
|
||||
lvmdriver-1:
|
||||
image_volume_cache_enabled: False
|
||||
devstack_plugins:
|
||||
heat: https://opendev.org/openstack/heat
|
||||
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
|
||||
: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
|
||||
=================================
|
||||
|
||||
|
@ -274,3 +274,14 @@ scale = {
|
||||
'required': ['type', 'aspectId'],
|
||||
'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": {
|
||||
"href": '/vnflcm/v1/vnf_instances/%s/heal'
|
||||
% 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 objects
|
||||
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_subscriptions as subscription_obj
|
||||
from tacker.plugins.common import constants
|
||||
@ -1577,6 +1578,49 @@ class VnfLcmController(wsgi.Controller):
|
||||
vnf_lcm_subscription, cast=False)
|
||||
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():
|
||||
return wsgi.Resource(VnfLcmController())
|
||||
|
@ -150,3 +150,8 @@ class VnflcmAPIRouter(wsgi.Router):
|
||||
methods = {"GET": "list_lcm_op_occs"}
|
||||
self._setup_route(mapper, "/vnf_lcm_op_occs",
|
||||
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")
|
||||
|
||||
|
||||
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):
|
||||
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 objects
|
||||
from tacker.objects import fields
|
||||
from tacker.objects.fields import ErrorPoint as EP
|
||||
from tacker.objects.vnf_package import VnfPackagesList
|
||||
from tacker.objects import vnfd as vnfd_db
|
||||
from tacker.objects import vnfd_attribute as vnfd_attribute_db
|
||||
@ -109,7 +110,8 @@ _ACTIVE_STATUS = ('ACTIVE',)
|
||||
_PENDING_STATUS = ('PENDING_CREATE',
|
||||
'PENDING_TERMINATE',
|
||||
'PENDING_DELETE',
|
||||
'PENDING_HEAL')
|
||||
'PENDING_HEAL',
|
||||
'PENDING_CHANGE_EXT_CONN')
|
||||
_ERROR_STATUS = ('ERROR',)
|
||||
_ALL_STATUSES = _ACTIVE_STATUS + _INACTIVE_STATUS + _PENDING_STATUS + \
|
||||
_ERROR_STATUS
|
||||
@ -781,6 +783,30 @@ class Conductor(manager.Manager):
|
||||
format(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
|
||||
def _add_additional_vnf_info(self, context, vnf_instance):
|
||||
'''this method adds misc info to 'vnf' table'''
|
||||
@ -834,6 +860,104 @@ class Conductor(manager.Manager):
|
||||
{'zip': csar_path, 'folder': csar_zip_temp_path,
|
||||
'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):
|
||||
LOG.info(
|
||||
"grant start grant_request[%s]" %
|
||||
@ -855,7 +979,11 @@ class Conductor(manager.Manager):
|
||||
grant_obj.remove_resources):
|
||||
msg = "grant remove resource error"
|
||||
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)
|
||||
|
||||
return grant_obj
|
||||
@ -881,6 +1009,16 @@ class Conductor(manager.Manager):
|
||||
msg = "grant remove resource error"
|
||||
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
|
||||
def _instantiate_grant(self,
|
||||
context,
|
||||
@ -1307,6 +1445,7 @@ class Conductor(manager.Manager):
|
||||
is_automatic_invocation,
|
||||
add_resources=[],
|
||||
remove_resources=[],
|
||||
update_resources=[],
|
||||
placement_constraints=[]):
|
||||
grant_request = objects.GrantRequest()
|
||||
grant_request.vnf_instance_id = vnf_instance.id
|
||||
@ -1330,6 +1469,8 @@ class Conductor(manager.Manager):
|
||||
grant_request.add_resources = add_resources
|
||||
if remove_resources:
|
||||
grant_request.remove_resources = remove_resources
|
||||
if update_resources:
|
||||
grant_request.update_resources = update_resources
|
||||
if placement_constraints:
|
||||
grant_request.placement_constraints = placement_constraints
|
||||
|
||||
@ -1443,7 +1584,12 @@ class Conductor(manager.Manager):
|
||||
jsonutils.dumps(affected_resources_snake_case)
|
||||
changed_resource = objects.ResourceChanges.obj_from_primitive(
|
||||
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.changed_ext_connectivity = changed_ext_connectivity
|
||||
vnf_notif.save()
|
||||
notification_data['affectedVnfcs'] = \
|
||||
affected_resources.get('affectedVnfcs', [])
|
||||
@ -1453,6 +1599,9 @@ class Conductor(manager.Manager):
|
||||
affected_resources.get('affectedVirtualStorages', [])
|
||||
notification_data['notificationStatus'] = \
|
||||
fields.LcmOccsNotificationStatus.RESULT
|
||||
notification_data['changedExtConnectivity'] = \
|
||||
utils.convert_snakecase_to_camelcase(
|
||||
[i.to_dict() for i in changed_ext_connectivity])
|
||||
|
||||
if operation_state == \
|
||||
fields.LcmOccsOperationState.FAILED_TEMP \
|
||||
@ -2035,6 +2184,113 @@ class Conductor(manager.Manager):
|
||||
self.vnflcm_driver.rollback_vnf(context, vnf_info,
|
||||
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):
|
||||
CONF(args=args, project='tacker',
|
||||
|
@ -136,3 +136,25 @@ class VNFLcmRPCAPI(object):
|
||||
vnf_info=vnf_info,
|
||||
vnf_instance=vnf_instance,
|
||||
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')
|
||||
|
||||
|
||||
class VNFChangeExtConnWaitFailed(exceptions.TackerException):
|
||||
message = _('VNF ChangeExtConn %(reason)s')
|
||||
|
||||
|
||||
class VNFDeleteFailed(exceptions.TackerException):
|
||||
message = _('%(reason)s')
|
||||
|
||||
|
@ -44,3 +44,4 @@ def register_all():
|
||||
__import__('tacker.objects.grant')
|
||||
__import__('tacker.objects.grant_request')
|
||||
__import__('tacker.objects.vnfd_attribute')
|
||||
__import__('tacker.objects.change_ext_conn_req')
|
||||
|
68
tacker/objects/change_ext_conn_req.py
Normal file
68
tacker/objects/change_ext_conn_req.py
Normal file
@ -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'
|
||||
HEAL = 'HEAL'
|
||||
SCALE = 'SCALE'
|
||||
CHANGE_EXT_CONN = 'CHANGE_EXT_CONN'
|
||||
|
||||
ALL = (INSTANTIATE, TERMINATE, HEAL, SCALE)
|
||||
ALL = (INSTANTIATE, TERMINATE, HEAL, SCALE, CHANGE_EXT_CONN)
|
||||
|
||||
|
||||
class LcmOccsNotificationStatus(BaseTackerEnum):
|
||||
|
@ -33,8 +33,12 @@ class Grant(base.TackerObject):
|
||||
'GrantInfo', nullable=True, default=[]),
|
||||
'remove_resources': fields.ListOfObjectsField(
|
||||
'GrantInfo', nullable=True, default=[]),
|
||||
'update_resources': fields.ListOfObjectsField(
|
||||
'GrantInfo', nullable=True, default=[]),
|
||||
'vim_assets': fields.ObjectField(
|
||||
'VimAssets', nullable=True)
|
||||
'VimAssets', nullable=True),
|
||||
'ext_virtual_links': fields.ListOfObjectsField(
|
||||
'ExtVirtualLinkData', nullable=True, default=[]),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@ -65,11 +69,20 @@ class Grant(base.TackerObject):
|
||||
remove_rsc) for remove_rsc in primitive.get(
|
||||
'remove_resources', [])]
|
||||
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():
|
||||
obj_data = VimAssets.obj_from_primitive(
|
||||
primitive.get('vim_assets'), context)
|
||||
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)
|
||||
|
||||
return obj_grant
|
||||
@ -83,7 +96,9 @@ class Grant(base.TackerObject):
|
||||
zones = data_dict.get('zones', [])
|
||||
add_resources = data_dict.get('add_resources', [])
|
||||
remove_resources = data_dict.get('remove_resources', [])
|
||||
update_resources = data_dict.get('update_resources', [])
|
||||
vim_assets = data_dict.get('vim_assets')
|
||||
ext_virtual_links = data_dict.get('ext_virtual_links', [])
|
||||
|
||||
obj = cls(
|
||||
id=id,
|
||||
@ -93,7 +108,9 @@ class Grant(base.TackerObject):
|
||||
zones=zones,
|
||||
add_resources=add_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
|
||||
|
||||
|
||||
|
@ -35,6 +35,8 @@ class GrantRequest(base.TackerObject):
|
||||
'ResourceDefinition', nullable=True, default=[]),
|
||||
'remove_resources': fields.ListOfObjectsField(
|
||||
'ResourceDefinition', nullable=True, default=[]),
|
||||
'update_resources': fields.ListOfObjectsField(
|
||||
'ResourceDefinition', nullable=True, default=[]),
|
||||
'placement_constraints': fields.ListOfObjectsField(
|
||||
'PlacementConstraint', nullable=True, default=[]),
|
||||
'_links': fields.ObjectField(
|
||||
@ -57,11 +59,20 @@ class GrantRequest(base.TackerObject):
|
||||
remove_rsc) for remove_rsc in primitive.get(
|
||||
'remove_resources', [])]
|
||||
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():
|
||||
obj_data = [PlacementConstraint._from_dict(
|
||||
place) for place in primitive.get(
|
||||
'placement_constraints', [])]
|
||||
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)
|
||||
|
||||
return obj_grant_req
|
||||
@ -76,6 +87,7 @@ class GrantRequest(base.TackerObject):
|
||||
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
||||
add_resources = data_dict.get('add_resources', [])
|
||||
remove_resources = data_dict.get('remove_resources', [])
|
||||
update_resources = data_dict.get('update_resources', [])
|
||||
placement_constraints = data_dict.get('placement_constraints', [])
|
||||
links = data_dict.get('_links')
|
||||
|
||||
@ -88,6 +100,7 @@ class GrantRequest(base.TackerObject):
|
||||
is_automatic_invocation=is_automatic_invocation,
|
||||
add_resources=add_resources,
|
||||
remove_resources=remove_resources,
|
||||
update_resources=update_resources,
|
||||
placement_constraints=placement_constraints,
|
||||
_links=links)
|
||||
return obj
|
||||
@ -112,6 +125,12 @@ class GrantRequest(base.TackerObject):
|
||||
remove_resources_list.append(remove_resource.to_dict())
|
||||
|
||||
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:
|
||||
placement_constraints_list = []
|
||||
for placement_constraint in self.placement_constraints:
|
||||
|
@ -291,7 +291,8 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
||||
changed_ext_conn = \
|
||||
[objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||
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._context = context
|
||||
|
@ -40,6 +40,7 @@ PENDING_SCALE_IN = "PENDING_SCALE_IN"
|
||||
PENDING_SCALE_OUT = "PENDING_SCALE_OUT"
|
||||
PENDING_HEAL = "PENDING_HEAL"
|
||||
PENDING_TERMINATE = "PENDING_TERMINATE"
|
||||
PENDING_CHANGE_EXT_CONN = "PENDING_CHANGE_EXT_CONN"
|
||||
DEAD = "DEAD"
|
||||
ERROR = "ERROR"
|
||||
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,
|
||||
grant_request, **kwargs):
|
||||
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
|
||||
Content-Type: text/x-python
|
||||
Algorithm: SHA-256
|
||||
Hash: 63cfaf9963680ff864981d4db809c2ec175d78054157c0bcd43ac7a85973af10
|
||||
Hash: 950422e356c3eb6a7c92f424d975e2d3f295f480321bd91a97501045eddeab4a
|
||||
|
@ -262,6 +262,9 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
self.ext_link_ports = list()
|
||||
# Create external subnet in net1
|
||||
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()
|
||||
for nw in networks.get('networks'):
|
||||
@ -281,13 +284,26 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
ext_mngd_net_id, _ = \
|
||||
self._create_network("external_managed_internal_net")
|
||||
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.
|
||||
networks = self.neutronclient().list_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
|
||||
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
|
||||
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
|
||||
|
||||
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):
|
||||
rollback_url = os.path.join(
|
||||
self.base_vnf_lcm_op_occs_url,
|
||||
@ -1140,18 +1166,18 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
self.fail("Failed, create network=<%s>, %s" %
|
||||
(uniq_name, e))
|
||||
|
||||
def _create_subnet(self, network):
|
||||
cidr_prefix = "22.22.{}".format(str(len(self.ext_subnets)))
|
||||
def _create_subnet(self, network, cidr, gateway):
|
||||
body = {'subnet': {'network_id': network['id'],
|
||||
'name': "subnet-%s" % uuidutils.generate_uuid(),
|
||||
'cidr': "{}.0/24".format(cidr_prefix),
|
||||
'cidr': "{}".format(cidr),
|
||||
'ip_version': 4,
|
||||
'gateway_ip': "{}.1".format(cidr_prefix),
|
||||
'gateway_ip': "{}".format(gateway),
|
||||
"enable_dhcp": True}}
|
||||
|
||||
try:
|
||||
subnet = self.neutronclient().create_subnet(body=body)["subnet"]
|
||||
self.addCleanup(self._delete_subnet, subnet['id'])
|
||||
print("Create subnet success, %s" % subnet['id'], flush=True)
|
||||
return subnet['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create subnet for net_id=<%s>, %s" %
|
||||
|
@ -40,7 +40,8 @@ class Subscription:
|
||||
"SCALE",
|
||||
"TERMINATE",
|
||||
"HEAL",
|
||||
"MODIFY_INFO"
|
||||
"MODIFY_INFO",
|
||||
"CHANGE_EXT_CONN"
|
||||
]
|
||||
},
|
||||
"callbackUri": callback_uri
|
||||
@ -373,3 +374,56 @@ class VnfInstances:
|
||||
"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,
|
||||
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):
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
@ -1684,3 +1726,146 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
self.assertIsNotNone(_links.get('rollback').get('href'))
|
||||
if _links.get('grant') is not None:
|
||||
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
|
||||
|
||||
@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
|
||||
def _make_vim_assets(image_id, flavour_id="1"):
|
||||
# set m1.tiny="1" for flavour_id
|
||||
@ -203,3 +214,17 @@ class Grant:
|
||||
request_body['removeResources'])
|
||||
|
||||
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):
|
||||
|
||||
def _register_vnf_package_mock_response(self):
|
||||
def _register_vnf_package_mock_response(self, package_dir="functional6"):
|
||||
"""Prepare VNF package for test.
|
||||
|
||||
Register VNF package response to fake NFVO server and Cleanups.
|
||||
@ -32,7 +32,7 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||
Response: VNF Package information
|
||||
"""
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = "functional6"
|
||||
sample_name = package_dir
|
||||
csar_package_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
@ -92,6 +92,152 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||
|
||||
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):
|
||||
"""Test basic life cycle operations with sample VNFD with UserData.
|
||||
|
||||
@ -315,3 +461,64 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||
self.assertEqual(
|
||||
'{} {}'.format(expected_auth_type, expected_token_value),
|
||||
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 tacker.common import utils as common_utils
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
from tacker.objects import scale_vnf_request
|
||||
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)
|
||||
|
||||
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["descriptor_version"] = vnf_data.pop("vnfd_version")
|
||||
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()
|
||||
|
178
tacker/tests/unit/objects/test_change_ext_conn_req.py
Normal file
178
tacker/tests/unit/objects/test_change_ext_conn_req.py
Normal file
@ -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'))
|
251
tacker/tests/unit/objects/test_grant.py
Normal file
251
tacker/tests/unit/objects/test_grant.py
Normal file
@ -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
|
||||
|
||||
from tacker.api.vnflcm.v1.router import VnflcmAPIRouter
|
||||
from tacker.common import utils
|
||||
from tacker import context
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
from tacker import objects
|
||||
from tacker.objects.change_ext_conn_req import ChangeExtConnRequest
|
||||
from tacker.objects import fields
|
||||
from tacker.objects.instantiate_vnf_req import ExtManagedVirtualLinkData
|
||||
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" %
|
||||
vnf_instance_id},
|
||||
"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
|
||||
|
||||
@ -1598,3 +1603,62 @@ def return_vnf_lcm_opoccs_list():
|
||||
obj = objects.VnfLcmOpOcc(**vnf_lcm_op_occs)
|
||||
|
||||
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_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")
|
||||
if 'get_rollback_ids' in args:
|
||||
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):
|
||||
@ -2900,3 +2908,348 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
||||
vnf_instance,
|
||||
operation_params)
|
||||
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
|
||||
|
||||
|
||||
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',
|
||||
instantiation_level_id=None, vnfc_resource_info=None,
|
||||
virtual_storage_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 []
|
||||
vnf_virtual_link_resource_info = vnf_virtual_link_resource_info or []
|
||||
virtual_storage_resource_info = virtual_storage_resource_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,
|
||||
instantiation_level_id=instantiation_level_id,
|
||||
@ -237,7 +305,9 @@ def get_vnf_instantiated_info(flavour_id='simple',
|
||||
vnfc_resource_info=vnfc_resource_info,
|
||||
vnf_virtual_link_resource_info=vnf_virtual_link_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
|
||||
|
||||
@ -332,6 +402,162 @@ def get_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",
|
||||
error_point=0):
|
||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc(
|
||||
|
@ -2178,3 +2178,126 @@ class TestOpenStack(base.FixturedTestCase):
|
||||
None, self.context, vnf_dict, 'SP1', None, None)
|
||||
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
"""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
|
||||
|
||||
|
||||
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):
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
if not ext_virtual_link.ext_link_ports:
|
||||
return
|
||||
@ -926,6 +1004,38 @@ def _set_ext_virtual_link_info(instantiate_vnf_req, ext_cp_info):
|
||||
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):
|
||||
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
|
||||
|
||||
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,
|
||||
operation_params,
|
||||
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
|
||||
"""
|
||||
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:
|
||||
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,
|
||||
plugin,
|
||||
context,
|
||||
|
@ -104,3 +104,15 @@ class VnfNoop(abstract_driver.VnfAbstractDriver):
|
||||
def post_heal_vnf(self, context, vnf_instance, vim_connection_info,
|
||||
heal_vnf_request):
|
||||
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
|
||||
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,
|
||||
stack_resources, resource_name,
|
||||
vim_connection_info):
|
||||
@ -2033,3 +2018,101 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||
return_rs_list = before_rs_list
|
||||
|
||||
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,
|
||||
grant_request, **kwargs):
|
||||
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,
|
||||
grant_request, **kwargs):
|
||||
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…
x
Reference in New Issue
Block a user