@ -12,561 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import collection s
from ovsdbapp . schema . open_vswitch import command s
from oslo_log import log as logging
from oslo_utils import excutils
from neutron . common import _deprecate
from neutron . _i18n import _ , _LE
from neutron . agent . ovsdb import api
from neutron . agent . ovsdb . native import idlutils
LOG = logging . getLogger ( __name__ )
class BaseCommand ( api . Command ) :
def __init__ ( self , api ) :
self . api = api
self . result = None
def execute ( self , check_error = False , log_errors = True ) :
try :
with self . api . transaction ( check_error , log_errors ) as txn :
txn . add ( self )
return self . result
except Exception :
with excutils . save_and_reraise_exception ( ) as ctx :
if log_errors :
LOG . exception ( _LE ( " Error executing command " ) )
if not check_error :
ctx . reraise = False
def post_commit ( self , txn ) :
pass
def __str__ ( self ) :
command_info = self . __dict__
return " %s ( %s ) " % (
self . __class__ . __name__ ,
" , " . join ( " %s = %s " % ( k , v ) for k , v in command_info . items ( )
if k not in [ ' api ' , ' result ' ] ) )
__repr__ = __str__
class AddManagerCommand ( BaseCommand ) :
def __init__ ( self , api , target ) :
super ( AddManagerCommand , self ) . __init__ ( api )
self . target = target
def run_idl ( self , txn ) :
row = txn . insert ( self . api . _tables [ ' Manager ' ] )
row . target = self . target
try :
self . api . _ovs . addvalue ( ' manager_options ' , row )
except AttributeError : # OVS < 2.6
self . api . _ovs . verify ( ' manager_options ' )
self . api . _ovs . manager_options = (
self . api . _ovs . manager_options + [ row ] )
class GetManagerCommand ( BaseCommand ) :
def __init__ ( self , api ) :
super ( GetManagerCommand , self ) . __init__ ( api )
def run_idl ( self , txn ) :
self . result = [ m . target for m in
self . api . _tables [ ' Manager ' ] . rows . values ( ) ]
class RemoveManagerCommand ( BaseCommand ) :
def __init__ ( self , api , target ) :
super ( RemoveManagerCommand , self ) . __init__ ( api )
self . target = target
def run_idl ( self , txn ) :
try :
manager = idlutils . row_by_value ( self . api . idl , ' Manager ' , ' target ' ,
self . target )
except idlutils . RowNotFound :
msg = _ ( " Manager with target %s does not exist " ) % self . target
LOG . error ( msg )
raise RuntimeError ( msg )
try :
self . api . _ovs . delvalue ( ' manager_options ' , manager )
except AttributeError : # OVS < 2.6
self . api . _ovs . verify ( ' manager_options ' )
manager_list = self . api . _ovs . manager_options
manager_list . remove ( manager )
self . api . _ovs . manager_options = manager_list
manager . delete ( )
class AddBridgeCommand ( BaseCommand ) :
def __init__ ( self , api , name , may_exist , datapath_type ) :
super ( AddBridgeCommand , self ) . __init__ ( api )
self . name = name
self . may_exist = may_exist
self . datapath_type = datapath_type
def run_idl ( self , txn ) :
if self . may_exist :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' ,
self . name , None )
if br :
if self . datapath_type :
br . datapath_type = self . datapath_type
return
row = txn . insert ( self . api . _tables [ ' Bridge ' ] )
row . name = self . name
if self . datapath_type :
row . datapath_type = self . datapath_type
try :
self . api . _ovs . addvalue ( ' bridges ' , row )
except AttributeError : # OVS < 2.6
self . api . _ovs . verify ( ' bridges ' )
self . api . _ovs . bridges = self . api . _ovs . bridges + [ row ]
# Add the internal bridge port
cmd = AddPortCommand ( self . api , self . name , self . name , self . may_exist )
cmd . run_idl ( txn )
cmd = DbSetCommand ( self . api , ' Interface ' , self . name ,
( ' type ' , ' internal ' ) )
cmd . run_idl ( txn )
class DelBridgeCommand ( BaseCommand ) :
def __init__ ( self , api , name , if_exists ) :
super ( DelBridgeCommand , self ) . __init__ ( api )
self . name = name
self . if_exists = if_exists
def run_idl ( self , txn ) :
try :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' ,
self . name )
except idlutils . RowNotFound :
if self . if_exists :
return
else :
msg = _ ( " Bridge %s does not exist " ) % self . name
LOG . error ( msg )
raise RuntimeError ( msg )
# Clean up cached ports/interfaces
for port in br . ports :
for interface in port . interfaces :
interface . delete ( )
port . delete ( )
try :
self . api . _ovs . delvalue ( ' bridges ' , br )
except AttributeError : # OVS < 2.6
self . api . _ovs . verify ( ' bridges ' )
bridges = self . api . _ovs . bridges
bridges . remove ( br )
self . api . _ovs . bridges = bridges
br . delete ( )
class BridgeExistsCommand ( BaseCommand ) :
def __init__ ( self , api , name ) :
super ( BridgeExistsCommand , self ) . __init__ ( api )
self . name = name
def run_idl ( self , txn ) :
self . result = bool ( idlutils . row_by_value ( self . api . idl , ' Bridge ' ,
' name ' , self . name , None ) )
class ListBridgesCommand ( BaseCommand ) :
def __init__ ( self , api ) :
super ( ListBridgesCommand , self ) . __init__ ( api )
def run_idl ( self , txn ) :
# NOTE (twilson) [x.name for x in rows.values()] if no index
self . result = [ x . name for x in
self . api . _tables [ ' Bridge ' ] . rows . values ( ) ]
class BrGetExternalIdCommand ( BaseCommand ) :
def __init__ ( self , api , name , field ) :
super ( BrGetExternalIdCommand , self ) . __init__ ( api )
self . name = name
self . field = field
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . name )
self . result = br . external_ids [ self . field ]
class BrSetExternalIdCommand ( BaseCommand ) :
def __init__ ( self , api , name , field , value ) :
super ( BrSetExternalIdCommand , self ) . __init__ ( api )
self . name = name
self . field = field
self . value = value
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . name )
external_ids = getattr ( br , ' external_ids ' , { } )
external_ids [ self . field ] = self . value
br . external_ids = external_ids
class DbCreateCommand ( BaseCommand ) :
def __init__ ( self , api , table , * * columns ) :
super ( DbCreateCommand , self ) . __init__ ( api )
self . table = table
self . columns = columns
def run_idl ( self , txn ) :
row = txn . insert ( self . api . _tables [ self . table ] )
for col , val in self . columns . items ( ) :
setattr ( row , col , idlutils . db_replace_record ( val ) )
# This is a temporary row to be used within the transaction
self . result = row
def post_commit ( self , txn ) :
# Replace the temporary row with the post-commit UUID to match vsctl
self . result = txn . get_insert_uuid ( self . result . uuid )
class DbDestroyCommand ( BaseCommand ) :
def __init__ ( self , api , table , record ) :
super ( DbDestroyCommand , self ) . __init__ ( api )
self . table = table
self . record = record
def run_idl ( self , txn ) :
record = idlutils . row_by_record ( self . api . idl , self . table , self . record )
record . delete ( )
class DbSetCommand ( BaseCommand ) :
def __init__ ( self , api , table , record , * col_values ) :
super ( DbSetCommand , self ) . __init__ ( api )
self . table = table
self . record = record
self . col_values = col_values
def run_idl ( self , txn ) :
record = idlutils . row_by_record ( self . api . idl , self . table , self . record )
for col , val in self . col_values :
# TODO(twilson) Ugh, the OVS library doesn't like OrderedDict
# We're only using it to make a unit test work, so we should fix
# this soon.
if isinstance ( val , collections . OrderedDict ) :
val = dict ( val )
if isinstance ( val , dict ) :
# NOTE(twilson) OVS 2.6's Python IDL has mutate methods that
# would make this cleaner, but it's too early to rely on them.
existing = getattr ( record , col , { } )
existing . update ( val )
val = existing
setattr ( record , col , idlutils . db_replace_record ( val ) )
class DbAddCommand ( BaseCommand ) :
def __init__ ( self , api , table , record , column , * values ) :
super ( DbAddCommand , self ) . __init__ ( api )
self . table = table
self . record = record
self . column = column
self . values = values
def run_idl ( self , txn ) :
record = idlutils . row_by_record ( self . api . idl , self . table , self . record )
for value in self . values :
if isinstance ( value , collections . Mapping ) :
# We should be doing an add on a 'map' column. If the key is
# already set, do nothing, otherwise set the key to the value
# Since this operation depends on the previous value, verify()
# must be called.
field = getattr ( record , self . column , { } )
for k , v in value . items ( ) :
if k in field :
continue
field [ k ] = v
else :
# We should be appending to a 'set' column.
try :
record . addvalue ( self . column ,
idlutils . db_replace_record ( value ) )
continue
except AttributeError : # OVS < 2.6
field = getattr ( record , self . column , [ ] )
field . append ( value )
record . verify ( self . column )
setattr ( record , self . column , idlutils . db_replace_record ( field ) )
class DbClearCommand ( BaseCommand ) :
def __init__ ( self , api , table , record , column ) :
super ( DbClearCommand , self ) . __init__ ( api )
self . table = table
self . record = record
self . column = column
def run_idl ( self , txn ) :
record = idlutils . row_by_record ( self . api . idl , self . table , self . record )
# Create an empty value of the column type
value = type ( getattr ( record , self . column ) ) ( )
setattr ( record , self . column , value )
class DbGetCommand ( BaseCommand ) :
def __init__ ( self , api , table , record , column ) :
super ( DbGetCommand , self ) . __init__ ( api )
self . table = table
self . record = record
self . column = column
def run_idl ( self , txn ) :
record = idlutils . row_by_record ( self . api . idl , self . table , self . record )
# TODO(twilson) This feels wrong, but ovs-vsctl returns single results
# on set types without the list. The IDL is returning them as lists,
# even if the set has the maximum number of items set to 1. Might be
# able to inspect the Schema and just do this conversion for that case.
result = idlutils . get_column_value ( record , self . column )
if isinstance ( result , list ) and len ( result ) == 1 :
self . result = result [ 0 ]
else :
self . result = result
class SetControllerCommand ( BaseCommand ) :
def __init__ ( self , api , bridge , targets ) :
super ( SetControllerCommand , self ) . __init__ ( api )
self . bridge = bridge
self . targets = targets
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
controllers = [ ]
for target in self . targets :
controller = txn . insert ( self . api . _tables [ ' Controller ' ] )
controller . target = target
controllers . append ( controller )
# Don't need to verify because we unconditionally overwrite
br . controller = controllers
class DelControllerCommand ( BaseCommand ) :
def __init__ ( self , api , bridge ) :
super ( DelControllerCommand , self ) . __init__ ( api )
self . bridge = bridge
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
br . controller = [ ]
class GetControllerCommand ( BaseCommand ) :
def __init__ ( self , api , bridge ) :
super ( GetControllerCommand , self ) . __init__ ( api )
self . bridge = bridge
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
self . result = [ c . target for c in br . controller ]
class SetFailModeCommand ( BaseCommand ) :
def __init__ ( self , api , bridge , mode ) :
super ( SetFailModeCommand , self ) . __init__ ( api )
self . bridge = bridge
self . mode = mode
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
br . fail_mode = self . mode
class AddPortCommand ( BaseCommand ) :
def __init__ ( self , api , bridge , port , may_exist ) :
super ( AddPortCommand , self ) . __init__ ( api )
self . bridge = bridge
self . port = port
self . may_exist = may_exist
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
if self . may_exist :
port = idlutils . row_by_value ( self . api . idl , ' Port ' , ' name ' ,
self . port , None )
if port :
return
port = txn . insert ( self . api . _tables [ ' Port ' ] )
port . name = self . port
try :
br . addvalue ( ' ports ' , port )
except AttributeError : # OVS < 2.6
br . verify ( ' ports ' )
ports = getattr ( br , ' ports ' , [ ] )
ports . append ( port )
br . ports = ports
iface = txn . insert ( self . api . _tables [ ' Interface ' ] )
txn . expected_ifaces . add ( iface . uuid )
iface . name = self . port
# This is a new port, so it won't have any existing interfaces
port . interfaces = [ iface ]
class DelPortCommand ( BaseCommand ) :
def __init__ ( self , api , port , bridge , if_exists ) :
super ( DelPortCommand , self ) . __init__ ( api )
self . port = port
self . bridge = bridge
self . if_exists = if_exists
def run_idl ( self , txn ) :
try :
port = idlutils . row_by_value ( self . api . idl , ' Port ' , ' name ' ,
self . port )
except idlutils . RowNotFound :
if self . if_exists :
return
msg = _ ( " Port %s does not exist " ) % self . port
raise RuntimeError ( msg )
if self . bridge :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' ,
self . bridge )
else :
br = next ( b for b in self . api . _tables [ ' Bridge ' ] . rows . values ( )
if port in b . ports )
if port not in br . ports and not self . if_exists :
# TODO(twilson) Make real errors across both implementations
msg = _ ( " Port %(port)s does not exist on %(bridge)s ! " ) % {
' port ' : self . port , ' bridge ' : self . bridge
}
LOG . error ( msg )
raise RuntimeError ( msg )
try :
br . delvalue ( ' ports ' , port )
except AttributeError : # OVS < 2.6
br . verify ( ' ports ' )
ports = br . ports
ports . remove ( port )
br . ports = ports
# The interface on the port will be cleaned up by ovsdb-server
for interface in port . interfaces :
interface . delete ( )
port . delete ( )
class ListPortsCommand ( BaseCommand ) :
def __init__ ( self , api , bridge ) :
super ( ListPortsCommand , self ) . __init__ ( api )
self . bridge = bridge
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
self . result = [ p . name for p in br . ports if p . name != self . bridge ]
class ListIfacesCommand ( BaseCommand ) :
def __init__ ( self , api , bridge ) :
super ( ListIfacesCommand , self ) . __init__ ( api )
self . bridge = bridge
def run_idl ( self , txn ) :
br = idlutils . row_by_value ( self . api . idl , ' Bridge ' , ' name ' , self . bridge )
self . result = [ i . name for p in br . ports if p . name != self . bridge
for i in p . interfaces ]
class PortToBridgeCommand ( BaseCommand ) :
def __init__ ( self , api , name ) :
super ( PortToBridgeCommand , self ) . __init__ ( api )
self . name = name
def run_idl ( self , txn ) :
# TODO(twilson) This is expensive!
# This traversal of all ports could be eliminated by caching the bridge
# name on the Port's external_id field
# In fact, if we did that, the only place that uses to_br functions
# could just add the external_id field to the conditions passed to find
port = idlutils . row_by_value ( self . api . idl , ' Port ' , ' name ' , self . name )
bridges = self . api . _tables [ ' Bridge ' ] . rows . values ( )
self . result = next ( br . name for br in bridges if port in br . ports )
class InterfaceToBridgeCommand ( BaseCommand ) :
def __init__ ( self , api , name ) :
super ( InterfaceToBridgeCommand , self ) . __init__ ( api )
self . name = name
def run_idl ( self , txn ) :
interface = idlutils . row_by_value ( self . api . idl , ' Interface ' , ' name ' ,
self . name )
ports = self . api . _tables [ ' Port ' ] . rows . values ( )
pname = next (
port for port in ports if interface in port . interfaces )
bridges = self . api . _tables [ ' Bridge ' ] . rows . values ( )
self . result = next ( br . name for br in bridges if pname in br . ports )
class DbListCommand ( BaseCommand ) :
def __init__ ( self , api , table , records , columns , if_exists ) :
super ( DbListCommand , self ) . __init__ ( api )
self . table = table
self . columns = columns
self . if_exists = if_exists
self . records = records
def run_idl ( self , txn ) :
table_schema = self . api . _tables [ self . table ]
columns = self . columns or list ( table_schema . columns . keys ( ) ) + [ ' _uuid ' ]
if self . records :
row_uuids = [ ]
for record in self . records :
try :
row_uuids . append ( idlutils . row_by_record (
self . api . idl , self . table , record ) . uuid )
except idlutils . RowNotFound :
if self . if_exists :
continue
# NOTE(kevinbenton): this is converted to a RuntimeError
# for compat with the vsctl version. It might make more
# sense to change this to a RowNotFoundError in the future.
raise RuntimeError ( _ (
" Row doesn ' t exist in the DB. Request info: "
" Table= %(table)s . Columns= %(columns)s . "
" Records= %(records)s . " ) % {
" table " : self . table ,
" columns " : self . columns ,
" records " : self . records ,
} )
else :
row_uuids = table_schema . rows . keys ( )
self . result = [
{
c : idlutils . get_column_value ( table_schema . rows [ uuid ] , c )
for c in columns
}
for uuid in row_uuids
]
class DbFindCommand ( BaseCommand ) :
def __init__ ( self , api , table , * conditions , * * kwargs ) :
super ( DbFindCommand , self ) . __init__ ( api )
self . table = self . api . _tables [ table ]
self . conditions = conditions
self . columns = ( kwargs . get ( ' columns ' ) or
list ( self . table . columns . keys ( ) ) + [ ' _uuid ' ] )
def run_idl ( self , txn ) :
self . result = [
{
c : idlutils . get_column_value ( r , c )
for c in self . columns
}
for r in self . table . rows . values ( )
if idlutils . row_match ( r , self . conditions )
]
_deprecate . _MovedGlobals ( commands )