Browse Source

Remove Service instance, context resources

These resources are out of the scope of tacker
(cherry picked from commit 5c7d475eb3)

Change-Id: Ib585e44e629908ca97c5ab67cdb8ed4375b61fe7
Closes-bug: 1519968
changes/00/256200/2
gong yong sheng 7 years ago committed by gongysh
parent
commit
1790718612
  1. 18
      etc/tacker/tacker.conf
  2. 115
      tacker/db/migration/alembic_migrations/versions/2774a42c7163_remove_service_related.py
  3. 2
      tacker/db/migration/alembic_migrations/versions/HEAD
  4. 392
      tacker/db/vm/vm_db.py
  5. 45
      tacker/extensions/vnfm.py
  6. 2
      tacker/tests/unit/db/utils.py
  7. 53
      tacker/vm/mgmt_drivers/abstract_driver.py
  8. 11
      tacker/vm/mgmt_drivers/noop.py
  9. 11
      tacker/vm/mgmt_drivers/openwrt/openwrt.py
  10. 302
      tacker/vm/plugin.py

18
etc/tacker/tacker.conf

@ -415,21 +415,3 @@ auth_plugin = password
heat_uri = http://localhost:8004/v1
stack_retries = 5
stack_retry_wait = 3
[servicevm_agent]
# VM agent requires that an interface driver be set. Choose the one that best
# matches your plugin.
# interface_driver =
# Example of interface_driver option for OVS based plugins (OVS, Ryu, NEC)
# that supports L3 agent
# interface_driver = tacker.agent.linux.interface.OVSInterfaceDriver
# Use veth for an OVS interface or not.
# Support kernels with limited namespace support
# (e.g. RHEL 6.5) so long as ovs_use_veth is set to True.
# ovs_use_veth = False
# Allow overlapping IP (Must have kernel build with CONFIG_NET_NS=y and
# iproute2 package that supports namespaces).
# use_namespaces = True

115
tacker/db/migration/alembic_migrations/versions/2774a42c7163_remove_service_related.py

