mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-25 09:33:24 +01:00
Add peer groups support for network routes (#1150)
This commit enhances the functionality of the network routes endpoint by introducing a new parameter called `peers_group`. This addition allows users to associate network routes with specific peer groups, simplifying the management and distribution of routes within a network.
This commit is contained in:
parent
1956ca169e
commit
8118d60ffb
@ -83,14 +83,14 @@ type AccountManager interface {
|
|||||||
DeleteGroup(accountId, userId, groupID string) error
|
DeleteGroup(accountId, userId, groupID string) error
|
||||||
ListGroups(accountId string) ([]*Group, error)
|
ListGroups(accountId string) ([]*Group, error)
|
||||||
GroupAddPeer(accountId, groupID, peerID string) error
|
GroupAddPeer(accountId, groupID, peerID string) error
|
||||||
GroupDeletePeer(accountId, groupID, peerKey string) error
|
GroupDeletePeer(accountId, groupID, peerID string) error
|
||||||
GroupListPeers(accountId, groupID string) ([]*Peer, error)
|
GroupListPeers(accountId, groupID string) ([]*Peer, error)
|
||||||
GetPolicy(accountID, policyID, userID string) (*Policy, error)
|
GetPolicy(accountID, policyID, userID string) (*Policy, error)
|
||||||
SavePolicy(accountID, userID string, policy *Policy) error
|
SavePolicy(accountID, userID string, policy *Policy) error
|
||||||
DeletePolicy(accountID, policyID, userID string) error
|
DeletePolicy(accountID, policyID, userID string) error
|
||||||
ListPolicies(accountID, userID string) ([]*Policy, error)
|
ListPolicies(accountID, userID string) ([]*Policy, error)
|
||||||
GetRoute(accountID, routeID, userID string) (*route.Route, error)
|
GetRoute(accountID, routeID, userID string) (*route.Route, error)
|
||||||
CreateRoute(accountID string, prefix, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
|
CreateRoute(accountID, prefix, peerID string, peerGroupIDs []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
|
||||||
SaveRoute(accountID, userID string, route *route.Route) error
|
SaveRoute(accountID, userID string, route *route.Route) error
|
||||||
DeleteRoute(accountID, routeID, userID string) error
|
DeleteRoute(accountID, routeID, userID string) error
|
||||||
ListRoutes(accountID, userID string) ([]*route.Route, error)
|
ListRoutes(accountID, userID string) ([]*route.Route, error)
|
||||||
@ -253,22 +253,39 @@ func (a *Account) filterRoutesByGroups(routes []*route.Route, groupListMap looku
|
|||||||
func (a *Account) getEnabledAndDisabledRoutesByPeer(peerID string) ([]*route.Route, []*route.Route) {
|
func (a *Account) getEnabledAndDisabledRoutesByPeer(peerID string) ([]*route.Route, []*route.Route) {
|
||||||
var enabledRoutes []*route.Route
|
var enabledRoutes []*route.Route
|
||||||
var disabledRoutes []*route.Route
|
var disabledRoutes []*route.Route
|
||||||
|
|
||||||
|
takeRoute := func(r *route.Route, id string) {
|
||||||
|
peer := a.GetPeer(peerID)
|
||||||
|
if peer == nil {
|
||||||
|
log.Errorf("route %s has peer %s that doesn't exist under account %s", r.ID, peerID, a.Id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Enabled {
|
||||||
|
enabledRoutes = append(enabledRoutes, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
disabledRoutes = append(disabledRoutes, r)
|
||||||
|
}
|
||||||
|
|
||||||
for _, r := range a.Routes {
|
for _, r := range a.Routes {
|
||||||
|
if len(r.PeerGroups) != 0 {
|
||||||
|
for _, groupID := range r.PeerGroups {
|
||||||
|
group := a.GetGroup(groupID)
|
||||||
|
if group == nil {
|
||||||
|
log.Errorf("route %s has peers group %s that doesn't exist under account %s", r.ID, groupID, a.Id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, id := range group.Peers {
|
||||||
|
if id == peerID {
|
||||||
|
takeRoute(r, id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if r.Peer == peerID {
|
if r.Peer == peerID {
|
||||||
// We need to set Peer.Key instead of Peer.ID because this object will be sent to agents as part of a network map.
|
takeRoute(r, peerID)
|
||||||
// Ideally we should have a separate field for that, but fine for now.
|
|
||||||
peer := a.GetPeer(peerID)
|
|
||||||
if peer == nil {
|
|
||||||
log.Errorf("route %s has peer %s that doesn't exist under account %s", r.ID, peerID, a.Id)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
raut := r.Copy()
|
|
||||||
raut.Peer = peer.Key
|
|
||||||
if r.Enabled {
|
|
||||||
enabledRoutes = append(enabledRoutes, raut)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
disabledRoutes = append(disabledRoutes, raut)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return enabledRoutes, disabledRoutes
|
return enabledRoutes, disabledRoutes
|
||||||
@ -316,8 +333,51 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap {
|
|||||||
}
|
}
|
||||||
peersToConnect = append(peersToConnect, p)
|
peersToConnect = append(peersToConnect, p)
|
||||||
}
|
}
|
||||||
// Please mind, that the returned route.Route objects will contain Peer.Key instead of Peer.ID.
|
|
||||||
routesUpdate := a.getRoutesToSync(peerID, peersToConnect)
|
routes := a.getRoutesToSync(peerID, peersToConnect)
|
||||||
|
|
||||||
|
takePeer := func(id string) (*Peer, bool) {
|
||||||
|
peer := a.GetPeer(id)
|
||||||
|
if peer == nil || peer.Meta.GoOS != "linux" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return peer, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to set Peer.Key instead of Peer.ID because this object will be sent to agents as part of a network map.
|
||||||
|
// Ideally we should have a separate field for that, but fine for now.
|
||||||
|
var routesUpdate []*route.Route
|
||||||
|
seenPeers := make(map[string]bool)
|
||||||
|
for _, r := range routes {
|
||||||
|
if r.Peer != "" {
|
||||||
|
peer, valid := takePeer(r.Peer)
|
||||||
|
if !valid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rCopy := r.Copy()
|
||||||
|
rCopy.Peer = peer.Key // client expects the key
|
||||||
|
routesUpdate = append(routesUpdate, rCopy)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, groupID := range r.PeerGroups {
|
||||||
|
if group := a.GetGroup(groupID); group != nil {
|
||||||
|
for _, peerId := range group.Peers {
|
||||||
|
peer, valid := takePeer(peerId)
|
||||||
|
if !valid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := seenPeers[peer.ID]; !ok {
|
||||||
|
rCopy := r.Copy()
|
||||||
|
rCopy.ID = r.ID + ":" + peer.ID // we have to provide unit route id when distribute network map
|
||||||
|
rCopy.Peer = peer.Key // client expects the key
|
||||||
|
routesUpdate = append(routesUpdate, rCopy)
|
||||||
|
}
|
||||||
|
seenPeers[peer.ID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dnsManagementStatus := a.getPeerDNSManagementStatus(peerID)
|
dnsManagementStatus := a.getPeerDNSManagementStatus(peerID)
|
||||||
dnsUpdate := nbdns.Config{
|
dnsUpdate := nbdns.Config{
|
||||||
|
@ -1385,8 +1385,9 @@ func TestAccount_Copy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Routes: map[string]*route.Route{
|
Routes: map[string]*route.Route{
|
||||||
"route1": {
|
"route1": {
|
||||||
ID: "route1",
|
ID: "route1",
|
||||||
Groups: []string{"group1"},
|
PeerGroups: []string{},
|
||||||
|
Groups: []string{"group1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NameServerGroups: map[string]*nbdns.NameServerGroup{
|
NameServerGroups: map[string]*nbdns.NameServerGroup{
|
||||||
|
@ -285,7 +285,7 @@ func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerID string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GroupDeletePeer removes peer from the group
|
// GroupDeletePeer removes peer from the group
|
||||||
func (am *DefaultAccountManager) GroupDeletePeer(accountID, groupID, peerKey string) error {
|
func (am *DefaultAccountManager) GroupDeletePeer(accountID, groupID, peerID string) error {
|
||||||
unlock := am.Store.AcquireAccountLock(accountID)
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ func (am *DefaultAccountManager) GroupDeletePeer(accountID, groupID, peerKey str
|
|||||||
|
|
||||||
account.Network.IncSerial()
|
account.Network.IncSerial()
|
||||||
for i, itemID := range group.Peers {
|
for i, itemID := range group.Peers {
|
||||||
if itemID == peerKey {
|
if itemID == peerID {
|
||||||
group.Peers = append(group.Peers[:i], group.Peers[i+1:]...)
|
group.Peers = append(group.Peers[:i], group.Peers[i+1:]...)
|
||||||
if err := am.Store.SaveAccount(account); err != nil {
|
if err := am.Store.SaveAccount(account); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -745,9 +745,15 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
example: true
|
example: true
|
||||||
peer:
|
peer:
|
||||||
description: Peer Identifier associated with route
|
description: Peer Identifier associated with route. This property can not be set together with `peer_groups`
|
||||||
type: string
|
type: string
|
||||||
example: chacbco6lnnbn6cg5s91
|
example: chacbco6lnnbn6cg5s91
|
||||||
|
peer_groups:
|
||||||
|
description: Peers Group Identifier associated with route. This property can not be set together with `peer`
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example: chacbco6lnnbn6cg5s91
|
||||||
network:
|
network:
|
||||||
description: Network range in CIDR format
|
description: Network range in CIDR format
|
||||||
type: string
|
type: string
|
||||||
@ -773,7 +779,9 @@ components:
|
|||||||
- description
|
- description
|
||||||
- network_id
|
- network_id
|
||||||
- enabled
|
- enabled
|
||||||
- peer
|
# Only one property has to be set
|
||||||
|
#- peer
|
||||||
|
#- peer_groups
|
||||||
- network
|
- network
|
||||||
- metric
|
- metric
|
||||||
- masquerade
|
- masquerade
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Package api provides primitives to interact with the openapi HTTP API.
|
// Package api provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen version v1.11.1-0.20220912230023-4a1477f6a8ba DO NOT EDIT.
|
// Code generated by github.com/deepmap/oapi-codegen version v1.15.0 DO NOT EDIT.
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -599,8 +599,11 @@ type Route struct {
|
|||||||
// NetworkType Network type indicating if it is IPv4 or IPv6
|
// NetworkType Network type indicating if it is IPv4 or IPv6
|
||||||
NetworkType string `json:"network_type"`
|
NetworkType string `json:"network_type"`
|
||||||
|
|
||||||
// Peer Peer Identifier associated with route
|
// Peer Peer Identifier associated with route. This property can not be set together with `peer_groups`
|
||||||
Peer string `json:"peer"`
|
Peer *string `json:"peer,omitempty"`
|
||||||
|
|
||||||
|
// PeerGroups Peers Group Identifier associated with route. This property can not be set together with `peer`
|
||||||
|
PeerGroups *[]string `json:"peer_groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteRequest defines model for RouteRequest.
|
// RouteRequest defines model for RouteRequest.
|
||||||
@ -626,8 +629,11 @@ type RouteRequest struct {
|
|||||||
// NetworkId Route network identifier, to group HA routes
|
// NetworkId Route network identifier, to group HA routes
|
||||||
NetworkId string `json:"network_id"`
|
NetworkId string `json:"network_id"`
|
||||||
|
|
||||||
// Peer Peer Identifier associated with route
|
// Peer Peer Identifier associated with route. This property can not be set together with `peer_groups`
|
||||||
Peer string `json:"peer"`
|
Peer *string `json:"peer,omitempty"`
|
||||||
|
|
||||||
|
// PeerGroups Peers Group Identifier associated with route. This property can not be set together with `peer`
|
||||||
|
PeerGroups *[]string `json:"peer_groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule defines model for Rule.
|
// Rule defines model for Rule.
|
||||||
|
@ -82,7 +82,33 @@ func (h *RoutesHandler) CreateRoute(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newRoute, err := h.accountManager.CreateRoute(account.Id, newPrefix.String(), req.Peer, req.Description, req.NetworkId, req.Masquerade, req.Metric, req.Groups, req.Enabled, user.Id)
|
peerId := ""
|
||||||
|
if req.Peer != nil {
|
||||||
|
peerId = *req.Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
peerGroupIds := []string{}
|
||||||
|
if req.PeerGroups != nil {
|
||||||
|
peerGroupIds = *req.PeerGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not allow non Linux peers
|
||||||
|
if peer := account.GetPeer(peerId); peer != nil {
|
||||||
|
if peer.Meta.GoOS != "linux" {
|
||||||
|
util.WriteError(status.Errorf(status.InvalidArgument, "non-linux peers are non supported as network routes"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoute, err := h.accountManager.CreateRoute(
|
||||||
|
account.Id, newPrefix.String(), peerId, peerGroupIds,
|
||||||
|
req.Description, req.NetworkId, req.Masquerade, req.Metric, req.Groups, req.Enabled, user.Id,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(err, w)
|
util.WriteError(err, w)
|
||||||
return
|
return
|
||||||
@ -135,19 +161,49 @@ func (h *RoutesHandler) UpdateRoute(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Peer != nil && req.PeerGroups != nil {
|
||||||
|
util.WriteError(status.Errorf(status.InvalidArgument, "only peer or peers_group should be provided"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Peer == nil && req.PeerGroups == nil {
|
||||||
|
util.WriteError(status.Errorf(status.InvalidArgument, "either peer or peers_group should be provided"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peerID := ""
|
||||||
|
if req.Peer != nil {
|
||||||
|
peerID = *req.Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not allow non Linux peers
|
||||||
|
if peer := account.GetPeer(peerID); peer != nil {
|
||||||
|
if peer.Meta.GoOS != "linux" {
|
||||||
|
util.WriteError(status.Errorf(status.InvalidArgument, "non-linux peers are non supported as network routes"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newRoute := &route.Route{
|
newRoute := &route.Route{
|
||||||
ID: routeID,
|
ID: routeID,
|
||||||
Network: newPrefix,
|
Network: newPrefix,
|
||||||
NetID: req.NetworkId,
|
NetID: req.NetworkId,
|
||||||
NetworkType: prefixType,
|
NetworkType: prefixType,
|
||||||
Masquerade: req.Masquerade,
|
Masquerade: req.Masquerade,
|
||||||
Peer: req.Peer,
|
|
||||||
Metric: req.Metric,
|
Metric: req.Metric,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Enabled: req.Enabled,
|
Enabled: req.Enabled,
|
||||||
Groups: req.Groups,
|
Groups: req.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Peer != nil {
|
||||||
|
newRoute.Peer = peerID
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.PeerGroups != nil {
|
||||||
|
newRoute.PeerGroups = *req.PeerGroups
|
||||||
|
}
|
||||||
|
|
||||||
err = h.accountManager.SaveRoute(account.Id, user.Id, newRoute)
|
err = h.accountManager.SaveRoute(account.Id, user.Id, newRoute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(err, w)
|
util.WriteError(err, w)
|
||||||
@ -208,16 +264,21 @@ func (h *RoutesHandler) GetRoute(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toRouteResponse(serverRoute *route.Route) *api.Route {
|
func toRouteResponse(serverRoute *route.Route) *api.Route {
|
||||||
return &api.Route{
|
route := &api.Route{
|
||||||
Id: serverRoute.ID,
|
Id: serverRoute.ID,
|
||||||
Description: serverRoute.Description,
|
Description: serverRoute.Description,
|
||||||
NetworkId: serverRoute.NetID,
|
NetworkId: serverRoute.NetID,
|
||||||
Enabled: serverRoute.Enabled,
|
Enabled: serverRoute.Enabled,
|
||||||
Peer: serverRoute.Peer,
|
Peer: &serverRoute.Peer,
|
||||||
Network: serverRoute.Network.String(),
|
Network: serverRoute.Network.String(),
|
||||||
NetworkType: serverRoute.NetworkType.String(),
|
NetworkType: serverRoute.NetworkType.String(),
|
||||||
Masquerade: serverRoute.Masquerade,
|
Masquerade: serverRoute.Masquerade,
|
||||||
Metric: serverRoute.Metric,
|
Metric: serverRoute.Metric,
|
||||||
Groups: serverRoute.Groups,
|
Groups: serverRoute.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(serverRoute.PeerGroups) > 0 {
|
||||||
|
route.PeerGroups = &serverRoute.PeerGroups
|
||||||
|
}
|
||||||
|
return route
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
existingRouteID = "existingRouteID"
|
existingRouteID = "existingRouteID"
|
||||||
notFoundRouteID = "notFoundRouteID"
|
existingRouteID2 = "existingRouteID2" // for peer_groups test
|
||||||
existingPeerIP = "100.64.0.100"
|
notFoundRouteID = "notFoundRouteID"
|
||||||
existingPeerID = "peer-id"
|
existingPeerIP1 = "100.64.0.100"
|
||||||
notFoundPeerID = "nonExistingPeer"
|
existingPeerIP2 = "100.64.0.101"
|
||||||
existingPeerKey = "existingPeerKey"
|
notFoundPeerID = "nonExistingPeer"
|
||||||
testAccountID = "test_id"
|
existingPeerKey = "existingPeerKey"
|
||||||
existingGroupID = "testGroup"
|
nonLinuxExistingPeerKey = "darwinExistingPeerKey"
|
||||||
|
testAccountID = "test_id"
|
||||||
|
existingGroupID = "testGroup"
|
||||||
|
notFoundGroupID = "nonExistingGroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var emptyString = ""
|
||||||
|
var existingPeerID = "peer-id"
|
||||||
|
var nonLinuxExistingPeerID = "darwin-peer-id"
|
||||||
|
|
||||||
var baseExistingRoute = &route.Route{
|
var baseExistingRoute = &route.Route{
|
||||||
ID: existingRouteID,
|
ID: existingRouteID,
|
||||||
Description: "base route",
|
Description: "base route",
|
||||||
@ -51,8 +58,19 @@ var testingAccount = &server.Account{
|
|||||||
Peers: map[string]*server.Peer{
|
Peers: map[string]*server.Peer{
|
||||||
existingPeerID: {
|
existingPeerID: {
|
||||||
Key: existingPeerKey,
|
Key: existingPeerKey,
|
||||||
IP: netip.MustParseAddr(existingPeerIP).AsSlice(),
|
IP: netip.MustParseAddr(existingPeerIP1).AsSlice(),
|
||||||
ID: existingPeerID,
|
ID: existingPeerID,
|
||||||
|
Meta: server.PeerSystemMeta{
|
||||||
|
GoOS: "linux",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nonLinuxExistingPeerID: {
|
||||||
|
Key: nonLinuxExistingPeerID,
|
||||||
|
IP: netip.MustParseAddr(existingPeerIP2).AsSlice(),
|
||||||
|
ID: nonLinuxExistingPeerID,
|
||||||
|
Meta: server.PeerSystemMeta{
|
||||||
|
GoOS: "darwin",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Users: map[string]*server.User{
|
Users: map[string]*server.User{
|
||||||
@ -67,17 +85,26 @@ func initRoutesTestData() *RoutesHandler {
|
|||||||
if routeID == existingRouteID {
|
if routeID == existingRouteID {
|
||||||
return baseExistingRoute, nil
|
return baseExistingRoute, nil
|
||||||
}
|
}
|
||||||
|
if routeID == existingRouteID2 {
|
||||||
|
route := baseExistingRoute.Copy()
|
||||||
|
route.PeerGroups = []string{existingGroupID}
|
||||||
|
return route, nil
|
||||||
|
}
|
||||||
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
|
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
|
||||||
},
|
},
|
||||||
CreateRouteFunc: func(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, _ string) (*route.Route, error) {
|
CreateRouteFunc: func(accountID, network, peerID string, peerGroups []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, _ string) (*route.Route, error) {
|
||||||
if peerID == notFoundPeerID {
|
if peerID == notFoundPeerID {
|
||||||
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||||
}
|
}
|
||||||
|
if len(peerGroups) > 0 && peerGroups[0] == notFoundGroupID {
|
||||||
|
return nil, status.Errorf(status.InvalidArgument, "peer groups with ID %s not found", peerGroups[0])
|
||||||
|
}
|
||||||
networkType, p, _ := route.ParseNetwork(network)
|
networkType, p, _ := route.ParseNetwork(network)
|
||||||
return &route.Route{
|
return &route.Route{
|
||||||
ID: existingRouteID,
|
ID: existingRouteID,
|
||||||
NetID: netID,
|
NetID: netID,
|
||||||
Peer: peerID,
|
Peer: peerID,
|
||||||
|
PeerGroups: peerGroups,
|
||||||
Network: p,
|
Network: p,
|
||||||
NetworkType: networkType,
|
NetworkType: networkType,
|
||||||
Description: description,
|
Description: description,
|
||||||
@ -124,6 +151,9 @@ func initRoutesTestData() *RoutesHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRoutesHandlers(t *testing.T) {
|
func TestRoutesHandlers(t *testing.T) {
|
||||||
|
baseExistingRouteWithPeerGroups := baseExistingRoute.Copy()
|
||||||
|
baseExistingRouteWithPeerGroups.PeerGroups = []string{existingGroupID}
|
||||||
|
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
name string
|
name string
|
||||||
expectedStatus int
|
expectedStatus int
|
||||||
@ -147,6 +177,14 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
requestPath: "/api/routes/" + notFoundRouteID,
|
requestPath: "/api/routes/" + notFoundRouteID,
|
||||||
expectedStatus: http.StatusNotFound,
|
expectedStatus: http.StatusNotFound,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Get Existing Route with Peer Groups",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/routes/" + existingRouteID2,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedBody: true,
|
||||||
|
expectedRoute: toRouteResponse(baseExistingRouteWithPeerGroups),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Delete Existing Route",
|
name: "Delete Existing Route",
|
||||||
requestType: http.MethodDelete,
|
requestType: http.MethodDelete,
|
||||||
@ -173,13 +211,21 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
Description: "Post",
|
Description: "Post",
|
||||||
NetworkId: "awesomeNet",
|
NetworkId: "awesomeNet",
|
||||||
Network: "192.168.0.0/16",
|
Network: "192.168.0.0/16",
|
||||||
Peer: existingPeerID,
|
Peer: &existingPeerID,
|
||||||
NetworkType: route.IPv4NetworkString,
|
NetworkType: route.IPv4NetworkString,
|
||||||
Masquerade: false,
|
Masquerade: false,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Groups: []string{existingGroupID},
|
Groups: []string{existingGroupID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "POST Non Linux Peer",
|
||||||
|
requestType: http.MethodPost,
|
||||||
|
requestPath: "/api/routes",
|
||||||
|
requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"]}", nonLinuxExistingPeerID, existingGroupID)),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "POST Not Found Peer",
|
name: "POST Not Found Peer",
|
||||||
requestType: http.MethodPost,
|
requestType: http.MethodPost,
|
||||||
@ -204,6 +250,24 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
expectedStatus: http.StatusUnprocessableEntity,
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
expectedBody: false,
|
expectedBody: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "POST UnprocessableEntity when both peer and peer_groups are provided",
|
||||||
|
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\",\"peer_groups\":[\"%s\"],\"groups\":[\"%s\"]}", existingPeerID, existingGroupID, existingGroupID))),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "POST UnprocessableEntity when no peer and peer_groups are provided",
|
||||||
|
requestType: http.MethodPost,
|
||||||
|
requestPath: "/api/routes",
|
||||||
|
requestBody: bytes.NewBuffer(
|
||||||
|
[]byte(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"groups\":[\"%s\"]}", existingPeerID))),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "PUT OK",
|
name: "PUT OK",
|
||||||
requestType: http.MethodPut,
|
requestType: http.MethodPut,
|
||||||
@ -216,7 +280,27 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
Description: "Post",
|
Description: "Post",
|
||||||
NetworkId: "awesomeNet",
|
NetworkId: "awesomeNet",
|
||||||
Network: "192.168.0.0/16",
|
Network: "192.168.0.0/16",
|
||||||
Peer: existingPeerID,
|
Peer: &existingPeerID,
|
||||||
|
NetworkType: route.IPv4NetworkString,
|
||||||
|
Masquerade: false,
|
||||||
|
Enabled: false,
|
||||||
|
Groups: []string{existingGroupID},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PUT OK when peer_groups provided",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/routes/" + existingRouteID,
|
||||||
|
requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"peer_groups\":[\"%s\"],\"groups\":[\"%s\"]}", existingGroupID, existingGroupID)),
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedBody: true,
|
||||||
|
expectedRoute: &api.Route{
|
||||||
|
Id: existingRouteID,
|
||||||
|
Description: "Post",
|
||||||
|
NetworkId: "awesomeNet",
|
||||||
|
Network: "192.168.0.0/16",
|
||||||
|
Peer: &emptyString,
|
||||||
|
PeerGroups: &[]string{existingGroupID},
|
||||||
NetworkType: route.IPv4NetworkString,
|
NetworkType: route.IPv4NetworkString,
|
||||||
Masquerade: false,
|
Masquerade: false,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
@ -239,6 +323,14 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
expectedStatus: http.StatusUnprocessableEntity,
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
expectedBody: false,
|
expectedBody: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "PUT Non Linux Peer",
|
||||||
|
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\"]}", nonLinuxExistingPeerID, existingGroupID)),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "PUT Invalid Network Identifier",
|
name: "PUT Invalid Network Identifier",
|
||||||
requestType: http.MethodPut,
|
requestType: http.MethodPut,
|
||||||
@ -255,6 +347,24 @@ func TestRoutesHandlers(t *testing.T) {
|
|||||||
expectedStatus: http.StatusUnprocessableEntity,
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
expectedBody: false,
|
expectedBody: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "PUT UnprocessableEntity when both peer and peer_groups are provided",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/routes/" + existingRouteID,
|
||||||
|
requestBody: bytes.NewBuffer(
|
||||||
|
[]byte(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"peer\":\"%s\",\"peer_groups\":[\"%s\"],\"groups\":[\"%s\"]}", existingPeerID, existingGroupID, existingGroupID))),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PUT UnprocessableEntity when no peer and peer_groups are provided",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/routes/" + existingRouteID,
|
||||||
|
requestBody: bytes.NewBuffer(
|
||||||
|
[]byte(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"groups\":[\"%s\"]}", existingPeerID))),
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
expectedBody: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
p := initRoutesTestData()
|
p := initRoutesTestData()
|
||||||
|
@ -33,8 +33,8 @@ type MockAccountManager struct {
|
|||||||
SaveGroupFunc func(accountID, userID string, group *server.Group) error
|
SaveGroupFunc func(accountID, userID string, group *server.Group) error
|
||||||
DeleteGroupFunc func(accountID, userId, groupID string) error
|
DeleteGroupFunc func(accountID, userId, groupID string) error
|
||||||
ListGroupsFunc func(accountID string) ([]*server.Group, error)
|
ListGroupsFunc func(accountID string) ([]*server.Group, error)
|
||||||
GroupAddPeerFunc func(accountID, groupID, peerKey string) error
|
GroupAddPeerFunc func(accountID, groupID, peerID string) error
|
||||||
GroupDeletePeerFunc func(accountID, groupID, peerKey string) error
|
GroupDeletePeerFunc func(accountID, groupID, peerID string) error
|
||||||
GroupListPeersFunc func(accountID, groupID string) ([]*server.Peer, error)
|
GroupListPeersFunc func(accountID, groupID string) ([]*server.Peer, error)
|
||||||
GetRuleFunc func(accountID, ruleID, userID string) (*server.Rule, error)
|
GetRuleFunc func(accountID, ruleID, userID string) (*server.Rule, error)
|
||||||
SaveRuleFunc func(accountID, userID string, rule *server.Rule) error
|
SaveRuleFunc func(accountID, userID string, rule *server.Rule) error
|
||||||
@ -50,7 +50,7 @@ type MockAccountManager struct {
|
|||||||
UpdatePeerMetaFunc func(peerID string, meta server.PeerSystemMeta) error
|
UpdatePeerMetaFunc func(peerID string, meta server.PeerSystemMeta) error
|
||||||
UpdatePeerSSHKeyFunc func(peerID string, sshKey string) error
|
UpdatePeerSSHKeyFunc func(peerID string, sshKey string) error
|
||||||
UpdatePeerFunc func(accountID, userID string, peer *server.Peer) (*server.Peer, error)
|
UpdatePeerFunc func(accountID, userID string, peer *server.Peer) (*server.Peer, error)
|
||||||
CreateRouteFunc func(accountID string, prefix, peer, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
|
CreateRouteFunc func(accountID, prefix, peer string, peerGroups []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
|
||||||
GetRouteFunc func(accountID, routeID, userID string) (*route.Route, error)
|
GetRouteFunc func(accountID, routeID, userID string) (*route.Route, error)
|
||||||
SaveRouteFunc func(accountID, userID string, route *route.Route) error
|
SaveRouteFunc func(accountID, userID string, route *route.Route) error
|
||||||
DeleteRouteFunc func(accountID, routeID, userID string) error
|
DeleteRouteFunc func(accountID, routeID, userID string) error
|
||||||
@ -281,17 +281,17 @@ func (am *MockAccountManager) ListGroups(accountID string) ([]*server.Group, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GroupAddPeer mock implementation of GroupAddPeer from server.AccountManager interface
|
// GroupAddPeer mock implementation of GroupAddPeer from server.AccountManager interface
|
||||||
func (am *MockAccountManager) GroupAddPeer(accountID, groupID, peerKey string) error {
|
func (am *MockAccountManager) GroupAddPeer(accountID, groupID, peerID string) error {
|
||||||
if am.GroupAddPeerFunc != nil {
|
if am.GroupAddPeerFunc != nil {
|
||||||
return am.GroupAddPeerFunc(accountID, groupID, peerKey)
|
return am.GroupAddPeerFunc(accountID, groupID, peerID)
|
||||||
}
|
}
|
||||||
return status.Errorf(codes.Unimplemented, "method GroupAddPeer is not implemented")
|
return status.Errorf(codes.Unimplemented, "method GroupAddPeer is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupDeletePeer mock implementation of GroupDeletePeer from server.AccountManager interface
|
// GroupDeletePeer mock implementation of GroupDeletePeer from server.AccountManager interface
|
||||||
func (am *MockAccountManager) GroupDeletePeer(accountID, groupID, peerKey string) error {
|
func (am *MockAccountManager) GroupDeletePeer(accountID, groupID, peerID string) error {
|
||||||
if am.GroupDeletePeerFunc != nil {
|
if am.GroupDeletePeerFunc != nil {
|
||||||
return am.GroupDeletePeerFunc(accountID, groupID, peerKey)
|
return am.GroupDeletePeerFunc(accountID, groupID, peerID)
|
||||||
}
|
}
|
||||||
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer is not implemented")
|
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer is not implemented")
|
||||||
}
|
}
|
||||||
@ -401,9 +401,9 @@ func (am *MockAccountManager) UpdatePeer(accountID, userID string, peer *server.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateRoute mock implementation of CreateRoute from server.AccountManager interface
|
// CreateRoute mock implementation of CreateRoute from server.AccountManager interface
|
||||||
func (am *MockAccountManager) CreateRoute(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
func (am *MockAccountManager) CreateRoute(accountID, network, peerID string, peerGroups []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
||||||
if am.CreateRouteFunc != nil {
|
if am.CreateRouteFunc != nil {
|
||||||
return am.CreateRouteFunc(accountID, network, peerID, description, netID, masquerade, metric, groups, enabled, userID)
|
return am.CreateRouteFunc(accountID, network, peerID, peerGroups, description, netID, masquerade, metric, groups, enabled, userID)
|
||||||
}
|
}
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented")
|
||||||
}
|
}
|
||||||
|
@ -39,30 +39,82 @@ func (am *DefaultAccountManager) GetRoute(accountID, routeID, userID string) (*r
|
|||||||
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
|
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otherwise returns nil
|
// checkRoutePrefixExistsForPeers checks if a route with a given prefix exists for a single peer or multiple peer groups.
|
||||||
func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peerID string, prefix netip.Prefix) error {
|
func (am *DefaultAccountManager) checkRoutePrefixExistsForPeers(account *Account, peerID, routeID string, peerGroupIDs []string, prefix netip.Prefix) error {
|
||||||
|
// routes can have both peer and peer_groups
|
||||||
if peerID == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
routesWithPrefix := account.GetRoutesByPrefix(prefix)
|
routesWithPrefix := account.GetRoutesByPrefix(prefix)
|
||||||
|
|
||||||
|
// lets remember all the peers and the peer groups from routesWithPrefix
|
||||||
|
seenPeers := make(map[string]bool)
|
||||||
|
seenPeerGroups := make(map[string]bool)
|
||||||
|
|
||||||
for _, prefixRoute := range routesWithPrefix {
|
for _, prefixRoute := range routesWithPrefix {
|
||||||
if prefixRoute.Peer == peerID {
|
// we skip route(s) with the same network ID as we want to allow updating of the existing route
|
||||||
return status.Errorf(status.AlreadyExists, "failed to add route with prefix %s - peer already has this route", prefix.String())
|
// when create a new route routeID is newly generated so nothing will be skipped
|
||||||
|
if routeID == prefixRoute.ID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefixRoute.Peer != "" {
|
||||||
|
seenPeers[prefixRoute.ID] = true
|
||||||
|
}
|
||||||
|
for _, groupID := range prefixRoute.PeerGroups {
|
||||||
|
seenPeerGroups[groupID] = true
|
||||||
|
|
||||||
|
group := account.GetGroup(groupID)
|
||||||
|
if group == nil {
|
||||||
|
return status.Errorf(
|
||||||
|
status.InvalidArgument, "failed to add route with prefix %s - peer group %s doesn't exist",
|
||||||
|
prefix.String(), groupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pID := range group.Peers {
|
||||||
|
seenPeers[pID] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if peerID != "" {
|
||||||
|
// check that peerID exists and is not in any route as single peer or part of the group
|
||||||
|
peer := account.GetPeer(peerID)
|
||||||
|
if peer == nil {
|
||||||
|
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||||
|
}
|
||||||
|
if _, ok := seenPeers[peerID]; ok {
|
||||||
|
return status.Errorf(status.AlreadyExists,
|
||||||
|
"failed to add route with prefix %s - peer %s already has this route", prefix.String(), peerID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that peerGroupIDs are not in any route peerGroups list
|
||||||
|
for _, groupID := range peerGroupIDs {
|
||||||
|
group := account.GetGroup(groupID) // we validated the group existent before entering this function, o need to check again.
|
||||||
|
|
||||||
|
if _, ok := seenPeerGroups[groupID]; ok {
|
||||||
|
return status.Errorf(
|
||||||
|
status.AlreadyExists, "failed to add route with prefix %s - peer group %s already has this route",
|
||||||
|
prefix.String(), group.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the peers from peerGroupIDs groups are not the same peers we saw in routesWithPrefix
|
||||||
|
for _, id := range group.Peers {
|
||||||
|
if _, ok := seenPeers[id]; ok {
|
||||||
|
peer := account.GetPeer(peerID)
|
||||||
|
if peer == nil {
|
||||||
|
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||||
|
}
|
||||||
|
return status.Errorf(status.AlreadyExists,
|
||||||
|
"failed to add route with prefix %s - peer %s from the group %s already has this route",
|
||||||
|
prefix.String(), peer.Name, group.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRoute creates and saves a new route
|
// CreateRoute creates and saves a new route
|
||||||
func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, peerGroupIDs []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
||||||
unlock := am.Store.AcquireAccountLock(accountID)
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
@ -71,19 +123,29 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerID != "" {
|
if peerID != "" && len(peerGroupIDs) != 0 {
|
||||||
peer := account.GetPeer(peerID)
|
return nil, status.Errorf(
|
||||||
if peer == nil {
|
status.InvalidArgument,
|
||||||
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
"peer with ID %s and peers group %s should not be provided at the same time",
|
||||||
}
|
peerID, peerGroupIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
var newRoute route.Route
|
var newRoute route.Route
|
||||||
|
newRoute.ID = xid.New().String()
|
||||||
|
|
||||||
prefixType, newPrefix, err := route.ParseNetwork(network)
|
prefixType, newPrefix, err := route.ParseNetwork(network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(status.InvalidArgument, "failed to parse IP %s", network)
|
return nil, status.Errorf(status.InvalidArgument, "failed to parse IP %s", network)
|
||||||
}
|
}
|
||||||
err = am.checkPrefixPeerExists(accountID, peerID, newPrefix)
|
|
||||||
|
if len(peerGroupIDs) > 0 {
|
||||||
|
err = validateGroups(peerGroupIDs, account.Groups)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.checkRoutePrefixExistsForPeers(account, peerID, newRoute.ID, peerGroupIDs, newPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -102,7 +164,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
newRoute.Peer = peerID
|
newRoute.Peer = peerID
|
||||||
newRoute.ID = xid.New().String()
|
newRoute.PeerGroups = peerGroupIDs
|
||||||
newRoute.Network = newPrefix
|
newRoute.Network = newPrefix
|
||||||
newRoute.NetworkType = prefixType
|
newRoute.NetworkType = prefixType
|
||||||
newRoute.Description = description
|
newRoute.Description = description
|
||||||
@ -160,13 +222,22 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if routeToSave.Peer != "" {
|
if routeToSave.Peer != "" && len(routeToSave.PeerGroups) != 0 {
|
||||||
peer := account.GetPeer(routeToSave.Peer)
|
return status.Errorf(status.InvalidArgument, "peer with ID and peer groups should not be provided at the same time")
|
||||||
if peer == nil {
|
}
|
||||||
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", routeToSave.Peer)
|
|
||||||
|
if len(routeToSave.PeerGroups) > 0 {
|
||||||
|
err = validateGroups(routeToSave.PeerGroups, 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
|
||||||
|
}
|
||||||
|
|
||||||
err = validateGroups(routeToSave.Groups, account.Groups)
|
err = validateGroups(routeToSave.Groups, account.Groups)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -14,24 +14,37 @@ import (
|
|||||||
const (
|
const (
|
||||||
peer1Key = "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8="
|
peer1Key = "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8="
|
||||||
peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI="
|
peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI="
|
||||||
|
peer3Key = "ayF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NaF="
|
||||||
|
peer4Key = "ayF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5acc="
|
||||||
|
peer5Key = "ayF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5a55="
|
||||||
peer1ID = "peer-1-id"
|
peer1ID = "peer-1-id"
|
||||||
peer2ID = "peer-2-id"
|
peer2ID = "peer-2-id"
|
||||||
|
peer3ID = "peer-3-id"
|
||||||
|
peer4ID = "peer-4-id"
|
||||||
|
peer5ID = "peer-5-id"
|
||||||
routeGroup1 = "routeGroup1"
|
routeGroup1 = "routeGroup1"
|
||||||
routeGroup2 = "routeGroup2"
|
routeGroup2 = "routeGroup2"
|
||||||
|
routeGroup3 = "routeGroup3" // for existing route
|
||||||
|
routeGroup4 = "routeGroup4" // for existing route
|
||||||
|
routeGroupHA1 = "routeGroupHA1"
|
||||||
|
routeGroupHA2 = "routeGroupHA2"
|
||||||
routeInvalidGroup1 = "routeInvalidGroup1"
|
routeInvalidGroup1 = "routeInvalidGroup1"
|
||||||
userID = "testingUser"
|
userID = "testingUser"
|
||||||
|
existingNetwork = "10.10.10.0/24"
|
||||||
|
existingRouteID = "random-id"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateRoute(t *testing.T) {
|
func TestCreateRoute(t *testing.T) {
|
||||||
type input struct {
|
type input struct {
|
||||||
network string
|
network string
|
||||||
netID string
|
netID string
|
||||||
peerKey string
|
peerKey string
|
||||||
description string
|
peerGroupIDs []string
|
||||||
masquerade bool
|
description string
|
||||||
metric int
|
masquerade bool
|
||||||
enabled bool
|
metric int
|
||||||
groups []string
|
enabled bool
|
||||||
|
groups []string
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@ -67,6 +80,48 @@ func TestCreateRoute(t *testing.T) {
|
|||||||
Groups: []string{routeGroup1},
|
Groups: []string{routeGroup1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Happy Path Peer Groups",
|
||||||
|
inputArgs: input{
|
||||||
|
network: "192.168.0.0/16",
|
||||||
|
netID: "happy",
|
||||||
|
peerGroupIDs: []string{routeGroupHA1, routeGroupHA2},
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
groups: []string{routeGroup1, routeGroup2},
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
NetID: "happy",
|
||||||
|
PeerGroups: []string{routeGroupHA1, routeGroupHA2},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1, routeGroup2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Both peer and peer_groups Provided Should Fail",
|
||||||
|
inputArgs: input{
|
||||||
|
network: "192.168.0.0/16",
|
||||||
|
netID: "happy",
|
||||||
|
peerKey: peer1ID,
|
||||||
|
peerGroupIDs: []string{routeGroupHA1},
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Bad Prefix Should Fail",
|
name: "Bad Prefix Should Fail",
|
||||||
inputArgs: input{
|
inputArgs: input{
|
||||||
@ -97,6 +152,36 @@ func TestCreateRoute(t *testing.T) {
|
|||||||
errFunc: require.Error,
|
errFunc: require.Error,
|
||||||
shouldCreate: false,
|
shouldCreate: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Peer already has this route",
|
||||||
|
inputArgs: input{
|
||||||
|
network: existingNetwork,
|
||||||
|
netID: "bad",
|
||||||
|
peerKey: peer5ID,
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Peers Group already has this route",
|
||||||
|
inputArgs: input{
|
||||||
|
network: existingNetwork,
|
||||||
|
netID: "bad",
|
||||||
|
peerGroupIDs: []string{routeGroup1, routeGroup3},
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Empty Peer Should Create",
|
name: "Empty Peer Should Create",
|
||||||
inputArgs: input{
|
inputArgs: input{
|
||||||
@ -238,13 +323,14 @@ func TestCreateRoute(t *testing.T) {
|
|||||||
|
|
||||||
account, err := initTestRouteAccount(t, am)
|
account, err := initTestRouteAccount(t, am)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("failed to init testing account")
|
t.Errorf("failed to init testing account: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
outRoute, err := am.CreateRoute(
|
outRoute, err := am.CreateRoute(
|
||||||
account.Id,
|
account.Id,
|
||||||
testCase.inputArgs.network,
|
testCase.inputArgs.network,
|
||||||
testCase.inputArgs.peerKey,
|
testCase.inputArgs.peerKey,
|
||||||
|
testCase.inputArgs.peerGroupIDs,
|
||||||
testCase.inputArgs.description,
|
testCase.inputArgs.description,
|
||||||
testCase.inputArgs.netID,
|
testCase.inputArgs.netID,
|
||||||
testCase.inputArgs.masquerade,
|
testCase.inputArgs.masquerade,
|
||||||
@ -272,6 +358,7 @@ func TestCreateRoute(t *testing.T) {
|
|||||||
|
|
||||||
func TestSaveRoute(t *testing.T) {
|
func TestSaveRoute(t *testing.T) {
|
||||||
validPeer := peer2ID
|
validPeer := peer2ID
|
||||||
|
validUsedPeer := peer5ID
|
||||||
invalidPeer := "nonExisting"
|
invalidPeer := "nonExisting"
|
||||||
validPrefix := netip.MustParsePrefix("192.168.0.0/24")
|
validPrefix := netip.MustParsePrefix("192.168.0.0/24")
|
||||||
invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34")
|
invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34")
|
||||||
@ -279,11 +366,14 @@ func TestSaveRoute(t *testing.T) {
|
|||||||
invalidMetric := 99999
|
invalidMetric := 99999
|
||||||
validNetID := "12345678901234567890qw"
|
validNetID := "12345678901234567890qw"
|
||||||
invalidNetID := "12345678901234567890qwertyuiopqwertyuiop1"
|
invalidNetID := "12345678901234567890qwertyuiopqwertyuiop1"
|
||||||
|
validGroupHA1 := routeGroupHA1
|
||||||
|
validGroupHA2 := routeGroupHA2
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
existingRoute *route.Route
|
existingRoute *route.Route
|
||||||
newPeer *string
|
newPeer *string
|
||||||
|
newPeerGroups []string
|
||||||
newMetric *int
|
newMetric *int
|
||||||
newPrefix *netip.Prefix
|
newPrefix *netip.Prefix
|
||||||
newGroups []string
|
newGroups []string
|
||||||
@ -325,6 +415,55 @@ func TestSaveRoute(t *testing.T) {
|
|||||||
Groups: []string{routeGroup2},
|
Groups: []string{routeGroup2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Happy Path Peer Groups",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
newPeerGroups: []string{validGroupHA1, validGroupHA2},
|
||||||
|
newMetric: &validMetric,
|
||||||
|
newPrefix: &validPrefix,
|
||||||
|
newGroups: []string{routeGroup2},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: validPrefix,
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{validGroupHA1, validGroupHA2},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: validMetric,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Both peer and peers_roup Provided Should Fail",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
newPeer: &validPeer,
|
||||||
|
newPeerGroups: []string{validGroupHA1},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Bad Prefix Should Fail",
|
name: "Bad Prefix Should Fail",
|
||||||
existingRoute: &route.Route{
|
existingRoute: &route.Route{
|
||||||
@ -461,6 +600,71 @@ func TestSaveRoute(t *testing.T) {
|
|||||||
newGroups: []string{routeInvalidGroup1},
|
newGroups: []string{routeInvalidGroup1},
|
||||||
errFunc: require.Error,
|
errFunc: require.Error,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Allow to modify existing route with new peer",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix(existingNetwork),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
Peer: peer1ID,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
newPeer: &validPeer,
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix(existingNetwork),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
Peer: validPeer,
|
||||||
|
PeerGroups: []string{},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Do not allow to modify existing route with a peer from another route",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix(existingNetwork),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
Peer: peer1ID,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
newPeer: &validUsedPeer,
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Do not allow to modify existing route with a peers group from another route",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Network: netip.MustParsePrefix(existingNetwork),
|
||||||
|
NetID: validNetID,
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{routeGroup3},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
},
|
||||||
|
newPeerGroups: []string{routeGroup4},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
@ -488,6 +692,9 @@ func TestSaveRoute(t *testing.T) {
|
|||||||
if testCase.newPeer != nil {
|
if testCase.newPeer != nil {
|
||||||
routeToSave.Peer = *testCase.newPeer
|
routeToSave.Peer = *testCase.newPeer
|
||||||
}
|
}
|
||||||
|
if len(testCase.newPeerGroups) != 0 {
|
||||||
|
routeToSave.PeerGroups = testCase.newPeerGroups
|
||||||
|
}
|
||||||
if testCase.newMetric != nil {
|
if testCase.newMetric != nil {
|
||||||
routeToSave.Metric = *testCase.newMetric
|
routeToSave.Metric = *testCase.newMetric
|
||||||
}
|
}
|
||||||
@ -569,6 +776,96 @@ func TestDeleteRoute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetNetworkMap_RouteSyncPeerGroups(t *testing.T) {
|
||||||
|
baseRoute := &route.Route{
|
||||||
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{routeGroupHA1, routeGroupHA2},
|
||||||
|
Description: "ha route",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1, routeGroup2},
|
||||||
|
}
|
||||||
|
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
newAccountRoutes, err := am.GetNetworkMap(peer1ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes")
|
||||||
|
|
||||||
|
newRoute, err := am.CreateRoute(
|
||||||
|
account.Id, baseRoute.Network.String(), baseRoute.Peer, baseRoute.PeerGroups, baseRoute.Description,
|
||||||
|
baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, baseRoute.Groups, baseRoute.Enabled, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, newRoute.Enabled, true)
|
||||||
|
|
||||||
|
peer1Routes, err := am.GetNetworkMap(peer1ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1Routes.Routes, 3, "HA route should have more than 1 routes")
|
||||||
|
|
||||||
|
peer2Routes, err := am.GetNetworkMap(peer2ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2Routes.Routes, 3, "HA route should have more than 1 routes")
|
||||||
|
|
||||||
|
peer4Routes, err := am.GetNetworkMap(peer4ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer4Routes.Routes, 3, "HA route should have more than 1 routes")
|
||||||
|
|
||||||
|
groups, err := am.ListGroups(account.Id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var groupHA1, groupHA2 *Group
|
||||||
|
for _, group := range groups {
|
||||||
|
switch group.Name {
|
||||||
|
case routeGroupHA1:
|
||||||
|
groupHA1 = group
|
||||||
|
case routeGroupHA2:
|
||||||
|
groupHA2 = group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.GroupDeletePeer(account.Id, groupHA1.ID, peer2ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer2RoutesAfterDelete, err := am.GetNetworkMap(peer2ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2RoutesAfterDelete.Routes, 2, "after peer deletion group should have only 2 route")
|
||||||
|
|
||||||
|
err = am.GroupDeletePeer(account.Id, groupHA2.ID, peer4ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer2RoutesAfterDelete, err = am.GetNetworkMap(peer2ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2RoutesAfterDelete.Routes, 1, "after peer deletion group should have only 1 route")
|
||||||
|
|
||||||
|
err = am.GroupAddPeer(account.Id, groupHA2.ID, peer4ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer1RoutesAfterAdd, err := am.GetNetworkMap(peer1ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1RoutesAfterAdd.Routes, 2, "HA route should have more than 1 route")
|
||||||
|
|
||||||
|
peer2RoutesAfterAdd, err := am.GetNetworkMap(peer2ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2RoutesAfterAdd.Routes, 2, "HA route should have more than 1 route")
|
||||||
|
|
||||||
|
err = am.DeleteRoute(account.Id, newRoute.ID, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer1DeletedRoute, err := am.GetNetworkMap(peer1ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1DeletedRoute.Routes, 0, "we should receive one route for peer1")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetNetworkMap_RouteSync(t *testing.T) {
|
func TestGetNetworkMap_RouteSync(t *testing.T) {
|
||||||
// no routes for peer in different groups
|
// no routes for peer in different groups
|
||||||
// no routes when route is deleted
|
// no routes when route is deleted
|
||||||
@ -599,7 +896,7 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes")
|
require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes")
|
||||||
|
|
||||||
createdRoute, err := am.CreateRoute(account.Id, baseRoute.Network.String(), peer1ID,
|
createdRoute, err := am.CreateRoute(account.Id, baseRoute.Network.String(), peer1ID, []string{},
|
||||||
baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, baseRoute.Groups, false,
|
baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, baseRoute.Groups, false,
|
||||||
userID)
|
userID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -695,6 +992,8 @@ func createRouterStore(t *testing.T) (Store, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) {
|
func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
accountID := "testingAcc"
|
accountID := "testingAcc"
|
||||||
domain := "example.com"
|
domain := "example.com"
|
||||||
|
|
||||||
@ -754,6 +1053,81 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er
|
|||||||
}
|
}
|
||||||
account.Peers[peer2.ID] = peer2
|
account.Peers[peer2.ID] = peer2
|
||||||
|
|
||||||
|
ips = account.getTakenIPs()
|
||||||
|
peer3IP, err := AllocatePeerIP(account.Network.Net, ips)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peer3 := &Peer{
|
||||||
|
IP: peer3IP,
|
||||||
|
ID: peer3ID,
|
||||||
|
Key: peer3Key,
|
||||||
|
Name: "test-host3@netbird.io",
|
||||||
|
UserID: userID,
|
||||||
|
Meta: PeerSystemMeta{
|
||||||
|
Hostname: "test-host3@netbird.io",
|
||||||
|
GoOS: "darwin",
|
||||||
|
Kernel: "Darwin",
|
||||||
|
Core: "13.4.1",
|
||||||
|
Platform: "arm64",
|
||||||
|
OS: "darwin",
|
||||||
|
WtVersion: "development",
|
||||||
|
UIVersion: "development",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
account.Peers[peer3.ID] = peer3
|
||||||
|
|
||||||
|
ips = account.getTakenIPs()
|
||||||
|
peer4IP, err := AllocatePeerIP(account.Network.Net, ips)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peer4 := &Peer{
|
||||||
|
IP: peer4IP,
|
||||||
|
ID: peer4ID,
|
||||||
|
Key: peer4Key,
|
||||||
|
Name: "test-host4@netbird.io",
|
||||||
|
UserID: userID,
|
||||||
|
Meta: PeerSystemMeta{
|
||||||
|
Hostname: "test-host4@netbird.io",
|
||||||
|
GoOS: "linux",
|
||||||
|
Kernel: "Linux",
|
||||||
|
Core: "21.04",
|
||||||
|
Platform: "x86_64",
|
||||||
|
OS: "Ubuntu",
|
||||||
|
WtVersion: "development",
|
||||||
|
UIVersion: "development",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
account.Peers[peer4.ID] = peer4
|
||||||
|
|
||||||
|
ips = account.getTakenIPs()
|
||||||
|
peer5IP, err := AllocatePeerIP(account.Network.Net, ips)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peer5 := &Peer{
|
||||||
|
IP: peer5IP,
|
||||||
|
ID: peer5ID,
|
||||||
|
Key: peer5Key,
|
||||||
|
Name: "test-host4@netbird.io",
|
||||||
|
UserID: userID,
|
||||||
|
Meta: PeerSystemMeta{
|
||||||
|
Hostname: "test-host4@netbird.io",
|
||||||
|
GoOS: "linux",
|
||||||
|
Kernel: "Linux",
|
||||||
|
Core: "21.04",
|
||||||
|
Platform: "x86_64",
|
||||||
|
OS: "Ubuntu",
|
||||||
|
WtVersion: "development",
|
||||||
|
UIVersion: "development",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
account.Peers[peer5.ID] = peer5
|
||||||
|
|
||||||
err = am.Store.SaveAccount(account)
|
err = am.Store.SaveAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -770,24 +1144,57 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
err = am.GroupAddPeer(accountID, groupAll.ID, peer3ID)
|
||||||
newGroup := &Group{
|
if err != nil {
|
||||||
ID: routeGroup1,
|
return nil, err
|
||||||
Name: routeGroup1,
|
|
||||||
Peers: []string{peer1.ID},
|
|
||||||
}
|
}
|
||||||
err = am.SaveGroup(accountID, userID, newGroup)
|
err = am.GroupAddPeer(accountID, groupAll.ID, peer4ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newGroup = &Group{
|
newGroup := []*Group{
|
||||||
ID: routeGroup2,
|
{
|
||||||
Name: routeGroup2,
|
ID: routeGroup1,
|
||||||
Peers: []string{peer2.ID},
|
Name: routeGroup1,
|
||||||
|
Peers: []string{peer1.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: routeGroup2,
|
||||||
|
Name: routeGroup2,
|
||||||
|
Peers: []string{peer2.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: routeGroup3,
|
||||||
|
Name: routeGroup3,
|
||||||
|
Peers: []string{peer5.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: routeGroup4,
|
||||||
|
Name: routeGroup4,
|
||||||
|
Peers: []string{peer5.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: routeGroupHA1,
|
||||||
|
Name: routeGroupHA1,
|
||||||
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID}, // we have one non Linux peer, see peer3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: routeGroupHA2,
|
||||||
|
Name: routeGroupHA2,
|
||||||
|
Peers: []string{peer1.ID, peer4.ID},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = am.SaveGroup(accountID, userID, newGroup)
|
for _, group := range newGroup {
|
||||||
|
err = am.SaveGroup(accountID, userID, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = am.CreateRoute(account.Id, existingNetwork, "", []string{routeGroup3, routeGroup4},
|
||||||
|
"", existingRouteID, false, 1000, []string{groupAll.ID}, true, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ type Route struct {
|
|||||||
NetID string
|
NetID string
|
||||||
Description string
|
Description string
|
||||||
Peer string
|
Peer string
|
||||||
|
PeerGroups []string
|
||||||
NetworkType NetworkType
|
NetworkType NetworkType
|
||||||
Masquerade bool
|
Masquerade bool
|
||||||
Metric int
|
Metric int
|
||||||
@ -79,7 +80,7 @@ type Route struct {
|
|||||||
|
|
||||||
// EventMeta returns activity event meta related to the route
|
// EventMeta returns activity event meta related to the route
|
||||||
func (r *Route) EventMeta() map[string]any {
|
func (r *Route) EventMeta() map[string]any {
|
||||||
return map[string]any{"name": r.NetID, "network_range": r.Network.String(), "peer_id": r.Peer}
|
return map[string]any{"name": r.NetID, "network_range": r.Network.String(), "peer_id": r.Peer, "peer_groups": r.PeerGroups}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy copies a route object
|
// Copy copies a route object
|
||||||
@ -91,12 +92,14 @@ func (r *Route) Copy() *Route {
|
|||||||
Network: r.Network,
|
Network: r.Network,
|
||||||
NetworkType: r.NetworkType,
|
NetworkType: r.NetworkType,
|
||||||
Peer: r.Peer,
|
Peer: r.Peer,
|
||||||
|
PeerGroups: make([]string, len(r.PeerGroups)),
|
||||||
Metric: r.Metric,
|
Metric: r.Metric,
|
||||||
Masquerade: r.Masquerade,
|
Masquerade: r.Masquerade,
|
||||||
Enabled: r.Enabled,
|
Enabled: r.Enabled,
|
||||||
Groups: make([]string, len(r.Groups)),
|
Groups: make([]string, len(r.Groups)),
|
||||||
}
|
}
|
||||||
copy(route.Groups, r.Groups)
|
copy(route.Groups, r.Groups)
|
||||||
|
copy(route.PeerGroups, r.PeerGroups)
|
||||||
return route
|
return route
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +114,8 @@ func (r *Route) IsEqual(other *Route) bool {
|
|||||||
other.Metric == r.Metric &&
|
other.Metric == r.Metric &&
|
||||||
other.Masquerade == r.Masquerade &&
|
other.Masquerade == r.Masquerade &&
|
||||||
other.Enabled == r.Enabled &&
|
other.Enabled == r.Enabled &&
|
||||||
compareGroupsList(r.Groups, other.Groups)
|
compareList(r.Groups, other.Groups) &&
|
||||||
|
compareList(r.PeerGroups, other.PeerGroups)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseNetwork Parses a network prefix string and returns a netip.Prefix object and if is invalid, IPv4 or IPv6
|
// ParseNetwork Parses a network prefix string and returns a netip.Prefix object and if is invalid, IPv4 or IPv6
|
||||||
@ -134,7 +138,7 @@ func ParseNetwork(networkString string) (NetworkType, netip.Prefix, error) {
|
|||||||
return IPv4Network, masked, nil
|
return IPv4Network, masked, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareGroupsList(list, other []string) bool {
|
func compareList(list, other []string) bool {
|
||||||
if len(list) != len(other) {
|
if len(list) != len(other) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user