Skip to content

Commit 9ffd759

Browse files
feat!: parameterise snapshot admin username (#2)
# What this PR is This PR parameterises the `db_snapshot_admin_username` parameter. This is because the `create_database_server` function internally was hardcoding the admin username of snapshots, which we discovered didn't align to our example in CSDA STAC API: NASA-IMPACT/csda-project#753 (comment) With this change, we can now override this value so that when a DB is restored from a snapshot, its admin user just gets a new password generated and we don't lock ourselves out 🎉 As this is a breaking change (changed the default value to be the RDS default value _and_ parameterised it) I've bumped the version - Not sure how we release this, but looks like we just install via git url in the projects that use this. # What I changed * Bumped version in `VERSION` * Added in `.flake8` just to reduce some linting issues (I envision in another workstream we actally give this repo some TLC in terms of dev tooling) * Added a new example to the `README.md` for the above changes and removed some unused vars in the other examples * Lint fixes in `cdk_bootstrapped_db/constructs.py` * Parameterised `db_snapshot_admin_username` in `cdk_boostrapped_db/helpers.py:create_database_server` # How you can test this If you're using the `create_database_server` functionality with a snapshot, you should be able to install this new version and just provide `db_snapshot_admin_username` as the value of the admin user of the snapshot and you should get a cdk diff with no changes to that construct. **Or** just watch this issue as we tackle it: NASA-IMPACT/csda-project#753 --------- Co-authored-by: Chris Holden <[email protected]>
1 parent 540c249 commit 9ffd759

File tree

5 files changed

+93
-14
lines changed

5 files changed

+93
-14
lines changed

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
max-line-length=88

README.md

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ This CDK Construct enables provisioning an RDS Database (and optionally a DB Ser
77
```python
88
import os
99
from aws_cdk import (
10-
Duration,
1110
aws_ec2 as ec2,
1211
aws_rds as rds,
1312
aws_lambda as lambda_,
1413
)
1514

1615
from constructs import Construct
1716

18-
from cdk_bootstrapped_db.helpers import create_database_server
1917
from cdk_bootstrapped_db.constructs import BootstrappedDb
2018

2119

@@ -24,7 +22,6 @@ class MyDatabase(Construct):
2422
self,
2523
scope: Construct,
2624
id: str,
27-
name: str,
2825
secrets_prefix: str,
2926
db_server: rds.DatabaseInstance,
3027
vpc: ec2.IVpc,
@@ -66,7 +63,6 @@ This package comes with a helper function for setting up a new RDS server. The a
6663
```python
6764
import os
6865
from aws_cdk import (
69-
Duration,
7066
aws_ec2 as ec2,
7167
aws_rds as rds,
7268
aws_lambda as lambda_,
@@ -83,7 +79,6 @@ class MyDatabase(Construct):
8379
self,
8480
scope: Construct,
8581
id: str,
86-
name: str,
8782
secrets_prefix: str,
8883
vpc: ec2.IVpc,
8984
**kwargs,
@@ -126,3 +121,79 @@ class MyDatabase(Construct):
126121

127122
self.db_connection_secret = self.db.secret
128123
```
124+
125+
### Creating an RDS Server from a Snapshot
126+
127+
If you have a snapshot of an RDS Server that you wish to restore in a new deployment, you can pass in the optional parameter
128+
`db_snapshot_arn` to `create_database_server` instead of using `db_name`.
129+
130+
This snapshot must reside in the region you're deploying into, you can copy a snapshot across regions following these docs:
131+
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_CopySnapshot.html
132+
133+
By default, the created server will use the admin username of `postgres` - If the RDS Server your snapshot is from used a
134+
different admin username, you can provide it with the parameter `db_snapshot_admin_username`.
135+
136+
This whole scenario is shown below:
137+
138+
```python
139+
import os
140+
from aws_cdk import (
141+
aws_ec2 as ec2,
142+
aws_rds as rds,
143+
aws_lambda as lambda_,
144+
)
145+
146+
from constructs import Construct
147+
148+
from cdk_bootstrapped_db.helpers import create_database_server
149+
from cdk_bootstrapped_db.constructs import BootstrappedDb
150+
151+
152+
class MyDatabase(Construct):
153+
def __init__(
154+
self,
155+
scope: Construct,
156+
id: str,
157+
secrets_prefix: str,
158+
vpc: ec2.IVpc,
159+
**kwargs,
160+
):
161+
super().__init__(scope, id, **kwargs)
162+
163+
self.db_server = create_database_server(
164+
self,
165+
"MyDBServer",
166+
identifier="mydbserver",
167+
vpc=vpc,
168+
db_snapshot_arn="arn:aws:rds:us-west-2:123456789012:snapshot:mysql-instance1-snapshot-20130805",
169+
db_snapshot_admin_username="myadminusername",
170+
db_version=rds.PostgresEngineVersion.VER_14,
171+
instance_type=ec2.InstanceType.of(
172+
ec2.InstanceClass.BURSTABLE4_GRAVITON, ec2.InstanceSize.NANO
173+
),
174+
)
175+
176+
db_setup_handler = lambda_.Function(
177+
self,
178+
"RunMigrations",
179+
handler="handler.handler",
180+
runtime=lambda_.Runtime.PYTHON_3_8,
181+
code=lambda_.Code.from_docker_build(
182+
path=os.path.abspath("."),
183+
file="Dockerfile",
184+
),
185+
vpc=vpc,
186+
)
187+
188+
self.db = BootstrappedDb(
189+
self,
190+
"MyDB",
191+
db=self.db_server,
192+
new_dbname="mydb",
193+
new_username="mydbuser",
194+
secrets_prefix=secrets_prefix,
195+
handler=db_setup_handler,
196+
)
197+
198+
self.db_connection_secret = self.db.secret
199+
```

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.0
1+
3.0.0

cdk_bootstrapped_db/constructs.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
import os
3-
from datetime import datetime
43
from typing import Optional, Union
54

65
from aws_cdk import (
@@ -56,7 +55,9 @@ def __init__(
5655
secret_string_template=json.dumps(
5756
{
5857
"dbname": new_dbname,
59-
"engine": db_engine if db_engine else db.engine.engine_type, # type: ignore
58+
"engine": db_engine
59+
if db_engine
60+
else db.engine.engine_type, # type: ignore
6061
"port": db.instance_endpoint.port,
6162
"host": db.instance_endpoint.hostname,
6263
"username": new_username,
@@ -83,7 +84,9 @@ def __init__(
8384
secret_string_template=json.dumps(
8485
{
8586
"dbname": new_dbname,
86-
"engine": db_engine if db_engine else db.engine.engine_type, # type: ignore
87+
"engine": db_engine
88+
if db_engine
89+
else db.engine.engine_type, # type: ignore
8790
"port": db.instance_endpoint.port,
8891
"host": db.instance_endpoint.hostname,
8992
"username": read_only_username,
@@ -92,7 +95,7 @@ def __init__(
9295
generate_string_key="password",
9396
exclude_punctuation=True,
9497
),
95-
description=f"Read-only user secret deployed by {Stack.of(self).stack_name}",
98+
description=f"Read-only user secret deployed by {Stack.of(self).stack_name}", # noqa: E501
9699
)
97100

98101
self.provider = custom_resources.Provider(
@@ -108,9 +111,9 @@ def __init__(
108111

109112
# Optionally include the read-only secret ARN
110113
if self.read_only_secret:
111-
resource_properties["read_only_user_secret_arn"] = (
112-
self.read_only_secret.secret_arn
113-
)
114+
resource_properties[
115+
"read_only_user_secret_arn"
116+
] = self.read_only_secret.secret_arn
114117

115118
self.resource = CustomResource(
116119
scope=scope,

cdk_bootstrapped_db/helpers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ def create_database_server(
1111
vpc: ec2.IVpc,
1212
subnet_selection: ec2.SubnetSelection,
1313
deletion_protect: bool,
14+
# Default admin username for Postgres is "postgres" for rds.DatabaseInstance
15+
# https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_rds/DatabaseInstance.html#aws_cdk.aws_rds.DatabaseInstance
16+
db_snapshot_admin_username: str = "postgres",
1417
db_name: Optional[str] = None,
1518
db_snapshot_arn: Optional[str] = None,
1619
db_version: Optional[rds.PostgresEngineVersion] = None,
@@ -51,7 +54,7 @@ def create_database_server(
5154
**params,
5255
snapshot_identifier=db_snapshot_arn,
5356
credentials=rds.SnapshotCredentials.from_generated_password(
54-
username="superuser"
57+
username=db_snapshot_admin_username
5558
),
5659
)
5760

0 commit comments

Comments
 (0)