Skip to content

Commit

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

Addresses Issue eBay#138

Signed-off-by: Andre Fredette <[email protected]>
  • Loading branch information
anfredette committed Mar 16, 2021
1 parent f6ee8f3 commit 49374a1
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 Pass Expected 1",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
true},
{"PG 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 Fail Expected",
PORT_GROUP,
PG_TEST_PG1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
false},
{"LS Pass Expected 1",
LOGICAL_SWITCH,
PG_TEST_LS1,
ACL{"", "drop", "from-lport", MATCH, 1001, false, []string{""}, "", nil},
MATCH_SECOND,
true},
{"LS 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 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 49374a1

Please sign in to comment.