This commit is contained in:
asteam
2025-11-14 17:38:59 +03:00
parent 562b6019d0
commit 0bf073da93
149 changed files with 11080 additions and 38 deletions

View File

@@ -0,0 +1,18 @@
// API Actor API for managing SDN adress pools
package adrspools
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
)
// Structure for creating request to address pools
type AddressPools struct {
client interfaces.Caller
}
// Builder for adress pools endpoints
func New(client interfaces.Caller) *AddressPools {
return &AddressPools{
client,
}
}

View File

@@ -0,0 +1,80 @@
package adrspools
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// CreateRequest struct to create address pool
type CreateRequest struct {
// ID of the access group
// Required: true
AccessGroupID string `url:"access_group_id" json:"access_group_id" validate:"required"`
// Description of the network
// Required: true
Description string `url:"description" json:"description" validate:"required"`
// Name of the network
// Required: true
Name string `url:"name" json:"name" validate:"required"`
// Network address type
// Required: true
NetAddressType string `url:"net_address_type" json:"net_address_type" validate:"required,addressPoolNetTypeValidator"`
// List of network addresses
// Required: false
NetAddresses []NetAddress `url:"net_addresses,omitempty" json:"net_addresses,omitempty" validate:"dive"`
}
// NetAddress struct representing network address
type NetAddress struct {
// Network address type
// Required: true
NetAddressType string `url:"net_address_type" json:"net_address_type" validate:"required,addressPoolNetTypeValidator"`
// IP address
// Required: true
IPAddr string `url:"ip_addr" json:"ip_addr" validate:"required"`
// End of IP address range
// Required: false
IPAddrRangeEnd string `url:"ip_addr_range_end,omitempty" json:"ip_addr_range_end,omitempty"`
// IP prefix
// Required: false
IPPrefix string `url:"ip_prefix,omitempty" json:"ip_prefix,omitempty"`
// MAC address
// Required: false
MACAddr string `url:"mac_addr,omitempty" json:"mac_addr,omitempty"`
}
// Create creates a address pool
func (i AddressPools) Create(ctx context.Context, req CreateRequest) (*NetworkAddressPool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/address_pool/create"
res, err := i.client.DecortApiCallCtype(ctx, http.MethodPost, url, constants.MIMEJSON, req)
if err != nil {
return nil, err
}
info := NetworkAddressPool{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}

View File

@@ -0,0 +1,51 @@
package adrspools
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// DeleteRequest struct to delete address pool
type DeleteRequest struct {
// Address pool ID
// Required: true
AddressPoolID string `url:"address_pool_id" json:"address_pool_id" validate:"required"`
// Version ID
// Required: true
VersionID uint64 `url:"version_id" json:"version_id" validate:"required"`
// Force delete
// Required: false
Force interface{} `url:"force,omitempty" json:"force,omitempty" validate:"omitempty,isBool"`
}
// Delete an address pool
func (i AddressPools) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/address_pool/delete"
res, err := i.client.DecortApiCallCtype(ctx, http.MethodDelete, url, constants.MIMEJSON, req)
if err != nil {
return false, err
}
if string(res) == "" {
return true, nil
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,42 @@
package adrspools
// FilterByID returns AddressPoolsList with specified ID.
func (agl AddressPoolsList) FilterByID(id string) AddressPoolsList {
predicate := func(ia NetworkAddressPool) bool {
return ia.ID == id
}
return agl.FilterFunc(predicate)
}
// FilterByName returns AddressPoolsList with specified Name.
func (agl AddressPoolsList) FilterByName(name string) AddressPoolsList {
predicate := func(ia NetworkAddressPool) bool {
return ia.Name == name
}
return agl.FilterFunc(predicate)
}
// FilterFunc allows filtering AddressPoolsList based on a user-specified predicate.
func (agl AddressPoolsList) FilterFunc(predicate func(NetworkAddressPool) bool) AddressPoolsList {
var result AddressPoolsList
for _, acc := range agl.Pools {
if predicate(acc) {
result.Pools = append(result.Pools, acc)
}
}
return result
}
// FindOne returns first element.
// If none was found, returns an empty struct.
func (agl AddressPoolsList) FindOne() NetworkAddressPool {
if len(agl.Pools) == 0 {
return NetworkAddressPool{}
}
return agl.Pools[0]
}

View File

@@ -0,0 +1,151 @@
package adrspools
import (
"testing"
)
var testAddressPools = AddressPoolsList{
Pools: []NetworkAddressPool{
{
ID: "pool1",
Name: "DevelopersPool",
Description: "First pool",
CreatedAt: "2023-01-01",
AccessGroupID: "group1",
AccessGroupName: "Developers",
NetAddressType: "IPv4",
NetAddresses: []NetworkAddress{
{
ID: "addr1",
IPAddr: "192.168.1.1",
NetAddressType: "IPv4",
NetAddressPoolID: "pool1",
},
},
PoolCounters: PoolCounters{
SecurityRules: 5,
},
VersionID: 1,
},
{
ID: "pool2",
Name: "AdminsPool",
Description: "Second pool",
CreatedAt: "2023-01-02",
AccessGroupID: "group2",
AccessGroupName: "Admins",
NetAddressType: "IPv4",
NetAddresses: []NetworkAddress{
{
ID: "addr2",
IPAddr: "192.168.1.2",
NetAddressType: "IPv4",
NetAddressPoolID: "pool2",
},
},
PoolCounters: PoolCounters{
SecurityRules: 3,
},
VersionID: 2,
},
{
ID: "pool3",
Name: "UsersPool",
Description: "Third pool",
CreatedAt: "2023-01-03",
AccessGroupID: "group3",
AccessGroupName: "Users",
NetAddressType: "IPv6",
NetAddresses: []NetworkAddress{
{
ID: "addr3",
IPAddr: "2001:db8::1",
NetAddressType: "IPv6",
NetAddressPoolID: "pool3",
},
},
PoolCounters: PoolCounters{
SecurityRules: 7,
},
VersionID: 3,
},
},
}
func TestFilterByID(t *testing.T) {
actual := testAddressPools.FilterByID("pool2").FindOne()
if actual.ID != "pool2" {
t.Fatal("actual:", actual.ID, "> expected: pool2")
}
}
func TestFilterByName(t *testing.T) {
actual := testAddressPools.FilterByName("UsersPool").FindOne()
if actual.Name != "UsersPool" {
t.Fatal("actual:", actual.Name, ">> expected: UsersPool")
}
}
func TestFilterFunc(t *testing.T) {
actual := testAddressPools.FilterFunc(func(ap NetworkAddressPool) bool {
return ap.Description == "Second pool"
})
if len(actual.Pools) != 1 || actual.Pools[0].ID != "pool2" {
t.Fatal("Expected 1 pool with description 'Second pool', found:", len(actual.Pools))
}
}
func TestFindOneWithResults(t *testing.T) {
result := testAddressPools.FilterByID("pool1").FindOne()
if result.ID != "pool1" {
t.Fatal("Expected pool1, got:", result.ID)
}
}
func TestFindOneEmpty(t *testing.T) {
emptyList := AddressPoolsList{}
result := emptyList.FindOne()
if result.ID != "" || result.Name != "" {
t.Fatal("Expected empty NetworkAddressPool, got:", result)
}
}
func TestFilterByIDNotFound(t *testing.T) {
actual := testAddressPools.FilterByID("nonexistent")
if len(actual.Pools) != 0 {
t.Fatal("Expected 0 pools, found:", len(actual.Pools))
}
}
func TestFilterByNameNotFound(t *testing.T) {
actual := testAddressPools.FilterByName("Nonexistent Pool")
if len(actual.Pools) != 0 {
t.Fatal("Expected 0 pools, found:", len(actual.Pools))
}
}
func TestFilterByNetAddressType(t *testing.T) {
actual := testAddressPools.FilterFunc(func(ap NetworkAddressPool) bool {
return ap.NetAddressType == "IPv6"
})
if len(actual.Pools) != 1 || actual.Pools[0].ID != "pool3" {
t.Fatal("Expected 1 pool with IPv6 type, found:", len(actual.Pools))
}
}
func TestFilterBySecurityRulesCount(t *testing.T) {
actual := testAddressPools.FilterFunc(func(ap NetworkAddressPool) bool {
return ap.PoolCounters.SecurityRules > 4
})
if len(actual.Pools) != 2 {
t.Fatal("Expected 2 pools with more than 4 security rules, found:", len(actual.Pools))
}
}

47
pkg/sdn/adrspools/get.go Normal file
View File

@@ -0,0 +1,47 @@
package adrspools
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// GetRequest struct to get information about address group
type GetRequest struct {
// ID an address group
// Required: true
ID string `url:"address_pool_id" json:"address_pool_id" validate:"required"`
}
// Get gets address pool details as a NetworkAddressPool struct
func (a AddressPools) Get(ctx context.Context, req GetRequest) (*NetworkAddressPool, error) {
res, err := a.GetRaw(ctx, req)
if err != nil {
return nil, err
}
info := NetworkAddressPool{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}
// GetRaw gets address pool details as an array of bytes
func (a AddressPools) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) {
err := validators.ValidateRequest(req)
if err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/address_pool/get"
res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req)
return res, err
}

10
pkg/sdn/adrspools/ids.go Normal file
View File

@@ -0,0 +1,10 @@
package adrspools
// IDs gets array of IDs from AddressPoolsList struct
func (agl AddressPoolsList) IDs() []string {
res := make([]string, 0, len(agl.Pools))
for _, c := range agl.Pools {
res = append(res, c.ID)
}
return res
}

92
pkg/sdn/adrspools/list.go Normal file
View File

@@ -0,0 +1,92 @@
package adrspools
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// ListAddressPoolsRequest struct to get a list of a groups
type ListAddressPoolsRequest struct {
// Filter by access group ID
// Required: false
AccessGroupID string `url:"access_group_id,omitempty" json:"access_group_id,omitempty"`
// Filter by name
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Filter by minimum address count (greater than or equal to)
// Required: false
AddrNumberMin uint64 `url:"addr_number_min,omitempty" json:"addr_number_min,omitempty"`
// Filter by maximum address count (less than)
// Required: false
AddrNumberMax uint64 `url:"addr_number_max,omitempty" json:"addr_number_max,omitempty"`
// Updated at lower bound (greater than or equal to)
// Required: false
UpdatedFrom string `url:"updated_from,omitempty" json:"updated_from,omitempty"`
// Updated at upper bound (less than)
// Required: false
UpdatedTo string `url:"updated_to,omitempty" json:"updated_to,omitempty"`
// Created at lower bound (greater than or equal to)
// Required: false
CreatedFrom string `url:"created_from,omitempty" json:"created_from,omitempty"`
// Created at upper bound (less than)
// Required: false
CreatedTo string `url:"created_to,omitempty" json:"created_to,omitempty"`
// Page number for pagination
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Number of results per page
// Required: false
PerPage uint64 `url:"per_page,omitempty" json:"per_page,omitempty"`
// Field to sort by (name, addr_count, created_at, updated_at)
// Required: false
SortBy string `url:"sort_by,omitempty" json:"sort_by,omitempty"`
// Sort order (asc/desc)
// Required: false
SortOrder string `url:"sort_order,omitempty" json:"sort_order,omitempty"`
}
// List of address pools
func (i AddressPools) List(ctx context.Context, req ListAddressPoolsRequest) (*AddressPoolsList, error) {
res, err := i.ListRaw(ctx, req)
if err != nil {
return nil, err
}
pools := []NetworkAddressPool{}
err = json.Unmarshal(res, &pools)
if err != nil {
return nil, err
}
result := AddressPoolsList{Pools: pools}
return &result, nil
}
// ListRaw gets a list of all address pools as an array of bytes
func (a AddressPools) ListRaw(ctx context.Context, req ListAddressPoolsRequest) ([]byte, error) {
if err := validators.ValidateRequest(req); err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/access_group/list"
res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req)
return res, err
}

