Support for grant request with Synchronous response
Supported grant for the following sequences: Instantiation Healing Scaling Termination Implements: blueprint support-vnfm-operations Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/support-sol003-vnfm-operations.html Change-Id: I47a6a995dc25256eb1bd10f2e03a1f810fdb3f69
This commit is contained in:
parent
49be782dc2
commit
ffe4c40921
@ -455,7 +455,7 @@ class VnfLcmController(wsgi.Controller):
|
||||
'vnfInstance': {
|
||||
'href': self._get_vnf_instance_href(vnf_instance)}}}
|
||||
|
||||
# call sendNotification
|
||||
# call send_notification
|
||||
self.rpc_api.send_notification(context, notification)
|
||||
|
||||
result = self._view_builder.create(vnf_instance)
|
||||
|
@ -25,7 +25,6 @@ import time
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
|
||||
from glance_store import exceptions as store_exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
@ -51,6 +50,7 @@ from tacker.common import utils
|
||||
import tacker.conf
|
||||
from tacker import context as t_context
|
||||
from tacker.db.common_services import common_services_db
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
from tacker.db.nfvo import nfvo_db
|
||||
from tacker.db.vnfm import vnfm_db
|
||||
from tacker.extensions import nfvo
|
||||
@ -66,6 +66,7 @@ from tacker import service as tacker_service
|
||||
from tacker import version
|
||||
from tacker.vnflcm import utils as vnflcm_utils
|
||||
from tacker.vnflcm import vnflcm_driver
|
||||
from tacker.vnfm import nfvo_client
|
||||
from tacker.vnfm import plugin
|
||||
|
||||
CONF = tacker.conf.CONF
|
||||
@ -230,6 +231,65 @@ def revert_update_lcm(function):
|
||||
return decorated_function
|
||||
|
||||
|
||||
@utils.expects_func_args('vnf_instance', 'vnf_lcm_op_occ_id')
|
||||
def grant_error_common(function):
|
||||
"""Decorator to revert upload_vnf_package on failure."""
|
||||
|
||||
@functools.wraps(function)
|
||||
def decorated_function(self, context, *args, **kwargs):
|
||||
try:
|
||||
return function(self, context, *args, **kwargs)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
wrapped_func = safe_utils.get_wrapped_function(function)
|
||||
keyed_args = inspect.getcallargs(wrapped_func, self, context,
|
||||
*args, **kwargs)
|
||||
context = keyed_args['context']
|
||||
vnf_instance = keyed_args['vnf_instance']
|
||||
vnf_lcm_op_occ_id = keyed_args['vnf_lcm_op_occ_id']
|
||||
try:
|
||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc.get_by_id(
|
||||
context, vnf_lcm_op_occ_id)
|
||||
timestamp = datetime.datetime.utcnow()
|
||||
vnf_lcm_op_occs.operation_state = 'ROLLED_BACK'
|
||||
vnf_lcm_op_occs.state_entered_time = timestamp
|
||||
vnf_lcm_op_occs.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 = {}
|
||||
notification['notificationType'] = \
|
||||
'VnfLcmOperationOccurrenceNotification'
|
||||
notification['vnfInstanceId'] = vnf_instance.id
|
||||
notification['notificationStatus'] = 'RESULT'
|
||||
notification['operation'] = vnf_lcm_op_occs.operation
|
||||
notification['operationState'] = 'ROLLED_BACK'
|
||||
notification['isAutomaticInvocation'] = \
|
||||
vnf_lcm_op_occs.is_automatic_invocation
|
||||
notification['vnfLcmOpOccId'] = vnf_lcm_op_occ_id
|
||||
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_occ_id
|
||||
notification['_links'] = {}
|
||||
notification['_links']['vnfInstance'] = {}
|
||||
notification['_links']['vnfInstance']['href'] = insta_url
|
||||
notification['_links']['vnfLcmOpOcc'] = {}
|
||||
notification['_links']['vnfLcmOpOcc']['href'] = vnflcm_url
|
||||
self.send_notification(context, notification)
|
||||
except Exception as e:
|
||||
LOG.warning("Failed notification for vnf "
|
||||
"instance %(id)s. Error: %(error)s",
|
||||
{"id": vnf_instance.id, "error": e})
|
||||
|
||||
return decorated_function
|
||||
|
||||
|
||||
class Conductor(manager.Manager):
|
||||
def __init__(self, host, conf=None):
|
||||
if conf:
|
||||
@ -661,9 +721,10 @@ class Conductor(manager.Manager):
|
||||
vim_connection_info = objects.VimConnectionInfo.\
|
||||
obj_from_primitive(vim_info, context)
|
||||
|
||||
vnflcm_utils._build_instantiated_vnf_info(vnfd_dict,
|
||||
instantiate_vnf_req, vnf_instance,
|
||||
vim_id=vim_connection_info.vim_id)
|
||||
if not vnf_instance.instantiated_vnf_info.instance_id:
|
||||
vnflcm_utils._build_instantiated_vnf_info(
|
||||
vnfd_dict, instantiate_vnf_req, vnf_instance,
|
||||
vim_id=vim_connection_info.vim_id)
|
||||
|
||||
if vnf_instance.instantiated_vnf_info.instance_id:
|
||||
self.vnf_manager.invoke(vim_connection_info.vim_type,
|
||||
@ -761,6 +822,522 @@ class Conductor(manager.Manager):
|
||||
{'zip': csar_path, 'folder': csar_zip_temp_path,
|
||||
'uuid': vnf_pack.id})
|
||||
|
||||
def _grant(self, context, grant_request):
|
||||
LOG.info(
|
||||
"grant start grant_request[%s]" %
|
||||
grant_request.to_request_body())
|
||||
|
||||
response = nfvo_client.GrantRequest().grants(
|
||||
json=grant_request.to_request_body())
|
||||
|
||||
res_body = response.json()
|
||||
res_dict = utils.convert_camelcase_to_snakecase(res_body)
|
||||
LOG.info("grant end res_body[%s]" % res_dict)
|
||||
grant_obj = objects.Grant.obj_from_primitive(
|
||||
res_dict, context=context)
|
||||
if len(grant_request.add_resources) != len(grant_obj.add_resources):
|
||||
msg = "grant add resource error"
|
||||
raise exceptions.ValidationError(detail=msg)
|
||||
if len(
|
||||
grant_request.remove_resources) != len(
|
||||
grant_obj.remove_resources):
|
||||
msg = "grant remove resource error"
|
||||
raise exceptions.ValidationError(detail=msg)
|
||||
|
||||
self._check_res_add_remove_rsc(context, grant_request, grant_obj)
|
||||
|
||||
return grant_obj
|
||||
|
||||
def _check_res_add_remove_rsc(self, context, grant_request, grant_obj):
|
||||
for add_resource in grant_request.add_resources:
|
||||
match_flg = False
|
||||
for rsc in grant_obj.add_resources:
|
||||
if add_resource.id == rsc.resource_definition_id:
|
||||
match_flg = True
|
||||
break
|
||||
if not match_flg:
|
||||
msg = "grant add resource error"
|
||||
raise exceptions.ValidationError(detail=msg)
|
||||
|
||||
for remove_resource in grant_request.remove_resources:
|
||||
match_flg = False
|
||||
for rsc in grant_obj.remove_resources:
|
||||
if remove_resource.id == rsc.resource_definition_id:
|
||||
match_flg = True
|
||||
break
|
||||
if not match_flg:
|
||||
msg = "grant remove resource error"
|
||||
raise exceptions.ValidationError(detail=msg)
|
||||
|
||||
@grant_error_common
|
||||
def _instantiate_grant(self,
|
||||
context,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
instantiate_vnf_request,
|
||||
vnf_lcm_op_occ_id):
|
||||
vnfd_dict = vnflcm_utils._get_vnfd_dict(context,
|
||||
vnf_dict['vnfd']['id'],
|
||||
instantiate_vnf_request.flavour_id)
|
||||
inst_level = instantiate_vnf_request.instantiation_level_id
|
||||
vnf_instance.instantiated_vnf_info = objects.InstantiatedVnfInfo(
|
||||
flavour_id=instantiate_vnf_request.flavour_id,
|
||||
instantiation_level_id=inst_level,
|
||||
vnf_instance_id=vnf_instance.id)
|
||||
vnf_instance.instantiated_vnf_info.reinitialize()
|
||||
vnflcm_utils._build_instantiated_vnf_info(vnfd_dict,
|
||||
instantiate_vnf_request, vnf_instance, '')
|
||||
if not self._get_grant_execute():
|
||||
return
|
||||
|
||||
add_resources = []
|
||||
vnf_inf = vnf_instance.instantiated_vnf_info
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = vnfc_resource.id
|
||||
resource.type = constants.TYPE_COMPUTE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = vnfc_resource.vdu_id
|
||||
add_resources.append(resource)
|
||||
|
||||
for vl_resource in vnf_inf.vnf_virtual_link_resource_info:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = vl_resource.id
|
||||
resource.type = constants.TYPE_VL
|
||||
resource.resource_template_id = \
|
||||
vl_resource.vnf_virtual_link_desc_id
|
||||
add_resources.append(resource)
|
||||
for cp_resource in vl_resource.vnf_link_ports:
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
for vnfc_cp_resource in vnfc_resource.vnfc_cp_info:
|
||||
if cp_resource.cp_instance_id == vnfc_cp_resource.id:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = cp_resource.id
|
||||
resource.type = constants.TYPE_LINKPORT
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
vnfc_cp_resource.cpd_id
|
||||
add_resources.append(resource)
|
||||
|
||||
for storage_resource in vnf_inf.virtual_storage_resource_info:
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
if storage_resource.id in vnfc_resource.storage_resource_ids:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = storage_resource.id
|
||||
resource.type = constants.TYPE_STORAGE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
storage_resource.virtual_storage_desc_id
|
||||
add_resources.append(resource)
|
||||
|
||||
p_c_list = []
|
||||
placement_obj_list = []
|
||||
topo_temp = vnfd_dict.get('topology_template', {})
|
||||
for policy in topo_temp.get('policies', []):
|
||||
for policy_name, policy_dict in policy.items():
|
||||
key_type = 'tosca.policies.nfv.AntiAffinityRule'
|
||||
if policy_dict['type'] == key_type:
|
||||
placement_constraint = objects.PlacementConstraint()
|
||||
placement_constraint.affinity_or_anti_affinity = \
|
||||
'ANTI_AFFINITY'
|
||||
placement_constraint.scope = 'ZONE'
|
||||
placement_constraint.resource = []
|
||||
placement_constraint.fallback_best_effort = True
|
||||
for target in policy_dict.get('targets', []):
|
||||
if target in topo_temp.get('groups', []):
|
||||
for member in topo_temp['groups']['members']:
|
||||
for vnfc_rsc in vnf_inf.vnfc_resource_info:
|
||||
if member == vnfc_rsc.vdu_id:
|
||||
resource = \
|
||||
objects.ConstraintResourceRef()
|
||||
resource.id_type = 'GRANT'
|
||||
resource.resource_id = vnfc_rsc.id
|
||||
p_rsc = \
|
||||
placement_constraint.resource
|
||||
p_rsc.append(resource)
|
||||
break
|
||||
else:
|
||||
for vnfc_rsc in vnf_inf.vnfc_resource_info:
|
||||
if target == vnfc_rsc.vdu_id:
|
||||
resource = \
|
||||
objects.ConstraintResourceRef()
|
||||
resource.id_type = 'GRANT'
|
||||
resource.resource_id = vnfc_rsc.id
|
||||
p_rsc = placement_constraint.resource
|
||||
p_rsc.append(resource)
|
||||
break
|
||||
p_c_list.append(placement_constraint)
|
||||
placement_obj = models.PlacementConstraint()
|
||||
placement_obj.id = uuidutils.generate_uuid()
|
||||
placement_obj.vnf_instance_id = vnf_instance.id
|
||||
placement_obj.affinity_or_anti_affinity = \
|
||||
placement_constraint.affinity_or_anti_affinity
|
||||
placement_obj.scope = placement_constraint.scope
|
||||
placement_obj.server_group_name = policy_name
|
||||
p_c_dict = placement_constraint.to_dict()
|
||||
res_dict = p_c_dict.get('resource', {})
|
||||
res_json = json.dumps(res_dict)
|
||||
placement_obj.resource = res_json
|
||||
placement_obj.created_at = timeutils.utcnow()
|
||||
placement_obj.deleted_at = datetime.datetime.min
|
||||
placement_obj_list.append(placement_obj)
|
||||
|
||||
g_request = self._make_grant_request(context,
|
||||
vnf_instance,
|
||||
vnf_lcm_op_occ_id,
|
||||
'INSTANTIATE',
|
||||
False,
|
||||
add_resources=add_resources,
|
||||
placement_constraints=p_c_list)
|
||||
|
||||
vnf_dict['placement_obj_list'] = placement_obj_list
|
||||
vnf_dict['grant'] = self._grant(context, g_request)
|
||||
|
||||
def _get_placement(self, context, vnf_instance):
|
||||
return self.vnfm_plugin.get_placement_constraint(context,
|
||||
vnf_instance.id)
|
||||
|
||||
@grant_error_common
|
||||
def _scale_grant(
|
||||
self,
|
||||
context,
|
||||
vnf_dict,
|
||||
vnf_instance,
|
||||
scale_vnf_request,
|
||||
vnf_lcm_op_occ_id):
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Scale action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
raise Exception("Scale action cannot be performed on vnf")
|
||||
|
||||
vim_info = vnflcm_utils._get_vim(
|
||||
context, vnf_instance.vim_connection_info)
|
||||
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
|
||||
vim_info, context)
|
||||
if scale_vnf_request.type == 'SCALE_IN':
|
||||
vnf_dict['action'] = 'in'
|
||||
reverse = scale_vnf_request.additional_params.get('is_reverse')
|
||||
region_name = vim_connection_info.access_info.get('region_name')
|
||||
scale_id_list, scale_name_list, grp_id, res_num = \
|
||||
self.vnf_manager.invoke(vim_connection_info.vim_type,
|
||||
'get_scale_in_ids',
|
||||
plugin=self,
|
||||
context=context,
|
||||
vnf_dict=vnf_dict,
|
||||
is_reverse=reverse,
|
||||
auth_attr=vim_connection_info.access_info,
|
||||
region_name=region_name,
|
||||
number_of_steps=scale_vnf_request.number_of_steps)
|
||||
vnf_dict['res_num'] = res_num
|
||||
else:
|
||||
scale_id_list = []
|
||||
if not self._get_grant_execute():
|
||||
return None, []
|
||||
|
||||
placement_obj_list = self.vnfm_plugin.get_placement_constraint(
|
||||
context, vnf_instance.id)
|
||||
self.vnf_manager.invoke(
|
||||
vim_connection_info.vim_type,
|
||||
'get_grant_resource',
|
||||
plugin=self,
|
||||
vnf_instance=vnf_instance,
|
||||
vnf_info=vnf_dict,
|
||||
scale_vnf_request=scale_vnf_request,
|
||||
placement_obj_list=placement_obj_list,
|
||||
vim_connection_info=vim_connection_info,
|
||||
del_list=scale_id_list
|
||||
)
|
||||
vnf_dict['placement_obj_list'] = placement_obj_list
|
||||
|
||||
grant_request = self._make_grant_request(
|
||||
context,
|
||||
vnf_instance,
|
||||
vnf_lcm_op_occ_id,
|
||||
'SCALE',
|
||||
False,
|
||||
add_resources=vnf_dict['addResources'],
|
||||
remove_resources=vnf_dict['removeResources'],
|
||||
placement_constraints=vnf_dict['placement_constraint_list'])
|
||||
|
||||
vnf_dict['grant'] = self._grant(context, grant_request)
|
||||
|
||||
@grant_error_common
|
||||
def _heal_grant(self,
|
||||
context,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
heal_vnf_request,
|
||||
vnf_lcm_op_occ_id):
|
||||
vnf_inf = vnf_instance.instantiated_vnf_info
|
||||
if not self._get_grant_execute():
|
||||
return
|
||||
|
||||
placement_obj_list = self._get_placement(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)
|
||||
|
||||
cinder_list = self.vnf_manager.invoke(vim_connection_info.vim_type,
|
||||
'get_cinder_list',
|
||||
vnf_info=vnf_dict)
|
||||
|
||||
vnf_instantiated_info_after = copy.deepcopy(vnf_inf)
|
||||
del_cre_vdu_list = []
|
||||
add_resources = []
|
||||
rm_resources = []
|
||||
affinity_list = []
|
||||
for vnfc_resource in vnf_instantiated_info_after.vnfc_resource_info:
|
||||
vnfc_key = vnfc_resource.compute_resource.resource_id
|
||||
if not heal_vnf_request.vnfc_instance_id or \
|
||||
vnfc_key in heal_vnf_request.vnfc_instance_id:
|
||||
if vnfc_resource.vdu_id not in del_cre_vdu_list:
|
||||
del_cre_vdu_list.append(vnfc_resource.vdu_id)
|
||||
for vnfc_resource in vnf_instantiated_info_after.vnfc_resource_info:
|
||||
if vnfc_resource.vdu_id in del_cre_vdu_list:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = vnfc_resource.id
|
||||
resource.type = constants.TYPE_COMPUTE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = vnfc_resource.vdu_id
|
||||
vim_id = vnfc_resource.compute_resource.vim_connection_id
|
||||
rsc_id = vnfc_resource.compute_resource.resource_id
|
||||
vnfc_rh = objects.ResourceHandle(
|
||||
vim_connection_id=vim_id,
|
||||
resource_id=rsc_id)
|
||||
resource.resource = vnfc_rh
|
||||
rm_resources.append(resource)
|
||||
add_uuid = uuidutils.generate_uuid()
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = add_uuid
|
||||
resource.type = constants.TYPE_COMPUTE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = vnfc_resource.vdu_id
|
||||
add_resources.append(resource)
|
||||
|
||||
key_id = vnfc_resource.compute_resource.resource_id
|
||||
for placement_obj in placement_obj_list:
|
||||
resource_dict = jsonutils.loads(placement_obj.resource)
|
||||
set_flg = False
|
||||
for resource in resource_dict:
|
||||
if resource.get('resource_id') == key_id:
|
||||
resource['id_type'] = 'GRANT'
|
||||
resource['resource_id'] = add_uuid
|
||||
g_name = placement_obj.server_group_name
|
||||
affinity_list.append(g_name)
|
||||
set_flg = True
|
||||
res_json = jsonutils.dump_as_bytes(resource_dict)
|
||||
placement_obj.resource = res_json
|
||||
break
|
||||
if set_flg:
|
||||
break
|
||||
vnfc_resource.id = add_uuid
|
||||
vnfc_resource.compute_resource = objects.ResourceHandle()
|
||||
|
||||
st_info = vnf_instantiated_info_after.virtual_storage_resource_info
|
||||
for storage_resource in st_info:
|
||||
if storage_resource.virtual_storage_desc_id in cinder_list:
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
id_list = vnfc_resource.storage_resource_ids
|
||||
if storage_resource.id in id_list:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = storage_resource.id
|
||||
resource.type = constants.TYPE_STORAGE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
storage_resource.virtual_storage_desc_id
|
||||
st_rh = objects.ResourceHandle()
|
||||
st_rh.vim_connection_id = \
|
||||
storage_resource.storage_resource.vim_connection_id
|
||||
st_rh.resource_id = \
|
||||
storage_resource.storage_resource.resource_id
|
||||
resource.resource = st_rh
|
||||
rm_resources.append(resource)
|
||||
|
||||
add_uuid = uuidutils.generate_uuid()
|
||||
resource = objects.ResourceDefinition()
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = add_uuid
|
||||
resource.type = constants.TYPE_STORAGE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
storage_resource.virtual_storage_desc_id
|
||||
add_resources.append(resource)
|
||||
storage_resource.id = add_uuid
|
||||
storage_resource.storage_resource = \
|
||||
objects.ResourceHandle()
|
||||
|
||||
p_c_list = []
|
||||
for placement_obj in placement_obj_list:
|
||||
p_constraint = objects.PlacementConstraint()
|
||||
p_constraint.affinity_or_anti_affinity = \
|
||||
placement_obj.affinity_or_anti_affinity
|
||||
p_constraint.scope = placement_obj.scope
|
||||
resource_dict = jsonutils.loads(placement_obj.resource)
|
||||
p_constraint.resource = []
|
||||
for rsc in resource_dict:
|
||||
rsc_obj = objects.ConstraintResourceRef()
|
||||
rsc_obj.id_type = rsc.get('id_type')
|
||||
rsc_obj.resource_id = rsc.get('resource_id')
|
||||
p_constraint.resource.append(rsc_obj)
|
||||
p_constraint.fallback_best_effort = True
|
||||
p_c_list.append(p_constraint)
|
||||
|
||||
g_request = self._make_grant_request(context,
|
||||
vnf_instance,
|
||||
vnf_lcm_op_occ_id,
|
||||
'HEAL',
|
||||
False,
|
||||
add_resources=add_resources,
|
||||
remove_resources=rm_resources,
|
||||
placement_constraints=p_c_list)
|
||||
|
||||
vnf_dict['placement_obj_list'] = placement_obj_list
|
||||
vnf_dict['grant'] = self._grant(context, g_request)
|
||||
vnf_dict['vnf_instantiated_info_after'] = vnf_instantiated_info_after
|
||||
|
||||
@grant_error_common
|
||||
def _terminate_grant(self, context, vnf_instance, vnf_lcm_op_occ_id):
|
||||
vnf_inf = vnf_instance.instantiated_vnf_info
|
||||
if not self._get_grant_execute():
|
||||
return
|
||||
|
||||
rm_resources = []
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = vnfc_resource.id
|
||||
resource.type = constants.TYPE_COMPUTE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = vnfc_resource.vdu_id
|
||||
vim_id = vnfc_resource.compute_resource.vim_connection_id
|
||||
rsc_id = vnfc_resource.compute_resource.resource_id
|
||||
vnfc_rh = objects.ResourceHandle(
|
||||
vim_connection_id=vim_id,
|
||||
resource_id=rsc_id)
|
||||
resource.resource = vnfc_rh
|
||||
rm_resources.append(resource)
|
||||
|
||||
for vl_resource in vnf_inf.vnf_virtual_link_resource_info:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = vl_resource.id
|
||||
resource.type = constants.TYPE_VL
|
||||
resource.resource_template_id = \
|
||||
vl_resource.vnf_virtual_link_desc_id
|
||||
vim_id = vl_resource.network_resource.vim_connection_id
|
||||
rsc_id = vl_resource.network_resource.resource_id
|
||||
vl_rh = objects.ResourceHandle(
|
||||
vim_connection_id=vim_id,
|
||||
resource_id=rsc_id)
|
||||
resource.resource = vl_rh
|
||||
rm_resources.append(resource)
|
||||
for cp_resource in vl_resource.vnf_link_ports:
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
for vnfc_cp_resource in vnfc_resource.vnfc_cp_info:
|
||||
if cp_resource.cp_instance_id == vnfc_cp_resource.id:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = cp_resource.id
|
||||
resource.type = constants.TYPE_LINKPORT
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
vnfc_cp_resource.cpd_id
|
||||
vim_id = \
|
||||
cp_resource.resource_handle.vim_connection_id
|
||||
rsc_id = cp_resource.resource_handle.resource_id
|
||||
cp_rh = objects.ResourceHandle(
|
||||
vim_connection_id=vim_id,
|
||||
resource_id=rsc_id)
|
||||
resource.resource = cp_rh
|
||||
rm_resources.append(resource)
|
||||
|
||||
for storage_resource in vnf_inf.virtual_storage_resource_info:
|
||||
for vnfc_resource in vnf_inf.vnfc_resource_info:
|
||||
if storage_resource.id in vnfc_resource.storage_resource_ids:
|
||||
resource = objects.ResourceDefinition()
|
||||
resource.id = storage_resource.id
|
||||
resource.type = constants.TYPE_STORAGE
|
||||
resource.vdu_id = vnfc_resource.vdu_id
|
||||
resource.resource_template_id = \
|
||||
storage_resource.virtual_storage_desc_id
|
||||
vim_id = \
|
||||
storage_resource.storage_resource.vim_connection_id
|
||||
rsc_id = storage_resource.storage_resource.resource_id
|
||||
st_rh = objects.ResourceHandle(
|
||||
vim_connection_id=vim_id,
|
||||
resource_id=rsc_id)
|
||||
resource.resource = st_rh
|
||||
rm_resources.append(resource)
|
||||
|
||||
grant_request = self._make_grant_request(context,
|
||||
vnf_instance,
|
||||
vnf_lcm_op_occ_id,
|
||||
'TERMINATE',
|
||||
False,
|
||||
remove_resources=rm_resources)
|
||||
self._grant(context, grant_request)
|
||||
|
||||
def _get_grant_execute(self):
|
||||
try:
|
||||
nfvo_client.GrantRequest().validate()
|
||||
except nfvo_client.UndefinedExternalSettingException:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _make_grant_request(self, context, vnf_instance,
|
||||
vnf_lcm_op_occ_id, operation,
|
||||
is_automatic_invocation,
|
||||
add_resources=[],
|
||||
remove_resources=[],
|
||||
placement_constraints=[]):
|
||||
grant_request = objects.GrantRequest()
|
||||
grant_request.vnf_instance_id = vnf_instance.id
|
||||
grant_request.vnf_lcm_op_occ_id = vnf_lcm_op_occ_id
|
||||
grant_request.vnfd_id = vnf_instance.vnfd_id
|
||||
grant_request.flavour_id = \
|
||||
vnf_instance.instantiated_vnf_info.flavour_id
|
||||
grant_request.operation = operation
|
||||
grant_request.is_automatic_invocation = is_automatic_invocation
|
||||
vnflcm_url = CONF.vnf_lcm.endpoint_url + \
|
||||
"/vnflcm/v1/vnf_lcm_op_occs/" + vnf_lcm_op_occ_id
|
||||
insta_url = CONF.vnf_lcm.endpoint_url + \
|
||||
"/vnflcm/v1/vnf_instances/" + vnf_instance.id
|
||||
link_vnflcm = objects.Link(href=vnflcm_url)
|
||||
link_insta = objects.Link(href=insta_url)
|
||||
link = objects.Links(vnf_lcm_op_occ=link_vnflcm,
|
||||
vnf_instance=link_insta)
|
||||
grant_request._links = link
|
||||
|
||||
if add_resources:
|
||||
grant_request.add_resources = add_resources
|
||||
if remove_resources:
|
||||
grant_request.remove_resources = remove_resources
|
||||
if placement_constraints:
|
||||
grant_request.placement_constraints = placement_constraints
|
||||
|
||||
return grant_request
|
||||
|
||||
def _create_placement(self, context, vnf_dict):
|
||||
p_list = vnf_dict.get('placement_obj_list', [])
|
||||
if len(p_list) == 0:
|
||||
return
|
||||
self.vnfm_plugin.create_placement_constraint(context,
|
||||
p_list)
|
||||
|
||||
def _update_placement(self, context, vnf_dict, vnf_instance):
|
||||
self.vnfm_plugin.update_placement_constraint(context,
|
||||
vnf_dict,
|
||||
vnf_instance)
|
||||
|
||||
def _delete_placement(self, context, vnf_instance_id):
|
||||
self.vnfm_plugin.delete_placement_constraint(context,
|
||||
vnf_instance_id)
|
||||
|
||||
@log.log
|
||||
def _get_vnf_notify(self, context, id):
|
||||
try:
|
||||
@ -790,6 +1367,7 @@ class Conductor(manager.Manager):
|
||||
is_automatic_invocation = \
|
||||
kwargs.get('is_automatic_invocation', False)
|
||||
error = kwargs.get('error', None)
|
||||
# Used for timing control when a failure occurs
|
||||
|
||||
if old_vnf_instance:
|
||||
vnf_instance_id = old_vnf_instance.id
|
||||
@ -918,7 +1496,7 @@ class Conductor(manager.Manager):
|
||||
self.__set_auth_subscription(line)
|
||||
|
||||
for num in range(CONF.vnf_lcm.retry_num):
|
||||
LOG.info("send notify[%s]" % json.dumps(notification))
|
||||
LOG.warn("send notify[%s]" % json.dumps(notification))
|
||||
auth_client = auth.auth_manager.get_auth_client(
|
||||
notification['subscriptionId'])
|
||||
response = auth_client.post(
|
||||
@ -965,6 +1543,12 @@ class Conductor(manager.Manager):
|
||||
instantiate_vnf,
|
||||
vnf_lcm_op_occs_id):
|
||||
|
||||
self._instantiate_grant(context,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
instantiate_vnf,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
try:
|
||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||
self._send_lcm_op_occ_notification(
|
||||
@ -993,6 +1577,8 @@ class Conductor(manager.Manager):
|
||||
instantiation_state=fields.VnfInstanceState.
|
||||
INSTANTIATED, task_state=None)
|
||||
|
||||
self._create_placement(context, vnf_dict)
|
||||
|
||||
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
@ -1024,6 +1610,11 @@ class Conductor(manager.Manager):
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def terminate(self, context, vnf_lcm_op_occs_id,
|
||||
vnf_instance, terminate_vnf_req, vnf_dict):
|
||||
|
||||
self._terminate_grant(context,
|
||||
vnf_instance,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
try:
|
||||
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||
|
||||
@ -1042,6 +1633,9 @@ class Conductor(manager.Manager):
|
||||
|
||||
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
|
||||
self._delete_placement(context, vnf_instance.id)
|
||||
|
||||
self._change_vnf_status(context, vnf_instance.id,
|
||||
_PENDING_STATUS, 'INACTIVE')
|
||||
|
||||
@ -1086,6 +1680,12 @@ class Conductor(manager.Manager):
|
||||
heal_vnf_request,
|
||||
vnf_lcm_op_occs_id):
|
||||
|
||||
self._heal_grant(context,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
heal_vnf_request,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
try:
|
||||
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||
|
||||
@ -1117,6 +1717,8 @@ class Conductor(manager.Manager):
|
||||
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
|
||||
task_state=None)
|
||||
|
||||
self._update_placement(context, vnf_dict, vnf_instance)
|
||||
|
||||
# update vnf_lcm_op_occs and send notification "COMPLETED"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
@ -1150,16 +1752,15 @@ class Conductor(manager.Manager):
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def scale(self, context, vnf_info, vnf_instance, scale_vnf_request):
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Scale action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
vnf_lcm_op_occ = vnf_info['vnf_lcm_op_occ']
|
||||
vnf_lcm_op_occ_id = vnf_lcm_op_occ.id
|
||||
|
||||
self._scale_grant(
|
||||
context,
|
||||
vnf_info,
|
||||
vnf_instance,
|
||||
scale_vnf_request,
|
||||
vnf_lcm_op_occ_id)
|
||||
|
||||
self.vnflcm_driver.scale_vnf(
|
||||
context, vnf_info, vnf_instance, scale_vnf_request)
|
||||
|
@ -301,7 +301,7 @@ class VnfLcmOpOccs(model_base.BASE, models.SoftDeleteMixin,
|
||||
"""VNF LCM OP OCCS Fields"""
|
||||
|
||||
__tablename__ = 'vnf_lcm_op_occs'
|
||||
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
id = sa.Column(sa.String(16), primary_key=True)
|
||||
vnf_instance_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('vnf_instances.id'),
|
||||
nullable=False)
|
||||
@ -316,3 +316,17 @@ class VnfLcmOpOccs(model_base.BASE, models.SoftDeleteMixin,
|
||||
resource_changes = sa.Column(sa.JSON(), nullable=True)
|
||||
changed_info = sa.Column(sa.JSON(), nullable=True)
|
||||
error_point = sa.Column(sa.Integer, nullable=False)
|
||||
|
||||
|
||||
class PlacementConstraint(model_base.BASE, models.SoftDeleteMixin,
|
||||
models.TimestampMixin, models_v1.HasId):
|
||||
"""Represents a Vnf Placement Constraint."""
|
||||
|
||||
__tablename__ = 'placement_constraint'
|
||||
vnf_instance_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('vnf_instances.id'),
|
||||
nullable=False)
|
||||
affinity_or_anti_affinity = sa.Column(sa.String(255), nullable=False)
|
||||
scope = sa.Column(sa.String(255), nullable=False)
|
||||
server_group_name = sa.Column(sa.String(255), nullable=False)
|
||||
resource = sa.Column(sa.JSON(), nullable=True)
|
||||
|
@ -0,0 +1,52 @@
|
||||
# Copyright 2020 OpenStack Foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""add placement table
|
||||
|
||||
Revision ID: 2c5211036579
|
||||
Revises: ee98bbc0789d
|
||||
Create Date: 2020-09-11 20:47:46.345771
|
||||
|
||||
"""
|
||||
# flake8: noqa: E402
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '2c5211036579'
|
||||
down_revision = 'ee98bbc0789d'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import Boolean
|
||||
|
||||
from tacker.db import types
|
||||
|
||||
|
||||
def upgrade(active_plugins=None, options=None):
|
||||
op.create_table(
|
||||
'placement_constraint',
|
||||
sa.Column('id', types.Uuid(length=36), nullable=False),
|
||||
sa.Column('vnf_instance_id', types.Uuid(length=36), nullable=False),
|
||||
sa.Column('affinity_or_anti_affinity',
|
||||
sa.String(length=255), nullable=False),
|
||||
sa.Column('scope', sa.String(length=255), nullable=False),
|
||||
sa.Column('server_group_name', sa.String(length=255), nullable=False),
|
||||
sa.Column('resource', sa.JSON(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('deleted', Boolean, default=False),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_engine='InnoDB'
|
||||
)
|
@ -1 +1 @@
|
||||
ee98bbc0789d
|
||||
2c5211036579
|
@ -18,6 +18,7 @@ from datetime import datetime
|
||||
|
||||
from oslo_db.exception import DBDuplicateEntry
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
@ -29,9 +30,11 @@ from sqlalchemy import schema
|
||||
from tacker._i18n import _
|
||||
from tacker.api.v1 import attributes
|
||||
from tacker.common import exceptions
|
||||
import tacker.conf
|
||||
from tacker import context as t_context
|
||||
from tacker.db.common_services import common_services_db_plugin
|
||||
from tacker.db import db_base
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
from tacker.db import model_base
|
||||
from tacker.db import models_v1
|
||||
from tacker.db.nfvo import ns_db
|
||||
@ -40,6 +43,8 @@ from tacker.extensions import vnfm
|
||||
from tacker import manager
|
||||
from tacker.plugins.common import constants
|
||||
|
||||
CONF = tacker.conf.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
_ACTIVE_UPDATE = (constants.ACTIVE, constants.PENDING_UPDATE,
|
||||
constants.PENDING_HEAL)
|
||||
@ -812,3 +817,51 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
constants.ERROR]
|
||||
return self._mark_vnf_status(
|
||||
vnf_id, exclude_status, constants.DEAD)
|
||||
|
||||
def create_placement_constraint(self, context, placement_obj_list):
|
||||
context.session.add_all(placement_obj_list)
|
||||
|
||||
def get_placement_constraint(self, context, vnf_instance_id):
|
||||
placement_constraint = (
|
||||
self._model_query(context, models.PlacementConstraint).filter(
|
||||
models.PlacementConstraint.vnf_instance_id == vnf_instance_id).
|
||||
filter(models.PlacementConstraint.deleted == 0).all())
|
||||
return placement_constraint
|
||||
|
||||
def update_placement_constraint_heal(self, context,
|
||||
vnf_info,
|
||||
vnf_instance):
|
||||
if not vnf_info.get('grant'):
|
||||
return
|
||||
placement_obj_list = vnf_info['placement_obj_list']
|
||||
inst_info = vnf_instance.instantiated_vnf_info
|
||||
for vnfc in inst_info.vnfc_resource_info:
|
||||
for placement_obj in placement_obj_list:
|
||||
rsc_dict = jsonutils.loads(placement_obj.resource)
|
||||
for rsc in rsc_dict:
|
||||
if vnfc.id == rsc.get('resource_id') and\
|
||||
rsc.get('id_type') == 'GRANT':
|
||||
rsc['id_type'] = 'RES_MGMT'
|
||||
rsc['resource_id'] = vnfc.\
|
||||
compute_resource.resource_id
|
||||
rsc['vim_connection_id'] = vnfc.\
|
||||
compute_resource.vim_connection_id
|
||||
placement_obj.resource = jsonutils.dumps(rsc_dict)
|
||||
self.update_placement_constraint(context, placement_obj)
|
||||
|
||||
def delete_placement_constraint(self, context, vnf_instance_id):
|
||||
(self._model_query(context, models.PlacementConstraint).
|
||||
filter(
|
||||
models.PlacementConstraint.vnf_instance_id == vnf_instance_id).
|
||||
filter(models.PlacementConstraint.deleted == 0).
|
||||
update({'deleted': 0, 'deleted_at': timeutils.utcnow()}))
|
||||
|
||||
def update_placement_constraint(self, context, placement_obj):
|
||||
(self._model_query(
|
||||
context,
|
||||
models.PlacementConstraint).filter(
|
||||
models.PlacementConstraint.id == placement_obj.id).
|
||||
filter(models.PlacementConstraint.deleted == 0).
|
||||
update({
|
||||
'resource': placement_obj.resource,
|
||||
'updated_at': timeutils.utcnow()}))
|
||||
|
@ -42,3 +42,7 @@ def register_all():
|
||||
__import__('tacker.objects.vnf_artifact')
|
||||
__import__('tacker.objects.vnf_lcm_subscriptions')
|
||||
__import__('tacker.objects.scale_vnf_request')
|
||||
__import__('tacker.objects.grant')
|
||||
__import__('tacker.objects.grant_request')
|
||||
__import__('tacker.objects.vnfd')
|
||||
__import__('tacker.objects.vnfd_attribute')
|
||||
|
287
tacker/objects/grant.py
Normal file
287
tacker/objects/grant.py
Normal file
@ -0,0 +1,287 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tacker import objects
|
||||
from tacker.objects import base
|
||||
from tacker.objects import fields
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class Grant(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'vnf_instance_id': fields.StringField(nullable=False),
|
||||
'vnf_lcm_op_occ_id': fields.StringField(nullable=False),
|
||||
'vim_connections': fields.ListOfObjectsField(
|
||||
'VimConnectionInfo', nullable=True, default=[]),
|
||||
'zones': fields.ListOfObjectsField(
|
||||
'ZoneInfo', nullable=True, default=[]),
|
||||
'add_resources': fields.ListOfObjectsField(
|
||||
'GrantInfo', nullable=True, default=[]),
|
||||
'remove_resources': fields.ListOfObjectsField(
|
||||
'GrantInfo', nullable=True, default=[]),
|
||||
'vim_assets': fields.ObjectField(
|
||||
'VimAssets', nullable=True)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_grant = super(
|
||||
Grant, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
if 'vim_connections' in primitive.keys():
|
||||
obj_data = [objects.VimConnectionInfo._from_dict(
|
||||
vim_conn) for vim_conn in primitive.get(
|
||||
'vim_connections', [])]
|
||||
primitive.update({'vim_connections': obj_data})
|
||||
|
||||
if 'zones' in primitive.keys():
|
||||
obj_data = [ZoneInfo._from_dict(
|
||||
zone) for zone in primitive.get(
|
||||
'zones', [])]
|
||||
primitive.update({'zones': obj_data})
|
||||
|
||||
if 'add_resources' in primitive.keys():
|
||||
obj_data = [GrantInfo._from_dict(
|
||||
add_rsc) for add_rsc in primitive.get(
|
||||
'add_resources', [])]
|
||||
primitive.update({'add_resources': obj_data})
|
||||
if 'remove_resources' in primitive.keys():
|
||||
obj_data = [GrantInfo._from_dict(
|
||||
remove_rsc) for remove_rsc in primitive.get(
|
||||
'remove_resources', [])]
|
||||
primitive.update({'remove_resources': obj_data})
|
||||
if 'vim_assets' in primitive.keys():
|
||||
obj_data = VimAssets.obj_from_primitive(
|
||||
primitive.get('vim_assets'), context)
|
||||
primitive.update({'vim_assets': obj_data})
|
||||
|
||||
obj_grant = Grant._from_dict(primitive)
|
||||
|
||||
return obj_grant
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
vnf_instance_id = data_dict.get('vnf_instance_id')
|
||||
vnf_lcm_op_occ_id = data_dict.get('vnf_lcm_op_occ_id')
|
||||
vim_connections = data_dict.get('vim_connections', [])
|
||||
zones = data_dict.get('zones', [])
|
||||
add_resources = data_dict.get('add_resources', [])
|
||||
remove_resources = data_dict.get('remove_resources', [])
|
||||
vim_assets = data_dict.get('vim_assets')
|
||||
|
||||
obj = cls(
|
||||
id=id,
|
||||
vnf_instance_id=vnf_instance_id,
|
||||
vnf_lcm_op_occ_id=vnf_lcm_op_occ_id,
|
||||
vim_connections=vim_connections,
|
||||
zones=zones,
|
||||
add_resources=add_resources,
|
||||
remove_resources=remove_resources,
|
||||
vim_assets=vim_assets)
|
||||
return obj
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ZoneInfo(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'zone_id': fields.StringField(nullable=False),
|
||||
'vim_connection_id': fields.StringField(nullable=True)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_zone_info = super(
|
||||
ZoneInfo, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
obj_zone_info = ZoneInfo._from_dict(primitive)
|
||||
|
||||
return obj_zone_info
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
zone_id = data_dict.get('zone_id')
|
||||
vim_connection_id = data_dict.get('vim_connection_id')
|
||||
|
||||
obj = cls(
|
||||
id=id,
|
||||
zone_id=zone_id,
|
||||
vim_connection_id=vim_connection_id)
|
||||
return obj
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class GrantInfo(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'resource_definition_id': fields.StringField(nullable=False),
|
||||
'vim_connection_id': fields.StringField(nullable=True),
|
||||
'zone_id': fields.StringField(nullable=True)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_grant_info = super(
|
||||
GrantInfo, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
obj_grant_info = GrantInfo._from_dict(primitive)
|
||||
|
||||
return obj_grant_info
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
resource_definition_id = data_dict.get('resource_definition_id')
|
||||
vim_connection_id = data_dict.get('vim_connection_id')
|
||||
zone_id = data_dict.get('zone_id')
|
||||
|
||||
obj = cls(
|
||||
resource_definition_id=resource_definition_id,
|
||||
vim_connection_id=vim_connection_id,
|
||||
zone_id=zone_id)
|
||||
return obj
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VimAssets(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'compute_resource_flavours': fields.ListOfObjectsField(
|
||||
'VimComputeResourceFlavour', nullable=True, default=[]),
|
||||
'software_images': fields.ListOfObjectsField(
|
||||
'VimSoftwareImage', nullable=True, default=[])
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_vim_assets = super(
|
||||
VimAssets, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
if 'compute_resource_flavours' in primitive.keys():
|
||||
obj_data = [VimComputeResourceFlavour._from_dict(
|
||||
flavour) for flavour in primitive.get(
|
||||
'compute_resource_flavours', [])]
|
||||
primitive.update({'compute_resource_flavours': obj_data})
|
||||
|
||||
if 'software_images' in primitive.keys():
|
||||
obj_data = [VimSoftwareImage._from_dict(
|
||||
img) for img in primitive.get(
|
||||
'software_images', [])]
|
||||
primitive.update({'software_images': obj_data})
|
||||
obj_vim_assets = VimAssets._from_dict(primitive)
|
||||
|
||||
return obj_vim_assets
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
compute_resource_flavours = data_dict.get(
|
||||
'compute_resource_flavours', [])
|
||||
software_images = data_dict.get('software_images', [])
|
||||
|
||||
obj = cls(
|
||||
compute_resource_flavours=compute_resource_flavours,
|
||||
software_images=software_images)
|
||||
return obj
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VimComputeResourceFlavour(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'vim_connection_id': fields.StringField(nullable=True),
|
||||
'vnfd_virtual_compute_desc_id': fields.StringField(nullable=False),
|
||||
'vim_flavour_id': fields.StringField(nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_flavour = super(
|
||||
VimComputeResourceFlavour,
|
||||
cls).obj_from_primitive(
|
||||
primitive,
|
||||
context)
|
||||
else:
|
||||
obj_flavour = VimComputeResourceFlavour._from_dict(primitive)
|
||||
|
||||
return obj_flavour
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
vim_connection_id = data_dict.get('vim_connection_id')
|
||||
vnfd_virtual_compute_desc_id = data_dict.get(
|
||||
'vnfd_virtual_compute_desc_id')
|
||||
vim_flavour_id = data_dict.get('vim_flavour_id')
|
||||
|
||||
obj = cls(
|
||||
vim_connection_id=vim_connection_id,
|
||||
vnfd_virtual_compute_desc_id=vnfd_virtual_compute_desc_id,
|
||||
vim_flavour_id=vim_flavour_id)
|
||||
return obj
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VimSoftwareImage(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'vim_connection_id': fields.StringField(nullable=True),
|
||||
'vnfd_software_image_id': fields.StringField(nullable=False),
|
||||
'vim_software_image_id': fields.StringField(nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_img = super(
|
||||
VimSoftwareImage, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
obj_img = VimSoftwareImage._from_dict(primitive)
|
||||
|
||||
return obj_img
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
vim_connection_id = data_dict.get('vim_connection_id')
|
||||
vnfd_software_image_id = data_dict.get('vnfd_software_image_id')
|
||||
vim_software_image_id = data_dict.get('vim_software_image_id')
|
||||
|
||||
obj = cls(
|
||||
vim_connection_id=vim_connection_id,
|
||||
vnfd_software_image_id=vnfd_software_image_id,
|
||||
vim_software_image_id=vim_software_image_id)
|
||||
return obj
|
407
tacker/objects/grant_request.py
Normal file
407
tacker/objects/grant_request.py
Normal file
@ -0,0 +1,407 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from tacker.common import utils
|
||||
from tacker.objects import base
|
||||
from tacker.objects import fields
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class GrantRequest(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'vnf_instance_id': fields.StringField(nullable=False),
|
||||
'vnf_lcm_op_occ_id': fields.StringField(nullable=False),
|
||||
'vnfd_id': fields.StringField(nullable=False),
|
||||
'flavour_id': fields.StringField(nullable=True),
|
||||
'operation': fields.StringField(nullable=False),
|
||||
'is_automatic_invocation': fields.BooleanField(nullable=False,
|
||||
default=False),
|
||||
'add_resources': fields.ListOfObjectsField(
|
||||
'ResourceDefinition', nullable=True, default=[]),
|
||||
'remove_resources': fields.ListOfObjectsField(
|
||||
'ResourceDefinition', nullable=True, default=[]),
|
||||
'placement_constraints': fields.ListOfObjectsField(
|
||||
'PlacementConstraint', nullable=True, default=[]),
|
||||
'_links': fields.ObjectField(
|
||||
'Links', nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_grant_req = super(
|
||||
GrantRequest, cls).obj_from_primitive(primitive, context)
|
||||
else:
|
||||
if 'add_resources' in primitive.keys():
|
||||
obj_data = [ResourceDefinition._from_dict(
|
||||
add_rsc) for add_rsc in primitive.get(
|
||||
'add_resources', [])]
|
||||
primitive.update({'add_resources': obj_data})
|
||||
if 'remove_resources' in primitive.keys():
|
||||
obj_data = [ResourceDefinition._from_dict(
|
||||
remove_rsc) for remove_rsc in primitive.get(
|
||||
'remove_resources', [])]
|
||||
primitive.update({'add_resources': obj_data})
|
||||
if 'placement_constraints' in primitive.keys():
|
||||
obj_data = [PlacementConstraint._from_dict(
|
||||
place) for place in primitive.get(
|
||||
'placement_constraints', [])]
|
||||
primitive.update({'add_resources': obj_data})
|
||||
obj_grant_req = GrantRequest._from_dict(primitive)
|
||||
|
||||
return obj_grant_req
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
vnf_instance_id = data_dict.get('vnf_instance_id')
|
||||
vnf_lcm_op_occ_id = data_dict.get('vnf_lcm_op_occ_id')
|
||||
vnfd_id = data_dict.get('vnfd_id')
|
||||
flavour_id = data_dict.get('flavour_id')
|
||||
operation = data_dict.get('operation')
|
||||
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
||||
add_resources = data_dict.get('add_resources', [])
|
||||
remove_resources = data_dict.get('remove_resources', [])
|
||||
placement_constraints = data_dict.get('placement_constraints', [])
|
||||
links = data_dict.get('_links')
|
||||
|
||||
obj = cls(
|
||||
vnf_instance_id=vnf_instance_id,
|
||||
vnf_lcm_op_occ_id=vnf_lcm_op_occ_id,
|
||||
vnfd_id=vnfd_id,
|
||||
flavour_id=flavour_id,
|
||||
operation=operation,
|
||||
is_automatic_invocation=is_automatic_invocation,
|
||||
add_resources=add_resources,
|
||||
remove_resources=remove_resources,
|
||||
placement_constraints=placement_constraints,
|
||||
_links=links)
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
data = {'vnf_instance_id': self.vnf_instance_id,
|
||||
'vnf_lcm_op_occ_id': self.vnf_lcm_op_occ_id,
|
||||
'vnfd_id': self.vnfd_id,
|
||||
'flavour_id': self.flavour_id,
|
||||
'operation': self.operation,
|
||||
'is_automatic_invocation': self.is_automatic_invocation,
|
||||
'_links': self._links.to_dict()}
|
||||
if self.add_resources:
|
||||
add_resources_list = []
|
||||
for add_resource in self.add_resources:
|
||||
add_resources_list.append(add_resource.to_dict())
|
||||
|
||||
data.update({'add_resources': add_resources_list})
|
||||
if self.remove_resources:
|
||||
remove_resources_list = []
|
||||
for remove_resource in self.remove_resources:
|
||||
remove_resources_list.append(remove_resource.to_dict())
|
||||
|
||||
data.update({'remove_resources': remove_resources_list})
|
||||
if self.placement_constraints:
|
||||
placement_constraints_list = []
|
||||
for placement_constraint in self.placement_constraints:
|
||||
placement_constraints_list.append(
|
||||
placement_constraint.to_dict())
|
||||
|
||||
data.update({'placement_constraints': placement_constraints_list})
|
||||
return data
|
||||
|
||||
def to_request_body(self):
|
||||
req_dict = self.to_dict()
|
||||
req_dict = utils.convert_snakecase_to_camelcase(req_dict)
|
||||
return jsonutils.dumps(req_dict).replace('Links', '_links')
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ResourceDefinition(base.TackerObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'type': fields.StringField(nullable=False),
|
||||
'vdu_id': fields.StringField(nullable=True, default=None),
|
||||
'resource_template_id': fields.StringField(nullable=False),
|
||||
'resource': fields.ObjectField(
|
||||
'ResourceHandle', nullable=True, default=None)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
obj_grant_req = super(
|
||||
ResourceDefinition, cls).\
|
||||
obj_from_primitive(primitive, context)
|
||||
else:
|
||||
if 'resource' in primitive.keys():
|
||||
obj_data = ResourceHandle._from_dict(
|
||||
primitive.get('resource'))
|
||||
primitive.update({'resource': obj_data})
|
||||
obj_grant_req = ResourceDefinition._from_dict(primitive)
|
||||
|
||||
return obj_grant_req
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
type = data_dict.get('type')
|
||||
vdu_id = data_dict.get('vdu_id')
|
||||
resource_template_id = data_dict.get('resource_template_id')
|
||||
resource = data_dict.get('resource')
|
||||
|
||||
obj = cls(
|
||||
id=id,
|
||||
type=type,
|
||||
vdu_id=vdu_id,
|
||||
resource_template_id=resource_template_id,
|
||||
resource=resource)
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||