Skip to content

Commit

Permalink
Extend ACL API to support changing match critera and logging for an e…
Browse files Browse the repository at this point in the history
…xisting ACL

This was accomplished by adding the following two APIs and corresponding
test cases:

- ACLSetMatchEntity()
- ACLSetLoggingEntity()

Addresses Issue eBay#138

Signed-off-by: Andre Fredette <[email protected]>
  • Loading branch information
anfredette committed Mar 16, 2021
1 parent f6ee8f3 commit 143aac0
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 14 deletions.
77 changes: 77 additions & 0 deletions acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,83 @@ func (odbi *ovndb) aclAddImp(entityType EntityType, entity, direct, match, actio
return &OvnCommand{operations, odbi, make([][]map[string]interface{}, len(operations))}, nil
}

func (odbi *ovndb) aclSetMatchEntityImp(entityType EntityType, entity, direct, oldMatch, newMatch string, priority int) (*OvnCommand, error) {
row := make(OVNRow)
row["direction"] = direct
row["match"] = oldMatch
row["priority"] = priority

aclUUID, err := odbi.getACLUUIDByRow(entityType, entity, row)
if err != nil {
return nil, err
} else if len(aclUUID) == 0 {
return nil, ErrorNotFound
}

// Check if an ACL with the newMatch already exists
row["match"] = newMatch
_, err = odbi.getACLUUIDByRow(entityType, entity, row)
if err == nil {
return nil, ErrorExist
}

// remove keys that don't need to be updated
delete(row,"direction")
delete(row,"priority")

condition := libovsdb.NewCondition("_uuid", "==", stringToGoUUID(aclUUID))
updateOp := libovsdb.Operation{
Op: opUpdate,
Table: TableACL,
Row: row,
Where: []interface{}{condition},
}
operations := []libovsdb.Operation{updateOp}
return &OvnCommand{operations, odbi, make([][]map[string]interface{}, len(operations))}, nil
}

func (odbi *ovndb) aCLSetLoggingEntityimp(entityType EntityType, entity, direct, match string, priority int, newLogflag bool, newMeter, newSeverity string) (*OvnCommand, error) {
row := make(OVNRow)
row["direction"] = direct
row["match"] = match
row["priority"] = priority

aclUUID, err := odbi.getACLUUIDByRow(entityType, entity, row)
if err != nil {
return nil, err
} else if len(aclUUID) == 0 {
return nil, ErrorNotFound
}

// reinitialize row and add the fields that need to be updated
row = make(OVNRow)
row["log"] = newLogflag
if newLogflag {
ok := odbi.meterFind(newMeter)
if ok {
row["meter"] = newMeter
}
switch newSeverity {
case "alert", "debug", "info", "notice", "warning":
row["severity"] = newSeverity
case "":
row["severity"] = "info"
default:
return nil, ErrorOption
}
}

condition := libovsdb.NewCondition("_uuid", "==", stringToGoUUID(aclUUID))
updateOp := libovsdb.Operation{
Op: opUpdate,
Table: TableACL,
Row: row,
Where: []interface{}{condition},
}
operations := []libovsdb.Operation{updateOp}
return &OvnCommand{operations, odbi, make([][]map[string]interface{}, len(operations))}, nil
}

