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
This commit is contained in:
Aldinson Esto 2020-08-27 21:00:12 +09:00 committed by Koichi Edagawa
parent ffe4c40921
commit 4543b961eb
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
: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
=========================

View File

@ -1116,6 +1116,90 @@ class VnfLcmController(wsgi.Controller):
return self._make_problem_detail(
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(
self,
detail,

View File

@ -112,6 +112,13 @@ class VnflcmAPIRouter(wsgi.Router):
"/vnf_instances/{id}/scale",
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"}
self._setup_route(mapper, "/subscriptions",
methods, controller, default_resource)

View File

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

View File

@ -112,3 +112,16 @@ class VNFLcmRPCAPI(object):
rpc_method = cctxt.cast if cast else cctxt.call
return rpc_method(context, 'send_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({
'resource': placement_obj.resource,
'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)
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):
"""Add a 'tacker.context' to WSGI environ."""

View File

@ -2535,7 +2535,7 @@ class TestController(base.TestCase):
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@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(vnf_lcm_rpc.VNFLcmRPCAPI, "send_notification")
@mock.patch.object(objects.VnfLcmOpOcc, "create")
@ -2594,3 +2594,223 @@ class TestController(base.TestCase):
'STARTING')
self.assertEqual(mock_send_notification.call_args[0][1].get(
'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
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from heatclient.v1 import resources
from tacker.common import driver_manager
from tacker.common import exceptions
from tacker.common import utils
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
from tacker import context
from tacker.db.common_services import common_services_db_plugin
from tacker.manager import TackerManager
from tacker import objects
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 uuidsentinel
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
@ -125,6 +132,8 @@ class FakeDriverManager(mock.Mock):
if self.fail_method_name and \
self.fail_method_name == 'post_heal_vnf':
raise InfraDriverException("post_heal_vnf failed")
if 'get_rollback_ids' in args:
return [], [], ""
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("NOT_INSTANTIATED",
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)
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("NOT_INSTANTIATED",
vnf_instance_obj.instantiation_state)
self.assertEqual(3, mock_vnf_instance_save.call_count)
self.assertEqual(5, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
# 3->1 reason: rollback_vnf_instantiated_resources deleted
self.assertEqual(1, mock_vnf_instance_save.call_count)
# 5->3 reason: rollback_vnf_instantiated_resources deleted
self.assertEqual(3, self._vnf_manager.invoke.call_count)
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@ -904,3 +916,765 @@ class TestVnflcmDriver(db_base.SqlTestCase):
driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request,
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.unit import base
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 \
fixture_data_utils as fd_utils
@ -1950,3 +1951,97 @@ class TestOpenStack(base.FixturedTestCase):
scale_vnf_request=scale_vnf_request,
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.db import base as db_base
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 plugin
@ -1326,3 +1327,53 @@ class TestVNFMPlugin(db_base.SqlTestCase):
self.vnfm_plugin.delete_placement_constraint(
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
@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')
def revert_to_error_scale(function):
"""Decorator to revert task_state to error on failure."""
@ -218,6 +172,116 @@ def revert_to_error_task_state(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):
def __init__(self):
@ -321,7 +385,6 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
error=encodeutils.exception_to_unicode(exp))
@log.log
@rollback_vnf_instantiated_resources
def instantiate_vnf(self, context, vnf_instance, vnf_dict,
instantiate_vnf_req):
@ -589,8 +652,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
return scale_id_list, scale_name_list, grp_id
def _get_node_template_for_vnf(self, vnfd_dict):
for node_template in vnfd_dict['topology_template']['\
node_templates'].values():
node_tmp = vnfd_dict['topology_template']['node_templates']
for node_template in node_tmp.values():
LOG.debug("node_template %s", node_template)
if not re.match('^tosca', node_template['type']):
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 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,
del_list):
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():
vnf['attributes'].update({name: self._format_base_hot(value)})
vnf['error_point'] = 4
# Create heat-stack with BaseHOT and parameters
stack = self._create_stack_with_user_data(
heatclient, vnf, base_hot_dict,
@ -1537,7 +1538,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
'parameters': paramDict,
'existing': True}
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)
vnf_info['attributes'].update({'stack_param': str(paramDict)})
@ -1842,3 +1843,66 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
vnf_info['removeResources'] = remove_resources
vnf_info['affinity_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,
del_list):
pass
@abc.abstractmethod
def get_rollback_ids(self,
plugin,
context,
vnf_dict,
aspect_id,
auth_attr,
region_name):
pass