VNF scaling: REST API
implments blueprint: #vnf-scaling Change-Id: Ib8cdd1295460e617806eec173e4d4ed8f35e6642
This commit is contained in:
parent
89cb3c4fbc
commit
ace3f15c56
@ -243,3 +243,17 @@ class InvalidCIDR(BadRequest):
|
||||
|
||||
class MgmtDriverException(TackerException):
|
||||
message = _("VNF configuration failed")
|
||||
|
||||
|
||||
class VnfPolicyNotFound(NotFound):
|
||||
message = _("Policy %(policy)s does not exist for VNF %(vnf_id)s")
|
||||
|
||||
|
||||
class VnfPolicyActionInvalid(BadRequest):
|
||||
message = _("Invalid action %(action)s for policy %(policy)s, "
|
||||
"should be one of %(valid_acions)s")
|
||||
|
||||
|
||||
class VnfPolicyTypeInvalid(BadRequest):
|
||||
message = _("Invalid type %(type)s for policy %(policy)s, "
|
||||
"should be one of %(valid_types)s")
|
||||
|
@ -402,6 +402,19 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
device_db.update({'status': new_status})
|
||||
return device_db
|
||||
|
||||
def _update_vnf_scaling_status(self,
|
||||
context,
|
||||
policy,
|
||||
previous_statuses,
|
||||
status,
|
||||
mgmt_url=None):
|
||||
with context.session.begin(subtransactions=True):
|
||||
device_db = self._get_device_db(
|
||||
context, policy['vnf']['id'], previous_statuses, status)
|
||||
if mgmt_url:
|
||||
device_db.update({'mgmt_url': mgmt_url})
|
||||
return self._make_device_dict(device_db)
|
||||
|
||||
def _update_device_pre(self, context, device_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
device_db = self._get_device_db(
|
||||
|
@ -20,8 +20,10 @@ import six
|
||||
|
||||
from tacker.api import extensions
|
||||
from tacker.api.v1 import attributes as attr
|
||||
from tacker.api.v1 import base
|
||||
from tacker.api.v1 import resource_helper
|
||||
from tacker.common import exceptions
|
||||
from tacker import manager
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.services import service_base
|
||||
|
||||
@ -305,6 +307,41 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
}
|
||||
|
||||
|
||||
SUB_RESOURCE_ATTRIBUTE_MAP = {
|
||||
'actions': {
|
||||
'parent': {
|
||||
'collection_name': 'vnfs',
|
||||
'member_name': 'vnf'
|
||||
},
|
||||
'members': {
|
||||
'scale': {
|
||||
'parameters': {
|
||||
'policy': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
'validate': {'type:string': None}
|
||||
},
|
||||
'type': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
'validate': {'type:string': None}
|
||||
},
|
||||
'tenant_id': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': False,
|
||||
'is_visible': False
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Vnfm(extensions.ExtensionDescriptor):
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
@ -333,9 +370,31 @@ class Vnfm(extensions.ExtensionDescriptor):
|
||||
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
||||
plural_mappings['service_types'] = 'service_type'
|
||||
attr.PLURALS.update(plural_mappings)
|
||||
return resource_helper.build_resource_info(
|
||||
resources = resource_helper.build_resource_info(
|
||||
plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.VNFM,
|
||||
translate_name=True)
|
||||
plugin = manager.TackerManager.get_service_plugins()[
|
||||
constants.VNFM]
|
||||
for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP:
|
||||
parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name]['parent']
|
||||
|
||||
for resource_name in SUB_RESOURCE_ATTRIBUTE_MAP[
|
||||
collection_name]['members']:
|
||||
params = SUB_RESOURCE_ATTRIBUTE_MAP[
|
||||
collection_name]['members'][resource_name]['parameters']
|
||||
|
||||
controller = base.create_resource(collection_name,
|
||||
resource_name,
|
||||
plugin, params,
|
||||
allow_bulk=True,
|
||||
parent=parent)
|
||||
|
||||
resource = extensions.ResourceExtension(
|
||||
collection_name,
|
||||
controller, parent,
|
||||
attr_map=params)
|
||||
resources.append(resource)
|
||||
return resources
|
||||
|
||||
@classmethod
|
||||
def get_plugin_interface(cls):
|
||||
@ -397,3 +456,8 @@ class VNFMPluginBase(service_base.NFVPluginBase):
|
||||
@abc.abstractmethod
|
||||
def delete_vnf(self, context, vnf_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_vnf_scale(
|
||||
self, context, vnf_id, scale):
|
||||
pass
|
||||
|
@ -29,9 +29,13 @@ COMMON_PREFIXES = {
|
||||
# Service operation status constants
|
||||
ACTIVE = "ACTIVE"
|
||||
DOWN = "DOWN"
|
||||
|
||||
PENDING_CREATE = "PENDING_CREATE"
|
||||
PENDING_UPDATE = "PENDING_UPDATE"
|
||||
PENDING_DELETE = "PENDING_DELETE"
|
||||
PENDING_SCALE_IN = "PENDING_SCALE_IN"
|
||||
PENDING_SCALE_OUT = "PENDING_SCALE_OUT"
|
||||
|
||||
INACTIVE = "INACTIVE"
|
||||
DEAD = "DEAD"
|
||||
ERROR = "ERROR"
|
||||
@ -41,3 +45,8 @@ ACTIVE_PENDING_STATUSES = (
|
||||
PENDING_CREATE,
|
||||
PENDING_UPDATE
|
||||
)
|
||||
|
||||
POLICY_SCALING = 'tosca.policy.tacker.Scaling'
|
||||
POLICY_SCALING_ACTIONS = (ACTION_SCALE_OUT,
|
||||
ACTION_SCALE_IN) = ('out', 'in')
|
||||
POLICY_ACTIONS = {POLICY_SCALING: POLICY_SCALING_ACTIONS}
|
||||
|
@ -17,6 +17,7 @@
|
||||
import copy
|
||||
import inspect
|
||||
import six
|
||||
import yaml
|
||||
|
||||
import eventlet
|
||||
from oslo_config import cfg
|
||||
@ -27,7 +28,7 @@ from oslo_utils import excutils
|
||||
from tacker._i18n import _LE
|
||||
from tacker.api.v1 import attributes
|
||||
from tacker.common import driver_manager
|
||||
from tacker.common.exceptions import MgmtDriverException
|
||||
from tacker.common import exceptions
|
||||
from tacker.db.vm import vm_db
|
||||
from tacker.extensions import vnfm
|
||||
from tacker.plugins.common import constants
|
||||
@ -243,7 +244,7 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
new_status = constants.ACTIVE
|
||||
try:
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
except MgmtDriverException:
|
||||
except exceptions.MgmtDriverException:
|
||||
LOG.error(_('VNF configuration failed'))
|
||||
new_status = constants.ERROR
|
||||
self.set_device_error_status_reason(context, device_id,
|
||||
@ -319,7 +320,7 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
context=context, device_id=instance_id, auth_attr=vim_auth,
|
||||
region_name=region_name)
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
except MgmtDriverException as e:
|
||||
except exceptions.MgmtDriverException as e:
|
||||
LOG.error(_('VNF configuration failed'))
|
||||
new_status = constants.ERROR
|
||||
self.set_device_error_status_reason(context, device_dict['id'],
|
||||
@ -415,6 +416,127 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
|
||||
self.spawn_n(self._delete_device_wait, context, device_dict, vim_auth)
|
||||
|
||||
def _handle_vnf_scaling(self, context, policy):
|
||||
# validate
|
||||
def _validate_scaling_policy():
|
||||
type = policy['type']
|
||||
|
||||
if type not in constants.POLICY_ACTIONS.keys():
|
||||
raise exceptions.VnfPolicyTypeInvalid(
|
||||
type=type,
|
||||
valid_types=constants.POLICY_ACTIONS.keys(),
|
||||
policy=policy['id']
|
||||
)
|
||||
action = policy['action']
|
||||
|
||||
if action not in constants.POLICY_ACTIONS[type]:
|
||||
raise exceptions.VnfPolicyActionInvalid(
|
||||
action=action,
|
||||
valid_actions=constants.POLICY_ACTIONS[type],
|
||||
policy=policy['id']
|
||||
)
|
||||
|
||||
LOG.debug(_("Policy %s is validated successfully") % policy)
|
||||
|
||||
def _get_status():
|
||||
if policy['action'] == constants.ACTION_SCALE_IN:
|
||||
status = constants.PENDING_SCALE_IN
|
||||
else:
|
||||
status = constants.PENDING_SCALE_OUT
|
||||
|
||||
return status
|
||||
|
||||
# pre
|
||||
def _handle_vnf_scaling_pre():
|
||||
status = _get_status()
|
||||
result = self._update_vnf_scaling_status(context,
|
||||
policy,
|
||||
[constants.ACTIVE],
|
||||
status)
|
||||
LOG.debug(_("Policy %(policy)s vnf is at %(status)s"),
|
||||
{'policy': policy,
|
||||
'status': status})
|
||||
return result
|
||||
|
||||
# post
|
||||
def _handle_vnf_scaling_post(new_status, mgmt_url=None):
|
||||
status = _get_status()
|
||||
result = self._update_vnf_scaling_status(context,
|
||||
policy,
|
||||
[status],
|
||||
new_status,
|
||||
mgmt_url)
|
||||
LOG.debug(_("Policy %(policy)s vnf is at %(status)s"),
|
||||
{'policy': policy,
|
||||
'status': new_status})
|
||||
return result
|
||||
|
||||
# action
|
||||
def _vnf_policy_action():
|
||||
try:
|
||||
self._device_manager.invoke(
|
||||
infra_driver,
|
||||
'scale',
|
||||
plugin=self,
|
||||
context=context,
|
||||
auth_attr=vim_auth,
|
||||
policy=policy,
|
||||
region_name=region_name
|
||||
)
|
||||
LOG.debug(_("Policy %s action is started successfully") %
|
||||
policy)
|
||||
except Exception as e:
|
||||
LOG.error(_("Policy %s action is failed to start") %
|
||||
policy)
|
||||
with excutils.save_and_reraise_exception():
|
||||
vnf['status'] = constants.ERROR
|
||||
self.set_device_error_status_reason(
|
||||
context,
|
||||
policy['vnf_id'],
|
||||
six.text_type(e))
|
||||
_handle_vnf_scaling_post(constants.ERROR)
|
||||
|
||||
# wait
|
||||
def _vnf_policy_action_wait():
|
||||
try:
|
||||
LOG.debug(_("Policy %s action is in progress") %
|
||||
policy)
|
||||
mgmt_url = self._device_manager.invoke(
|
||||
infra_driver,
|
||||
'scale_wait',
|
||||
plugin=self,
|
||||
context=context,
|
||||
auth_attr=vim_auth,
|
||||
policy=policy,
|
||||
region_name=region_name
|
||||
)
|
||||
LOG.debug(_("Policy %s action is completed successfully") %
|
||||
policy)
|
||||
_handle_vnf_scaling_post(constants.ACTIVE, mgmt_url)
|
||||
# TODO(kanagaraj-manickam): Add support for config and mgmt
|
||||
except Exception as e:
|
||||
LOG.error(_("Policy %s action is failed to complete") %
|
||||
policy)
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.set_device_error_status_reason(
|
||||
context,
|
||||
policy['vnf_id'],
|
||||
six.text_type(e))
|
||||
_handle_vnf_scaling_post(constants.ERROR)
|
||||
|
||||
_validate_scaling_policy()
|
||||
|
||||
vnf = _handle_vnf_scaling_pre()
|
||||
policy['instance_id'] = vnf['instance_id']
|
||||
|
||||
infra_driver = self._infra_driver_name(vnf)
|
||||
vim_auth = self.get_vim(context, vnf)
|
||||
region_name = vnf.get('placement_attr', {}).get('region_name', None)
|
||||
_vnf_policy_action()
|
||||
self.spawn_n(_vnf_policy_action_wait)
|
||||
|
||||
return policy
|
||||
|
||||
def create_vnf(self, context, vnf):
|
||||
vnf['device'] = vnf.pop('vnf')
|
||||
vnf_attributes = vnf['device']
|
||||
@ -436,3 +558,59 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
vnfd['device_template'] = vnfd.pop('vnfd')
|
||||
new_dict = self.create_device_template(context, vnfd)
|
||||
return new_dict
|
||||
|
||||
def _make_policy_dict(self, vnf, name, policy):
|
||||
p = {}
|
||||
p['type'] = policy['type']
|
||||
p['properties'] = policy['properties']
|
||||
p['vnf'] = vnf
|
||||
p['name'] = name
|
||||
p['id'] = p['name']
|
||||
return p
|
||||
|
||||
def get_vnf_policies(
|
||||
self, context, vnf_id, filters=None, fields=None):
|
||||
vnf = self.get_device(context, vnf_id)
|
||||
vnfd_tmpl = yaml.load(vnf['device_template']['attributes']['vnfd'])
|
||||
policy_list = []
|
||||
|
||||
if vnfd_tmpl.get('tosca_definitions_version'):
|
||||
polices = vnfd_tmpl['topology_template'].get('policies', [])
|
||||
for policy_dict in polices:
|
||||
for name, policy in policy_dict.items():
|
||||
def _add(policy):
|
||||
p = self._make_policy_dict(vnf, name, policy)
|
||||
p['name'] = name
|
||||
policy_list.append(p)
|
||||
|
||||
# Check for filters
|
||||
if filters.get('name'):
|
||||
if name == filters.get('name'):
|
||||
_add(policy)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
_add(policy)
|
||||
|
||||
return policy_list
|
||||
|
||||
def get_vnf_policy(
|
||||
self, context, policy_id, vnf_id, fields=None):
|
||||
policies = self.get_vnf_policies(context,
|
||||
vnf_id,
|
||||
filters={'name': policy_id})
|
||||
if policies:
|
||||
return policies[0]
|
||||
|
||||
raise exceptions.VnfPolicyNotFound(policy=policy_id,
|
||||
vnf_id=vnf_id)
|
||||
|
||||
def create_vnf_scale(self, context, vnf_id, scale):
|
||||
policy_ = self.get_vnf_policy(context,
|
||||
scale['scale']['policy'],
|
||||
vnf_id)
|
||||
policy_.update({'action': scale['scale']['type']})
|
||||
self._handle_vnf_scaling(context, policy_)
|
||||
|
||||
return scale['scale']
|
||||
|
Loading…
Reference in New Issue
Block a user