cloud-foundry 0.1.2__tar.gz → 0.1.4__tar.gz
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.
- cloud_foundry-0.1.4/.gitignore +10 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/PKG-INFO +15 -15
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/__init__.py +13 -3
- cloud_foundry-0.1.4/cloud_foundry/pulumi/__init__.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/cdn.py +291 -18
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/cdn_api_origin.py +8 -0
- cloud_foundry-0.1.4/cloud_foundry/pulumi/connection_store.py +176 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/document_repository.py +28 -4
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/domain.py +8 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/function.py +126 -32
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/python_function.py +12 -9
- cloud_foundry-0.1.4/cloud_foundry/pulumi/queue.py +211 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/rest_api.py +27 -20
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/rest_api_logging_role.py +3 -3
- cloud_foundry-0.1.4/cloud_foundry/pulumi/topic.py +147 -0
- cloud_foundry-0.1.4/cloud_foundry/pulumi/websocket_api.py +463 -0
- cloud_foundry-0.1.4/cloud_foundry/pulumi/websocket_function.py +149 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/python_archive_builder.py +123 -32
- cloud_foundry-0.1.4/cloud_foundry/utils/websocket_utils.py +340 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/pyproject.toml +12 -3
- cloud_foundry-0.1.2/cloud_foundry/.DS_Store +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/LICENSE +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/README.md +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/archive_builder.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/cloud_foundry.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/mail_publisher.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/api_waf.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/cdn_site_origin.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/cloudfront_waf.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/content_repository.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/custom_domain.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/log_group.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/publisher.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/site_bucket.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/pulumi/ui_publisher.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/services/authorization_api/security_lambda.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/services/mail_publisher.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/utils/aws_openapi_editor.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/utils/hash_comparator.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/utils/logger.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/utils/names.py +0 -0
- {cloud_foundry-0.1.2 → cloud_foundry-0.1.4}/cloud_foundry/utils/openapi_editor.py +0 -0
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloud-foundry
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: cloud-foundry is a curated set of cloud components that can be used to assemble cloud-based applications.
|
|
5
|
+
Project-URL: Documentation, https://github.com/DanRepik/cloud-foundry
|
|
6
|
+
Project-URL: Source, https://github.com/DanRepik/cloud-foundry
|
|
5
7
|
Author-email: Daniel Repik <danrepik@icloud.com>
|
|
6
|
-
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
8
|
+
License: Apache-2.0
|
|
10
9
|
License-File: LICENSE
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Requires-Dist: boto3
|
|
11
14
|
Requires-Dist: pulumi
|
|
12
15
|
Requires-Dist: pulumi-aws
|
|
13
|
-
Requires-Dist: boto3
|
|
14
|
-
Requires-Dist: pytest>=7.0 ; extra == "dev"
|
|
15
|
-
Requires-Dist: pytest-cov>=4.0.0 ; extra == "dev"
|
|
16
|
-
Requires-Dist: black>=23.0.0 ; extra == "dev"
|
|
17
|
-
Requires-Dist: isort>=5.12.0 ; extra == "dev"
|
|
18
|
-
Requires-Dist: mypy>=1.0.0 ; extra == "dev"
|
|
19
|
-
Requires-Dist: flit>=3.9 ; extra == "dev"
|
|
20
|
-
Project-URL: Documentation, https://github.com/DanRepik/cloud-foundry
|
|
21
|
-
Project-URL: Source, https://github.com/DanRepik/cloud-foundry
|
|
22
16
|
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: flit>=3.9; extra == 'dev'
|
|
19
|
+
Requires-Dist: isort>=5.12.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
23
24
|
|
|
24
25
|
# Cloud Foundry
|
|
25
26
|
|
|
@@ -973,4 +974,3 @@ cdn_instance = cdn(
|
|
|
973
974
|
#### **Conclusion**
|
|
974
975
|
|
|
975
976
|
The `cdn` function simplifies the deployment of a Content Delivery Network using AWS CloudFront, Route 53, and ACM. It supports static sites, APIs, custom domains, and advanced features like logging and geo-restrictions. This function is ideal for building scalable, secure, and performant web applications.
|
|
976
|
-
|
|
@@ -5,13 +5,23 @@ from cloud_foundry.pulumi.function import function # noqa: F401
|
|
|
5
5
|
from cloud_foundry.pulumi.python_function import python_function # noqa: F401
|
|
6
6
|
from cloud_foundry.pulumi.rest_api import RestAPI # noqa: F401
|
|
7
7
|
from cloud_foundry.pulumi.rest_api import rest_api # noqa: F401
|
|
8
|
+
from cloud_foundry.pulumi.websocket_api import WebSocketAPI # noqa: F401
|
|
9
|
+
from cloud_foundry.pulumi.websocket_function import ( # noqa: F401
|
|
10
|
+
WebSocketFunction,
|
|
11
|
+
)
|
|
12
|
+
from cloud_foundry.pulumi.connection_store import ( # noqa: F401
|
|
13
|
+
ConnectionStore,
|
|
14
|
+
)
|
|
8
15
|
|
|
9
16
|
from cloud_foundry.utils.openapi_editor import OpenAPISpecEditor # noqa: F401
|
|
10
17
|
from cloud_foundry.pulumi.site_bucket import site_bucket # noqa: F401
|
|
11
18
|
from cloud_foundry.pulumi.document_repository import document_repository # noqa: F401
|
|
12
|
-
from cloud_foundry.pulumi.cdn import cdn # noqa: F401
|
|
19
|
+
from cloud_foundry.pulumi.cdn import cdn, CDN, CDNArgs # noqa: F401
|
|
13
20
|
from cloud_foundry.pulumi.domain import domain # noqa: F401
|
|
14
21
|
|
|
15
|
-
from cloud_foundry.
|
|
22
|
+
from cloud_foundry.pulumi.queue import queue
|
|
23
|
+
from cloud_foundry.pulumi.topic import topic
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
from cloud_foundry.utils.names import resource_id
|
|
26
|
+
|
|
27
|
+
version = "0.1.4"
|
|
File without changes
|
|
@@ -1,3 +1,99 @@
|
|
|
1
|
+
"""CloudFront CDN Component for Cloud Foundry.
|
|
2
|
+
|
|
3
|
+
This module provides a comprehensive CloudFront Content Delivery Network (CDN)
|
|
4
|
+
component with support for multiple origin types, custom domains, SSL/TLS
|
|
5
|
+
certificates, geo-restrictions, and advanced caching configurations.
|
|
6
|
+
|
|
7
|
+
Key Features:
|
|
8
|
+
- Multiple origin types: S3 buckets, API Gateway REST APIs, custom domains
|
|
9
|
+
- Automatic SSL/TLS certificate provisioning via ACM
|
|
10
|
+
- Custom domain configuration with Route53 DNS
|
|
11
|
+
- Geo-restriction support (whitelist/blacklist countries)
|
|
12
|
+
- Origin Shield for improved cache hit ratios
|
|
13
|
+
- Apex domain support
|
|
14
|
+
- CORS and security headers via managed policies
|
|
15
|
+
- Automatic cache behaviors for API origins
|
|
16
|
+
|
|
17
|
+
Origin Types:
|
|
18
|
+
1. S3 Bucket (SiteOrigin):
|
|
19
|
+
- Static website hosting
|
|
20
|
+
- Origin Access Identity for secure access
|
|
21
|
+
- Example: {"bucket": bucket_resource, "name": "site"}
|
|
22
|
+
|
|
23
|
+
2. Domain Name (ApiOrigin):
|
|
24
|
+
- Direct domain name for custom origins
|
|
25
|
+
- Path-based routing with cache behaviors
|
|
26
|
+
- Example: {"domain_name": "api.example.com", "path_pattern": "/api/*"}
|
|
27
|
+
|
|
28
|
+
3. REST API (ApiOrigin):
|
|
29
|
+
- API Gateway REST API integration
|
|
30
|
+
- Automatic domain resolution
|
|
31
|
+
- Example: {"rest_api": rest_api_resource, "path_pattern": "/api/*"}
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
from cloud_foundry.pulumi.cdn import CDN, CDNArgs
|
|
35
|
+
|
|
36
|
+
# Basic CDN with API origin
|
|
37
|
+
cdn = CDN(
|
|
38
|
+
"my-cdn",
|
|
39
|
+
CDNArgs(
|
|
40
|
+
hosted_zone_id="Z1234567890ABC",
|
|
41
|
+
subdomain="api",
|
|
42
|
+
site_domain_name="example.com",
|
|
43
|
+
origins=[
|
|
44
|
+
{
|
|
45
|
+
"name": "api",
|
|
46
|
+
"domain_name": api.domain,
|
|
47
|
+
"path_pattern": "/api/*",
|
|
48
|
+
"origin_shield_region": "us-east-1"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# CDN with S3 bucket and API origin
|
|
55
|
+
cdn = CDN(
|
|
56
|
+
"multi-origin-cdn",
|
|
57
|
+
CDNArgs(
|
|
58
|
+
hosted_zone_id="Z1234567890ABC",
|
|
59
|
+
subdomain="cdn",
|
|
60
|
+
create_apex=True,
|
|
61
|
+
site_domain_name="example.com",
|
|
62
|
+
root_uri="index.html",
|
|
63
|
+
origins=[
|
|
64
|
+
{
|
|
65
|
+
"name": "site",
|
|
66
|
+
"bucket": s3_bucket,
|
|
67
|
+
"is_target_origin": True
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "api",
|
|
71
|
+
"domain_name": "api.example.com",
|
|
72
|
+
"path_pattern": "/api/*"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
whitelist_countries=["US", "CA", "GB"]
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
Configuration:
|
|
80
|
+
- hosted_zone_id: Route53 hosted zone for DNS records
|
|
81
|
+
- subdomain: Subdomain for CDN distribution (e.g., "www", "cdn")
|
|
82
|
+
- site_domain_name: Base domain name for apex domain support
|
|
83
|
+
- create_apex: Create A record for apex domain (example.com)
|
|
84
|
+
- origins: List of origin configurations (see Origin Types above)
|
|
85
|
+
- error_responses: Custom error response configurations
|
|
86
|
+
- root_uri: Default root object (e.g., "index.html")
|
|
87
|
+
- whitelist_countries: ISO country codes to allow (exclusive with blacklist)
|
|
88
|
+
- blacklist_countries: ISO country codes to block (default: CN, RU, CU, KP, IR, BY)
|
|
89
|
+
|
|
90
|
+
Outputs:
|
|
91
|
+
- distribution: CloudFront Distribution resource
|
|
92
|
+
- domain_name: CDN domain name (custom domain or CloudFront domain)
|
|
93
|
+
- dns_alias: Route53 A record for custom domain
|
|
94
|
+
- apex_alias: Route53 A record for apex domain (if create_apex=True)
|
|
95
|
+
"""
|
|
96
|
+
|
|
1
97
|
import pulumi
|
|
2
98
|
import pulumi_aws as aws
|
|
3
99
|
from pulumi import ResourceOptions
|
|
@@ -22,12 +118,36 @@ DEFAULT_BLACKLIST_COUNTRIES = [
|
|
|
22
118
|
|
|
23
119
|
|
|
24
120
|
class CDNArgs:
|
|
121
|
+
"""Configuration arguments for CDN component.
|
|
122
|
+
|
|
123
|
+
Attributes:
|
|
124
|
+
origins: List of origin configurations. Each origin dict can contain:
|
|
125
|
+
- name (str): Unique identifier for the origin
|
|
126
|
+
- bucket (aws.s3.Bucket): S3 bucket for static site hosting
|
|
127
|
+
- domain_name (str|Output): Custom domain name for API origin
|
|
128
|
+
- rest_api (RestAPI): API Gateway REST API resource
|
|
129
|
+
- path_pattern (str): Path pattern for cache behavior (e.g., "/api/*")
|
|
130
|
+
- origin_path (str): Optional path prefix on origin
|
|
131
|
+
- origin_shield_region (str): AWS region for Origin Shield
|
|
132
|
+
- is_target_origin (bool): Whether this is the default origin
|
|
133
|
+
- api_key_password (str): Optional API key for custom header
|
|
134
|
+
create_apex: Whether to create DNS record for apex domain (default: False)
|
|
135
|
+
hosted_zone_id: Route53 hosted zone ID for DNS records
|
|
136
|
+
subdomain: Subdomain for the CDN (e.g., "www", "cdn", "api")
|
|
137
|
+
site_domain_name: Base domain name for apex domain creation
|
|
138
|
+
error_responses: List of custom error response configurations
|
|
139
|
+
root_uri: Default root object for distribution (e.g., "index.html")
|
|
140
|
+
whitelist_countries: ISO country codes to allow (exclusive with blacklist)
|
|
141
|
+
blacklist_countries: ISO country codes to block (default: CN, RU, CU, KP, IR, BY)
|
|
142
|
+
"""
|
|
143
|
+
|
|
25
144
|
def __init__(
|
|
26
145
|
self,
|
|
27
146
|
origins: Optional[List[dict]] = None,
|
|
28
147
|
create_apex: Optional[bool] = False,
|
|
29
148
|
hosted_zone_id: Optional[str] = None,
|
|
30
149
|
subdomain: Optional[str] = None,
|
|
150
|
+
site_domain_name: Optional[str] = None,
|
|
31
151
|
error_responses: Optional[list] = None,
|
|
32
152
|
root_uri: Optional[str] = None,
|
|
33
153
|
whitelist_countries: Optional[List[str]] = None,
|
|
@@ -37,6 +157,7 @@ class CDNArgs:
|
|
|
37
157
|
self.create_apex = create_apex
|
|
38
158
|
self.hosted_zone_id = hosted_zone_id
|
|
39
159
|
self.subdomain = subdomain
|
|
160
|
+
self.site_domain_name = site_domain_name
|
|
40
161
|
self.error_responses = error_responses
|
|
41
162
|
self.root_uri = root_uri
|
|
42
163
|
self.whitelist_countries = whitelist_countries
|
|
@@ -44,7 +165,59 @@ class CDNArgs:
|
|
|
44
165
|
|
|
45
166
|
|
|
46
167
|
class CDN(pulumi.ComponentResource):
|
|
168
|
+
"""CloudFront CDN Component Resource.
|
|
169
|
+
|
|
170
|
+
Creates a CloudFront distribution with:
|
|
171
|
+
- Multiple origin support (S3, API Gateway, custom domains)
|
|
172
|
+
- SSL/TLS certificate provisioned via ACM
|
|
173
|
+
- Custom domain with Route53 DNS configuration
|
|
174
|
+
- Geo-restriction support
|
|
175
|
+
- Origin Shield for improved performance
|
|
176
|
+
- Managed CORS and security headers
|
|
177
|
+
- Path-based cache behaviors for API origins
|
|
178
|
+
|
|
179
|
+
The component automatically:
|
|
180
|
+
- Provisions and validates ACM certificate
|
|
181
|
+
- Creates Route53 DNS records for custom domain
|
|
182
|
+
- Configures origin-specific cache behaviors
|
|
183
|
+
- Sets up S3 bucket policies for OAI access
|
|
184
|
+
- Applies geo-restrictions
|
|
185
|
+
|
|
186
|
+
Attributes:
|
|
187
|
+
distribution: CloudFront Distribution resource
|
|
188
|
+
domain_name: CDN domain name (custom or CloudFront)
|
|
189
|
+
dns_alias: Route53 A record for subdomain
|
|
190
|
+
apex_alias: Route53 A record for apex domain (if create_apex=True)
|
|
191
|
+
site_origins: List of SiteOrigin resources
|
|
192
|
+
hosted_zone_id: Route53 hosted zone ID
|
|
193
|
+
subdomain: CDN subdomain
|
|
194
|
+
|
|
195
|
+
Example:
|
|
196
|
+
cdn = CDN(
|
|
197
|
+
"my-cdn",
|
|
198
|
+
CDNArgs(
|
|
199
|
+
hosted_zone_id="Z123456",
|
|
200
|
+
subdomain="api",
|
|
201
|
+
origins=[
|
|
202
|
+
{
|
|
203
|
+
"name": "api",
|
|
204
|
+
"domain_name": legis_api.domain,
|
|
205
|
+
"path_pattern": "/api/*",
|
|
206
|
+
"origin_shield_region": "us-east-1"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
"""
|
|
212
|
+
|
|
47
213
|
def __init__(self, name: str, args: CDNArgs, opts: ResourceOptions = None):
|
|
214
|
+
"""Initialize CDN component.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
name: Resource name for the CDN
|
|
218
|
+
args: CDN configuration arguments
|
|
219
|
+
opts: Pulumi resource options
|
|
220
|
+
"""
|
|
48
221
|
super().__init__("cloud_foundry:pulumi:CDN", name, {}, opts)
|
|
49
222
|
|
|
50
223
|
self.hosted_zone_id = args.hosted_zone_id
|
|
@@ -61,17 +234,10 @@ class CDN(pulumi.ComponentResource):
|
|
|
61
234
|
include_apex=args.create_apex,
|
|
62
235
|
)
|
|
63
236
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
+ {
|
|
69
|
-
(
|
|
70
|
-
[self.domain_name, args.site_domain_name]
|
|
71
|
-
if args.create_apex
|
|
72
|
-
else [self.domain_name]
|
|
73
|
-
)
|
|
74
|
-
}
|
|
237
|
+
aliases_list = (
|
|
238
|
+
[self.domain_name, args.site_domain_name]
|
|
239
|
+
if args.create_apex
|
|
240
|
+
else [self.domain_name]
|
|
75
241
|
)
|
|
76
242
|
|
|
77
243
|
origins, caches, target_origin_id = self.get_origins(name, args.origins)
|
|
@@ -86,11 +252,7 @@ class CDN(pulumi.ComponentResource):
|
|
|
86
252
|
include_cookies=False,
|
|
87
253
|
prefix="logs/",
|
|
88
254
|
),
|
|
89
|
-
aliases=
|
|
90
|
-
[self.domain_name, args.site_domain_name]
|
|
91
|
-
if args.create_apex
|
|
92
|
-
else [self.domain_name]
|
|
93
|
-
),
|
|
255
|
+
aliases=aliases_list,
|
|
94
256
|
default_cache_behavior=aws.cloudfront.DistributionDefaultCacheBehaviorArgs(
|
|
95
257
|
target_origin_id=target_origin_id,
|
|
96
258
|
viewer_protocol_policy="redirect-to-https",
|
|
@@ -184,6 +346,34 @@ class CDN(pulumi.ComponentResource):
|
|
|
184
346
|
self.domain_name = self.distribution.domain_name
|
|
185
347
|
|
|
186
348
|
def get_origins(self, name: str, origins: List[dict]):
|
|
349
|
+
"""Process and configure CDN origins.
|
|
350
|
+
|
|
351
|
+
Processes the origin configurations and creates appropriate origin resources
|
|
352
|
+
(SiteOrigin for S3, ApiOrigin for APIs/domains). Determines the default
|
|
353
|
+
target origin and configures cache behaviors.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
name: Base name for origin resources
|
|
357
|
+
origins: List of origin configuration dicts with keys:
|
|
358
|
+
- bucket: S3 bucket for static sites
|
|
359
|
+
- domain_name: Custom domain name string
|
|
360
|
+
- rest_api: RestAPI resource
|
|
361
|
+
- name: Origin identifier
|
|
362
|
+
- path_pattern: Cache behavior path pattern
|
|
363
|
+
- origin_path: Path prefix on origin
|
|
364
|
+
- origin_shield_region: Origin Shield region
|
|
365
|
+
- is_target_origin: Mark as default origin
|
|
366
|
+
- api_key_password: API key for custom header
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Tuple of (cdn_origins, caches, target_origin_id):
|
|
370
|
+
- cdn_origins: List of DistributionOriginArgs
|
|
371
|
+
- caches: List of DistributionOrderedCacheBehaviorArgs
|
|
372
|
+
- target_origin_id: Default origin ID
|
|
373
|
+
|
|
374
|
+
Raises:
|
|
375
|
+
ValueError: If origin configuration is invalid or domain cannot be resolved
|
|
376
|
+
"""
|
|
187
377
|
target_origin_id = None
|
|
188
378
|
cdn_origins = []
|
|
189
379
|
caches = []
|
|
@@ -204,7 +394,13 @@ class CDN(pulumi.ComponentResource):
|
|
|
204
394
|
self.site_origins.append(cdn_origin)
|
|
205
395
|
|
|
206
396
|
elif "domain_name" in origin:
|
|
207
|
-
cdn_origin = ApiOrigin(
|
|
397
|
+
cdn_origin = ApiOrigin(
|
|
398
|
+
f"{name}-{origin["name"]}",
|
|
399
|
+
domain_name=origin["domain_name"],
|
|
400
|
+
path_pattern=origin.get("path_pattern"),
|
|
401
|
+
origin_path=origin.get("origin_path"),
|
|
402
|
+
shield_region=origin.get("origin_shield_region"),
|
|
403
|
+
)
|
|
208
404
|
cdn_origins.append(cdn_origin.distribution_origin)
|
|
209
405
|
caches.append(cdn_origin.cache_behavior)
|
|
210
406
|
|
|
@@ -262,6 +458,22 @@ class CDN(pulumi.ComponentResource):
|
|
|
262
458
|
def set_up_certificate(
|
|
263
459
|
self, name, domain_name, alternative_names: Optional[List[str]] = None
|
|
264
460
|
):
|
|
461
|
+
"""Provision and validate ACM certificate for custom domain.
|
|
462
|
+
|
|
463
|
+
Creates an ACM certificate with DNS validation via Route53. Automatically
|
|
464
|
+
creates validation DNS records and waits for certificate validation.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
name: Resource name prefix
|
|
468
|
+
domain_name: Primary domain name for certificate
|
|
469
|
+
alternative_names: List of Subject Alternative Names (SANs)
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
Tuple of (certificate, validation) resources
|
|
473
|
+
|
|
474
|
+
Raises:
|
|
475
|
+
ValueError: If hosted_zone_id is not configured
|
|
476
|
+
"""
|
|
265
477
|
if not self.hosted_zone_id:
|
|
266
478
|
raise ValueError(
|
|
267
479
|
"Hosted zone ID is required for custom domain setup. "
|
|
@@ -314,6 +526,21 @@ class CDN(pulumi.ComponentResource):
|
|
|
314
526
|
stage_name: str,
|
|
315
527
|
rest_api_id,
|
|
316
528
|
):
|
|
529
|
+
"""Configure custom domain for API Gateway REST API.
|
|
530
|
+
|
|
531
|
+
Creates ACM certificate, API Gateway domain name, base path mapping,
|
|
532
|
+
and Route53 DNS record for a custom domain pointing to an API Gateway.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
name: Resource name prefix
|
|
536
|
+
hosted_zone_id: Route53 hosted zone ID for DNS
|
|
537
|
+
domain_name: Custom domain name
|
|
538
|
+
stage_name: API Gateway stage name
|
|
539
|
+
rest_api_id: API Gateway REST API ID
|
|
540
|
+
|
|
541
|
+
Returns:
|
|
542
|
+
The configured domain name string
|
|
543
|
+
"""
|
|
317
544
|
certificate, validation = self.set_up_certificate(name, domain_name)
|
|
318
545
|
|
|
319
546
|
custom_domain = aws.apigateway.DomainName(
|
|
@@ -354,6 +581,20 @@ class CDN(pulumi.ComponentResource):
|
|
|
354
581
|
return domain_name
|
|
355
582
|
|
|
356
583
|
def find_hosted_zone_id(self, name: str) -> str:
|
|
584
|
+
"""Find Route53 hosted zone ID by domain name.
|
|
585
|
+
|
|
586
|
+
Placeholder method for looking up hosted zone ID dynamically.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
name: Domain name to search for
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
Hosted zone ID string
|
|
593
|
+
|
|
594
|
+
Note:
|
|
595
|
+
This method is not yet implemented. Pass hosted_zone_id
|
|
596
|
+
directly in CDNArgs instead.
|
|
597
|
+
"""
|
|
357
598
|
# Implement your logic to find the hosted zone ID
|
|
358
599
|
pass
|
|
359
600
|
|
|
@@ -368,7 +609,39 @@ def cdn(
|
|
|
368
609
|
root_uri: Optional[str] = None,
|
|
369
610
|
opts: ResourceOptions = None,
|
|
370
611
|
) -> CDN:
|
|
371
|
-
|
|
612
|
+
"""Factory function to create a CDN component.
|
|
613
|
+
|
|
614
|
+
Convenience function for creating a CDN without explicitly constructing
|
|
615
|
+
CDNArgs. Wraps the CDN component resource initialization.
|
|
616
|
+
|
|
617
|
+
Args:
|
|
618
|
+
name: Resource name for the CDN
|
|
619
|
+
origins: List of origin configuration dicts
|
|
620
|
+
hosted_zone_id: Route53 hosted zone ID for custom domain
|
|
621
|
+
subdomain: Subdomain for CDN (e.g., "www", "cdn")
|
|
622
|
+
error_responses: Custom error response configurations
|
|
623
|
+
create_apex: Create apex domain A record (default: False)
|
|
624
|
+
root_uri: Default root object (e.g., "index.html")
|
|
625
|
+
opts: Pulumi resource options
|
|
626
|
+
|
|
627
|
+
Returns:
|
|
628
|
+
CDN component resource instance
|
|
629
|
+
|
|
630
|
+
Example:
|
|
631
|
+
my_cdn = cdn(
|
|
632
|
+
"website-cdn",
|
|
633
|
+
origins=[
|
|
634
|
+
{
|
|
635
|
+
"name": "site",
|
|
636
|
+
"bucket": website_bucket,
|
|
637
|
+
"is_target_origin": True
|
|
638
|
+
}
|
|
639
|
+
],
|
|
640
|
+
hosted_zone_id="Z123456",
|
|
641
|
+
subdomain="www",
|
|
642
|
+
root_uri="index.html"
|
|
643
|
+
)
|
|
644
|
+
"""
|
|
372
645
|
return CDN(
|
|
373
646
|
name,
|
|
374
647
|
CDNArgs(
|
|
@@ -52,6 +52,7 @@ class ApiOrigin(pulumi.ComponentResource):
|
|
|
52
52
|
|
|
53
53
|
self.origin_id = f"{name}-api"
|
|
54
54
|
log.info(f"Creating API origin with ID: {self.origin_id}")
|
|
55
|
+
log.info(f"Domain name type: {type(domain_name)}, value: {domain_name}")
|
|
55
56
|
|
|
56
57
|
# Configure custom headers if API key is provided
|
|
57
58
|
custom_headers = []
|
|
@@ -59,6 +60,13 @@ class ApiOrigin(pulumi.ComponentResource):
|
|
|
59
60
|
custom_headers.append({"name": "X-API-Key", "value": api_key_password})
|
|
60
61
|
log.debug("Custom headers configured for API key.")
|
|
61
62
|
|
|
63
|
+
# If domain_name is an Output, we need to handle it properly
|
|
64
|
+
# Pulumi should handle Output automatically, but let's ensure it's properly typed
|
|
65
|
+
if isinstance(domain_name, pulumi.Output):
|
|
66
|
+
log.info(
|
|
67
|
+
"Domain name is a Pulumi Output - will be resolved at deployment time"
|
|
68
|
+
)
|
|
69
|
+
|
|
62
70
|
# Define the CloudFront distribution origin
|
|
63
71
|
self.distribution_origin = aws.cloudfront.DistributionOriginArgs(
|
|
64
72
|
domain_name=domain_name,
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# connection_store.py
|
|
2
|
+
|
|
3
|
+
import pulumi
|
|
4
|
+
import pulumi_aws as aws
|
|
5
|
+
from cloud_foundry.utils.logger import logger
|
|
6
|
+
|
|
7
|
+
log = logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConnectionStore(pulumi.ComponentResource):
|
|
11
|
+
"""
|
|
12
|
+
A DynamoDB table for managing WebSocket connections.
|
|
13
|
+
|
|
14
|
+
This component creates a DynamoDB table optimized for storing and
|
|
15
|
+
querying WebSocket connection information including:
|
|
16
|
+
- Connection IDs (primary key)
|
|
17
|
+
- User identification and metadata
|
|
18
|
+
- Connection timestamps
|
|
19
|
+
- Custom routing attributes
|
|
20
|
+
- TTL for automatic cleanup of stale connections
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
table: aws.dynamodb.Table
|
|
24
|
+
table_name: pulumi.Output[str]
|
|
25
|
+
table_arn: pulumi.Output[str]
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
name: str,
|
|
30
|
+
*,
|
|
31
|
+
ttl_attribute: str = "ttl",
|
|
32
|
+
ttl_enabled: bool = True,
|
|
33
|
+
read_capacity: int = 5,
|
|
34
|
+
write_capacity: int = 5,
|
|
35
|
+
billing_mode: str = "PAY_PER_REQUEST",
|
|
36
|
+
global_secondary_indexes: list[dict] = None,
|
|
37
|
+
opts=None,
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
Initialize the ConnectionStore component.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
name (str): Name of the connection store
|
|
44
|
+
ttl_attribute (str): Name of the TTL attribute (default: "ttl")
|
|
45
|
+
ttl_enabled (bool): Enable TTL for automatic cleanup
|
|
46
|
+
(default: True)
|
|
47
|
+
read_capacity (int): Provisioned read capacity units
|
|
48
|
+
(only used if billing_mode is PROVISIONED)
|
|
49
|
+
write_capacity (int): Provisioned write capacity units
|
|
50
|
+
(only used if billing_mode is PROVISIONED)
|
|
51
|
+
billing_mode (str): Billing mode - "PAY_PER_REQUEST" or
|
|
52
|
+
"PROVISIONED" (default: "PAY_PER_REQUEST")
|
|
53
|
+
global_secondary_indexes (list[dict]): Additional GSIs for
|
|
54
|
+
querying connections by custom attributes. Each dict should
|
|
55
|
+
have:
|
|
56
|
+
- name (str): Index name
|
|
57
|
+
- hash_key (str): Partition key attribute
|
|
58
|
+
- range_key (str, optional): Sort key attribute
|
|
59
|
+
- projection_type (str): ALL, KEYS_ONLY, or INCLUDE
|
|
60
|
+
- non_key_attributes (list, optional): For INCLUDE projection
|
|
61
|
+
opts (pulumi.ResourceOptions): Pulumi resource options
|
|
62
|
+
"""
|
|
63
|
+
super().__init__("cloud_foundry:websocket:ConnectionStore", name, None, opts)
|
|
64
|
+
self.name = name
|
|
65
|
+
self.ttl_attribute = ttl_attribute
|
|
66
|
+
self.ttl_enabled = ttl_enabled
|
|
67
|
+
self.global_secondary_indexes = global_secondary_indexes or []
|
|
68
|
+
|
|
69
|
+
# Create the DynamoDB table
|
|
70
|
+
self.table = self._create_table(billing_mode, read_capacity, write_capacity)
|
|
71
|
+
self.table_name = self.table.name
|
|
72
|
+
self.table_arn = self.table.arn
|
|
73
|
+
|
|
74
|
+
# Register outputs
|
|
75
|
+
self.register_outputs(
|
|
76
|
+
{
|
|
77
|
+
"table_name": self.table_name,
|
|
78
|
+
"table_arn": self.table_arn,
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def _create_table(self, billing_mode: str, read_capacity: int, write_capacity: int):
|
|
83
|
+
"""
|
|
84
|
+
Create the DynamoDB table for connection storage.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
billing_mode: Billing mode for the table
|
|
88
|
+
read_capacity: Provisioned read capacity
|
|
89
|
+
write_capacity: Provisioned write capacity
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
aws.dynamodb.Table: The created table
|
|
93
|
+
"""
|
|
94
|
+
log.info("Creating connection store table: %s", self.name)
|
|
95
|
+
|
|
96
|
+
table_name = f"{pulumi.get_project()}-{pulumi.get_stack()}-{self.name}"
|
|
97
|
+
|
|
98
|
+
# Define base attributes
|
|
99
|
+
attributes = [
|
|
100
|
+
aws.dynamodb.TableAttributeArgs(
|
|
101
|
+
name="connectionId",
|
|
102
|
+
type="S",
|
|
103
|
+
),
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
# Add attributes for GSIs
|
|
107
|
+
for gsi in self.global_secondary_indexes:
|
|
108
|
+
if gsi.get("hash_key") and not any(
|
|
109
|
+
attr.name == gsi["hash_key"] for attr in attributes
|
|
110
|
+
):
|
|
111
|
+
attributes.append(
|
|
112
|
+
aws.dynamodb.TableAttributeArgs(
|
|
113
|
+
name=gsi["hash_key"],
|
|
114
|
+
type=gsi.get("hash_key_type", "S"),
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
if gsi.get("range_key") and not any(
|
|
118
|
+
attr.name == gsi["range_key"] for attr in attributes
|
|
119
|
+
):
|
|
120
|
+
attributes.append(
|
|
121
|
+
aws.dynamodb.TableAttributeArgs(
|
|
122
|
+
name=gsi["range_key"],
|
|
123
|
+
type=gsi.get("range_key_type", "S"),
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Prepare GSI configurations
|
|
128
|
+
gsi_configs = []
|
|
129
|
+
for gsi in self.global_secondary_indexes:
|
|
130
|
+
gsi_config = aws.dynamodb.TableGlobalSecondaryIndexArgs(
|
|
131
|
+
name=gsi["name"],
|
|
132
|
+
hash_key=gsi["hash_key"],
|
|
133
|
+
projection_type=gsi.get("projection_type", "ALL"),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if gsi.get("range_key"):
|
|
137
|
+
gsi_config.range_key = gsi["range_key"]
|
|
138
|
+
|
|
139
|
+
if gsi.get("projection_type") == "INCLUDE":
|
|
140
|
+
gsi_config.non_key_attributes = gsi.get("non_key_attributes", [])
|
|
141
|
+
|
|
142
|
+
if billing_mode == "PROVISIONED":
|
|
143
|
+
gsi_config.read_capacity = gsi.get("read_capacity", 5)
|
|
144
|
+
gsi_config.write_capacity = gsi.get("write_capacity", 5)
|
|
145
|
+
|
|
146
|
+
gsi_configs.append(gsi_config)
|
|
147
|
+
|
|
148
|
+
# Create table configuration
|
|
149
|
+
table_config = {
|
|
150
|
+
"name": table_name,
|
|
151
|
+
"hash_key": "connectionId",
|
|
152
|
+
"attributes": attributes,
|
|
153
|
+
"billing_mode": billing_mode,
|
|
154
|
+
"global_secondary_indexes": gsi_configs if gsi_configs else None,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Add capacity settings for PROVISIONED mode
|
|
158
|
+
if billing_mode == "PROVISIONED":
|
|
159
|
+
table_config["read_capacity"] = read_capacity
|
|
160
|
+
table_config["write_capacity"] = write_capacity
|
|
161
|
+
|
|
162
|
+
# Add TTL configuration if enabled
|
|
163
|
+
if self.ttl_enabled:
|
|
164
|
+
table_config["ttl"] = aws.dynamodb.TableTtlArgs(
|
|
165
|
+
attribute_name=self.ttl_attribute,
|
|
166
|
+
enabled=True,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Create the table
|
|
170
|
+
table = aws.dynamodb.Table(
|
|
171
|
+
f"{self.name}-table",
|
|
172
|
+
**table_config,
|
|
173
|
+
opts=pulumi.ResourceOptions(parent=self),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return table
|