[NB] Add "if_exists" flag to ACL and Port_Group deletion commands

Related-Bug: #2084977
Change-Id: I64fd656fa7ce48e44bcf2881e7a06697335fd09f
This commit is contained in:
Rodolfo Alonso Hernandez 2024-11-06 11:20:44 +00:00
parent d603441459
commit e2d8d39fa1
4 changed files with 68 additions and 14 deletions

View File

@ -128,7 +128,8 @@ class API(api.API, metaclass=abc.ABCMeta):
""" """
@abc.abstractmethod @abc.abstractmethod
def acl_del(self, switch, direction=None, priority=None, match=None): def acl_del(self, switch, direction=None, priority=None, match=None,
if_exists=False):
"""Remove ACLs from 'switch' """Remove ACLs from 'switch'
If only switch is supplied, all the ACLs from the logical switch are If only switch is supplied, all the ACLs from the logical switch are
@ -144,6 +145,9 @@ class API(api.API, metaclass=abc.ABCMeta):
:type priority: int :type priority: int
:param match: The match rule :param match: The match rule
:type match: string :type match: string
:param if_exists: If True, don't fail if the parent logical switch
containing the ACL doesn't exist
:type if_exists: boolean
:returns: :class:`Command` with no result :returns: :class:`Command` with no result
""" """
@ -189,7 +193,7 @@ class API(api.API, metaclass=abc.ABCMeta):
@abc.abstractmethod @abc.abstractmethod
def pg_acl_del(self, port_group, direction=None, priority=None, def pg_acl_del(self, port_group, direction=None, priority=None,
match=None): match=None, if_exists=False):
"""Remove ACLs from 'port_group' """Remove ACLs from 'port_group'
If only port_group is supplied, all the ACLs from the logical switch If only port_group is supplied, all the ACLs from the logical switch
@ -205,6 +209,9 @@ class API(api.API, metaclass=abc.ABCMeta):
:type priority: int :type priority: int
:param match: The match rule :param match: The match rule
:type match: string :type match: string
:param if_exists: If True, don't fail if the parent port group
containing the ACL doesn't exist
:type if_exists: boolean
:returns: :class:`Command` with no result :returns: :class:`Command` with no result
""" """

View File

@ -190,13 +190,14 @@ class PgAclAddCommand(_AclAddHelper):
class _AclDelHelper(cmd.BaseCommand): class _AclDelHelper(cmd.BaseCommand):
def __init__(self, api, entity, direction=None, def __init__(self, api, entity, direction=None,
priority=None, match=None): priority=None, match=None, if_exists=False):
if (priority is None) != (match is None): if (priority is None) != (match is None):
raise TypeError("Must specify priority and match together") raise TypeError("Must specify priority and match together")
if priority is not None and not direction: if priority is not None and not direction:
raise TypeError("Cannot specify priority/match without direction") raise TypeError("Cannot specify priority/match without direction")
super().__init__(api) super().__init__(api)
self.entity = entity self.entity = entity
self.if_exists = if_exists
self.conditions = [] self.conditions = []
if direction: if direction:
self.conditions.append(('direction', '=', direction)) self.conditions.append(('direction', '=', direction))
@ -206,7 +207,14 @@ class _AclDelHelper(cmd.BaseCommand):
('match', '=', match)] ('match', '=', match)]
def run_idl(self, txn): def run_idl(self, txn):
entity = self.api.lookup(self.lookup_table, self.entity) try:
entity = self.api.lookup(self.lookup_table, self.entity)
except idlutils.RowNotFound as e:
if self.if_exists:
return
msg = "%s %s does not exist" % (self.lookup_table, self.entity)
raise RuntimeError(msg) from e
for acl in [a for a in entity.acls for acl in [a for a in entity.acls
if idlutils.row_match(a, self.conditions)]: if idlutils.row_match(a, self.conditions)]:
entity.delvalue('acls', acl) entity.delvalue('acls', acl)
@ -216,12 +224,6 @@ class _AclDelHelper(cmd.BaseCommand):
class AclDelCommand(_AclDelHelper): class AclDelCommand(_AclDelHelper):
lookup_table = 'Logical_Switch' lookup_table = 'Logical_Switch'
def __init__(self, api, switch, direction=None,
priority=None, match=None):
# NOTE: we're overriding the constructor here to not break any
# existing callers before we introduced Port Groups.
super().__init__(api, switch, direction, priority, match)
class PgAclDelCommand(_AclDelHelper): class PgAclDelCommand(_AclDelHelper):
lookup_table = 'Port_Group' lookup_table = 'Port_Group'

