Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v5.0.0
uses: actions/checkout@v6.0.1

- name: Install Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v6.1.0
with:
go-version-file: go.mod
cache: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v5.0.0
uses: actions/checkout@v6.0.1

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/vulnerability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5.0.0
uses: actions/checkout@v6.0.1

- name: Install Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v6.1.0
with:
go-version-file: go.mod
cache: true
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
See updating [Changelog example here](https://keepachangelog.com/en/1.0.0/).

## 0.44.0 (5th December 2025)

### Added:
* Added Transit Gateway invitation support: `ListInvitations()`, `AcceptInvitation()`, and `RejectInvitation()` methods for both Pro and Active-Active subscriptions

## 0.43.0 (11th November 2025)

### Added:
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ module github.com/RedisLabs/rediscloud-go-api

go 1.24.0

toolchain go1.25.3
toolchain go1.25.5

require (
github.com/avast/retry-go/v4 v4.7.0
github.com/stretchr/testify v1.11.1
golang.org/x/tools v0.38.0
golang.org/x/tools v0.39.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
20 changes: 10 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
26 changes: 26 additions & 0 deletions service/transit_gateway/attachments/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,32 @@ type updateCidrs struct {
Cidrs *[]*string `json:"cidrs,omitempty"`
}

type TransitGatewayInvitation struct {
Id *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
ResourceShareUid *string `json:"resourceShareUid,omitempty"`
AwsAccountId *string `json:"awsAccountId,omitempty"`
Status *string `json:"status,omitempty"`
SharedDate *string `json:"sharedDate,omitempty"`
}

type InvitationsResource struct {
Resources []*TransitGatewayInvitation `json:"resources,omitempty"`
}

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

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

type NotFound struct {
subId int
}
Expand Down
129 changes: 128 additions & 1 deletion service/transit_gateway/attachments/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,66 @@ func (a *API) DeleteActiveActive(ctx context.Context, subscription int, regionId
return nil
}

func (a *API) ListInvitations(ctx context.Context, subscription int) ([]*TransitGatewayInvitation, error) {
message := fmt.Sprintf("list TGw invitations for subscription %d", subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/invitations", subscription)
invitations, err := a.listInvitations(ctx, message, address)
if err != nil {
return nil, wrap404Error(subscription, err)
}
return invitations, nil
}

func (a *API) ListInvitationsActiveActive(ctx context.Context, subscription int, regionId int) ([]*TransitGatewayInvitation, error) {
message := fmt.Sprintf("list TGw invitations for subscription %d in region %d", subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways/invitations", subscription, regionId)
invitations, err := a.listInvitations(ctx, message, address)
if err != nil {
return nil, wrap404ErrorActiveActive(subscription, regionId, err)
}
return invitations, nil
}

func (a *API) AcceptInvitation(ctx context.Context, subscription int, tgwInvitationId int) error {
message := fmt.Sprintf("accept TGw invitation %d for subscription %d", tgwInvitationId, subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/invitations/%d/accept", subscription, tgwInvitationId)
err := a.acceptInvitation(ctx, message, address)
if err != nil {
return wrap404Error(subscription, err)
}
return nil
}

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

func (a *API) RejectInvitation(ctx context.Context, subscription int, tgwInvitationId int) error {
message := fmt.Sprintf("reject TGw invitation %d for subscription %d", tgwInvitationId, subscription)
address := fmt.Sprintf("/subscriptions/%d/transitGateways/invitations/%d/reject", subscription, tgwInvitationId)
err := a.rejectInvitation(ctx, message, address)
if err != nil {
return wrap404Error(subscription, err)
}
return nil
}

func (a *API) RejectInvitationActiveActive(ctx context.Context, subscription int, regionId int, tgwInvitationId int) error {
message := fmt.Sprintf("reject TGw invitation %d for subscription %d in region %d", tgwInvitationId, subscription, regionId)
address := fmt.Sprintf("/subscriptions/%d/regions/%d/transitGateways/invitations/%d/reject", subscription, regionId, tgwInvitationId)
err := a.rejectInvitation(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)
Expand All @@ -124,8 +184,11 @@ func (a *API) get(ctx context.Context, message string, address string) (*GetAtta
a.logger.Printf("Waiting for tgwGetRequest %d to complete", task.ID)

err = a.taskWaiter.Wait(ctx, *task.ID)
if err != nil {
return nil, err
}

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

var getAttachmentsTask *GetAttachmentsTask
err = a.client.Get(ctx,
Expand Down Expand Up @@ -194,6 +257,70 @@ func (a *API) delete(ctx context.Context, message string, address string) error
return nil
}

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

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

err = a.taskWaiter.Wait(ctx, *task.ID)
if err != nil {
return nil, err
}

a.logger.Printf("tgwListInvitationsRequest %d completed", task.ID)

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

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

return invitationsResponse.Response.Resource.Resources, nil
}

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

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

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

return nil
}

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

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

err = a.taskWaiter.Wait(ctx, *task.ID)
if err != nil {
return fmt.Errorf("failed when rejecting TGw invitation %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}
Expand Down
Loading