@ -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 )