BuzzerboyAWSLightsail 0.332.1__py3-none-any.whl → 0.333.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- BuzzerboyAWSLightsailStack/LightsailBase.py +4 -331
- BuzzerboyAWSLightsailStack/LightsailBaseStandalone.py +4 -168
- BuzzerboyAWSLightsailStack/LightsailContainer.py +6 -242
- BuzzerboyAWSLightsailStack/LightsailContainerStandalone.py +6 -242
- BuzzerboyAWSLightsailStack/LightsailDatabase.py +6 -369
- BuzzerboyAWSLightsailStack/LightsailDatabaseStandalone.py +6 -369
- BuzzerboyAWSLightsailStack/LightsailFlags.py +38 -0
- BuzzerboyAWSLightsailStack/LightsailMixins.py +542 -0
- {buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/METADATA +1 -1
- buzzerboyawslightsail-0.333.1.dist-info/RECORD +17 -0
- buzzerboyawslightsail-0.332.1.dist-info/RECORD +0 -15
- {buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/WHEEL +0 -0
- {buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/licenses/LICENSE +0 -0
- {buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared mixins for Lightsail stacks.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from cdktf import TerraformOutput
|
|
9
|
+
|
|
10
|
+
from cdktf_cdktf_provider_aws import (
|
|
11
|
+
lightsail_container_service,
|
|
12
|
+
lightsail_database,
|
|
13
|
+
s3_bucket,
|
|
14
|
+
)
|
|
15
|
+
from cdktf_cdktf_provider_aws.secretsmanager_secret import SecretsmanagerSecret
|
|
16
|
+
from cdktf_cdktf_provider_aws.secretsmanager_secret_version import SecretsmanagerSecretVersion
|
|
17
|
+
from cdktf_cdktf_provider_aws.data_aws_secretsmanager_secret_version import (
|
|
18
|
+
DataAwsSecretsmanagerSecretVersion,
|
|
19
|
+
)
|
|
20
|
+
from cdktf_cdktf_provider_null.resource import Resource as NullResource
|
|
21
|
+
from cdktf_cdktf_provider_random import password
|
|
22
|
+
|
|
23
|
+
from .LightsailFlags import (
|
|
24
|
+
BaseLightsailArchitectureFlags,
|
|
25
|
+
ContainerArchitectureFlags,
|
|
26
|
+
DatabaseArchitectureFlags,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LightsailBaseMixin:
|
|
31
|
+
"""
|
|
32
|
+
Shared helpers for Lightsail base stacks.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def get_extra_secret_env(self, env_var_name=None):
|
|
36
|
+
if env_var_name is None:
|
|
37
|
+
env_var_name = self.default_extra_secret_env
|
|
38
|
+
|
|
39
|
+
extra_secret_env = os.environ.get(env_var_name, None)
|
|
40
|
+
|
|
41
|
+
if extra_secret_env:
|
|
42
|
+
try:
|
|
43
|
+
extra_secret_json = json.loads(extra_secret_env)
|
|
44
|
+
for key, value in extra_secret_json.items():
|
|
45
|
+
if key not in self.secrets:
|
|
46
|
+
self.secrets[key] = value
|
|
47
|
+
except json.JSONDecodeError:
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
def create_security_resources(self):
|
|
51
|
+
self.secrets_manager_secret = SecretsmanagerSecret(
|
|
52
|
+
self, self.secret_name, name=f"{self.secret_name}"
|
|
53
|
+
)
|
|
54
|
+
self.resources["secretsmanager_secret"] = self.secrets_manager_secret
|
|
55
|
+
|
|
56
|
+
self.secrets.update(
|
|
57
|
+
{
|
|
58
|
+
"service_user_access_key": self.service_key.id,
|
|
59
|
+
"service_user_secret_key": self.service_key.secret,
|
|
60
|
+
"access_key": self.service_key.id,
|
|
61
|
+
"secret_access_key": self.service_key.secret,
|
|
62
|
+
"region_name": self.region,
|
|
63
|
+
"signature_version": self.default_signature_version,
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self.get_extra_secret_env()
|
|
68
|
+
|
|
69
|
+
if self.has_flag(BaseLightsailArchitectureFlags.PRESERVE_EXISTING_SECRETS.value):
|
|
70
|
+
self._create_secret_version_conditionally()
|
|
71
|
+
elif self.has_flag(BaseLightsailArchitectureFlags.IGNORE_SECRET_CHANGES.value):
|
|
72
|
+
self._create_secret_version_with_lifecycle_ignore()
|
|
73
|
+
else:
|
|
74
|
+
SecretsmanagerSecretVersion(
|
|
75
|
+
self,
|
|
76
|
+
self.secret_name + "_version",
|
|
77
|
+
secret_id=self.secrets_manager_secret.id,
|
|
78
|
+
secret_string=(
|
|
79
|
+
json.dumps(self.secrets, indent=2, sort_keys=True)
|
|
80
|
+
if self.secrets
|
|
81
|
+
else None
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def _create_secret_version_conditionally(self):
|
|
86
|
+
try:
|
|
87
|
+
DataAwsSecretsmanagerSecretVersion(
|
|
88
|
+
self,
|
|
89
|
+
self.secret_name + "_existing_check",
|
|
90
|
+
secret_id=self.secrets_manager_secret.id,
|
|
91
|
+
version_stage="AWSCURRENT",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
conditional_secret = SecretsmanagerSecretVersion(
|
|
95
|
+
self,
|
|
96
|
+
self.secret_name + "_version_conditional",
|
|
97
|
+
secret_id=self.secrets_manager_secret.id,
|
|
98
|
+
secret_string=json.dumps(self.secrets, indent=2, sort_keys=True)
|
|
99
|
+
if self.secrets
|
|
100
|
+
else None,
|
|
101
|
+
lifecycle={"ignore_changes": ["secret_string"], "create_before_destroy": False},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
conditional_secret.add_override(
|
|
105
|
+
"count",
|
|
106
|
+
"${length(try(jsondecode(data.aws_secretsmanager_secret_version."
|
|
107
|
+
+ self.secret_name.replace("/", "_").replace("-", "_")
|
|
108
|
+
+ "_existing_check.secret_string), {})) == 0 ? 1 : 0}",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
except Exception:
|
|
112
|
+
SecretsmanagerSecretVersion(
|
|
113
|
+
self,
|
|
114
|
+
self.secret_name + "_version_fallback",
|
|
115
|
+
secret_id=self.secrets_manager_secret.id,
|
|
116
|
+
secret_string=json.dumps(self.secrets, indent=2, sort_keys=True)
|
|
117
|
+
if self.secrets
|
|
118
|
+
else None,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def _create_secret_version_with_lifecycle_ignore(self):
|
|
122
|
+
secret_version = SecretsmanagerSecretVersion(
|
|
123
|
+
self,
|
|
124
|
+
self.secret_name + "_version_ignored",
|
|
125
|
+
secret_id=self.secrets_manager_secret.id,
|
|
126
|
+
secret_string=json.dumps(self.secrets, indent=2, sort_keys=True)
|
|
127
|
+
if self.secrets
|
|
128
|
+
else None,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
secret_version.add_override("lifecycle", {"ignore_changes": ["secret_string"]})
|
|
132
|
+
|
|
133
|
+
def execute_post_apply_scripts(self):
|
|
134
|
+
if not self.post_apply_scripts:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
dependencies = []
|
|
138
|
+
if hasattr(self, "secrets_manager_secret"):
|
|
139
|
+
dependencies.append(self.secrets_manager_secret)
|
|
140
|
+
|
|
141
|
+
for i, script in enumerate(self.post_apply_scripts):
|
|
142
|
+
script_resource = NullResource(
|
|
143
|
+
self, f"post_apply_script_{i}", depends_on=dependencies if dependencies else None
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
script_resource.add_override(
|
|
147
|
+
"provisioner",
|
|
148
|
+
[{"local-exec": {"command": script, "on_failure": "continue"}}],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def has_flag(self, flag_value):
|
|
152
|
+
return flag_value in self.flags
|
|
153
|
+
|
|
154
|
+
def clean_hyphens(self, text):
|
|
155
|
+
return text.replace("-", "_")
|
|
156
|
+
|
|
157
|
+
def properize_s3_bucketname(self, bucket_name):
|
|
158
|
+
clean_name = bucket_name.lower().replace("_", "-")
|
|
159
|
+
clean_name = clean_name.strip("-.")
|
|
160
|
+
return clean_name
|
|
161
|
+
|
|
162
|
+
def create_iam_outputs(self):
|
|
163
|
+
TerraformOutput(
|
|
164
|
+
self,
|
|
165
|
+
"iam_user_access_key",
|
|
166
|
+
value=self.service_key.id,
|
|
167
|
+
sensitive=True,
|
|
168
|
+
description="IAM user access key ID (sensitive)",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
TerraformOutput(
|
|
172
|
+
self,
|
|
173
|
+
"iam_user_secret_key",
|
|
174
|
+
value=self.service_key.secret,
|
|
175
|
+
sensitive=True,
|
|
176
|
+
description="IAM user secret access key (sensitive)",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
TerraformOutput(
|
|
180
|
+
self,
|
|
181
|
+
"secrets_manager_secret_name",
|
|
182
|
+
value=self.secret_name,
|
|
183
|
+
description="AWS Secrets Manager secret name containing all credentials",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class LightsailContainerMixin:
|
|
188
|
+
"""
|
|
189
|
+
Shared container stack behavior.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def _set_default_post_apply_scripts(self):
|
|
193
|
+
super()._set_default_post_apply_scripts()
|
|
194
|
+
|
|
195
|
+
if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
container_scripts = [
|
|
199
|
+
f"echo '🚀 Container Service URL: https://{self.project_name}.{self.region}.cs.amazonlightsail.com'",
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
if self.post_apply_scripts:
|
|
203
|
+
insert_index = len(self.post_apply_scripts) - 1
|
|
204
|
+
for script in reversed(container_scripts):
|
|
205
|
+
self.post_apply_scripts.insert(insert_index, script)
|
|
206
|
+
|
|
207
|
+
def create_lightsail_resources(self):
|
|
208
|
+
self.container_service = lightsail_container_service.LightsailContainerService(
|
|
209
|
+
self,
|
|
210
|
+
"app_container",
|
|
211
|
+
name=f"{self.project_name}",
|
|
212
|
+
power="nano",
|
|
213
|
+
region=self.region,
|
|
214
|
+
scale=1,
|
|
215
|
+
is_disabled=False,
|
|
216
|
+
tags={
|
|
217
|
+
"Environment": self.environment,
|
|
218
|
+
"Project": self.project_name,
|
|
219
|
+
"Stack": self.__class__.__name__,
|
|
220
|
+
},
|
|
221
|
+
)
|
|
222
|
+
self.container_service_url = self.get_lightsail_container_service_domain()
|
|
223
|
+
|
|
224
|
+
if not self.has_flag(ContainerArchitectureFlags.SKIP_DATABASE.value):
|
|
225
|
+
self.create_lightsail_database()
|
|
226
|
+
|
|
227
|
+
self.create_s3_bucket()
|
|
228
|
+
self.resources["lightsail_container_service"] = self.container_service
|
|
229
|
+
|
|
230
|
+
def create_lightsail_database(self):
|
|
231
|
+
self.db_password = password.Password(
|
|
232
|
+
self,
|
|
233
|
+
"db_password",
|
|
234
|
+
length=16,
|
|
235
|
+
special=True,
|
|
236
|
+
override_special="!#$%&*()-_=+[]{}<>:?",
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
self.database = lightsail_database.LightsailDatabase(
|
|
240
|
+
self,
|
|
241
|
+
"app_database",
|
|
242
|
+
relational_database_name=f"{self.project_name}-db",
|
|
243
|
+
blueprint_id="postgres_14",
|
|
244
|
+
bundle_id="micro_2_0",
|
|
245
|
+
master_database_name=self.clean_hyphens(f"{self.project_name}"),
|
|
246
|
+
master_username=self.default_db_username,
|
|
247
|
+
master_password=self.db_password.result,
|
|
248
|
+
skip_final_snapshot=True,
|
|
249
|
+
tags={
|
|
250
|
+
"Environment": self.environment,
|
|
251
|
+
"Project": self.project_name,
|
|
252
|
+
"Stack": self.__class__.__name__,
|
|
253
|
+
},
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
self.secrets.update(
|
|
257
|
+
{
|
|
258
|
+
"password": self.db_password.result,
|
|
259
|
+
"username": self.default_db_username,
|
|
260
|
+
"dbname": self.default_db_name,
|
|
261
|
+
"host": self.database.master_endpoint_address,
|
|
262
|
+
"port": self.database.master_endpoint_port,
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def create_s3_bucket(self, bucket_name=None):
|
|
267
|
+
if bucket_name is None:
|
|
268
|
+
bucket_name = self.properize_s3_bucketname(f"{self.project_name}-s3")
|
|
269
|
+
|
|
270
|
+
self.s3_bucket = s3_bucket.S3Bucket(
|
|
271
|
+
self,
|
|
272
|
+
"app_data_bucket",
|
|
273
|
+
bucket=bucket_name,
|
|
274
|
+
acl="private",
|
|
275
|
+
versioning={"enabled": True},
|
|
276
|
+
server_side_encryption_configuration={
|
|
277
|
+
"rule": {
|
|
278
|
+
"apply_server_side_encryption_by_default": {"sse_algorithm": "AES256"},
|
|
279
|
+
"bucket_key_enabled": True,
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
tags={
|
|
283
|
+
"Environment": self.environment,
|
|
284
|
+
"Project": self.project_name,
|
|
285
|
+
"Stack": self.__class__.__name__,
|
|
286
|
+
},
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
self.resources["s3_bucket"] = self.s3_bucket
|
|
290
|
+
self.bucket_name = bucket_name
|
|
291
|
+
|
|
292
|
+
def get_lightsail_container_service_domain(self):
|
|
293
|
+
return f"{self.project_name}.{self.region}.cs.amazonlightsail.com"
|
|
294
|
+
|
|
295
|
+
def create_outputs(self):
|
|
296
|
+
TerraformOutput(
|
|
297
|
+
self,
|
|
298
|
+
"container_service_url",
|
|
299
|
+
value=self.container_service_url,
|
|
300
|
+
description="Public URL of the Lightsail container service",
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
if not self.has_flag(ContainerArchitectureFlags.SKIP_DATABASE.value) and hasattr(
|
|
304
|
+
self, "database"
|
|
305
|
+
):
|
|
306
|
+
TerraformOutput(
|
|
307
|
+
self,
|
|
308
|
+
"database_endpoint",
|
|
309
|
+
value=f"{self.database.master_endpoint_address}:{self.database.master_endpoint_port}",
|
|
310
|
+
description="Database connection endpoint",
|
|
311
|
+
)
|
|
312
|
+
TerraformOutput(
|
|
313
|
+
self,
|
|
314
|
+
"database_password",
|
|
315
|
+
value=self.database.master_password,
|
|
316
|
+
sensitive=True,
|
|
317
|
+
description="Database master password (sensitive)",
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
self.create_iam_outputs()
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class LightsailDatabaseMixin:
|
|
324
|
+
"""
|
|
325
|
+
Shared database stack behavior.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
def _set_default_post_apply_scripts(self):
|
|
329
|
+
super()._set_default_post_apply_scripts()
|
|
330
|
+
|
|
331
|
+
if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
databases_list = ", ".join(self.databases)
|
|
335
|
+
database_scripts = [
|
|
336
|
+
f"echo '️ Database Instance: {self.project_name}-db'",
|
|
337
|
+
f"echo '📊 Databases Created: {databases_list}'",
|
|
338
|
+
f"echo '👥 Database Users: {len(self.databases)} individual users created'",
|
|
339
|
+
"echo '🔗 Connection Information:'",
|
|
340
|
+
"echo ' - Instance Endpoint: Available in Terraform outputs'",
|
|
341
|
+
f"echo ' - Master User: {self.master_username}'",
|
|
342
|
+
"echo ' - Port: 5432 (PostgreSQL)'",
|
|
343
|
+
"echo ' - Credentials: Stored in AWS Secrets Manager'",
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
if self.post_apply_scripts:
|
|
347
|
+
insert_index = len(self.post_apply_scripts) - 1
|
|
348
|
+
for script in reversed(database_scripts):
|
|
349
|
+
self.post_apply_scripts.insert(insert_index, script)
|
|
350
|
+
|
|
351
|
+
def create_lightsail_resources(self):
|
|
352
|
+
self.create_database_passwords()
|
|
353
|
+
self.create_lightsail_database()
|
|
354
|
+
self.create_database_users()
|
|
355
|
+
|
|
356
|
+
def create_database_passwords(self):
|
|
357
|
+
self.master_password = password.Password(
|
|
358
|
+
self,
|
|
359
|
+
"master_db_password",
|
|
360
|
+
length=20,
|
|
361
|
+
special=True,
|
|
362
|
+
override_special="!#$%&*()-_=+[]{}<>:?",
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
for db_name in self.databases:
|
|
366
|
+
db_password = password.Password(
|
|
367
|
+
self,
|
|
368
|
+
f"{db_name}_user_password",
|
|
369
|
+
length=16,
|
|
370
|
+
special=True,
|
|
371
|
+
override_special="!#$%&*()-_=+[]{}<>:?",
|
|
372
|
+
)
|
|
373
|
+
self.database_passwords[db_name] = db_password
|
|
374
|
+
|
|
375
|
+
def create_lightsail_database(self):
|
|
376
|
+
master_db_name = self.clean_hyphens(self.databases[0])
|
|
377
|
+
|
|
378
|
+
self.database = lightsail_database.LightsailDatabase(
|
|
379
|
+
self,
|
|
380
|
+
"database_instance",
|
|
381
|
+
relational_database_name=f"{self.project_name}-db",
|
|
382
|
+
blueprint_id=self.db_engine,
|
|
383
|
+
bundle_id=self.db_instance_size,
|
|
384
|
+
master_database_name=master_db_name,
|
|
385
|
+
master_username=self.master_username,
|
|
386
|
+
master_password=self.master_password.result,
|
|
387
|
+
publicly_accessible=self.db_publicly_accessible,
|
|
388
|
+
skip_final_snapshot=True,
|
|
389
|
+
tags={
|
|
390
|
+
"Environment": self.environment,
|
|
391
|
+
"Project": self.project_name,
|
|
392
|
+
"Stack": self.__class__.__name__,
|
|
393
|
+
"DatabaseCount": str(len(self.databases)),
|
|
394
|
+
},
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
self.resources["lightsail_database"] = self.database
|
|
398
|
+
|
|
399
|
+
self.secrets.update(
|
|
400
|
+
{
|
|
401
|
+
"master_username": self.master_username,
|
|
402
|
+
"master_password": self.master_password.result,
|
|
403
|
+
"master_database": master_db_name,
|
|
404
|
+
"host": self.database.master_endpoint_address,
|
|
405
|
+
"port": self.database.master_endpoint_port,
|
|
406
|
+
"engine": self.db_engine,
|
|
407
|
+
"region": self.region,
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def create_database_users(self):
|
|
412
|
+
if DatabaseArchitectureFlags.SKIP_DATABASE_USERS.value in self.flags:
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
for db_name in self.databases:
|
|
416
|
+
clean_db_name = self.clean_hyphens(db_name)
|
|
417
|
+
username = f"{clean_db_name}-dbuser"
|
|
418
|
+
password_ref = self.database_passwords[db_name].result
|
|
419
|
+
|
|
420
|
+
self.secrets[f"{clean_db_name}_username"] = username
|
|
421
|
+
self.secrets[f"{clean_db_name}_password"] = password_ref
|
|
422
|
+
self.secrets[f"{clean_db_name}_database"] = clean_db_name
|
|
423
|
+
|
|
424
|
+
self.database_users[clean_db_name] = {
|
|
425
|
+
"username": username,
|
|
426
|
+
"password": password_ref,
|
|
427
|
+
"database": clean_db_name,
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
databases_to_create = self.databases[1:] if len(self.databases) > 1 else []
|
|
431
|
+
|
|
432
|
+
for db_name in databases_to_create:
|
|
433
|
+
clean_db_name = self.clean_hyphens(db_name)
|
|
434
|
+
username = f"{clean_db_name}-dbuser"
|
|
435
|
+
password_ref = self.database_passwords[db_name].result
|
|
436
|
+
|
|
437
|
+
sql_commands = f"""#!/bin/bash
|
|
438
|
+
set -e
|
|
439
|
+
|
|
440
|
+
echo "Creating database: {clean_db_name}"
|
|
441
|
+
|
|
442
|
+
for i in {{1..30}}; do
|
|
443
|
+
if PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT 1" > /dev/null 2>&1; then
|
|
444
|
+
echo "Database is ready"
|
|
445
|
+
break
|
|
446
|
+
fi
|
|
447
|
+
echo "Waiting for database to be ready... ($i/30)"
|
|
448
|
+
sleep 10
|
|
449
|
+
done
|
|
450
|
+
|
|
451
|
+
PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "CREATE DATABASE \\"{clean_db_name}\\";" || echo "Database {clean_db_name} may already exist"
|
|
452
|
+
|
|
453
|
+
PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "CREATE USER \\"{username}\\" WITH PASSWORD '$USER_PASSWORD';" || echo "User {username} may already exist"
|
|
454
|
+
|
|
455
|
+
PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \\"{clean_db_name}\\" TO \\"{username}\\";"
|
|
456
|
+
|
|
457
|
+
PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d {clean_db_name} -c "GRANT ALL ON SCHEMA public TO \\"{username}\\";"
|
|
458
|
+
|
|
459
|
+
echo "Successfully created database: {clean_db_name} with user: {username}"
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
db_resource = NullResource(
|
|
463
|
+
self, f"create_database_{clean_db_name}", depends_on=[self.database]
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
db_resource.add_override(
|
|
467
|
+
"provisioner",
|
|
468
|
+
[
|
|
469
|
+
{
|
|
470
|
+
"local-exec": {
|
|
471
|
+
"command": sql_commands,
|
|
472
|
+
"environment": {
|
|
473
|
+
"DB_HOST": self.database.master_endpoint_address,
|
|
474
|
+
"DB_PORT": self.database.master_endpoint_port,
|
|
475
|
+
"DB_USER": self.master_username,
|
|
476
|
+
"MASTER_PASSWORD": self.master_password.result,
|
|
477
|
+
"USER_PASSWORD": password_ref,
|
|
478
|
+
},
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
],
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
def create_outputs(self):
|
|
485
|
+
TerraformOutput(
|
|
486
|
+
self,
|
|
487
|
+
"database_endpoint",
|
|
488
|
+
value=f"{self.database.master_endpoint_address}:{self.database.master_endpoint_port}",
|
|
489
|
+
description="Database instance connection endpoint",
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
TerraformOutput(
|
|
493
|
+
self,
|
|
494
|
+
"database_instance_name",
|
|
495
|
+
value=self.database.relational_database_name,
|
|
496
|
+
description="Lightsail database instance name",
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
TerraformOutput(
|
|
500
|
+
self,
|
|
501
|
+
"master_username",
|
|
502
|
+
value=self.master_username,
|
|
503
|
+
description="Master database username",
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
TerraformOutput(
|
|
507
|
+
self,
|
|
508
|
+
"master_password",
|
|
509
|
+
value=self.master_password.result,
|
|
510
|
+
sensitive=True,
|
|
511
|
+
description="Master database password (sensitive)",
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
TerraformOutput(
|
|
515
|
+
self,
|
|
516
|
+
"databases_created",
|
|
517
|
+
value=json.dumps(self.databases),
|
|
518
|
+
description="List of databases created in the instance",
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
if not self.has_flag(DatabaseArchitectureFlags.SKIP_DATABASE_USERS.value):
|
|
522
|
+
for db_name in self.databases:
|
|
523
|
+
clean_name = self.clean_hyphens(db_name)
|
|
524
|
+
if clean_name in self.database_users:
|
|
525
|
+
user_info = self.database_users[clean_name]
|
|
526
|
+
|
|
527
|
+
TerraformOutput(
|
|
528
|
+
self,
|
|
529
|
+
f"{clean_name}_username",
|
|
530
|
+
value=user_info["username"],
|
|
531
|
+
description=f"Database user for {clean_name}",
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
TerraformOutput(
|
|
535
|
+
self,
|
|
536
|
+
f"{clean_name}_password",
|
|
537
|
+
value=user_info["password"],
|
|
538
|
+
sensitive=True,
|
|
539
|
+
description=f"Database password for {clean_name} (sensitive)",
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
self.create_iam_outputs()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
BuzzerboyAWSLightsailStack/ArchitectureMaker.py,sha256=e_dr9cEL8FW7Vp-F1mUUkHx_bHdg1kRNWMOdvuTqgrQ,7404
|
|
2
|
+
BuzzerboyAWSLightsailStack/LightSailPostDeploy.py,sha256=uOEOe5qORPgvivC0Ba0w045PQztfS6z-ynwyikaPQzI,5025
|
|
3
|
+
BuzzerboyAWSLightsailStack/LightsailAIContainer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
BuzzerboyAWSLightsailStack/LightsailBase.py,sha256=ulzt3P2HIabUPYxGc5OFYsKeJ4Tx0ALQbwPpq53epD4,13324
|
|
5
|
+
BuzzerboyAWSLightsailStack/LightsailBaseStandalone.py,sha256=uVhpjELuZrvbbd3spz7taMHGLJ6toPUQBGd5G6xMGuE,5795
|
|
6
|
+
BuzzerboyAWSLightsailStack/LightsailContainer.py,sha256=iYDUBQYGSuWLM3IdhLn0UEEmWJtg_BFlQEhxRZnBnWM,4955
|
|
7
|
+
BuzzerboyAWSLightsailStack/LightsailContainerStandalone.py,sha256=6rKhlr2bgOs7Zobv_USmHu5C8xSPoV47OGOfjl5dDqw,5230
|
|
8
|
+
BuzzerboyAWSLightsailStack/LightsailDatabase.py,sha256=UYSrbMXSgUyQvbdbGgHtyUuD5Qq9d7VMiUbSEc5VdtA,4788
|
|
9
|
+
BuzzerboyAWSLightsailStack/LightsailDatabaseStandalone.py,sha256=P0am1KemvxcyV61u10Rpr5jINcqvGw48PK-cralEQqU,4838
|
|
10
|
+
BuzzerboyAWSLightsailStack/LightsailFlags.py,sha256=6ytYxSz8VDghfyrS0QBF7SCich7YKhjsP-dp5lRbMrc,1100
|
|
11
|
+
BuzzerboyAWSLightsailStack/LightsailMixins.py,sha256=pzTld96vTazlLNIsM6GxxHsKFXs6g_J66tmTKlfGByM,19433
|
|
12
|
+
BuzzerboyAWSLightsailStack/__init__.py,sha256=Cb3FwpoTCYmXW3ZVEEe0nyg8HQixOAIiXPrld0164UU,49
|
|
13
|
+
buzzerboyawslightsail-0.333.1.dist-info/licenses/LICENSE,sha256=hxCyRAUWBBbbve3BaE8Qtl_sxcUo-8AYNAslHjeiu3w,921
|
|
14
|
+
buzzerboyawslightsail-0.333.1.dist-info/METADATA,sha256=vkPJnT8fLYC5OWO3MfAQY4ySBQTUYzWViRU3gf_lFZk,6809
|
|
15
|
+
buzzerboyawslightsail-0.333.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
buzzerboyawslightsail-0.333.1.dist-info/top_level.txt,sha256=xqYoH36d7_13q4vRi5bZr1zIz9mR7b8ms_6ez3BqRgQ,27
|
|
17
|
+
buzzerboyawslightsail-0.333.1.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
BuzzerboyAWSLightsailStack/ArchitectureMaker.py,sha256=e_dr9cEL8FW7Vp-F1mUUkHx_bHdg1kRNWMOdvuTqgrQ,7404
|
|
2
|
-
BuzzerboyAWSLightsailStack/LightSailPostDeploy.py,sha256=uOEOe5qORPgvivC0Ba0w045PQztfS6z-ynwyikaPQzI,5025
|
|
3
|
-
BuzzerboyAWSLightsailStack/LightsailAIContainer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
BuzzerboyAWSLightsailStack/LightsailBase.py,sha256=Fn1RQv4lVtkLmCZH6FFpxpnGQ6W0CRjF7nNNjI_uFjY,26085
|
|
5
|
-
BuzzerboyAWSLightsailStack/LightsailBaseStandalone.py,sha256=LR3DBw0Hg4dsWeaPmHerI0wTPhQOv1DeXhkvkbr4zq8,12067
|
|
6
|
-
BuzzerboyAWSLightsailStack/LightsailContainer.py,sha256=Ax7MIaeKY3tCxiTeX3sfnviM9ksWjestDXkg2w3XLes,13871
|
|
7
|
-
BuzzerboyAWSLightsailStack/LightsailContainerStandalone.py,sha256=b_NXxUmL1D4pNT5INL97Pr2pUUe3M5hVPpPLlRvoIpA,14147
|
|
8
|
-
BuzzerboyAWSLightsailStack/LightsailDatabase.py,sha256=yKgWbM5UaEV-kSxy3rV8hM6WIDCRRM_z-DUAaY2X654,19258
|
|
9
|
-
BuzzerboyAWSLightsailStack/LightsailDatabaseStandalone.py,sha256=Fvd72Ei0sS7mGZaeosv-Nq54EZFxdrNpiMVSmLqJMrg,19308
|
|
10
|
-
BuzzerboyAWSLightsailStack/__init__.py,sha256=Cb3FwpoTCYmXW3ZVEEe0nyg8HQixOAIiXPrld0164UU,49
|
|
11
|
-
buzzerboyawslightsail-0.332.1.dist-info/licenses/LICENSE,sha256=hxCyRAUWBBbbve3BaE8Qtl_sxcUo-8AYNAslHjeiu3w,921
|
|
12
|
-
buzzerboyawslightsail-0.332.1.dist-info/METADATA,sha256=R-5WGMtAU-vsN_G3dusPqnW2Ln7idDA1LeBOV9Sd-iw,6809
|
|
13
|
-
buzzerboyawslightsail-0.332.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
-
buzzerboyawslightsail-0.332.1.dist-info/top_level.txt,sha256=xqYoH36d7_13q4vRi5bZr1zIz9mR7b8ms_6ez3BqRgQ,27
|
|
15
|
-
buzzerboyawslightsail-0.332.1.dist-info/RECORD,,
|
|
File without changes
|
{buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{buzzerboyawslightsail-0.332.1.dist-info → buzzerboyawslightsail-0.333.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|