View File

@@ -0,0 +1,62 @@
package adrspools
type AddressPoolsList struct {
Pools []NetworkAddressPool
}
// Main information about network address pool
type NetworkAddressPool struct {
// Access group ID
AccessGroupID string `json:"access_group_id"`
// Access group name
AccessGroupName string `json:"access_group_name"`
// Created time
CreatedAt string `json:"created_at"`
// Updated time
UpdatedAt string `json:"updated_at"`
// Description
Description string `json:"description"`
// ID
ID string `json:"id"`
// Name
Name string `json:"name"`
// Network address type
NetAddressType string `json:"net_address_type"`
// List of network addresses
NetAddresses []NetworkAddress `json:"net_addresses"`
// Pool counters
PoolCounters PoolCounters `json:"pool_counters"`
// Version ID
VersionID uint64 `json:"version_id"`
}
// Network address information
type NetworkAddress struct {
// ID
ID string `json:"id"`
// IP address
IPAddr string `json:"ip_addr"`
// Network address type
NetAddressType string `json:"net_address_type"`
// Network address pool ID
NetAddressPoolID string `json:"net_address_pool_id"`
}
// Pool counters information
type PoolCounters struct {
// Security rules count
SecurityRules uint64 `json:"security_rules"`
}

View File

@@ -0,0 +1,43 @@
package adrspools
import (
"encoding/json"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/serialization"
)
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
//
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (la AddressPoolsList) Serialize(params ...string) (serialization.Serialized, error) {
if len(la.Pools) == 0 {
return []byte{}, nil
}
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(la, prefix, indent)
}
return json.Marshal(la)
}
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
//
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (ia NetworkAddressPool) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(ia, prefix, indent)
}
return json.Marshal(ia)
}

