Skip to content

Commit a55e879

Browse files
authored
go: refactor multi-region for new dsql sdk (#129)
* Updated cluster_management examples to utilize the new AWS Multiregion SDK functionality provided in dsql (v1.3.0) * Added Makefile to build and test
1 parent 967c6a4 commit a55e879

28 files changed

Lines changed: 1217 additions & 389 deletions

.github/workflows/go-cm-integ-tests.yml

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,49 @@ jobs:
4444
with:
4545
role-to-assume: ${{ secrets.GO_IAM_ROLE }}
4646
aws-region: us-east-1
47+
48+
- name: echo-default-env-variables
49+
run: |
50+
echo "Home: ${HOME}"
51+
echo "GITHUB_WORKFLOW: ${GITHUB_WORKFLOW}"
52+
echo "GITHUB_ACTIONS: ${GITHUB_ACTIONS}"
53+
echo "GITHUB_ACTOR: ${GITHUB_ACTOR}"
54+
echo "GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}"
55+
echo "GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}"
56+
echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}"
57+
echo "GITHUB_RUN_ID: ${GITHUB_RUN_ID}"
58+
echo "GITHUB_SHA: ${GITHUB_SHA}"
59+
echo "GITHUB_REF: ${GITHUB_REF}"
60+
echo "GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER}"
61+
4762
48-
- name: Build & Run
49-
working-directory: ./go/cluster_management
63+
- name: Build & Run Create Multi region
64+
working-directory: ./go/cluster_management/cmd/create_multi_region
65+
run: |
66+
go env -w GOPROXY=direct
67+
go test
68+
- name: Build & Run Create Single region
69+
working-directory: ./go/cluster_management/cmd/create_single_region
70+
run: |
71+
go env -w GOPROXY=direct
72+
go test
73+
- name: Build & Run Get Cluster
74+
working-directory: ./go/cluster_management/cmd/get_cluster
75+
run: |
76+
go env -w GOPROXY=direct
77+
go test
78+
- name: Build & Run Update Cluster
79+
working-directory: ./go/cluster_management/cmd/update_cluster
80+
run: |
81+
go env -w GOPROXY=direct
82+
go test
83+
- name: Build & Run Delete Single region
84+
working-directory: ./go/cluster_management/cmd/delete_single_region
85+
run: |
86+
go env -w GOPROXY=direct
87+
go test
88+
- name: Build & Run Delete Multi region
89+
working-directory: ./go/cluster_management/cmd/delete_multi_region
5090
run: |
5191
go env -w GOPROXY=direct
5292
go test