func (odbi *ovndb) aclDelImp(entityType EntityType, entity, direct, match string, priority int, external_ids map[string]string) (*OvnCommand, error) {
var table string

Expand Down
220 changes: 206 additions & 14 deletions acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package goovn

import (
"testing"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -200,7 +200,6 @@ func TestLogicalSwitchACLs(t *testing.T) {
}
assert.Equal(t, true, len(acls) == 4, "test[%s]", "add second acl")


cmd, err = ovndbapi.ACLDel(LSW, "to-lport", MATCH_SECOND, 1002, nil)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -346,13 +345,13 @@ func compareMeterSlices(s1, s2 []string) bool {
}

// Returns true if an acl is in aclList
func containsACL(aclList []*ACL, acl *ACL) bool{
func containsACL(aclList []*ACL, acl *ACL) bool {
for _, a := range aclList {
// Compare everything except UUID
if a.Action == acl.Action &&
a.Direction == acl.Direction &&
a.Match == acl.Match &&
a.Priority == acl.Priority &&
if a.Action == acl.Action &&
a.Direction == acl.Direction &&
a.Match == acl.Match &&
a.Priority == acl.Priority &&
a.Log == acl.Log &&
compareMeterSlices(a.Meter, acl.Meter) &&
a.Severity == acl.Severity &&
Expand All @@ -375,7 +374,7 @@ func iMapToSMap(iMap map[interface{}]interface{}) map[string]string {
return sMap
}

func TestPortGroupACLs(t *testing.T) {
func TestEntityACLs(t *testing.T) {
ovndbapi := getOVNClient(DBNB)
var cmd *OvnCommand
var cmds []*OvnCommand
Expand Down Expand Up @@ -424,10 +423,15 @@ func TestPortGroupACLs(t *testing.T) {
assert.Nil(t, err)

// Create a meter
cmds = make([]*OvnCommand, 0)
cmd, err = ovndbapi.MeterAdd("meter1", "drop", 101, "kbps", nil, 300)
assert.Nil(t, err)
// execute to create lsw and lsp
err = ovndbapi.Execute(cmd)
cmds = append(cmds, cmd)
cmd, err = ovndbapi.MeterAdd("meter2", "drop", 101, "kbps", nil, 300)
assert.Nil(t, err)
cmds = append(cmds, cmd)
// execute to create meters
err = ovndbapi.Execute(cmds...)
assert.Nil(t, err)
})

Expand Down Expand Up @@ -478,22 +482,210 @@ func TestPortGroupACLs(t *testing.T) {
}
})

type aclMatchUpdateTest struct {
name string
entityType EntityType
entity string
acl ACL
newMatch string
passExpected bool
}

aclMatchUpdateTests := []aclMatchUpdateTest{
{"PG ACL update pass expected 1",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
true},
{"PG ACL update pass expected 2",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1002, true, []string{"meter1"}, "alert", map[interface{}]interface{}{"A": "a", "B": "b"}},
MATCH3,
true},
{"PG ACL update fail expected",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
false},
{"LS ACL update pass expected 1",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
true},
{"LS ACL update pass expected 2",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1002, true, []string{"meter1"}, "alert", map[interface{}]interface{}{"A": "a", "B": "b"}},
MATCH3,
true},
{"LS ACL update fail expected",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
false},
}

for i, tc := range aclMatchUpdateTests {
tcName := "add " + tc.name
t.Run(tcName, func(t *testing.T) {
cmd, err = ovndbapi.ACLAddEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.acl.Action, tc.acl.Priority, iMapToSMap(tc.acl.ExternalID), tc.acl.Log, tc.acl.Meter[0], tc.acl.Severity)
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err := ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
assert.True(t, containsACL(acls, &tc.acl))

cmd, err = ovndbapi.ACLSetMatchEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.newMatch, tc.acl.Priority)
if tc.passExpected {
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err = ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
aclMatchUpdateTests[i].acl.Match = tc.newMatch
assert.True(t, containsACL(acls, &aclMatchUpdateTests[i].acl))
} else {
assert.NotNil(t, err)
}
})
}

// Delete the aclMatchUpdateTest ACLs
for _, tc := range aclMatchUpdateTests {
tcName := "delete " + tc.name
t.Run(tcName, func(t *testing.T) {
cmd, err = ovndbapi.ACLDelEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.acl.Priority, iMapToSMap(tc.acl.ExternalID))
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err := ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
assert.False(t, containsACL(acls, &tc.acl))
})
}

type aclLogUpdateTest struct {
name string
entityType EntityType
entity string
acl ACL
newMeter string
passExpected bool
}

aclLogUpdateTests := []aclLogUpdateTest{
{"PG log update pass expected 1",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
"meter1",
true},
{"PG log update pass expected 2",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1002, true, []string{"meter1"}, "alert", map[interface{}]interface{}{"A": "a", "B": "b"}},
"meter2",
true},
{"PG log update pass expected 3",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH_SECOND, 1001, false, []string{""}, "", nil},
"meter2",
true},
{"LS log update pass expected 1",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
"meter1",
true},
{"LS log update pass expected 2",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1002, true, []string{"meter1"}, "alert", map[interface{}]interface{}{"A": "a", "B": "b"}},
"meter2",
true},
{"LS log update pass expected 3",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH_SECOND, 1001, false, []string{""}, "", nil},
"meter2",
true},
}

