From 641b6b857e29868ed25c02df554816e164bfaa53 Mon Sep 17 00:00:00 2001 From: Anton Vazhnetsov Date: Sat, 13 Nov 2021 23:45:21 +0300 Subject: [PATCH] nb: add support for set of addresses API This change adds functions and commands to add, delete, list, get and update sets of addresses. Closes-Bug: #1951110 Change-Id: I9390bf5e3586a3dd28c3743d06578c2a8f262e77 --- ovsdbapp/schema/ovn_northbound/api.py | 62 ++++++++++ ovsdbapp/schema/ovn_northbound/commands.py | 82 +++++++++++++ ovsdbapp/schema/ovn_northbound/impl_idl.py | 18 +++ .../schema/ovn_northbound/fixtures.py | 5 + .../schema/ovn_northbound/test_impl_idl.py | 110 ++++++++++++++++++ ...vide-address-set-api-3cb387b9e571d4ea.yaml | 4 + 6 files changed, 281 insertions(+) create mode 100644 releasenotes/notes/provide-address-set-api-3cb387b9e571d4ea.yaml diff --git a/ovsdbapp/schema/ovn_northbound/api.py b/ovsdbapp/schema/ovn_northbound/api.py index 6a6f4b6b..85566699 100644 --- a/ovsdbapp/schema/ovn_northbound/api.py +++ b/ovsdbapp/schema/ovn_northbound/api.py @@ -206,6 +206,68 @@ class API(api.API, metaclass=abc.ABCMeta): :returns: :class:`Command` with RowView list result """ + @abc.abstractmethod + def address_set_add(self, name, addresses=None, may_exist=False): + """Create a set of addresses named 'name' + + :param name: The name of the address set + :type name: string + :param addresses: One or more IP addresses to add to the address set + :type addresses: list of strings + :param may_exist: If True, don't fail if the address set already exists + :type may_exist: boolean + :returns: :class:`Command` with RowView result + """ + + @abc.abstractmethod + def address_set_del(self, address_set, if_exists=False): + """Delete a set of addresses 'address_set' + + :param address_set: The name of the address set + :type address_set: string or uuid.UUID + :param if_exists: Do not fail if the Address_set row does not exist + :type if_exists: bool + :returns: :class:`Command` with no result + """ + + @abc.abstractmethod + def address_set_get(self, address_set): + """Get a set of addresses for 'address_set' + + :param address_set: The name of the address set + :type address_set: string or uuid.UUID + :returns: :class:`Command` with RowView result + """ + + @abc.abstractmethod + def address_set_list(self): + """Get all sets of addresses + + :returns: :class:`Command` with RowView list result + """ + + @abc.abstractmethod + def address_set_add_addresses(self, address_set, addresses): + """Add a list of addresses to 'address_set' + + :param address_set: The name of the address set + :type address_set: string or uuid.UUID + :param addresses: One or more IP addresses to add to the address set + :type addresses: string or list of strings + :returns: :class:`Command` with no result + """ + + @abc.abstractmethod + def address_set_remove_addresses(self, address_set, addresses): + """Remove a list of addresses from 'address_set' + + :param address_set: The name of the address set + :type address_set: string or uuid.UUID + :param addresses: One or more IP addresses to remove from address set + :type addresses: string of list of strings + :returns: :class:`Command` with no result + """ + @abc.abstractmethod def qos_add(self, switch, direction, priority, match, rate=None, burst=None, dscp=None, may_exist=False, **columns): diff --git a/ovsdbapp/schema/ovn_northbound/commands.py b/ovsdbapp/schema/ovn_northbound/commands.py index 979c593d..ec6f2118 100644 --- a/ovsdbapp/schema/ovn_northbound/commands.py +++ b/ovsdbapp/schema/ovn_northbound/commands.py @@ -214,6 +214,88 @@ class PgAclListCommand(_AclListHelper): lookup_table = 'Port_Group' +class AddressSetAddCommand(cmd.AddCommand): + table_name = 'Address_Set' + + def __init__(self, api, name, addresses=None, may_exist=False): + super().__init__(api) + self.name = name + self.addresses = [str(netaddr.IPAddress(address)) + for address in addresses or []] + self.may_exist = may_exist + + def run_idl(self, txn): + address_set = self.api.lookup(self.table_name, self.name, None) + if address_set: + if self.may_exist: + self.result = rowview.RowView(address_set) + return + raise RuntimeError("Address set %s exists" % self.name) + + address_set = txn.insert(self.api.tables[self.table_name]) + address_set.name = self.name + if self.addresses: + address_set.addresses = self.addresses + self.result = address_set.uuid + + +class AddressSetDelCommand(cmd.BaseCommand): + table_name = 'Address_Set' + + def __init__(self, api, address_set, if_exists=False): + super().__init__(api) + self.address_set = address_set + self.if_exists = if_exists + + def run_idl(self, txn): + try: + address_set = self.api.lookup(self.table_name, self.address_set) + address_set.delete() + except idlutils.RowNotFound as e: + if self.if_exists: + return + msg = "Address set %s does not exist" % self.address_set + raise RuntimeError(msg) from e + + +class AddressSetGetCommand(cmd.BaseGetRowCommand): + table = 'Address_Set' + + +class AddressSetListCommand(cmd.ReadOnlyCommand): + table = 'Address_Set' + + def run_idl(self, txn): + self.result = [rowview.RowView(r) for + r in self.api.tables[self.table].rows.values()] + + +class AddressSetUpdateAddressesCommand(cmd.BaseCommand): + table_name = 'Address_Set' + + def __init__(self, api, address_set, addresses): + super().__init__(api) + self.address_set = address_set + if isinstance(addresses, (str, bytes)): + addresses = [addresses] + self.addresses = [str(netaddr.IPAddress(address)) + for address in addresses] + + +class AddressSetAddAddressesCommand(AddressSetUpdateAddressesCommand): + def run_idl(self, txn): + address_set = self.api.lookup(self.table_name, self.address_set) + for address in self.addresses: + address_set.addvalue('addresses', address) + + +class AddressSetRemoveAddressCommand(AddressSetUpdateAddressesCommand): + def run_idl(self, txn): + address_set = self.api.lookup(self.table_name, self.address_set) + for address in self.addresses: + address_set.delvalue('addresses', address) + + class QoSAddCommand(cmd.AddCommand): table_name = 'QoS' diff --git a/ovsdbapp/schema/ovn_northbound/impl_idl.py b/ovsdbapp/schema/ovn_northbound/impl_idl.py index 1254df5f..53f788b9 100644 --- a/ovsdbapp/schema/ovn_northbound/impl_idl.py +++ b/ovsdbapp/schema/ovn_northbound/impl_idl.py @@ -80,6 +80,24 @@ class OvnNbApiIdlImpl(ovs_idl.Backend, api.API): def pg_acl_list(self, port_group): return cmd.PgAclListCommand(self, port_group) + def address_set_add(self, name, addresses=None, may_exist=False): + return cmd.AddressSetAddCommand(self, name, addresses, may_exist) + + def address_set_del(self, address_set, if_exists=False): + return cmd.AddressSetDelCommand(self, address_set, if_exists) + + def address_set_get(self, address_set): + return cmd.AddressSetGetCommand(self, address_set) + + def address_set_list(self): + return cmd.AddressSetListCommand(self) + + def address_set_add_addresses(self, address_set, addresses): + return cmd.AddressSetAddAddressesCommand(self, address_set, addresses) + + def address_set_remove_addresses(self, address_set, addresses): + return cmd.AddressSetRemoveAddressCommand(self, address_set, addresses) + def qos_add(self, switch, direction, priority, match, rate=None, burst=None, dscp=None, may_exist=False, **columns): return cmd.QoSAddCommand(self, switch, direction, priority, match, diff --git a/ovsdbapp/tests/functional/schema/ovn_northbound/fixtures.py b/ovsdbapp/tests/functional/schema/ovn_northbound/fixtures.py index d37f0794..c5cc5e0e 100644 --- a/ovsdbapp/tests/functional/schema/ovn_northbound/fixtures.py +++ b/ovsdbapp/tests/functional/schema/ovn_northbound/fixtures.py @@ -45,6 +45,11 @@ class PortGroupFixture(fixtures.ImplIdlFixture): delete = 'pg_del' +class AddressSetFixture(fixtures.ImplIdlFixture): + create = 'address_set_add' + delete = 'address_set_del' + + class MeterFixture(fixtures.ImplIdlFixture): create = 'meter_add' delete = 'meter_del' diff --git a/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py b/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py index d4562a40..27e27a6f 100644 --- a/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py +++ b/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py @@ -236,6 +236,116 @@ class TestAclOps(OvnNorthboundTest): self.assertIn(r2, acls) +class TestAddressSetOps(OvnNorthboundTest): + def setUp(self): + super(TestAddressSetOps, self).setUp() + self.table = self.api.tables['Address_Set'] + + def _addr_set_add(self, name=None, *args, **kwargs): + if name is None: + name = utils.get_rand_name() + fix = self.useFixture(fixtures.AddressSetFixture(self.api, name, + *args, **kwargs)) + self.assertIn(fix.obj.uuid, self.table.rows) + return fix.obj + + def _test_addr_set_get(self, col): + addr_set = self._addr_set_add() + val = getattr(addr_set, col) + found = self.api.address_set_get(val).execute(check_error=True) + self.assertEqual(addr_set, found) + + def test_addr_set_get_uuid(self): + self._test_addr_set_get('uuid') + + def test_addr_set_get_name(self): + self._test_addr_set_get('name') + + def test_addr_set_add_name(self): + name = utils.get_rand_device_name() + addr_set = self._addr_set_add(name) + self.assertEqual(name, addr_set.name) + + def test_addr_set_add_exists(self): + name = utils.get_rand_device_name() + self._addr_set_add(name) + cmd = self.api.address_set_add(name) + self.assertRaises(RuntimeError, cmd.execute, check_error=True) + + def test_addr_set_add_may_exist(self): + name = utils.get_rand_device_name() + addr_set = self._addr_set_add(name) + addr_set2 = self.api.address_set_add( + name, may_exist=True).execute(check_error=True) + self.assertEqual(addr_set, addr_set2) + + def test_addr_set_add_with_addresses(self): + addresses = ['192.168.0.1', '192.168.0.2'] + addr_set = self._addr_set_add(addresses=addresses) + self.assertEqual(addresses, addr_set.addresses) + + def test_addr_set_del(self): + addr_set = self._addr_set_add() + self.api.address_set_del(addr_set.uuid).execute(check_error=True) + self.assertNotIn(addr_set.uuid, self.table.rows) + + def test_addr_set_del_by_name(self): + name = utils.get_rand_device_name() + self._addr_set_add(name) + self.api.address_set_del(name).execute(check_error=True) + + def test_addr_set_del_no_exist(self): + name = utils.get_rand_device_name() + cmd = self.api.address_set_del(name) + self.assertRaises(RuntimeError, cmd.execute, check_error=True) + + def test_addr_set_del_if_exists(self): + name = utils.get_rand_device_name() + self.api.address_set_del( + name, if_exists=True).execute(check_error=True) + + def test_addr_set_list(self): + addr_sets = {self._addr_set_add() for _ in range(3)} + found_sets = set(self.api.address_set_list().execute(check_error=True)) + self.assertTrue(addr_sets.issubset(found_sets)) + + def test_addr_set_add_addresses(self): + addresses = ['192.168.0.1', '192.168.0.2'] + addr_set = self._addr_set_add() + + self.api.address_set_add_addresses( + addr_set.uuid, addresses).execute(check_error=True) + self.assertEqual(addresses, addr_set.addresses) + + self.api.address_set_add_addresses( + addr_set.uuid, addresses).execute(check_error=True) + self.assertEqual(addresses, addr_set.addresses) + + def test_addr_set_remove_addresses(self): + addresses = ['192.168.0.1', '192.168.0.2'] + addr_set = self._addr_set_add(addresses=addresses) + + self.api.address_set_remove_addresses( + addr_set.uuid, addresses).execute(check_error=True) + self.assertEqual(addr_set.addresses, []) + + self.api.address_set_remove_addresses( + addr_set.uuid, addresses).execute(check_error=True) + self.assertEqual(addr_set.addresses, []) + + def test_addr_set_add_remove_addresses_by_str(self): + address = "192.168.0.1" + addr_set = self._addr_set_add() + + self.api.address_set_add_addresses( + addr_set.uuid, address).execute(check_error=True) + self.assertEqual([address], addr_set.addresses) + + self.api.address_set_remove_addresses( + addr_set.uuid, address).execute(check_error=True) + self.assertEqual([], addr_set.addresses) + + class TestQoSOps(OvnNorthboundTest): def setUp(self): super(TestQoSOps, self).setUp() diff --git a/releasenotes/notes/provide-address-set-api-3cb387b9e571d4ea.yaml b/releasenotes/notes/provide-address-set-api-3cb387b9e571d4ea.yaml new file mode 100644 index 00000000..ccc5405d --- /dev/null +++ b/releasenotes/notes/provide-address-set-api-3cb387b9e571d4ea.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Added functions and commands to add, delete, list and update records of 'Address_Set' table.