Skip to content

Commit 5d47c0d

Browse files
committed
Initial version of new cluster management sdk
1 parent c38e2c5 commit 5d47c0d

14 files changed

Lines changed: 511 additions & 306 deletions

File tree

go/cluster_management/client_util.go

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

0 commit comments

Comments
 (0)