Support Rollback of LCM Resource

Supported rollback LCM operation

Implements: blueprint support-etsi-nfv-specs
Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/support-etsi-nfv-based-errorhandling.html

Change-Id: Ic5701c6c1379ee6e08515bf3086da39d75160f82
(cherry picked from commit 4543b961eb)
This commit is contained in:
Aldinson Esto 2020-08-27 21:00:12 +09:00 committed by Toshiaki Takahashi
parent afa192c984
commit c70200423d
16 changed files with 2210 additions and 56 deletions

View File

@ -777,6 +777,39 @@ Response Example
.. literalinclude:: samples/vnflcm/show-vnflcm-operation-occurrence-response.json .. literalinclude:: samples/vnflcm/show-vnflcm-operation-occurrence-response.json
:language: javascript :language: javascript
Roll back a VNF lifecycle operation
===================================
.. rest_method:: POST /vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}/rollback
The POST method initiates rolling back a VNF lifecycle operation if that operation has experienced a temporary failure,
i.e. the related "Individual VNF LCM operation occurrence" resource is in "FAILED_TEMP" state.
In case of success of processing the asynchronous request, the "operationState" attribute in the representation of the
parent resource shall be changed to "ROLLING_BACK" and the applicable "start" notification
shall be emitted to indicate that rollback of the underlying VNF LCM operation occurrence is attempted.
Response Codes
--------------
.. rest_status_code:: success status.yaml
- 202
.. rest_status_code:: error status.yaml
- 401
- 403
- 404
- 409
Request Parameters
------------------
.. rest_parameters:: parameters_vnflcm.yaml
- vnfLcmOpOccId: vnf_lcm_op_occ_id
Create a new subscription Create a new subscription
========================= =========================

View File

@ -1116,6 +1116,90 @@ class VnfLcmController(wsgi.Controller):
return self._make_problem_detail( return self._make_problem_detail(
str(e), 500, title='Internal Server Error') str(e), 500, title='Internal Server Error')
def _rollback(
self,
context,
vnf_info,
vnf_instance,
vnf_lcm_op_occs,
operation_params):
self.rpc_api.rollback(
context,
vnf_info,
vnf_instance,
operation_params)
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
vnflcm_url = CONF.vnf_lcm.endpoint_url + \
"/vnflcm/v1/vnf_lcm_op_occs/" + vnf_lcm_op_occs.id
res = webob.Response()
res.status_int = 202
location = ('Location', vnflcm_url)
res.headerlist.append(location)
return res
def _get_rollback_vnf(self, context, vnf_instance_id):
return self._vnfm_plugin.get_vnf(context, vnf_instance_id)
@wsgi.response(http_client.ACCEPTED)
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN,
http_client.NOT_FOUND, http_client.CONFLICT))
def rollback(self, request, id):
context = request.environ['tacker.context']
context.can(vnf_lcm_policies.VNFLCM % 'rollback')
try:
vnf_lcm_op_occs = objects.VnfLcmOpOcc.get_by_id(context, id)
if vnf_lcm_op_occs.operation_state != 'FAILED_TEMP':
return self._make_problem_detail(
'OperationState IS NOT FAILED_TEMP',
409,
title='OperationState IS NOT FAILED_TEMP')
if vnf_lcm_op_occs.operation != 'INSTANTIATION' \
and vnf_lcm_op_occs.operation != 'SCALE':
return self._make_problem_detail(
'OPERATION IS NOT INSTANTIATION/SCALE',
409,
title='OPERATION IS NOT INSTANTIATION/SCALE')
operation_params = jsonutils.loads(
vnf_lcm_op_occs.operation_params)
if vnf_lcm_op_occs.operation == 'SCALE' \
and operation_params['type'] == 'SCALE_IN':
return self._make_problem_detail(
'SCALE_IN CAN NOT ROLLBACK', 409,
title='SCALE_IN CAN NOT ROLLBACK')
vnf_info = self._get_rollback_vnf(
context, vnf_lcm_op_occs.vnf_instance_id)
vnf_instance = self._get_vnf_instance(
context, vnf_lcm_op_occs.vnf_instance_id)
vnf_lcm_op_occs.changed_info = None
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
return self._rollback(
context,
vnf_info,
vnf_instance,
vnf_lcm_op_occs,
operation_params)
except vnfm.VNFNotFound as vnf_e:
return self._make_problem_detail(
str(vnf_e), 404, title='VNF NOT FOUND')
except exceptions.NotFound as occ_e:
return self._make_problem_detail(
str(occ_e), 404, title='VNF NOT FOUND')
except webob.exc.HTTPNotFound as inst_e:
return self._make_problem_detail(
str(inst_e), 404, title='VNF NOT FOUND')
except Exception as e:
LOG.error(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
def _make_problem_detail( def _make_problem_detail(
self, self,
detail, detail,

View File

@ -112,6 +112,13 @@ class VnflcmAPIRouter(wsgi.Router):
"/vnf_instances/{id}/scale", "/vnf_instances/{id}/scale",
methods, controller, default_resource) methods, controller, default_resource)
# Allowed methods on
# {apiRoot}/vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}/rollback resource
methods = {"POST": "rollback"}
self._setup_route(mapper,
"/vnf_lcm_op_occs/{id}/rollback",
methods, controller, default_resource)
methods = {"GET": "subscription_list", "POST": "register_subscription"} methods = {"GET": "subscription_list", "POST": "register_subscription"}
self._setup_route(mapper, "/subscriptions", self._setup_route(mapper, "/subscriptions",
methods, controller, default_resource) methods, controller, default_resource)

View File

@ -1368,6 +1368,7 @@ class Conductor(manager.Manager):
kwargs.get('is_automatic_invocation', False) kwargs.get('is_automatic_invocation', False)
error = kwargs.get('error', None) error = kwargs.get('error', None)
# Used for timing control when a failure occurs # Used for timing control when a failure occurs
error_point = kwargs.get('error_point', 0)
if old_vnf_instance: if old_vnf_instance:
vnf_instance_id = old_vnf_instance.id vnf_instance_id = old_vnf_instance.id
@ -1381,6 +1382,7 @@ class Conductor(manager.Manager):
vnf_notif = self._get_vnf_notify(context, vnf_lcm_op_occs_id) vnf_notif = self._get_vnf_notify(context, vnf_lcm_op_occs_id)
vnf_notif.operation_state = operation_state vnf_notif.operation_state = operation_state
if operation_state == fields.LcmOccsOperationState.FAILED_TEMP: if operation_state == fields.LcmOccsOperationState.FAILED_TEMP:
vnf_notif.error_point = error_point
error_details = objects.ProblemDetails( error_details = objects.ProblemDetails(
context=context, context=context,
status=500, status=500,
@ -1543,6 +1545,8 @@ class Conductor(manager.Manager):
instantiate_vnf, instantiate_vnf,
vnf_lcm_op_occs_id): vnf_lcm_op_occs_id):
vnf_dict['error_point'] = 1
self._instantiate_grant(context, self._instantiate_grant(context,
vnf_instance, vnf_instance,
vnf_dict, vnf_dict,
@ -1565,12 +1569,15 @@ class Conductor(manager.Manager):
self._change_vnf_status(context, vnf_instance.id, self._change_vnf_status(context, vnf_instance.id,
_INACTIVE_STATUS, 'PENDING_CREATE') _INACTIVE_STATUS, 'PENDING_CREATE')
vnf_dict['error_point'] = 3
self.vnflcm_driver.instantiate_vnf(context, vnf_instance, self.vnflcm_driver.instantiate_vnf(context, vnf_instance,
vnf_dict, instantiate_vnf) vnf_dict, instantiate_vnf)
vnf_dict['error_point'] = 5
self._build_instantiated_vnf_info(context, self._build_instantiated_vnf_info(context,
vnf_instance, vnf_instance,
instantiate_vnf_req=instantiate_vnf) instantiate_vnf_req=instantiate_vnf)
vnf_dict['error_point'] = 7
self._update_vnf_attributes(context, vnf_dict, self._update_vnf_attributes(context, vnf_dict,
_PENDING_STATUS, _ACTIVE_STATUS) _PENDING_STATUS, _ACTIVE_STATUS)
self.vnflcm_driver._vnf_instance_update(context, vnf_instance, self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
@ -1604,7 +1611,8 @@ class Conductor(manager.Manager):
vnf_instance=vnf_instance, vnf_instance=vnf_instance,
request_obj=instantiate_vnf, request_obj=instantiate_vnf,
operation_state=fields.LcmOccsOperationState.FAILED_TEMP, operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
error=str(ex) error=str(ex),
error_point=vnf_dict['error_point']
) )
@coordination.synchronized('{vnf_instance[id]}') @coordination.synchronized('{vnf_instance[id]}')
@ -1887,6 +1895,11 @@ class Conductor(manager.Manager):
notification_data['changed_info'] = changed_info.to_dict() notification_data['changed_info'] = changed_info.to_dict()
self.send_notification(context, notification_data) self.send_notification(context, notification_data)
@coordination.synchronized('{vnf_instance[id]}')
def rollback(self, context, vnf_info, vnf_instance, operation_params):
self.vnflcm_driver.rollback_vnf(context, vnf_info,
vnf_instance, operation_params)
def init(args, **kwargs): def init(args, **kwargs):
CONF(args=args, project='tacker', CONF(args=args, project='tacker',

View File

@ -112,3 +112,16 @@ class VNFLcmRPCAPI(object):
rpc_method = cctxt.cast if cast else cctxt.call rpc_method = cctxt.cast if cast else cctxt.call
return rpc_method(context, 'send_notification', return rpc_method(context, 'send_notification',
notification=notification) notification=notification)
def rollback(self, context, vnf_info, vnf_instance,
operation_params, 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, 'rollback',
vnf_info=vnf_info,
vnf_instance=vnf_instance,
operation_params=operation_params)

View File

@ -865,3 +865,87 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
update({ update({
'resource': placement_obj.resource, 'resource': placement_obj.resource,
'updated_at': timeutils.utcnow()})) 'updated_at': timeutils.utcnow()}))
def update_vnf_rollback_status_err(self,
context,
vnf_info):
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.operation == 'SCALE':
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state='ERROR',
evt_type=constants.RES_EVT_SCALE,
tstamp=timeutils.utcnow())
else:
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state='ERROR',
evt_type=constants.RES_EVT_CREATE,
tstamp=timeutils.utcnow())
def _update_vnf_rollback_pre(self,
context,
vnf_info):
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.operation == 'SCALE':
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state='ROLL_BACK',
evt_type=constants.RES_EVT_SCALE,
tstamp=timeutils.utcnow())
else:
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state='ROLL_BACK',
evt_type=constants.RES_EVT_CREATE,
tstamp=timeutils.utcnow())
def _update_vnf_rollback(self,
context,
vnf_info,
previous_statuses,
status,
vnf_instance=None,
vnf_lcm_op_occ=None):
with context.session.begin(subtransactions=True):
timestamp = timeutils.utcnow()
(self._model_query(context, VNF).
filter(VNF.id == vnf_info['id']).
filter(VNF.status == previous_statuses).
update({'status': status,
'updated_at': timestamp}))
dev_attrs = vnf_info.get('attributes', {})
(context.session.query(VNFAttribute).
filter(VNFAttribute.vnf_id == vnf_info['id']).
filter(~VNFAttribute.key.in_(dev_attrs.keys())).
delete(synchronize_session='fetch'))
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.operation == 'SCALE':
for (key, value) in dev_attrs.items():
if 'vim_auth' not in key:
self._vnf_attribute_update_or_create(
context, vnf_info['id'], key, value)
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state=status,
evt_type=constants.RES_EVT_SCALE,
tstamp=timestamp)
else:
self._cos_db_plg.create_event(
context, res_id=vnf_info['id'],
res_type=constants.RES_TYPE_VNF,
res_state=status,
evt_type=constants.RES_EVT_CREATE,
tstamp=timestamp)
if vnf_lcm_op_occ:
vnf_lcm_op_occ.state_entered_time = timestamp
vnf_lcm_op_occ.save()
if vnf_instance:
vnf_instance.save()

