Skip to content

Commit d37824e

Browse files
author
Mitchell Elholm
committed
Python SR/MR cluster management
1 parent e419c78 commit d37824e

14 files changed

Lines changed: 347 additions & 174 deletions

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ jobs:
5555

5656
- name: Configure and run integration for cluster management
5757
working-directory: ./python/cluster_management
58+
env:
59+
IS_CI: "TRUE"
5860
run: |
5961
python3 -m venv cm-integ
6062
source cm-integ/bin/activate

python/cluster_management/README.md

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,61 @@
22

33
## Overview
44

5-
The code examples in this topic show you how to use the AWS Python SDK with DSQL to create, read, update, and delete clusters.
5+
The code examples in this topic show you how to use the AWS Python SDK with DSQL
6+
to create, update, get, and delete single- and multi-Region clusters.
7+
8+
Each file in the [/src](src) directory demonstrates a minimum
9+
working example for each operation. The example function for each operation is invoked
10+
in [`test_dsql_cluster_management.py`](test/test_dsql_cluster_management.py).
611

712
## Run the examples
813

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

11-
* python version >=3.8.0 is needed
25+
- Python version >= 3.8.0 is installed.
26+
- Valid AWS credentials can be discovered by the [default provider chain](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html).
1227

13-
### Setup test running environment
28+
### Execute tests to create and delete clusters
1429

1530
```sh
16-
source setup.sh
31+
# Optional: Single-Region examples will execute in REGION_1. Defaults to 'us-east-1'.
32+
export REGION_1="us-east-1"
33+
34+
# Optional: Multi-Region examples will create clusters in REGION_1 and REGION_2
35+
# with WITNESS_REGION as witness for both. Defaults to 'us-east-2' for REGION_2
36+
# and 'us-west-2' for WITNESS_REGION.
37+
export REGION_2="us-east-2"
38+
export WITNESS_REGION="us-west-2"
39+
40+
python3 -m venv .venv && source .venv/bin/activate
41+
pip install -r requirements.txt
42+
43+
# Will create, update, read, then delete clusters, use -s to see print statements when running tests
44+
pytest test/test_dsql_cluster_management.py [-s]
1745
```
1846

19-
### Run the example tests
47+
Test execution will take around five minutes as it waits for clusters to complete activation and deletion.
2048