for _, tc := range aclLogUpdateTests {
tcName := "add " + tc.name
t.Run(tcName, func(t *testing.T) {
cmd, err = ovndbapi.ACLAddEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.acl.Action, tc.acl.Priority, iMapToSMap(tc.acl.ExternalID), tc.acl.Log, tc.acl.Meter[0], tc.acl.Severity)
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err := ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
assert.True(t, containsACL(acls, &tc.acl))

if len(tc.newMeter) > 0 {
tc.acl.Log = true
tc.acl.Meter[0] = tc.newMeter
tc.acl.Severity = "info"
} else {
tc.acl.Log = false
tc.acl.Meter[0] = ""
tc.acl.Severity = ""
}

cmd, err = ovndbapi.ACLSetLoggingEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.acl.Priority, tc.acl.Log, tc.acl.Meter[0], tc.acl.Severity)
if tc.passExpected {
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err = ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
tc.acl.Meter[0] = tc.newMeter
assert.True(t, containsACL(acls, &tc.acl))
} else {
assert.NotNil(t, err)
}
})
}

// Delete log update test ACLs
for _, tc := range aclLogUpdateTests {
tcName := "delete " + tc.name
t.Run(tcName, func(t *testing.T) {
cmd, err = ovndbapi.ACLDelEntity(tc.entityType, tc.entity, tc.acl.Direction, tc.acl.Match, tc.acl.Priority, iMapToSMap(tc.acl.ExternalID))
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
acls, err := ovndbapi.ACLListEntity(tc.entityType, tc.entity)
assert.Nil(t, err)
assert.False(t, containsACL(acls, &tc.acl))
})
}

t.Run("delete meter, switch, ports and port group used for ACL testing", func(t *testing.T) {
cmd, err = ovndbapi.MeterDel("meter1")
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)

cmds = make([]*OvnCommand, 0)
cmd, err := ovndbapi.LSDel(PG_TEST_LS1)
cmd, err = ovndbapi.MeterDel("meter2")
assert.Nil(t, err)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)

cmd, err = ovndbapi.LSDel(PG_TEST_LS1)
assert.Nil(t, err)
cmds = append(cmds, cmd)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)

cmd, err = ovndbapi.PortGroupDel(PG_TEST_PG1)
assert.Nil(t, err)
cmds = append(cmds, cmd)
err = ovndbapi.Execute(cmd)
assert.Nil(t, err)
})
Expand Down
14 changes: 14 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ type Client interface {
ACLAddEntity(entityType EntityType, entity, direct, match, action string, priority int, external_ids map[string]string, logflag bool, meter string, severity string) (*OvnCommand, error)
// Deprecated in favor of ACLAddEntity(). Add ACL to logical switch.
ACLAdd(ls, direct, match, action string, priority int, external_ids map[string]string, logflag bool, meter string, severity string) (*OvnCommand, error)
// Set (change) match criteria for ACL
ACLSetMatchEntity(entityType EntityType, entity, direct, oldMatch, newMatch string, priority int) (*OvnCommand, error)
// Set (change) logging for ACL
ACLSetLoggingEntity(entityType EntityType, entity, direct, match string, priority int, newLogflag bool, newMeter, newSeverity string) (*OvnCommand, error)
// Delete acl from entity (PORT_GROUP or LOGICAL_SWITCH)
ACLDelEntity(entityType EntityType, entity, direct, match string, priority int, external_ids map[string]string) (*OvnCommand, error)
// Deprecated in favor of ACLDelEntity(). Delete acl from logical switch
Expand Down Expand Up @@ -620,6 +624,16 @@ func (c *ovndb) ACLAdd(ls, direct, match, action string, priority int, external_
return c.aclAddImp(LOGICAL_SWITCH, ls, direct, match, action, priority, external_ids, logflag, meter, severity)
}

// Set (change) match criteria for ACL
func (c *ovndb) ACLSetMatchEntity(entityType EntityType, entity, direct, oldMatch, newMatch string, priority int) (*OvnCommand, error) {
return c.aclSetMatchEntityImp(entityType, entity, direct, oldMatch, newMatch, priority)
}

// Set (change) logging for ACL
func (c *ovndb) ACLSetLoggingEntity(entityType EntityType, entity, direct, match string, priority int, newLogflag bool, newMeter, newSeverity string) (*OvnCommand, error) {
return c.aCLSetLoggingEntityimp(entityType, entity, direct, match, priority, newLogflag, newMeter, newSeverity)
}

func (c *ovndb) ACLDelEntity(entityType EntityType, entity, direct, match string, priority int, external_ids map[string]string) (*OvnCommand, error) {
return c.aclDelImp(entityType, entity, direct, match, priority, external_ids)
}
Expand Down

0 comments on commit 143aac0

Please sign in to comment.