BuzzerboyAWSLightsail 0.330.1__py3-none-any.whl → 0.331.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.
@@ -70,18 +70,19 @@ class ArchitectureFlags(Enum):
70
70
  """
71
71
  Architecture configuration flags for optional components.
72
72
 
73
- Includes both base and container-specific flags.
73
+ Includes both base flags and container-specific flags.
74
74
 
75
75
  Base flags:
76
76
  :param SKIP_DEFAULT_POST_APPLY_SCRIPTS: Skip default post-apply scripts
77
- :param PRESERVE_EXISTING_SECRETS: Don't overwrite existing secret versions
77
+ :param PRESERVE_EXISTING_SECRETS: Don't overwrite existing secret versions (smart detection)
78
78
  :param IGNORE_SECRET_CHANGES: Ignore all changes to secret after initial creation
79
79
 
80
80
  Container-specific flags:
81
81
  :param SKIP_DATABASE: Skip database creation
82
82
  :param SKIP_DOMAIN: Skip domain and DNS configuration
83
83
  """
84
- # Base flags (from BaseLightsailArchitectureFlags)
84
+
85
+ # Base flags from BaseLightsailArchitectureFlags
85
86
  SKIP_DEFAULT_POST_APPLY_SCRIPTS = "skip_default_post_apply_scripts"
86
87
  PRESERVE_EXISTING_SECRETS = "preserve_existing_secrets"
87
88
  IGNORE_SECRET_CHANGES = "ignore_secret_changes"
@@ -185,7 +186,7 @@ class LightsailContainerStack(LightsailBase):
185
186
  super()._set_default_post_apply_scripts()
186
187
 
187
188
  # Skip if flag is set
188
- if ArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
189
+ if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
189
190
  return
190
191
 
191
192
  # Add container-specific scripts
@@ -41,22 +41,28 @@ from cdktf_cdktf_provider_random import password
41
41
 
42
42
  #endregion
43
43
 
44
+ #region Null Provider and Resources
45
+ from cdktf_cdktf_provider_null.resource import Resource as NullResource
46
+
47
+ #endregion
48
+
44
49
  #region ArchitectureFlags
45
50
  class ArchitectureFlags(Enum):
46
51
  """
47
52
  Architecture configuration flags for optional components.
48
53
 
49
- Includes both base and database-specific flags.
54
+ Includes both base flags and database-specific flags.
50
55
 
51
56
  Base flags:
52
57
  :param SKIP_DEFAULT_POST_APPLY_SCRIPTS: Skip default post-apply scripts
53
- :param PRESERVE_EXISTING_SECRETS: Don't overwrite existing secret versions
58
+ :param PRESERVE_EXISTING_SECRETS: Don't overwrite existing secret versions (smart detection)
54
59
  :param IGNORE_SECRET_CHANGES: Ignore all changes to secret after initial creation
55
60
 
56
61
  Database-specific flags:
57
62
  :param SKIP_DATABASE_USERS: Skip creating individual database users (use master user only)
58
63
  """
59
- # Base flags (from BaseLightsailArchitectureFlags)
64
+
65
+ # Base flags from BaseLightsailArchitectureFlags
60
66
  SKIP_DEFAULT_POST_APPLY_SCRIPTS = "skip_default_post_apply_scripts"
61
67
  PRESERVE_EXISTING_SECRETS = "preserve_existing_secrets"
62
68
  IGNORE_SECRET_CHANGES = "ignore_secret_changes"
@@ -73,8 +79,8 @@ class LightsailDatabaseStack(LightsailBase):
73
79
 
74
80
  A comprehensive database stack that deploys:
75
81
  * Lightsail Database instance with PostgreSQL
76
- * Multiple databases within the instance
77
- * Individual database users with scoped permissions
82
+ * Multiple databases within the instance (automated creation)
83
+ * Individual database users with scoped permissions (automated creation)
78
84
  * Secrets Manager for storing all database credentials
79
85
  * IAM resources for programmatic access
80
86
 
@@ -126,6 +132,7 @@ class LightsailDatabaseStack(LightsailBase):
126
132
  :param db_instance_size: Database instance size (default: "micro_2_0")
127
133
  :param db_engine: Database engine version (default: "postgres_14")
128
134
  :param master_username: Master database username (default: "dbmasteruser")
