@go-to-k/cdkd 0.141.0 → 0.142.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/dist/cli.js CHANGED
@@ -27395,6 +27395,16 @@ var EFSProvider = class {
27395
27395
  //#endregion
27396
27396
  //#region src/provisioning/providers/firehose-provider.ts
27397
27397
  /**
27398
+ * CFn destination property names that this provider can apply
27399
+ * in-place via UpdateDestinationCommand. Other destination types
27400
+ * still hard-reject in update() with a tightened error pointing at
27401
+ * the per-shape reverse-mapper follow-up issue (#549).
27402
+ *
27403
+ * Membership grows as each follow-up PR lands. Keep alphabetical
27404
+ * to minimize merge conflicts when multiple follow-ups race.
27405
+ */
27406
+ const SUPPORTED_UPDATE_DESTINATIONS = new Set(["ExtendedS3DestinationConfiguration", "RedshiftDestinationConfiguration"]);
27407
+ /**
27398
27408
  * SDK Provider for AWS Kinesis Firehose resources
27399
27409
  *
27400
27410
  * Supports:
@@ -27586,16 +27596,29 @@ var FirehoseProvider = class {
27586
27596
  * `DescribeDeliveryStream` call, then applies the diff. Only fires
27587
27597
  * when the destination shape actually differs.
27588
27598
  *
27599
+ * - `RedshiftDestinationConfiguration` (#549) — same flow as
27600
+ * ExtendedS3: `DescribeDeliveryStream` recovers VersionId +
27601
+ * DestinationId, then `UpdateDestinationCommand` issues the
27602
+ * diff with a `RedshiftDestinationUpdate` payload produced by
27603
+ * {@link mapRedshiftConfigToUpdate}. Handles `CopyCommand`,
27604
+ * `RetryOptions`, `S3Configuration` → `S3Update`,
27605
+ * `S3BackupConfiguration` → `S3BackupUpdate`,
27606
+ * `ProcessingConfiguration`, `S3BackupMode`,
27607
+ * `CloudWatchLoggingOptions`, `Username` / `Password` /
27608
+ * `RoleARN` / `ClusterJDBCURL`.
27609
+ *
27589
27610
  * Other destination types (`S3DestinationConfiguration`,
27590
- * `HttpEndpointDestinationConfiguration`, `RedshiftDestinationConfiguration`,
27611
+ * `HttpEndpointDestinationConfiguration`,
27591
27612
  * `ElasticsearchDestinationConfiguration`,
27592
27613
  * `AmazonopensearchserviceDestinationConfiguration`,
27593
27614
  * `SplunkDestinationConfiguration`,
27594
- * `AmazonOpenSearchServerlessDestinationConfiguration`) stay rejected
27595
- * with a tightened error message naming the AWS API. Each one is a
27596
- * follow-up to (#477) AWS provides `UpdateDestination` for them too,
27597
- * but the per-shape reverse-mappers are deep and each warrants its own
27598
- * focused PR. Re-deploy with `cdkd deploy --replace` until they land.
27615
+ * `AmazonOpenSearchServerlessDestinationConfiguration`,
27616
+ * `IcebergDestinationConfiguration`,
27617
+ * `SnowflakeDestinationConfiguration`) stay rejected with a tightened
27618
+ * error message naming the AWS API. Each one is a follow-up to (#549)
27619
+ * AWS provides `UpdateDestination` for them too, but the per-shape
27620
+ * reverse-mappers are deep and each warrants its own focused PR.
27621
+ * Re-deploy with `cdkd deploy --replace` until they land.
27599
27622
  *
27600
27623
  * Destination-type SWITCHES (e.g. ExtendedS3 → Redshift) are immutable
27601
27624
  * on AWS; cdkd surfaces `ResourceUpdateNotSupportedError` so the caller
@@ -27607,10 +27630,10 @@ var FirehoseProvider = class {
27607
27630
  const prevDestKey = this.findDestinationKey(previousProperties);
27608
27631
  if (destKey && prevDestKey && destKey !== prevDestKey) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `Switching Firehose destination type from '${prevDestKey}' to '${destKey}' is not supported in-place — AWS UpdateDestination requires the same destination type as the original CreateDeliveryStream. Re-deploy with cdkd deploy --replace.`);
27609
27632
  const activeDest = destKey ?? prevDestKey;
27610
- if (activeDest && activeDest !== "ExtendedS3DestinationConfiguration") {
27633
+ if (activeDest && !SUPPORTED_UPDATE_DESTINATIONS.has(activeDest)) {
27611
27634
  const nextDest = properties[activeDest] ?? {};
27612
27635
  const prevDest = previousProperties[activeDest] ?? {};
27613
- if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `In-place update for '${activeDest}' on AWS::KinesisFirehose::DeliveryStream is not yet implemented in cdkd (AWS exposes UpdateDestination for it; the per-shape reverse-mapper is a follow-up to #477). Re-deploy with cdkd deploy --replace.`);
27636
+ if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `In-place update for '${activeDest}' on AWS::KinesisFirehose::DeliveryStream is not yet implemented in cdkd (AWS exposes UpdateDestination for it; the per-shape reverse-mapper is a follow-up to #549). Re-deploy with cdkd deploy --replace.`);
27614
27637
  }
27615
27638
  await this.applyTagsDiff(physicalId, properties["Tags"], previousProperties["Tags"]);
27616
27639
  if (activeDest === "ExtendedS3DestinationConfiguration") {
@@ -27618,6 +27641,11 @@ var FirehoseProvider = class {
27618
27641
  const prevDest = previousProperties[activeDest] ?? {};
27619
27642
  if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) await this.applyExtendedS3DestinationUpdate(physicalId, nextDest);
27620
27643
  }
27644
+ if (activeDest === "RedshiftDestinationConfiguration") {
27645
+ const nextDest = properties[activeDest] ?? {};
27646
+ const prevDest = previousProperties[activeDest] ?? {};
27647
+ if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) await this.applyRedshiftDestinationUpdate(physicalId, nextDest);
27648
+ }
27621
27649
  const desc = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }))).DeliveryStreamDescription;
27622
27650
  return {
27623
27651
  physicalId,
@@ -27811,6 +27839,54 @@ var FirehoseProvider = class {
27811
27839
  return result;
27812
27840
  }
27813
27841
  /**
27842
+ * Recover `CurrentDeliveryStreamVersionId` + `DestinationId` from
27843
+ * `DescribeDeliveryStream` and issue `UpdateDestination` with the new
27844
+ * Redshift shape. The reverse-mapper at
27845
+ * {@link mapRedshiftConfigToUpdate} produces the
27846
+ * `RedshiftDestinationUpdate` payload — only fields present in the
27847
+ * input are forwarded so omitted CFn keys don't clobber AWS-side
27848
+ * state. Mirrors {@link applyExtendedS3DestinationUpdate} (#549).
27849
+ */
27850
+ async applyRedshiftDestinationUpdate(physicalId, nextConfig) {
27851
+ const desc = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }))).DeliveryStreamDescription;
27852
+ const currentVersionId = desc?.VersionId;
27853
+ const destinationId = (desc?.Destinations?.[0])?.DestinationId;
27854
+ if (!currentVersionId || !destinationId) throw new ProvisioningError(`DescribeDeliveryStream for ${physicalId} did not return VersionId or DestinationId; UpdateDestination cannot proceed.`, "AWS::KinesisFirehose::DeliveryStream", physicalId);
27855
+ await this.getClient().send(new UpdateDestinationCommand({
27856
+ DeliveryStreamName: physicalId,
27857
+ CurrentDeliveryStreamVersionId: currentVersionId,
27858
+ DestinationId: destinationId,
27859
+ RedshiftDestinationUpdate: this.mapRedshiftConfigToUpdate(nextConfig)
27860
+ }));
27861
+ }
27862
+ /**
27863
+ * Map CFn `RedshiftDestinationConfiguration` to the
27864
+ * `RedshiftDestinationUpdate` shape used by AWS
27865
+ * `UpdateDestinationCommand` (#549). Every field is `!== undefined`
27866
+ * gated so omitted CFn keys do not clobber AWS-side state. The CFn
27867
+ * `S3Configuration` field is mapped through
27868
+ * {@link mapS3ConfigToUpdate} into the SDK-side `S3Update` slot;
27869
+ * `S3BackupConfiguration` likewise into `S3BackupUpdate`.
27870
+ */
27871
+ mapRedshiftConfigToUpdate(config) {
27872
+ const result = {};
27873
+ const roleArn = config["RoleArn"] ?? config["RoleARN"];
27874
+ if (roleArn !== void 0) result.RoleARN = roleArn;
27875
+ const clusterJdbcUrl = config["ClusterJDBCURL"] ?? config["ClusterJdbcUrl"];
27876
+ if (clusterJdbcUrl !== void 0) result.ClusterJDBCURL = clusterJdbcUrl;
27877
+ if (config["CopyCommand"] !== void 0) result.CopyCommand = config["CopyCommand"];
27878
+ if (config["Username"] !== void 0) result.Username = config["Username"];
27879
+ if (config["Password"] !== void 0) result.Password = config["Password"];
27880
+ if (config["RetryOptions"] !== void 0) result.RetryOptions = config["RetryOptions"];
27881
+ if (config["S3Configuration"] !== void 0) result.S3Update = this.mapS3ConfigToUpdate(config["S3Configuration"]);
27882
+ if (config["ProcessingConfiguration"] !== void 0) result.ProcessingConfiguration = config["ProcessingConfiguration"];
27883
+ if (config["S3BackupMode"] !== void 0) result.S3BackupMode = config["S3BackupMode"];
27884
+ if (config["S3BackupConfiguration"] !== void 0) result.S3BackupUpdate = this.mapS3ConfigToUpdate(config["S3BackupConfiguration"]);
27885
+ if (config["CloudWatchLoggingOptions"] !== void 0) result.CloudWatchLoggingOptions = config["CloudWatchLoggingOptions"];
27886
+ if (config["SecretsManagerConfiguration"] !== void 0) result.SecretsManagerConfiguration = config["SecretsManagerConfiguration"];
27887
+ return result;
27888
+ }
27889
+ /**
27814
27890
  * Map CFn `S3DestinationConfiguration` to the `S3DestinationUpdate`
27815
27891
  * shape used by AWS `UpdateDestinationCommand` (#477; consumed by
27816
27892
  * {@link mapExtendedS3ConfigToUpdate} for the `S3BackupUpdate` field).
@@ -30170,7 +30246,7 @@ var ECRProvider = class {
30170
30246
  *
30171
30247
  * Each helper is a no-op when the before/after JSON is identical.
30172
30248
  */
