From 6828b9384e5b4757fecdc15788b14b757d52fd6f Mon Sep 17 00:00:00 2001 From: Lee Spottiswood Date: Wed, 23 Feb 2022 10:27:04 +0000 Subject: [PATCH] Ecloud loadbalancer changes (#108) * add vips * update to reflect API changes --- pkg/service/ecloud/error.go | 16 +- pkg/service/ecloud/model.go | 28 ++-- .../ecloud/model_paginated_generated.go | 24 +-- .../ecloud/model_response_generated.go | 24 +-- pkg/service/ecloud/request.go | 24 +-- pkg/service/ecloud/service.go | 18 +-- pkg/service/ecloud/service_loadbalancer.go | 45 ------ .../ecloud/service_loadbalancer_test.go | 83 ---------- .../ecloud/service_loadbalancernetwork.go | 146 ------------------ pkg/service/ecloud/service_vip.go | 146 ++++++++++++++++++ ...cernetwork_test.go => service_vip_test.go} | 120 +++++++------- 11 files changed, 273 insertions(+), 401 deletions(-) delete mode 100644 pkg/service/ecloud/service_loadbalancernetwork.go create mode 100644 pkg/service/ecloud/service_vip.go rename pkg/service/ecloud/{service_loadbalancernetwork_test.go => service_vip_test.go} (53%) diff --git a/pkg/service/ecloud/error.go b/pkg/service/ecloud/error.go index 0cfb715..07b73f3 100644 --- a/pkg/service/ecloud/error.go +++ b/pkg/service/ecloud/error.go @@ -398,20 +398,20 @@ func (e *LoadBalancerNotFoundError) Error() string { return fmt.Sprintf("Load balancer not found with ID [%s]", e.ID) } -// LoadBalancerNetworkNotFoundError indicates a load balancer network was not found -type LoadBalancerNetworkNotFoundError struct { +// LoadBalancerNetworkNotFoundError indicates a load balancer spec was not found +type LoadBalancerSpecNotFoundError struct { ID string } -func (e *LoadBalancerNetworkNotFoundError) Error() string { - return fmt.Sprintf("Load balancer network not found with ID [%s]", e.ID) +func (e *LoadBalancerSpecNotFoundError) Error() string { + return fmt.Sprintf("Load balancer spec not found with ID [%s]", e.ID) } -// LoadBalancerNetworkNotFoundError indicates a load balancer spec was not found -type LoadBalancerSpecNotFoundError struct { +// VIPNotFoundError indicates a load balancer VIP was not found +type VIPNotFoundError struct { ID string } -func (e *LoadBalancerSpecNotFoundError) Error() string { - return fmt.Sprintf("Load balancer spec not found with ID [%s]", e.ID) +func (e *VIPNotFoundError) Error() string { + return fmt.Sprintf("Load balancer VIP not found with ID [%s]", e.ID) } diff --git a/pkg/service/ecloud/model.go b/pkg/service/ecloud/model.go index b0c4c14..9a22f40 100644 --- a/pkg/service/ecloud/model.go +++ b/pkg/service/ecloud/model.go @@ -1085,23 +1085,11 @@ type LoadBalancer struct { Sync ResourceSync `json:"sync"` ConfigID int `json:"config_id"` Nodes int `json:"nodes"` + NetworkID string `json:"network_id"` CreatedAt connection.DateTime `json:"created_at"` UpdatedAt connection.DateTime `json:"updated_at"` } -// LoadBalancerNetwork represents an eCloud loadbalancer network -// +genie:model_response -// +genie:model_paginated -type LoadBalancerNetwork struct { - ID string `json:"id"` - Name string `json:"name"` - LoadBalancerID string `json:"load_balancer_id"` - NetworkID string `json:"network_id"` - Sync ResourceSync `json:"sync"` - CreatedAt connection.DateTime `json:"created_at"` - UpdatedAt connection.DateTime `json:"updated_at"` -} - // LoadBalancerSpec represents an eCloud loadbalancer specification // +genie:model_response // +genie:model_paginated @@ -1112,3 +1100,17 @@ type LoadBalancerSpec struct { CreatedAt connection.DateTime `json:"created_at"` UpdatedAt connection.DateTime `json:"updated_at"` } + +// VIP represents an eCloud load balancer VIP +// +genie:model_response +// +genie:model_paginated +type VIP struct { + ID string `json:"id"` + Name string `json:"name"` + LoadBalancerID string `json:"load_balancer_id"` + IPAddressID string `json:"ip_address_id"` + ConfigID int `json:"config_id"` + Sync ResourceSync `json:"sync"` + CreatedAt connection.DateTime `json:"created_at"` + UpdatedAt connection.DateTime `json:"updated_at"` +} diff --git a/pkg/service/ecloud/model_paginated_generated.go b/pkg/service/ecloud/model_paginated_generated.go index 3a67c4a..29dc1ca 100644 --- a/pkg/service/ecloud/model_paginated_generated.go +++ b/pkg/service/ecloud/model_paginated_generated.go @@ -674,29 +674,29 @@ func NewPaginatedLoadBalancer(getFunc connection.PaginatedGetFunc, parameters co } } -// PaginatedLoadBalancerNetwork represents a paginated collection of LoadBalancerNetwork -type PaginatedLoadBalancerNetwork struct { +// PaginatedLoadBalancerSpec represents a paginated collection of LoadBalancerSpec +type PaginatedLoadBalancerSpec struct { *connection.PaginatedBase - Items []LoadBalancerNetwork + Items []LoadBalancerSpec } -// NewPaginatedLoadBalancerNetwork returns a pointer to an initialized PaginatedLoadBalancerNetwork struct -func NewPaginatedLoadBalancerNetwork(getFunc connection.PaginatedGetFunc, parameters connection.APIRequestParameters, pagination connection.APIResponseMetadataPagination, items []LoadBalancerNetwork) *PaginatedLoadBalancerNetwork { - return &PaginatedLoadBalancerNetwork{ +// NewPaginatedLoadBalancerSpec returns a pointer to an initialized PaginatedLoadBalancerSpec struct +func NewPaginatedLoadBalancerSpec(getFunc connection.PaginatedGetFunc, parameters connection.APIRequestParameters, pagination connection.APIResponseMetadataPagination, items []LoadBalancerSpec) *PaginatedLoadBalancerSpec { + return &PaginatedLoadBalancerSpec{ Items: items, PaginatedBase: connection.NewPaginatedBase(parameters, pagination, getFunc), } } -// PaginatedLoadBalancerSpec represents a paginated collection of LoadBalancerSpec -type PaginatedLoadBalancerSpec struct { +// PaginatedVIP represents a paginated collection of VIP +type PaginatedVIP struct { *connection.PaginatedBase - Items []LoadBalancerSpec + Items []VIP } -// NewPaginatedLoadBalancerSpec returns a pointer to an initialized PaginatedLoadBalancerSpec struct -func NewPaginatedLoadBalancerSpec(getFunc connection.PaginatedGetFunc, parameters connection.APIRequestParameters, pagination connection.APIResponseMetadataPagination, items []LoadBalancerSpec) *PaginatedLoadBalancerSpec { - return &PaginatedLoadBalancerSpec{ +// NewPaginatedVIP returns a pointer to an initialized PaginatedVIP struct +func NewPaginatedVIP(getFunc connection.PaginatedGetFunc, parameters connection.APIRequestParameters, pagination connection.APIResponseMetadataPagination, items []VIP) *PaginatedVIP { + return &PaginatedVIP{ Items: items, PaginatedBase: connection.NewPaginatedBase(parameters, pagination, getFunc), } diff --git a/pkg/service/ecloud/model_response_generated.go b/pkg/service/ecloud/model_response_generated.go index 22fc45a..17a4ff3 100644 --- a/pkg/service/ecloud/model_response_generated.go +++ b/pkg/service/ecloud/model_response_generated.go @@ -626,18 +626,6 @@ type GetLoadBalancerResponseBody struct { Data LoadBalancer `json:"data"` } -// GetLoadBalancerNetworkSliceResponseBody represents an API response body containing []LoadBalancerNetwork data -type GetLoadBalancerNetworkSliceResponseBody struct { - connection.APIResponseBody - Data []LoadBalancerNetwork `json:"data"` -} - -// GetLoadBalancerNetworkResponseBody represents an API response body containing LoadBalancerNetwork data -type GetLoadBalancerNetworkResponseBody struct { - connection.APIResponseBody - Data LoadBalancerNetwork `json:"data"` -} - // GetLoadBalancerSpecSliceResponseBody represents an API response body containing []LoadBalancerSpec data type GetLoadBalancerSpecSliceResponseBody struct { connection.APIResponseBody @@ -649,3 +637,15 @@ type GetLoadBalancerSpecResponseBody struct { connection.APIResponseBody Data LoadBalancerSpec `json:"data"` } + +// GetVIPSliceResponseBody represents an API response body containing []VIP data +type GetVIPSliceResponseBody struct { + connection.APIResponseBody + Data []VIP `json:"data"` +} + +// GetVIPResponseBody represents an API response body containing VIP data +type GetVIPResponseBody struct { + connection.APIResponseBody + Data VIP `json:"data"` +} diff --git a/pkg/service/ecloud/request.go b/pkg/service/ecloud/request.go index 733bc29..7c26204 100644 --- a/pkg/service/ecloud/request.go +++ b/pkg/service/ecloud/request.go @@ -536,11 +536,11 @@ type PatchVolumeGroupRequest struct { // CreateLoadBalancerRequest represents a request to create a load balancer type CreateLoadBalancerRequest struct { - Name string `json:"name,omitempty"` - AvailabilityZoneID string `json:"availability_zone_id"` - VPCID string `json:"vpc_id"` - LoadBalancerSpecID string `json:"load_balancer_spec_id"` - NetworkIDs []string `json:"network_ids,omitempty"` + Name string `json:"name,omitempty"` + AvailabilityZoneID string `json:"availability_zone_id"` + VPCID string `json:"vpc_id"` + LoadBalancerSpecID string `json:"load_balancer_spec_id"` + NetworkID string `json:"network_id"` } // CreateLoadBalancerRequest represents a request to patch a load balancer @@ -548,14 +548,14 @@ type PatchLoadBalancerRequest struct { Name string `json:"name,omitempty"` } -// CreateLoadBalancerNetworkRequest represents a request to create a load balancer network -type CreateLoadBalancerNetworkRequest struct { - Name string `json:"name,omitempty"` - LoadBalancerID string `json:"load_balancer_id"` - NetworkID string `json:"network_id"` +// CreateVIPRequest represents a request to create a load balancer VIP +type CreateVIPRequest struct { + Name string `json:"name,omitempty"` + LoadBalancerID string `json:"load_balancer_id"` + AllocateFloatingIP bool `json:"allocate_floating_ip"` } -// PatchLoadBalancerNetworkRequest represents a request to patch a load balancer network -type PatchLoadBalancerNetworkRequest struct { +// PatchVIPRequest represents a request to patch a load balancer VIP +type PatchVIPRequest struct { Name string `json:"name,omitempty"` } diff --git a/pkg/service/ecloud/service.go b/pkg/service/ecloud/service.go index d269873..3de41ec 100644 --- a/pkg/service/ecloud/service.go +++ b/pkg/service/ecloud/service.go @@ -393,21 +393,19 @@ type ECloudService interface { CreateLoadBalancer(req CreateLoadBalancerRequest) (TaskReference, error) PatchLoadBalancer(loadbalancerID string, req PatchLoadBalancerRequest) (TaskReference, error) DeleteLoadBalancer(loadbalancerID string) (string, error) - GetLoadBalancerLoadBalancerNetworks(loadbalancerID string, parameters connection.APIRequestParameters) ([]LoadBalancerNetwork, error) - GetLoadBalancerLoadBalancerNetworksPaginated(loadbalancerID string, parameters connection.APIRequestParameters) (*PaginatedLoadBalancerNetwork, error) - - // Load Balancer Network - GetLoadBalancerNetworks(parameters connection.APIRequestParameters) ([]LoadBalancerNetwork, error) - GetLoadBalancerNetworksPaginated(parameters connection.APIRequestParameters) (*PaginatedLoadBalancerNetwork, error) - GetLoadBalancerNetwork(lbNetworkID string) (LoadBalancerNetwork, error) - CreateLoadBalancerNetwork(req CreateLoadBalancerNetworkRequest) (TaskReference, error) - PatchLoadBalancerNetwork(lbNetworkID string, req PatchLoadBalancerNetworkRequest) (TaskReference, error) - DeleteLoadBalancerNetwork(lbNetworkID string) (string, error) // Load Balancer Spec GetLoadBalancerSpecs(parameters connection.APIRequestParameters) ([]LoadBalancerSpec, error) GetLoadBalancerSpecsPaginated(parameters connection.APIRequestParameters) (*PaginatedLoadBalancerSpec, error) GetLoadBalancerSpec(lbSpecID string) (LoadBalancerSpec, error) + + // VIP + GetVIPs(parameters connection.APIRequestParameters) ([]VIP, error) + GetVIPsPaginated(parameters connection.APIRequestParameters) (*PaginatedVIP, error) + GetVIP(vipID string) (VIP, error) + CreateVIP(req CreateVIPRequest) (TaskReference, error) + PatchVIP(vipID string, patch PatchVIPRequest) (TaskReference, error) + DeleteVIP(vipID string) (string, error) } // Service implements ECloudService for managing diff --git a/pkg/service/ecloud/service_loadbalancer.go b/pkg/service/ecloud/service_loadbalancer.go index a42b0c4..448ddad 100644 --- a/pkg/service/ecloud/service_loadbalancer.go +++ b/pkg/service/ecloud/service_loadbalancer.go @@ -142,48 +142,3 @@ func (s *Service) deleteLoadBalancerResponseBody(loadbalancerID string) (*GetTas return nil }) } - -// GetLoadBalancerLoadBalancerNetworks retrieves a list of lb networks -func (s *Service) GetLoadBalancerLoadBalancerNetworks(loadbalancerID string, parameters connection.APIRequestParameters) ([]LoadBalancerNetwork, error) { - var lbs []LoadBalancerNetwork - - getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetLoadBalancerLoadBalancerNetworksPaginated(loadbalancerID, p) - } - - responseFunc := func(response connection.Paginated) { - lbs = append(lbs, response.(*PaginatedLoadBalancerNetwork).Items...) - } - - return lbs, connection.InvokeRequestAll(getFunc, responseFunc, parameters) -} - -// GetLoadBalancerLoadBalancerNetworksPaginated retrieves a paginated list of lb networks -func (s *Service) GetLoadBalancerLoadBalancerNetworksPaginated(loadbalancerID string, parameters connection.APIRequestParameters) (*PaginatedLoadBalancerNetwork, error) { - body, err := s.getLoadBalancerLoadBalancerNetworksPaginatedResponseBody(loadbalancerID, parameters) - - return NewPaginatedLoadBalancerNetwork(func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetLoadBalancerLoadBalancerNetworksPaginated(loadbalancerID, p) - }, parameters, body.Metadata.Pagination, body.Data), err -} - -func (s *Service) getLoadBalancerLoadBalancerNetworksPaginatedResponseBody(loadbalancerID string, parameters connection.APIRequestParameters) (*GetLoadBalancerNetworkSliceResponseBody, error) { - body := &GetLoadBalancerNetworkSliceResponseBody{} - - if loadbalancerID == "" { - return body, fmt.Errorf("invalid load balancer id") - } - - response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/load-balancers/%s/networks", loadbalancerID), parameters) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { - if response.StatusCode == 404 { - return &LoadBalancerNotFoundError{ID: loadbalancerID} - } - - return nil - }) -} diff --git a/pkg/service/ecloud/service_loadbalancer_test.go b/pkg/service/ecloud/service_loadbalancer_test.go index fcc8c83..d3aca72 100644 --- a/pkg/service/ecloud/service_loadbalancer_test.go +++ b/pkg/service/ecloud/service_loadbalancer_test.go @@ -355,86 +355,3 @@ func TestDeleteLoadBalancer(t *testing.T) { assert.IsType(t, &LoadBalancerNotFoundError{}, err) }) } - -func TestGetLoadBalancerLoadBalancerNetworks(t *testing.T) { - t.Run("Single", func(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - c := mocks.NewMockConnection(mockCtrl) - - s := Service{ - connection: c, - } - - c.EXPECT().Get("/ecloud/v2/load-balancers/lb-abcdef12/networks", gomock.Any()).Return(&connection.APIResponse{ - Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"lbn-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), - StatusCode: 200, - }, - }, nil).Times(1) - - networks, err := s.GetLoadBalancerLoadBalancerNetworks("lb-abcdef12", connection.APIRequestParameters{}) - - assert.Nil(t, err) - assert.Len(t, networks, 1) - assert.Equal(t, "lbn-abcdef12", networks[0].ID) - }) - - t.Run("ConnectionError_ReturnsError", func(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - c := mocks.NewMockConnection(mockCtrl) - - s := Service{ - connection: c, - } - - c.EXPECT().Get("/ecloud/v2/load-balancers/lb-abcdef12/networks", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) - - _, err := s.GetLoadBalancerLoadBalancerNetworks("lb-abcdef12", connection.APIRequestParameters{}) - - assert.NotNil(t, err) - assert.Equal(t, "test error 1", err.Error()) - }) - - t.Run("InvalidLoadBalancerID_ReturnsError", func(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - c := mocks.NewMockConnection(mockCtrl) - - s := Service{ - connection: c, - } - - _, err := s.GetLoadBalancerLoadBalancerNetworks("", connection.APIRequestParameters{}) - - assert.NotNil(t, err) - assert.Equal(t, "invalid load balancer id", err.Error()) - }) - - t.Run("404_ReturnsLoadBalancerNotFoundError", func(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - c := mocks.NewMockConnection(mockCtrl) - - s := Service{ - connection: c, - } - - c.EXPECT().Get("/ecloud/v2/load-balancers/lb-abcdef12/networks", gomock.Any()).Return(&connection.APIResponse{ - Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), - StatusCode: 404, - }, - }, nil).Times(1) - - _, err := s.GetLoadBalancerLoadBalancerNetworks("lb-abcdef12", connection.APIRequestParameters{}) - - assert.NotNil(t, err) - assert.IsType(t, &LoadBalancerNotFoundError{}, err) - }) -} diff --git a/pkg/service/ecloud/service_loadbalancernetwork.go b/pkg/service/ecloud/service_loadbalancernetwork.go deleted file mode 100644 index 3439060..0000000 --- a/pkg/service/ecloud/service_loadbalancernetwork.go +++ /dev/null @@ -1,146 +0,0 @@ -package ecloud - -import ( - "fmt" - - "github.com/ukfast/sdk-go/pkg/connection" -) - -// GetLoadBalancerNetworks retrieves a list of load balancer networks -func (s *Service) GetLoadBalancerNetworks(parameters connection.APIRequestParameters) ([]LoadBalancerNetwork, error) { - var networks []LoadBalancerNetwork - - getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetLoadBalancerNetworksPaginated(p) - } - - responseFunc := func(response connection.Paginated) { - for _, network := range response.(*PaginatedLoadBalancerNetwork).Items { - networks = append(networks, network) - } - } - - return networks, connection.InvokeRequestAll(getFunc, responseFunc, parameters) -} - -// GetLoadBalancerNetworksPaginated retrieves a paginated list of load balancer networks -func (s *Service) GetLoadBalancerNetworksPaginated(parameters connection.APIRequestParameters) (*PaginatedLoadBalancerNetwork, error) { - body, err := s.getLoadBalancerNetworksPaginatedResponseBody(parameters) - - return NewPaginatedLoadBalancerNetwork(func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetLoadBalancerNetworksPaginated(p) - }, parameters, body.Metadata.Pagination, body.Data), err -} - -func (s *Service) getLoadBalancerNetworksPaginatedResponseBody(parameters connection.APIRequestParameters) (*GetLoadBalancerNetworkSliceResponseBody, error) { - body := &GetLoadBalancerNetworkSliceResponseBody{} - - response, err := s.connection.Get("/ecloud/v2/load-balancer-networks", parameters) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, nil) -} - -// GetLoadBalancerNetwork retrieves a single network by id -func (s *Service) GetLoadBalancerNetwork(lbNetworkID string) (LoadBalancerNetwork, error) { - body, err := s.getLoadBalancerNetworkResponseBody(lbNetworkID) - - return body.Data, err -} - -func (s *Service) getLoadBalancerNetworkResponseBody(lbNetworkID string) (*GetLoadBalancerNetworkResponseBody, error) { - body := &GetLoadBalancerNetworkResponseBody{} - - if lbNetworkID == "" { - return body, fmt.Errorf("invalid load balancer network id") - } - - response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/load-balancer-networks/%s", lbNetworkID), connection.APIRequestParameters{}) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { - if response.StatusCode == 404 { - return &LoadBalancerNetworkNotFoundError{ID: lbNetworkID} - } - - return nil - }) -} - -// CreateLoadBalancerNetwork creates a new LoadBalancerNetwork -func (s *Service) CreateLoadBalancerNetwork(req CreateLoadBalancerNetworkRequest) (TaskReference, error) { - body, err := s.createLoadBalancerNetworkResponseBody(req) - - return body.Data, err -} - -func (s *Service) createLoadBalancerNetworkResponseBody(req CreateLoadBalancerNetworkRequest) (*GetTaskReferenceResponseBody, error) { - body := &GetTaskReferenceResponseBody{} - - response, err := s.connection.Post("/ecloud/v2/load-balancer-networks", &req) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, nil) -} - -// PatchLoadBalancerNetwork patches a LoadBalancerNetwork -func (s *Service) PatchLoadBalancerNetwork(lbNetworkID string, req PatchLoadBalancerNetworkRequest) (TaskReference, error) { - body, err := s.patchLoadBalancerNetworkResponseBody(lbNetworkID, req) - - return body.Data, err -} - -func (s *Service) patchLoadBalancerNetworkResponseBody(lbNetworkID string, req PatchLoadBalancerNetworkRequest) (*GetTaskReferenceResponseBody, error) { - body := &GetTaskReferenceResponseBody{} - - if lbNetworkID == "" { - return body, fmt.Errorf("invalid load balancer network id") - } - - response, err := s.connection.Patch(fmt.Sprintf("/ecloud/v2/load-balancer-networks/%s", lbNetworkID), &req) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { - if response.StatusCode == 404 { - return &LoadBalancerNetworkNotFoundError{ID: lbNetworkID} - } - - return nil - }) -} - -// DeleteLoadBalancerNetwork deletes a LoadBalancerNetwork -func (s *Service) DeleteLoadBalancerNetwork(lbNetworkID string) (string, error) { - body, err := s.deleteLoadBalancerNetworkResponseBody(lbNetworkID) - - return body.Data.TaskID, err -} - -func (s *Service) deleteLoadBalancerNetworkResponseBody(lbNetworkID string) (*GetTaskReferenceResponseBody, error) { - body := &GetTaskReferenceResponseBody{} - - if lbNetworkID == "" { - return body, fmt.Errorf("invalid load balancer network id") - } - - response, err := s.connection.Delete(fmt.Sprintf("/ecloud/v2/load-balancer-networks/%s", lbNetworkID), nil) - if err != nil { - return body, err - } - - return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { - if response.StatusCode == 404 { - return &LoadBalancerNetworkNotFoundError{ID: lbNetworkID} - } - - return nil - }) -} diff --git a/pkg/service/ecloud/service_vip.go b/pkg/service/ecloud/service_vip.go new file mode 100644 index 0000000..e60d58e --- /dev/null +++ b/pkg/service/ecloud/service_vip.go @@ -0,0 +1,146 @@ +package ecloud + +import ( + "fmt" + + "github.com/ukfast/sdk-go/pkg/connection" +) + +// GetVIPs retrieves a list of vips +func (s *Service) GetVIPs(parameters connection.APIRequestParameters) ([]VIP, error) { + var vips []VIP + + getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVIPsPaginated(p) + } + + responseFunc := func(response connection.Paginated) { + for _, vip := range response.(*PaginatedVIP).Items { + vips = append(vips, vip) + } + } + + return vips, connection.InvokeRequestAll(getFunc, responseFunc, parameters) +} + +// GetVIPsPaginated retrieves a paginated list of vips +func (s *Service) GetVIPsPaginated(parameters connection.APIRequestParameters) (*PaginatedVIP, error) { + body, err := s.getVIPsPaginatedResponseBody(parameters) + + return NewPaginatedVIP(func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVIPsPaginated(p) + }, parameters, body.Metadata.Pagination, body.Data), err +} + +func (s *Service) getVIPsPaginatedResponseBody(parameters connection.APIRequestParameters) (*GetVIPSliceResponseBody, error) { + body := &GetVIPSliceResponseBody{} + + response, err := s.connection.Get("/ecloud/v2/vips", parameters) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, nil) +} + +// GetVIP retrieves a single vip by id +func (s *Service) GetVIP(vipID string) (VIP, error) { + body, err := s.getVIPResponseBody(vipID) + + return body.Data, err +} + +func (s *Service) getVIPResponseBody(vipID string) (*GetVIPResponseBody, error) { + body := &GetVIPResponseBody{} + + if vipID == "" { + return body, fmt.Errorf("invalid vip id") + } + + response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/vips/%s", vipID), connection.APIRequestParameters{}) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VIPNotFoundError{ID: vipID} + } + + return nil + }) +} + +// CreateVIP creates a new VIP +func (s *Service) CreateVIP(req CreateVIPRequest) (TaskReference, error) { + body, err := s.createVIPResponseBody(req) + + return body.Data, err +} + +func (s *Service) createVIPResponseBody(req CreateVIPRequest) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + response, err := s.connection.Post("/ecloud/v2/vips", &req) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, nil) +} + +// PatchVIP patches a VIP +func (s *Service) PatchVIP(vipID string, req PatchVIPRequest) (TaskReference, error) { + body, err := s.patchVIPResponseBody(vipID, req) + + return body.Data, err +} + +func (s *Service) patchVIPResponseBody(vipID string, req PatchVIPRequest) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + if vipID == "" { + return body, fmt.Errorf("invalid vip id") + } + + response, err := s.connection.Patch(fmt.Sprintf("/ecloud/v2/vips/%s", vipID), &req) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VIPNotFoundError{ID: vipID} + } + + return nil + }) +} + +// DeleteVIP deletes a VIP +func (s *Service) DeleteVIP(vipID string) (string, error) { + body, err := s.deleteVIPResponseBody(vipID) + + return body.Data.TaskID, err +} + +func (s *Service) deleteVIPResponseBody(vipID string) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + if vipID == "" { + return body, fmt.Errorf("invalid vip id") + } + + response, err := s.connection.Delete(fmt.Sprintf("/ecloud/v2/vips/%s", vipID), nil) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VIPNotFoundError{ID: vipID} + } + + return nil + }) +} diff --git a/pkg/service/ecloud/service_loadbalancernetwork_test.go b/pkg/service/ecloud/service_vip_test.go similarity index 53% rename from pkg/service/ecloud/service_loadbalancernetwork_test.go rename to pkg/service/ecloud/service_vip_test.go index 54eb817..4b66545 100644 --- a/pkg/service/ecloud/service_loadbalancernetwork_test.go +++ b/pkg/service/ecloud/service_vip_test.go @@ -13,7 +13,7 @@ import ( "github.com/ukfast/sdk-go/test/mocks" ) -func TestGetLoadBalancerNetworks(t *testing.T) { +func TestGetVIPs(t *testing.T) { t.Run("Single", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -24,18 +24,18 @@ func TestGetLoadBalancerNetworks(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/load-balancer-networks", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Get("/ecloud/v2/vips", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"lbn-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"vip-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), StatusCode: 200, }, }, nil).Times(1) - networks, err := s.GetLoadBalancerNetworks(connection.APIRequestParameters{}) + vips, err := s.GetVIPs(connection.APIRequestParameters{}) assert.Nil(t, err) - assert.Len(t, networks, 1) - assert.Equal(t, "lbn-abcdef12", networks[0].ID) + assert.Len(t, vips, 1) + assert.Equal(t, "vip-abcdef12", vips[0].ID) }) t.Run("ConnectionError_ReturnsError", func(t *testing.T) { @@ -48,16 +48,16 @@ func TestGetLoadBalancerNetworks(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/load-balancer-networks", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) + c.EXPECT().Get("/ecloud/v2/vips", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) - _, err := s.GetLoadBalancerNetworks(connection.APIRequestParameters{}) + _, err := s.GetVIPs(connection.APIRequestParameters{}) assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) }) } -func TestGetLoadBalancerNetwork(t *testing.T) { +func TestGetVIP(t *testing.T) { t.Run("Valid", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -68,17 +68,17 @@ func TestGetLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/load-balancer-networks/lbn-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Get("/ecloud/v2/vips/vip-abcdef12", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"lbn-abcdef12\"}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"vip-abcdef12\"}}"))), StatusCode: 200, }, }, nil).Times(1) - network, err := s.GetLoadBalancerNetwork("lbn-abcdef12") + vip, err := s.GetVIP("vip-abcdef12") assert.Nil(t, err) - assert.Equal(t, "lbn-abcdef12", network.ID) + assert.Equal(t, "vip-abcdef12", vip.ID) }) t.Run("ConnectionError_ReturnsError", func(t *testing.T) { @@ -91,15 +91,15 @@ func TestGetLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/load-balancer-networks/lbn-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + c.EXPECT().Get("/ecloud/v2/vips/vip-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) - _, err := s.GetLoadBalancerNetwork("lbn-abcdef12") + _, err := s.GetVIP("vip-abcdef12") assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) }) - t.Run("InvalidLoadBalancerNetworkID_ReturnsError", func(t *testing.T) { + t.Run("InvalidVIPID_ReturnsError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -109,13 +109,13 @@ func TestGetLoadBalancerNetwork(t *testing.T) { connection: c, } - _, err := s.GetLoadBalancerNetwork("") + _, err := s.GetVIP("") assert.NotNil(t, err) - assert.Equal(t, "invalid load balancer network id", err.Error()) + assert.Equal(t, "invalid vip id", err.Error()) }) - t.Run("404_ReturnsLoadBalancerNetworkNotFoundError", func(t *testing.T) { + t.Run("404_ReturnsVIPNotFoundError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -125,21 +125,21 @@ func TestGetLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/load-balancer-networks/lbn-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Get("/ecloud/v2/vips/vip-abcdef12", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), StatusCode: 404, }, }, nil).Times(1) - _, err := s.GetLoadBalancerNetwork("lbn-abcdef12") + _, err := s.GetVIP("vip-abcdef12") assert.NotNil(t, err) - assert.IsType(t, &LoadBalancerNetworkNotFoundError{}, err) + assert.IsType(t, &VIPNotFoundError{}, err) }) } -func TestCreateLoadBalancerNetwork(t *testing.T) { +func TestCreateVIP(t *testing.T) { t.Run("Valid", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -150,21 +150,21 @@ func TestCreateLoadBalancerNetwork(t *testing.T) { connection: c, } - req := CreateLoadBalancerNetworkRequest{ + req := CreateVIPRequest{ Name: "test", } - c.EXPECT().Post("/ecloud/v2/load-balancer-networks", &req).Return(&connection.APIResponse{ + c.EXPECT().Post("/ecloud/v2/vips", &req).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"lbn-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"vip-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), StatusCode: 200, }, }, nil).Times(1) - taskRef, err := s.CreateLoadBalancerNetwork(req) + taskRef, err := s.CreateVIP(req) assert.Nil(t, err) - assert.Equal(t, "lbn-abcdef12", taskRef.ResourceID) + assert.Equal(t, "vip-abcdef12", taskRef.ResourceID) assert.Equal(t, "task-abcdef12", taskRef.TaskID) }) @@ -178,16 +178,16 @@ func TestCreateLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Post("/ecloud/v2/load-balancer-networks", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + c.EXPECT().Post("/ecloud/v2/vips", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) - _, err := s.CreateLoadBalancerNetwork(CreateLoadBalancerNetworkRequest{}) + _, err := s.CreateVIP(CreateVIPRequest{}) assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) }) } -func TestPatchLoadBalancerNetwork(t *testing.T) { +func TestPatchVIP(t *testing.T) { t.Run("Valid", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -198,22 +198,22 @@ func TestPatchLoadBalancerNetwork(t *testing.T) { connection: c, } - req := PatchLoadBalancerNetworkRequest{ - Name: "somenetwork", + req := PatchVIPRequest{ + Name: "somevip", } - c.EXPECT().Patch("/ecloud/v2/load-balancer-networks/lbn-abcdef12", &req).Return(&connection.APIResponse{ + c.EXPECT().Patch("/ecloud/v2/vips/vip-abcdef12", &req).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"lbn-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"vip-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), StatusCode: 200, }, }, nil).Times(1) - task, err := s.PatchLoadBalancerNetwork("lbn-abcdef12", req) + taskRef, err := s.PatchVIP("vip-abcdef12", req) assert.Nil(t, err) - assert.Equal(t, "lbn-abcdef12", task.ResourceID) - assert.Equal(t, "task-abcdef12", task.TaskID) + assert.Equal(t, "vip-abcdef12", taskRef.ResourceID) + assert.Equal(t, "task-abcdef12", taskRef.TaskID) }) t.Run("ConnectionError_ReturnsError", func(t *testing.T) { @@ -226,15 +226,15 @@ func TestPatchLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Patch("/ecloud/v2/load-balancer-networks/lbn-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + c.EXPECT().Patch("/ecloud/v2/vips/vip-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) - _, err := s.PatchLoadBalancerNetwork("lbn-abcdef12", PatchLoadBalancerNetworkRequest{}) + _, err := s.PatchVIP("vip-abcdef12", PatchVIPRequest{}) assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) }) - t.Run("InvalidLoadBalancerNetworkID_ReturnsError", func(t *testing.T) { + t.Run("InvalidVIPID_ReturnsError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -244,13 +244,13 @@ func TestPatchLoadBalancerNetwork(t *testing.T) { connection: c, } - _, err := s.PatchLoadBalancerNetwork("", PatchLoadBalancerNetworkRequest{}) + _, err := s.PatchVIP("", PatchVIPRequest{}) assert.NotNil(t, err) - assert.Equal(t, "invalid load balancer network id", err.Error()) + assert.Equal(t, "invalid vip id", err.Error()) }) - t.Run("404_ReturnsLoadBalancerNetworkNotFoundError", func(t *testing.T) { + t.Run("404_ReturnsVIPNotFoundError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -260,21 +260,21 @@ func TestPatchLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Patch("/ecloud/v2/load-balancer-networks/lbn-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Patch("/ecloud/v2/vips/vip-abcdef12", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), StatusCode: 404, }, }, nil).Times(1) - _, err := s.PatchLoadBalancerNetwork("lbn-abcdef12", PatchLoadBalancerNetworkRequest{}) + _, err := s.PatchVIP("vip-abcdef12", PatchVIPRequest{}) assert.NotNil(t, err) - assert.IsType(t, &LoadBalancerNetworkNotFoundError{}, err) + assert.IsType(t, &VIPNotFoundError{}, err) }) } -func TestDeleteLoadBalancerNetwork(t *testing.T) { +func TestDeleteVIP(t *testing.T) { t.Run("Valid", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -285,14 +285,14 @@ func TestDeleteLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Delete("/ecloud/v2/load-balancer-networks/lbn-abcdef12", nil).Return(&connection.APIResponse{ + c.EXPECT().Delete("/ecloud/v2/vips/vip-abcdef12", nil).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"task_id\":\"task-abcdef12\"}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"vip-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), StatusCode: 200, }, }, nil).Times(1) - taskID, err := s.DeleteLoadBalancerNetwork("lbn-abcdef12") + taskID, err := s.DeleteVIP("vip-abcdef12") assert.Nil(t, err) assert.Equal(t, "task-abcdef12", taskID) @@ -308,15 +308,15 @@ func TestDeleteLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Delete("/ecloud/v2/load-balancer-networks/lbn-abcdef12", nil).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + c.EXPECT().Delete("/ecloud/v2/vips/vip-abcdef12", nil).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) - _, err := s.DeleteLoadBalancerNetwork("lbn-abcdef12") + _, err := s.DeleteVIP("vip-abcdef12") assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) }) - t.Run("InvalidLoadBalancerNetworkID_ReturnsError", func(t *testing.T) { + t.Run("InvalidVIPID_ReturnsError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -326,13 +326,13 @@ func TestDeleteLoadBalancerNetwork(t *testing.T) { connection: c, } - _, err := s.DeleteLoadBalancerNetwork("") + _, err := s.DeleteVIP("") assert.NotNil(t, err) - assert.Equal(t, "invalid load balancer network id", err.Error()) + assert.Equal(t, "invalid vip id", err.Error()) }) - t.Run("404_ReturnsLoadBalancerNetworkNotFoundError", func(t *testing.T) { + t.Run("404_ReturnsVIPNotFoundError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -342,16 +342,16 @@ func TestDeleteLoadBalancerNetwork(t *testing.T) { connection: c, } - c.EXPECT().Delete("/ecloud/v2/load-balancer-networks/lbn-abcdef12", nil).Return(&connection.APIResponse{ + c.EXPECT().Delete("/ecloud/v2/vips/vip-abcdef12", nil).Return(&connection.APIResponse{ Response: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), StatusCode: 404, }, }, nil).Times(1) - _, err := s.DeleteLoadBalancerNetwork("lbn-abcdef12") + _, err := s.DeleteVIP("vip-abcdef12") assert.NotNil(t, err) - assert.IsType(t, &LoadBalancerNetworkNotFoundError{}, err) + assert.IsType(t, &VIPNotFoundError{}, err) }) }