go/cluster_management/Makefile

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Build all cluster management examples
2+
# Go parameters
3+
GOCMD=go
4+
GOBUILD=$(GOCMD) build
5+
GOCLEAN=$(GOCMD) clean
6+
BINARY_DIR=bin
7+
TEST_FLAGS=-v -count=1
8+
9+
# Find all cmd directories
10+
CMD_DIRS := $(notdir $(wildcard cmd/*))
11+
BINARIES := $(addprefix $(BINARY_DIR)/,$(CMD_DIRS))
12+
13+
# Default target
14+
.PHONY: all
15+
all: clean build
16+
17+
.PHONY: test
18+
test: test-all
19+
20+
# Test all commands
21+
.PHONY: test-all
22+
test-all: $(addprefix test-,$(CMD_DIRS))
23+
24+
# Rule to test each command individually
25+
.PHONY: test-%
26+
test-%:
27+
$(GOCMD) test $(TEST_FLAGS) ./cmd/$*
28+
29+
# Create bin directory
30+
$(BINARY_DIR):
31+
mkdir -p $(BINARY_DIR)
32+
33+
# Build all commands
34+
.PHONY: build
35+
build: $(BINARY_DIR) $(BINARIES)
36+
37+
# Rule to build each binary
38+
$(BINARY_DIR)/%: cmd/%
39+
$(GOBUILD) -o $@ ./cmd/$*
40+
41+
# Clean build artifacts
42+
.PHONY: clean
43+
clean:
44+
$(GOCLEAN)
45+
rm -rf $(BINARY_DIR)
46+
47+
# List all commands
48+
.PHONY: list
49+
list:
50+
@echo "Available commands:"
51+
@echo $(CMD_DIRS) | tr ' ' '\n'

go/cluster_management/README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@ The code examples in this topic show you how to use the AWS Go SDK with DSQL to
66

77
## Run the examples
88

9+
### ⚠️ Important
10+
11+
* Running this code might result in charges to your AWS account.
12+
* We recommend that you grant your code least privilege. At most, grant only the
13+
minimum permissions required to perform the task. For more information, see
14+
[Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
15+
* This code is not tested in every AWS Region. For more information, see
16+
[AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).
17+
918
### Prerequisites
1019

1120
* Go version >= 1.21
12-
* AWS credentials file is configured
13-
21+
* Valid AWS credentials can be discovered by the [default provider chain](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials-chain.html).
1422

1523
### Setup test running environment
1624

@@ -20,10 +28,23 @@ Ensure you are authenticated with AWS credentials. No other setup is needed besi
2028

2129
In a terminal run the following commands:
2230

31+
32+
33+
### Execute tests to create and delete clusters
2334
```sh
24-
# Use the account credentials dedicated for golang
35+
make test
36+
```
37+
38+
OR
39+
40+
```shell
2541
go env -w GOPROXY=direct
26-
go test
42+
go test -v -count=1 ./cmd/create_multi_region
43+
go test -v -count=1 ./cmd/create_single_region
44+
go test -v -count=1 ./cmd/get_cluster
45+
go test -v -count=1 ./cmd/update_cluster
46+
go test -v -count=1 ./cmd/delete_multi_region
47+
go test -v -count=1 ./cmd/delete_single_region
2748
```
2849

2950
---

go/cluster_management/client_util.go

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"example/internal/util"
6+
"fmt"
7+
"log"
8+
"os"
9+
"time"
10+
11+
"github.com/aws/aws-sdk-go-v2/aws"
12+
"github.com/aws/aws-sdk-go-v2/config"
13+
"github.com/aws/aws-sdk-go-v2/service/dsql"
14+
dtypes "github.com/aws/aws-sdk-go-v2/service/dsql/types"
15+
)
16+
17+
func CreateMultiRegionClusters(ctx context.Context, witness, region1, region2 string) error {
18+
19+
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region1))
20+
if err != nil {
21+
log.Fatalf("Failed to load AWS configuration: %v", err)
22+
}
23+
24+
// Create a DSQL region 1 client
25+
client := dsql.NewFromConfig(cfg, func(o *dsql.Options) {
26+
o.Region = region1
27+
})
28+
29+
cfg2, err := config.LoadDefaultConfig(ctx, config.WithRegion(region2))
30+
if err != nil {
31+
log.Fatalf("Failed to load AWS configuration: %v", err)
32+
}
33+
34+
// Create a DSQL region 2 client
35+
client2 := dsql.NewFromConfig(cfg2, func(o *dsql.Options) {
36+
o.Region = region2
37+
})
38+
39+
// Create cluster
40+
deleteProtect := true
41+
42+
// We can only set the witness region for the first cluster
43+
input := &dsql.CreateClusterInput{
44+
DeletionProtectionEnabled: &deleteProtect,
45+
MultiRegionProperties: &dtypes.MultiRegionProperties{
46+
WitnessRegion: aws.String(witness),
47+
},
48+
Tags: map[string]string{
49+
"Repo": os.Getenv("GITHUB_REPOSITORY"),
50+
"Name": util.GetUniqueRunTagName("go multi-region cluster"),
51+
},
52+
}
53+
54+
clusterProperties, err := client.CreateCluster(context.Background(), input)
55+
56+
if err != nil {
57+
return fmt.Errorf("failed to create first cluster: %v", err)
58+
}
59+
60+
// create second cluster
61+
cluster2Arns := []string{*clusterProperties.Arn}
62+
63+
// For the second cluster we can set witness region and designate the first cluster as a peer
64+
input2 := &dsql.CreateClusterInput{
65+
DeletionProtectionEnabled: &deleteProtect,
66+
MultiRegionProperties: &dtypes.MultiRegionProperties{
67+
WitnessRegion: aws.String("us-west-2"),
68+
Clusters: cluster2Arns,
69+
},
70+
Tags: map[string]string{
71+
"Repo": os.Getenv("GITHUB_REPOSITORY"),
72+
"Name": util.GetUniqueRunTagName("go multi-region cluster"),
73+
},
74+
}
75+
76+
clusterProperties2, err := client2.CreateCluster(context.Background(), input2)
77+
78+
if err != nil {
79+
return fmt.Errorf("failed to create second cluster: %v", err)
80+
}
81+
82+
// link initial cluster to second cluster
83+
cluster1Arns := []string{*clusterProperties2.Arn}
84+
85+
// Now that we know the second cluster arn we can set it as a peer of the first cluster
86+
input3 := dsql.UpdateClusterInput{
87+
Identifier: clusterProperties.Identifier,
88+
MultiRegionProperties: &dtypes.MultiRegionProperties{
89+
WitnessRegion: aws.String("us-west-2"),
90+
Clusters: cluster1Arns,
91+
}}
92+
93+
_, err = client.UpdateCluster(context.Background(), &input3)
94+
95+
if err != nil {
96+
return fmt.Errorf("failed to update cluster to associate with first cluster. %v", err)
97+
}
98+
99+
// Create the waiter with our custom options for first cluster
100+
waiter := dsql.NewClusterActiveWaiter(client, func(o *dsql.ClusterActiveWaiterOptions) {
101+
o.MaxDelay = 30 * time.Second // Creating a multi-region cluster can take a few minutes
102+
o.MinDelay = 10 * time.Second
103+
o.LogWaitAttempts = true
104+
})
105+
106+
// Now that multiRegionProperties is fully defined for both clusters
107+
// they'll begin the transition to ACTIVE
108+
109+
// Create the input for the clusterProperties to monitor for first cluster
110+
getInput := &dsql.GetClusterInput{
111+
Identifier: clusterProperties.Identifier,
112+
}
113+
114+
// Wait for the first cluster to become active
115+
fmt.Printf("Waiting for first cluster %s to become active...\n", *clusterProperties.Identifier)
116+
err = waiter.Wait(ctx, getInput, 5*time.Minute)
117+
if err != nil {
118+
return fmt.Errorf("error waiting for first cluster to become active: %w", err)
119+
}
120+
121+
// Create the waiter with our custom options
122+
waiter2 := dsql.NewClusterActiveWaiter(client2, func(o *dsql.ClusterActiveWaiterOptions) {
123+
o.MaxDelay = 30 * time.Second // Creating a multi-region cluster can take a few minutes
124+
o.MinDelay = 10 * time.Second
125+
o.LogWaitAttempts = true
126+
})
127+
128+
// Create the input for the clusterProperties to monitor for second
129+
getInput2 := &dsql.GetClusterInput{
130+
Identifier: clusterProperties2.Identifier,
131+
}
132+
133+
// Wait for the second cluster to become active
134+
fmt.Printf("Waiting for second cluster %s to become active...\n", *clusterProperties2.Identifier)
135+
err = waiter2.Wait(ctx, getInput2, 5*time.Minute)
136+
if err != nil {
137+
return fmt.Errorf("error waiting for second cluster to become active: %w", err)
138+
}
139+
140+
fmt.Printf("Cluster %s is now active\n", *clusterProperties.Identifier)
141+
fmt.Printf("Cluster %s is now active\n", *clusterProperties2.Identifier)
142+
return nil
143+
}
144+
145+
// Example usage in main function
146+
func main() {
147+
// Set up context with timeout
148+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
149+
defer cancel()
150+
151+
witnessRegion := util.GetEnvWithDefault("WITNESS_REGION", "us-west-2")
152+
153+
region1 := util.GetEnvWithDefault("REGION_1", "us-east-1")
154+
region2 := util.GetEnvWithDefault("REGION_2", "us-east-2")
155+
156+
err := CreateMultiRegionClusters(ctx, witnessRegion, region1, region2)
157+
if err != nil {
158+
fmt.Printf("failed to create multi-region clusters: %v", err)
159+
panic(err)
160+
}
161+
162+
}

0 commit comments

Comments
 (0)