30173
- var ASGProvider = class {
30249
+ var ASGProvider = class ASGProvider {
30174
30250
  asgClient;
30175
30251
  providerRegion = process.env["AWS_REGION"];
30176
30252
  logger = getLogger().child("ASGProvider");
@@ -30459,7 +30535,11 @@ var ASGProvider = class {
30459
30535
  result["Tags"] = normalizeAwsTagsToCfn(group.Tags);
30460
30536
  result["MetricsCollection"] = mapEnabledMetricsToCfn(group.EnabledMetrics);
30461
30537
  result["LifecycleHookSpecificationList"] = mapLifecycleHooksToCfn(lifecycleHooks);
30462
- result["TrafficSources"] = mapTrafficSourcesToCfn(trafficSources);
30538
+ result["TrafficSources"] = mapTrafficSourcesToCfn(trafficSources.filter((t) => {
30539
+ if (t.Identifier === void 0) return false;
30540
+ if (t.Type === "elbv2" || t.Type === "elb") return false;
30541
+ return true;
30542
+ }));
30463
30543
  result["NotificationConfigurations"] = mapNotificationsToCfn(notifications);
30464
30544
  return result;
30465
30545
  }
@@ -30468,7 +30548,7 @@ var ASGProvider = class {
30468
30548
  if (!lt) return void 0;
30469
30549
  const out = {};
30470
30550
  if (lt.LaunchTemplateId !== void 0) out.LaunchTemplateId = lt.LaunchTemplateId;
30471
- if (lt.LaunchTemplateName !== void 0) out.LaunchTemplateName = lt.LaunchTemplateName;
30551
+ else if (lt.LaunchTemplateName !== void 0) out.LaunchTemplateName = lt.LaunchTemplateName;
30472
30552
  if (lt.Version !== void 0) out.Version = String(lt.Version);
30473
30553
  if (out.LaunchTemplateId === void 0 && out.LaunchTemplateName === void 0) return;
30474
30554
  return out;
@@ -30630,6 +30710,27 @@ var ASGProvider = class {
30630
30710
  AutoScalingGroupName: physicalId,
30631
30711
  TargetGroupARNs: toAttach
30632
30712
  }));
30713
+ if (toDetach.length > 0 || toAttach.length > 0) await this.waitForTargetGroupArnsConvergence(physicalId, new Set(nextArns));
30714
+ }
30715
+ static TG_CONVERGENCE_TIMEOUT_MS = 3e4;
30716
+ static TG_CONVERGENCE_POLL_INTERVAL_MS = 1e3;
30717
+ async waitForTargetGroupArnsConvergence(physicalId, expected) {
30718
+ const deadlineMs = Date.now() + ASGProvider.TG_CONVERGENCE_TIMEOUT_MS;
30719
+ let lastObserved = /* @__PURE__ */ new Set();
30720
+ while (Date.now() < deadlineMs) {
30721
+ let resp;
30722
+ try {
30723
+ resp = await this.getClient().send(new DescribeAutoScalingGroupsCommand({ AutoScalingGroupNames: [physicalId] }));
30724
+ } catch (err) {
30725
+ this.logger.debug(`applyTargetGroupArnsDiff convergence poll: transient error, retrying — ${err instanceof Error ? err.message : String(err)}`);
30726
+ await new Promise((r) => setTimeout(r, ASGProvider.TG_CONVERGENCE_POLL_INTERVAL_MS));
30727
+ continue;
30728
+ }
30729
+ lastObserved = new Set(resp.AutoScalingGroups?.[0]?.TargetGroupARNs ?? []);
30730
+ if (lastObserved.size === expected.size && [...expected].every((a) => lastObserved.has(a))) return;
30731
+ await new Promise((r) => setTimeout(r, ASGProvider.TG_CONVERGENCE_POLL_INTERVAL_MS));
30732
+ }
30733
+ this.logger.warn(`applyTargetGroupArnsDiff: TG set did not converge within ${ASGProvider.TG_CONVERGENCE_TIMEOUT_MS}ms for ASG ${physicalId}. expected=${JSON.stringify([...expected])} observed=${JSON.stringify([...lastObserved])}`);
30633
30734
  }
30634
30735
  async applyMetricsCollectionDiff(physicalId, next, prev) {
30635
30736
  if (JSON.stringify(next ?? []) === JSON.stringify(prev ?? [])) return;
@@ -55134,7 +55235,7 @@ function reorderArgs(argv) {
55134
55235
  */
55135
55236
  async function main() {
55136
55237
  const program = new Command();
55137
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.141.0");
55238
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.142.0");
55138
55239
  program.addCommand(createBootstrapCommand());
55139
55240
  program.addCommand(createSynthCommand());
55140
55241
  program.addCommand(createListCommand());