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 default secirity policies
package defsecpolicies
import (
"repository.basistech.ru/BASIS/decort-golang-sdk/interfaces"
)
// Structure for creating request to default security policies
type DefaultSecurityPolicies struct {
client interfaces.Caller
}
// Builder for adress pools endpoints
func New(client interfaces.Caller) *DefaultSecurityPolicies {
return &DefaultSecurityPolicies{
client,
}
}

View File

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

View File

@@ -0,0 +1,268 @@
package defsecpolicies
import (
"testing"
)
var testSecurityPolicies = SecurityPoliciesList{
Policies: []SecurityPolicy{
{
ID: "policy1",
DisplayName: "DevelopersPolicy",
Description: "First policy",
CreatedAt: "2023-01-01T00:00:00Z",
UpdatedAt: "2023-01-01T01:00:00Z",
AccessGroupID: "group1",
DefaultACLDrop: "DROP",
DefaultOpenSessionDrop: true,
SecurityRules: []SecurityRule{
{
ID: "rule1",
DisplayName: "DevRule1",
Action: "ALLOW",
Direction: "INGRESS",
Enabled: true,
Priority: 100,
SecurityPolicyID: "policy1",
VersionID: 1,
},
},
Status: Status{
Common: "ACTIVE",
Hypervisors: []HypervisorStatus{
{
Name: "hv1",
DisplayName: "Hypervisor1",
Status: "SYNCED",
HypervisorStatus: "HEALTHY",
SyncedAt: "2023-01-01T01:00:00Z",
},
},
},
VersionID: 1,
},
{
ID: "policy2",
DisplayName: "AdminsPolicy",
Description: "Second policy",
CreatedAt: "2023-01-02T00:00:00Z",
UpdatedAt: "2023-01-02T01:00:00Z",
AccessGroupID: "group2",
DefaultACLDrop: "REJECT",
DefaultOpenSessionDrop: false,
SecurityRules: []SecurityRule{
{
ID: "rule2",
DisplayName: "AdminRule1",
Action: "DENY",
Direction: "EGRESS",
Enabled: true,
Priority: 50,
SecurityPolicyID: "policy2",
VersionID: 1,
},
},
Status: Status{
Common: "ACTIVE",
Hypervisors: []HypervisorStatus{
{
Name: "hv2",
DisplayName: "Hypervisor2",
Status: "SYNCED",
HypervisorStatus: "HEALTHY",
SyncedAt: "2023-01-02T01:00:00Z",
},
},
},
VersionID: 2,
},
{
ID: "policy3",
DisplayName: "UsersPolicy",
Description: "Third policy",
CreatedAt: "2023-01-03T00:00:00Z",
UpdatedAt: "2023-01-03T01:00:00Z",
AccessGroupID: "group3",
DefaultACLDrop: "DROP",
DefaultOpenSessionDrop: true,
SecurityRules: []SecurityRule{
{
ID: "rule3",
DisplayName: "UserRule1",
Action: "ALLOW",
Direction: "INGRESS",
Enabled: false,
Priority: 200,
SecurityPolicyID: "policy3",
VersionID: 1,
},
},
Status: Status{
Common: "PENDING",
Hypervisors: []HypervisorStatus{
{
Name: "hv3",
DisplayName: "Hypervisor3",
Status: "SYNCING",
HypervisorStatus: "HEALTHY",
SyncedAt: "2023-01-03T01:00:00Z",
},
},
},
VersionID: 3,
},
},
}
func TestFilterByID(t *testing.T) {
actual := testSecurityPolicies.FilterByID("policy2").FindOne()
if actual.ID != "policy2" {
t.Fatal("actual:", actual.ID, "> expected: policy2")
}
}
func TestFilterByDisplayName(t *testing.T) {
actual := testSecurityPolicies.FilterByName("UsersPolicy").FindOne()
if actual.DisplayName != "UsersPolicy" {
t.Fatal("actual:", actual.DisplayName, ">> expected: UsersPolicy")
}
}
func TestFilterFunc(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.Description == "Second policy"
})
if len(actual.Policies) != 1 || actual.Policies[0].ID != "policy2" {
t.Fatal("Expected 1 policy with description 'Second policy', found:", len(actual.Policies))
}
}
func TestFindOneWithResults(t *testing.T) {
result := testSecurityPolicies.FilterByID("policy1").FindOne()
if result.ID != "policy1" {
t.Fatal("Expected policy1, got:", result.ID)
}
}
func TestFindOneEmpty(t *testing.T) {
emptyList := SecurityPoliciesList{}
result := emptyList.FindOne()
if result.ID != "" || result.DisplayName != "" {
t.Fatal("Expected empty SecurityPolicy, got:", result)
}
}
func TestFilterByIDNotFound(t *testing.T) {
actual := testSecurityPolicies.FilterByID("nonexistent")
if len(actual.Policies) != 0 {
t.Fatal("Expected 0 policies, found:", len(actual.Policies))
}
}
func TestFilterByDisplayNameNotFound(t *testing.T) {
actual := testSecurityPolicies.FilterByName("Nonexistent Policy")
if len(actual.Policies) != 0 {
t.Fatal("Expected 0 policies, found:", len(actual.Policies))
}
}
func TestFilterByDefaultACLDrop(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.DefaultACLDrop == "DROP"
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with DROP default ACL, found:", len(actual.Policies))
}
}
func TestFilterByDefaultOpenSessionDrop(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.DefaultOpenSessionDrop == true
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with default open session drop enabled, found:", len(actual.Policies))
}
}
func TestFilterByStatus(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.Status.Common == "ACTIVE"
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with ACTIVE status, found:", len(actual.Policies))
}
}
func TestFilterByAccessGroupID(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.AccessGroupID == "group1"
})
if len(actual.Policies) != 1 || actual.Policies[0].ID != "policy1" {
t.Fatal("Expected 1 policy with access group ID 'group1', found:", len(actual.Policies))
}
}
func TestFilterByRuleAction(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
for _, rule := range sp.SecurityRules {
if rule.Action == "ALLOW" {
return true
}
}
return false
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with ALLOW rules, found:", len(actual.Policies))
}
}
func TestFilterByRuleDirection(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
for _, rule := range sp.SecurityRules {
if rule.Direction == "INGRESS" {
return true
}
}
return false
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with INGRESS rules, found:", len(actual.Policies))
}
}
func TestFilterByRuleEnabled(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
for _, rule := range sp.SecurityRules {
if rule.Enabled {
return true
}
}
return false
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with enabled rules, found:", len(actual.Policies))
}
}
func TestFilterByVersionID(t *testing.T) {
actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicy) bool {
return sp.VersionID > 1
})
if len(actual.Policies) != 2 {
t.Fatal("Expected 2 policies with version ID > 1, found:", len(actual.Policies))
}
}

