diff --git a/pkg/service/draas/error.go b/pkg/service/draas/error.go index ae8d12a..4c377b5 100644 --- a/pkg/service/draas/error.go +++ b/pkg/service/draas/error.go @@ -55,3 +55,12 @@ type BillingTypeNotFoundError struct { func (e *BillingTypeNotFoundError) Error() string { return fmt.Sprintf("Billing type not found with ID [%s]", e.ID) } + +// ReplicaNotFoundError indicates a replica was not found +type ReplicaNotFoundError struct { + ID string +} + +func (e *ReplicaNotFoundError) Error() string { + return fmt.Sprintf("Replica not found with ID [%s]", e.ID) +} diff --git a/pkg/service/draas/model.go b/pkg/service/draas/model.go index 03c051e..7f4c645 100644 --- a/pkg/service/draas/model.go +++ b/pkg/service/draas/model.go @@ -79,7 +79,7 @@ type HardwarePlan struct { Public int `json:"public"` Private int `json:"private"` } `json:"networks"` - Storage struct { + Storage []struct { ID string `json:"id"` Name string `json:"name"` Type string `json:"Type"` @@ -94,7 +94,7 @@ type Replica struct { Platform string `json:"platform"` CPU int `json:"cpu"` RAM int `json:"ram"` - HDD int `json:"hdd"` + Disk int `json:"disk"` IOPS int `json:"iops"` Power bool `json:"power"` } diff --git a/pkg/service/draas/request.go b/pkg/service/draas/request.go index 61282f1..33c468a 100644 --- a/pkg/service/draas/request.go +++ b/pkg/service/draas/request.go @@ -1,11 +1,24 @@ package draas +import "github.com/ukfast/sdk-go/pkg/connection" + // PatchSolutionRequest represents a request to patch a solution type PatchSolutionRequest struct { Name string `json:"name,omitempty"` IOPSTierID string `json:"iops_tier_id,omitempty"` } +// ResetBackupServiceCredentialsRequest represents a request to reset backup service credentials type ResetBackupServiceCredentialsRequest struct { Password string `json:"password"` } + +// StartFailoverPlanRequest represents a request to start a failover plan +type StartFailoverPlanRequest struct { + StartDate connection.DateTime `json:"start_date"` +} + +// UpdateReplicaIOPSRequest represents a request to update the IOPS for a replica +type UpdateReplicaIOPSRequest struct { + IOPSTierID string `json:"iops_tier_id"` +} diff --git a/pkg/service/draas/service.go b/pkg/service/draas/service.go index 41c5843..e8596ec 100644 --- a/pkg/service/draas/service.go +++ b/pkg/service/draas/service.go @@ -20,7 +20,7 @@ type DRaaSService interface { GetSolutionFailoverPlans(solutionID string, parameters connection.APIRequestParameters) ([]FailoverPlan, error) GetSolutionFailoverPlansPaginated(solutionID string, parameters connection.APIRequestParameters) (*PaginatedFailoverPlan, error) GetSolutionFailoverPlan(solutionID string, failoverPlanID string) (FailoverPlan, error) - StartSolutionFailoverPlan(solutionID string, failoverPlanID string) error + StartSolutionFailoverPlan(solutionID string, failoverPlanID string, req StartFailoverPlanRequest) error StopSolutionFailoverPlan(solutionID string, failoverPlanID string) error GetSolutionComputeResources(solutionID string, parameters connection.APIRequestParameters) ([]ComputeResource, error) @@ -32,6 +32,8 @@ type DRaaSService interface { GetSolutionHardwarePlan(solutionID string, hardwarePlanID string) (HardwarePlan, error) GetSolutionHardwarePlanReplicas(solutionID string, hardwarePlanID string, parameters connection.APIRequestParameters) ([]Replica, error) + UpdateSolutionReplicaIOPS(solutionID string, replicaID string, req UpdateReplicaIOPSRequest) error + GetIOPSTiers(parameters connection.APIRequestParameters) ([]IOPSTier, error) GetIOPSTier(iopsTierID string) (IOPSTier, error) diff --git a/pkg/service/draas/service_solution.go b/pkg/service/draas/service_solution.go index d19c5a0..db123b5 100644 --- a/pkg/service/draas/service_solution.go +++ b/pkg/service/draas/service_solution.go @@ -281,13 +281,13 @@ func (s *Service) getSolutionFailoverPlanResponseBody(solutionID string, failove } // StartSolutionFailoverPlan starts the specified failover plan -func (s *Service) StartSolutionFailoverPlan(solutionID string, failoverPlanID string) error { - _, err := s.startSolutionFailoverPlanResponseBody(solutionID, failoverPlanID) +func (s *Service) StartSolutionFailoverPlan(solutionID string, failoverPlanID string, req StartFailoverPlanRequest) error { + _, err := s.startSolutionFailoverPlanResponseBody(solutionID, failoverPlanID, req) return err } -func (s *Service) startSolutionFailoverPlanResponseBody(solutionID string, failoverPlanID string) (*connection.APIResponseBody, error) { +func (s *Service) startSolutionFailoverPlanResponseBody(solutionID string, failoverPlanID string, req StartFailoverPlanRequest) (*connection.APIResponseBody, error) { body := &connection.APIResponseBody{} if solutionID == "" { @@ -297,7 +297,7 @@ func (s *Service) startSolutionFailoverPlanResponseBody(solutionID string, failo return body, fmt.Errorf("invalid failover plan id") } - response, err := s.connection.Post(fmt.Sprintf("/draas/v1/solutions/%s/failover-plans/%s/start", solutionID, failoverPlanID), connection.APIRequestParameters{}) + response, err := s.connection.Post(fmt.Sprintf("/draas/v1/solutions/%s/failover-plans/%s/start", solutionID, failoverPlanID), &req) if err != nil { return body, err } @@ -328,7 +328,7 @@ func (s *Service) stopSolutionFailoverPlanResponseBody(solutionID string, failov return body, fmt.Errorf("invalid failover plan id") } - response, err := s.connection.Post(fmt.Sprintf("/draas/v1/solutions/%s/failover-plans/%s/stop", solutionID, failoverPlanID), connection.APIRequestParameters{}) + response, err := s.connection.Post(fmt.Sprintf("/draas/v1/solutions/%s/failover-plans/%s/stop", solutionID, failoverPlanID), nil) if err != nil { return body, err } @@ -547,3 +547,34 @@ func (s *Service) getSolutionHardwarePlanReplicasPaginatedResponseBody(solutionI return nil }) } + +// UpdateSolutionReplicaIOPS updates a solution replica by ID +func (s *Service) UpdateSolutionReplicaIOPS(solutionID string, replicaID string, req UpdateReplicaIOPSRequest) error { + _, err := s.updateSolutionReplicaResponseBody(solutionID, replicaID, req) + + return err +} + +func (s *Service) updateSolutionReplicaResponseBody(solutionID string, replicaID string, req UpdateReplicaIOPSRequest) (*connection.APIResponseBody, error) { + body := &connection.APIResponseBody{} + + if solutionID == "" { + return body, fmt.Errorf("invalid solution id") + } + if replicaID == "" { + return body, fmt.Errorf("invalid replica id") + } + + response, err := s.connection.Post(fmt.Sprintf("/draas/v1/solutions/%s/replicas/%s/iops", solutionID, replicaID), &req) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &ReplicaNotFoundError{ID: replicaID} + } + + return nil + }) +} diff --git a/pkg/service/draas/service_solution_test.go b/pkg/service/draas/service_solution_test.go index b82d0c2..917ea92 100644 --- a/pkg/service/draas/service_solution_test.go +++ b/pkg/service/draas/service_solution_test.go @@ -616,14 +616,18 @@ func TestStartSolutionFailoverPlan(t *testing.T) { connection: c, } - c.EXPECT().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/failover-plans/00000000-0000-0000-0000-000000000001/start", gomock.Any()).Return(&connection.APIResponse{ + req := StartFailoverPlanRequest{ + StartDate: "2020-05-19T08:34:45.031Z", + } + + c.EXPECT().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/failover-plans/00000000-0000-0000-0000-000000000001/start", &req).Return(&connection.APIResponse{ Response: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"00000000-0000-0000-0000-000000000001\"}}"))), StatusCode: 200, }, }, nil).Times(1) - err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001") + err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", req) assert.Nil(t, err) }) @@ -640,7 +644,7 @@ func TestStartSolutionFailoverPlan(t *testing.T) { c.EXPECT().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/failover-plans/00000000-0000-0000-0000-000000000001/start", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) - err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001") + err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", StartFailoverPlanRequest{}) assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) @@ -656,7 +660,7 @@ func TestStartSolutionFailoverPlan(t *testing.T) { connection: c, } - err := s.StartSolutionFailoverPlan("", "00000000-0000-0000-0000-000000000001") + err := s.StartSolutionFailoverPlan("", "00000000-0000-0000-0000-000000000001", StartFailoverPlanRequest{}) assert.NotNil(t, err) assert.Equal(t, "invalid solution id", err.Error()) @@ -672,7 +676,7 @@ func TestStartSolutionFailoverPlan(t *testing.T) { connection: c, } - err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "") + err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "", StartFailoverPlanRequest{}) assert.NotNil(t, err) assert.Equal(t, "invalid failover plan id", err.Error()) @@ -695,7 +699,7 @@ func TestStartSolutionFailoverPlan(t *testing.T) { }, }, nil).Times(1) - err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001") + err := s.StartSolutionFailoverPlan("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", StartFailoverPlanRequest{}) assert.NotNil(t, err) assert.IsType(t, &FailoverPlanNotFoundError{}, err) @@ -1190,3 +1194,104 @@ func TestGetSolutionHardwarePlanReplicas(t *testing.T) { assert.Equal(t, "test error 1", err.Error()) }) } + +func TestUpdateSolutionReplicaIOPS(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + req := UpdateReplicaIOPSRequest{ + IOPSTierID: "someid", + } + + c.EXPECT().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/replicas/00000000-0000-0000-0000-000000000001/iops", &req).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + err := s.UpdateSolutionReplicaIOPS("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", req) + + assert.Nil(t, err) + }) + + 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().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/replicas/00000000-0000-0000-0000-000000000001/iops", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + + err := s.UpdateSolutionReplicaIOPS("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", UpdateReplicaIOPSRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) + + t.Run("InvalidSolutionID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + err := s.UpdateSolutionReplicaIOPS("", "00000000-0000-0000-0000-000000000001", UpdateReplicaIOPSRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "invalid solution id", err.Error()) + }) + + t.Run("InvalidReplicaID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + err := s.UpdateSolutionReplicaIOPS("00000000-0000-0000-0000-000000000000", "", UpdateReplicaIOPSRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "invalid replica id", err.Error()) + }) + + t.Run("404_ReturnsReplicaNotFoundError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Post("/draas/v1/solutions/00000000-0000-0000-0000-000000000000/replicas/00000000-0000-0000-0000-000000000001/iops", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + StatusCode: 404, + }, + }, nil).Times(1) + + err := s.UpdateSolutionReplicaIOPS("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001", UpdateReplicaIOPSRequest{}) + + assert.NotNil(t, err) + assert.IsType(t, &ReplicaNotFoundError{}, err) + }) +}