Skip to content

Commit

Permalink
Extend network route with access control groups (#2027)
Browse files Browse the repository at this point in the history
* extends route with access control groups

* add support for creating and updating routes with access control groups

* Add access control groups to routes API request and response

* fix tests

* fix tests
  • Loading branch information
bcmmbaga authored Jun 4, 2024
1 parent 69048bf commit ab78a62
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 127 deletions.
2 changes: 1 addition & 1 deletion management/server/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ type AccountManager interface {
DeletePolicy(accountID, policyID, userID string) error
ListPolicies(accountID, userID string) ([]*Policy, error)
GetRoute(accountID string, routeID route.ID, userID string) (*route.Route, error)
CreateRoute(accountID, prefix, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
CreateRoute(accountID, prefix, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, accessControlGroupIDs []string, enabled bool, userID string) (*route.Route, error)
SaveRoute(accountID, userID string, route *route.Route) error
DeleteRoute(accountID string, routeID route.ID, userID string) error
ListRoutes(accountID, userID string) ([]*route.Route, error)
Expand Down
7 changes: 4 additions & 3 deletions management/server/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1576,9 +1576,10 @@ func TestAccount_Copy(t *testing.T) {
},
Routes: map[route.ID]*route.Route{
"route1": {
ID: "route1",
PeerGroups: []string{},
Groups: []string{"group1"},
ID: "route1",
PeerGroups: []string{},
Groups: []string{"group1"},
AccessControlGroups: []string{},
},
},
NameServerGroups: map[string]*nbdns.NameServerGroup{
Expand Down
6 changes: 6 additions & 0 deletions management/server/http/api/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,12 @@ components:
items:
type: string
example: "chacdk86lnnboviihd70"
access_control_groups:
description: Access control group identifier associated with route.
type: array
items:
type: string
example: "chacbco6lnnbn6cg5s91"
required:
- id
- description
Expand Down
6 changes: 6 additions & 0 deletions management/server/http/api/types.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions management/server/http/routes_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,16 @@ func (h *RoutesHandler) CreateRoute(w http.ResponseWriter, r *http.Request) {
peerId = *req.Peer
}

peerGroupIds := []string{}
var peerGroupIds []string
if req.PeerGroups != nil {
peerGroupIds = *req.PeerGroups
}

var accessControlGroupIds []string
if req.AccessControlGroups != nil {
accessControlGroupIds = *req.AccessControlGroups
}

if (peerId != "" && len(peerGroupIds) > 0) || (peerId == "" && len(peerGroupIds) == 0) {
util.WriteError(status.Errorf(status.InvalidArgument, "only one peer or peer_groups should be provided"), w)
return
Expand All @@ -107,7 +112,7 @@ func (h *RoutesHandler) CreateRoute(w http.ResponseWriter, r *http.Request) {

newRoute, err := h.accountManager.CreateRoute(
account.Id, newPrefix.String(), peerId, peerGroupIds,
req.Description, route.NetID(req.NetworkId), req.Masquerade, req.Metric, req.Groups, req.Enabled, user.Id,
req.Description, route.NetID(req.NetworkId), req.Masquerade, req.Metric, req.Groups, accessControlGroupIds, req.Enabled, user.Id,
)
if err != nil {
util.WriteError(err, w)
Expand Down Expand Up @@ -204,6 +209,10 @@ func (h *RoutesHandler) UpdateRoute(w http.ResponseWriter, r *http.Request) {
newRoute.PeerGroups = *req.PeerGroups
}

if req.AccessControlGroups != nil {
newRoute.AccessControlGroups = *req.AccessControlGroups
}

err = h.accountManager.SaveRoute(account.Id, user.Id, newRoute)
if err != nil {
util.WriteError(err, w)
Expand Down Expand Up @@ -280,5 +289,8 @@ func toRouteResponse(serverRoute *route.Route) *api.Route {
if len(serverRoute.PeerGroups) > 0 {
route.PeerGroups = &serverRoute.PeerGroups
}
if len(serverRoute.AccessControlGroups) > 0 {
route.AccessControlGroups = &serverRoute.AccessControlGroups
}
return route
}
64 changes: 53 additions & 11 deletions management/server/http/routes_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func initRoutesTestData() *RoutesHandler {
}
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
},
CreateRouteFunc: func(accountID, network, peerID string, peerGroups []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, _ string) (*route.Route, error) {
CreateRouteFunc: func(accountID, network, peerID string, peerGroups []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, accessControlGroups []string, enabled bool, _ string) (*route.Route, error) {
if peerID == notFoundPeerID {
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
}
Expand All @@ -102,16 +102,17 @@ func initRoutesTestData() *RoutesHandler {
}
networkType, p, _ := route.ParseNetwork(network)
return &route.Route{
ID: existingRouteID,
NetID: netID,
Peer: peerID,
PeerGroups: peerGroups,
Network: p,
NetworkType: networkType,
Description: description,
Masquerade: masquerade,
Enabled: enabled,
Groups: groups,
ID: existingRouteID,
NetID: netID,
Peer: peerID,
PeerGroups: peerGroups,
Network: p,
NetworkType: networkType,
Description: description,
Masquerade: masquerade,
Enabled: enabled,
Groups: groups,
AccessControlGroups: accessControlGroups,
}, nil
},
SaveRouteFunc: func(_, _ string, r *route.Route) error {
Expand Down Expand Up @@ -210,6 +211,27 @@ func TestRoutesHandlers(t *testing.T) {
Groups: []string{existingGroupID},
},
},
{
name: "POST OK With Access Control Groups",
requestType: http.MethodPost,
requestPath: "/api/routes",
requestBody: bytes.NewBuffer(
[]byte(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"],\"access_control_groups\":[\"%s\"]}", existingPeerID, existingGroupID, existingGroupID))),
expectedStatus: http.StatusOK,
expectedBody: true,
expectedRoute: &api.Route{
Id: existingRouteID,
Description: "Post",
NetworkId: "awesomeNet",
Network: "192.168.0.0/16",
Peer: &existingPeerID,
NetworkType: route.IPv4NetworkString,
Masquerade: false,
Enabled: false,
Groups: []string{existingGroupID},
AccessControlGroups: &[]string{existingGroupID},
},
},
{
name: "POST Non Linux Peer",
requestType: http.MethodPost,
Expand Down Expand Up @@ -279,6 +301,26 @@ func TestRoutesHandlers(t *testing.T) {
Groups: []string{existingGroupID},
},
},
{
name: "PUT OK With Access Control Groups",
requestType: http.MethodPut,
requestPath: "/api/routes/" + existingRouteID,
requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"],\"access_control_groups\":[\"%s\"]}}", existingPeerID, existingGroupID, existingGroupID)),
expectedStatus: http.StatusOK,
expectedBody: true,
expectedRoute: &api.Route{
Id: existingRouteID,
Description: "Post",
NetworkId: "awesomeNet",
Network: "192.168.0.0/16",
Peer: &existingPeerID,
NetworkType: route.IPv4NetworkString,
Masquerade: false,
Enabled: false,
Groups: []string{existingGroupID},
AccessControlGroups: &[]string{existingGroupID},
},
},
{
name: "PUT OK when peer_groups provided",
requestType: http.MethodPut,
Expand Down
6 changes: 3 additions & 3 deletions management/server/mock_server/account_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type MockAccountManager struct {
UpdatePeerMetaFunc func(peerID string, meta nbpeer.PeerSystemMeta) error
UpdatePeerSSHKeyFunc func(peerID string, sshKey string) error
UpdatePeerFunc func(accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error)
CreateRouteFunc func(accountID, prefix, peer string, peerGroups []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
CreateRouteFunc func(accountID, prefix, peer string, peerGroups []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, accessControlGroups []string, enabled bool, userID string) (*route.Route, error)
GetRouteFunc func(accountID string, routeID route.ID, userID string) (*route.Route, error)
SaveRouteFunc func(accountID string, userID string, route *route.Route) error
DeleteRouteFunc func(accountID string, routeID route.ID, userID string) error
Expand Down Expand Up @@ -412,9 +412,9 @@ func (am *MockAccountManager) UpdatePeer(accountID, userID string, peer *nbpeer.
}

// CreateRoute mock implementation of CreateRoute from server.AccountManager interface
func (am *MockAccountManager) CreateRoute(accountID, prefix, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
func (am *MockAccountManager) CreateRoute(accountID, prefix, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, accessControlGroups []string, enabled bool, userID string) (*route.Route, error) {
if am.CreateRouteFunc != nil {
return am.CreateRouteFunc(accountID, prefix, peerID, peerGroupIDs, description, netID, masquerade, metric, groups, enabled, userID)
return am.CreateRouteFunc(accountID, prefix, peerID, peerGroupIDs, description, netID, masquerade, metric, groups, accessControlGroups, enabled, userID)
}
return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented")
}
Expand Down
17 changes: 16 additions & 1 deletion management/server/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (am *DefaultAccountManager) checkRoutePrefixExistsForPeers(account *Account
}

// CreateRoute creates and saves a new route
func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, accessControlGroupIDs []string, enabled bool, userID string) (*route.Route, error) {
unlock := am.Store.AcquireAccountWriteLock(accountID)
defer unlock()

Expand Down Expand Up @@ -145,6 +145,13 @@ func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string,
}
}

if len(accessControlGroupIDs) > 0 {
err = validateGroups(accessControlGroupIDs, account.Groups)
if err != nil {
return nil, err
}
}

err = am.checkRoutePrefixExistsForPeers(account, peerID, newRoute.ID, peerGroupIDs, newPrefix)
if err != nil {
return nil, err
Expand Down Expand Up @@ -173,6 +180,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string,
newRoute.Metric = metric
newRoute.Enabled = enabled
newRoute.Groups = groups
newRoute.AccessControlGroups = accessControlGroupIDs

if account.Routes == nil {
account.Routes = make(map[route.ID]*route.Route)
Expand Down Expand Up @@ -229,6 +237,13 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave
}
}

if len(routeToSave.AccessControlGroups) > 0 {
err = validateGroups(routeToSave.AccessControlGroups, account.Groups)
if err != nil {
return err
}
}

err = am.checkRoutePrefixExistsForPeers(account, routeToSave.Peer, routeToSave.ID, routeToSave.Copy().PeerGroups, routeToSave.Network)
if err != nil {
return err
Expand Down
Loading

0 comments on commit ab78a62

Please sign in to comment.