diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index f6ea39a8e..58134d375 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -4068,6 +4068,31 @@ paths: "$ref": "#/components/responses/forbidden" '500': "$ref": "#/components/responses/internal_error" + /api/networks/routers: + get: + summary: List all Network Routers + description: Returns a list of all routers in a network + tags: [ Networks ] + security: + - BearerAuth: [ ] + - TokenAuth: [ ] + responses: + '200': + description: A JSON Array of Routers + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NetworkRouter' + '400': + "$ref": "#/components/responses/bad_request" + '401': + "$ref": "#/components/responses/requires_authentication" + '403': + "$ref": "#/components/responses/forbidden" + '500': + "$ref": "#/components/responses/internal_error" /api/dns/nameservers: get: summary: List all Nameserver Groups diff --git a/management/server/http/handlers/networks/routers_handler.go b/management/server/http/handlers/networks/routers_handler.go index f1a3fba0b..6b00534fc 100644 --- a/management/server/http/handlers/networks/routers_handler.go +++ b/management/server/http/handlers/networks/routers_handler.go @@ -19,7 +19,8 @@ type routersHandler struct { func addRouterEndpoints(routersManager routers.Manager, router *mux.Router) { routersHandler := newRoutersHandler(routersManager) - router.HandleFunc("/networks/{networkId}/routers", routersHandler.getAllRouters).Methods("GET", "OPTIONS") + router.HandleFunc("/networks/routers", routersHandler.getAllRouters).Methods("GET", "OPTIONS") + router.HandleFunc("/networks/{networkId}/routers", routersHandler.getNetworkRouters).Methods("GET", "OPTIONS") router.HandleFunc("/networks/{networkId}/routers", routersHandler.createRouter).Methods("POST", "OPTIONS") router.HandleFunc("/networks/{networkId}/routers/{routerId}", routersHandler.getRouter).Methods("GET", "OPTIONS") router.HandleFunc("/networks/{networkId}/routers/{routerId}", routersHandler.updateRouter).Methods("PUT", "OPTIONS") @@ -41,6 +42,31 @@ func (h *routersHandler) getAllRouters(w http.ResponseWriter, r *http.Request) { accountID, userID := userAuth.AccountId, userAuth.UserId + routersMap, err := h.routersManager.GetAllRoutersInAccount(r.Context(), accountID, userID) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + routersResponse := make([]*api.NetworkRouter, 0) + for _, routers := range routersMap { + for _, router := range routers { + routersResponse = append(routersResponse, router.ToAPIResponse()) + } + } + + util.WriteJSONObject(r.Context(), w, routersResponse) +} + +func (h *routersHandler) getNetworkRouters(w http.ResponseWriter, r *http.Request) { + userAuth, err := nbcontext.GetUserAuthFromContext(r.Context()) + if err != nil { + util.WriteError(r.Context(), err, w) + return + } + + accountID, userID := userAuth.AccountId, userAuth.UserId + networkID := mux.Vars(r)["networkId"] routers, err := h.routersManager.GetAllRoutersInNetwork(r.Context(), accountID, userID, networkID) if err != nil { diff --git a/management/server/peer.go b/management/server/peer.go index f91db928d..4a468a6cd 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -17,6 +17,7 @@ import ( "github.com/netbirdio/netbird/management/domain" "github.com/netbirdio/netbird/management/server/geolocation" + routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types" "github.com/netbirdio/netbird/management/server/permissions/modules" "github.com/netbirdio/netbird/management/server/permissions/operations" @@ -352,7 +353,7 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer return err } - if err = am.validatePeerDelete(ctx, accountID, peerID); err != nil { + if err = am.validatePeerDelete(ctx, transaction, accountID, peerID); err != nil { return err } @@ -1543,7 +1544,7 @@ func ConvertSliceToMap(existingLabels []string) map[string]struct{} { } // validatePeerDelete checks if the peer can be deleted. -func (am *DefaultAccountManager) validatePeerDelete(ctx context.Context, accountId, peerId string) error { +func (am *DefaultAccountManager) validatePeerDelete(ctx context.Context, transaction store.Store, accountId, peerId string) error { linkedInIngressPorts, err := am.proxyController.IsPeerInIngressPorts(ctx, accountId, peerId) if err != nil { return err @@ -1553,5 +1554,27 @@ func (am *DefaultAccountManager) validatePeerDelete(ctx context.Context, account return status.Errorf(status.PreconditionFailed, "peer is linked to ingress ports: %s", peerId) } + linked, router := isPeerLinkedToNetworkRouter(ctx, transaction, accountId, peerId) + if linked { + return status.Errorf(status.PreconditionFailed, "peer is linked to a network router: %s", router.ID) + } + return nil } + +// isPeerLinkedToNetworkRouter checks if a peer is linked to any network router in the account. +func isPeerLinkedToNetworkRouter(ctx context.Context, transaction store.Store, accountID string, peerID string) (bool, *routerTypes.NetworkRouter) { + routers, err := transaction.GetNetworkRoutersByAccountID(ctx, store.LockingStrengthShare, accountID) + if err != nil { + log.WithContext(ctx).Errorf("error retrieving network routers while checking peer linkage: %v", err) + return false, nil + } + + for _, router := range routers { + if router.Peer == peerID { + return true, router + } + } + + return false, nil +}