@go-to-k/cdkd 0.247.0 → 0.248.0

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/README.md CHANGED
@@ -4,15 +4,14 @@
4
4
  [![Downloads](https://img.shields.io/npm/dw/@go-to-k/cdkd.svg)](https://www.npmjs.com/package/@go-to-k/cdkd)
5
5
  [![License: Apache-2.0](https://img.shields.io/npm/l/@go-to-k/cdkd.svg)](./LICENSE)
6
6
 
7
- Drop-in CDK CLI for existing CDK apps: up to 15x faster deploys via AWS SDK instead of CloudFormation.
7
+ Drop-in CDK CLI for existing CDK apps up to 15x faster deploys via direct AWS SDK calls instead of CloudFormation.
8
8
 
9
9
  - **Drop-in CDK compatible**: your existing CDK app code runs as-is.
10
10
  - **Up to 15x faster deploys**: direct SDK calls, aggressive parallelization, and `--no-wait` to skip slow stabilization waits.
11
- - **Local execution**: run your functions and APIs locally, with env vars, secrets, and resource references resolved from your deployed stack instead of hand-written `.env` files.
12
11
 
13
12
  ![cdk deploy vs cdkd deploy — side-by-side, 35s recording, real AWS deploy. cdkd finishes while cdk is still creating its CloudFormation changeset.](assets/cdk-vs-cdkd.gif)
14
13
 
15
- **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and SAM-style local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Install cdkd alongside an existing `cdk deploy` workflow no migration needed, `cdkd local *` reads deployed state directly via `--from-cfn-stack`. Bidirectional migration is also supported [import](#importing-existing-resources) into cdkd or [export](#exporting-a-stack-back-to-cloudformation) back to CloudFormation when ready.
14
+ **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Install cdkd alongside an existing `cdk deploy` workflow: no migration needed. Bidirectional migration is also supported: [import](#importing-existing-resources) into cdkd or [export](#exporting-a-stack-back-to-cloudformation) back to CloudFormation when ready.
16
15
 
17
16
  **A natural fit for AI-driven development.** AI coding agents iterate in tight spin-up / tear-down loops — and cdkd keeps each turn short, with fast deploys and an equally fast `cdkd destroy` that deletes via direct SDK calls instead of polling a CloudFormation stack-delete.
18
17
 
@@ -139,13 +138,14 @@ parsing → synthesis → asset publishing → per-stack deploy), see
139
138
  ## Prerequisites
140
139
 
141
140
  - **Node.js** >= 20.0.0
142
- - **AWS CDK Bootstrap: not required.** `cdkd bootstrap` (once per account) creates
143
- everything cdkd needs, and per-region asset storage is added automatically on the
144
- first `cdkd deploy` into each region. Existing setups, legacy-mode opt-outs, and
145
- how this relates to `cdk bootstrap`: see
146
- [Upgrading from an earlier cdkd version](#upgrading-from-an-earlier-cdkd-version).
147
141
  - **AWS credentials with admin-equivalent permissions** for the resources being deployed. cdkd does NOT route through CloudFormation, so CDK CLI's `cdk-hnb659fds-deploy-role-*` is NOT sufficient — see [`--role-arn`](docs/cli-reference.md).
148
142
 
143
+ AWS CDK's `cdk bootstrap` is not required. Instead, run `cdkd bootstrap` once per
144
+ account: it creates everything cdkd needs, and per-region asset storage is added
145
+ automatically on the first `cdkd deploy` into each region. Existing setups,
146
+ legacy-mode opt-outs, and how this relates to `cdk bootstrap`: see
147
+ [Upgrading from an earlier cdkd version](#upgrading-from-an-earlier-cdkd-version).
148
+
149
149
  ## Installation
150
150
 
151
151
  ```bash
package/dist/cli.js CHANGED
@@ -60,7 +60,7 @@ import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPer
60
60
  import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ResourceNotFoundException as ResourceNotFoundException$9, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
61
61
  import { AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, PutBackupPolicyCommand, PutFileSystemPolicyCommand, PutLifecycleConfigurationCommand, UpdateFileSystemCommand, UpdateFileSystemProtectionCommand } from "@aws-sdk/client-efs";
62
62
  import { CreateFileSystemCommand as CreateFileSystemCommand$1, CreateFileSystemFromBackupCommand, DeleteFileSystemCommand as DeleteFileSystemCommand$1, DescribeFileSystemsCommand as DescribeFileSystemsCommand$1, FSxClient, FileSystemNotFound as FileSystemNotFound$1, TagResourceCommand as TagResourceCommand$18, UntagResourceCommand as UntagResourceCommand$18, UpdateFileSystemCommand as UpdateFileSystemCommand$1 } from "@aws-sdk/client-fsx";
63
- import { AddTagsCommand as AddTagsCommand$1, DescribeClusterCommand, EMRClient, InvalidRequestException, ModifyClusterCommand, PutAutoTerminationPolicyCommand, PutManagedScalingPolicyCommand, RemoveAutoTerminationPolicyCommand, RemoveManagedScalingPolicyCommand, RemoveTagsCommand as RemoveTagsCommand$1, RunJobFlowCommand, SetTerminationProtectionCommand, SetVisibleToAllUsersCommand, TerminateJobFlowsCommand } from "@aws-sdk/client-emr";
63
+ import { AddTagsCommand as AddTagsCommand$1, DescribeClusterCommand, EMRClient, InvalidRequestException, ListClustersCommand as ListClustersCommand$1, ListInstanceFleetsCommand, ListInstanceGroupsCommand, ModifyClusterCommand, PutAutoTerminationPolicyCommand, PutManagedScalingPolicyCommand, RemoveAutoTerminationPolicyCommand, RemoveManagedScalingPolicyCommand, RemoveTagsCommand as RemoveTagsCommand$1, RunJobFlowCommand, SetTerminationProtectionCommand, SetVisibleToAllUsersCommand, TerminateJobFlowsCommand } from "@aws-sdk/client-emr";
64
64
  import { CreateDeliveryStreamCommand, DeleteDeliveryStreamCommand, DescribeDeliveryStreamCommand, FirehoseClient, ListDeliveryStreamsCommand, ListTagsForDeliveryStreamCommand, ResourceNotFoundException as ResourceNotFoundException$10, TagDeliveryStreamCommand, UntagDeliveryStreamCommand, UpdateDestinationCommand } from "@aws-sdk/client-firehose";
65
65
  import { AddTagsCommand as AddTagsCommand$2, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$1, ListTrailsCommand, PutEventSelectorsCommand, PutInsightSelectorsCommand, RemoveTagsCommand as RemoveTagsCommand$2, StartLoggingCommand, StopLoggingCommand, TrailNotFoundException, UpdateTrailCommand } from "@aws-sdk/client-cloudtrail";
66
66
  import { BatchGetProjectsCommand, CodeBuildClient, CreateProjectCommand, DeleteProjectCommand, ListProjectsCommand, ResourceNotFoundException as ResourceNotFoundException$11, UpdateProjectCommand } from "@aws-sdk/client-codebuild";
@@ -1891,7 +1891,7 @@ const FLUSH_INTERVAL_MS = 2e3;
1891
1891
  const FLUSH_EVENT_THRESHOLD = 50;
1892
1892
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
1893
1893
  function getCdkdVersion() {
1894
- return "0.247.0";
1894
+ return "0.248.0";
1895
1895
  }
1896
1896
  /**
1897
1897
  * Generate a time-sortable unique run id, e.g.
@@ -35021,6 +35021,18 @@ const CREATE_READY_STATES = new Set(["WAITING", "RUNNING"]);
35021
35021
  */
35022
35022
  const TERMINAL_STATES = new Set(["TERMINATED", "TERMINATED_WITH_ERRORS"]);
35023
35023
  /**
35024
+ * Cluster states that mean "the cluster is alive" — the `ListClusters` filter
35025
+ * used by `import()` discovery so a long-gone `TERMINATED*` cluster is never
35026
+ * adopted. Everything except the two `TERMINAL_STATES`.
35027
+ */
35028
+ const NON_TERMINATED_STATES = [
35029
+ "STARTING",
35030
+ "BOOTSTRAPPING",
35031
+ "RUNNING",
35032
+ "WAITING",
35033
+ "TERMINATING"
35034
+ ];
35035
+ /**
35024
35036
  * Top-level CFn properties that map to a MUTABLE EMR API surface. Every other
35025
35037
  * property is either registry-createOnly (routed through DELETE+CREATE by the
35026
35038
  * replacement-detection layer) or lives inside the `Instances` block (handled
@@ -35520,6 +35532,279 @@ var EMRClusterProvider = class {
35520
35532
  default: return;
35521
35533
  }
35522
35534
  }
35535
+ /**
35536
+ * Adopt an existing EMR cluster into cdkd state.
35537
+ *
35538
+ * Lookup order:
35539
+ * 1. `--resource <logicalId>=j-XXXX` override (`knownPhysicalId`) → verify
35540
+ * via `DescribeCluster`. There is no template name property that equals
35541
+ * the physical id — a cluster's id (`j-...`) is service-generated, while
35542
+ * the template `Name` is only the display name — so no name fallback
35543
+ * applies (`resolveExplicitPhysicalId(..., null)`).
35544
+ * 2. Tag-based lookup: `ListClusters` filtered to the non-terminated states
35545
+ * (a `TERMINATED*` cluster is gone and must never be adopted), then a
35546
+ * `DescribeCluster` per candidate to read `Tags` (the list summaries do
35547
+ * NOT carry tags) and match `aws:cdk:path`.
35548
+ */
35549
+ async import(input) {
35550
+ const explicit = resolveExplicitPhysicalId(input, null);
35551
+ if (explicit) {
35552
+ const cluster = await this.describeClusterOrNull(explicit);
35553
+ if (!cluster || cluster.Status?.State && TERMINAL_STATES.has(cluster.Status.State)) return null;
35554
+ return {
35555
+ physicalId: explicit,
35556
+ attributes: this.buildAttributes(cluster)
35557
+ };
35558
+ }
35559
+ if (!input.cdkPath) return null;
35560
+ let marker;
35561
+ do {
35562
+ const list = await this.getClient().send(new ListClustersCommand$1({
35563
+ ClusterStates: [...NON_TERMINATED_STATES],
35564
+ ...marker && { Marker: marker }
35565
+ }));
35566
+ for (const summary of list.Clusters ?? []) {
35567
+ if (!summary.Id) continue;
35568
+ const cluster = await this.describeClusterOrNull(summary.Id);
35569
+ if (!cluster) continue;
35570
+ if (matchesCdkPath(cluster.Tags, input.cdkPath)) return {
35571
+ physicalId: summary.Id,
35572
+ attributes: this.buildAttributes(cluster)
35573
+ };
35574
+ }
35575
+ marker = list.Marker;
35576
+ } while (marker);
35577
+ return null;
35578
+ }
35579
+ /**
35580
+ * `DescribeCluster` that maps a not-found (`InvalidRequestException` — the
35581
+ * cluster id is unknown in this region / aged out of Describe) to `null`
35582
+ * instead of throwing, so `import()` can treat it as "no match" rather than
35583
+ * aborting the whole adoption run.
35584
+ */
35585
+ async describeClusterOrNull(clusterId) {
35586
+ try {
35587
+ return (await this.getClient().send(new DescribeClusterCommand({ ClusterId: clusterId }))).Cluster;
35588
+ } catch (err) {
35589
+ if (err instanceof InvalidRequestException) return void 0;
35590
+ throw err;
35591
+ }
35592
+ }
35593
+ /**
35594
+ * Read the currently-deployed properties for `cdkd drift` and to seed the
35595
+ * `observedProperties` baseline right after `cdkd import`.
35596
+ *
35597
+ * The bulk of the work is reversing the flatten that `create()` applies to
35598
+ * the CFn `Instances` block: `DescribeCluster` reports the cluster's
35599
+ * `InstanceCollectionType`, and the instance groups / fleets themselves come
35600
+ * from `ListInstanceGroups` / `ListInstanceFleets` as FLAT arrays with a
35601
+ * per-entry `InstanceGroupType` / `InstanceFleetType` discriminator — the
35602
+ * exact inverse of the role-keyed CFn `MasterInstanceGroup` /
35603
+ * `CoreInstanceGroup` / `TaskInstanceGroups` (+ `*InstanceFleet(s)`) shape.
35604
+ * `reverseInstancesToCfn` re-buckets them and folds in the flat
35605
+ * `Ec2InstanceAttributes` (subnet / key name / security groups).
35606
+ *
35607
+ * Scope: the reversible property set — the reverse-mapped `Instances` block,
35608
+ * `Tags` (via `normalizeAwsTagsToCfn`, `aws:*` stripped), and the top-level
35609
+ * scalar fields `DescribeCluster` returns directly. Create-only sub-config
35610
+ * that AWS does not read back faithfully (`ManagedScalingPolicy` /
35611
+ * `AutoTerminationPolicy` — separate Get* APIs; `BootstrapActions` / `Steps`
35612
+ * / `KerberosAttributes` / `Configurations` nesting / `AdditionalInfo` /
35613
+ * `PlacementGroupConfigs`; `Instances` EBS / auto-scaling sub-specs) is
35614
+ * declared in `getDriftUnknownPaths` so the drift comparator skips it on the
35615
+ * `properties`-fallback path instead of firing a guaranteed false positive.
35616
+ * On the normal path the baseline is `observedProperties` (captured via this
35617
+ * same method), so observed == current and there is no phantom drift.
35618
+ *
35619
+ * Returns `undefined` when the cluster is gone (`InvalidRequestException`)
35620
+ * so the caller reports drift-unknown rather than throwing — mirrors the
35621
+ * optional `import` method's incremental opt-in shape.
35622
+ */
35623
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
35624
+ const cluster = await this.describeClusterOrNull(physicalId);
35625
+ if (!cluster) return void 0;
35626
+ let instanceGroups = [];
35627
+ let instanceFleets = [];
35628
+ if (cluster.InstanceCollectionType === "INSTANCE_FLEET") instanceFleets = await this.listInstanceFleets(physicalId);
35629
+ else instanceGroups = await this.listInstanceGroups(physicalId);
35630
+ return {
35631
+ Name: cluster.Name ?? "",
35632
+ ReleaseLabel: cluster.ReleaseLabel ?? "",
35633
+ ServiceRole: cluster.ServiceRole ?? "",
35634
+ LogUri: cluster.LogUri ?? "",
35635
+ LogEncryptionKmsKeyId: cluster.LogEncryptionKmsKeyId ?? "",
35636
+ AutoScalingRole: cluster.AutoScalingRole ?? "",
35637
+ ScaleDownBehavior: cluster.ScaleDownBehavior ?? "",
35638
+ CustomAmiId: cluster.CustomAmiId ?? "",
35639
+ OSReleaseLabel: cluster.OSReleaseLabel ?? "",
35640
+ SecurityConfiguration: cluster.SecurityConfiguration ?? "",
35641
+ EbsRootVolumeSize: cluster.EbsRootVolumeSize,
35642
+ EbsRootVolumeIops: cluster.EbsRootVolumeIops,
35643
+ EbsRootVolumeThroughput: cluster.EbsRootVolumeThroughput,
35644
+ StepConcurrencyLevel: cluster.StepConcurrencyLevel,
35645
+ VisibleToAllUsers: cluster.VisibleToAllUsers ?? false,
35646
+ JobFlowRole: cluster.Ec2InstanceAttributes?.IamInstanceProfile ?? "",
35647
+ Applications: cluster.Applications ?? [],
35648
+ Tags: normalizeAwsTagsToCfn(cluster.Tags),
35649
+ Instances: this.reverseInstancesToCfn(cluster, instanceGroups, instanceFleets)
35650
+ };
35651
+ }
35652
+ /**
35653
+ * State property paths this provider cannot read back from AWS faithfully,
35654
+ * skipped by the drift comparator to avoid a guaranteed false positive on
35655
+ * the `properties`-fallback path. See `readCurrentState`'s docstring.
35656
+ *
35657
+ * NOTE on the `Instances.*` entries: `reverseInstancesToCfn` deliberately
35658
+ * reconstructs only the primary topology per group / fleet (role, type,
35659
+ * count / capacity, market, bid price, name, custom AMI) — the lossy
35660
+ * sub-specs `create()` reads (`EbsConfiguration` / `AutoScalingPolicy` /
35661
+ * per-group `Configurations`; per-fleet `InstanceTypeConfigs` /
35662
+ * `LaunchSpecifications` / `ResizeSpecifications`) and the top-level
35663
+ * `Instances` fields AWS does not report back (`HadoopVersion` /
35664
+ * `Placement` / `KeepJobFlowAliveWhenNoSteps`) are NOT reconstructed. On the
35665
+ * NORMAL drift path both the `observedProperties` baseline and the current
35666
+ * snapshot go through this same lossy reverse, so these paths are absent
35667
+ * from both sides and never drift — ignoring them there is a no-op. On the
35668
+ * `properties`-fallback path (no `observedProperties`) the baseline is the
35669
+ * full template `Instances`, which DOES carry these sub-fields, so without
35670
+ * the skip every one would fire guaranteed false-positive drift. The two
35671
+ * `Task*` arrays are ignored WHOLE (the comparator compares arrays as leaves,
35672
+ * so an element sub-field cannot be path-targeted); Master/Core groups and
35673
+ * fleets are single objects, so their lossy sub-fields are targeted directly.
35674
+ */
35675
+ getDriftUnknownPaths(_resourceType) {
35676
+ return [
35677
+ "AdditionalInfo",
35678
+ "Applications",
35679
+ "AutoTerminationPolicy",
35680
+ "BootstrapActions",
35681
+ "Configurations",
35682
+ "Instances.HadoopVersion",
35683
+ "Instances.KeepJobFlowAliveWhenNoSteps",
35684
+ "Instances.Placement",
35685
+ "Instances.CoreInstanceGroup.AutoScalingPolicy",
35686
+ "Instances.CoreInstanceGroup.Configurations",
35687
+ "Instances.CoreInstanceGroup.EbsConfiguration",
35688
+ "Instances.MasterInstanceGroup.AutoScalingPolicy",
35689
+ "Instances.MasterInstanceGroup.Configurations",
35690
+ "Instances.MasterInstanceGroup.EbsConfiguration",
35691
+ "Instances.CoreInstanceFleet.InstanceTypeConfigs",
35692
+ "Instances.CoreInstanceFleet.LaunchSpecifications",
35693
+ "Instances.CoreInstanceFleet.ResizeSpecifications",
35694
+ "Instances.MasterInstanceFleet.InstanceTypeConfigs",
35695
+ "Instances.MasterInstanceFleet.LaunchSpecifications",
35696
+ "Instances.MasterInstanceFleet.ResizeSpecifications",
35697
+ "Instances.TaskInstanceFleets",
35698
+ "Instances.TaskInstanceGroups",
35699
+ "KerberosAttributes",
35700
+ "ManagedScalingPolicy",
35701
+ "PlacementGroupConfigs",
35702
+ "Steps"
35703
+ ];
35704
+ }
35705
+ async listInstanceGroups(clusterId) {
35706
+ const groups = [];
35707
+ let marker;
35708
+ do {
35709
+ const resp = await this.getClient().send(new ListInstanceGroupsCommand({
35710
+ ClusterId: clusterId,
35711
+ ...marker && { Marker: marker }
35712
+ }));
35713
+ groups.push(...resp.InstanceGroups ?? []);
35714
+ marker = resp.Marker;
35715
+ } while (marker);
35716
+ return groups;
35717
+ }
35718
+ async listInstanceFleets(clusterId) {
35719
+ const fleets = [];
35720
+ let marker;
35721
+ do {
35722
+ const resp = await this.getClient().send(new ListInstanceFleetsCommand({
35723
+ ClusterId: clusterId,
35724
+ ...marker && { Marker: marker }
35725
+ }));
35726
+ fleets.push(...resp.InstanceFleets ?? []);
35727
+ marker = resp.Marker;
35728
+ } while (marker);
35729
+ return fleets;
35730
+ }
35731
+ /**
35732
+ * Reverse of `toJobFlowInstancesConfig` — re-bucket the flat SDK
35733
+ * `InstanceGroup[]` / `InstanceFleet[]` (each carrying a role discriminator)
35734
+ * back into the role-keyed CFn `Instances` shape, and fold in the flat
35735
+ * `Ec2InstanceAttributes` (subnet / key name / security groups).
35736
+ *
35737
+ * Only the primary topology fields per group / fleet are reversed (role,
35738
+ * type, count / capacity, market, bid price, name, custom AMI). Lossy
35739
+ * sub-specs (EBS block-device / auto-scaling for groups; per-instance-type
35740
+ * specs for fleets) are intentionally NOT reconstructed — they are covered
35741
+ * by the drift baseline being `observedProperties` on the normal path.
35742
+ */
35743
+ reverseInstancesToCfn(cluster, instanceGroups, instanceFleets) {
35744
+ const ec2 = cluster.Ec2InstanceAttributes;
35745
+ const instances = {};
35746
+ const taskGroups = [];
35747
+ for (const g of instanceGroups) {
35748
+ const cfn = this.reverseInstanceGroup(g);
35749
+ switch (g.InstanceGroupType) {
35750
+ case "MASTER":
35751
+ instances["MasterInstanceGroup"] = cfn;
35752
+ break;
35753
+ case "CORE":
35754
+ instances["CoreInstanceGroup"] = cfn;
35755
+ break;
35756
+ case "TASK":
35757
+ taskGroups.push(cfn);
35758
+ break;
35759
+ }
35760
+ }
35761
+ if (taskGroups.length > 0) instances["TaskInstanceGroups"] = taskGroups;
35762
+ const taskFleets = [];
35763
+ for (const f of instanceFleets) {
35764
+ const cfn = this.reverseInstanceFleet(f);
35765
+ switch (f.InstanceFleetType) {
35766
+ case "MASTER":
35767
+ instances["MasterInstanceFleet"] = cfn;
35768
+ break;
35769
+ case "CORE":
35770
+ instances["CoreInstanceFleet"] = cfn;
35771
+ break;
35772
+ case "TASK":
35773
+ taskFleets.push(cfn);
35774
+ break;
35775
+ }
35776
+ }
35777
+ if (taskFleets.length > 0) instances["TaskInstanceFleets"] = taskFleets;
35778
+ if (ec2?.Ec2KeyName !== void 0) instances["Ec2KeyName"] = ec2.Ec2KeyName;
35779
+ if (ec2?.Ec2SubnetId !== void 0) instances["Ec2SubnetId"] = ec2.Ec2SubnetId;
35780
+ if (ec2?.RequestedEc2SubnetIds !== void 0) instances["Ec2SubnetIds"] = ec2.RequestedEc2SubnetIds;
35781
+ if (ec2?.EmrManagedMasterSecurityGroup !== void 0) instances["EmrManagedMasterSecurityGroup"] = ec2.EmrManagedMasterSecurityGroup;
35782
+ if (ec2?.EmrManagedSlaveSecurityGroup !== void 0) instances["EmrManagedSlaveSecurityGroup"] = ec2.EmrManagedSlaveSecurityGroup;
35783
+ if (ec2?.ServiceAccessSecurityGroup !== void 0) instances["ServiceAccessSecurityGroup"] = ec2.ServiceAccessSecurityGroup;
35784
+ if (ec2?.AdditionalMasterSecurityGroups !== void 0) instances["AdditionalMasterSecurityGroups"] = ec2.AdditionalMasterSecurityGroups;
35785
+ if (ec2?.AdditionalSlaveSecurityGroups !== void 0) instances["AdditionalSlaveSecurityGroups"] = ec2.AdditionalSlaveSecurityGroups;
35786
+ if (cluster.TerminationProtected !== void 0) instances["TerminationProtected"] = cluster.TerminationProtected;
35787
+ if (cluster.UnhealthyNodeReplacement !== void 0) instances["UnhealthyNodeReplacement"] = cluster.UnhealthyNodeReplacement;
35788
+ return instances;
35789
+ }
35790
+ reverseInstanceGroup(g) {
35791
+ const out = {
35792
+ InstanceType: g.InstanceType ?? "",
35793
+ InstanceCount: g.RequestedInstanceCount ?? 0
35794
+ };
35795
+ if (g.Name !== void 0) out["Name"] = g.Name;
35796
+ if (g.Market !== void 0) out["Market"] = g.Market;
35797
+ if (g.BidPrice !== void 0) out["BidPrice"] = g.BidPrice;
35798
+ if (g.CustomAmiId !== void 0) out["CustomAmiId"] = g.CustomAmiId;
35799
+ return out;
35800
+ }
35801
+ reverseInstanceFleet(f) {
35802
+ const out = {};
35803
+ if (f.Name !== void 0) out["Name"] = f.Name;
35804
+ if (f.TargetOnDemandCapacity !== void 0) out["TargetOnDemandCapacity"] = f.TargetOnDemandCapacity;
35805
+ if (f.TargetSpotCapacity !== void 0) out["TargetSpotCapacity"] = f.TargetSpotCapacity;
35806
+ return out;
35807
+ }
35523
35808
  };
35524
35809
 
35525
35810
  //#endregion
@@ -60412,7 +60697,7 @@ function reorderArgs(argv) {
60412
60697
  async function main() {
60413
60698
  installPipeCloseHandler();
60414
60699
  const program = new Command();
60415
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.247.0");
60700
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.248.0");
60416
60701
  program.addCommand(createBootstrapCommand());
60417
60702
  program.addCommand(createSynthCommand());
60418
60703
  program.addCommand(createListCommand());