[management] Add API of new network concept (#3012)

This commit is contained in:
Pascal Fischer
2024-12-11 12:58:45 +01:00
committed by GitHub
parent 9f859a240e
commit 60ee31df3e
92 changed files with 5320 additions and 3562 deletions

View File

@@ -0,0 +1,47 @@
package resources
import (
"context"
"errors"
"github.com/netbirdio/netbird/management/server/networks/resources/types"
"github.com/netbirdio/netbird/management/server/store"
)
type Manager interface {
GetAllResources(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkResource, error)
CreateResource(ctx context.Context, accountID string, resource *types.NetworkResource) (*types.NetworkResource, error)
GetResource(ctx context.Context, accountID, userID, networkID, resourceID string) (*types.NetworkResource, error)
UpdateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error)
DeleteResource(ctx context.Context, accountID, userID, networkID, resourceID string) error
}
type managerImpl struct {
store store.Store
}
func NewManager(store store.Store) Manager {
return &managerImpl{
store: store,
}
}
func (m *managerImpl) GetAllResources(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkResource, error) {
return nil, errors.New("not implemented")
}
func (m *managerImpl) CreateResource(ctx context.Context, accountID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
return nil, errors.New("not implemented")
}
func (m *managerImpl) GetResource(ctx context.Context, accountID, userID, networkID, resourceID string) (*types.NetworkResource, error) {
return nil, errors.New("not implemented")
}
func (m *managerImpl) UpdateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
return nil, errors.New("not implemented")
}
func (m *managerImpl) DeleteResource(ctx context.Context, accountID, userID, networkID, resourceID string) error {
return errors.New("not implemented")
}

View File

@@ -0,0 +1,105 @@
package types
import (
"errors"
"fmt"
"net"
"regexp"
"strings"
"github.com/rs/xid"
"github.com/netbirdio/netbird/management/server/http/api"
)
type NetworkResourceType string
const (
host NetworkResourceType = "host"
subnet NetworkResourceType = "subnet"
domain NetworkResourceType = "domain"
)
func (p NetworkResourceType) String() string {
return string(p)
}
type NetworkResource struct {
ID string `gorm:"index"`
NetworkID string `gorm:"index"`
AccountID string `gorm:"index"`
Name string
Description string
Type NetworkResourceType
Address string
}
func NewNetworkResource(accountID, networkID, name, description, address string) (*NetworkResource, error) {
resourceType, err := getResourceType(address)
if err != nil {
return nil, fmt.Errorf("invalid address: %w", err)
}
return &NetworkResource{
ID: xid.New().String(),
AccountID: accountID,
NetworkID: networkID,
Name: name,
Description: description,
Type: resourceType,
Address: address,
}, nil
}
func (n *NetworkResource) ToAPIResponse() *api.NetworkResource {
return &api.NetworkResource{
Id: n.ID,
Name: n.Name,
Description: &n.Description,
Type: api.NetworkResourceType(n.Type.String()),
Address: n.Address,
}
}
func (n *NetworkResource) FromAPIRequest(req *api.NetworkResourceRequest) {
n.Name = req.Name
n.Description = ""
if req.Description != nil {
n.Description = *req.Description
}
n.Address = req.Address
}
func (n *NetworkResource) Copy() *NetworkResource {
return &NetworkResource{
ID: n.ID,
AccountID: n.AccountID,
NetworkID: n.NetworkID,
Name: n.Name,
Description: n.Description,
Type: n.Type,
Address: n.Address,
}
}
// getResourceType returns the type of the resource based on the address
func getResourceType(address string) (NetworkResourceType, error) {
if ip, cidr, err := net.ParseCIDR(address); err == nil {
ones, _ := cidr.Mask.Size()
if strings.HasSuffix(address, "/32") || (ip != nil && ones == 32) {
return host, nil
}
return subnet, nil
}
if net.ParseIP(address) != nil {
return host, nil
}
domainRegex := regexp.MustCompile(`^(\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$`)
if domainRegex.MatchString(address) {
return domain, nil
}
return "", errors.New("not a host, subnet, or domain")
}

View File

@@ -0,0 +1,41 @@
package types
import (
"testing"
)
func TestGetResourceType(t *testing.T) {
tests := []struct {
input string
expectedType NetworkResourceType
expectedErr bool
}{
// Valid host IPs
{"1.1.1.1", host, false},
{"1.1.1.1/32", host, false},
// Valid subnets
{"192.168.1.0/24", subnet, false},
{"10.0.0.0/16", subnet, false},
// Valid domains
{"example.com", domain, false},
{"*.example.com", domain, false},
{"sub.example.com", domain, false},
// Invalid inputs
{"invalid", "", true},
{"1.1.1.1/abc", "", true},
{"1234", "", true},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
result, err := getResourceType(tt.input)
if result != tt.expectedType {
t.Errorf("Expected type %v, got %v", tt.expectedType, result)
}
if tt.expectedErr && err == nil {
t.Errorf("Expected error, got nil")
}
})
}
}