135
+ :param db_publicly_accessible: Enable public access to database (default: True, required for automated provisioning)
129
136
  """
130
137
  # Set database-specific defaults
131
138
  if "project_name" not in kwargs:
@@ -135,7 +142,7 @@ class LightsailDatabaseStack(LightsailBase):
135
142
  environment = kwargs.get("environment", "dev")
136
143
  kwargs["secret_name"] = f"{project_name}/{environment}/database-credentials"
137
144
 
138
- # ===== Database-Specific Configuration (set before parent init) =====
145
+ # ===== Database-Specific Configuration (MUST be set before super().__init__) =====
139
146
  self.databases = kwargs.get("databases", [])
140
147
 
141
148
  # Validate required parameters
@@ -146,12 +153,13 @@ class LightsailDatabaseStack(LightsailBase):
146
153
  self.master_username = kwargs.get("master_username", "dbmasteruser")
147
154
  self.db_instance_size = kwargs.get("db_instance_size", "micro_2_0")
148
155
  self.db_engine = kwargs.get("db_engine", "postgres_14")
156
+ self.db_publicly_accessible = kwargs.get("db_publicly_accessible", True)
149
157
 
150
158
  # ===== Internal State =====
151
159
  self.database_users = {}
152
160
  self.database_passwords = {}
153
161
 
154
- # Call parent constructor
162
+ # Call parent constructor (this will call _set_default_post_apply_scripts)
155
163
  super().__init__(scope, id, **kwargs)
156
164
 
157
165
  def _set_default_post_apply_scripts(self):
@@ -162,7 +170,7 @@ class LightsailDatabaseStack(LightsailBase):
162
170
  super()._set_default_post_apply_scripts()
163
171
 
164
172
  # Skip if flag is set
165
- if ArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
173
+ if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
166
174
  return
167
175
 
168
176
  # Add database-specific scripts before the final message
@@ -191,8 +199,9 @@ class LightsailDatabaseStack(LightsailBase):
191
199
 
192
200
  Creates:
193
201
  * Database passwords for master and individual users
194
- * Lightsail PostgreSQL database instance
195
- * Individual database user credentials (for later manual creation)
202
+ * Lightsail PostgreSQL database instance (with public access enabled)
203
+ * Individual databases within the instance (automated via SQL)
204
+ * Individual database users with scoped permissions (automated via SQL)
196
205
  """
197
206
  # Generate passwords first
198
207
  self.create_database_passwords()
@@ -241,7 +250,13 @@ class LightsailDatabaseStack(LightsailBase):
241
250
  * Engine: PostgreSQL (version specified by db_engine)
242
251
  * Size: Configurable (default: micro_2_0)
243
252
  * Master database: Uses first database name from the list
253
+ * Public Access: Configurable (default: True for automated provisioning)
244
254
  * Final snapshot: Disabled (skip_final_snapshot=True)
255
+
256
+ .. note::
257
+ Public access is enabled by default to allow automated database creation
258
+ via local-exec provisioners. This can be disabled by setting
259
+ db_publicly_accessible=False, but will require manual database setup.
245
260
  """
246
261
  # Use the first database name as the master database name
247
262
  master_db_name = self.clean_hyphens(self.databases[0])
@@ -255,6 +270,7 @@ class LightsailDatabaseStack(LightsailBase):
255
270
  master_database_name=master_db_name,
256
271
  master_username=self.master_username,
257
272
  master_password=self.master_password.result,
273
+ publicly_accessible=self.db_publicly_accessible,
258
274
  skip_final_snapshot=True,
259
275
  tags={
260
276
  "Environment": self.environment,
@@ -280,28 +296,35 @@ class LightsailDatabaseStack(LightsailBase):
280
296
 
281
297
  def create_database_users(self):
282
298
  """
