diff --git a/availability_zones.go b/availability_zones.go new file mode 100644 index 00000000..efa5c241 --- /dev/null +++ b/availability_zones.go @@ -0,0 +1,51 @@ +package edgecloud + +import ( + "context" + "net/http" +) + +const ( + AvailabilityZoneBasePath = "/v1/availability_zones" +) + +// AvailabilityZonesService is an interface for managing Availability Zones with the EdgecenterCloud API. +// See: https://apidocs.edgecenter.ru/cloud#tag/Availability-Zones +type AvailabilityZonesService interface { + List(context.Context) (*AvailabilityZonesList, *Response, error) +} + +// AvailabilityZonesServiceOp handles communication with Availability Zones methods of the EdgecenterCloud API. +type AvailabilityZonesServiceOp struct { + client *Client +} + +var _ AvailabilityZonesService = &AvailabilityZonesServiceOp{} + +// AvailabilityZonesList represents an EdgecenterCloud availability zones list. +type AvailabilityZonesList struct { + RegionID int `json:"region_id"` + AvailabilityZones []string `json:"availability_zones"` +} + +// List get availability zones in a region. +func (s *AvailabilityZonesServiceOp) List(ctx context.Context) (*AvailabilityZonesList, *Response, error) { + if resp, err := s.client.ValidateRegion(); err != nil { + return nil, resp, err + } + + path := s.client.addRegionPath(AvailabilityZoneBasePath) + + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + az := new(AvailabilityZonesList) + resp, err := s.client.Do(ctx, req, az) + if err != nil { + return nil, resp, err + } + + return az, resp, nil +} diff --git a/availability_zones_test.go b/availability_zones_test.go new file mode 100644 index 00000000..86acdab7 --- /dev/null +++ b/availability_zones_test.go @@ -0,0 +1,74 @@ +package edgecloud + +import ( + "encoding/json" + "fmt" + "net/http" + "path" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAvailabilityZonesServiceOp_List(t *testing.T) { + setup() + defer teardown() + + client.Project = 0 + URL := path.Join(AvailabilityZoneBasePath, strconv.Itoa(regionID)) + expResp := AvailabilityZonesList{ + RegionID: regionID, + AvailabilityZones: []string{"availability-zone-1", "availability-zone-2"}, + } + + mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + resp, err := json.Marshal(expResp) + if err != nil { + t.Errorf("failed to marshal response: %v", err) + } + _, err = w.Write(resp) + if err != nil { + t.Errorf("failed to write response: %v", err) + } + }) + + respActual, resp, err := client.AvailabilityZones.List(ctx) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, expResp, *respActual) +} + +func TestAvailabilityZonesServiceOp_List_NotFoundError(t *testing.T) { + setup() + defer teardown() + + URL := path.Join(AvailabilityZoneBasePath, strconv.Itoa(regionID)) + + mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + w.WriteHeader(http.StatusNotFound) + _, _ = fmt.Fprint(w, "Region not found") + }) + + respActual, resp, err := client.AvailabilityZones.List(ctx) + assert.Nil(t, respActual) + assert.Error(t, err) + assert.Equal(t, http.StatusNotFound, resp.StatusCode) +} + +func TestAvailabilityZonesServiceOp_List_ClientWithoutRegion(t *testing.T) { + setup() + defer teardown() + + client.Region = 0 + expectedError := NewArgError("Client.Region", "is not set") + + respActual, resp, err := client.AvailabilityZones.List(ctx) + assert.Nil(t, respActual) + assert.Error(t, err) + assert.Equal(t, err, expectedError) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) +} diff --git a/e2e/cloud/mkaas/mkaas_test.go b/e2e/cloud/mkaas/mkaas_test.go index 2ddc53bd..9ba641a5 100644 --- a/e2e/cloud/mkaas/mkaas_test.go +++ b/e2e/cloud/mkaas/mkaas_test.go @@ -39,7 +39,7 @@ type Config struct { var ( randomString, _ = util.GenerateRandomString(6, true, true, false) - clusterCreateRequest = edgecloud.MkaaSClusterCreateRequest{ + clusterCreateRequest = edgecloud.MKaaSClusterCreateRequest{ Name: fmt.Sprintf("Cluster_from_go_client_%s", randomString), ControlPlane: edgecloud.ControlPlaneCreateRequest{ Flavor: mkaaSE2EFlavor, @@ -48,7 +48,7 @@ var ( VolumeType: "", Version: "v1.31.0", }, - Pools: []edgecloud.MkaaSPoolCreateRequest{ + Pools: []edgecloud.MKaaSPoolCreateRequest{ { Name: fmt.Sprintf("pool_from_go_client_%s", randomString), Flavor: mkaaSE2EFlavor, @@ -61,7 +61,7 @@ var ( Taints: nil, }, }} - poolCreateRequest = edgecloud.MkaaSPoolCreateRequest{ + poolCreateRequest = edgecloud.MKaaSPoolCreateRequest{ Name: "pool-create", Flavor: mkaaSE2EFlavor, NodeCount: 3, @@ -72,13 +72,13 @@ var ( Taints: nil, } - increaseNodeCountRequest = edgecloud.MkaaSPoolUpdateRequest{ + increaseNodeCountRequest = edgecloud.MKaaSPoolUpdateRequest{ NodeCount: edgecloud.PtrTo(4), MinNodeCount: edgecloud.PtrTo(1), MaxNodeCount: edgecloud.PtrTo(5), } - decreaseNodeCountRequest = edgecloud.MkaaSPoolUpdateRequest{ + decreaseNodeCountRequest = edgecloud.MKaaSPoolUpdateRequest{ NodeCount: edgecloud.PtrTo(1), MinNodeCount: edgecloud.PtrTo(1), MaxNodeCount: edgecloud.PtrTo(5), @@ -189,7 +189,7 @@ func (s *MkaasSuite) Test_CreateAndDeletePoolSimple() { s.Require().NoError(err) s.Assert().Equal(http.StatusOK, resp.StatusCode) s.Assert().Equal(len(clusterCreateRequest.Pools)+1, len(cluster.Pools)) - createdPool, found := lo.Find(cluster.Pools, func(pool edgecloud.MkaaSPool) bool { + createdPool, found := lo.Find(cluster.Pools, func(pool edgecloud.MKaaSPool) bool { return pool.Name == poolCreateRequest.Name }) s.Require().Equal(true, found) @@ -206,7 +206,7 @@ func (s *MkaasSuite) deleteCluster(clusterID int) { s.Assert().Equal(http.StatusOK, resp.StatusCode) } -func (s *MkaasSuite) createClusterAndWait(ctx context.Context, createRequest edgecloud.MkaaSClusterCreateRequest) { +func (s *MkaasSuite) createClusterAndWait(ctx context.Context, createRequest edgecloud.MKaaSClusterCreateRequest) { client := s.client s.T().Log("Creating cluster started") taskResponse, resp, err := client.MkaaS.ClusterCreate(ctx, createRequest) @@ -225,7 +225,7 @@ func (s *MkaasSuite) deletePoolAndWait(ctx context.Context, poolID int) { s.waitTaskWithLoggingAndSaveClusterID(ctx, taskResponse, poolDeleteTimeout, clusterCreateRequest.Name) } -func (s *MkaasSuite) updatePoolAndWait(ctx context.Context, poolID int, updatedPoolRequest edgecloud.MkaaSPoolUpdateRequest) { +func (s *MkaasSuite) updatePoolAndWait(ctx context.Context, poolID int, updatedPoolRequest edgecloud.MKaaSPoolUpdateRequest) { client := s.client s.T().Log("Updating pool started") taskResponse, resp, err := client.MkaaS.PoolUpdate(ctx, s.clusterID, poolID, updatedPoolRequest) @@ -254,7 +254,7 @@ func (s *MkaasSuite) waitTaskWithLoggingAndSaveClusterID(ctx context.Context, ta for !taskProcessed { time.Sleep(5 * time.Second) if s.clusterID == 0 { - clusters, resp, err := s.client.MkaaS.ClustersList(ctx, &edgecloud.MkaaSClusterListOptions{ + clusters, resp, err := s.client.MkaaS.ClustersList(ctx, &edgecloud.MKaaSClusterListOptions{ Name: clusterName, }) s.Assert().NoError(err) @@ -270,7 +270,7 @@ func (s *MkaasSuite) waitTaskWithLoggingAndSaveClusterID(ctx context.Context, ta s.T().Logf("task processed") } -func (s *MkaasSuite) changePoolsNodeCountTest(ctx context.Context, changeNodeCountRequest edgecloud.MkaaSPoolUpdateRequest) { +func (s *MkaasSuite) changePoolsNodeCountTest(ctx context.Context, changeNodeCountRequest edgecloud.MKaaSPoolUpdateRequest) { client := s.client cluster, resp, err := client.MkaaS.ClusterGet(ctx, s.clusterID) s.Require().NoError(err) diff --git a/edgecloud.go b/edgecloud.go index 8ef1c54c..07e98514 100644 --- a/edgecloud.go +++ b/edgecloud.go @@ -79,7 +79,7 @@ type Client struct { ResellerNetworks ResellerNetworksService ResellerImageV2 ResellerImageV2Service AvailabilityZones AvailabilityZonesService - MkaaS MkaaSService + MKaaS MKaaSService // Optional function called after every successful request made to the DO APIs onRequestCompleted RequestCompletionCallback @@ -259,7 +259,7 @@ func NewClient(httpClient *http.Client) *Client { c.ResellerNetworks = &ResellerNetworksServiceOp{client: c} c.ResellerImageV2 = &ResellerImageV2ServiceOp{client: c} c.AvailabilityZones = &AvailabilityZonesServiceOp{client: c} - c.MkaaS = &MkaasServiceOp{client: c} + c.MKaaS = &MKaaSServiceOp{client: c} c.headers = make(map[string]string) diff --git a/instances.go b/instances.go index 82ef2c69..3409e623 100644 --- a/instances.go +++ b/instances.go @@ -124,6 +124,7 @@ type Instance struct { TaskID string `json:"task_id"` TaskState string `json:"task_state,omitempty"` VMState string `json:"vm_state,omitempty"` // todo: need to implement new vm_state type + AvailabilityZone string `json:"availability_zone"` Volumes []InstanceVolume `json:"volumes"` } @@ -143,8 +144,8 @@ const ( // InstanceAddress represent an instance network struct. type InstanceAddress struct { Type string `json:"type"` - SubnetName string `json:"subnet_name"` - SubnetID string `json:"subnet_id"` + SubnetName string `json:"subnet_name,omitempty"` + SubnetID string `json:"subnet_id,omitempty"` Address net.IP `json:"addr"` } @@ -183,20 +184,21 @@ type InstanceVolumeCreate struct { // InstanceCreateRequest represents a request to create an Instance. type InstanceCreateRequest struct { - Names []string `json:"names,omitempty" validate:"required_without=NameTemplates"` - Flavor string `json:"flavor" required:"true"` - NameTemplates []string `json:"name_templates,omitempty" validate:"required_without=Names"` - KeypairName string `json:"keypair_name,omitempty"` - UserData string `json:"user_data,omitempty" validate:"omitempty,base64"` - Username string `json:"username,omitempty" validate:"omitempty,required_with=Password"` - Password string `json:"password,omitempty" validate:"omitempty,required_with=Username"` - Interfaces []InstanceInterface `json:"interfaces" required:"true" validate:"required,dive"` - SecurityGroups []ID `json:"security_groups,omitempty" validate:"omitempty,dive,uuid4"` - Metadata Metadata `json:"metadata,omitempty" validate:"omitempty,dive"` - Configuration map[string]interface{} `json:"configuration,omitempty" validate:"omitempty,dive"` - ServerGroupID string `json:"servergroup_id,omitempty" validate:"omitempty,uuid4"` - AllowAppPorts bool `json:"allow_app_ports,omitempty"` - Volumes []InstanceVolumeCreate `json:"volumes" required:"true" validate:"required,dive"` + Names []string `json:"names,omitempty" validate:"required_without=NameTemplates"` + Flavor string `json:"flavor" required:"true"` + NameTemplates []string `json:"name_templates,omitempty" validate:"required_without=Names"` + KeypairName string `json:"keypair_name,omitempty"` + UserData string `json:"user_data,omitempty" validate:"omitempty,base64"` + Username string `json:"username,omitempty" validate:"omitempty,required_with=Password"` + Password string `json:"password,omitempty" validate:"omitempty"` + Interfaces []InstanceInterface `json:"interfaces" required:"true" validate:"required,dive"` + SecurityGroups []ID `json:"security_groups,omitempty" validate:"omitempty,dive,uuid4"` + Metadata Metadata `json:"metadata,omitempty" validate:"omitempty,dive"` + Configuration map[string]interface{} `json:"configuration,omitempty" validate:"omitempty,dive"` + ServerGroupID string `json:"servergroup_id,omitempty" validate:"omitempty,uuid4"` + AvailabilityZone string `json:"availability_zone,omitempty" validate:"omitempty"` + AllowAppPorts bool `json:"allow_app_ports,omitempty"` + Volumes []InstanceVolumeCreate `json:"volumes" required:"true" validate:"required,dive"` } // InstanceDeleteOptions specifies the optional query parameters to Delete method. diff --git a/mkaas.go b/mkaas.go index d23e20a9..a5b0b845 100644 --- a/mkaas.go +++ b/mkaas.go @@ -7,57 +7,56 @@ import ( ) const ( - MkaaSClustersBasePathV2 = "/internal/mkaas/v2/clusters" + MKaaSClustersBasePathV2 = "/internal/mkaas/v2/clusters" ) -// MkaaSService is an interface for creating and managing mkaas clusters with the EdgecenterCloud API. +// MKaaSService is an interface for creating and managing mkaas clusters with the EdgecenterCloud API. // See: https://apidocs.edgecenter.ru/cloud#tag/mkaas -type MkaaSService interface { - MkaasClusters - MkaasPools +type MKaaSService interface { + MKaaSClusters + MKaaSPools } -type MkaasClusters interface { - ClusterCreate(context.Context, MkaaSClusterCreateRequest) (*TaskResponse, *Response, error) - ClustersList(context.Context, *MkaaSClusterListOptions) ([]MkaaSCluster, *Response, error) - ClusterGet(context.Context, int) (*MkaaSCluster, *Response, error) - ClusterUpdate(ctx context.Context, clusterID int, reqBody MkaaSClusterUpdateRequest) (*TaskResponse, *Response, error) +type MKaaSClusters interface { + ClusterCreate(context.Context, MKaaSClusterCreateRequest) (*TaskResponse, *Response, error) + ClustersList(context.Context, *MKaaSClusterListOptions) ([]MKaaSCluster, *Response, error) + ClusterGet(context.Context, int) (*MKaaSCluster, *Response, error) ClusterDelete(context.Context, int) (*TaskResponse, *Response, error) } -type MkaasPools interface { - PoolCreate(ctx context.Context, clusterID int, reqBody MkaaSPoolCreateRequest) (*TaskResponse, *Response, error) - PoolsList(ctx context.Context, clusterID int, opts *MkaaSPoolListOptions) ([]MkaaSPool, *Response, error) - PoolGet(ctx context.Context, clusterID, poolID int) (*MkaaSPool, *Response, error) - PoolUpdate(ctx context.Context, clusterID, poolID int, reqBody MkaaSPoolUpdateRequest) (*TaskResponse, *Response, error) +type MKaaSPools interface { + PoolCreate(ctx context.Context, clusterID int, reqBody MKaaSPoolCreateRequest) (*TaskResponse, *Response, error) + PoolsList(ctx context.Context, clusterID int, opts *MKaaSPoolListOptions) ([]MKaaSPool, *Response, error) + PoolGet(ctx context.Context, clusterID, poolID int) (*MKaaSPool, *Response, error) + PoolUpdate(ctx context.Context, clusterID, poolID int, reqBody MKaaSPoolUpdateRequest) (*TaskResponse, *Response, error) PoolDelete(ctx context.Context, clusterID, poolID int) (*TaskResponse, *Response, error) } -// MkaasServiceOp handles communication with mkaas methods of the EdgecenterCloud API. -type MkaasServiceOp struct { +// MKaaSServiceOp handles communication with mkaas methods of the EdgecenterCloud API. +type MKaaSServiceOp struct { client *Client } -var _ MkaaSService = &MkaasServiceOp{} +var _ MKaaSService = &MKaaSServiceOp{} -type MkaaSClustersRoot struct { +type MKaaSClustersRoot struct { Count int - Clusters []MkaaSCluster `json:"results"` + Clusters []MKaaSCluster `json:"results"` } -type MkaaSPoolsRoot struct { +type MKaaSPoolsRoot struct { Count int - Pools []MkaaSPool `json:"results"` + Pools []MKaaSPool `json:"results"` } -type MkaaSClusterListOptions struct { +type MKaaSClusterListOptions struct { Name string `url:"name,omitempty"` Status string `url:"status,omitempty"` Limit int `url:"limit,omitempty"` Offset int `url:"offset,omitempty"` } -type MkaaSClusterCreateRequest struct { +type MKaaSClusterCreateRequest struct { Name string `json:"name"` SSHKeyPairName string `json:"ssh_keypair_name"` NetworkID string `json:"network_id"` @@ -66,15 +65,16 @@ type MkaaSClusterCreateRequest struct { ServiceSubnet *string `json:"service_subnet,omitempty"` PublishKubeAPIToInternet bool `json:"publish_kube_api_to_internet"` ControlPlane ControlPlaneCreateRequest `json:"control_plane"` + Pools []MKaaSPoolCreateRequest `json:"pools"` } -type MkaaSClusterUpdateRequest struct { +type MKaaSClusterUpdateRequest struct { Name string `json:"name"` MasterNodeCount int `json:"master_node_count"` } -// MkaaSCluster represents an EdgecenterCloud MkaaS Cluster. -type MkaaSCluster struct { +// MKaaSCluster represents an EdgecenterCloud MKaaS Cluster. +type MKaaSCluster struct { ID int `json:"id"` RegionID int `json:"region_id"` ProjectID int `json:"project_id"` @@ -83,6 +83,7 @@ type MkaaSCluster struct { NetworkID string `json:"network_id"` SubnetID string `json:"subnet_id"` ControlPlane ControlPlane `json:"control_plane"` + Pools []MKaaSPool `json:"pools"` InternalIP string `json:"internal_ip"` ExternalIP string `json:"external_ip"` Existed string `json:"existed,omitempty"` // Duration string (e.g., "237h36m46.703341967s") @@ -111,67 +112,70 @@ type ControlPlane struct { Version string `json:"version"` } -type MkaaSPoolListOptions struct { +type MKaaSPoolListOptions struct { Name string `url:"name,omitempty"` Status string `url:"status,omitempty"` Limit int `url:"limit,omitempty"` Offset int `url:"offset,omitempty"` } -type MkaaSPoolCreateRequest struct { - Name string `json:"name,omitempty"` - Flavor string `json:"flavor,omitempty"` - MaxNodeCount *int `json:"max_node_count,omitempty"` - MinNodeCount *int `json:"min_node_count,omitempty"` - NodeCount int `json:"node_count,omitempty"` - VolumeSize int `json:"volume_size,omitempty"` - SecurityGroupID *string `json:"security_group_id,omitempty"` - VolumeType VolumeType `json:"volume_type,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - Taints []MkaaSTaint `json:"taints,omitempty"` +type MKaaSPoolCreateRequest struct { + Name string `json:"name,omitempty"` + Flavor string `json:"flavor,omitempty"` + MaxNodeCount *int `json:"max_node_count,omitempty"` + MinNodeCount *int `json:"min_node_count,omitempty"` + NodeCount int `json:"node_count,omitempty"` + VolumeSize int `json:"volume_size,omitempty"` + SecurityGroupID *string `json:"security_group_id,omitempty"` + VolumeType VolumeType `json:"volume_type,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Taints []MKaaSTaint `json:"taints,omitempty"` + SecurityGroupIds []string `json:"security_group_ids,omitempty"` } -type MkaaSPoolUpdateRequest struct { - Name *string `json:"name,omitempty"` - Flavor *string `json:"flavor,omitempty"` - MaxNodeCount *int `json:"max_node_count,omitempty"` - MinNodeCount *int `json:"min_node_count,omitempty"` - NodeCount *int `json:"node_count,omitempty"` - VolumeSize *int `json:"volume_size,omitempty"` - SecurityGroupID *string `json:"security_group_id,omitempty"` - VolumeType *VolumeType `json:"volume_type,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - Taints []MkaaSTaint `json:"taints,omitempty"` +type MKaaSPoolUpdateRequest struct { + Name *string `json:"name,omitempty"` + Flavor *string `json:"flavor,omitempty"` + MaxNodeCount *int `json:"max_node_count,omitempty"` + MinNodeCount *int `json:"min_node_count,omitempty"` + NodeCount *int `json:"node_count,omitempty"` + VolumeSize *int `json:"volume_size,omitempty"` + SecurityGroupID *string `json:"security_group_id,omitempty"` + VolumeType *VolumeType `json:"volume_type,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Taints []MKaaSTaint `json:"taints,omitempty"` + SecurityGroupIds []string `json:"security_group_ids,omitempty"` } -type MkaaSPool struct { - ID int `json:"id"` - Name string `json:"name"` - Flavor string `json:"flavor"` - MaxNodeCount int `json:"max_node_count"` - MinNodeCount int `json:"min_node_count"` - NodeCount int `json:"node_count"` - VolumeSize int `json:"volume_size"` - VolumeType VolumeType `json:"volume_type"` - Labels map[string]string `json:"labels"` - Taints []MkaaSTaint `json:"taints"` - State string `json:"state"` - Status string `json:"status"` +type MKaaSPool struct { + ID int `json:"id"` + Name string `json:"name"` + Flavor string `json:"flavor"` + MaxNodeCount int `json:"max_node_count"` + MinNodeCount int `json:"min_node_count"` + NodeCount int `json:"node_count"` + VolumeSize int `json:"volume_size"` + VolumeType VolumeType `json:"volume_type"` + Labels map[string]string `json:"labels"` + Taints []MKaaSTaint `json:"taints"` + State string `json:"state"` + Status string `json:"status"` + SecurityGroupIds []string `json:"security_group_ids"` } -// MkaaSTaint configuration for nodes. -type MkaaSTaint struct { +// MKaaSTaint configuration for nodes. +type MKaaSTaint struct { Key string `json:"key"` Value string `json:"value"` Effect string `json:"effect"` } -func (m *MkaasServiceOp) ClusterCreate(ctx context.Context, reqBody MkaaSClusterCreateRequest) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) ClusterCreate(ctx context.Context, reqBody MKaaSClusterCreateRequest) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := m.client.addProjectRegionPath(MkaaSClustersBasePathV2) + path := m.client.addProjectRegionPath(MKaaSClustersBasePathV2) req, err := m.client.NewRequest(ctx, http.MethodPost, path, reqBody) if err != nil { @@ -187,12 +191,12 @@ func (m *MkaasServiceOp) ClusterCreate(ctx context.Context, reqBody MkaaSCluster return tasks, resp, err } -func (m *MkaasServiceOp) ClustersList(ctx context.Context, opts *MkaaSClusterListOptions) ([]MkaaSCluster, *Response, error) { +func (m *MKaaSServiceOp) ClustersList(ctx context.Context, opts *MKaaSClusterListOptions) ([]MKaaSCluster, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := m.client.addProjectRegionPath(MkaaSClustersBasePathV2) + path := m.client.addProjectRegionPath(MKaaSClustersBasePathV2) path, err := addOptions(path, opts) if err != nil { return nil, nil, err @@ -203,7 +207,7 @@ func (m *MkaasServiceOp) ClustersList(ctx context.Context, opts *MkaaSClusterLis return nil, nil, err } - root := new(MkaaSClustersRoot) + root := new(MKaaSClustersRoot) resp, err := m.client.Do(ctx, req, root) if err != nil { return nil, resp, err @@ -212,19 +216,19 @@ func (m *MkaasServiceOp) ClustersList(ctx context.Context, opts *MkaaSClusterLis return root.Clusters, resp, err } -func (m *MkaasServiceOp) ClusterGet(ctx context.Context, clusterID int) (*MkaaSCluster, *Response, error) { +func (m *MKaaSServiceOp) ClusterGet(ctx context.Context, clusterID int) (*MKaaSCluster, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID) + path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID) req, err := m.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } - cluster := new(MkaaSCluster) + cluster := new(MKaaSCluster) resp, err := m.client.Do(ctx, req, cluster) if err != nil { return nil, resp, err @@ -233,12 +237,14 @@ func (m *MkaasServiceOp) ClusterGet(ctx context.Context, clusterID int) (*MkaaSC return cluster, resp, err } -func (m *MkaasServiceOp) ClusterUpdate(ctx context.Context, clusterID int, reqBody MkaaSClusterUpdateRequest) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) ClusterUpdate(ctx context.Context, clusterID int, + reqBody MKaaSClusterUpdateRequest, +) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID) + path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID) req, err := m.client.NewRequest(ctx, http.MethodPatch, path, reqBody) if err != nil { @@ -254,12 +260,12 @@ func (m *MkaasServiceOp) ClusterUpdate(ctx context.Context, clusterID int, reqBo return tasks, resp, err } -func (m *MkaasServiceOp) ClusterDelete(ctx context.Context, clusterID int) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) ClusterDelete(ctx context.Context, clusterID int) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID) + path := fmt.Sprintf("%s/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID) req, err := m.client.NewRequest(ctx, http.MethodDelete, path, nil) if err != nil { @@ -275,12 +281,12 @@ func (m *MkaasServiceOp) ClusterDelete(ctx context.Context, clusterID int) (*Tas return tasks, resp, err } -func (m *MkaasServiceOp) PoolCreate(ctx context.Context, clusterID int, reqBody MkaaSPoolCreateRequest) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) PoolCreate(ctx context.Context, clusterID int, reqBody MKaaSPoolCreateRequest) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d/pools", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID) + path := fmt.Sprintf("%s/%d/pools", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID) req, err := m.client.NewRequest(ctx, http.MethodPost, path, reqBody) if err != nil { @@ -296,12 +302,12 @@ func (m *MkaasServiceOp) PoolCreate(ctx context.Context, clusterID int, reqBody return tasks, resp, err } -func (m *MkaasServiceOp) PoolUpdate(ctx context.Context, clusterID, poolID int, reqBody MkaaSPoolUpdateRequest) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) PoolUpdate(ctx context.Context, clusterID, poolID int, reqBody MKaaSPoolUpdateRequest) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID, poolID) + path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID, poolID) req, err := m.client.NewRequest(ctx, http.MethodPatch, path, reqBody) if err != nil { @@ -317,12 +323,12 @@ func (m *MkaasServiceOp) PoolUpdate(ctx context.Context, clusterID, poolID int, return tasks, resp, err } -func (m *MkaasServiceOp) PoolsList(ctx context.Context, clusterID int, opts *MkaaSPoolListOptions) ([]MkaaSPool, *Response, error) { +func (m *MKaaSServiceOp) PoolsList(ctx context.Context, clusterID int, opts *MKaaSPoolListOptions) ([]MKaaSPool, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d/pools", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID) + path := fmt.Sprintf("%s/%d/pools", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID) path, err := addOptions(path, opts) if err != nil { return nil, nil, err @@ -333,7 +339,7 @@ func (m *MkaasServiceOp) PoolsList(ctx context.Context, clusterID int, opts *Mka return nil, nil, err } - root := new(MkaaSPoolsRoot) + root := new(MKaaSPoolsRoot) resp, err := m.client.Do(ctx, req, root) if err != nil { return nil, resp, err @@ -342,19 +348,19 @@ func (m *MkaasServiceOp) PoolsList(ctx context.Context, clusterID int, opts *Mka return root.Pools, resp, err } -func (m *MkaasServiceOp) PoolGet(ctx context.Context, clusterID, poolID int) (*MkaaSPool, *Response, error) { +func (m *MKaaSServiceOp) PoolGet(ctx context.Context, clusterID, poolID int) (*MKaaSPool, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID, poolID) + path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID, poolID) req, err := m.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } - pool := new(MkaaSPool) + pool := new(MKaaSPool) resp, err := m.client.Do(ctx, req, pool) if err != nil { return nil, resp, err @@ -363,12 +369,12 @@ func (m *MkaasServiceOp) PoolGet(ctx context.Context, clusterID, poolID int) (*M return pool, resp, err } -func (m *MkaasServiceOp) PoolDelete(ctx context.Context, clusterID, poolID int) (*TaskResponse, *Response, error) { +func (m *MKaaSServiceOp) PoolDelete(ctx context.Context, clusterID, poolID int) (*TaskResponse, *Response, error) { if resp, err := m.client.Validate(); err != nil { return nil, resp, err } - path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MkaaSClustersBasePathV2), clusterID, poolID) + path := fmt.Sprintf("%s/%d/pools/%d", m.client.addProjectRegionPath(MKaaSClustersBasePathV2), clusterID, poolID) req, err := m.client.NewRequest(ctx, http.MethodDelete, path, nil) if err != nil { diff --git a/mkaas_test.go b/mkaas_test.go index 57caade0..9e8c6f9b 100644 --- a/mkaas_test.go +++ b/mkaas_test.go @@ -26,7 +26,7 @@ func TestMkaasServiceOp_ClusterCreate(t *testing.T) { setup() defer teardown() - request := MkaaSClusterCreateRequest{ + request := MKaaSClusterCreateRequest{ Name: mkaasClusterName, SSHKeyPairName: mkaasKeypairName, NetworkID: mkaasTestNetworkID, @@ -37,7 +37,7 @@ func TestMkaasServiceOp_ClusterCreate(t *testing.T) { VolumeSize: 10, Version: mkaasVersion, }, - Pools: []MkaaSPoolCreateRequest{ + Pools: []MKaaSPoolCreateRequest{ { Name: mkaasPoolName, Flavor: mkaasFlavor, @@ -51,11 +51,11 @@ func TestMkaasServiceOp_ClusterCreate(t *testing.T) { }, } expectedResp := &TaskResponse{Tasks: []string{taskID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) - reqBody := &MkaaSClusterCreateRequest{} + reqBody := &MKaaSClusterCreateRequest{} if err := json.NewDecoder(r.Body).Decode(reqBody); err != nil { t.Errorf("failed to decode request body: %v", err) } @@ -67,7 +67,7 @@ func TestMkaasServiceOp_ClusterCreate(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.ClusterCreate(ctx, request) + respActual, resp, err := client.MKaaS.ClusterCreate(ctx, request) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -77,8 +77,8 @@ func TestMkaasServiceOp_ClustersList(t *testing.T) { setup() defer teardown() - expectedResp := []MkaaSCluster{{ID: testResourceIntID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) + expectedResp := []MKaaSCluster{{ID: testResourceIntID}} + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) @@ -89,7 +89,7 @@ func TestMkaasServiceOp_ClustersList(t *testing.T) { _, _ = fmt.Fprintf(w, `{"results":%s}`, string(resp)) }) - respActual, resp, err := client.MkaaS.ClustersList(ctx, nil) + respActual, resp, err := client.MKaaS.ClustersList(ctx, nil) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -99,7 +99,7 @@ func TestMkaasServiceOp_ClustersList_ResponseError(t *testing.T) { setup() defer teardown() - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) @@ -107,7 +107,7 @@ func TestMkaasServiceOp_ClustersList_ResponseError(t *testing.T) { _, _ = fmt.Fprint(w, "Bad request") }) - respActual, resp, err := client.MkaaS.ClustersList(ctx, nil) + respActual, resp, err := client.MKaaS.ClustersList(ctx, nil) assert.Nil(t, respActual) assert.Error(t, err) assert.Equal(t, resp.StatusCode, 400) @@ -117,10 +117,10 @@ func TestMkaasServiceOp_ClustersGet(t *testing.T) { setup() defer teardown() - expectedResp := &MkaaSCluster{ + expectedResp := &MKaaSCluster{ ID: testResourceIntID, } - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID)) + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) @@ -128,7 +128,7 @@ func TestMkaasServiceOp_ClustersGet(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.ClusterGet(ctx, testResourceIntID) + respActual, resp, err := client.MKaaS.ClusterGet(ctx, testResourceIntID) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -139,7 +139,7 @@ func TestMkaasServiceOp_ClustersDelete(t *testing.T) { defer teardown() expectedResp := &TaskResponse{Tasks: []string{taskID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID)) + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) @@ -150,7 +150,7 @@ func TestMkaasServiceOp_ClustersDelete(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.ClusterDelete(ctx, testResourceIntID) + respActual, resp, err := client.MKaaS.ClusterDelete(ctx, testResourceIntID) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -160,7 +160,7 @@ func TestMkaasServiceOp_PoolCreate(t *testing.T) { setup() defer teardown() - request := MkaaSPoolCreateRequest{ + request := MKaaSPoolCreateRequest{ Name: mkaasClusterName, Flavor: mkaasFlavor, NodeCount: 1, @@ -168,11 +168,11 @@ func TestMkaasServiceOp_PoolCreate(t *testing.T) { } expectedResp := &TaskResponse{Tasks: []string{taskID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools") + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools") mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) - reqBody := &MkaaSPoolCreateRequest{} + reqBody := &MKaaSPoolCreateRequest{} if err := json.NewDecoder(r.Body).Decode(reqBody); err != nil { t.Errorf("failed to decode request body: %v", err) } @@ -184,7 +184,7 @@ func TestMkaasServiceOp_PoolCreate(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.PoolCreate(ctx, testResourceIntID, request) + respActual, resp, err := client.MKaaS.PoolCreate(ctx, testResourceIntID, request) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -194,8 +194,8 @@ func TestMkaasServiceOp_PoolsList(t *testing.T) { setup() defer teardown() - expectedResp := []MkaaSPool{{ID: testResourceIntID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools") + expectedResp := []MKaaSPool{{ID: testResourceIntID}} + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools") mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) @@ -206,7 +206,7 @@ func TestMkaasServiceOp_PoolsList(t *testing.T) { _, _ = fmt.Fprintf(w, `{"results":%s}`, string(resp)) }) - respActual, resp, err := client.MkaaS.PoolsList(ctx, testResourceIntID, nil) + respActual, resp, err := client.MKaaS.PoolsList(ctx, testResourceIntID, nil) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -216,10 +216,10 @@ func TestMkaasServiceOp_PoolGet(t *testing.T) { setup() defer teardown() - expectedResp := &MkaaSPool{ + expectedResp := &MKaaSPool{ ID: testResourceIntID, } - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(testResourceIntID)) + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(testResourceIntID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) @@ -227,7 +227,7 @@ func TestMkaasServiceOp_PoolGet(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.PoolGet(ctx, testResourceIntID, testResourceIntID) + respActual, resp, err := client.MKaaS.PoolGet(ctx, testResourceIntID, testResourceIntID) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) @@ -238,7 +238,7 @@ func TestMkaasServiceOp_PoolDelete(t *testing.T) { defer teardown() expectedResp := &TaskResponse{Tasks: []string{taskID}} - URL := path.Join(MkaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(testResourceIntID)) mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { @@ -250,7 +250,7 @@ func TestMkaasServiceOp_PoolDelete(t *testing.T) { _, _ = fmt.Fprint(w, string(resp)) }) - respActual, resp, err := client.MkaaS.PoolDelete(ctx, testResourceIntID, testResourceIntID) + respActual, resp, err := client.MKaaS.PoolDelete(ctx, testResourceIntID, testResourceIntID) require.NoError(t, err) require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) diff --git a/projects.go b/projects.go index 3c3d7116..3bf4965d 100644 --- a/projects.go +++ b/projects.go @@ -69,7 +69,7 @@ type ProjectCreateRequest struct { } type ProjectListOptions struct { - ClientID string `url:"key,omitempty" validate:"omitempty"` + ClientID string `url:"client_id,omitempty" validate:"omitempty"` OrderBy string `url:"order_by,omitempty" validate:"omitempty"` Name string `url:"name,omitempty" validate:"omitempty"` IncludeDeleted bool `url:"include_deleted,omitempty" validate:"omitempty"` diff --git a/securitygroups.go b/securitygroups.go index 2cba4763..a411daa3 100644 --- a/securitygroups.go +++ b/securitygroups.go @@ -18,9 +18,9 @@ const ( ) var ( - ErrSGEtherTypeNotAllowed = fmt.Errorf("invalid EtherType, allowed only %s or %s", EtherTypeIPv4, EtherTypeIPv6) - ErrSGInvalidProtocol = fmt.Errorf("invalid Protocol") - ErrSGRuleDirectionNotAllowed = fmt.Errorf("invalid RuleDirection type, allowed only %s or %s", SGRuleDirectionIngress, SGRuleDirectionEgress) + ErrSGEtherTypeNotAllowed = fmt.Errorf("invalid Security Group EtherType, allowed only %s or %s", EtherTypeIPv4, EtherTypeIPv6) + ErrSGInvalidProtocol = fmt.Errorf("invalid Security Group Protocol") + ErrSGRuleDirectionNotAllowed = fmt.Errorf("invalid Security Group RuleDirection type, allowed only %s or %s", SGRuleDirectionIngress, SGRuleDirectionEgress) ) // SecurityGroupsService is an interface for creating and managing Security Groups (Firewalls) with the EdgecenterCloud API. @@ -191,18 +191,19 @@ func (rd *SecurityGroupRuleDirection) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s); err != nil { return err } - v := SecurityGroupRuleDirection(s) - err := v.IsValid() - if err != nil { - return err - } - *rd = v + + *rd = SecurityGroupRuleDirection(s) return nil } // MarshalJSON - implements Marshaler interface. func (rd *SecurityGroupRuleDirection) MarshalJSON() ([]byte, error) { + err := rd.IsValid() + if err != nil { + return nil, err + } + return json.Marshal(rd.String()) } @@ -253,18 +254,19 @@ func (et *EtherType) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s); err != nil { return err } - v := EtherType(s) - err := v.IsValid() - if err != nil { - return err - } - *et = v + + *et = EtherType(s) return nil } // MarshalJSON - implements Marshaler interface. func (et *EtherType) MarshalJSON() ([]byte, error) { + err := et.IsValid() + if err != nil { + return nil, err + } + return json.Marshal(et.String()) } @@ -349,18 +351,20 @@ func (p *SecurityGroupRuleProtocol) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s); err != nil { return err } - v := SecurityGroupRuleProtocol(s) - err := v.IsValid() - if err != nil { - return err - } - *p = v + + *p = SecurityGroupRuleProtocol(s) return nil } // MarshalJSON - implements Marshaler interface. func (p *SecurityGroupRuleProtocol) MarshalJSON() ([]byte, error) { + err := p.IsValid() + if err != nil { + return nil, fmt.Errorf( + "%w. Current protocol is: %s. The protocols that can be used in the rule are: %s", err, p.String(), p.StringList()) + } + return json.Marshal(p.String()) } diff --git a/securitygroups_test.go b/securitygroups_test.go index 3ccb3753..2935cac1 100644 --- a/securitygroups_test.go +++ b/securitygroups_test.go @@ -26,6 +26,27 @@ func TestSecurityGroupRuleDirection_IsValid(t *testing.T) { require.NoError(t, err) } +func TestSecurityGroupRuleProtocol_IsValid_InvalidProtocol(t *testing.T) { + invalidProtocol := SecurityGroupRuleProtocol("invalid_protocol") + err := invalidProtocol.IsValid() + assert.Error(t, err) + assert.EqualError(t, err, "invalid Security Group Protocol") +} + +func TestSecurityGroupRuleDirection_IsValid_InvalidDirection(t *testing.T) { + invalidDirection := SecurityGroupRuleDirection("invalid_direction") + err := invalidDirection.IsValid() + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid Security Group RuleDirection type") +} + +func TestEtherType_IsValid_InvalidEtherType(t *testing.T) { + invalidEtherType := EtherType("invalid_ethertype") + err := invalidEtherType.IsValid() + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid Security Group EtherType") +} + func TestSecurityGroups_List(t *testing.T) { setup() defer teardown() @@ -163,6 +184,90 @@ func TestSecurityGroups_Create_reqBodyNil(t *testing.T) { assert.EqualError(t, err, NewArgError("reqBody", "cannot be nil").Error()) } +func TestSecurityGroups_Create_ProtocolValidationError(t *testing.T) { + setup() + defer teardown() + + // Создаем запрос с недопустимым протоколом + invalidProtocol := SecurityGroupRuleProtocol("invalid_protocol") + request := &SecurityGroupCreateRequest{ + SecurityGroup: SecurityGroupCreateRequestInner{ + Name: "test-security-group", + SecurityGroupRules: []RuleCreateRequest{ + { + Direction: SGRuleDirectionIngress, + Protocol: invalidProtocol, + EtherType: EtherTypeIPv4, + }, + }, + }, + } + + // Попытка создания должна завершиться ошибкой валидации протокола + // Ошибка возникает при попытке сериализации JSON в методе NewRequest + respActual, resp, err := client.SecurityGroups.Create(ctx, request) + assert.Nil(t, respActual) + assert.Nil(t, resp) + assert.Error(t, err) + assert.EqualError(t, err, "json: error calling MarshalJSON for type edgecloud.SecurityGroupRuleProtocol: invalid Security Group Protocol. Current protocol is: invalid_protocol. The protocols that can be used in the rule are: [udp tcp any icmp ah dccp egp esp gre igmp ospf pgm rsvp sctp udplite vrrp ipip ipencap]") +} + +func TestSecurityGroups_Create_DirectionValidationError(t *testing.T) { + setup() + defer teardown() + + // Создаем запрос с недопустимым направлением + invalidDirection := SecurityGroupRuleDirection("invalid_direction") + request := &SecurityGroupCreateRequest{ + SecurityGroup: SecurityGroupCreateRequestInner{ + Name: "test-security-group", + SecurityGroupRules: []RuleCreateRequest{ + { + Direction: invalidDirection, + Protocol: SGRuleProtocolTCP, + EtherType: EtherTypeIPv4, + }, + }, + }, + } + + // Попытка создания должна завершиться ошибкой валидации направления + // Ошибка возникает при попытке сериализации JSON в методе NewRequest + respActual, resp, err := client.SecurityGroups.Create(ctx, request) + assert.Nil(t, respActual) + assert.Nil(t, resp) + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid Security Group RuleDirection type") +} + +func TestSecurityGroups_Create_EtherTypeValidationError(t *testing.T) { + setup() + defer teardown() + + // Создаем запрос с недопустимым типом Ethernet + invalidEtherType := EtherType("invalid_ethertype") + request := &SecurityGroupCreateRequest{ + SecurityGroup: SecurityGroupCreateRequestInner{ + Name: "test-security-group", + SecurityGroupRules: []RuleCreateRequest{ + { + Direction: SGRuleDirectionIngress, + Protocol: SGRuleProtocolTCP, + EtherType: invalidEtherType, + }, + }, + }, + } + + // Попытка создания должна завершиться ошибкой валидации типа Ethernet + // Ошибка возникает при попытке сериализации JSON в методе NewRequest + respActual, resp, err := client.SecurityGroups.Create(ctx, request) + assert.Nil(t, respActual) + assert.Nil(t, resp) + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid Security Group EtherType") +} + func TestSecurityGroups_Delete(t *testing.T) { setup() defer teardown() @@ -350,7 +455,7 @@ func TestSecurityGroups_RuleCreate_ResponseError(t *testing.T) { respActual, resp, err := client.SecurityGroups.RuleCreate(ctx, testResourceID, request) assert.Nil(t, respActual) assert.Error(t, err) - assert.Equal(t, resp.StatusCode, 400) + assert.Nil(t, resp) } func TestSecurityGroups_RuleCreate_reqBodyNil(t *testing.T) { @@ -447,7 +552,7 @@ func TestSecurityGroups_RuleUpdate_ResponseError(t *testing.T) { respActual, resp, err := client.SecurityGroups.RuleUpdate(ctx, testResourceID, request) assert.Nil(t, respActual) assert.Error(t, err) - assert.Equal(t, resp.StatusCode, 400) + assert.Nil(t, resp) } func TestSecurityGroups_RuleUpdate_reqBodyNil(t *testing.T) {