Skip to content

Commit

Permalink
Transit gateway attachments (#175)
Browse files Browse the repository at this point in the history
Transit Gateway Attachment functionality
  • Loading branch information
JohnSharpe authored Jul 19, 2024
1 parent 2a79730 commit 81b4873
Show file tree
Hide file tree
Showing 4 changed files with 956 additions and 18 deletions.
39 changes: 21 additions & 18 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,20 @@ import (
"github.com/RedisLabs/rediscloud-go-api/service/pricing"
"github.com/RedisLabs/rediscloud-go-api/service/regions"
"github.com/RedisLabs/rediscloud-go-api/service/subscriptions"
"github.com/RedisLabs/rediscloud-go-api/service/transit_gateway/attachments"
)

type Client struct {
Account *account.API
CloudAccount *cloud_accounts.API
Database *databases.API
Subscription *subscriptions.API
Regions *regions.API
LatestBackup *latest_backups.API
LatestImport *latest_imports.API
Pricing *pricing.API
Maintenance *maintenance.API
Account *account.API
CloudAccount *cloud_accounts.API
Database *databases.API
Subscription *subscriptions.API
Regions *regions.API
LatestBackup *latest_backups.API
LatestImport *latest_imports.API
Maintenance *maintenance.API
Pricing *pricing.API
TransitGatewayAttachments *attachments.API
// fixed
FixedPlans *plans.API
FixedSubscriptions *fixedSubscriptions.API
Expand Down Expand Up @@ -77,15 +79,16 @@ func NewClient(configs ...Option) (*Client, error) {
t := internal.NewAPI(client, config.logger)

return &Client{
Account: account.NewAPI(client),
CloudAccount: cloud_accounts.NewAPI(client, t, config.logger),
Database: databases.NewAPI(client, t, config.logger),
Subscription: subscriptions.NewAPI(client, t, config.logger),
Regions: regions.NewAPI(client, t, config.logger),
LatestBackup: latest_backups.NewAPI(client, t, config.logger),
LatestImport: latest_imports.NewAPI(client, t, config.logger),
Pricing: pricing.NewAPI(client),
Maintenance: maintenance.NewAPI(client, t, config.logger),
Account: account.NewAPI(client),
CloudAccount: cloud_accounts.NewAPI(client, t, config.logger),
Database: databases.NewAPI(client, t, config.logger),
Subscription: subscriptions.NewAPI(client, t, config.logger),
Regions: regions.NewAPI(client, t, config.logger),
LatestBackup: latest_backups.NewAPI(client, t, config.logger),
LatestImport: latest_imports.NewAPI(client, t, config.logger),
Maintenance: maintenance.NewAPI(client, t, config.logger),
Pricing: pricing.NewAPI(client),
TransitGatewayAttachments: attachments.NewAPI(client, t, config.logger),
// fixed
FixedPlans: plans.NewAPI(client, config.logger),
FixedPlanSubscriptions: plan_subscriptions.NewAPI(client, config.logger),
Expand Down
56 changes: 56 additions & 0 deletions service/transit_gateway/attachments/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package attachments

import "fmt"

type GetAttachmentsTask struct {
CommandType *string `json:"commandType,omitempty"`
Description *string `json:"description,omitempty"`
Status *string `json:"status,omitempty"`
ID *string `json:"taskId,omitempty"`
Response *Response `json:"response,omitempty"`
}

type Response struct {
ResourceId *int `json:"resourceId,omitempty"`
Resource *Resource `json:"resource,omitempty"`
}

type Resource struct {
TransitGatewayAttachment []*TransitGatewayAttachment `json:"tgws,omitempty"`
}

type TransitGatewayAttachment struct {
Id *int `json:"id,omitempty"`
AwsTgwUid *string `json:"awsTgwUid,omitempty"`
AttachmentUid *string `json:"attachmentUid,omitempty"`
Status *string `json:"status,omitempty"`
AttachmentStatus *string `json:"attachmentStatus,omitempty"`
AwsAccountId *string `json:"awsAccountId,omitempty"`
Cidrs []*Cidr `json:"cidrs,omitempty"`
}

type Cidr struct {
CidrAddress *string `json:"cidrAddress,omitempty"`
Status *string `json:"status,omitempty"`
}

type updateCidrs struct {
Cidrs *[]*string `json:"cidrs,omitempty"`
}

type NotFound struct {
subId int
}

func (f *NotFound) Error() string {
return fmt.Sprintf("subscription %d not found", f.subId)
}

type NotFoundActiveActive struct {
subId int
regionId int
}

func (f *NotFoundActiveActive) Error() string {
return fmt.Sprintf("subscription %d in region %d not found", f.subId, f.regionId)
}
209 changes: 209 additions & 0 deletions service/transit_gateway/attachments/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package attachments

import (
"context"
"fmt"
"net/http"

"github.com/RedisLabs/rediscloud-go-api/internal"
)

type HttpClient interface {
Get(ctx context.Context, name, path string, responseBody interface{}) error
Post(ctx context.Context, name, path string, requsetBody interface{}, responseBody interface{}) error
Put(ctx context.Context, name, path string, requestBody interface{}, responseBody interface{}) error
Delete(ctx context.Context, name, path string, responseBody interface{}) error
}

type TaskWaiter interface {
WaitForResourceId(ctx context.Context, id string) (int, error)
Wait(ctx context.Context, id string) error
}

type Log interface {
Printf(format string, args ...interface{})
}

type API struct {
client HttpClient
taskWaiter TaskWaiter
logger Log
}

func NewAPI(client HttpClient, taskWaiter TaskWaiter, logger Log) *API {
return &API{client: client, taskWaiter: taskWaiter, logger: logger}
}

func (a *API) Get(ctx context.Context, subscription int) (*GetAttachmentsTask, error) {
message := fmt.Sprintf("get TGw attachments for subscription %d", subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways", subscription)
task, err := a.get(ctx, message, address)
if err != nil {
return nil, wrap404Error(subscription, err)
}
return task, nil
}

func (a *API) GetActiveActive(ctx context.Context, subscription int, regionId int) (*GetAttachmentsTask, error) {
message := fmt.Sprintf("get TGw attachments for subscription %d in region %d", subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways", subscription, regionId)
task, err := a.get(ctx, message, address)
if err != nil {
return nil, wrap404ErrorActiveActive(subscription, regionId, err)
}
return task, nil
}

func (a *API) Create(ctx context.Context, subscription int, tgwId int) (int, error) {
message := fmt.Sprintf("create TGw attachment for subscription %d", subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/%d/attachment", subscription, tgwId)
resourceId, err := a.create(ctx, message, address)
if err != nil {
return 0, wrap404Error(subscription, err)
}
return resourceId, nil
}

func (a *API) CreateActiveActive(ctx context.Context, subscription int, regionId int, tgwId int) (int, error) {
message := fmt.Sprintf("create TGw attachment for subscription %d in region %d", subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways/%d/attachment", subscription, regionId, tgwId)
resourceId, err := a.create(ctx, message, address)
if err != nil {
return 0, wrap404ErrorActiveActive(subscription, regionId, err)
}
return resourceId, nil
}

func (a *API) Update(ctx context.Context, subscription int, tgwId int, cidrs []*string) error {
message := fmt.Sprintf("update TGw attachment %d for subscription %d", tgwId, subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/%d/attachment", subscription, tgwId)
err := a.update(ctx, message, address, cidrs)
if err != nil {
return wrap404Error(subscription, err)
}
return nil
}

func (a *API) UpdateActiveActive(ctx context.Context, subscription int, regionId int, tgwId int, cidrs []*string) error {
message := fmt.Sprintf("update TGw attachment %d for subscription %d in region %d", tgwId, subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways/%d/attachment", subscription, regionId, tgwId)
err := a.update(ctx, message, address, cidrs)
if err != nil {
return wrap404ErrorActiveActive(subscription, regionId, err)
}
return nil
}

func (a *API) Delete(ctx context.Context, subscription int, tgwId int) error {
message := fmt.Sprintf("delete TGw attachment %d for subscription %d", tgwId, subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/%d/attachment", subscription, tgwId)
err := a.delete(ctx, message, address)
if err != nil {
return wrap404Error(subscription, err)
}
return nil
}

func (a *API) DeleteActiveActive(ctx context.Context, subscription int, regionId int, tgwId int) error {
message := fmt.Sprintf("delete TGw attachment %d for subscription %d in region %d", tgwId, subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways/%d/attachment", subscription, regionId, tgwId)
err := a.delete(ctx, message, address)
if err != nil {
return wrap404ErrorActiveActive(subscription, regionId, err)
}
return nil
}

func (a *API) get(ctx context.Context, message string, address string) (*GetAttachmentsTask, error) {
var task internal.TaskResponse
err := a.client.Get(ctx, message, address, &task)
if err != nil {
return nil, err
}

a.logger.Printf("Waiting for tgwGetRequest %d to complete", task.ID)

err = a.taskWaiter.Wait(ctx, *task.ID)

a.logger.Printf("tgwGetRequest %d completed, possibly with error", task.ID, err)

var getAttachmentsTask *GetAttachmentsTask
err = a.client.Get(ctx,
fmt.Sprintf("retrieve completed tgwGetRequest task %d", task.ID),
"/tasks/"+*task.ID,
&getAttachmentsTask,
)

if err != nil {
return nil, fmt.Errorf("failed to retrieve completed tgwGetRequest %d: %w", task.ID, err)
}

return getAttachmentsTask, nil
}

func (a *API) create(ctx context.Context, message string, address string) (int, error) {
var task internal.TaskResponse
// TODO Assuming nil is an allowed body
err := a.client.Post(ctx, message, address, nil, &task)
if err != nil {
return 0, err
}

a.logger.Printf("Waiting for task %s to finish creating the TGw attachment", task)

id, err := a.taskWaiter.WaitForResourceId(ctx, *task.ID)
if err != nil {
return 0, fmt.Errorf("failed when creating TGw attachment %d: %w", id, err)
}

return id, nil
}

func (a *API) update(ctx context.Context, message string, address string, cidrs []*string) error {
var task internal.TaskResponse
request := updateCidrs{&cidrs}
err := a.client.Put(ctx, message, address, request, &task)
if err != nil {
return err
}

a.logger.Printf("Waiting for task %s to finish updating the TGw attachment", task)

err = a.taskWaiter.Wait(ctx, *task.ID)
if err != nil {
return fmt.Errorf("failed when updating TGw attachment %w", err)
}

return nil
}

func (a *API) delete(ctx context.Context, message string, address string) error {
var task internal.TaskResponse
err := a.client.Delete(ctx, message, address, &task)
if err != nil {
return err
}

a.logger.Printf("Waiting for task %s to finish deleting the TGw attachment", task)

err = a.taskWaiter.Wait(ctx, *task.ID)
if err != nil {
return fmt.Errorf("failed when deleting TGw attachment %w", err)
}

return nil
}

func wrap404Error(subId int, err error) error {
if v, ok := err.(*internal.HTTPError); ok && v.StatusCode == http.StatusNotFound {
return &NotFound{subId: subId}
}
return err
}

func wrap404ErrorActiveActive(subId int, regionId int, err error) error {
if v, ok := err.(*internal.HTTPError); ok && v.StatusCode == http.StatusNotFound {
return &NotFoundActiveActive{subId: subId, regionId: regionId}
}
return err
}
Loading

0 comments on commit 81b4873

Please sign in to comment.