Skip to content

Commit

Permalink
Merge pull request #163 from ans-group/backup-props-change
Browse files Browse the repository at this point in the history
Backup Gateway support
  • Loading branch information
Xiol authored Nov 13, 2024
2 parents 65414da + 0a3f2ca commit 904fd1f
Show file tree
Hide file tree
Showing 8 changed files with 698 additions and 0 deletions.
18 changes: 18 additions & 0 deletions pkg/service/ecloud/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,21 @@ type VPNGatewayUserNotFoundError struct {
func (e *VPNGatewayUserNotFoundError) Error() string {
return fmt.Sprintf("VPN gateway user not found with ID [%s]", e.ID)
}

// BackupGatewaySpecificationNotFoundError represents a VPN gateway specification not found error
type BackupGatewaySpecificationNotFoundError struct {
ID string
}

func (e *BackupGatewaySpecificationNotFoundError) Error() string {
return fmt.Sprintf("Backup gateway specification not found with ID [%s]", e.ID)
}

// BackupGatewayNotFoundError represents a backup gateway not found error
type BackupGatewayNotFoundError struct {
ID string
}

func (e *BackupGatewayNotFoundError) Error() string {
return fmt.Sprintf("Backup gateway not found with ID [%s]", e.ID)
}
27 changes: 27 additions & 0 deletions pkg/service/ecloud/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ type Instance struct {
RAMCapacity int `json:"ram_capacity"`
Locked bool `json:"locked"`
BackupEnabled bool `json:"backup_enabled"`
BackupGatewayID string `json:"backup_gateway_id"`
BackupAgentEnabled bool `json:"secure_backup"` // TODO: Change tag to 'backup_agent_enabled' when ADO#34659 released
IsEncrypted bool `json:"is_encrypted"`
Platform string `json:"platform"`
VolumeCapacity int `json:"volume_capacity"`
Expand Down Expand Up @@ -1063,3 +1065,28 @@ type VPNGatewayUser struct {
CreatedAt connection.DateTime `json:"created_at"`
UpdatedAt connection.DateTime `json:"updated_at"`
}

// BackupGatewaySpecification represents a Backup Gateway specification
type BackupGatewaySpecification struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CPU int `json:"cpu"`
RAM int `json:"ram"`
IopsID string `json:"iops_id"`
VolumeCapacity int `json:"volume_capacity"`
ImageID string `json:"image_id"`
}

// BackupGateway represents a Backup Gateway
type BackupGateway struct {
ID string `json:"id"`
VPCID string `json:"vpc_id"`
Name string `json:"name"`
AvailabilityZoneID string `json:"availability_zone_id"`
GatewaySpecID string `json:"gateway_spec_id"`
Sync ResourceSync `json:"sync"`
Task ResourceTask `json:"task"`
CreatedAt connection.DateTime `json:"created_at"`
UpdatedAt connection.DateTime `json:"updated_at"`
}
13 changes: 13 additions & 0 deletions pkg/service/ecloud/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ type CreateInstanceRequest struct {
VolumeCapacity int `json:"volume_capacity"`
VolumeIOPS int `json:"volume_iops,omitempty"`
BackupEnabled bool `json:"backup_enabled"`
BackupGatewayID string `json:"backup_gateway_id,omitempty"`
BackupAgentEnabled bool `json:"secure_backup,omitempty"` // XXX: This will change in the future to `backup_agent_enabled`, see ADO#34659
IsEncrypted bool `json:"is_encrypted"`
NetworkID string `json:"network_id,omitempty"`
FloatingIPID string `json:"floating_ip_id,omitempty"`
Expand Down Expand Up @@ -662,3 +664,14 @@ type PatchVPNGatewayUserRequest struct {
Name string `json:"name,omitempty"`
Password string `json:"password,omitempty"`
}

type CreateBackupGatewayRequest struct {
Name string `json:"name,omitempty"`
VPCID string `json:"vpc_id"`
RouterID string `json:"router_id"`
GatewaySpecID string `json:"gateway_spec_id"`
}

type PatchBackupGatewayRequest struct {
Name string `json:"name"`
}
13 changes: 13 additions & 0 deletions pkg/service/ecloud/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,19 @@ type ECloudService interface {
GetIOPSTiers(parameters connection.APIRequestParameters) ([]IOPSTier, error)
GetIOPSTiersPaginated(parameters connection.APIRequestParameters) (*connection.Paginated[IOPSTier], error)
GetIOPSTier(iopsID string) (IOPSTier, error)

// Backup Gateway Specifications
GetBackupGatewaySpecifications(parameters connection.APIRequestParameters) ([]BackupGatewaySpecification, error)
GetBackupGatewaySpecificationsPaginated(parameters connection.APIRequestParameters) (*connection.Paginated[BackupGatewaySpecification], error)
GetBackupGatewaySpecification(specificationID string) (BackupGatewaySpecification, error)

// Backup Gateways
GetBackupGateways(parameters connection.APIRequestParameters) ([]BackupGateway, error)
GetBackupGatewaysPaginated(parameters connection.APIRequestParameters) (*connection.Paginated[BackupGateway], error)
GetBackupGateway(gatewayID string) (BackupGateway, error)
CreateBackupGateway(req CreateBackupGatewayRequest) (TaskReference, error)
PatchBackupGateway(gatewayID string, req PatchBackupGatewayRequest) (TaskReference, error)
DeleteBackupGateway(gatewayID string) (string, error)
}

// Service implements ECloudService for managing
Expand Down
88 changes: 88 additions & 0 deletions pkg/service/ecloud/service_backupgateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package ecloud

import (
"fmt"

"github.com/ans-group/sdk-go/pkg/connection"
)

// GetBackupGateways retrieves a list of backup gateways
func (s *Service) GetBackupGateways(parameters connection.APIRequestParameters) ([]BackupGateway, error) {
return connection.InvokeRequestAll(s.GetBackupGatewaysPaginated, parameters)
}

// GetBackupGatewaysPaginated retrieves a paginated list of backup gateways
func (s *Service) GetBackupGatewaysPaginated(parameters connection.APIRequestParameters) (*connection.Paginated[BackupGateway], error) {
body, err := s.getBackupGatewaysPaginatedResponseBody(parameters)
return connection.NewPaginated(body, parameters, s.GetBackupGatewaysPaginated), err
}

func (s *Service) getBackupGatewaysPaginatedResponseBody(parameters connection.APIRequestParameters) (*connection.APIResponseBodyData[[]BackupGateway], error) {
return connection.Get[[]BackupGateway](s.connection, "/ecloud/v2/backup-gateways", parameters)
}

// GetBackupGateway retrieves a single backup gateway by ID
func (s *Service) GetBackupGateway(gatewayID string) (BackupGateway, error) {
body, err := s.getBackupGatewayResponseBody(gatewayID)

return body.Data, err
}

func (s *Service) getBackupGatewayResponseBody(gatewayID string) (*connection.APIResponseBodyData[BackupGateway], error) {
if gatewayID == "" {
return &connection.APIResponseBodyData[BackupGateway]{}, fmt.Errorf("invalid backup gateway id")
}

return connection.Get[BackupGateway](s.connection, fmt.Sprintf("/ecloud/v2/backup-gateways/%s", gatewayID), connection.APIRequestParameters{}, connection.NotFoundResponseHandler(&BackupGatewayNotFoundError{ID: gatewayID}))
}

// CreateBackupGateway creates a new backup gateway
func (s *Service) CreateBackupGateway(req CreateBackupGatewayRequest) (TaskReference, error) {
body, err := s.createBackupGatewayResponseBody(req)

return body.Data, err
}

func (s *Service) createBackupGatewayResponseBody(req CreateBackupGatewayRequest) (*connection.APIResponseBodyData[TaskReference], error) {
return connection.Post[TaskReference](s.connection, "/ecloud/v2/backup-gateways", &req)
}

// PatchBackupGateway patches a backup gateway
func (s *Service) PatchBackupGateway(gatewayID string, req PatchBackupGatewayRequest) (TaskReference, error) {
body, err := s.patchBackupGatewayResponseBody(gatewayID, req)

return body.Data, err
}

func (s *Service) patchBackupGatewayResponseBody(gatewayID string, req PatchBackupGatewayRequest) (*connection.APIResponseBodyData[TaskReference], error) {
if gatewayID == "" {
return &connection.APIResponseBodyData[TaskReference]{}, fmt.Errorf("invalid gateway id")
}

return connection.Patch[TaskReference](
s.connection,
fmt.Sprintf("/ecloud/v2/backup-gateways/%s", gatewayID),
&req,
connection.NotFoundResponseHandler(&BackupGatewayNotFoundError{ID: gatewayID}),
)
}

// DeleteBackupGateway deletes a backup gateway
func (s *Service) DeleteBackupGateway(gatewayID string) (string, error) {
body, err := s.deleteBackupGatewayResponseBody(gatewayID)

return body.Data.TaskID, err
}

func (s *Service) deleteBackupGatewayResponseBody(gatewayID string) (*connection.APIResponseBodyData[TaskReference], error) {
if gatewayID == "" {
return &connection.APIResponseBodyData[TaskReference]{}, fmt.Errorf("invalid gateway id")
}

return connection.Delete[TaskReference](
s.connection,
fmt.Sprintf("/ecloud/v2/backup-gateways/%s", gatewayID),
nil,
connection.NotFoundResponseHandler(&BackupGatewayNotFoundError{ID: gatewayID}),
)
}
42 changes: 42 additions & 0 deletions pkg/service/ecloud/service_backupgateway_specs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ecloud

import (
"fmt"

"github.com/ans-group/sdk-go/pkg/connection"
)

// GetBackupGatewaySpecifications retrieves a list of Backup gateway specifications
func (s *Service) GetBackupGatewaySpecifications(parameters connection.APIRequestParameters) ([]BackupGatewaySpecification, error) {
return connection.InvokeRequestAll(s.GetBackupGatewaySpecificationsPaginated, parameters)
}

// GetBackupGatewaySpecificationsPaginated retrieves a paginated list of Backup gateway specifications
func (s *Service) GetBackupGatewaySpecificationsPaginated(parameters connection.APIRequestParameters) (*connection.Paginated[BackupGatewaySpecification], error) {
body, err := s.getBackupGatewaySpecificationsPaginatedResponseBody(parameters)
return connection.NewPaginated(body, parameters, s.GetBackupGatewaySpecificationsPaginated), err
}

func (s *Service) getBackupGatewaySpecificationsPaginatedResponseBody(parameters connection.APIRequestParameters) (*connection.APIResponseBodyData[[]BackupGatewaySpecification], error) {
return connection.Get[[]BackupGatewaySpecification](s.connection, "/ecloud/v2/backup-gateway-specs", parameters)
}

// GetBackupGatewaySpecification retrieves a single Backup gateway specification by ID
func (s *Service) GetBackupGatewaySpecification(specificationID string) (BackupGatewaySpecification, error) {
body, err := s.getBackupGatewaySpecificationResponseBody(specificationID)

return body.Data, err
}

func (s *Service) getBackupGatewaySpecificationResponseBody(specificationID string) (*connection.APIResponseBodyData[BackupGatewaySpecification], error) {
if specificationID == "" {
return &connection.APIResponseBodyData[BackupGatewaySpecification]{}, fmt.Errorf("invalid backup gateway specification id")
}

return connection.Get[BackupGatewaySpecification](
s.connection,
fmt.Sprintf("/ecloud/v2/backup-gateway-specs/%s", specificationID),
connection.APIRequestParameters{},
connection.NotFoundResponseHandler(&BackupGatewaySpecificationNotFoundError{ID: specificationID}),
)
}
140 changes: 140 additions & 0 deletions pkg/service/ecloud/service_backupgateway_specs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package ecloud

import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"testing"

"github.com/ans-group/sdk-go/pkg/connection"
"github.com/ans-group/sdk-go/test/mocks"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

func TestGetBackupGatewaySpecifications(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/backup-gateway-specs", gomock.Any()).Return(&connection.APIResponse{
Response: &http.Response{
Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"bkupgs-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))),
StatusCode: 200,
},
}, nil).Times(1)

specs, err := s.GetBackupGatewaySpecifications(connection.APIRequestParameters{})

assert.Nil(t, err)
assert.Len(t, specs, 1)
assert.Equal(t, "bkupgs-abcdef12", specs[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/backup-gateway-specs", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1"))

_, err := s.GetBackupGatewaySpecifications(connection.APIRequestParameters{})

assert.NotNil(t, err)
assert.Equal(t, "test error 1", err.Error())
})
}