View File

@ -61,8 +61,10 @@ class OvnNbApiIdlImpl(ovs_idl.Backend, api.API):
return cmd.AclAddCommand(self, switch, direction, priority, return cmd.AclAddCommand(self, switch, direction, priority,
match, action, log, may_exist, **external_ids) match, action, log, may_exist, **external_ids)
def acl_del(self, switch, direction=None, priority=None, match=None): def acl_del(self, switch, direction=None, priority=None, match=None,
return cmd.AclDelCommand(self, switch, direction, priority, match) if_exists=False):
return cmd.AclDelCommand(self, switch, direction, priority, match,
if_exists)
def acl_list(self, switch): def acl_list(self, switch):
return cmd.AclListCommand(self, switch) return cmd.AclListCommand(self, switch)
@ -76,9 +78,9 @@ class OvnNbApiIdlImpl(ovs_idl.Backend, api.API):
**external_ids) **external_ids)
def pg_acl_del(self, port_group, direction=None, priority=None, def pg_acl_del(self, port_group, direction=None, priority=None,
match=None): match=None, if_exists=False):
return cmd.PgAclDelCommand(self, port_group, direction, priority, return cmd.PgAclDelCommand(self, port_group, direction, priority,
match) match, if_exists)
def pg_acl_list(self, port_group): def pg_acl_list(self, port_group):
return cmd.PgAclListCommand(self, port_group) return cmd.PgAclListCommand(self, port_group)

View File

@ -217,6 +217,27 @@ class TestAclOps(OvnNorthboundTest):
self.assertRaises(TypeError, self.api.acl_del, self.switch.uuid, self.assertRaises(TypeError, self.api.acl_del, self.switch.uuid,
priority=0) priority=0)
def test_acl_del_acl_not_present(self):
r1 = self._acl_add('lswitch', 'from-lport', 0,
'output == "fake_port"', 'drop')
cmd = self.api.acl_del(self.switch.uuid,
'from-lport', 0, 'output == "fake_port"')
cmd.execute(check_error=True)
self.assertNotIn(r1, self.switch.acls)
# The acl_del command is idempotent.
cmd.execute(check_error=True)
self.assertNotIn(r1, self.switch.acls)
def test_acl_del_if_exists_false(self):
cmd = self.api.acl_del('lswitch2', 'from-lport', 0, 'match')
self.assertRaises(RuntimeError, cmd.execute, check_error=True)
def test_acl_del_if_exists_true(self):
self.assertIsNone(
self.api.acl_del('lswitch2', 'from-lport', 0, 'match',
if_exists=True).execute(check_error=True))
def test_acl_list(self): def test_acl_list(self):
r1 = self._acl_add('lswitch', 'from-lport', 0, r1 = self._acl_add('lswitch', 'from-lport', 0,
'output == "fake_port"', 'drop') 'output == "fake_port"', 'drop')
@ -255,6 +276,28 @@ class TestAclOps(OvnNorthboundTest):
self.assertNotIn(r1.uuid, self.api.tables['ACL'].rows) self.assertNotIn(r1.uuid, self.api.tables['ACL'].rows)
self.assertEqual([], self.port_group.acls) self.assertEqual([], self.port_group.acls)
def test_pg_acl_del_acl_not_present(self):
r1 = self._acl_add('port_group', 'from-lport', 0,
'output == "fake_port"', 'drop')
cmd = self.api.pg_acl_del(self.port_group.uuid)
cmd.execute(check_error=True)
self.assertNotIn(r1.uuid, self.api.tables['ACL'].rows)
self.assertEqual([], self.port_group.acls)
# The pg_acl_del command is idempotent.
cmd.execute(check_error=True)
self.assertNotIn(r1.uuid, self.api.tables['ACL'].rows)
self.assertEqual([], self.port_group.acls)
def test_pg_acl_del_if_exists_false(self):
cmd = self.api.pg_acl_del('port_group2')
self.assertRaises(RuntimeError, cmd.execute, check_error=True)
def test_pg_acl_del_if_exists_true(self):
self.assertIsNone(
self.api.pg_acl_del('port_group2',
if_exists=True).execute(check_error=True))
def test_pg_acl_list(self): def test_pg_acl_list(self):
r1 = self._acl_add('port_group', 'from-lport', 0, r1 = self._acl_add('port_group', 'from-lport', 0,
'output == "fake_port"', 'drop') 'output == "fake_port"', 'drop')