BuzzerboyAWSLightsail 0.329.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.
@@ -0,0 +1,367 @@
1
+ """
2
+ AWS Lightsail Mini Infrastructure Stack
3
+ ======================================
4
+
5
+ This module provides a comprehensive AWS Lightsail infrastructure deployment stack
6
+ using CDKTF (Cloud Development Kit for Terraform) with Python.
7
+
8
+ The stack includes:
9
+ * Lightsail Container Service with automatic custom domain attachment
10
+ * PostgreSQL Database (optional)
11
+ * DNS management with CNAME records
12
+ * SSL certificate management with automatic validation
13
+ * IAM resources for service access
14
+ * S3 bucket for application data
15
+ * Secrets Manager for credential storage
16
+
17
+ :author: Generated with GitHub Copilot
18
+ :version: 1.0.0
19
+ :license: MIT
20
+ """
21
+
22
+
23
+ #region specific imports
24
+
25
+ import os
26
+ import json
27
+ from enum import Enum
28
+ from constructs import Construct
29
+ from cdktf import TerraformOutput
30
+
31
+ # Import the base class
32
+ from .LightsailBase import LightsailBase, BaseLightsailArchitectureFlags
33
+
34
+ #endregion
35
+
36
+ #region AWS Provider and Resources
37
+ from cdktf_cdktf_provider_aws.provider import AwsProvider
38
+ from cdktf_cdktf_provider_aws import (
39
+ lightsail_container_service,
40
+ lightsail_database,
41
+ cloudfront_distribution,
42
+ s3_bucket,
43
+ )
44
+ #endregion
45
+
46
+ #region Random Provider and Resources
47
+ from cdktf_cdktf_provider_random import password
48
+
49
+ # AWS WAF (currently unused but imported for future use)
50
+ from cdktf_cdktf_provider_aws.wafv2_web_acl import (
51
+ Wafv2WebAcl,
52
+ Wafv2WebAclDefaultAction,
53
+ Wafv2WebAclRule,
54
+ Wafv2WebAclVisibilityConfig,
55
+ Wafv2WebAclDefaultActionAllow,
56
+ Wafv2WebAclRuleOverrideAction,
57
+ Wafv2WebAclRuleOverrideActionNone,
58
+ Wafv2WebAclRuleOverrideActionCount,
59
+ Wafv2WebAclRuleVisibilityConfig,
60
+ )
61
+ from cdktf_cdktf_provider_aws.wafv2_web_acl_association import Wafv2WebAclAssociation
62
+ from cdktf_cdktf_provider_aws.wafv2_rule_group import Wafv2RuleGroupRuleVisibilityConfig
63
+
64
+ #endregion
65
+
66
+
67
+
68
+ #region ArchitectureFlags
69
+ class ArchitectureFlags(BaseLightsailArchitectureFlags):
70
+ """
71
+ Architecture configuration flags for optional components.
72
+
73
+ Extends BaseLightsailArchitectureFlags with container-specific flags.
74
+
75
+ :param SKIP_DATABASE: Skip database creation
76
+ :param SKIP_DOMAIN: Skip domain and DNS configuration
77
+ """
78
+
79
+ SKIP_DATABASE = "skip_database"
80
+ SKIP_DOMAIN = "skip_domain"
81
+
82
+ #endregion
83
+
84
+
85
+ class LightsailContainerStack(LightsailBase):
86
+ """
87
+ AWS Lightsail Mini Infrastructure Stack.
88
+
89
+ A comprehensive infrastructure stack that deploys:
90
+ * Lightsail Container Service with custom domain support
91
+ * PostgreSQL database (optional)
92
+ * IAM resources and S3 storage
93
+
94
+ :param scope: The construct scope
95
+ :param id: The construct ID
96
+ :param kwargs: Configuration parameters including region, domains, flags, etc.
97
+
98
+ Example:
99
+ >>> stack = LightsailContainerStack(
100
+ ... app, "my-stack",
101
+ ... region="ca-central-1",
102
+ ... domains=["app.example.com"],
103
+ ... project_name="my-app",
104
+ ... postApplyScripts=[
105
+ ... "echo 'Deployment completed'",
106
+ ... "curl -X POST https://webhook.example.com/notify"
107
+ ... ]
108
+ ... )
109
+ """
110
+
111
+ @staticmethod
112
+ def get_architecture_flags():
113
+ """
114
+ Get the ArchitectureFlags enum for configuration.
115
+
116
+ :returns: ArchitectureFlags enum class
117
+ :rtype: type[ArchitectureFlags]
118
+ """
119
+ return ArchitectureFlags
120
+
121
+ def __init__(self, scope, id, **kwargs):
122
+ """
123
+ Initialize the AWS Lightsail Mini Infrastructure Stack.
124
+
125
+ :param scope: The construct scope
126
+ :param id: Unique identifier for this stack
127
+ :param kwargs: Configuration parameters
128
+
129
+ **Configuration Parameters:**
130
+
131
+ :param region: AWS region (default: "us-east-1")
132
+ :param environment: Environment name (default: "dev")
133
+ :param project_name: Project identifier (default: "bb-aws-lightsail-mini-v1a-app")
134
+ :param domain_name: Primary domain name
135
+ :param domains: List of custom domains to configure
136
+ :param flags: List of ArchitectureFlags to modify behavior
137
+ :param profile: AWS profile to use (default: "default")
138
+ :param postApplyScripts: List of shell commands to execute after deployment
139
+
140
+ .. warning::
141
+ Lightsail domain operations must use us-east-1 region regardless of
142
+ the main stack region.
143
+ """
144
+ # Set container-specific defaults
145
+ if "project_name" not in kwargs:
146
+ kwargs["project_name"] = "bb-aws-lightsail-mini-v1a-app"
147
+
148
+ # Call parent constructor which handles all the base initialization
149
+ super().__init__(scope, id, **kwargs)
150
+
151
+ # ===== Container-Specific Configuration =====
152
+ self.domains = kwargs.get("domains", []) or []
153
+
154
+ # ===== Database Configuration =====
155
+ self.default_db_name = kwargs.get("default_db_name", self.project_name)
156
+ self.default_db_username = kwargs.get("default_db_username", "dbadmin")
157
+
158
+ def _initialize_providers(self):
159
+ """Initialize all required Terraform providers."""
160
+ # Call parent class to initialize base providers
161
+ super()._initialize_providers()
162
+
163
+ # Add Lightsail-specific provider for domain operations (must be us-east-1)
164
+ self.aws_domain_provider = AwsProvider(
165
+ self, "aws_domain", region="us-east-1", profile=self.profile, alias="domain"
166
+ )
167
+ self.resources["aws_domain"] = self.aws_domain_provider
168
+
169
+ def _set_default_post_apply_scripts(self):
170
+ """
171
+ Set default post-apply scripts specific to container deployments.
172
+ """
173
+ # Call parent method for base scripts
174
+ super()._set_default_post_apply_scripts()
175
+
176
+ # Skip if flag is set
177
+ if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
178
+ return
179
+
180
+ # Add container-specific scripts
181
+ container_scripts = [
182
+ f"echo '🚀 Container Service URL: https://{self.project_name}.{self.region}.cs.amazonlightsail.com'",
183
+ ]
184
+
185
+ # Insert container-specific scripts before the final "execution started" message
186
+ if self.post_apply_scripts:
187
+ # Find the index of the last script and insert before it
188
+ insert_index = len(self.post_apply_scripts) - 1
189
+ for script in reversed(container_scripts):
190
+ self.post_apply_scripts.insert(insert_index, script)
191
+
192
+ def create_lightsail_resources(self):
193
+ """
194
+ Create core Lightsail resources.
195
+
196
+ Creates:
197
+ * Lightsail Container Service with nano power and scale of 1
198
+ * Random password for database authentication (if database not skipped)
199
+
200
+ .. note::
201
+ Custom domains are configured separately through DNS records and
202
+ post-deployment automation rather than the public_domain_names parameter
203
+ due to CDKTF type complexity.
204
+ """
205
+ # Lightsail Container Service
206
+ self.container_service = lightsail_container_service.LightsailContainerService(
207
+ self,
208
+ "app_container",
209
+ name=f"{self.project_name}",
210
+ power="nano",
211
+ region=self.region,
212
+ scale=1,
213
+ is_disabled=False,
214
+ # Note: Custom domains are configured separately via DNS records
215
+ # The public_domain_names parameter has complex type requirements
216
+ tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
217
+ )
218
+ self.container_service_url = self.get_lightsail_container_service_domain()
219
+
220
+ # Create Lightsail database if not skipped
221
+ if not self.has_flag(ArchitectureFlags.SKIP_DATABASE.value):
222
+ self.create_lightsail_database()
223
+
224
+ # Create S3 bucket for application data
225
+ self.create_s3_bucket()
226
+
227
+ self.resources["lightsail_container_service"] = self.container_service
228
+
229
+ def create_lightsail_database(self):
230
+ """
231
+ Create Lightsail PostgreSQL database (optional).
232
+
233
+ Creates a micro PostgreSQL 14 database instance if the SKIP_DATABASE flag
234
+ is not set. Also populates the secrets dictionary with database connection
235
+ information for use in Secrets Manager.
236
+
237
+ Database Configuration:
238
+ * Engine: PostgreSQL 14
239
+ * Size: micro_2_0
240
+ * Final snapshot: Disabled (skip_final_snapshot=True)
241
+
242
+ .. note::
243
+ Database creation can be skipped by including ArchitectureFlags.SKIP_DATABASE
244
+ in the flags parameter during stack initialization.
245
+ """
246
+ # Database Password Generation
247
+ self.db_password = password.Password(
248
+ self, "db_password", length=16, special=True, override_special="!#$%&*()-_=+[]{}<>:?"
249
+ )
250
+
251
+ self.database = lightsail_database.LightsailDatabase(
252
+ self,
253
+ "app_database",
254
+ relational_database_name=f"{self.project_name}-db",
255
+ blueprint_id="postgres_14",
256
+ bundle_id="micro_2_0",
257
+ master_database_name=self.clean_hyphens(f"{self.project_name}"),
258
+ master_username=self.default_db_username,
259
+ master_password=self.db_password.result,
260
+ skip_final_snapshot=True,
261
+ tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
262
+ )
263
+
264
+ # Populate secrets for database connection
265
+ self.secrets.update(
266
+ {
267
+ "password": self.db_password.result,
268
+ "username": self.default_db_username,
269
+ "dbname": self.default_db_name,
270
+ "host": self.database.master_endpoint_address,
271
+ "port": self.database.master_endpoint_port,
272
+ }
273
+ def create_s3_bucket(self, bucket_name=None):
274
+ """
275
+ Create S3 bucket for application data storage.
276
+
277
+ Creates a private S3 bucket with proper tagging for application data storage
278
+ and security configurations:
279
+ - Bucket versioning enabled
280
+ - Server-side encryption with Amazon S3 managed keys (SSE-S3)
281
+ - Bucket key enabled to reduce encryption costs
282
+ - Private ACL
283
+
284
+ The bucket name follows the pattern: {project_name}-s3
285
+
286
+ .. note::
287
+ The ACL parameter is deprecated in favor of aws_s3_bucket_acl resource
288
+ but is retained for backwards compatibility.
289
+ """
290
+ if bucket_name is None:
291
+ bucket_name = self.properize_s3_bucketname(f"{self.project_name}-s3")
292
+
293
+ self.s3_bucket = s3_bucket.S3Bucket(
294
+ self,
295
+ "app_data_bucket",
296
+ bucket=bucket_name,
297
+ acl="private",
298
+ versioning={"enabled": True},
299
+ server_side_encryption_configuration=({
300
+ "rule": ({
301
+ "apply_server_side_encryption_by_default": {
302
+ "sse_algorithm": "AES256"
303
+ },
304
+ "bucket_key_enabled": True
305
+ })
306
+ }),
307
+ tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
308
+ )
309
+
310
+ # Store the S3 bucket in resources registry
311
+ self.resources["s3_bucket"] = self.s3_bucket
312
+ self.bucket_name = bucket_name
313
+
314
+ def get_lightsail_container_service_domain(self):
315
+ """
316
+ Retrieve the actual Lightsail container service domain from AWS.
317
+
318
+ Returns a default format domain since we cannot query AWS at synthesis time.
319
+
320
+ :returns: The public domain URL for the container service
321
+ :rtype: str
322
+ """
323
+ return f"{self.project_name}.{self.region}.cs.amazonlightsail.com"
324
+
325
+ def create_outputs(self):
326
+ """
327
+ Create Terraform outputs for important resource information.
328
+
329
+ Generates outputs for:
330
+ * Container service public URL
331
+ * Database endpoint (if database is enabled)
332
+ * Database password (sensitive, if database is enabled)
333
+ * IAM access keys (sensitive)
334
+
335
+ .. note::
336
+ Sensitive outputs are marked as such and will be hidden in
337
+ Terraform output unless explicitly requested.
338
+ """
339
+ # Container service public URL
340
+ TerraformOutput(
341
+ self,
342
+ "container_service_url",
343
+ value=self.container_service_url,
344
+ description="Public URL of the Lightsail container service",
345
+ )
346
+
347
+ # Database outputs (if database is enabled)
348
+ if not self.has_flag(ArchitectureFlags.SKIP_DATABASE.value) and hasattr(self, 'database'):
349
+ TerraformOutput(
350
+ self,
351
+ "database_endpoint",
352
+ value=f"{self.database.master_endpoint_address}:{self.database.master_endpoint_port}",
353
+ description="Database connection endpoint",
354
+ )
355
+ TerraformOutput(
356
+ self,
357
+ "database_password",
358
+ value=self.database.master_password,
359
+ sensitive=True,
360
+ description="Database master password (sensitive)",
361
+ )
362
+
363
+ # Use the shared IAM output helper
364
+ self.create_iam_outputs()
365
+
366
+ """Placeholder for networking resources creation."""
367
+ pass