@go-to-k/cdkd 0.0.1 → 0.0.2
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.
- package/LICENSE +201 -0
- package/README.md +552 -29
- package/dist/cli.js +26879 -0
- package/dist/cli.js.map +7 -0
- package/dist/go-to-k-cdkd-0.0.2.tgz +0 -0
- package/dist/index.js +7979 -0
- package/dist/index.js.map +7 -0
- package/package.json +130 -6
package/README.md
CHANGED
|
@@ -1,45 +1,568 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cdkd
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**cdkd** (CDK Direct) - A from-scratch CDK CLI with its own deployment engine — provisions via AWS SDK instead of CloudFormation.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
- **Direct provisioning** via AWS SDK instead of CloudFormation
|
|
6
|
+
- **From-scratch CDK CLI** - synthesis orchestration, asset publishing, context resolution (no aws-cdk / toolkit-lib dependency)
|
|
7
|
+
- **CDK compatible** - use your existing CDK app code as-is
|
|
8
|
+
- **Own deployment engine** - diff calculation, dependency graph, parallel execution, state management (what CloudFormation handles internally)
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+

|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
> **⚠️ WARNING: NOT PRODUCTION READY**
|
|
13
|
+
>
|
|
14
|
+
> This project is in early development and is **NOT suitable for production use**. Features are incomplete, APIs may change without notice, and there may be bugs that could affect your AWS infrastructure. Use at your own risk in development/testing environments only.
|
|
10
15
|
|
|
11
|
-
This
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@go-to-k/cdkd`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
16
|
+
> **Note**: This is an experimental/educational project exploring alternative deployment approaches for AWS CDK. It is **not intended to replace** the official AWS CDK CLI, but rather to experiment with direct SDK provisioning as a learning exercise and proof of concept.
|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## Features
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
- **Synthesis orchestration**: CDK app subprocess execution, Cloud Assembly parsing, context provider loop
|
|
21
|
+
- **Asset handling**: Self-implemented asset publisher for S3 file assets (ZIP packaging) and Docker images (ECR)
|
|
22
|
+
- **Context resolution**: Self-implemented context provider loop for Vpc.fromLookup(), AZ, SSM, HostedZone, etc.
|
|
23
|
+
- **Hybrid provisioning**: SDK Providers for fast direct API calls, Cloud Control API fallback for broad resource coverage
|
|
24
|
+
- **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
|
|
25
|
+
- **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
|
|
26
|
+
- **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
> **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. If you encounter an unsupported resource type, deployment will fail with a clear error message.
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
## Benchmark
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
32
|
+
**cdkd deploys up to ~5x faster than AWS CDK (CloudFormation).**
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
Measured on `us-east-1` with 5 independent resources per stack (fully parallelized by cdkd's DAG scheduler).
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
+
### SDK Provider path — **4.8x faster** (20.5s vs 98.4s)
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
Stack: S3 Bucket, DynamoDB Table, SQS Queue, SNS Topic, SSM Parameter.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
| Phase | cdkd | AWS CDK (CFn) | Speedup |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| Synthesis | 3.5s | 4.1s | 1.2x |
|
|
43
|
+
| Deploy | 17.0s | 94.4s | **5.5x** |
|
|
44
|
+
| **Total** | **20.5s** | **98.4s** | **4.8x** |
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
### Cloud Control API fallback path — **1.5x faster** (44.6s vs 69.1s)
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
Stack: SSM Document × 3 + Athena WorkGroup × 2 (no SDK provider — CC API fallback).
|
|
49
|
+
|
|
50
|
+
| Phase | cdkd | AWS CDK (CFn) | Speedup |
|
|
51
|
+
| --- | --- | --- | --- |
|
|
52
|
+
| Synthesis | 3.7s | 4.2s | 1.1x |
|
|
53
|
+
| Deploy | 40.9s | 64.9s | **1.6x** |
|
|
54
|
+
| **Total** | **44.6s** | **69.1s** | **1.5x** |
|
|
55
|
+
|
|
56
|
+
Reproduce with `./tests/benchmark/run-benchmark.sh all`. See [tests/benchmark/README.md](tests/benchmark/README.md) for details.
|
|
57
|
+
|
|
58
|
+
## How it works
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
┌─────────────────┐
|
|
62
|
+
│ Your CDK App │ (aws-cdk-lib)
|
|
63
|
+
└────────┬────────┘
|
|
64
|
+
│
|
|
65
|
+
▼
|
|
66
|
+
┌─────────────────┐
|
|
67
|
+
│ cdkd Synthesis │ Subprocess + Cloud Assembly parser
|
|
68
|
+
└────────┬────────┘
|
|
69
|
+
│
|
|
70
|
+
▼
|
|
71
|
+
┌─────────────────┐
|
|
72
|
+
│ CloudFormation │
|
|
73
|
+
│ Template │
|
|
74
|
+
└────────┬────────┘
|
|
75
|
+
│
|
|
76
|
+
▼
|
|
77
|
+
┌─────────────────┐
|
|
78
|
+
│ cdkd Engine │
|
|
79
|
+
│ - DAG Analysis │ Dependency graph construction
|
|
80
|
+
│ - Diff Calc │ Compare with existing resources
|
|
81
|
+
│ - Parallel Exec │ Deploy by levels
|
|
82
|
+
└────────┬────────┘
|
|
83
|
+
│
|
|
84
|
+
┌────┴────┐
|
|
85
|
+
▼ ▼
|
|
86
|
+
┌────────┐ ┌────────┐
|
|
87
|
+
│ SDK │ │ Cloud │
|
|
88
|
+
│Provider│ │Control │ Fallback for many
|
|
89
|
+
│ │ │ API │ additional types
|
|
90
|
+
└────────┘ └────────┘
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Detailed Processing Flow (`cdkd deploy`)
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
1. CLI Layer
|
|
97
|
+
├── Resolve --app (CLI > CDKD_APP env > cdk.json "app")
|
|
98
|
+
├── Resolve --state-bucket (CLI > env > cdk.json > auto: cdkd-state-{accountId}-{region})
|
|
99
|
+
└── Initialize AWS clients
|
|
100
|
+
|
|
101
|
+
2. Synthesis (self-implemented, no CDK CLI dependency)
|
|
102
|
+
├── Load context (merge order, later wins):
|
|
103
|
+
│ ├── CDK defaults (path-metadata, asset-metadata, version-reporting, bundling-stacks)
|
|
104
|
+
│ ├── ~/.cdk.json "context" field (user defaults)
|
|
105
|
+
│ ├── cdk.json "context" field (project settings)
|
|
106
|
+
│ ├── cdk.context.json (cached lookups, reloaded each iteration)
|
|
107
|
+
│ └── CLI -c key=value (highest priority)
|
|
108
|
+
├── Execute CDK app as subprocess
|
|
109
|
+
│ ├── child_process.spawn(app command)
|
|
110
|
+
│ ├── Pass env: CDK_OUTDIR, CDK_CONTEXT_JSON, CDK_DEFAULT_REGION/ACCOUNT
|
|
111
|
+
│ └── App writes Cloud Assembly to cdk.out/
|
|
112
|
+
├── Parse cdk.out/manifest.json
|
|
113
|
+
│ ├── Extract stacks (type: aws:cloudformation:stack)
|
|
114
|
+
│ ├── Extract asset manifests (type: cdk:asset-manifest)
|
|
115
|
+
│ └── Extract stack dependencies
|
|
116
|
+
└── Context provider loop (if missing context detected):
|
|
117
|
+
├── Resolve via AWS SDK (all CDK context provider types supported)
|
|
118
|
+
├── Save to cdk.context.json
|
|
119
|
+
└── Re-execute CDK app with updated context
|
|
120
|
+
|
|
121
|
+
3. Asset Publishing + Deployment (WorkGraph DAG)
|
|
122
|
+
├── Each asset is a node, each stack deploy is a node
|
|
123
|
+
│ ├── asset-publish nodes: 8 concurrent (file S3 uploads + Docker build+push)
|
|
124
|
+
│ ├── stack nodes: 4 concurrent deployments
|
|
125
|
+
│ ├── Dependencies: asset-publish → stack (all assets complete before deploy)
|
|
126
|
+
│ └── Inter-stack: stack A → stack B (CDK dependency order)
|
|
127
|
+
├── Region resolved from asset manifest destination (stack's target region)
|
|
128
|
+
├── Skip if already exists (HeadObject for S3, DescribeImages for ECR)
|
|
129
|
+
├── Per-stack deploy flow:
|
|
130
|
+
│ ├── Acquire S3 lock (optimistic locking)
|
|
131
|
+
│ ├── Load current state from S3
|
|
132
|
+
│ ├── Build DAG from template (Ref/Fn::GetAtt/DependsOn)
|
|
133
|
+
│ ├── Calculate diff (CREATE/UPDATE/DELETE)
|
|
134
|
+
│ ├── Resolve intrinsic functions (Ref, Fn::Sub, Fn::Join, etc.)
|
|
135
|
+
│ ├── Execute by levels (parallel within each level):
|
|
136
|
+
│ │ ├── SDK Providers (direct API calls, preferred)
|
|
137
|
+
│ │ └── Cloud Control API (fallback, async polling)
|
|
138
|
+
│ ├── Save state after each level (partial state save)
|
|
139
|
+
│ └── Release lock
|
|
140
|
+
└── synth does NOT publish assets or deploy (deploy only)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Supported Features
|
|
144
|
+
|
|
145
|
+
### Intrinsic Functions
|
|
146
|
+
|
|
147
|
+
| Function | Status | Notes |
|
|
148
|
+
|----------|--------|-------|
|
|
149
|
+
| `Ref` | ✅ Supported | Resource physical IDs, Parameters, Pseudo parameters |
|
|
150
|
+
| `Fn::GetAtt` | ✅ Supported | Resource attributes (ARN, DomainName, etc.) |
|
|
151
|
+
| `Fn::Join` | ✅ Supported | String concatenation |
|
|
152
|
+
| `Fn::Sub` | ✅ Supported | Template string substitution |
|
|
153
|
+
| `Fn::Select` | ✅ Supported | Array index selection |
|
|
154
|
+
| `Fn::Split` | ✅ Supported | String splitting |
|
|
155
|
+
| `Fn::If` | ✅ Supported | Conditional values |
|
|
156
|
+
| `Fn::Equals` | ✅ Supported | Equality comparison |
|
|
157
|
+
| `Fn::And` | ✅ Supported | Logical AND (2-10 conditions) |
|
|
158
|
+
| `Fn::Or` | ✅ Supported | Logical OR (2-10 conditions) |
|
|
159
|
+
| `Fn::Not` | ✅ Supported | Logical NOT |
|
|
160
|
+
| `Fn::ImportValue` | ✅ Supported | Cross-stack references via S3 state |
|
|
161
|
+
| `Fn::FindInMap` | ✅ Supported | Mapping lookup |
|
|
162
|
+
| `Fn::GetAZs` | ✅ Supported | Availability Zone list |
|
|
163
|
+
| `Fn::Base64` | ✅ Supported | Base64 encoding |
|
|
164
|
+
| `Fn::Cidr` | ✅ Supported | CIDR address block generation |
|
|
165
|
+
|
|
166
|
+
### Pseudo Parameters
|
|
167
|
+
|
|
168
|
+
| Parameter | Status |
|
|
169
|
+
|-----------|--------|
|
|
170
|
+
| `AWS::Region` | ✅ |
|
|
171
|
+
| `AWS::AccountId` | ✅ (via STS) |
|
|
172
|
+
| `AWS::Partition` | ✅ |
|
|
173
|
+
| `AWS::URLSuffix` | ✅ |
|
|
174
|
+
| `AWS::NoValue` | ✅ |
|
|
175
|
+
| `AWS::StackName` | ✅ |
|
|
176
|
+
| `AWS::StackId` | ✅ |
|
|
177
|
+
|
|
178
|
+
### Resource Provisioning
|
|
179
|
+
|
|
180
|
+
| Category | Resource Type | Provider | Status |
|
|
181
|
+
|----------|--------------|----------|--------|
|
|
182
|
+
| **IAM** | AWS::IAM::Role | SDK Provider | ✅ |
|
|
183
|
+
| **IAM** | AWS::IAM::Policy | SDK Provider | ✅ |
|
|
184
|
+
| **IAM** | AWS::IAM::InstanceProfile | SDK Provider | ✅ |
|
|
185
|
+
| **IAM** | AWS::IAM::User | SDK Provider | ✅ |
|
|
186
|
+
| **IAM** | AWS::IAM::Group | SDK Provider | ✅ |
|
|
187
|
+
| **IAM** | AWS::IAM::UserToGroupAddition | SDK Provider | ✅ |
|
|
188
|
+
| **Storage** | AWS::S3::Bucket | SDK Provider | ✅ |
|
|
189
|
+
| **Storage** | AWS::S3::BucketPolicy | SDK Provider | ✅ |
|
|
190
|
+
| **Messaging** | AWS::SQS::Queue | SDK Provider | ✅ |
|
|
191
|
+
| **Messaging** | AWS::SQS::QueuePolicy | SDK Provider | ✅ |
|
|
192
|
+
| **Messaging** | AWS::SNS::Topic | SDK Provider | ✅ |
|
|
193
|
+
| **Messaging** | AWS::SNS::Subscription | SDK Provider | ✅ |
|
|
194
|
+
| **Messaging** | AWS::SNS::TopicPolicy | SDK Provider | ✅ |
|
|
195
|
+
| **Compute** | AWS::Lambda::Function | SDK Provider | ✅ |
|
|
196
|
+
| **Compute** | AWS::Lambda::Permission | SDK Provider | ✅ |
|
|
197
|
+
| **Compute** | AWS::Lambda::Url | SDK Provider | ✅ |
|
|
198
|
+
| **Compute** | AWS::Lambda::EventSourceMapping | SDK Provider | ✅ |
|
|
199
|
+
| **Compute** | AWS::Lambda::LayerVersion | SDK Provider | ✅ |
|
|
200
|
+
| **Database** | AWS::DynamoDB::Table | SDK Provider | ✅ |
|
|
201
|
+
| **Monitoring** | AWS::Logs::LogGroup | SDK Provider | ✅ |
|
|
202
|
+
| **Monitoring** | AWS::CloudWatch::Alarm | SDK Provider | ✅ |
|
|
203
|
+
| **Secrets** | AWS::SecretsManager::Secret | SDK Provider | ✅ |
|
|
204
|
+
| **Config** | AWS::SSM::Parameter | SDK Provider | ✅ |
|
|
205
|
+
| **Events** | AWS::Events::Rule | SDK Provider | ✅ |
|
|
206
|
+
| **Events** | AWS::Events::EventBus | SDK Provider | ✅ |
|
|
207
|
+
| **Networking** | AWS::EC2::VPC | SDK Provider | ✅ |
|
|
208
|
+
| **Networking** | AWS::EC2::Subnet | SDK Provider | ✅ |
|
|
209
|
+
| **Networking** | AWS::EC2::InternetGateway | SDK Provider | ✅ |
|
|
210
|
+
| **Networking** | AWS::EC2::VPCGatewayAttachment | SDK Provider | ✅ |
|
|
211
|
+
| **Networking** | AWS::EC2::RouteTable | SDK Provider | ✅ |
|
|
212
|
+
| **Networking** | AWS::EC2::Route | SDK Provider | ✅ |
|
|
213
|
+
| **Networking** | AWS::EC2::SubnetRouteTableAssociation | SDK Provider | ✅ |
|
|
214
|
+
| **Networking** | AWS::EC2::SecurityGroup | SDK Provider | ✅ |
|
|
215
|
+
| **Networking** | AWS::EC2::SecurityGroupIngress | SDK Provider | ✅ |
|
|
216
|
+
| **Networking** | AWS::EC2::NetworkAcl | SDK Provider | ✅ |
|
|
217
|
+
| **Networking** | AWS::EC2::NetworkAclEntry | SDK Provider | ✅ |
|
|
218
|
+
| **Networking** | AWS::EC2::SubnetNetworkAclAssociation | SDK Provider | ✅ |
|
|
219
|
+
| **Compute** | AWS::EC2::Instance | SDK Provider | ✅ |
|
|
220
|
+
| **API Gateway** | AWS::ApiGateway::Account | SDK Provider | ✅ |
|
|
221
|
+
| **API Gateway** | AWS::ApiGateway::Resource | SDK Provider | ✅ |
|
|
222
|
+
| **API Gateway** | AWS::ApiGateway::Deployment | SDK Provider | ✅ |
|
|
223
|
+
| **API Gateway** | AWS::ApiGateway::Stage | SDK Provider | ✅ |
|
|
224
|
+
| **API Gateway** | AWS::ApiGateway::Method | SDK Provider | ✅ |
|
|
225
|
+
| **API Gateway** | AWS::ApiGateway::Authorizer | SDK Provider | ✅ |
|
|
226
|
+
| **API Gateway** | AWS::ApiGatewayV2::Api | SDK Provider | ✅ |
|
|
227
|
+
| **API Gateway** | AWS::ApiGatewayV2::Stage | SDK Provider | ✅ |
|
|
228
|
+
| **API Gateway** | AWS::ApiGatewayV2::Integration | SDK Provider | ✅ |
|
|
229
|
+
| **API Gateway** | AWS::ApiGatewayV2::Route | SDK Provider | ✅ |
|
|
230
|
+
| **API Gateway** | AWS::ApiGatewayV2::Authorizer | SDK Provider | ✅ |
|
|
231
|
+
| **CDN** | AWS::CloudFront::CloudFrontOriginAccessIdentity | SDK Provider | ✅ |
|
|
232
|
+
| **CDN** | AWS::CloudFront::Distribution | SDK Provider | ✅ |
|
|
233
|
+
| **Orchestration** | AWS::StepFunctions::StateMachine | SDK Provider | ✅ |
|
|
234
|
+
| **Container** | AWS::ECS::Cluster | SDK Provider | ✅ |
|
|
235
|
+
| **Container** | AWS::ECS::TaskDefinition | SDK Provider | ✅ |
|
|
236
|
+
| **Container** | AWS::ECS::Service | SDK Provider | ✅ |
|
|
237
|
+
| **Load Balancing** | AWS::ElasticLoadBalancingV2::LoadBalancer | SDK Provider | ✅ |
|
|
238
|
+
| **Load Balancing** | AWS::ElasticLoadBalancingV2::TargetGroup | SDK Provider | ✅ |
|
|
239
|
+
| **Load Balancing** | AWS::ElasticLoadBalancingV2::Listener | SDK Provider | ✅ |
|
|
240
|
+
| **Database** | AWS::RDS::DBSubnetGroup | SDK Provider | ✅ |
|
|
241
|
+
| **Database** | AWS::RDS::DBCluster | SDK Provider | ✅ |
|
|
242
|
+
| **Database** | AWS::RDS::DBInstance | SDK Provider | ✅ |
|
|
243
|
+
| **DNS** | AWS::Route53::HostedZone | SDK Provider | ✅ |
|
|
244
|
+
| **DNS** | AWS::Route53::RecordSet | SDK Provider | ✅ |
|
|
245
|
+
| **Security** | AWS::WAFv2::WebACL | SDK Provider | ✅ |
|
|
246
|
+
| **Auth** | AWS::Cognito::UserPool | SDK Provider | ✅ |
|
|
247
|
+
| **Cache** | AWS::ElastiCache::CacheCluster | SDK Provider | ✅ |
|
|
248
|
+
| **Cache** | AWS::ElastiCache::SubnetGroup | SDK Provider | ✅ |
|
|
249
|
+
| **Discovery** | AWS::ServiceDiscovery::PrivateDnsNamespace | SDK Provider | ✅ |
|
|
250
|
+
| **Discovery** | AWS::ServiceDiscovery::Service | SDK Provider | ✅ |
|
|
251
|
+
| **GraphQL** | AWS::AppSync::GraphQLApi | SDK Provider | ✅ |
|
|
252
|
+
| **GraphQL** | AWS::AppSync::GraphQLSchema | SDK Provider | ✅ |
|
|
253
|
+
| **GraphQL** | AWS::AppSync::DataSource | SDK Provider | ✅ |
|
|
254
|
+
| **GraphQL** | AWS::AppSync::Resolver | SDK Provider | ✅ |
|
|
255
|
+
| **GraphQL** | AWS::AppSync::ApiKey | SDK Provider | ✅ |
|
|
256
|
+
| **Analytics** | AWS::Glue::Database | SDK Provider | ✅ |
|
|
257
|
+
| **Analytics** | AWS::Glue::Table | SDK Provider | ✅ |
|
|
258
|
+
| **Encryption** | AWS::KMS::Key | SDK Provider | ✅ |
|
|
259
|
+
| **Encryption** | AWS::KMS::Alias | SDK Provider | ✅ |
|
|
260
|
+
| **Streaming** | AWS::Kinesis::Stream | SDK Provider | ✅ |
|
|
261
|
+
| **Streaming** | AWS::KinesisFirehose::DeliveryStream | SDK Provider | ✅ |
|
|
262
|
+
| **Storage** | AWS::EFS::FileSystem | SDK Provider | ✅ |
|
|
263
|
+
| **Storage** | AWS::EFS::MountTarget | SDK Provider | ✅ |
|
|
264
|
+
| **Storage** | AWS::EFS::AccessPoint | SDK Provider | ✅ |
|
|
265
|
+
| **Storage** | AWS::S3Express::DirectoryBucket | SDK Provider | ✅ |
|
|
266
|
+
| **Storage** | AWS::S3Tables::TableBucket | SDK Provider | ✅ |
|
|
267
|
+
| **Storage** | AWS::S3Tables::Namespace | SDK Provider | ✅ |
|
|
268
|
+
| **Storage** | AWS::S3Tables::Table | SDK Provider | ✅ |
|
|
269
|
+
| **Storage** | AWS::S3Vectors::VectorBucket | SDK Provider | ✅ |
|
|
270
|
+
| **Audit** | AWS::CloudTrail::Trail | SDK Provider | ✅ |
|
|
271
|
+
| **CI/CD** | AWS::CodeBuild::Project | SDK Provider | ✅ |
|
|
272
|
+
| **AI/ML** | AWS::BedrockAgentCore::Runtime | SDK Provider | ✅ |
|
|
273
|
+
| **Custom** | Custom::* (Lambda/SNS-backed) | SDK Provider | ✅ |
|
|
274
|
+
| **Other** | All other resource types | Cloud Control | ✅ |
|
|
275
|
+
|
|
276
|
+
### Other Features
|
|
277
|
+
|
|
278
|
+
| Feature | Status | Notes |
|
|
279
|
+
|---------|--------|-------|
|
|
280
|
+
| CloudFormation Parameters | ✅ | Default values, type coercion |
|
|
281
|
+
| Conditions | ✅ | With logical operators |
|
|
282
|
+
| Cross-stack references | ✅ | Via `Fn::ImportValue` + S3 state |
|
|
283
|
+
| JSON Patch updates | ✅ | RFC 6902, minimal patches |
|
|
284
|
+
| Resource replacement detection | ✅ | 10+ resource types |
|
|
285
|
+
| Dynamic References | ✅ | `{{resolve:secretsmanager:...}}`, `{{resolve:ssm:...}}` |
|
|
286
|
+
| DELETE idempotency | ✅ | Not-found errors treated as success |
|
|
287
|
+
| Asset publishing (S3) | ✅ | Lambda code packages |
|
|
288
|
+
| Asset publishing (ECR) | ✅ | Self-implemented Docker image publishing |
|
|
289
|
+
| Custom Resources (SNS-backed) | ✅ | SNS Topic ServiceToken + S3 response |
|
|
290
|
+
| Custom Resources (CDK Provider) | ✅ | isCompleteHandler/onEventHandler async pattern detection |
|
|
291
|
+
| Rollback | ✅ | --no-rollback flag to skip |
|
|
292
|
+
| DeletionPolicy: Retain | ✅ | Skip deletion for retained resources |
|
|
293
|
+
| UpdateReplacePolicy: Retain | ✅ | Keep old resource on replacement |
|
|
294
|
+
| Implicit delete dependencies | ✅ | VPC/IGW/EventBus/Subnet/RouteTable ordering |
|
|
295
|
+
| Stack dependency resolution | ✅ | Auto-deploy dependency stacks, `-e` to skip |
|
|
296
|
+
| Multi-stack parallel deploy | ✅ | Independent stacks deployed in parallel |
|
|
297
|
+
| Attribute enrichment | ✅ | CloudFront OAI, DynamoDB StreamArn, API Gateway RootResourceId, Lambda FunctionUrl, Route53 HealthCheckId, ECR Repository Arn |
|
|
298
|
+
| CC API null value stripping | ✅ | Removes null values before API calls |
|
|
299
|
+
| Retry with HTTP status codes | ✅ | 429/503 + cause chain inspection |
|
|
300
|
+
|
|
301
|
+
## Prerequisites
|
|
302
|
+
|
|
303
|
+
- **Node.js** >= 20.0.0
|
|
304
|
+
- **AWS CDK Bootstrap**: You must run `cdk bootstrap` before using cdkd. cdkd uses CDK's bootstrap bucket (`cdk-hnb659fds-assets-*`) for asset uploads (Lambda code, Docker images). Custom bootstrap qualifiers are supported — CDK embeds the correct bucket/repo names in the asset manifest during synthesis.
|
|
305
|
+
- **AWS Credentials**: Configured via environment variables, `~/.aws/credentials`, or `--profile` option
|
|
306
|
+
|
|
307
|
+
## Installation
|
|
308
|
+
|
|
309
|
+
### From npm (experimental)
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
npm i -g @go-to-k/cdkd@experimental # latest experimental
|
|
313
|
+
npm i -g @go-to-k/cdkd@0.1.0 # pin to a specific version
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The installed binary is `cdkd` — run it the same way in either install path.
|
|
317
|
+
|
|
318
|
+
> Published under the `experimental` dist-tag while the project is in early development. There is no `latest` tag yet — always pin to `@experimental` (or a specific version) so `npm i -g @go-to-k/cdkd` does not silently resolve to a future stable release with different behavior.
|
|
319
|
+
|
|
320
|
+
### From source
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
git clone https://github.com/go-to-k/cdkd.git
|
|
324
|
+
cd cdkd
|
|
325
|
+
pnpm install
|
|
326
|
+
pnpm run build
|
|
327
|
+
npm link
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
If `cdkd` is not found after `npm link`, set an alias in the current shell:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
alias cdkd="node $(pwd)/dist/cli.js"
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Quick Start
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Bootstrap (creates S3 state bucket - only needed once per account/region)
|
|
340
|
+
cdkd bootstrap
|
|
341
|
+
|
|
342
|
+
# Deploy your CDK app
|
|
343
|
+
cdkd deploy
|
|
344
|
+
|
|
345
|
+
# Check what would change
|
|
346
|
+
cdkd diff
|
|
347
|
+
|
|
348
|
+
# Tear down
|
|
349
|
+
cdkd destroy
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
That's it. cdkd reads `--app` from `cdk.json` and auto-resolves the state bucket from your AWS account ID (`cdkd-state-{accountId}-{region}`).
|
|
353
|
+
|
|
354
|
+
## Usage
|
|
355
|
+
|
|
356
|
+
Options like `--app`, `--state-bucket`, and `--context` can be omitted if configured via `cdk.json` or environment variables (`CDKD_APP`, `CDKD_STATE_BUCKET`).
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Bootstrap (create S3 bucket for state)
|
|
360
|
+
cdkd bootstrap \
|
|
361
|
+
--state-bucket my-cdkd-state \
|
|
362
|
+
--region us-east-1
|
|
363
|
+
|
|
364
|
+
# Synthesize only
|
|
365
|
+
cdkd synth --app "npx ts-node app.ts"
|
|
366
|
+
|
|
367
|
+
# Deploy (single stack auto-detected, reads --app from cdk.json)
|
|
368
|
+
cdkd deploy
|
|
369
|
+
|
|
370
|
+
# Deploy specific stack(s)
|
|
371
|
+
cdkd deploy MyStack
|
|
372
|
+
cdkd deploy Stack1 Stack2
|
|
373
|
+
|
|
374
|
+
# Deploy all stacks
|
|
375
|
+
cdkd deploy --all
|
|
376
|
+
|
|
377
|
+
# Deploy with wildcard
|
|
378
|
+
cdkd deploy 'My*'
|
|
379
|
+
|
|
380
|
+
# Deploy with context values
|
|
381
|
+
cdkd deploy -c env=staging -c featureFlag=true
|
|
382
|
+
|
|
383
|
+
# Deploy with explicit options
|
|
384
|
+
cdkd deploy MyStack \
|
|
385
|
+
--app "npx ts-node app.ts" \
|
|
386
|
+
--state-bucket my-cdkd-state \
|
|
387
|
+
--region us-east-1 \
|
|
388
|
+
--verbose
|
|
389
|
+
|
|
390
|
+
# Show diff (what would change)
|
|
391
|
+
cdkd diff MyStack
|
|
392
|
+
|
|
393
|
+
# Dry run (plan only, no changes)
|
|
394
|
+
cdkd deploy --dry-run
|
|
395
|
+
|
|
396
|
+
# Deploy with no rollback on failure (Terraform-style)
|
|
397
|
+
cdkd deploy --no-rollback
|
|
398
|
+
|
|
399
|
+
# Deploy only the specified stack (skip dependency auto-inclusion)
|
|
400
|
+
cdkd deploy -e MyStack
|
|
401
|
+
|
|
402
|
+
# Destroy resources
|
|
403
|
+
cdkd destroy MyStack
|
|
404
|
+
cdkd destroy --all --force
|
|
405
|
+
|
|
406
|
+
# Force-unlock a stale lock from interrupted deploy
|
|
407
|
+
cdkd force-unlock MyStack
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Concurrency Options
|
|
411
|
+
|
|
412
|
+
| Option | Default | Description |
|
|
413
|
+
| --- | --- | --- |
|
|
414
|
+
| `--concurrency` | 10 | Maximum concurrent resource operations per stack |
|
|
415
|
+
| `--stack-concurrency` | 4 | Maximum concurrent stack deployments |
|
|
416
|
+
| `--asset-publish-concurrency` | 8 | Maximum concurrent asset publish operations (S3 + ECR push) |
|
|
417
|
+
| `--image-build-concurrency` | 4 | Maximum concurrent Docker image builds |
|
|
418
|
+
|
|
419
|
+
## `--no-wait`
|
|
420
|
+
|
|
421
|
+
By default, cdkd waits for async resources (CloudFront Distribution, RDS Cluster/Instance, ElastiCache) to reach a ready state before completing — the same behavior as CloudFormation.
|
|
422
|
+
|
|
423
|
+
Use `--no-wait` to skip this and return immediately after resource creation:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
cdkd deploy --no-wait
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
This can significantly speed up deployments with CloudFront (which takes 3-15 minutes to deploy to edge locations). The resource is fully functional once AWS finishes the async deployment.
|
|
430
|
+
|
|
431
|
+
## Example
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
const table = new dynamodb.Table(stack, 'Table', {
|
|
435
|
+
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
|
|
436
|
+
});
|
|
437
|
+
const fn = new lambda.Function(stack, 'Handler', {
|
|
438
|
+
runtime: lambda.Runtime.NODEJS_20_X,
|
|
439
|
+
handler: 'index.handler',
|
|
440
|
+
code: lambda.Code.fromAsset('lambda'),
|
|
441
|
+
environment: { TABLE_NAME: table.tableName },
|
|
442
|
+
});
|
|
443
|
+
table.grantReadWriteData(fn);
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
$ cdkd deploy
|
|
448
|
+
LambdaStack
|
|
449
|
+
ServiceRole CREATE AWS::IAM::Role ✓ (2.1s)
|
|
450
|
+
Table CREATE AWS::DynamoDB::Table ✓ (1.8s)
|
|
451
|
+
DefaultPolicy CREATE AWS::IAM::Policy ✓ (1.5s)
|
|
452
|
+
Handler CREATE AWS::Lambda::Function ✓ (3.4s)
|
|
453
|
+
|
|
454
|
+
✓ Deployed LambdaStack (4 resources, 7.2s)
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Resources without dependencies (ServiceRole and Table) are created in parallel.
|
|
458
|
+
|
|
459
|
+
## Architecture
|
|
460
|
+
|
|
461
|
+
Built on modern AWS tooling:
|
|
462
|
+
|
|
463
|
+
- **Synthesis orchestration** - Executes CDK app as subprocess (synthesis itself is done by aws-cdk-lib), parses Cloud Assembly (manifest.json) directly, context provider loop (missing context → SDK lookup → re-synthesize)
|
|
464
|
+
- **Self-implemented asset publisher** - S3 file upload with ZIP packaging (via `archiver`) and ECR Docker image publishing
|
|
465
|
+
- **AWS SDK v3** - Direct resource provisioning
|
|
466
|
+
- **Cloud Control API** - Fallback resource management for types without SDK Providers
|
|
467
|
+
- **S3 Conditional Writes** - State locking via `If-None-Match`/`If-Match`
|
|
468
|
+
|
|
469
|
+
## State Management
|
|
470
|
+
|
|
471
|
+
State is stored in S3. Each stack has its own `state.json` and `lock.json`:
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
s3://{state-bucket}/
|
|
475
|
+
└── {prefix}/ # Default: "cdkd" (configurable via --state-prefix)
|
|
476
|
+
├── MyStack/
|
|
477
|
+
│ ├── state.json # Resource state
|
|
478
|
+
│ └── lock.json # Exclusive deploy lock
|
|
479
|
+
└── AnotherStack/
|
|
480
|
+
├── state.json
|
|
481
|
+
└── lock.json
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Configuration
|
|
485
|
+
|
|
486
|
+
| Setting | CLI | cdk.json | Env var | Default |
|
|
487
|
+
|---------|-----|----------|---------|---------|
|
|
488
|
+
| Bucket | `--state-bucket` | `context.cdkd.stateBucket` | `CDKD_STATE_BUCKET` | `cdkd-state-{accountId}-{region}` |
|
|
489
|
+
| Prefix | `--state-prefix` | - | - | `cdkd` |
|
|
490
|
+
|
|
491
|
+
### Multi-app isolation
|
|
492
|
+
|
|
493
|
+
The state bucket is shared across all CDK apps in the same account/region by default. To isolate apps, use different prefixes:
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
# App A
|
|
497
|
+
cdkd deploy --state-prefix app-a
|
|
498
|
+
|
|
499
|
+
# App B
|
|
500
|
+
cdkd deploy --state-prefix app-b
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
> **Note**: `cdkd destroy --all` only targets stacks from the current CDK app (determined by synthesis), not all stacks in the bucket.
|
|
504
|
+
|
|
505
|
+
State schema:
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
{
|
|
509
|
+
version: 1,
|
|
510
|
+
stackName: "MyStack",
|
|
511
|
+
resources: {
|
|
512
|
+
"MyFunction": {
|
|
513
|
+
physicalId: "arn:aws:lambda:...",
|
|
514
|
+
resourceType: "AWS::Lambda::Function",
|
|
515
|
+
properties: { ... },
|
|
516
|
+
attributes: { Arn: "...", ... }, // For Fn::GetAtt
|
|
517
|
+
dependencies: ["MyBucket"] // For proper deletion order
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
outputs: { ... },
|
|
521
|
+
lastModified: 1234567890
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Stack Outputs
|
|
526
|
+
|
|
527
|
+
CDK's `CfnOutput` constructs are resolved and stored in the state file:
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
// In your CDK code
|
|
531
|
+
new cdk.CfnOutput(this, 'BucketArn', {
|
|
532
|
+
value: bucket.bucketArn, // Uses Fn::GetAtt internally
|
|
533
|
+
description: 'ARN of the bucket',
|
|
534
|
+
});
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
After deployment, outputs are resolved and saved to the S3 state file:
|
|
538
|
+
|
|
539
|
+
```json
|
|
540
|
+
{
|
|
541
|
+
"outputs": {
|
|
542
|
+
"BucketArn": "arn:aws:s3:::actual-bucket-name-xyz"
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**Key differences from CloudFormation**:
|
|
548
|
+
|
|
549
|
+
- CloudFormation: Outputs accessible via `aws cloudformation describe-stacks`
|
|
550
|
+
- cdkd: Outputs saved in S3 state file (e.g., `s3://bucket/cdkd/MyStack/state.json`)
|
|
551
|
+
- Both resolve intrinsic functions (Ref, Fn::GetAtt, etc.) to actual values
|
|
552
|
+
|
|
553
|
+
## Testing
|
|
554
|
+
|
|
555
|
+
- Unit tests covering all layers
|
|
556
|
+
- Integration examples verified with real AWS deployments (see `tests/integration/`)
|
|
557
|
+
- E2E test script for automated deploy/diff/update/destroy cycles
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
pnpm test # Run unit tests
|
|
561
|
+
pnpm run test:coverage # With coverage report
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
See [docs/testing.md](docs/testing.md) for integration and E2E testing instructions.
|
|
565
|
+
|
|
566
|
+
## License
|
|
567
|
+
|
|
568
|
+
Apache 2.0
|