21-
```sh
22-
# Use the account credentials dedicated for python
23-
pytest test/test_example.py
49+
### Executing single operations
50+
Files in [src/](src/) each have a `main()` function that let you exercise single operations.
51+
52+
```shell
53+
# Check each operation for its expected environment variables
54+
REGION_1="us-east-1" CLUSTER_ID_1="<your cluster id>" \
55+
python src/get_cluster.py
2456
```
2557

2658
---
2759

28-
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
60+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2961

3062
SPDX-License-Identifier: MIT-0
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[tool.pytest.ini_options]
22
pythonpath = [
33
"src"
4-
]
4+
]
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pytest>=8
2-
botocore>=1.35.74
3-
boto3>=1.35.74
1+
boto3>=1.38.15
2+
botocore>=1.38.15
3+
pytest>=8

python/cluster_management/setup.sh

Lines changed: 0 additions & 13 deletions
This file was deleted.

python/cluster_management/src/create_multi_region.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,70 @@
11
import boto3
2+
import os
23

3-
def create_multi_region_clusters(client, linkedRegionList, witnessRegion, clusterProperties):
4+
5+
def create_multi_region_clusters(region_1, region_2, witness_region):
46
try:
5-
response = client.create_multi_region_clusters(
6-
linkedRegionList=linkedRegionList,
7-
witnessRegion=witnessRegion,
8-
clusterProperties=clusterProperties,
7+
client_1 = boto3.client("dsql", region_name=region_1)
8+
client_2 = boto3.client("dsql", region_name=region_2)
9+
10+
# We can only set the witness region for the first cluster
11+
cluster_1 = client_1.create_cluster(
12+
deletionProtectionEnabled=True,
13+
multiRegionProperties={"witnessRegion": witness_region},
14+
tags={"Name": "Python-CM-Example-Multi-Region", "Repo": "aws-samples/aurora-dsql-samples"}
15+
)
16+
print(f"Created {cluster_1["arn"]}")
17+
18+
# For the second cluster we can set witness region and designate cluster_1 as a peer
19+
cluster_2 = client_2.create_cluster(
20+
deletionProtectionEnabled=True,
21+
multiRegionProperties={"witnessRegion": witness_region, "clusters": [cluster_1["arn"]]},
22+
tags={"Name": "Python-CM-Example-Multi-Region", "Repo": "aws-samples/aurora-dsql-samples"}
923
)
10-
return response
24+
25+
print(f"Created {cluster_2["arn"]}")
26+
# Now that we know the cluster_2 arn we can set it as a peer of cluster_1
27+
client_1.update_cluster(
28+
identifier=cluster_1["identifier"],
29+
multiRegionProperties={"witnessRegion": witness_region, "clusters": [cluster_2["arn"]]}
30+
)
31+
print(f"Added {cluster_2["arn"]} as a peer of {cluster_1["arn"]}")
32+
33+
# Now that multiRegionProperties is fully defined for both clusters
34+
# they'll begin the transition to ACTIVE
35+
print(f"Waiting for {cluster_1["arn"]} to become ACTIVE")
36+
client_1.get_waiter("cluster_active").wait(
37+
identifier=cluster_1["identifier"],
38+
WaiterConfig={
39+
'Delay': 10,
40+
'MaxAttempts': 50
41+
}
42+
)
43+
44+
print(f"Waiting for {cluster_2["arn"]} to become ACTIVE")
45+
client_2.get_waiter("cluster_active").wait(
46+
identifier=cluster_2["identifier"],
47+
WaiterConfig={
48+
'Delay': 10,
49+
'MaxAttempts': 50
50+
}
51+
)
52+
53+
return cluster_1, cluster_2
54+
1155
except:
12-
print("Unable to create multi-region cluster")
56+
print("Unable to create cluster")
1357
raise
1458

59+
1560
def main():
16-
region = "us-east-1"
17-
client = boto3.client("dsql", region_name=region)
18-
linkedRegionList = ["us-east-1", "us-east-2"]
19-
witnessRegion = "us-west-2"
20-
clusterProperties = {
21-
"us-east-1": {"tags": {"Name": "Foo"}},
22-
"us-east-2": {"tags": {"Name": "Bar"}}
23-
}
24-
response = create_multi_region_clusters(client, linkedRegionList, witnessRegion, clusterProperties)
25-
print("Linked Cluster Arns:", response['linkedClusterArns'])
61+
region_1 = os.environ.get("REGION_1", "us-east-1")
62+
region_2 = os.environ.get("REGION_2", "us-east-2")
63+
witness_region = os.environ.get("WITNESS_REGION", "us-west-2")
64+
(cluster_1, cluster_2) = create_multi_region_clusters(region_1, region_2, witness_region)
65+
print("Created multi region clusters:")
66+
print("Cluster id: " + cluster_1['arn'])
67+
print("Cluster id: " + cluster_2['arn'])
2668

2769

2870
if __name__ == "__main__":

python/cluster_management/src/create_single_region.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
11
import boto3
2+
import os
23

3-
def create_cluster(client, tags, deletion_protection):
4+
5+
def create_cluster(region):
46
try:
5-
response = client.create_cluster(tags=tags, deletionProtectionEnabled=deletion_protection)
6-
return response
7+
client = boto3.client("dsql", region_name=region)
8+
tags = {"Name": "Python-CM-Example-Single-Region", "Repo": "aws-samples/aurora-dsql-samples"}
9+
cluster = client.create_cluster(tags=tags, deletionProtectionEnabled=True)
10+
print(f"Initiated creation of cluster: {cluster["identifier"]}")
11+
12+
print(f"Waiting for {cluster["arn"]} to become ACTIVE")
13+
client.get_waiter("cluster_active").wait(
14+
identifier=cluster["identifier"],
15+
WaiterConfig={
16+
'Delay': 10,
17+
'MaxAttempts': 50
18+
}
19+
)
20+
21+
return cluster
722
except:
823
print("Unable to create cluster")
924
raise
1025

26+
1127
def main():
12-
region = "us-east-1"
13-
client = boto3.client("dsql", region_name=region)
14-
tag = {"Name": "FooBar"}
15-
deletion_protection = True
16-
response = create_cluster(client, tags=tag, deletion_protection=deletion_protection)
17-
print("Cluster id: " + response['identifier'])
28+
region = os.environ.get("REGION_1", "us-east-1")
29+
response = create_cluster(region)
30+
print(f"Created cluster: {response["arn"]}")
1831

1932

2033
if __name__ == "__main__":

python/cluster_management/src/delete_multi_region.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,56 @@
11
import boto3
2+
import os
3+
4+
5+
def delete_multi_region_clusters(region_1, cluster_id_1, region_2, cluster_id_2):
6+
try:
7+
8+
client_1 = boto3.client("dsql", region_name=region_1)
9+
client_2 = boto3.client("dsql", region_name=region_2)
10+
11+
client_1.delete_cluster(identifier=cluster_id_1)
12+
print(f"Deleting cluster {cluster_id_1} in {region_1}")
13+
14+
# cluster_1 will stay in PENDING_DELETE state until cluster_2 is deleted
15+
16+
client_2.delete_cluster(identifier=cluster_id_2)
17+
print(f"Deleting cluster {cluster_id_2} in {region_2}")
18+
19+
# Now that both clusters have been marked for deletion they will transition
20+
# to DELETING state and finalize deletion
21+
print(f"Waiting for {cluster_id_1} to finish deletion")
22+
client_1.get_waiter("cluster_not_exists").wait(
23+
identifier=cluster_id_1,
24+
WaiterConfig={
25+
'Delay': 10,
26+
'MaxAttempts': 50
27+
}
28+
)
29+
30+
print(f"Waiting for {cluster_id_2} to finish deletion")
31+
client_2.get_waiter("cluster_not_exists").wait(
32+
identifier=cluster_id_2,
33+
WaiterConfig={
34+
'Delay': 10,
35+
'MaxAttempts': 50
36+
}
37+
)
38+
39+
except:
40+
print("Unable to delete cluster")
41+
raise
242

3-
def delete_multi_region_clusters(linkedClusterArns, client):
4-
client.delete_multi_region_clusters(linkedClusterArns=linkedClusterArns)
543

644
def main():
7-
region = "us-east-1"
8-
client = boto3.client("dsql", region_name=region)
9-
linkedClusterArns = [
10-
"arn:aws:dsql:us-east-1:111111999999::cluster/foo0bar1baz2quux3quuux4",
11-
"arn:aws:dsql:us-east-2:111111999999::cluster/bar0foo1baz2quux3quuux4"
12-
]
13-
delete_multi_region_clusters(linkedClusterArns, client)
14-
print("Deleting clusters with ARNs:", linkedClusterArns)
45+
region_1 = os.environ.get("REGION_1", "us-east-1")
46+
cluster_id_1 = os.environ.get("CLUSTER_ID_1")
47+
assert cluster_id_1 is not None, "Must provide CLUSTER_ID_1"
48+
region_2 = os.environ.get("REGION_2", "us-east-2")
49+
cluster_id_2 = os.environ.get("CLUSTER_ID_2")
50+
assert cluster_id_2 is not None, "Must provide CLUSTER_ID_2"
51+
52+
delete_multi_region_clusters(region_1, cluster_id_1, region_2, cluster_id_2)
53+
print(f"Deleted {cluster_id_1} in {region_1} and {cluster_id_2} in {region_2}")
1554

1655

1756
if __name__ == "__main__":

python/cluster_management/src/delete_single_region.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
import boto3
2+
import os
23

3-
def delete_cluster(cluster_id, client):
4-
try:
5-
return client.delete_cluster(identifier=cluster_id)
4+
5+
def delete_cluster(region, identifier):
6+
try:
7+
client = boto3.client("dsql", region_name=region)
8+
cluster = client.delete_cluster(identifier=identifier)
9+
print(f"Initiated delete of {cluster["arn"]}")
10+
11+
print("Waiting for cluster to finish deletion")
12+
client.get_waiter("cluster_not_exists").wait(
13+
identifier=cluster["identifier"],
14+
WaiterConfig={
15+
'Delay': 10,
16+
'MaxAttempts': 50
17+
}
18+
)
619
except:
7-
print("Unable to delete cluster " + cluster_id)
20+
print("Unable to delete cluster " + identifier)
821
raise
922

23+
1024
def main():
11-
region = "us-east-1"
12-
client = boto3.client("dsql", region_name=region)
13-
cluster_id = "foo0bar1baz2quux3quuux4"
14-
response = delete_cluster(cluster_id, client)
15-
print("Deleting cluster with ID: " + cluster_id + ", Cluster Status: " + response['status'])
25+
region = os.environ.get("REGION_1", "us-east-1")
26+
cluster_id = os.environ.get("CLUSTER_ID_1")
27+
assert cluster_id is not None, "Must provide CLUSTER_ID_1"
28+
delete_cluster(region, cluster_id)
29+
print(f"Deleted {cluster_id}")
1630

1731

1832
if __name__ == "__main__":

0 commit comments

Comments
 (0)