func TestGetBackupGatewaySpecification(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,
}

c.EXPECT().Get("/ecloud/v2/backup-gateway-specs/bkupgs-abcdef12", gomock.Any()).Return(&connection.APIResponse{
Response: &http.Response{
Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"bkupgs-abcdef12\"}}"))),
StatusCode: 200,
},
}, nil).Times(1)

spec, err := s.GetBackupGatewaySpecification("bkupgs-abcdef12")

assert.Nil(t, err)
assert.Equal(t, "bkupgs-abcdef12", spec.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/backup-gateway-specs/bkupgs-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1)

_, err := s.GetBackupGatewaySpecification("bkupgs-abcdef12")

assert.NotNil(t, err)
assert.Equal(t, "test error 1", err.Error())
})

t.Run("InvalidBackupGatewaySpecificationID_ReturnsError", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

c := mocks.NewMockConnection(mockCtrl)

s := Service{
connection: c,
}

_, err := s.GetBackupGatewaySpecification("")

assert.NotNil(t, err)
assert.Equal(t, "invalid backup gateway specification id", err.Error())
})

t.Run("404_ReturnsBackupGatewaySpecificationNotFoundError", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

c := mocks.NewMockConnection(mockCtrl)

s := Service{
connection: c,
}

c.EXPECT().Get("/ecloud/v2/backup-gateway-specs/bkupgs-abcdef12", gomock.Any()).Return(&connection.APIResponse{
Response: &http.Response{
Body: ioutil.NopCloser(bytes.NewReader([]byte(""))),
StatusCode: 404,
},
}, nil).Times(1)

_, err := s.GetBackupGatewaySpecification("bkupgs-abcdef12")

assert.NotNil(t, err)
assert.IsType(t, &BackupGatewaySpecificationNotFoundError{}, err)
})
}
Loading

0 comments on commit 904fd1f

Please sign in to comment.