View File

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

View File

@@ -0,0 +1,64 @@
package defsecpolicies
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/validators"
)
// ListRequest struct to get a list of default security group
type ListRequest struct {
// Filter by access group ID
// Required: false
AccessGroupID string `url:"access_group_id,omitempty" json:"access_group_id,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 default security policies
func (i DefaultSecurityPolicies) List(ctx context.Context, req ListRequest) (*SecurityPoliciesList, error) {
res, err := i.ListRaw(ctx, req)
if err != nil {
return nil, err
}
policies := []SecurityPolicy{}
err = json.Unmarshal(res, &policies)
if err != nil {
return nil, err
}
result := SecurityPoliciesList{Policies: policies}
return &result, nil
}
// ListRaw gets a list of all default security policies as an array of bytes
func (a DefaultSecurityPolicies) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) {
if err := validators.ValidateRequest(req); err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/default_security_policy/list"
res, err := a.client.DecortApiCall(ctx, http.MethodGet, url, req)
return res, err
}

View File

@@ -0,0 +1,191 @@
package defsecpolicies
type SecurityPoliciesList struct {
Policies []SecurityPolicy `json:"policies"`
}
// Main information about security policy
type SecurityPolicy struct {
// Access group ID
AccessGroupID string `json:"access_group_id"`
// Created time
CreatedAt string `json:"created_at"`
// Default ACL drop behavior
DefaultACLDrop string `json:"default_acl_drop"`
// Default open session drop flag
DefaultOpenSessionDrop bool `json:"default_open_session_drop"`
// Description
Description string `json:"description"`
// Display name
DisplayName string `json:"display_name"`
// ID
ID string `json:"id"`
// Security rules
SecurityRules []SecurityRule `json:"security_rules"`
// Locked time
LockedAt string `json:"locked_at"`
// Status information
Status Status `json:"status"`
// Version ID
VersionID uint64 `json:"version_id"`
// Updated time
UpdatedAt string `json:"updated_at"`
}
// Security rule information
type SecurityRule struct {
// Access group ID
AccessGroupID string `json:"access_group_id"`
// Action
Action string `json:"action"`
// Description
Description string `json:"description"`
// Destination network object
DestinationNetObject NetObject `json:"destination_net_object"`
// Direction
Direction string `json:"direction"`
// Display name
DisplayName string `json:"display_name"`
// Enabled flag
Enabled bool `json:"enabled"`
// Filter configuration
Filter Filter `json:"filter"`
// ID
ID string `json:"id"`
// Log enabled flag
LogEnabled bool `json:"log_enabled"`
// Log name
LogName string `json:"log_name"`
// Log severity
LogSeverity string `json:"log_severity"`
// Priority
Priority int `json:"priority"`
// Security policy ID
SecurityPolicyID string `json:"security_policy_id"`
// Source network object
SourceNetObject NetObject `json:"source_net_object"`
// Statistics enabled flag
StatisticsEnabled bool `json:"statistics_enabled"`
// Version ID
VersionID uint64 `json:"version_id"`
}
// Network object information
type NetObject struct {
// Display name
DisplayName string `json:"display_name"`
// Network address pool ID
NetAddressPoolID string `json:"net_address_pool_id"`
// Network object group ID
NetObjectGroupID string `json:"net_object_group_id"`
}
// Filter configuration
type Filter struct {
// Filter parameters
Filters FilterParams `json:"filters"`
// Name
Name string `json:"name"`
}
// Filter parameters
type FilterParams struct {
// All protocols flag
All bool `json:"all"`
// ARP protocol flag
ARP bool `json:"arp"`
// DHCP protocol flag
DHCP bool `json:"dhcp"`
// Filter expression
Expression string `json:"expression"`
// ICMP protocol flag
ICMP bool `json:"icmp"`
// IP protocol flag
IP bool `json:"ip"`
// IPv4 protocol flag
IPv4 bool `json:"ip_v4"`
// IPv6 protocol flag
IPv6 bool `json:"ip_v6"`
// Keep opened sessions flag
KeepOpenedSessions bool `json:"keep_opened_sessions"`
// ND protocol flag
ND bool `json:"nd"`
// TCP protocol flag
TCP bool `json:"tcp"`
// TCP destination ports
TCPDstPorts []string `json:"tcp_dst_ports"`
// UDP protocol flag
UDP bool `json:"udp"`
// UDP destination ports
UDPDstPorts []string `json:"udp_dst_ports"`
}
// Status information
type Status struct {
// Common status
Common string `json:"common"`
// Hypervisor statuses
Hypervisors []HypervisorStatus `json:"hypervisors"`
}
// Hypervisor status information
type HypervisorStatus struct {
// Status
Status string `json:"status"`
// Name
Name string `json:"name"`
// Display name
DisplayName string `json:"display_name"`
// Hypervisor status
HypervisorStatus string `json:"hypervisor_status"`
// Last sync time
SyncedAt string `json:"synced_at"`
}

View File

@@ -0,0 +1,43 @@
package defsecpolicies
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 SecurityPoliciesList) Serialize(params ...string) (serialization.Serialized, error) {
if len(la.Policies) == 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 SecurityPolicy) 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,53 @@
package defsecpolicies
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 default security policy
type UpdateRequest struct {
// ID of the access group
// Required: true
AccessGroupID string `url:"access_group_id" json:"access_group_id" validate:"required"`
// ID of the version
// Required: true
VersionID uint64 `url:"version_id" json:"version_id" validate:"required"`
// Default ACL drop behavior
// Required: false
DefaultACLDrop string `url:"default_acl_drop,omitempty" json:"default_acl_drop,omitempty"`
// Default open session drop flag
// Required: false
DefaultOpenSessionDrop bool `url:"default_open_session_drop,omitempty" json:"default_open_session_drop,omitempty"`
}
// Update updates a default security policy
func (i DefaultSecurityPolicies) Update(ctx context.Context, req UpdateRequest) (*SecurityPolicy, error) {
err := validators.ValidateRequest(req)
if err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/sdn/default_security_policy/update"
res, err := i.client.DecortApiCallCtype(ctx, http.MethodPatch, url, constants.MIMEJSON, req)
if err != nil {
return nil, err
}
info := SecurityPolicy{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}