View File

@ -132,6 +132,17 @@ rules = [
} }
] ]
), ),
policy.DocumentedRuleDefault(
name=VNFLCM % 'rollback',
check_str=base.RULE_ADMIN_OR_OWNER,
description="Rollback a VNF instance.",
operations=[
{
'method': 'POST',
'path': '/vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}/rollback'
}
]
),
] ]

View File

@ -836,6 +836,252 @@ def vnf_scale():
vim_id=uuidsentinel.vim_id) vim_id=uuidsentinel.vim_id)
def vnflcm_rollback(error_point=7):
return objects.VnfLcmOpOcc(
state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
start_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
vnf_instance_id=uuidsentinel.vnf_instance_id,
operation='SCALE',
operation_state='FAILED_TEMP',
is_automatic_invocation=False,
operation_params='{"type": "SCALE_OUT", "aspect_id": "SP1"}',
error_point=error_point,
id=constants.UUID,
created_at=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC))
def vnflcm_rollback_insta(error_point=7):
return objects.VnfLcmOpOcc(
state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
start_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
vnf_instance_id=uuidsentinel.vnf_instance_id,
operation='INSTANTIATION',
operation_state='FAILED_TEMP',
is_automatic_invocation=False,
operation_params='{}',
error_point=error_point,
id=constants.UUID,
created_at=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC))
def vnflcm_rollback_active():
return objects.VnfLcmOpOcc(
state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
start_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
vnf_instance_id=uuidsentinel.vnf_instance_id,
operation='SCALE',
operation_state='ACTIVE',
is_automatic_invocation=False,
operation_params='{"type": "SCALE_OUT", "aspect_id": "SP1"}',
error_point=7,
id=constants.UUID,
created_at=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC))
def vnflcm_rollback_ope():
return objects.VnfLcmOpOcc(
state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
start_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
vnf_instance_id=uuidsentinel.vnf_instance_id,
operation='HEAL',
operation_state='FAILED_TEMP',
is_automatic_invocation=False,
operation_params='{}',
error_point=7,
id=constants.UUID,
created_at=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC))
def vnflcm_rollback_scale_in():
return objects.VnfLcmOpOcc(
state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
start_time=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC),
vnf_instance_id=uuidsentinel.vnf_instance_id,
operation='SCALE',
operation_state='FAILED_TEMP',
is_automatic_invocation=False,
operation_params='{"type": "SCALE_IN", "aspect_id": "SP1"}',
error_point=7,
id=constants.UUID,
created_at=datetime.datetime(2000, 1, 1, 1, 1, 1,
tzinfo=iso8601.UTC))
def vnf_rollback():
return tacker.db.vnfm.vnfm_db.VNF(id=constants.UUID,
vnfd_id=uuidsentinel.vnfd_id,
name='test',
status='ERROR',
vim_id=uuidsentinel.vim_id)
def vnf_dict():
heat_temp = 'heat_template_version: ' + \
'2013-05-23\ndescription: \'VNF Descriptor (TEST)' + \
'\n\n \'\nparameters:\n current_num:\n type: ' + \
'number\n nfv:\n type: json\nresources:\n ' + \
'SP1_scale_out:\n type: OS::Heat::ScalingPolicy\n' + \
' properties:\n auto_scaling_group_id: ' + \
'{get_resource: SP1_group}\n adjustment_type: ' + \
'change_in_capacity\n scaling_adjustment: 1\n ' + \
'SP1_group:\n type: OS::Heat::AutoScalingGroup\n ' + \
'properties:\n min_size: 0\n desired_capacity:' + \
' {get_param: current_num}\n resource:\n ' + \
'type: SP1_res.yaml\n properties:\n nfv:' + \
' {get_param: nfv}\n max_size: 3\n SP1_scale_in:\n' + \
' type: OS::Heat::ScalingPolicy\n properties:\n' + \
' auto_scaling_group_id: {get_resource: SP1_group}\n' + \
' adjustment_type: change_in_capacity\n ' + \
'scaling_adjustment: -1\noutputs: {}\n'
scale_g = '{\"scaleGroupDict\": { \"SP1\": { \"vdu\":' + \
' [\"VDU1\"], \"num\": 1, \"maxLevel\": 3, \"initialNum\":' + \
' 0, \"initialLevel\": 0, \"default\": 0 }}}'
vnfd = 'tosca_definitions_version: ' + \
'tosca_simple_yaml_1_2\n\ndescription: Simple deployment' + \
' flavour for Sample VNF\n\nimports:\n' + \
' - etsi_nfv_sol001_common_types.yaml\n' + \
' - etsi_nfv_sol001_vnfd_types.yaml\n\n' + \
'topology_template:\n node_templates:\n' + \
' VNF:\n type: nec.ossmano.VNF\n' + \
' properties:\n' + \
' flavour_description: A simple flavour\n' + \
' interfaces:\n Vnflcm:\n' + \
' scale_start: noop\n' + \
' scale: scale_standard\n' + \
' scale_end: noop\n artifacts:\n' + \
' hot:\n' + \
' type: tosca.artifacts.Implementation.nfv.Hot\n' + \
' file: ../Files/scale.yaml\n hot-nest:\n' + \
' type: tosca.artifacts.Implementation.nfv.Hot\n' + \
' file: ../Files/SP1_res.yaml\n' + \
' properties:\n nest: "True"\n\n' + \
' VDU1:\n type: tosca.nodes.nfv.Vdu.Compute\n' + \
' properties:\n name: VDU1\n' + \
' description: VDU1 compute node\n' + \
' vdu_profile:\n' + \
' min_number_of_instances: 1\n' + \
' max_number_of_instances: 3\n\n' + \
' capabilities:\n virtual_compute:\n' + \
' properties:\n virtual_memory:\n' + \
' virtual_mem_size: 512 MB\n' + \
' virtual_cpu:\n' + \
' num_virtual_cpu: 1\n' + \
' virtual_local_storage:\n' + \
' - size_of_storage: 1 GB\n' + \
' requirements:\n' + \
' - virtual_storage: VirtualStorage\n\n' + \
' VirtualStorage:\n' + \
' type: tosca.nodes.nfv.Vdu.VirtualBlockStorage\n' + \
' properties:\n virtual_block_storage_data:\n' + \
' size_of_storage: 1 GB\n' + \
' rdma_enabled: true\n sw_image_data:\n' + \
' name: VirtualStorage\n' + \
' version: \'0.4.0\'\n checksum:\n' + \
' algorithm: sha-512\n' + \
' hash: 6513f21e44aa3da349f248188a44bc304a3' + \
'653a04122d8fb4535423c8e1d14cd6a153f735bb0982e2161b5b5' + \
'186106570c17a9e58b64dd39390617cd5a350f78\n' + \
' container_format: bare\n' + \
' disk_format: qcow2\n' + \
' min_disk: 2 GB\n' + \
' min_ram: 256 MB\n' + \
' size: 1 GB\n\n CP1:\n' + \
' type: tosca.nodes.nfv.VduCp\n' + \
' properties:\n layer_protocols: [ ipv4 ]\n' + \
' order: 2\n requirements:\n' + \
' - virtual_binding: VDU1\n' + \
' - virtual_link: internalVL1\n\n' + \
' internalVL1:\n' + \
' type: tosca.nodes.nfv.VnfVirtualLink\n' + \
' properties:\n connectivity_type:\n' + \
' layer_protocols: [ ipv4 ]\n' + \
' description: Internal Virtual link in the VNF\n' + \
' vl_profile:\n' + \
' max_bitrate_requirements:\n' + \
' root: 1048576\n' + \
' leaf: 1048576\n' + \
' min_bitrate_requirements:\n' + \
' root: 1048576\n leaf: 1048576\n' + \
' virtual_link_protocol_data:\n' + \
' - associated_layer_protocol: ipv4\n' + \
' l3_protocol_data:\n' + \
' ip_version: ipv4\n' + \
' cidr: 33.33.0.0/24\n\n policies:\n' + \
' - scaling_aspects:\n' + \
' type: tosca.policies.nfv.ScalingAspects\n' + \
' properties:\n aspects:\n' + \
' SP1:\n name: SP1_aspect\n' + \
' description: SP1 scaling aspect\n' + \
' max_scale_level: 2\n' + \
' step_deltas:\n' + \
' - delta_1\n\n' + \
' - VDU1_initial_delta:\n' + \
' type: tosca.policies.nfv.VduInitialDelta\n' + \
' properties:\n initial_delta:\n' + \
' number_of_instances: 0\n' + \
' targets: [ VDU1 ]\n\n' + \
' - VDU1_scaling_aspect_deltas:\n' + \
' type: tosca.policies.nfv.VduScalingAspectDeltas\n' + \
' properties:\n aspect: SP1\n' + \
' deltas:\n delta_1:\n' + \
' number_of_instances: 1\n' + \
' targets: [ VDU1 ]\n\n' + \
' - instantiation_levels:\n' + \
' type: tosca.policies.nfv.InstantiationLevels\n' + \
' properties:\n levels:\n' + \
' instantiation_level_1:\n' + \
' description: Smallest size\n' + \
' scale_info:\n SP1:\n' + \
' scale_level: 0\n' + \
' instantiation_level_2:\n' + \
' description: Largest size\n' + \
' scale_info:\n SP1:\n' + \
' scale_level: 3\n' + \
' default_level: instantiation_level_1\n\n' + \
' - VDU1_instantiation_levels:\n' + \
' type: tosca.policies.nfv.VduInstantiationLevels\n' + \
' properties:\n levels:\n' + \
' instantiation_level_1:\n' + \
' number_of_instances: 0\n' + \
' instantiation_level_2:\n' + \
' number_of_instances: 3\n' + \
' targets: [ VDU1 ]\n'
vnf_dict = {
'attributes': {
'heat_template': heat_temp,
'scale_group': scale_g
},
'status': 'ERROR',
'vnfd_id': '576acf48-b9df-491d-a57c-342de660ec78',
'tenant_id': '13d2ca8de70d48b2a2e0dbac2c327c0b',
'vim_id': '3f41faa7-5630-47d2-9d4a-1216953c8887',
'instance_id': 'd1121d3c-368b-4ac2-b39d-835aa3e4ccd8',
'placement_attr': {'vim_name': 'openstack-vim'},
'id': 'a27fc58e-66ae-4031-bba4-efede318c60b',
'name': 'vnf_create_1',
'vnfd': {
'attributes': {
'vnfd_simple': vnfd
}
}
}
return vnf_dict
class InjectContext(wsgi.Middleware): class InjectContext(wsgi.Middleware):
"""Add a 'tacker.context' to WSGI environ.""" """Add a 'tacker.context' to WSGI environ."""

