from neutron.agent.ovsdb import api
from neutron.agent.ovsdb.native import idlutils
-from neutron.common import exceptions
from neutron.i18n import _LE
LOG = logging.getLogger(__name__)
-class RowNotFound(exceptions.NeutronException):
- message = _("Table %(table)s has no row with %(col)s=%(match)s")
-
-
class BaseCommand(api.Command):
def __init__(self, api):
self.api = api
if not check_error:
ctx.reraise = False
- def row_by_index(self, table, match, *default):
- tab = self.api._tables[table]
- idx = idlutils.get_index_column(tab)
- return self.row_by_value(table, idx, match, *default)
-
- def row_by_value(self, table, column, match, *default):
- tab = self.api._tables[table]
- try:
- return next(r for r in tab.rows.values()
- if getattr(r, column) == match)
- except StopIteration:
- if len(default) == 1:
- return default[0]
- else:
- raise RowNotFound(table=table, col=column, match=match)
-
def __str__(self):
command_info = self.__dict__
return "%s(%s)" % (
def run_idl(self, txn):
if self.may_exist:
- br = self.row_by_value('Bridge', 'name', self.name, None)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name',
+ self.name, None)
if br:
return
row = txn.insert(self.api._tables['Bridge'])
def run_idl(self, txn):
try:
- br = self.row_by_value('Bridge', 'name', self.name)
- except RowNotFound:
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name',
+ self.name)
+ except idlutils.RowNotFound:
if self.if_exists:
return
else:
self.name = name
def run_idl(self, txn):
- self.result = bool(self.row_by_value('Bridge',
- 'name', self.name, None))
+ self.result = bool(idlutils.row_by_value(self.api.idl, 'Bridge',
+ 'name', self.name, None))
class ListBridgesCommand(BaseCommand):
self.field = field
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.name)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.name)
self.result = br.external_ids[self.field]
self.value = value
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.name)
+ 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
self.col_values = col_values
def run_idl(self, txn):
- record = self.row_by_index(self.table, self.record)
+ 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
self.column = column
def run_idl(self, txn):
- record = self.row_by_index(self.table, self.record)
+ 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)
self.column = column
def run_idl(self, txn):
- record = self.row_by_index(self.table, self.record)
+ 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
self.targets = targets
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ 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'])
self.bridge = bridge
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.bridge)
br.controller = []
self.bridge = bridge
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.bridge)
br.verify('controller')
self.result = [c.target for c in br.controller]
self.mode = mode
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.bridge)
br.verify('fail_mode')
br.fail_mode = self.mode
self.may_exist = may_exist
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name', self.bridge)
if self.may_exist:
- port = self.row_by_value('Port', 'name', self.port, None)
+ port = idlutils.row_by_value(self.api.idl, 'Port', 'name',
+ self.port, None)
if port:
return
port = txn.insert(self.api._tables['Port'])
def run_idl(self, txn):
try:
- port = self.row_by_value('Port', 'name', self.port)
- except RowNotFound:
+ port = idlutils.row_by_value(self.api.idl, 'Port', 'name',
+ self.port)
+ except idlutils.RowNotFound:
if self.if_exists:
return
msg = _LE("Port %s does not exist") % self.port
raise RuntimeError(msg)
if self.bridge:
- br = self.row_by_value('Bridge', 'name', 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)
self.bridge = bridge
def run_idl(self, txn):
- br = self.row_by_value('Bridge', 'name', self.bridge)
+ 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]
# name on the Port's (or Interface's for iface_to_br) 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 = self.row_by_value('Port', 'name', self.name)
+ 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)
self.table = self.api._tables[table]
self.columns = columns or self.table.columns.keys() + ['_uuid']
self.if_exists = if_exists
- idx = idlutils.get_index_column(self.table)
if records:
- self.records = [uuid for uuid, row in self.table.rows.items()
- if getattr(row, idx) in records]
+ self.records = [
+ idlutils.row_by_record(self.api.idl, table, record).uuid
+ for record in records]
else:
self.records = self.table.rows.keys()
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import os
import time
+import uuid
from ovs.db import idl
from ovs import jsonrpc
from ovs import poller
from ovs import stream
+from neutron.common import exceptions
+
+
+RowLookup = collections.namedtuple('RowLookup',
+ ['table', 'column', 'uuid_column'])
+
+# Tables with no index in OVSDB and special record lookup rules
+_LOOKUP_TABLE = {
+ 'Controller': RowLookup('Bridge', 'name', 'controller'),
+ 'Flow_Table': RowLookup('Flow_Table', 'name', None),
+ 'IPFIX': RowLookup('Bridge', 'name', 'ipfix'),
+ 'Mirror': RowLookup('Mirror', 'name', None),
+ 'NetFlow': RowLookup('Bridge', 'name', 'netflow'),
+ 'QoS': RowLookup('Port', 'name', 'qos'),
+ 'Queue': RowLookup(None, None, None),
+ 'sFlow': RowLookup('Bridge', 'name', 'sflow'),
+ 'SSL': RowLookup('Open_vSwitch', None, 'ssl'),
+}
+
+_NO_DEFAULT = object()
+
+
+class RowNotFound(exceptions.NeutronException):
+ message = _("Cannot find %(table)s with %(col)s=%(match)s")
+
+
+def row_by_value(idl_, table, column, match, default=_NO_DEFAULT):
+ """Lookup an IDL row in a table by column/value"""
+ tab = idl_.tables[table]
+ for r in tab.rows.values():
+ if getattr(r, column) == match:
+ return r
+ if default is not _NO_DEFAULT:
+ return default
+ raise RowNotFound(table=table, col=column, match=match)
+
+
+def row_by_record(idl_, table, record):
+ t = idl_.tables[table]
+ try:
+ if isinstance(record, uuid.UUID):
+ return t.rows[record]
+ uuid_ = uuid.UUID(record)
+ return t.rows[uuid_]
+ except ValueError:
+ # Not a UUID string, continue lookup by other means
+ pass
+ except KeyError:
+ raise RowNotFound(table=table, col='uuid', match=record)
+
+ rl = _LOOKUP_TABLE.get(table, RowLookup(table, get_index_column(t), None))
+ # no table means uuid only, no column is just SSL which we don't need
+ if rl.table is None:
+ raise ValueError(_("Table %s can only be queried by UUID") % table)
+ if rl.column is None:
+ raise NotImplementedError(_("'.' searches are not implemented"))
+ row = row_by_value(idl_, rl.table, rl.column, record)
+ if rl.uuid_column:
+ rows = getattr(row, rl.uuid_column)
+ if len(rows) != 1:
+ raise RowNotFound(table=table, col=_('record'), match=record)
+ row = rows[0]
+ return row
+
def get_schema_helper(connection):
err, strm = stream.Stream.open_block(