View File

@@ -0,0 +1,84 @@
package adrspools
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// UpdateRequest struct to update address pool
type UpdateRequest struct {
// ID of the address pool
// Required: true
AddressPoolID string `url:"address_pool_id" json:"address_pool_id" validate:"required"`
// ID of the version
// Required: true
VersionID uint64 `url:"version_id" json:"version_id" validate:"required"`
// Description of the network
// Required: true
Description string `url:"description" json:"description" validate:"required"`
// Name of the network
// Required: true
Name string `url:"name" json:"name" validate:"required"`
// Network address type
// Required: true
NetAddressType string `url:"net_address_type" json:"net_address_type" validate:"required,addressPoolNetTypeValidator"`
// List of network addresses
// Required: false
NetAddresses []UpdateNetAddress `url:"net_addresses,omitempty" json:"net_addresses,omitempty" validate:"dive"`
}
// UpdateNetAddress struct representing network address
type UpdateNetAddress struct {
// Network address type
// Required: true
NetAddressType string `url:"net_address_type" json:"net_address_type" validate:"required,addressPoolNetTypeValidator"`
// IP address
// Required: true
IPAddr string `url:"ip_addr" json:"ip_addr" validate:"required"`
// End of IP address range
// Required: false
IPAddrRangeEnd string `url:"ip_addr_range_end,omitempty" json:"ip_addr_range_end,omitempty"`
// IP prefix
// Required: false
IPPrefix string `url:"ip_prefix,omitempty" json:"ip_prefix,omitempty"`
// MAC address
// Required: false
MACAddr string `url:"mac_addr,omitempty" json:"mac_addr,omitempty"`
}
// Update updates a address pool
func (i AddressPools) Update(ctx context.Context, req UpdateRequest) (*NetworkAddressPool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/address_pool/update"
res, err := i.client.DecortApiCallCtype(ctx, http.MethodPut, url, constants.MIMEJSON, req)
if err != nil {
return nil, err
}
info := NetworkAddressPool{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}