283
- Prepare database user credentials for individual databases.
284
-
285
- This method creates credentials for individual database users that would be
286
- created manually or via external scripts after deployment. For each database
287
- in the databases list, it will:
288
- 1. Generate a password for the database user
289
- 2. Store credentials in the secrets dictionary
290
- 3. Create user information for reference
291
-
292
- **Manual Database Setup Required:**
293
- After deployment, you'll need to manually create databases and users:
299
+ Create individual databases and users within the Lightsail PostgreSQL instance.
300
+
301
+ This method automates the creation of databases and users using SQL commands
302
+ executed via null_resource provisioners. For each database in the databases list:
303
+ 1. Generates a password for the database user
304
+ 2. Stores credentials in the secrets dictionary
305
+ 3. Creates the database (if not the first one - master database)
306
+ 4. Creates a dedicated user with the generated password
307
+ 5. Grants all privileges on the database to the user
308
+
309
+ **Automated Database Setup:**
310
+ The following operations are performed automatically for each database:
294
311
  * CREATE DATABASE {db_name};
295
312
  * CREATE USER "{db_name}-dbuser" WITH PASSWORD '{password}';
296
313
  * GRANT ALL PRIVILEGES ON DATABASE {db_name} TO "{db_name}-dbuser";
314
+ * GRANT ALL ON SCHEMA public TO "{db_name}-dbuser";
297
315
 
298
316
  .. note::