View File

@ -2535,7 +2535,7 @@ class TestController(base.TestCase):
@mock.patch.object(TackerManager, 'get_service_plugins', @mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()}) return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.ScaleVnfRequest, "obj_from_primitive") @mock.patch.object(objects.ScaleVnfRequest, "obj_from_primitive")
@mock.patch.object(tacker.db.vnfm.vnfm_db.VNFMPluginDb, "get_vnf") @mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
@mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(objects.VnfInstance, "get_by_id")
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "send_notification") @mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfLcmOpOcc, "create") @mock.patch.object(objects.VnfLcmOpOcc, "create")
@ -2594,3 +2594,223 @@ class TestController(base.TestCase):
'STARTING') 'STARTING')
self.assertEqual(mock_send_notification.call_args[0][1].get( self.assertEqual(mock_send_notification.call_args[0][1].get(
'isAutomaticInvocation'), 'False') 'isAutomaticInvocation'), 'False')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
@mock.patch.object(objects.VnfInstance, "get_by_id")
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "rollback")
def test_rollback(
self,
mock_rollback,
mock_vnf_instance,
mock_get_vnf,
mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
vnf_obj = fakes.vnf_rollback()
mock_get_vnf.return_value = vnf_obj
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.NOT_INSTANTIATED,
task_state=fields.VnfInstanceTaskState.ERROR)
mock_vnf_instance.return_value = vnf_instance
resp = req.get_response(self.app)
self.assertEqual(http_client.ACCEPTED, resp.status_code)
mock_rollback.assert_called_once()
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
@mock.patch.object(objects.VnfInstance, "get_by_id")
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "rollback")
def test_rollback_2(
self,
mock_rollback,
mock_vnf_instance,
mock_get_vnf,
mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
vnf_obj = fakes.vnf_rollback()
mock_get_vnf.return_value = vnf_obj
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.NOT_INSTANTIATED,
task_state=fields.VnfInstanceTaskState.ERROR)
mock_vnf_instance.return_value = vnf_instance
resp = req.get_response(self.app)
self.assertEqual(http_client.ACCEPTED, resp.status_code)
mock_rollback.assert_called_once()
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
def test_rollback_vnf_lcm_op_occs_access_error(self,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
resp = req.get_response(self.app)
self.assertEqual(500, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_rollback_lcm_not_found(self, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % constants.INVALID_UUID)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
mock_lcm_by_id.side_effect = exceptions.NotFound(resource='table',
name='vnf_lcm_op_occs')
resp = req.get_response(self.app)
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_rollback_not_failed_temp(self, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_active()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
resp = req.get_response(self.app)
self.assertEqual(http_client.CONFLICT, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id",)
def test_rollback_not_ope(self, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_ope()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
resp = req.get_response(self.app)
self.assertEqual(http_client.CONFLICT, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_rollback_not_scale_in(self, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_scale_in()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
resp = req.get_response(self.app)
self.assertEqual(http_client.CONFLICT, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_rollback_vnf_error(self, mock_lcm_by_id, mock_get_vnf,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
mock_get_vnf.side_effect = Exception("error")
resp = req.get_response(self.app)
self.assertEqual(500, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
def test_rollback_vnf_not_found(self, mock_get_vnf, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
mock_get_vnf.side_effect = vnfm.VNFNotFound(
vnf_id=uuidsentinel.vnf_instance_id)
resp = req.get_response(self.app)
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
def test_rollback_vnf_instance_error(self, mock_get_vnf, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
vnf_obj = fakes.vnf_rollback()
mock_get_vnf.return_value = vnf_obj
resp = req.get_response(self.app)
self.assertEqual(500, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
@mock.patch.object(controller.VnfLcmController, "_get_rollback_vnf")
@mock.patch.object(objects.VnfInstance, "get_by_id")
def test_rollback_vnf_instance_not_found(
self, mock_vnf_instance, mock_get_vnf, mock_lcm_by_id,
mock_get_service_plugins):
req = fake_request.HTTPRequest.blank(
'/vnf_lcm_op_occs/%s/rollback' % uuidsentinel.vnf_instance_id)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
mock_lcm_by_id.return_value = vnf_lcm_op_occs
vnf_obj = fakes.vnf_rollback()
mock_get_vnf.return_value = vnf_obj
mock_vnf_instance.side_effect = vnfm.VNFNotFound(
vnf_id=uuidsentinel.vnf_instance_id)
resp = req.get_response(self.app)
self.assertEqual(http_client.NOT_FOUND, resp.status_code)

View File

@ -20,12 +20,16 @@ from unittest import mock
import yaml import yaml
from oslo_config import cfg from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
from heatclient.v1 import resources
from tacker.common import driver_manager from tacker.common import driver_manager
from tacker.common import exceptions from tacker.common import exceptions
from tacker.common import utils from tacker.common import utils
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
from tacker import context from tacker import context
from tacker.db.common_services import common_services_db_plugin
from tacker.manager import TackerManager from tacker.manager import TackerManager
from tacker import objects from tacker import objects
from tacker.objects import fields from tacker.objects import fields
@ -36,6 +40,9 @@ from tacker.tests.unit.vnflcm import fakes
from tacker.tests import utils as test_utils from tacker.tests import utils as test_utils
from tacker.tests import uuidsentinel from tacker.tests import uuidsentinel
from tacker.vnflcm import vnflcm_driver from tacker.vnflcm import vnflcm_driver
from tacker.vnfm.infra_drivers.openstack import heat_client
from tacker.vnfm.infra_drivers.openstack import openstack as opn
from tacker.vnfm import plugin
from tacker.vnfm import vim_client from tacker.vnfm import vim_client
@ -125,6 +132,8 @@ class FakeDriverManager(mock.Mock):
if self.fail_method_name and \ if self.fail_method_name and \
self.fail_method_name == 'post_heal_vnf': self.fail_method_name == 'post_heal_vnf':
raise InfraDriverException("post_heal_vnf failed") raise InfraDriverException("post_heal_vnf failed")
if 'get_rollback_ids' in args:
return [], [], ""
class FakeVimClient(mock.Mock): class FakeVimClient(mock.Mock):
@ -308,7 +317,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self.assertEqual(expected_error % vnf_instance_obj.id, str(error)) self.assertEqual(expected_error % vnf_instance_obj.id, str(error))
self.assertEqual("NOT_INSTANTIATED", self.assertEqual("NOT_INSTANTIATED",
vnf_instance_obj.instantiation_state) vnf_instance_obj.instantiation_state)
self.assertEqual(2, mock_vnf_instance_save.call_count) # 2->1 reason: rollback_vnf_instantiated_resources deleted
self.assertEqual(1, mock_vnf_instance_save.call_count)
self.assertEqual(2, self._vnf_manager.invoke.call_count) self.assertEqual(2, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once() mock_final_vnf_dict.assert_called_once()
@ -356,9 +366,11 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self.assertEqual(expected_error % vnf_instance_obj.id, str(error)) self.assertEqual(expected_error % vnf_instance_obj.id, str(error))
self.assertEqual("NOT_INSTANTIATED", self.assertEqual("NOT_INSTANTIATED",
vnf_instance_obj.instantiation_state) vnf_instance_obj.instantiation_state)
self.assertEqual(3, mock_vnf_instance_save.call_count) # 3->1 reason: rollback_vnf_instantiated_resources deleted
self.assertEqual(5, self._vnf_manager.invoke.call_count) self.assertEqual(1, mock_vnf_instance_save.call_count)
mock_final_vnf_dict.assert_called_once() # 5->3 reason: rollback_vnf_instantiated_resources deleted
self.assertEqual(3, self._vnf_manager.invoke.call_count)
shutil.rmtree(fake_csar) shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict') @mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@ -904,3 +916,765 @@ class TestVnflcmDriver(db_base.SqlTestCase):
driver = vnflcm_driver.VnfLcmDriver() driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request, driver.scale(self.context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id) vim_connection_info, scale_name_list, grp_id)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_7(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_6(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta(error_point=6)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_5(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta(error_point=5)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_4(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta(error_point=4)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_3(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta(error_point=3)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_6(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback(error_point=6)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_5(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback(error_point=5)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_4(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback(error_point=4)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
@mock.patch.object(VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_3(
self,
mock_update,
mock_up,
mock_insta_save,
mock_notification,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback(error_point=3)
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.rollback_vnf(
self.context,
vnf_info,
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(objects.VnfLcmOpOcc, "save")
def test_rollback_vnf_save_error(self, mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_lcm_save.side_effect = exceptions.DBAccessError()
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(heat_client.HeatClient, "resource_get")
@mock.patch.object(heat_client.HeatClient, "resource_get_list")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_resource_error(
self,
mock_update,
mock_up,
mock_resource_get_list,
mock_resource_get,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
vnf_info['scale_level'] = 0
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_resource_get.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(heat_client.HeatClient, "resource_get")
@mock.patch.object(heat_client.HeatClient, "resource_get_list")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_resource_list_error(
self,
mock_update,
mock_up,
mock_resource_list,
mock_resource_get,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
resource1 = resources.Resource(None, {
'resource_name': 'SP1_group',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce7',
'id': '1111'
})
mock_resource_get.return_value = resource1
mock_resource_list.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(2, mock_resource_list.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(plugin.VNFMMgmtMixin, "mgmt_call")
@mock.patch.object(opn.OpenStack, "delete")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_delete_error(
self,
mock_update,
mock_up,
mock_delete,
mock_mgmt,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_delete.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(1, mock_delete.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(plugin.VNFMMgmtMixin, "mgmt_call")
@mock.patch.object(opn.OpenStack, "delete")
@mock.patch.object(opn.OpenStack, "delete_wait")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_delete_wait_error(
self,
mock_update,
mock_up,
mock_delete_wait,
mock_delete,
mock_mgmt,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_lcm_op_occs = fakes.vnflcm_rollback_insta()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_delete_wait.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(1, mock_delete.call_count)
self.assertEqual(1, mock_delete_wait.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(heat_client.HeatClient, "resource_get")
@mock.patch.object(heat_client.HeatClient, "resource_get_list")
@mock.patch.object(opn.OpenStack, "get_rollback_ids")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call")
@mock.patch.object(opn.OpenStack, "scale_in_reverse")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_update_error(
self,
mock_update,
mock_up,
mock_scale,
mock_mgmt,
mock_resource_get,
mock_resource_get_list,
mock_resource,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
vnf_info['scale_level'] = 0
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_resource_get.return_value = (
['342bd357-7c4a-438c-9b5b-1f56702137d8'],
['VDU1'],
'49c1cf71-abd4-4fb1-afb3-5f63f3b04246')
mock_scale.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(1, mock_scale.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(heat_client.HeatClient, "resource_get")
@mock.patch.object(heat_client.HeatClient, "resource_get_list")
@mock.patch.object(opn.OpenStack, "get_rollback_ids")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call")
@mock.patch.object(opn.OpenStack, "scale_in_reverse")
@mock.patch.object(opn.OpenStack, "scale_update_wait")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_update_wait_error(
self,
mock_update,
mock_up,
mock_wait,
mock_scale,
mock_mgmt,
mock_resource_get,
mock_resource_get_list,
mock_resource,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
vnf_info['scale_level'] = 0
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_resource_get.return_value = (
['342bd357-7c4a-438c-9b5b-1f56702137d8'],
['VDU1'],
'49c1cf71-abd4-4fb1-afb3-5f63f3b04246')
mock_wait.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(1, mock_scale.call_count)
self.assertEqual(1, mock_wait.call_count)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(common_services_db_plugin.CommonServicesPluginDb,
"create_event")
@mock.patch.object(heat_client.HeatClient, "__init__")
@mock.patch.object(opn.OpenStack, "get_rollback_ids")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call")
@mock.patch.object(opn.OpenStack, "scale_in_reverse")
@mock.patch.object(opn.OpenStack, "scale_update_wait")
@mock.patch.object(opn.OpenStack, "scale_resource_update")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre")
@mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback")
def test_rollback_vnf_scale_resource_get_error(
self,
mock_update,
mock_up,
mock_scale_resource,
mock_wait,
mock_scale,
mock_mgmt,
mock_resource_get,
mock_init,
mock_event,
mock_lcm_save,
mock_get_service_plugins):
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
vnf_instance.instantiated_vnf_info.instance_id =\
uuidsentinel.instance_id
vnf_instance.instantiated_vnf_info.scale_status = []
vnf_instance.instantiated_vnf_info.scale_status.append(
objects.ScaleInfo(aspect_id='SP1', scale_level=0))
vnf_lcm_op_occs = fakes.vnflcm_rollback()
vnf_info = fakes.vnf_dict()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occs
vnf_info['scale_level'] = 0
operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params)
mock_init.return_value = None
mock_resource_get.return_value = (
['342bd357-7c4a-438c-9b5b-1f56702137d8'],
['VDU1'],
'49c1cf71-abd4-4fb1-afb3-5f63f3b04246')
resource1 = resources.Resource(None, {
'resource_name': 'SP1_group',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'UPDATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce7',
'id': '1111'
})
mock_wait.return_value = resource1
mock_scale_resource.side_effect = exceptions.DBAccessError()
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(
exceptions.DBAccessError,
driver.rollback_vnf,
self.context,
vnf_info,
vnf_instance,
operation_params)
self.assertEqual(2, mock_lcm_save.call_count)
self.assertEqual(1, mock_scale.call_count)
self.assertEqual(1, mock_wait.call_count)
self.assertEqual(2, mock_scale_resource.call_count)

View File

@ -35,6 +35,7 @@ from tacker.tests.common import helpers
from tacker.tests import constants from tacker.tests import constants
from tacker.tests.unit import base from tacker.tests.unit import base
from tacker.tests.unit.db import utils from tacker.tests.unit.db import utils
from tacker.tests.unit.vnflcm import fakes
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import client from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import client
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \ from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \
fixture_data_utils as fd_utils fixture_data_utils as fd_utils
@ -1950,3 +1951,97 @@ class TestOpenStack(base.FixturedTestCase):
scale_vnf_request=scale_vnf_request, scale_vnf_request=scale_vnf_request,
region_name=None region_name=None
) )
@mock.patch.object(hc.HeatClient, "resource_get")
@mock.patch.object(hc.HeatClient, "resource_get_list")
def test_get_rollback_ids(self, mock_list, mock_resource):
resource1 = resources.Resource(None, {
'resource_name': 'SP1_group',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce7',
'id': '1111'
})
mock_resource.return_value = resource1
res_list = []
resource2 = resources.Resource(None, {
'resource_name': 'aaaaaaaa',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce8',
'id': '1111'
})
res_list.append(resource2)
resource3 = resources.Resource(None, {
'resource_name': 'bbbbbbbb',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce9',
'id': '1111'
})
res_list.append(resource3)
resource4 = resources.Resource(None, {
'resource_name': 'cccccccc',
'creation_time': '2020-01-01T00:00:01',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce0',
'id': '1111'
})
res_list.append(resource4)
mock_list.return_value = res_list
vnf_dict = fakes.vnf_dict()
vnf_dict['res_num'] = 2
scale_id_list, scale_name_list, grp_id = \
self.openstack.get_rollback_ids(
None, self.context, vnf_dict, 'SP1', None, None)
self.assertEqual('30435eb8-1472-4cbc-abbe-00b395165ce7', grp_id)
@mock.patch.object(hc.HeatClient, "resource_get")
@mock.patch.object(hc.HeatClient, "resource_get_list")
def test_get_rollback_ids_0(self, mock_list, mock_resource):
resource1 = resources.Resource(None, {
'resource_name': 'SP1_group',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce7',
'id': '1111'
})
mock_resource.return_value = resource1
res_list = []
resource2 = resources.Resource(None, {
'resource_name': 'aaaaaaaa',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce8',
'id': '1111'
})
res_list.append(resource2)
resource3 = resources.Resource(None, {
'resource_name': 'bbbbbbbb',
'creation_time': '2020-01-01T00:00:00',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce9',
'id': '1111'
})
res_list.append(resource3)
resource4 = resources.Resource(None, {
'resource_name': 'cccccccc',
'creation_time': '2020-01-01T00:00:01',
'resource_status': 'CREATE_COMPLETE',
'physical_resource_id': '30435eb8-1472-4cbc-abbe-00b395165ce0',
'id': '1111'
})
res_list.append(resource4)
mock_list.return_value = res_list
vnf_dict = fakes.vnf_dict()
vnf_dict['res_num'] = 0
scale_id_list, scale_name_list, grp_id = \
self.openstack.get_rollback_ids(
None, self.context, vnf_dict, 'SP1', None, None)
self.assertEqual('30435eb8-1472-4cbc-abbe-00b395165ce7', grp_id)

View File

@ -37,6 +37,7 @@ from tacker.plugins.common import constants
from tacker.tests.unit.conductor import fakes from tacker.tests.unit.conductor import fakes
from tacker.tests.unit.db import base as db_base from tacker.tests.unit.db import base as db_base
from tacker.tests.unit.db import utils from tacker.tests.unit.db import utils
from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes
from tacker.vnfm import monitor from tacker.vnfm import monitor
from tacker.vnfm import plugin from tacker.vnfm import plugin
@ -1326,3 +1327,53 @@ class TestVNFMPlugin(db_base.SqlTestCase):
self.vnfm_plugin.delete_placement_constraint( self.vnfm_plugin.delete_placement_constraint(
self.context, '7ddc38c3-a116-48b0-bfc1-68d7f306f467') self.context, '7ddc38c3-a116-48b0-bfc1-68d7f306f467')
def test_update_vnf_rollback_pre_scale(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin._update_vnf_rollback_pre(
self.context, vnf_info)
def test_update_vnf_rollback_pre_insta(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback_insta()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin._update_vnf_rollback_pre(
self.context, vnf_info)
def test_update_vnf_rollback_scale(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin._update_vnf_rollback(
self.context, vnf_info,
'ERROR', 'ACTIVE')
def test_update_vnf_rollback_insta(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback_insta()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin._update_vnf_rollback(
self.context, vnf_info,
'ERROR', 'INACTIVE')
def test_update_vnf_rollback_status_err_scale(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin.update_vnf_rollback_status_err(
self.context, vnf_info)
def test_update_vnf_rollback_status_err_insta(self):
vnf_info = {}
vnf_lcm_op_occ = vnflcm_fakes.vnflcm_rollback_insta()
vnf_info['vnf_lcm_op_occ'] = vnf_lcm_op_occ
vnf_info['id'] = uuidutils.generate_uuid()
self.vnfm_plugin.update_vnf_rollback_status_err(
self.context, vnf_info)

View File

@ -47,52 +47,6 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
@utils.expects_func_args('vnf_instance')
def rollback_vnf_instantiated_resources(function):
"""Decorator to rollback resources created during vnf instantiation"""
def _rollback_vnf(vnflcm_driver, context, vnf_instance):
vim_info = vnflcm_utils._get_vim(context,
vnf_instance.vim_connection_info)
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
LOG.info("Rollback vnf %s", vnf_instance.id)
try:
vnflcm_driver._delete_vnf_instance_resources(context, vnf_instance,
vim_connection_info)
if vnf_instance.instantiated_vnf_info:
vnf_instance.instantiated_vnf_info.reinitialize()
vnflcm_driver._vnf_instance_update(context, vnf_instance,
vim_connection_info=[], task_state=None)
LOG.info("Vnf %s rollback completed successfully", vnf_instance.id)
except Exception as ex:
LOG.error("Unable to rollback vnf instance "
"%s due to error: %s", vnf_instance.id, ex)
@functools.wraps(function)
def decorated_function(self, context, *args, **kwargs):
try:
return function(self, context, *args, **kwargs)
except Exception as exp:
with excutils.save_and_reraise_exception():
wrapped_func = safe_utils.get_wrapped_function(function)
keyed_args = inspect.getcallargs(wrapped_func, self, context,
*args, **kwargs)
vnf_instance = keyed_args['vnf_instance']
LOG.error("Failed to instantiate vnf %(id)s. Error: %(error)s",
{"id": vnf_instance.id,
"error": six.text_type(exp)})
_rollback_vnf(self, context, vnf_instance)
return decorated_function
@utils.expects_func_args('vnf_info', 'vnf_instance', 'scale_vnf_request') @utils.expects_func_args('vnf_info', 'vnf_instance', 'scale_vnf_request')
def revert_to_error_scale(function): def revert_to_error_scale(function):
"""Decorator to revert task_state to error on failure.""" """Decorator to revert task_state to error on failure."""
@ -218,6 +172,116 @@ def revert_to_error_task_state(function):
return decorated_function return decorated_function
@utils.expects_func_args('vnf_info', 'vnf_instance', 'operation_params')
def revert_to_error_rollback(function):
"""Decorator to revert task_state to error on failure."""
@functools.wraps(function)
def decorated_function(self, context, *args, **kwargs):
try:
return function(self, context, *args, **kwargs)
except Exception as ex:
with excutils.save_and_reraise_exception():
wrapped_func = safe_utils.get_wrapped_function(function)
keyed_args = inspect.getcallargs(wrapped_func, self, context,
*args, **kwargs)
resource_changes = None
try:
vnf_info = keyed_args['vnf_info']
vnf_instance = keyed_args['vnf_instance']
operation_params = keyed_args['operation_params']
vim_info = vnflcm_utils._get_vim(context,
vnf_instance.vim_connection_info)
vim_connection_info =\
objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_info.get('resource_changes'):
resource_changes = vnf_info.get('resource_changes')
else:
if vnf_lcm_op_occs.operation == 'SCALE':
scale_vnf_request =\
objects.ScaleVnfRequest.obj_from_primitive(
operation_params, context=context)
scale_vnf_request_copy = \
copy.deepcopy(scale_vnf_request)
scale_vnf_request_copy.type = 'SCALE_IN'
resource_changes = self._scale_resource_update(
context,
vnf_info,
vnf_instance,
scale_vnf_request_copy,
vim_connection_info,
error=True)
else:
resource_changes = self._term_resource_update(
context,
vnf_info,
vnf_instance)
except Exception as e:
LOG.warning(traceback.format_exc())
LOG.warning("Failed to scale resource update "
"instance %(id)s. Error: %(error)s",
{"id": vnf_instance.id, "error": e})
try:
self._update_vnf_rollback_status_err(context, vnf_info)
except Exception as e:
LOG.warning("Failed to revert scale info for event "
"instance %(id)s. Error: %(error)s",
{"id": vnf_instance.id, "error": e})
try:
self._vnf_instance_update(context, vnf_instance)
except Exception as e:
LOG.warning("Failed to revert instantiation info for vnf "
"instance %(id)s. Error: %(error)s",
{"id": vnf_instance.id, "error": e})
problem = objects.ProblemDetails(status=500,
detail=str(ex))
try:
timestamp = datetime.utcnow()
vnf_lcm_op_occ = vnf_info['vnf_lcm_op_occ']
vnf_lcm_op_occ.operation_state = 'FAILED_TEMP'
vnf_lcm_op_occ.state_entered_time = timestamp
if resource_changes:
vnf_lcm_op_occ.resource_changes = resource_changes
vnf_lcm_op_occ.error = problem
vnf_lcm_op_occ.save()
except Exception as e:
LOG.warning("Failed to update vnf_lcm_op_occ for vnf "
"instance %(id)s. Error: %(error)s",
{"id": vnf_instance.id, "error": e})
try:
notification = vnf_info['notification']
notification['notificationStatus'] = 'RESULT'
notification['operationState'] = 'FAILED_TEMP'
notification['error'] = problem.to_dict()
if resource_changes:
resource_dict = resource_changes.to_dict()
if resource_dict.get('affected_vnfcs'):
notification['affectedVnfcs'] = \
jsonutils.dump_as_bytes(
resource_dict.get('affected_vnfcs'))
if resource_dict.get('affected_virtual_links'):
notification['affectedVirtualLinks'] = \
jsonutils.dump_as_bytes(
resource_dict.get(
'affected_virtual_links'))
if resource_dict.get('affected_virtual_storages'):
notification['affectedVirtualStorages'] = \
jsonutils.dump_as_bytes(
resource_dict.get(
'affected_virtual_storages'))
self.rpc_api.sendNotification(context, notification)
except Exception as e:
LOG.warning("Failed to revert scale info for vnf "
"instance %(id)s. Error: %(error)s",
{"id": vnf_instance.id, "error": e})
return decorated_function
class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
def __init__(self): def __init__(self):
@ -321,7 +385,6 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
error=encodeutils.exception_to_unicode(exp)) error=encodeutils.exception_to_unicode(exp))
@log.log @log.log
@rollback_vnf_instantiated_resources
def instantiate_vnf(self, context, vnf_instance, vnf_dict, def instantiate_vnf(self, context, vnf_instance, vnf_dict,
instantiate_vnf_req): instantiate_vnf_req):
@ -589,8 +652,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
return scale_id_list, scale_name_list, grp_id return scale_id_list, scale_name_list, grp_id
def _get_node_template_for_vnf(self, vnfd_dict): def _get_node_template_for_vnf(self, vnfd_dict):
for node_template in vnfd_dict['topology_template']['\ node_tmp = vnfd_dict['topology_template']['node_templates']
node_templates'].values(): for node_template in node_tmp.values():
LOG.debug("node_template %s", node_template) LOG.debug("node_template %s", node_template)
if not re.match('^tosca', node_template['type']): if not re.match('^tosca', node_template['type']):
LOG.debug("VNF node_template %s", node_template) LOG.debug("VNF node_template %s", node_template)
@ -1007,3 +1070,380 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
if i != scale_vnf_request.number_of_steps - 1: if i != scale_vnf_request.number_of_steps - 1:
if cooldown: if cooldown:
time.sleep(cooldown) time.sleep(cooldown)
def _term_resource_update(self, context, vnf_info, vnf_instance,
error=False):
if not vnf_instance.instantiated_vnf_info:
resource_changes = objects.ResourceChanges()
resource_changes.affected_vnfcs = []
resource_changes.affected_virtual_links = []
resource_changes.affected_virtual_storages = []
vnf_info['resource_changes'] = resource_changes
return resource_changes
instantiated_vnf_before = copy.deepcopy(
vnf_instance.instantiated_vnf_info)
vnf_instance.instantiated_vnf_info.reinitialize()
if not error:
vnf_instance.vim_connection_info = []
vnf_instance.task_state = None
LOG.debug(
"vnf_instance.instantiated_vnf_info %s",
vnf_instance.instantiated_vnf_info)
affected_vnfcs = []
affected_virtual_storages = []
affected_virtual_links = []
for vnfc in instantiated_vnf_before.vnfc_resource_info:
vnfc_delete = True
for rsc in vnf_instance.instantiated_vnf_info.vnfc_resource_info:
if vnfc.compute_resource.resource_id == \
rsc.compute_resource.resource_id:
vnfc_delete = False
break
if vnfc_delete:
affected_vnfc = objects.AffectedVnfc(
id=vnfc.id,
vdu_id=vnfc.vdu_id,
change_type='REMOVED',
compute_resource=vnfc.compute_resource)
affected_vnfcs.append(affected_vnfc)
for st in instantiated_vnf_before.virtual_storage_resource_info:
st_delete = True
for rsc in \
vnf_instance.instantiated_vnf_info.\
virtual_storage_resource_info:
if st.storage_resource.resource_id == \
rsc.storage_resource.resource_id:
st_delete = False
break
if st_delete:
affected_st = objects.AffectedVirtualStorage(
id=st.id,
virtual_storage_desc_id=st.virtual_storage_desc_id,
change_type='REMOVED',
storage_resource=st.storage_resource)
affected_virtual_storages.append(affected_st)
for vl in instantiated_vnf_before.vnf_virtual_link_resource_info:
vm_delete = False
for rsc in \
vnf_instance.instantiated_vnf_info.\
vnf_virtual_link_resource_info:
if st.network_resource.resource_id == \
rsc.network_resource.resource_id:
vm_delete = False
break
if vm_delete:
affected_vl = objects.AffectedVirtualLink(
id=vl.id,
vnf_virtual_link_desc_id=vl.vnf_virtual_link_desc_id,
change_type='REMOVED',
network_resource=vl.network_resource)
affected_virtual_links.append(affected_vl)
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
resource_changes = objects.ResourceChanges()
resource_changes.affected_vnfcs = []
resource_changes.affected_virtual_links = []
resource_changes.affected_virtual_storages = []
if 'resource_changes' in vnf_lcm_op_occs \
and vnf_lcm_op_occs.resource_changes:
if 'affected_vnfcs' in vnf_lcm_op_occs.resource_changes:
if len(vnf_lcm_op_occs.resource_changes.affected_vnfcs) > 0:
resource_changes.affected_vnfcs.extend(
vnf_lcm_op_occs.resource_changes.affected_vnfcs)
if 'affected_virtual_storages' in vnf_lcm_op_occs.resource_changes:
if len(vnf_lcm_op_occs.resource_changes.
affected_virtual_storages) > 0:
resource_changes.affected_virtual_storages.extend(
vnf_lcm_op_occs.resource_changes.
affected_virtual_storages)
if 'affected_virtual_links' in vnf_lcm_op_occs.resource_changes:
if len(vnf_lcm_op_occs.resource_changes.
affected_virtual_links) > 0:
resource_changes.affected_virtual_links.extend(
vnf_lcm_op_occs.resource_changes.
affected_virtual_links)
resource_changes.affected_vnfcs.extend(affected_vnfcs)
resource_changes.affected_virtual_storages.extend(
affected_virtual_storages)
resource_changes.affected_virtual_links.extend(affected_virtual_links)
vnf_info['resource_changes'] = resource_changes
return resource_changes
def _rollback_vnf_pre(
self,
context,
vnf_info,
vnf_instance,
operation_params,
vim_connection_info):
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
scale_id_list = []
scale_name_list = []
grp_id = None
self._update_vnf_rollback_pre(context, vnf_info)
if vnf_lcm_op_occs.operation == 'SCALE':
scaleGroupDict = jsonutils.loads(
vnf_info['attributes']['scale_group'])
cap_size = scaleGroupDict['scaleGroupDict'][operation_params
['aspect_id']]['default']
vnf_info['res_num'] = cap_size
scale_vnf_request = objects.ScaleVnfRequest.obj_from_primitive(
operation_params, context=context)
for scale in vnf_instance.instantiated_vnf_info.scale_status:
if scale_vnf_request.aspect_id == scale.aspect_id:
vnf_info['after_scale_level'] = scale.scale_level
break
if vnf_lcm_op_occs.operation == 'SCALE' \
and vnf_lcm_op_occs.error_point >= 4:
scale_id_list, scale_name_list, grp_id = self._vnf_manager.invoke(
vim_connection_info.vim_type,
'get_rollback_ids',
plugin=self,
context=context,
vnf_dict=vnf_info,
aspect_id=operation_params['aspect_id'],
auth_attr=vim_connection_info.access_info,
region_name=vim_connection_info.access_info.get('region_name')
)
if vnf_lcm_op_occs.error_point == 7:
if vnf_lcm_op_occs.operation == 'SCALE':
vnfd_yaml = vnf_info['vnfd']['attributes'].\
get('vnfd_' +
vnf_instance.instantiated_vnf_info.flavour_id, '')
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces'].get('Vnflcm'):
if vnf_node['interfaces']['Vnflcm'].get('scale_start'):
vnf_info['vnfd']['mgmt_driver'] = \
vnf_node['interfaces']['Vnflcm']['scale_start']
vnf_info['action'] = 'in'
if len(scale_id_list) != 0 and vnf_info['vnfd'].get(
'mgmt_driver'):
if len(scale_id_list) > 1:
stack_value = []
stack_value = scale_id_list
else:
stack_value = scale_id_list[0]
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_SCALE_IN_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info},
mgmt_constants.KEY_SCALE:
stack_value,
}
self._rollback_mgmt_call(context, vnf_info, kwargs)
else:
vnfd_yaml = vnf_info['vnfd']['attributes'].\
get('vnfd_' +
vnf_instance.instantiated_vnf_info.flavour_id, '')
vnfd_dict = yaml.safe_load(vnfd_yaml)
# mgmt_driver from vnfd
vnf_node = self._get_node_template_for_vnf(vnfd_dict)
if vnf_node and vnf_node.get('interfaces'):
if vnf_node['interfaces'].get('Vnflcm'):
if vnf_node['interfaces']['Vnflcm'].get(
'termination_start'):
vnf_info['vnfd']['mgmt_driver'] = vnf_node[
'interfaces']['Vnflcm']['termination_start']
if len(scale_id_list) != 0 and vnf_info['vnfd'].get(
'mgmt_driver'):
kwargs = {
mgmt_constants.KEY_ACTION:
mgmt_constants.ACTION_DELETE_VNF,
mgmt_constants.KEY_KWARGS:
{'vnf': vnf_info}
}
self._rollback_mgmt_call(context, vnf_info, kwargs)
vnf_lcm_op_occs.error_point = 6
return scale_name_list, grp_id
def _rollback_vnf(
self,
context,
vnf_info,
vnf_instance,
operation_params,
vim_connection_info,
scale_name_list,
grp_id):
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.error_point >= 4:
if vnf_lcm_op_occs.operation == 'SCALE':
scale_vnf_request = objects.ScaleVnfRequest.obj_from_primitive(
operation_params, context=context)
self._vnf_manager.invoke(
vim_connection_info.vim_type,
'scale_in_reverse',
plugin=self,
context=context,
auth_attr=vim_connection_info.access_info,
vnf_info=vnf_info,
scale_vnf_request=scale_vnf_request,
region_name=vim_connection_info.access_info.get(
'region_name'),
scale_name_list=scale_name_list,
grp_id=grp_id)
self._vnf_manager.invoke(
vim_connection_info.vim_type,
'scale_update_wait',
plugin=self,
context=context,
auth_attr=vim_connection_info.access_info,
vnf_info=vnf_info,
region_name=vim_connection_info.access_info.get(
'region_name'))
else:
instance_id = vnf_instance.instantiated_vnf_info.instance_id
access_info = vim_connection_info.access_info
self._vnf_manager.invoke(vim_connection_info.vim_type,
'delete', plugin=self, context=context,
vnf_id=instance_id, auth_attr=access_info)
self._vnf_manager.invoke(vim_connection_info.vim_type,
'delete_wait', plugin=self, context=context,
vnf_id=instance_id, auth_attr=access_info)
vnf_lcm_op_occs.error_point = 3
def _update_vnf_rollback_pre(self, context, vnf_info):
self._vnfm_plugin._update_vnf_rollback_pre(context, vnf_info)
def _update_vnf_rollback(self, context, vnf_info,
vnf_instance, vnf_lcm_op_occs):
self._vnfm_plugin._update_vnf_rollback(context, vnf_info,
'ERROR',
'ACTIVE',
vnf_instance=vnf_instance,
vnf_lcm_op_occ=vnf_lcm_op_occs)
def _update_vnf_rollback_status_err(self, context, vnf_info):
self._vnfm_plugin._update_vnf_rollback_status_err(context, vnf_info)
def _rollback_mgmt_call(self, context, vnf_info, kwargs):
self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs)
def _rollback_vnf_post(
self,
context,
vnf_info,
vnf_instance,
operation_params,
vim_connection_info):
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.operation == 'SCALE':
scale_vnf_request = objects.ScaleVnfRequest.obj_from_primitive(
operation_params, context=context)
scale_vnf_request_copy = copy.deepcopy(scale_vnf_request)
scale_vnf_request_copy.type = 'SCALE_IN'
resource_changes = self._scale_resource_update(context, vnf_info,
vnf_instance,
scale_vnf_request_copy,
vim_connection_info)
else:
resource_changes = self._term_resource_update(
context, vnf_info, vnf_instance)
vnf_lcm_op_occs.error_point = 2
timestamp = datetime.utcnow()
vnf_lcm_op_occs.operation_state = 'ROLLED_BACK'
vnf_lcm_op_occs.state_entered_time = timestamp
vnf_lcm_op_occs.resource_changes = resource_changes
self._update_vnf_rollback(context, vnf_info,
vnf_instance,
vnf_lcm_op_occs)
notification = vnf_info['notification']
notification['notificationStatus'] = 'RESULT'
notification['operationState'] = 'ROLLED_BACK'
resource_dict = resource_changes.to_dict()
if resource_dict.get('affected_vnfcs'):
notification['affectedVnfcs'] = resource_dict.get('affected_vnfcs')
if resource_dict.get('affected_virtual_links'):
notification['affectedVirtualLinks'] = \
resource_dict.get('affected_virtual_links')
if resource_dict.get('affected_virtual_storages'):
notification['affectedVirtualStorages'] = \
resource_dict.get('affected_virtual_storages')
self.rpc_api.send_notification(context, notification)
@log.log
@revert_to_error_rollback
def rollback_vnf(self, context, vnf_info, vnf_instance, operation_params):
LOG.info("Request received for rollback vnf '%s'", vnf_instance.id)
vnf_lcm_op_occs = vnf_info['vnf_lcm_op_occ']
if vnf_lcm_op_occs.operation == 'SCALE':
scale_vnf_request = objects.ScaleVnfRequest.obj_from_primitive(
operation_params, context=context)
for scale in vnf_instance.instantiated_vnf_info.scale_status:
if scale_vnf_request.aspect_id == scale.aspect_id:
vnf_info['after_scale_level'] = scale.scale_level
break
timestamp = datetime.utcnow()
vnf_lcm_op_occs.operation_state = 'ROLLING_BACK'
vnf_lcm_op_occs.state_entered_time = timestamp
LOG.debug("vnf_lcm_op_occs %s", vnf_lcm_op_occs)
insta_url = CONF.vnf_lcm.endpoint_url + \
"/vnflcm/v1/vnf_instances/" + \
vnf_instance.id
vnflcm_url = CONF.vnf_lcm.endpoint_url + \
"/vnflcm/v1/vnf_lcm_op_occs/" + \
vnf_lcm_op_occs.id
notification = {}
notification['notificationType'] = \
'VnfLcmOperationOccurrenceNotification'
notification['vnfInstanceId'] = vnf_instance.id
notification['notificationStatus'] = 'START'
notification['operation'] = vnf_lcm_op_occs.operation
notification['operationState'] = 'ROLLING_BACK'
if vnf_lcm_op_occs.operation == 'SCALE':
notification['isAutomaticInvocation'] = \
vnf_lcm_op_occs.is_automatic_invocation
else:
notification['isAutomaticInvocation'] = False
notification['vnfLcmOpOccId'] = vnf_lcm_op_occs.id
notification['_links'] = {}
notification['_links']['vnfInstance'] = {}
notification['_links']['vnfInstance']['href'] = insta_url
notification['_links']['vnfLcmOpOcc'] = {}
notification['_links']['vnfLcmOpOcc']['href'] = vnflcm_url
vnf_info['notification'] = notification
vnf_lcm_op_occs.save()
self.rpc_api.send_notification(context, notification)
vim_info = vnflcm_utils._get_vim(context,
vnf_instance.vim_connection_info)
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
scale_name_list, grp_id = self._rollback_vnf_pre(
context, vnf_info, vnf_instance,
operation_params, vim_connection_info)
self._rollback_vnf(
context,
vnf_info,
vnf_instance,
operation_params,
vim_connection_info,
scale_name_list,
grp_id)
self._rollback_vnf_post(
context,
vnf_info,
vnf_instance,
operation_params,
vim_connection_info)

View File

@ -1379,3 +1379,12 @@ class Kubernetes(abstract_driver.VnfAbstractDriver,
vim_connection_info, vim_connection_info,
del_list): del_list):
pass pass
def get_rollback_ids(self,
plugin,
context,
vnf_dict,
aspect_id,
auth_attr,
region_name):
pass

View File

@ -275,6 +275,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for name, value in nested_hot_dict.items(): for name, value in nested_hot_dict.items():
vnf['attributes'].update({name: self._format_base_hot(value)}) vnf['attributes'].update({name: self._format_base_hot(value)})
vnf['error_point'] = 4
# Create heat-stack with BaseHOT and parameters # Create heat-stack with BaseHOT and parameters
stack = self._create_stack_with_user_data( stack = self._create_stack_with_user_data(
heatclient, vnf, base_hot_dict, heatclient, vnf, base_hot_dict,
@ -1537,7 +1538,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
'parameters': paramDict, 'parameters': paramDict,
'existing': True} 'existing': True}
heatclient.update(vnf_info['instance_id'], **stack_update_param) heatclient.update(vnf_info['instance_id'], **stack_update_param)
stack_param = jsonutils.loads(vnf_info['attributes']['stack_param']) stack_param = yaml.safe_load(vnf_info['attributes']['stack_param'])
stack_param.update(paramDict) stack_param.update(paramDict)
vnf_info['attributes'].update({'stack_param': str(paramDict)}) vnf_info['attributes'].update({'stack_param': str(paramDict)})
@ -1842,3 +1843,66 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
vnf_info['removeResources'] = remove_resources vnf_info['removeResources'] = remove_resources
vnf_info['affinity_list'] = [] vnf_info['affinity_list'] = []
vnf_info['placement_constraint_list'] = [] vnf_info['placement_constraint_list'] = []
@log.log
def get_rollback_ids(self, plugin, context,
vnf_dict,
aspect_id,
auth_attr,
region_name):
heatclient = hc.HeatClient(auth_attr, region_name)
grp = heatclient.resource_get(vnf_dict['instance_id'],
aspect_id + '_group')
res_list = []
for rsc in heatclient.resource_get_list(grp.physical_resource_id):
scale_rsc = heatclient.resource_get(grp.physical_resource_id,
rsc.resource_name)
if 'COMPLETE' in scale_rsc.resource_status \
and 'INIT_COMPLETE' != scale_rsc.resource_status:
res_list.append(scale_rsc)
res_list = sorted(
res_list,
key=lambda x: (x.creation_time, x.resource_name)
)
LOG.debug("res_list %s", res_list)
heat_template = vnf_dict['attributes']['heat_template']
group_name = aspect_id + '_group'
heat_resource = yaml.safe_load(heat_template)
group_temp = heat_resource['resources'][group_name]
group_prop = group_temp['properties']
min_size = group_prop['min_size']
cap_size = vnf_dict['res_num']
if cap_size < min_size:
cap_size = min_size
reversed_res_list = res_list[:cap_size]
LOG.debug("reversed_res_list reverse %s", reversed_res_list)
# List of physical_resource_id before Rollback
before_list = []
# List of physical_resource_ids remaining after Rollback
after_list = []
# List of resource_name before Rollback
before_rs_list = []
# List of resource_names left after Rollback
after_rs_list = []
for rsc in res_list:
before_list.append(rsc.physical_resource_id)
before_rs_list.append(rsc.resource_name)
for rsc in reversed_res_list:
after_list.append(rsc.physical_resource_id)
after_rs_list.append(rsc.resource_name)
# Make a list of the physical_resource_id and r
# esource_name of the VMs that will actually be deleted
if 0 < cap_size:
return_list = list(set(before_list) - set(after_list))
return_rs_list = list(set(before_rs_list) - set(after_rs_list))
else:
return_list = before_list
return_rs_list = before_rs_list
return return_list, return_rs_list, grp.physical_resource_id

View File

@ -112,3 +112,13 @@ class VnfScaleAbstractDriver(extensions.PluginInterface):
vim_connection_info, vim_connection_info,
del_list): del_list):
pass pass
@abc.abstractmethod
def get_rollback_ids(self,
plugin,
context,
vnf_dict,
aspect_id,
auth_attr,
region_name):
pass