Revert "drop service instance rest resources and drop related codes"
This reverts commit 885387a4da
.
Conflicts:
tacker/db/migration/alembic_migrations/versions/4c31092895b8_remove_service_instance.py
tacker/db/vm/vm_db.py
tacker/extensions/servicevm.py
tacker/vm/plugin.py
Change-Id: Idef94da39de90cc5bcc4e830a054083059844a04
This commit is contained in:
parent
8c84c75ff6
commit
0eb6636990
|
@ -1 +1 @@
|
|||
4c31092895b8
|
||||
4c31092895b8
|
||||
|
|
|
@ -51,6 +51,11 @@ class DeviceTemplate(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
|||
name = sa.Column(sa.String(255))
|
||||
description = sa.Column(sa.String(255))
|
||||
|
||||
# service type that this service vm provides.
|
||||
# At first phase, this includes only single service
|
||||
# In future, single service VM may accomodate multiple services.
|
||||
service_types = orm.relationship('ServiceType', backref='template')
|
||||
|
||||
# driver to create hosting device. e.g. noop, nova, heat, etc...
|
||||
infra_driver = sa.Column(sa.String(255))
|
||||
|
||||
|
@ -59,6 +64,16 @@ class DeviceTemplate(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
|||
backref='template')
|
||||
|
||||
|
||||
class ServiceType(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
||||
"""Represents service type which hosting device provides.
|
||||
Since a device may provide many services, This is one-to-many
|
||||
relationship.
|
||||
"""
|
||||
template_id = sa.Column(sa.String(36), sa.ForeignKey('devicetemplates.id'),
|
||||
nullable=False)
|
||||
service_type = sa.Column(sa.String(255), nullable=False)
|
||||
|
||||
|
||||
class DeviceTemplateAttribute(model_base.BASE, models_v1.HasId):
|
||||
"""Represents attributes necessary for spinning up VM in (key, value) pair
|
||||
key value pair is adopted for being agnostic to actuall manager of VMs
|
||||
|
@ -88,6 +103,9 @@ class Device(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
|||
# e.g. (driver, mgmt_url) = (ssh, ip address), ...
|
||||
mgmt_url = sa.Column(sa.String(255), nullable=True)
|
||||
|
||||
service_context = orm.relationship('DeviceServiceContext')
|
||||
services = orm.relationship('ServiceDeviceBinding', backref='device')
|
||||
|
||||
status = sa.Column(sa.String(255), nullable=False)
|
||||
|
||||
|
||||
|
@ -106,8 +124,132 @@ class DeviceAttribute(model_base.BASE, models_v1.HasId):
|
|||
value = sa.Column(sa.String(4096), nullable=True)
|
||||
|
||||
|
||||
# TODO(yamahata): This is tentative.
|
||||
# In the future, this will be replaced with db models of
|
||||
# service insertion/chain.
|
||||
# Since such models are under discussion/development as of
|
||||
# this time, this models is just for lbaas driver of hosting
|
||||
# device
|
||||
# This corresponds to the instantiation of DP_IF_Types
|
||||
class DeviceServiceContext(model_base.BASE, models_v1.HasId):
|
||||
"""Represents service context of Device for scheduler.
|
||||
This represents service insertion/chainging of a given device.
|
||||
"""
|
||||
device_id = sa.Column(sa.String(36), sa.ForeignKey('devices.id'))
|
||||
network_id = sa.Column(sa.String(36), nullable=True)
|
||||
subnet_id = sa.Column(sa.String(36), nullable=True)
|
||||
port_id = sa.Column(sa.String(36), nullable=True)
|
||||
router_id = sa.Column(sa.String(36), nullable=True)
|
||||
|
||||
role = sa.Column(sa.String(255), nullable=True)
|
||||
# disambiguation between same roles
|
||||
index = sa.Column(sa.Integer, nullable=True)
|
||||
|
||||
|
||||
# this table corresponds to ServiceInstance of the original spec
|
||||
class ServiceInstance(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
||||
"""Represents logical service instance
|
||||
This table is only to tell what logical service instances exists.
|
||||
There will be service specific tables for each service types which holds
|
||||
actuall parameters necessary for specific service type.
|
||||
For example, tables for "Routers", "LBaaS", "FW", tables. which table
|
||||
is implicitly determined by service_type_id.
|
||||
"""
|
||||
name = sa.Column(sa.String(255), nullable=True)
|
||||
service_type_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('servicetypes.id'))
|
||||
service_type = orm.relationship('ServiceType')
|
||||
# points to row in service specific table if any.
|
||||
service_table_id = sa.Column(sa.String(36), nullable=True)
|
||||
|
||||
# True: This service is managed by user so that user is able to
|
||||
# change its configurations
|
||||
# False: This service is manged by other tacker service like lbaas
|
||||
# so that user can't change the configuration directly via
|
||||
# servicevm API, but via API for the service.
|
||||
managed_by_user = sa.Column(sa.Boolean(), default=False)
|
||||
|
||||
# mgmt driver to communicate with logical service instance in
|
||||
# hosting device.
|
||||
# e.g. noop, OpenStack MGMT, OpenStack notification, netconf, snmp,
|
||||
# ssh, etc...
|
||||
mgmt_driver = sa.Column(sa.String(255))
|
||||
|
||||
# For a management tool to talk to manage this service instance.
|
||||
# opaque string. mgmt_driver interprets it.
|
||||
mgmt_address = sa.Column(sa.String(255), nullable=True)
|
||||
|
||||
service_context = orm.relationship('ServiceContext')
|
||||
devices = orm.relationship('ServiceDeviceBinding')
|
||||
|
||||
status = sa.Column(sa.String(255), nullable=False)
|
||||
|
||||
# TODO(yamahata): re-think the necessity of following columns
|
||||
# They are all commented out for minimalism for now.
|
||||
# They will be added when it is found really necessary.
|
||||
#
|
||||
# multi_tenant = sa.Column(sa.Boolean())
|
||||
# state = sa.Column(sa.Enum('UP', 'DOWN',
|
||||
# name='service_instance_state'))
|
||||
# For a logical service instance in hosting device to recieve
|
||||
# requests from management tools.
|
||||
# opaque string. mgmt_driver interprets it.
|
||||
# e.g. the name of the interface inside the VM + protocol
|
||||
# vm_mgmt_if = sa.Column(sa.String(255), default=None, nullable=True)
|
||||
# networks =
|
||||
# obj_store =
|
||||
# cost_factor =
|
||||
|
||||
|
||||
# TODO(yamahata): This is tentative.
|
||||
# In the future, this will be replaced with db models of
|
||||
# service insertion/chain.
|
||||
# Since such models are under discussion/development as of
|
||||
# this time, this models is just for lbaas driver of hosting
|
||||
# device
|
||||
# This corresponds to networks of Logical Service Instance in the origianl spec
|
||||
class ServiceContext(model_base.BASE, models_v1.HasId):
|
||||
"""Represents service context of logical service instance.
|
||||
This represents service insertion/chainging of a given device.
|
||||
This is equal or subset of DeviceServiceContext of the
|
||||
corresponding Device.
|
||||
"""
|
||||
service_instance_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('serviceinstances.id'))
|
||||
network_id = sa.Column(sa.String(36), nullable=True)
|
||||
subnet_id = sa.Column(sa.String(36), nullable=True)
|
||||
port_id = sa.Column(sa.String(36), nullable=True)
|
||||
router_id = sa.Column(sa.String(36), nullable=True)
|
||||
|
||||
role = sa.Column(sa.String(255), nullable=True)
|
||||
index = sa.Column(sa.Integer, nullable=True) # disambiguation
|
||||
|
||||
|
||||
class ServiceDeviceBinding(model_base.BASE):
|
||||
"""Represents binding with Device and LogicalResource.
|
||||
Since Device can accomodate multiple services, it's many-to-one
|
||||
relationship.
|
||||
"""
|
||||
service_instance_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('serviceinstances.id'), primary_key=True)
|
||||
device_id = sa.Column(sa.String(36), sa.ForeignKey('devices.id'),
|
||||
primary_key=True)
|
||||
|
||||
|
||||
###########################################################################
|
||||
# actual code to manage those tables
|
||||
class ServiceContextEntry(dict):
|
||||
@classmethod
|
||||
def create(cls, network_id, subnet_id, port_id, router_id, role, index):
|
||||
return cls({
|
||||
'network_id': network_id,
|
||||
'subnet_id': subnet_id,
|
||||
'port_id': port_id,
|
||||
'router_id': router_id,
|
||||
'role': role,
|
||||
'index': index,
|
||||
})
|
||||
|
||||
|
||||
class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
||||
db_base.CommonDbMixin):
|
||||
|
@ -130,6 +272,10 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
except orm_exc.NoResultFound:
|
||||
if issubclass(model, DeviceTemplate):
|
||||
raise servicevm.DeviceTemplateNotFound(device_tempalte_id=id)
|
||||
elif issubclass(model, ServiceType):
|
||||
raise servicevm.ServiceTypeNotFound(service_type_id=id)
|
||||
elif issubclass(model, ServiceInstance):
|
||||
raise servicevm.ServiceInstanceNotFound(service_instance_id=id)
|
||||
if issubclass(model, Device):
|
||||
raise servicevm.DeviceNotFound(device_id=id)
|
||||
else:
|
||||
|
@ -138,6 +284,11 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
def _make_attributes_dict(self, attributes_db):
|
||||
return dict((attr.key, attr.value) for attr in attributes_db)
|
||||
|
||||
def _make_service_types_list(self, service_types):
|
||||
return [{'id': service_type.id,
|
||||
'service_type': service_type.service_type}
|
||||
for service_type in service_types]
|
||||
|
||||
def _make_template_dict(self, template, fields=None):
|
||||
res = {
|
||||
'attributes': self._make_attributes_dict(template['attributes']),
|
||||
|
@ -146,21 +297,56 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
res.update((key, template[key]) for key in key_list)
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _make_services_list(self, binding_db):
|
||||
return [binding.service_instance_id for binding in binding_db]
|
||||
|
||||
def _make_kwargs_dict(self, kwargs_db):
|
||||
return dict((arg.key, jsonutils.loads(arg.value)) for arg in kwargs_db)
|
||||
|
||||
def _make_device_service_context_dict(self, service_context):
|
||||
key_list = ('id', 'network_id', 'subnet_id', 'port_id', 'router_id',
|
||||
'role', 'index')
|
||||
return [self._fields(dict((key, entry[key]) for key in key_list), None)
|
||||
for entry in service_context]
|
||||
|
||||
def _make_device_dict(self, device_db, fields=None):
|
||||
LOG.debug(_('device_db %s'), device_db)
|
||||
res = {
|
||||
'services':
|
||||
self._make_services_list(getattr(device_db, 'services', [])),
|
||||
'device_template':
|
||||
self._make_template_dict(device_db.template),
|
||||
'kwargs': self._make_kwargs_dict(device_db.kwargs),
|
||||
'service_context':
|
||||
self._make_device_service_context_dict(device_db.service_context),
|
||||
}
|
||||
key_list = ('id', 'tenant_id', 'instance_id', 'template_id', 'status',
|
||||
'mgmt_url')
|
||||
res.update((key, device_db[key]) for key in key_list)
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _make_service_context_dict(self, service_context):
|
||||
key_list = ('id', 'network_id', 'subnet_id', 'port_id', 'router_id',
|
||||
'role', 'index')
|
||||
return [self._fields(dict((key, entry[key]) for key in key_list), None)
|
||||
for entry in service_context]
|
||||
|
||||
def _make_service_device_list(self, devices):
|
||||
return [binding.device_id for binding in devices]
|
||||
|
||||
def _make_service_instance_dict(self, instance_db, fields=None):
|
||||
res = {
|
||||
'service_context':
|
||||
self._make_service_context_dict(instance_db.service_context),
|
||||
'devices':
|
||||
self._make_service_device_list(instance_db.devices)
|
||||
}
|
||||
key_list = ('id', 'tenant_id', 'name', 'service_type_id',
|
||||
'service_table_id', 'mgmt_driver', 'mgmt_address',
|
||||
'status')
|
||||
res.update((key, instance_db[key]) for key in key_list)
|
||||
return self._fields(res, fields)
|
||||
|
||||
@staticmethod
|
||||
def _infra_driver_name(device_dict):
|
||||
return device_dict['device_template']['infra_driver']
|
||||
|
@ -177,10 +363,18 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
LOG.debug(_('template %s'), template)
|
||||
tenant_id = self._get_tenant_id_for_create(context, template)
|
||||
infra_driver = template.get('infra_driver')
|
||||
mgmt_driver = template.get('mgmt_driver')
|
||||
service_types = template.get('service_types')
|
||||
|
||||
if (not attributes.is_attr_set(infra_driver)):
|
||||
LOG.debug(_('hosting device driver unspecified'))
|
||||
raise servicevm.InfraDriverNotSpecified()
|
||||
if (not attributes.is_attr_set(mgmt_driver)):
|
||||
LOG.debug(_('mgmt driver unspecified'))
|
||||
raise servicevm.MGMTDriverNotSpecified()
|
||||
if (not attributes.is_attr_set(service_types)):
|
||||
LOG.debug(_('service types unspecified'))
|
||||
raise servicevm.SeviceTypesNotSpecified()
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
template_id = str(uuid.uuid4())
|
||||
|
@ -198,6 +392,14 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
key=key,
|
||||
value=value)
|
||||
context.session.add(attribute_db)
|
||||
for service_type in (item['service_type']
|
||||
for item in template['service_types']):
|
||||
service_type_db = ServiceType(
|
||||
id=str(uuid.uuid4()),
|
||||
tenant_id=tenant_id,
|
||||
template_id=template_id,
|
||||
service_type=service_type)
|
||||
context.session.add(service_type_db)
|
||||
|
||||
LOG.debug(_('template_db %(template_db)s %(attributes)s '),
|
||||
{'template_db': template_db,
|
||||
|
@ -222,6 +424,8 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
raise servicevm.DeviceTemplateInUse(
|
||||
device_template_id=device_template_id)
|
||||
|
||||
context.session.query(ServiceType).filter_by(
|
||||
template_id=device_template_id).delete()
|
||||
context.session.query(DeviceTemplateAttribute).filter_by(
|
||||
template_id=device_template_id).delete()
|
||||
template_db = self._get_resource(context, DeviceTemplate,
|
||||
|
@ -240,11 +444,18 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
|
||||
# called internally, not by REST API
|
||||
# need enhancement?
|
||||
def choose_device_template(self, context, required_attributes=None):
|
||||
def choose_device_template(self, context, service_type,
|
||||
required_attributes=None):
|
||||
required_attributes = required_attributes or []
|
||||
LOG.debug(_('required_attributes %s'), required_attributes)
|
||||
with context.session.begin(subtransactions=True):
|
||||
query = context.session.query(DeviceTemplate)
|
||||
query = (
|
||||
context.session.query(DeviceTemplate).
|
||||
filter(
|
||||
sa.exists().
|
||||
where(sa.and_(
|
||||
DeviceTemplate.id == ServiceType.template_id,
|
||||
ServiceType.service_type == service_type))))
|
||||
for key in required_attributes:
|
||||
query = query.filter(
|
||||
sa.exists().
|
||||
|
@ -268,6 +479,7 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
template_id = device['template_id']
|
||||
device_id = device.get('id') or str(uuid.uuid4())
|
||||
kwargs = device.get('kwargs', {})
|
||||
service_context = device.get('service_context', [])
|
||||
with context.session.begin(subtransactions=True):
|
||||
device_db = Device(id=device_id,
|
||||
tenant_id=tenant_id,
|
||||
|
@ -281,12 +493,28 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
key=key, value=jsonutils.dumps(value))
|
||||
context.session.add(arg)
|
||||
|
||||
LOG.debug(_('service_context %s'), service_context)
|
||||
for sc_entry in service_context:
|
||||
LOG.debug(_('sc_entry %s'), sc_entry)
|
||||
network_id = sc_entry.get('network_id')
|
||||
subnet_id = sc_entry.get('subnet_id')
|
||||
port_id = sc_entry.get('port_id')
|
||||
router_id = sc_entry.get('router_id')
|
||||
role = sc_entry.get('role')
|
||||
index = sc_entry.get('index')
|
||||
network_binding = DeviceServiceContext(
|
||||
id=str(uuid.uuid4()), device_id=device_id,
|
||||
network_id=network_id, subnet_id=subnet_id,
|
||||
port_id=port_id, router_id=router_id, role=role,
|
||||
index=index)
|
||||
context.session.add(network_binding)
|
||||
|
||||
return self._make_device_dict(device_db)
|
||||
|
||||
# called internally, not by REST API
|
||||
# intsance_id = None means error on creation
|
||||
def _create_device_post(self, context, device_id, instance_id,
|
||||
mgmt_url):
|
||||
mgmt_url, service_context):
|
||||
with context.session.begin(subtransactions=True):
|
||||
query = (self._model_query(context, Device).
|
||||
filter(Device.id == device_id).
|
||||
|
@ -296,6 +524,18 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
if instance_id is None:
|
||||
query.update({'status': constants.ERROR})
|
||||
|
||||
for sc_entry in service_context:
|
||||
# some member of service context is determined during
|
||||
# creating hosting device.
|
||||
(self._model_query(context, DeviceServiceContext).
|
||||
filter(DeviceServiceContext.id == sc_entry['id']).
|
||||
update({'network_id': sc_entry['network_id'],
|
||||
'subnet_id': sc_entry['subnet_id'],
|
||||
'port_id': sc_entry['port_id'],
|
||||
'router_id': sc_entry['router_id'],
|
||||
'role': sc_entry['role'],
|
||||
'index': sc_entry['index']}))
|
||||
|
||||
def _create_device_status(self, context, device_id, new_status):
|
||||
with context.session.begin(subtransactions=True):
|
||||
(self._model_query(context, Device).
|
||||
|
@ -333,6 +573,11 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
|
||||
def _delete_device_pre(self, context, device_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
# TODO(yamahata): race. keep others from inserting new binding
|
||||
binding_db = (context.session.query(ServiceDeviceBinding).
|
||||
filter_by(device_id=device_id).first())
|
||||
if binding_db is not None:
|
||||
raise servicevm.DeviceInUse(device_id=device_id)
|
||||
device_db = self._get_device_db(context, device_id,
|
||||
constants.PENDING_DELETE)
|
||||
|
||||
|
@ -349,6 +594,8 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
else:
|
||||
(self._model_query(context, DeviceAttribute).
|
||||
filter(DeviceAttribute.device_id == device_id).delete())
|
||||
(self._model_query(context, DeviceServiceContext).
|
||||
filter(DeviceServiceContext.device_id == device_id).delete())
|
||||
query.delete()
|
||||
|
||||
# reference implementation. needs to be overrided by subclass
|
||||
|
@ -359,7 +606,8 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
# by another thread if it takes a while.
|
||||
instance_id = str(uuid.uuid4())
|
||||
device_dict['instance_id'] = instance_id
|
||||
self._create_device_post(context, device_dict['id'], instance_id, None)
|
||||
self._create_device_post(context, device_dict['id'], instance_id, None,
|
||||
device_dict['service_context'])
|
||||
self._create_device_status(context, device_dict['id'],
|
||||
constants.ACTIVE)
|
||||
return device_dict
|
||||
|
@ -388,3 +636,184 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
|
|||
def get_devices(self, context, filters=None, fields=None):
|
||||
return self._get_collection(context, Device, self._make_device_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
||||
###########################################################################
|
||||
# logical service instance
|
||||
|
||||
# called internally, not by REST API
|
||||
def _create_service_instance(self, context, device_id,
|
||||
service_instance_param, managed_by_user):
|
||||
"""
|
||||
:param service_instance_param: dictionary to create
|
||||
instance of ServiceInstance. The following keys are used.
|
||||
name, service_type_id, service_table_id, mgmt_driver, mgmt_address
|
||||
mgmt_driver, mgmt_address can be determined later.
|
||||
"""
|
||||
name = service_instance_param['name']
|
||||
service_type_id = service_instance_param['service_type_id']
|
||||
service_table_id = service_instance_param['service_table_id']
|
||||
mgmt_driver = service_instance_param.get('mgmt_driver')
|
||||
mgmt_address = service_instance_param.get('mgmt_address')
|
||||
|
||||
service_instance_id = str(uuid.uuid4())
|
||||
LOG.debug('service_instance_id %s device_id %s',
|
||||
service_instance_id, device_id)
|
||||
with context.session.begin(subtransactions=True):
|
||||
# TODO(yamahata): race. prevent modifying/deleting service_type
|
||||
# with_lockmode("update")
|
||||
device_db = self._get_resource(context, Device, device_id)
|
||||
device_dict = self._make_device_dict(device_db)
|
||||
tenant_id = self._get_tenant_id_for_create(context, device_dict)
|
||||
instance_db = ServiceInstance(
|
||||
id=service_instance_id,
|
||||
tenant_id=tenant_id,
|
||||
name=name,
|
||||
service_type_id=service_type_id,
|
||||
service_table_id=service_table_id,
|
||||
managed_by_user=managed_by_user,
|
||||
status=constants.PENDING_CREATE,
|
||||
mgmt_driver=mgmt_driver,
|
||||
mgmt_address=mgmt_address)
|
||||
context.session.add(instance_db)
|
||||
context.session.flush()
|
||||
|
||||
binding_db = ServiceDeviceBinding(
|
||||
service_instance_id=service_instance_id, device_id=device_id)
|
||||
context.session.add(binding_db)
|
||||
|
||||
return self._make_service_instance_dict(instance_db)
|
||||
|
||||
# reference implementation. must be overriden by subclass
|
||||
def create_service_instance(self, context, service_instance):
|
||||
self._create_service_instance(
|
||||
context, service_instance['service_instance'], True)
|
||||
|
||||
def _update_service_instance_mgmt(self, context, service_instance_id,
|
||||
mgmt_driver, mgmt_address):
|
||||
with context.session.begin(subtransactions=True):
|
||||
(self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.id == service_instance_id).
|
||||
filter(ServiceInstance.status == constants.PENDING_CREATE).
|
||||
one().
|
||||
update({'mgmt_driver': mgmt_driver,
|
||||
'mgmt_address': mgmt_address}))
|
||||
|
||||
def _update_service_instance_pre(self, context, service_instance_id,
|
||||
service_instance):
|
||||
with context.session.begin(subtransactions=True):
|
||||
instance_db = (
|
||||
self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.id == service_instance_id).
|
||||
filter(Device.status == constants.ACTIVE).
|
||||
with_lockmode('update').one())
|
||||
instance_db.update(service_instance)
|
||||
instance_db.update({'status': constants.PENDING_UPDATE})
|
||||
return self._make_service_instance_dict(instance_db)
|
||||
|
||||
def _update_service_instance_post(self, context, service_instance_id,
|
||||
status):
|
||||
with context.session.begin(subtransactions=True):
|
||||
(self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.id == service_instance_id).
|
||||
filter(ServiceInstance.status.in_(
|
||||
[constants.PENDING_CREATE, constants.PENDING_UPDATE])).one().
|
||||
update({'status': status}))
|
||||
|
||||
# reference implementation
|
||||
def update_service_instance(self, context, service_instance_id,
|
||||
service_instance):
|
||||
service_instance_dict = self._update_service_instance_pre(
|
||||
context, service_instance_id, service_instance)
|
||||
self._update_service_instance_post(
|
||||
context, service_instance_id, service_instance, constants.ACTIVE)
|
||||
return service_instance_dict
|
||||
|
||||
def _delete_service_instance_pre(self, context, service_instance_id,
|
||||
managed_by_user):
|
||||
with context.session.begin(subtransactions=True):
|
||||
service_instance = (
|
||||
self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.id == service_instance_id).
|
||||
filter(ServiceInstance.status == constants.ACTIVE).
|
||||
with_lockmode('update').one())
|
||||
|
||||
if service_instance.managed_by_user != managed_by_user:
|
||||
raise servicevm.ServiceInstanceNotManagedByUser(
|
||||
service_instance_id=service_instance_id)
|
||||
|
||||
service_instance.status = constants.PENDING_DELETE
|
||||
|
||||
binding_db = (
|
||||
self._model_query(context, ServiceDeviceBinding).
|
||||
filter(ServiceDeviceBinding.service_instance_id ==
|
||||
service_instance_id).
|
||||
all())
|
||||
assert binding_db
|
||||
# check only. _post method will delete it.
|
||||
if len(binding_db) > 1:
|
||||
raise servicevm.ServiceInstanceInUse(
|
||||
service_instance_id=service_instance_id)
|
||||
|
||||
def _delete_service_instance_post(self, context, service_instance_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
binding_db = (
|
||||
self._model_query(context, ServiceDeviceBinding).
|
||||
filter(ServiceDeviceBinding. service_instance_id ==
|
||||
service_instance_id).
|
||||
all())
|
||||
assert binding_db
|
||||
assert len(binding_db) == 1
|
||||
context.session.delete(binding_db[0])
|
||||
|
||||
(self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.id == service_instance_id).
|
||||
filter(ServiceInstance.status == constants.PENDING_DELETE).
|
||||
delete())
|
||||
|
||||
# reference implementation. needs to be overriden by subclass
|
||||
def _delete_service_instance(self, context, service_instance_id,
|
||||
managed_by_user):
|
||||
self._delete_service_instance_pre(context, service_instance_id,
|
||||
managed_by_user)
|
||||
self._delete_service_instance_post(context, service_instance_id)
|
||||
|
||||
# reference implementation. needs to be overriden by subclass
|
||||
def delete_service_instance(self, context, service_instance_id):
|
||||
self._delete_service_instance(context, service_instance_id, True)
|
||||
|
||||
def get_by_service_table_id(self, context, service_table_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
instance_db = (self._model_query(context, ServiceInstance).
|
||||
filter(ServiceInstance.service_table_id ==
|
||||
service_table_id).one())
|
||||
device_db = (
|
||||
self._model_query(context, Device).
|
||||
filter(sa.exists().where(sa.and_(
|
||||
ServiceDeviceBinding.device_id == Device.id,
|
||||
ServiceDeviceBinding.service_instance_id ==
|
||||
instance_db.id))).one())
|
||||
return (self._make_device_dict(device_db),
|
||||
self._make_service_instance_dict(instance_db))
|
||||
|
||||
def get_by_service_instance_id(self, context, service_instance_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
instance_db = self._get_resource(context, ServiceInstance,
|
||||
service_instance_id)
|
||||
device_db = (
|
||||
self._model_query(context, Device).
|
||||
filter(sa.exists().where(sa.and_(
|
||||
ServiceDeviceBinding.device_id == Device.id,
|
||||
ServiceDeviceBinding.service_instance_id ==
|
||||
instance_db.id))).one())
|
||||
return (self._make_device_dict(device_db),
|
||||
self._make_service_instance_dict(instance_db))
|
||||
|
||||
def get_service_instance(self, context, service_instance_id, fields=None):
|
||||
instance_db = self._get_resource(context, ServiceInstance,
|
||||
service_instance_id)
|
||||
return self._make_service_instance_dict(instance_db, fields)
|
||||
|
||||
def get_service_instances(self, context, filters=None, fields=None):
|
||||
return self._get_collection(
|
||||
context, ServiceInstance, self._make_service_instance_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
|
|
@ -40,6 +40,10 @@ class InfraDriverNotSpecified(exceptions.InvalidInput):
|
|||
message = _('infra driver is not speicfied')
|
||||
|
||||
|
||||
class ServiceTypesNotSpecified(exceptions.InvalidInput):
|
||||
message = _('service types are not speicfied')
|
||||
|
||||
|
||||
class DeviceTemplateInUse(exceptions.InUse):
|
||||
message = _('device template %(device_template_id)s is still in use')
|
||||
|
||||
|
@ -80,6 +84,66 @@ class DeviceNotFound(exceptions.NotFound):
|
|||
message = _('device %(device_id)s could not be found')
|
||||
|
||||
|
||||
class ServiceInstanceNotManagedByUser(exceptions.InUse):
|
||||
message = _('service instance %(service_instance_id)s is '
|
||||
'managed by other service')
|
||||
|
||||
|
||||
class ServiceInstanceInUse(exceptions.InUse):
|
||||
message = _('service instance %(service_instance_id)s is still in use')
|
||||
|
||||
|
||||
class ServiceInstanceNotFound(exceptions.NotFound):
|
||||
message = _('service instance %(service_instance_id)s could not be found')
|
||||
|
||||
|
||||
def _validate_service_type_list(data, valid_values=None):
|
||||
if not isinstance(data, list):
|
||||
msg = _("invalid data format for service list: '%s'") % data
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
if not data:
|
||||
msg = _("empty list is not allowed for service list. '%s'") % data
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
key_specs = {
|
||||
'service_type': {
|
||||
'type:string': None,
|
||||
}
|
||||
}
|
||||
for service in data:
|
||||
msg = attr._validate_dict(service, key_specs)
|
||||
if msg:
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_service_context_list(data, valid_values=None):
|
||||
if not isinstance(data, list):
|
||||
msg = _("invalid data format for service context list: '%s'") % data
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
key_specs = {
|
||||
'network_id': {'type:uuid': None},
|
||||
'subnet_id': {'type:uuid': None},
|
||||
'port_id': {'type:uuid': None},
|
||||
'router_id': {'type:uuid': None},
|
||||
'role': {'type:string': None},
|
||||
'index': {'type:non_negative': None,
|
||||
'convert_to': attr.convert_to_int},
|
||||
}
|
||||
for sc_entry in data:
|
||||
msg = attr._validate_dict_or_empty(sc_entry, key_specs=key_specs)
|
||||
if msg:
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
|
||||
attr.validators['type:service_type_list'] = _validate_service_type_list
|
||||
attr.validators['type:service_context_list'] = _validate_service_context_list
|
||||
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
|
||||
'device_templates': {
|
||||
|
@ -111,6 +175,14 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||
'is_visible': True,
|
||||
'default': '',
|
||||
},
|
||||
'service_types': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'convert_to': attr.convert_to_list,
|
||||
'validate': {'type:service_type_list': None},
|
||||
'is_visible': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
},
|
||||
'infra_driver': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
|
@ -118,6 +190,13 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||
'is_visible': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
},
|
||||
'mgmt_driver': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
},
|
||||
'attributes': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
|
@ -168,12 +247,96 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||
'is_visible': True,
|
||||
'default': {},
|
||||
},
|
||||
'service_contexts': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:service_context_list': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'services': {
|
||||
'allow_post': False,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'status': {
|
||||
'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
},
|
||||
},
|
||||
|
||||
'service_instances': {
|
||||
'id': {
|
||||
'allow_post': False,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True
|
||||
},
|
||||
'tenant_id': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True
|
||||
},
|
||||
'name': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'service_type_id': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'service_table_id': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'mgmt_driver': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'mgmt_address': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'service_contexts': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:service_context_list': None},
|
||||
'is_visible': True,
|
||||
},
|
||||
'devices': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'convert_to': attr.convert_to_list,
|
||||
'is_visible': True,
|
||||
},
|
||||
'status': {
|
||||
'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
},
|
||||
'kwargs': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'validate': {'type:dict_or_none': None},
|
||||
'is_visible': True,
|
||||
'default': {},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,6 +367,9 @@ class Servicevm(extensions.ExtensionDescriptor):
|
|||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
||||
plural_mappings['devices'] = 'device'
|
||||
plural_mappings['service_types'] = 'service_type'
|
||||
plural_mappings['service_contexts'] = 'service_context'
|
||||
plural_mappings['services'] = 'service'
|
||||
attr.PLURALS.update(plural_mappings)
|
||||
action_map = {'device': {'attach_interface': 'PUT',
|
||||
'detach_interface': 'PUT'}}
|
||||
|
@ -265,7 +431,8 @@ class ServiceVMPluginBase(ServicePluginBase):
|
|||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_device(self, context, device_id, device):
|
||||
def update_device(
|
||||
self, context, device_id, device):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
|
@ -276,6 +443,19 @@ class ServiceVMPluginBase(ServicePluginBase):
|
|||
def attach_interface(self, context, id, port_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@abc.abstractmetho
|
||||
def detach_interface(self, contexct, id, port_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_service_instances(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_service_instance(self, context, service_instance_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_service_instance(self, context, service_instance_id,
|
||||
service_instance):
|
||||
pass
|
||||
|
|
|
@ -24,10 +24,12 @@ import inspect
|
|||
|
||||
import eventlet
|
||||
from oslo_config import cfg
|
||||
from sqlalchemy.orm import exc as orm_exc
|
||||
|
||||
from tacker.api.v1 import attributes
|
||||
from tacker.common import driver_manager
|
||||
from tacker.common import topics
|
||||
from tacker.db.vm import proxy_db # noqa
|
||||
from tacker.db.vm import vm_db
|
||||
from tacker.extensions import servicevm
|
||||
from tacker.openstack.common import excutils
|
||||
|
@ -96,6 +98,59 @@ class ServiceVMMgmtMixin(object):
|
|||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
kwargs=kwargs)
|
||||
|
||||
def mgmt_service_driver(self, context, device_dict, service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_create_pre(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_create_post(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_update_pre(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_update_post(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_delete_pre(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_delete_post(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_address(self, context, device_dict,
|
||||
service_instance_dict):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict)
|
||||
|
||||
def mgmt_service_call(self, context, device_dict, service_instance_dict,
|
||||
kwargs):
|
||||
return self._invoke(
|
||||
device_dict, plugin=self, context=context, device=device_dict,
|
||||
service_instance=service_instance_dict, kwargs=kwargs)
|
||||
|
||||
|
||||
class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
|
||||
"""ServiceVMPlugin which supports ServiceVM framework
|
||||
|
@ -137,6 +192,16 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
|
|||
'drivers': cfg.CONF.servicevm.infra_driver})
|
||||
raise servicevm.InvalidInfraDriver(infra_driver=infra_driver)
|
||||
|
||||
service_types = template.get('service_types')
|
||||
if not attributes.is_attr_set(service_types):
|
||||
LOG.debug(_('service type must be specified'))
|
||||
raise servicevm.ServiceTypesNotSpecified()
|
||||
for service_type in service_types:
|
||||
# TODO(yamahata):
|
||||
# framework doesn't know what services are valid for now.
|
||||
# so doesn't check it here yet.
|
||||
pass
|
||||
|
||||
return super(ServiceVMPlugin, self).create_device_template(
|
||||
context, device_template)
|
||||
|
||||
|
@ -206,12 +271,14 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
|
|||
return device_dict
|
||||
|
||||
# not for wsgi, but for service to creaste hosting device
|
||||
def create_device_sync(self, context, template_id, kwargs):
|
||||
def create_device_sync(self, context, template_id, kwargs,
|
||||
service_context):
|
||||
assert template_id is not None
|
||||
device = {
|
||||
'device': {
|
||||
'template_id': template_id,
|
||||
'kwargs': kwargs,
|
||||
'service_context': service_context,
|
||||
},
|
||||
}
|
||||
device_dict = self._create_device(context, device)
|
||||
|
@ -323,3 +390,250 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
|
|||
|
||||
def detach_interface(self, context, id, port_id):
|
||||
return self._do_interface(context, id, port_id, 'dettach_interface')
|
||||
|
||||
###########################################################################
|
||||
# logical service instance
|
||||
#
|
||||
def _create_service_instance_mgmt(
|
||||
self, context, device_dict, service_instance_dict):
|
||||
kwargs = {
|
||||
mgmt_constants.KEY_ACTION: mgmt_constants.ACTION_CREATE_SERVICE,
|
||||
mgmt_constants.KEY_KWARGS: {
|
||||
'device': device_dict,
|
||||
'service_instance': service_instance_dict,
|
||||
},
|
||||
}
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
|
||||
mgmt_driver = self.mgmt_service_driver(
|
||||
context, device_dict, service_instance_dict)
|
||||
service_instance_dict['mgmt_driver'] = mgmt_driver
|
||||
mgmt_address = self.mgmt_service_address(
|
||||
context, device_dict, service_instance_dict)
|
||||
service_instance_dict['mgmt_address'] = mgmt_address
|
||||
LOG.debug(_('service_instance_dict '
|
||||
'%(service_instance_dict)s '
|
||||
'mgmt_driver %(mgmt_driver)s '
|
||||
'mgmt_address %(mgmt_address)s'),
|
||||
{'service_instance_dict':
|
||||
service_instance_dict,
|
||||
'mgmt_driver': mgmt_driver, 'mgmt_address': mgmt_address})
|
||||
self._update_service_instance_mgmt(
|
||||
context, service_instance_dict['id'], mgmt_driver, mgmt_address)
|
||||
|
||||
self.mgmt_service_create_pre(
|
||||
context, device_dict, service_instance_dict)
|
||||
self.mgmt_service_call(
|
||||
context, device_dict, service_instance_dict, kwargs)
|
||||
|
||||
def _create_service_instance_db(self, context, device_id,
|
||||
service_instance_param, managed_by_user):
|
||||
return super(ServiceVMPlugin, self)._create_service_instance(
|
||||
context, device_id, service_instance_param, managed_by_user)
|
||||
|
||||
def _create_service_instance_by_type(
|
||||
self, context, device_dict,
|
||||
name, service_type, service_table_id):
|
||||
LOG.debug(_('device_dict %(device_dict)s '
|
||||
'service_type %(service_type)s'),
|
||||
{'device_dict': device_dict,
|
||||
'service_type': service_type})
|
||||
service_type_id = [
|
||||
s['id'] for s in
|
||||
device_dict['device_template']['service_types']
|
||||
if s['service_type'].upper() == service_type.upper()][0]
|
||||
|
||||
service_instance_param = {
|
||||
'name': name,
|
||||
'service_table_id': service_table_id,
|
||||
'service_type': service_type,
|
||||
'service_type_id': service_type_id,
|
||||
}
|
||||
service_instance_dict = self._create_service_instance_db(
|
||||
context, device_dict['id'], service_instance_param, False)
|
||||
|
||||
new_status = constants.ACTIVE
|
||||
try:
|
||||
self._create_service_instance_mgmt(
|
||||
context, device_dict, service_instance_dict)
|
||||
except Exception:
|
||||
new_status = constants.ERROR
|
||||
raise
|
||||
finally:
|
||||
service_instance_dict['status'] = new_status
|
||||
self.mgmt_service_create_post(
|
||||
context, device_dict, service_instance_dict)
|
||||
self._update_service_instance_post(
|
||||
context, service_instance_dict['id'], new_status)
|
||||
return service_instance_dict
|
||||
|
||||
# for service drivers. e.g. hosting_driver of loadbalancer
|
||||
def create_service_instance_by_type(self, context, device_dict,
|
||||
name, service_type, service_table_id):
|
||||
self._update_device_pre(context, device_dict['id'])
|
||||
new_status = constants.ACTIVE
|
||||
try:
|
||||
return self._create_service_instance_by_type(
|
||||
context, device_dict, name, service_type,
|
||||
service_table_id)
|
||||
except Exception:
|
||||
LOG.exception(_('create_service_instance_by_type'))
|
||||
new_status = constants.ERROR
|
||||
finally:
|
||||
self._update_device_post(context, device_dict['id'], new_status)
|
||||
|
||||
def _create_service_instance_wait(self, context, device_id,
|
||||
service_instance_dict):
|
||||
device_dict = self.get_device(context, device_id)
|
||||
|
||||
new_status = constants.ACTIVE
|
||||
try:
|
||||
self._create_service_instance_mgmt(
|
||||
context, device_dict, service_instance_dict)
|
||||
except Exception:
|
||||
LOG.exception(_('_create_service_instance_mgmt'))
|
||||
new_status = constants.ERROR
|
||||
service_instance_dict['status'] = new_status
|
||||
self.mgmt_service_create_post(
|
||||
context, device_dict, service_instance_dict)
|
||||
self._update_service_instance_post(
|
||||
context, service_instance_dict['id'], new_status)
|
||||
|
||||
# for service drivers. e.g. hosting_driver of loadbalancer
|
||||
def _create_service_instance(self, context, device_id,
|
||||
service_instance_param, managed_by_user):
|
||||
service_instance_dict = self._create_service_instance_db(
|
||||
context, device_id, service_instance_param, managed_by_user)
|
||||
self.spawn_n(self._create_service_instance_wait, context,
|
||||
device_id, service_instance_dict)
|
||||
return service_instance_dict
|
||||
|
||||
def create_service_instance(self, context, service_instance):
|
||||
service_instance_param = service_instance['service_instance'].copy()
|
||||
device = service_instance_param.pop('devices')
|
||||
device_id = device[0]
|
||||
service_instance_dict = self._create_service_instance(
|
||||
context, device_id, service_instance_param, True)
|
||||
return service_instance_dict
|
||||
|
||||
def _update_service_instance_wait(self, context, service_instance_dict,
|
||||
mgmt_kwargs, callback, errorback):
|
||||
devices = service_instance_dict['devices']
|
||||
assert len(devices) == 1
|
||||
device_dict = self.get_device(context, devices[0])
|
||||
kwargs = {
|
||||
mgmt_constants.KEY_ACTION: mgmt_constants.ACTION_UPDATE_SERVICE,
|
||||
mgmt_constants.KEY_KWARGS: {
|
||||
'device': device_dict,
|
||||
'service_instance': service_instance_dict,
|
||||
mgmt_constants.KEY_KWARGS: mgmt_kwargs,
|
||||
}
|
||||
}
|
||||
try:
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
self.mgmt_service_update_pre(context, device_dict,
|
||||
service_instance_dict)
|
||||
self.mgmt_service_call(context, device_dict,
|
||||
service_instance_dict, kwargs)
|
||||
except Exception:
|
||||
LOG.exception(_('mgmt call failed %s'), kwargs)
|
||||
service_instance_dict['status'] = constants.ERROR
|
||||
self.mgmt_service_update_post(context, device_dict,
|
||||
service_instance_dict)
|
||||
self._update_service_instance_post(
|
||||
context, service_instance_dict['id'], constants.ERROR)
|
||||
if errorback:
|
||||
errorback()
|
||||
else:
|
||||
service_instance_dict['status'] = constants.ACTIVE
|
||||
self.mgmt_service_update_post(context, device_dict,
|
||||
service_instance_dict)
|
||||
self._update_service_instance_post(
|
||||
context, service_instance_dict['id'], constants.ACTIVE)
|
||||
if callback:
|
||||
callback()
|
||||
|
||||
# for service drivers. e.g. hosting_driver of loadbalancer
|
||||
def _update_service_instance(self, context, service_instance_id,
|
||||
mgmt_kwargs, callback, errorback):
|
||||
service_instance_dict = self._update_service_instance_pre(
|
||||
context, service_instance_id, {})
|
||||
self.spawn_n(self._update_service_instance_wait, context,
|
||||
service_instance_dict, mgmt_kwargs, callback, errorback)
|
||||
|
||||
# for service drivers. e.g. hosting_driver of loadbalancer
|
||||
def _update_service_table_instance(
|
||||
self, context, service_table_id, mgmt_kwargs, callback, errorback):
|
||||
_device_dict, service_instance_dict = self.get_by_service_table_id(
|
||||
context, service_table_id)
|
||||
service_instance_dict = self._update_service_instance_pre(
|
||||
context, service_instance_dict['id'], {})
|
||||
self.spawn_n(self._update_service_instance_wait, context,
|
||||
service_instance_dict, mgmt_kwargs, callback, errorback)
|
||||
|
||||
def update_service_instance(self, context, service_instance_id,
|
||||
service_instance):
|
||||
mgmt_kwargs = service_instance['service_instance'].get('kwarg', {})
|
||||
service_instance_dict = self._update_service_instance_pre(
|
||||
context, service_instance_id, service_instance)
|
||||
|
||||
self.spawn_n(self._update_service_instance_wait, context,
|
||||
service_instance_dict, mgmt_kwargs, None, None)
|
||||
return service_instance_dict
|
||||
|
||||
def _delete_service_instance_wait(self, context, device, service_instance,
|
||||
mgmt_kwargs, callback, errorback):
|
||||
service_instance_id = service_instance['id']
|
||||
kwargs = {
|
||||
mgmt_constants.KEY_ACTION: mgmt_constants.ACTION_DELETE_SERVICE,
|
||||
mgmt_constants.KEY_KWARGS: {
|
||||
'device': device,
|
||||
'service_instance': service_instance,
|
||||
mgmt_constants.KEY_KWARGS: mgmt_kwargs,
|
||||
}
|
||||
}
|
||||
try:
|
||||
self.mgmt_service_delete_pre(context, device, service_instance)
|
||||
self.mgmt_service_call(context, device, service_instance, kwargs)
|
||||
self.mgmt_call(context, device, kwargs)
|
||||
except Exception:
|
||||
LOG.exception(_('mgmt call failed %s'), kwargs)
|
||||
service_instance['status'] = constants.ERROR
|
||||
self.mgmt_service_delete_post(context, device, service_instance)
|
||||
self._update_service_instance_post(context, service_instance_id,
|
||||
constants.ERROR)
|
||||
if errorback:
|
||||
errorback()
|
||||
else:
|
||||
service_instance['status'] = constants.ACTIVE
|
||||
self.mgmt_service_delete_post(context, device, service_instance)
|
||||
self._delete_service_instance_post(context, service_instance_id)
|
||||
if callback:
|
||||
callback()
|
||||
|
||||
# for service drivers. e.g. hosting_driver of loadbalancer
|
||||
def _delete_service_table_instance(
|
||||
self, context, service_table_instance_id,
|
||||
mgmt_kwargs, callback, errorback):
|
||||
try:
|
||||
device, service_instance = self.get_by_service_table_id(
|
||||
context, service_table_instance_id)
|
||||
except orm_exc.NoResultFound:
|
||||
# there are no entry for some reason.
|
||||
# e.g. partial creation due to error
|
||||
callback()
|
||||
return
|
||||
self._delete_service_instance_pre(context, service_instance['id'],
|
||||
False)
|
||||
self.spawn_n(
|
||||
self._delete_service_instance_wait, context, device,
|
||||
service_instance, mgmt_kwargs, callback, errorback)
|
||||
|
||||
def delete_service_instance(self, context, service_instance_id):
|
||||
# mgmt_kwargs is needed?
|
||||
device, service_instance = self.get_by_service_instance_id(
|
||||
context, service_instance_id)
|
||||
self._delete_service_instance_pre(context, service_instance_id, True)
|
||||
self.spawn_n(
|
||||
self._delete_service_instance_wait, context, device,
|
||||
service_instance, {}, None, None)
|
||||
|
|
Loading…
Reference in New Issue