299
- Database and user creation happens manually after deployment since
300
- Lightsail doesn't provide Terraform resources for individual databases.
317
+ The first database in the list is created as the master database during
318
+ instance creation, so it's skipped in this automated provisioning process.
319
+
320
+ .. note::
321
+ Requires publicly_accessible=True on the database instance for the
322
+ provisioner to connect from the local machine running Terraform.
301
323
  """
302
324
  if ArchitectureFlags.SKIP_DATABASE_USERS.value in self.flags:
303
325
  return
304
326
 
327
+ # Store credentials for all databases
305
328
  for db_name in self.databases:
306
329
  clean_db_name = self.clean_hyphens(db_name)
307
330
  username = f"{clean_db_name}-dbuser"
@@ -319,22 +342,67 @@ class LightsailDatabaseStack(LightsailBase):
319
342
  "database": clean_db_name
320
343
  }
321
344
 
322
- # Add manual setup instructions to post-terraform messages
323
- if self.databases and not self.has_flag(ArchitectureFlags.SKIP_DATABASE_USERS.value):
324
- setup_commands = []
325
- for db_name in self.databases:
326
- clean_db_name = self.clean_hyphens(db_name)
327
- username = f"{clean_db_name}-dbuser"
328
- setup_commands.extend([
329
- f"CREATE DATABASE IF NOT EXISTS \"{clean_db_name}\";",
330
- f"CREATE USER \"{username}\" WITH PASSWORD '<password_from_secrets>';",
331
- f"GRANT ALL PRIVILEGES ON DATABASE \"{clean_db_name}\" TO \"{username}\";"
332
- ])
345
+ # Skip the first database as it's already created as the master database
346
+ databases_to_create = self.databases[1:] if len(self.databases) > 1 else []
347
+
348
+ # Create additional databases and users using null_resource
349
+ for db_name in databases_to_create:
350
+ clean_db_name = self.clean_hyphens(db_name)
351
+ username = f"{clean_db_name}-dbuser"
352
+ password_ref = self.database_passwords[db_name].result
333
353
 
334
- self.post_terraform_messages.append(
335
- f"Manual database setup required. Connect to the database instance and run:\n" +
336
- "\n".join(setup_commands)
354
+ # SQL commands to create database and user
355
+ # Using environment variables to avoid Terraform interpolation issues
356
+ sql_commands = f"""#!/bin/bash
357
+ set -e
358
+
359
+ echo "Creating database: {clean_db_name}"
360
+
361
+ # Wait for database to be ready (add retry logic)
362
+ for i in {{1..30}}; do
363
+ if PGPASSWORD="$MASTER_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT 1" > /dev/null 2>&1; then
364
+ echo "Database is ready"
365
+ break
366
+ fi
367
+ echo "Waiting for database to be ready... ($i/30)"
368
+ sleep 10
369
+ done
370
+
371
+ # Create database
372
+ 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"
373
+
374
+ # Create user
375
+ 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"
376
+
377
+ # Grant database privileges
378
+ 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}\\";"
379
+
380
+ # Grant schema privileges
381
+ 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}\\";"
382
+
383
+ echo "Successfully created database: {clean_db_name} with user: {username}"
384
+ """
385
+
386
+ # Create null_resource to execute SQL commands
387
+ db_resource = NullResource(
388
+ self,
389
+ f"create_database_{clean_db_name}",
390
+ depends_on=[self.database]
337
391
  )
392
+
393
+ # Add provisioner using override
394
+ db_resource.add_override("provisioner", [{
395
+ "local-exec": {
396
+ "command": sql_commands,
397
+ "environment": {
398
+ "DB_HOST": self.database.master_endpoint_address,
399
+ "DB_PORT": self.database.master_endpoint_port,
400
+ "DB_USER": self.master_username,
401
+ "MASTER_PASSWORD": self.master_password.result,
402
+ "USER_PASSWORD": password_ref,
403
+ }
404
+ }
405
+ }])
338
406
 
339
407
  def create_outputs(self):
340
408
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BuzzerboyAWSLightsail
3
- Version: 0.330.1
3
+ Version: 0.331.1
4
4
  Summary: Buzzerboy Architecture for Deploying Web Applications on AWS LightSail
5
5
  Home-page: https://www.buzzerboy.com/
6
6
  Author: Buzzerboy Inc
@@ -0,0 +1,11 @@
1
+ BuzzerboyAWSLightsailStack/LightSailPostDeploy.py,sha256=uOEOe5qORPgvivC0Ba0w045PQztfS6z-ynwyikaPQzI,5025
2
+ BuzzerboyAWSLightsailStack/LightsailAIContainer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ BuzzerboyAWSLightsailStack/LightsailBase.py,sha256=Fn1RQv4lVtkLmCZH6FFpxpnGQ6W0CRjF7nNNjI_uFjY,26085
4
+ BuzzerboyAWSLightsailStack/LightsailContainer.py,sha256=Ax7MIaeKY3tCxiTeX3sfnviM9ksWjestDXkg2w3XLes,13871
5
+ BuzzerboyAWSLightsailStack/LightsailDatabase.py,sha256=yKgWbM5UaEV-kSxy3rV8hM6WIDCRRM_z-DUAaY2X654,19258
6
+ BuzzerboyAWSLightsailStack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ buzzerboyawslightsail-0.331.1.dist-info/licenses/LICENSE,sha256=hxCyRAUWBBbbve3BaE8Qtl_sxcUo-8AYNAslHjeiu3w,921
8
+ buzzerboyawslightsail-0.331.1.dist-info/METADATA,sha256=34sNvPKHxuM1uhrG-deG4ClnsLIBQXp2u27-Vd9-iMk,4942
9
+ buzzerboyawslightsail-0.331.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ buzzerboyawslightsail-0.331.1.dist-info/top_level.txt,sha256=xqYoH36d7_13q4vRi5bZr1zIz9mR7b8ms_6ez3BqRgQ,27
11
+ buzzerboyawslightsail-0.331.1.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- BuzzerboyAWSLightsailStack/LightSailPostDeploy.py,sha256=uOEOe5qORPgvivC0Ba0w045PQztfS6z-ynwyikaPQzI,5025
2
- BuzzerboyAWSLightsailStack/LightsailAIContainer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- BuzzerboyAWSLightsailStack/LightsailBase.py,sha256=Fn1RQv4lVtkLmCZH6FFpxpnGQ6W0CRjF7nNNjI_uFjY,26085
4
- BuzzerboyAWSLightsailStack/LightsailContainer.py,sha256=XnJU1iydnmiWTB_9MNIA9pnvsAnMyymuw38koKJj4bM,13831
5
- BuzzerboyAWSLightsailStack/LightsailDatabase.py,sha256=hXZzphlD3COTd7J7yNjzHFqQu-wvh1fX6k7LRoPvews,15962
6
- BuzzerboyAWSLightsailStack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- buzzerboyawslightsail-0.330.1.dist-info/licenses/LICENSE,sha256=hxCyRAUWBBbbve3BaE8Qtl_sxcUo-8AYNAslHjeiu3w,921
8
- buzzerboyawslightsail-0.330.1.dist-info/METADATA,sha256=vYh8iPWubNWfx3fcSktLnl3H8T7J5c7n6kKSNOT343I,4942
9
- buzzerboyawslightsail-0.330.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
- buzzerboyawslightsail-0.330.1.dist-info/top_level.txt,sha256=xqYoH36d7_13q4vRi5bZr1zIz9mR7b8ms_6ez3BqRgQ,27
11
- buzzerboyawslightsail-0.330.1.dist-info/RECORD,,