Skip to content

Commit

Permalink
ovsdb: Add support for retrieving single record
Browse files Browse the repository at this point in the history
At present the SimpleOVSDB allows you to find records.

The `find` command does however not allow you to match on a
records UUID.

Add API for retrieval of a specific record by subscripting the
SimpleOVSDB Table class.
  • Loading branch information
fnordahl committed Sep 12, 2022
1 parent 6e302ba commit 5195b15
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 41 deletions.
58 changes: 46 additions & 12 deletions charmhelpers/contrib/network/ovs/ovsdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,14 @@ def _deserialize_ovsdb(self, data):
f = ovs_type_cb_map.get(data[0], str)
return f(data[1])

def _find_tbl(self, condition=None):
"""Run and parse output of OVSDB `find` command.
def _cmd_deserialize_data_generator(self, cmd):
"""Run command and provide generator with deserialized data.
:param condition: An optional RFC 7047 5.1 match condition
:type condition: Optional[str]
:returns: Dictionary with data
:rtype: Dict[str, any]
:param cmd: Command and arguments to run.
:type cmd: Iterable[str]
:returns: Deserialzed data.
:rtype: Generator[Dict[str,any], None, None]
"""
cmd = [self._tool]
if self._args:
cmd.extend(self._args)
cmd.extend(['-f', 'json', 'find', self._table])
if condition:
cmd.append(condition)
output = utils._run(*cmd)
data = json.loads(output)
for row in data['data']:
Expand All @@ -238,9 +232,49 @@ def _find_tbl(self, condition=None):
values.append(col)
yield dict(zip(data['headings'], values))

def _get_command(self):
"""Get base command.
:rtype: List[str]
"""
cmd = [self._tool]
if self._args:
cmd.extend(self._args)
cmd += ['-f', 'json']
return cmd

def _find_tbl(self, condition=None):
"""Run and parse output of OVSDB `find` command.
:param condition: An optional RFC 7047 5.1 match condition
:type condition: Optional[str]
:returns: Dictionary with data
:rtype: Generator[Dict[str, any], None, None]
"""
cmd = self._get_command()
cmd.extend(['find', self._table])
if condition:
cmd.append(condition)
return self._cmd_deserialize_data_generator(cmd)

def _list_tbl_record(self, record):
"""Run and parse output of OVSDB `list` command for record.
:param record: The UUID of the record to list data for.
:type record: uuid.UUID
:returns: Dictionary with data
:rtype: Dict[str, any]
"""
cmd = self._get_command()
cmd.extend(['list', self._table, str(record)])
return next(self._cmd_deserialize_data_generator(cmd))

def __iter__(self):
return self._find_tbl()

def __getitem__(self, key):
return self._list_tbl_record(key)

def clear(self, rec, col):
utils._run(self._tool, 'clear', self._table, rec, col)

Expand Down
75 changes: 46 additions & 29 deletions tests/contrib/network/ovs/test_ovsdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,37 @@
""")


VSCTL_BRIDGE_TBL_DESERIALIZED = {
'_uuid': uuid.UUID('1e21ba48-61ff-4b32-b35e-cb80411da351'),
'auto_attach': [],
'controller': [],
'datapath_id': '0000a0369fdd3890',
'datapath_type': '',
'datapath_version': '<unknown>',
'external_ids': {
'charm-ovn-chassis': 'managed',
'other': 'value',
},
'fail_mode': [],
'flood_vlans': [],
'flow_tables': {},
'ipfix': [],
'mcast_snooping_enable': False,
'mirrors': [],
'name': 'br-test',
'netflow': [],
'other_config': {},
'ports': [uuid.UUID('617f9359-77e2-41be-8af6-4c44e7a6bcc3'),
uuid.UUID('da840476-8809-4107-8733-591f4696f056')],
'protocols': ['OpenFlow10', 'OpenFlow13', 'OpenFlow14'],
'rstp_enable': False,
'rstp_status': {},
'sflow': [],
'status': {},
'stp_enable': False,
}


class TestSimpleOVSDB(test_utils.BaseTestCase):

def patch_target(self, attr, return_value=None):
Expand All @@ -55,37 +86,9 @@ def test__find_tbl(self):
self.patch_object(ovsdb.utils, '_run')
self._run.return_value = VSCTL_BRIDGE_TBL
self.maxDiff = None
expect = {
'_uuid': uuid.UUID('1e21ba48-61ff-4b32-b35e-cb80411da351'),
'auto_attach': [],
'controller': [],
'datapath_id': '0000a0369fdd3890',
'datapath_type': '',
'datapath_version': '<unknown>',
'external_ids': {
'charm-ovn-chassis': 'managed',
'other': 'value',
},
'fail_mode': [],
'flood_vlans': [],
'flow_tables': {},
'ipfix': [],
'mcast_snooping_enable': False,
'mirrors': [],
'name': 'br-test',
'netflow': [],
'other_config': {},
'ports': [uuid.UUID('617f9359-77e2-41be-8af6-4c44e7a6bcc3'),
uuid.UUID('da840476-8809-4107-8733-591f4696f056')],
'protocols': ['OpenFlow10', 'OpenFlow13', 'OpenFlow14'],
'rstp_enable': False,
'rstp_status': {},
'sflow': [],
'status': {},
'stp_enable': False}
# this in effect also tests the __iter__ front end method
for el in self.target.bridge:
self.assertDictEqual(el, expect)
self.assertDictEqual(el, VSCTL_BRIDGE_TBL_DESERIALIZED)
break
self._run.assert_called_once_with(
'ovs-vsctl', '-f', 'json', 'find', 'bridge')
Expand All @@ -104,6 +107,20 @@ def test__find_tbl(self):
'ovs-vsctl', 'extra', 'args',
'-f', 'json', 'find', 'bridge', 'name=br-test')

def test__list_tbl_record(self):
self.target = ovsdb.SimpleOVSDB('ovs-vsctl')
self.patch_object(ovsdb.utils, '_run')
self._run.return_value = VSCTL_BRIDGE_TBL
self.maxDiff = None
# this in effect also tests the __getitem__ front end method
self.assertEqual(
VSCTL_BRIDGE_TBL_DESERIALIZED,
self.target.bridge[
uuid.UUID('1e21ba48-61ff-4b32-b35e-cb80411da351')])
self._run.assert_called_once_with(
'ovs-vsctl', '-f', 'json', 'list', 'bridge',
'1e21ba48-61ff-4b32-b35e-cb80411da351')

def test_clear(self):
self.target = ovsdb.SimpleOVSDB('ovs-vsctl')
self.patch_object(ovsdb.utils, '_run')
Expand Down

0 comments on commit 5195b15

Please sign in to comment.