mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 09:16:40 +00:00
[management] Add API of new network concept (#3012)
This commit is contained in:
47
management/server/networks/resources/manager.go
Normal file
47
management/server/networks/resources/manager.go
Normal 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")
|
||||
}
|
||||
105
management/server/networks/resources/types/resource.go
Normal file
105
management/server/networks/resources/types/resource.go
Normal 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")
|
||||
}
|
||||
41
management/server/networks/resources/types/resource_test.go
Normal file
41
management/server/networks/resources/types/resource_test.go
Normal 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")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user