@ -0,0 +1,115 @@
# Copyright 2015 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.
#
"""remove service related
Revision ID: 2774a42c7163
Revises: 12a57080b278
Create Date: 2015-11-26 15:47:51.161749
"""
# revision identifiers, used by Alembic.
revision = '2774a42c7163'
down_revision = '12a57080b278'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
def upgrade(active_plugins=None, options=None):
### commands auto generated by Alembic - please adjust! ###
op.drop_table('servicecontexts')
op.drop_table('deviceservicecontexts')
op.drop_table('servicedevicebindings')
op.drop_table('serviceinstances')
### end Alembic commands ###
def downgrade(active_plugins=None, options=None):
### commands auto generated by Alembic - please adjust! ###
op.create_table(
'deviceservicecontexts',
sa.Column('id', mysql.VARCHAR(length=36), nullable=False),
sa.Column('device_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('network_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('subnet_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('port_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('router_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('role', mysql.VARCHAR(length=255), nullable=True),
sa.Column('index', mysql.INTEGER(display_width=11),
autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['device_id'], [u'devices.id'],
name=u'deviceservicecontexts_ibfk_1'),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset=u'utf8',
mysql_engine=u'InnoDB'
)
op.create_table(
'serviceinstances',
sa.Column('tenant_id', mysql.VARCHAR(length=255), nullable=True),
sa.Column('id', mysql.VARCHAR(length=36), nullable=False),
sa.Column('name', mysql.VARCHAR(length=255), nullable=True),
sa.Column('service_type_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('service_table_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('managed_by_user', mysql.TINYINT(display_width=1),
autoincrement=False, nullable=True),
sa.Column('mgmt_driver', mysql.VARCHAR(length=255), nullable=True),
sa.Column('mgmt_url', mysql.VARCHAR(length=255), nullable=True),
sa.Column('status', mysql.VARCHAR(length=255), nullable=False),
sa.ForeignKeyConstraint(['service_type_id'], [u'servicetypes.id'],
name=u'serviceinstances_ibfk_1'),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset=u'utf8',
mysql_engine=u'InnoDB'
)
op.create_table(
'servicedevicebindings',
sa.Column('service_instance_id', mysql.VARCHAR(length=36),
nullable=False),
sa.Column('device_id', mysql.VARCHAR(length=36), nullable=False),
sa.ForeignKeyConstraint(['device_id'], [u'devices.id'],
name=u'servicedevicebindings_ibfk_1'),
sa.ForeignKeyConstraint(['service_instance_id'],
[u'serviceinstances.id'],
name=u'servicedevicebindings_ibfk_2'),
sa.PrimaryKeyConstraint('service_instance_id', 'device_id'),
mysql_default_charset=u'utf8',
mysql_engine=u'InnoDB'
)
op.create_table(
'servicecontexts',
sa.Column('id', mysql.VARCHAR(length=36), nullable=False),
sa.Column('service_instance_id', mysql.VARCHAR(length=36),
nullable=True),
sa.Column('network_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('subnet_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('port_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('router_id', mysql.VARCHAR(length=36), nullable=True),
sa.Column('role', mysql.VARCHAR(length=255), nullable=True),
sa.Column('index', mysql.INTEGER(display_width=11),
autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['service_instance_id'],
[u'serviceinstances.id'],
name=u'servicecontexts_ibfk_1'),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset=u'utf8',
mysql_engine=u'InnoDB'
)
### end Alembic commands ###

2
tacker/db/migration/alembic_migrations/versions/HEAD

@ -1 +1 @@
12a57080b278
2774a42c7163

392
tacker/db/vm/vm_db.py

@ -118,9 +118,6 @@ class Device(model_base.BASE, models_v1.HasTenant):
mgmt_url = sa.Column(sa.String(255), nullable=True)
attributes = orm.relationship("DeviceAttribute", backref="device")
service_context = orm.relationship('DeviceServiceContext')
services = orm.relationship('ServiceDeviceBinding', backref='device')
status = sa.Column(sa.String(255), nullable=False)
@ -138,133 +135,6 @@ 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_url = 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 VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
@property
@ -287,8 +157,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
raise vnfm.DeviceTemplateNotFound(device_tempalte_id=id)
elif issubclass(model, ServiceType):
raise vnfm.ServiceTypeNotFound(service_type_id=id)
elif issubclass(model, ServiceInstance):
raise vnfm.ServiceInstanceNotFound(service_instance_id=id)
if issubclass(model, Device):
raise vnfm.DeviceNotFound(device_id=id)
else:
@ -313,57 +181,22 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
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_dev_attrs_dict(self, dev_attrs_db):
return dict((arg.key, arg.value) for arg in dev_attrs_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)
LOG.debug(_('device_db attributes %s'), device_db.attributes)
res = {
'services':
self._make_services_list(getattr(device_db, 'services', [])),
'device_template':
self._make_template_dict(device_db.template),
'attributes': self._make_dev_attrs_dict(device_db.attributes),
'service_context':
self._make_device_service_context_dict(device_db.service_context),
}
key_list = ('id', 'tenant_id', 'name', 'description', '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_url',
'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']
@ -376,9 +209,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
def _instance_id(device_dict):
return device_dict['instance_id']
###########################################################################
# hosting device template
def create_device_template(self, context, device_template):
template = device_template['device_template']
LOG.debug(_('template %s'), template)
@ -464,8 +294,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
self._make_template_dict,
filters=filters, fields=fields)
# called internally, not by REST API
# need enhancement?
def choose_device_template(self, context, service_type,
required_attributes=None):
required_attributes = required_attributes or []
@ -490,9 +318,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
if template_db:
return self._make_template_dict(template_db)
###########################################################################
# hosting device
def _device_attribute_update_or_create(
self, context, device_id, key, value):
arg = (self._model_query(context, DeviceAttribute).
@ -515,7 +340,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
name = device.get('name')
device_id = device.get('id') or str(uuid.uuid4())
attributes = device.get('attributes', {})
service_context = device.get('service_context', [])
with context.session.begin(subtransactions=True):
template_db = self._get_resource(context, DeviceTemplate,
template_id)
@ -533,22 +357,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
key=key, value=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
@ -569,18 +377,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
self._device_attribute_update_or_create(context, device_id,
key, value)
for sc_entry in device_dict['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).
@ -628,11 +424,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
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 vnfm.DeviceInUse(device_id=device_id)
device_db = self._get_device_db(
context, device_id, _ACTIVE_UPDATE_ERROR_DEAD,
constants.PENDING_DELETE)
@ -650,8 +441,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
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
@ -749,187 +538,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
update({'device_id': new_device_id}))
context.session.delete(device_db)
###########################################################################
# 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_url
mgmt_driver, mgmt_url 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_url = service_instance_param.get('mgmt_url')
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_url=mgmt_url)
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_url):
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_url': mgmt_url}))
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 vnfm.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 vnfm.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)
def get_vnfs(self, context, filters=None, fields=None):
return self.get_devices(context, filters, fields)

45
tacker/extensions/vnfm.py

@ -77,19 +77,6 @@ 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')
class ParamYAMLNotWellFormed(exceptions.InvalidInput):
message = _("Parameter YAML not well formed - %(error_msg_details)s")
@ -135,30 +122,8 @@ def _validate_service_type_list(data, valid_values=None):
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 = {
@ -277,13 +242,6 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True,
'default': {},
},
'service_contexts': {
'allow_post': True,
'allow_put': False,
'validate': {'type:service_context_list': None},
'is_visible': True,
'default': [],
},
'status': {
'allow_post': False,
'allow_put': False,
@ -449,7 +407,6 @@ class Vnfm(extensions.ExtensionDescriptor):
plural_mappings = resource_helper.build_plural_mappings(
special_mappings, RESOURCE_ATTRIBUTE_MAP)
plural_mappings['service_types'] = 'service_type'
plural_mappings['service_contexts'] = 'service_context'
attr.PLURALS.update(plural_mappings)
return resource_helper.build_resource_info(
plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.VNFM,

2
tacker/tests/unit/db/utils.py

@ -53,7 +53,7 @@ def get_dummy_vnf_obj():
return {'vnf': {'description': 'dummy_vnf_description',
'vnfd_id': u'eb094833-995e-49f0-a047-dfb56aaf7c4e',
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'name': 'dummy_vnf', 'service_contexts': [],
'name': 'dummy_vnf',
'attributes': {}}}

53
tacker/vm/mgmt_drivers/abstract_driver.py

@ -87,43 +87,6 @@ class DeviceMGMTAbstractDriver(extensions.PluginInterface):
def mgmt_call(self, plugin, context, device, kwargs):
pass
def mgmt_service_driver(self, plugin, context, device, service_instance):
# use same mgmt driver to communicate with service
return self.get_name()
def mgmt_service_create_pre(self, plugin, context, device,
service_instance):
pass
def mgmt_service_create_post(self, plugin, context, device,
service_instance):
pass
def mgmt_service_update_pre(self, plugin, context, device,
service_instance):
pass
def mgmt_service_update_post(self, plugin, context, device,
service_instance):
pass
def mgmt_service_delete_pre(self, plugin, context, device,
service_instance):
pass
def mgmt_service_delete_post(self, plugin, context, device,
service_instance):
pass
@abc.abstractmethod
def mgmt_service_address(self, plugin, context, device, service_instance):
pass
@abc.abstractmethod
def mgmt_service_call(self, plugin, context, device,
service_instance, kwargs):
pass
class DeviceMGMTByNetwork(DeviceMGMTAbstractDriver):
def mgmt_url(self, plugin, context, device):
@ -140,19 +103,3 @@ class DeviceMGMTByNetwork(DeviceMGMTAbstractDriver):
mgmt_url['port_id'] = port['id']
mgmt_url['mac_address'] = port['mac_address']
return jsonutils.dumps(mgmt_url)
def mgmt_service_address(self, plugin, context, device, service_instance):
mgmt_entries = [sc_entry for sc_entry
in service_instance.service_context
if (sc_entry.role == constants.ROLE_MGMT and
sc_entry.port_id)]
if not mgmt_entries:
return
port = plugin._core_plugin.get_port(context, mgmt_entries[0].port_id)
if not port:
return
mgmt_url = port['fixed_ips'][0] # subnet_id and ip_address
mgmt_url['network_id'] = port['network_id']
mgmt_url['port_id'] = port['id']
mgmt_url['mac_address'] = port['mac_address']
return jsonutils.dumps(mgmt_url)

11
tacker/vm/mgmt_drivers/noop.py

@ -44,14 +44,3 @@ class DeviceMgmtNoop(abstract_driver.DeviceMGMTAbstractDriver):
def mgmt_call(self, plugin, context, device, kwargs):
LOG.debug(_('mgmt_device_call %(device)s %(kwargs)s'),
{'device': device, 'kwargs': kwargs})
def mgmt_service_address(self, plugin, context,
device, service_instance):
LOG.debug(_('mgmt_service_address %(device)s %(service_instance)s'),
{'device': device, 'service_instance': service_instance})
return 'noop-mgmt-service-address'
def mgmt_service_call(self, plugin, context, device,
service_instance, kwargs):
LOG.debug(_('mgmt_service_call %(device)s %(service_instance)s'),
{'device': device, 'service_instance': service_instance})

11
tacker/vm/mgmt_drivers/openwrt/openwrt.py

@ -90,14 +90,3 @@ class DeviceMgmtOpenWRT(abstract_driver.DeviceMGMTAbstractDriver):
vdu)
continue
self._config_service(mgmt_ip_address, key, conf_value)
def mgmt_service_address(self, plugin, context,
device, service_instance):
LOG.debug(_('mgmt_service_address %(device)s %(service_instance)s'),
{'device': device, 'service_instance': service_instance})
return 'noop-mgmt-service-address'
def mgmt_service_call(self, plugin, context, device,
service_instance, kwargs):
LOG.debug(_('mgmt_service_call %(device)s %(service_instance)s'),
{'device': device, 'service_instance': service_instance})

302
tacker/vm/plugin.py

@ -25,7 +25,6 @@ import eventlet
import inspect
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
@ -100,59 +99,6 @@ class VNFMMgmtMixin(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 VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
"""ServiceVMPlugin which supports ServiceVM framework
@ -410,254 +356,6 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
self._delete_device_post(context, device_id, None)
self.spawn_n(self._delete_device_wait, context, device_dict)
###########################################################################
# 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_url = self.mgmt_service_address(
context, device_dict, service_instance_dict)
service_instance_dict['mgmt_url'] = mgmt_url
LOG.debug(_('service_instance_dict '
'%(service_instance_dict)s '
'mgmt_driver %(mgmt_driver)s '
'mgmt_url %(mgmt_url)s'),
{'service_instance_dict':
service_instance_dict,
'mgmt_driver': mgmt_driver, 'mgmt_url': mgmt_url})
self._update_service_instance_mgmt(
context, service_instance_dict['id'], mgmt_driver, mgmt_url)
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(VNFMPlugin, 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:
LOG.exception(_('_create_service_instance_by_type'))
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)
def create_vnf(self, context, vnf):
vnf['device'] = vnf.pop('vnf')
vnf_attributes = vnf['device']

Loading…
Cancel
Save