@firestartr/cli 2.8.0-snapshot-5 → 2.8.0-snapshot-variant-cloning-test-1

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/build/index.js CHANGED
@@ -320683,6 +320683,13 @@ const GithubSchemas = [
320683
320683
  module: {
320684
320684
  type: 'string',
320685
320685
  },
320686
+ variants: {
320687
+ type: 'array',
320688
+ items: {
320689
+ $ref: 'firestartr.dev://terraform/TerraformProviderVariant',
320690
+ },
320691
+ description: 'variant clones of this workspace — stripped before parent claim validation',
320692
+ },
320686
320693
  context: {
320687
320694
  type: 'object',
320688
320695
  properties: {
@@ -320717,6 +320724,90 @@ const GithubSchemas = [
320717
320724
  },
320718
320725
  ],
320719
320726
  },
320727
+ TerraformProviderVariantOverride: {
320728
+ $id: 'firestartr.dev://terraform/TerraformProviderVariantOverride',
320729
+ description: 'Override fields for a variant of a TFWorkspaceClaim',
320730
+ type: 'object',
320731
+ properties: {
320732
+ name: {
320733
+ type: 'string',
320734
+ description: 'override the terraform provider name',
320735
+ },
320736
+ values: {
320737
+ type: 'object',
320738
+ additionalProperties: true,
320739
+ description: 'override values',
320740
+ },
320741
+ context: {
320742
+ type: 'object',
320743
+ properties: {
320744
+ providers: {
320745
+ type: 'array',
320746
+ items: {
320747
+ type: 'object',
320748
+ properties: { name: { type: 'string' } },
320749
+ additionalProperties: false,
320750
+ },
320751
+ },
320752
+ backend: {
320753
+ type: 'object',
320754
+ properties: { name: { type: 'string' } },
320755
+ additionalProperties: false,
320756
+ },
320757
+ },
320758
+ additionalProperties: false,
320759
+ description: 'override context',
320760
+ },
320761
+ files: {
320762
+ $ref: 'firestartr.dev://terraform/TerraformProviderFiles',
320763
+ },
320764
+ policy: {
320765
+ type: 'string',
320766
+ enum: [
320767
+ 'apply',
320768
+ 'create-only',
320769
+ 'create-update-only',
320770
+ 'full-control',
320771
+ 'observe',
320772
+ 'observe-only',
320773
+ ],
320774
+ },
320775
+ tfStateKey: {
320776
+ $ref: 'firestartr.dev://common/TerraformStateKey',
320777
+ },
320778
+ sync: {
320779
+ type: 'object',
320780
+ properties: {
320781
+ enabled: { type: 'boolean' },
320782
+ period: { type: 'string', pattern: '^[0-9]+[smhd]$' },
320783
+ schedule: { type: 'string' },
320784
+ schedule_timezone: { type: 'string' },
320785
+ policy: { type: 'string' },
320786
+ },
320787
+ additionalProperties: false,
320788
+ },
320789
+ valuesSchema: {
320790
+ type: 'string',
320791
+ },
320792
+ },
320793
+ additionalProperties: false,
320794
+ },
320795
+ TerraformProviderVariant: {
320796
+ $id: 'firestartr.dev://terraform/TerraformProviderVariant',
320797
+ description: 'A single variant of a TFWorkspace',
320798
+ type: 'object',
320799
+ properties: {
320800
+ name: {
320801
+ type: 'string',
320802
+ description: 'name of the variant — used as claim name and CR name base',
320803
+ },
320804
+ overrides: {
320805
+ $ref: 'firestartr.dev://terraform/TerraformProviderVariantOverride',
320806
+ },
320807
+ },
320808
+ additionalProperties: false,
320809
+ required: ['name', 'overrides'],
320810
+ },
320720
320811
  },
320721
320812
  });
320722
320813
 
@@ -321187,6 +321278,12 @@ async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchCla
321187
321278
  try {
321188
321279
  const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
321189
321280
  const claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
321281
+ let variants = [];
321282
+ if (claim.kind === 'TFWorkspaceClaim' &&
321283
+ claim.providers?.terraform?.variants) {
321284
+ variants = claim.providers.terraform.variants;
321285
+ delete claim.providers.terraform.variants;
321286
+ }
321190
321287
  logger.silly(`Patched claim is:
321191
321288
  ---
321192
321289
  ${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
@@ -321224,6 +321321,47 @@ async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchCla
321224
321321
  result = lodash_default().merge(result, resolvedReferences);
321225
321322
  }
321226
321323
  }
321324
+ if (variants.length > 0) {
321325
+ const parentClaimPath = VisitedClaims[claimRef];
321326
+ for (const variant of variants) {
321327
+ if (!variant.name || !variant.overrides) {
321328
+ throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
321329
+ }
321330
+ const prohibitedOverrideFields = ['source', 'module'];
321331
+ for (const field of prohibitedOverrideFields) {
321332
+ if (field in variant.overrides) {
321333
+ throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
321334
+ }
321335
+ }
321336
+ const variantClaim = lodash_default().cloneDeep(claim);
321337
+ variantClaim.name = variant.name;
321338
+ variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
321339
+ if (!variant.overrides.name) {
321340
+ variantClaim.providers.terraform.name = variant.name;
321341
+ }
321342
+ if (!variantClaim.annotations) {
321343
+ variantClaim.annotations = {};
321344
+ }
321345
+ variantClaim.annotations['firestartr.dev/variant-of'] =
321346
+ claim.providers.terraform.name;
321347
+ const variantRef = `TFWorkspaceClaim-${variant.name}`;
321348
+ if (result[variantRef]) {
321349
+ throw new Error(`Variant name '${variant.name}' from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
321350
+ }
321351
+ logger.info(`Creating synthetic variant claim ${variantRef}`);
321352
+ result[variantRef] = {};
321353
+ result[variantRef]['claim'] = variantClaim;
321354
+ result[variantRef]['claimPath'] = parentClaimPath;
321355
+ result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
321356
+ const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
321357
+ for (const ref of variantReferences) {
321358
+ if (!result[ref]) {
321359
+ const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
321360
+ result = lodash_default().merge(result, resolvedReferences);
321361
+ }
321362
+ }
321363
+ }
321364
+ }
321227
321365
  }
321228
321366
  catch (err) {
321229
321367
  throw `Lazy Loading: ${err}`;
@@ -327723,6 +327861,9 @@ class TFWorkspaceChart extends BaseWorkspaceChart {
327723
327861
  return {
327724
327862
  metadata: {
327725
327863
  name: claim.providers.terraform.name,
327864
+ ...(claim.annotations && Object.keys(claim.annotations).length > 0
327865
+ ? { annotations: claim.annotations }
327866
+ : {}),
327726
327867
  },
327727
327868
  spec: {
327728
327869
  firestartr: {
@@ -328076,6 +328217,7 @@ class SecretsChart extends BaseSecretsChart {
328076
328217
 
328077
328218
 
328078
328219
 
328220
+
328079
328221
  function normalizeProvidesApis(providesApis) {
328080
328222
  if (!providesApis)
328081
328223
  return [];
@@ -328146,7 +328288,10 @@ async function renderClaim(catalogScope, firestartrScope, claim, patches, previo
328146
328288
  let catalogEntity = undefined;
328147
328289
  let firestartrEntity = undefined;
328148
328290
  const extraCharts = [];
328149
- const chartId = `${claim.kind}-${claim.name}`.toLowerCase();
328291
+ const isVariant = claim.annotations?.['firestartr.dev/variant-of'] !== undefined;
328292
+ const chartId = isVariant
328293
+ ? `${claim.kind}-${claim.name}.variant`.toLowerCase()
328294
+ : `${claim.kind}-${claim.name}`.toLowerCase();
328150
328295
  let firestartrId = null;
328151
328296
  if (previousCR) {
328152
328297
  firestartrId = previousCR?.spec?.firestartr?.tfStateKey || null;
@@ -328326,6 +328471,21 @@ async function renderClaim(catalogScope, firestartrScope, claim, patches, previo
328326
328471
  ],
328327
328472
  };
328328
328473
  }
328474
+ function renameVariantCrFiles(outputDir, renderedMap) {
328475
+ for (const cr of Object.values(renderedMap)) {
328476
+ const crJson = cr.toJson ? cr.toJson() : cr;
328477
+ if (crJson.metadata?.annotations?.['firestartr.dev/variant-of'] &&
328478
+ crJson.kind &&
328479
+ crJson.metadata?.name) {
328480
+ const oldPath = external_path_.join(outputDir, `${crJson.kind}.${crJson.metadata.name}.yaml`);
328481
+ const newPath = external_path_.join(outputDir, `${crJson.kind}.${crJson.metadata.name}.variant.yaml`);
328482
+ if (external_fs_.existsSync(oldPath)) {
328483
+ external_fs_.renameSync(oldPath, newPath);
328484
+ logger.info(`Renamed variant CR file: ${oldPath} -> ${newPath}`);
328485
+ }
328486
+ }
328487
+ }
328488
+ }
328329
328489
 
328330
328490
  ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crossReferences.ts
328331
328491
 
@@ -328830,6 +328990,9 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
328830
328990
  });
328831
328991
  const result = await renderClaims(catalogScope, firestartrScope, { renderClaims: rClaims, crs, renames: [] });
328832
328992
  firestartrScope.synth();
328993
+ if (crOutputDir) {
328994
+ renameVariantCrFiles(crOutputDir, result);
328995
+ }
328833
328996
  return result;
328834
328997
  }
328835
328998
  async function solver(type, value, rClaims) {
@@ -328889,6 +329052,7 @@ async function addLastStateAndLastClaimAnnotations(filePath, lastStatePRLink, la
328889
329052
 
328890
329053
 
328891
329054
 
329055
+
328892
329056
 
328893
329057
 
328894
329058
  /* harmony default export */ const cdk8s_renderer = ({
@@ -328967,8 +329131,9 @@ async function runRenderer(globalsPath, initializersPath, claimsPath, crsPath, c
328967
329131
  // the system takes everything defined in the claims path
328968
329132
  claimRefsList = await resolveClaimEntries([claimsPath]);
328969
329133
  }
329134
+ let renderedMap;
328970
329135
  try {
328971
- await renderer_render(catalogApp, firestartrApp, claimRefsList);
329136
+ renderedMap = await renderer_render(catalogApp, firestartrApp, claimRefsList);
328972
329137
  }
328973
329138
  catch (error) {
328974
329139
  console.log(`Rendering the system: \n ${error}`);
@@ -328976,6 +329141,7 @@ async function runRenderer(globalsPath, initializersPath, claimsPath, crsPath, c
328976
329141
  }
328977
329142
  catalogApp.synth();
328978
329143
  firestartrApp.synth();
329144
+ renameVariantCrFiles(outputCrDir, renderedMap);
328979
329145
  }
328980
329146
 
328981
329147
  ;// CONCATENATED MODULE: ../importer/src/decanter/config.ts
@@ -335193,6 +335359,20 @@ ${providersString}
335193
335359
 
335194
335360
 
335195
335361
  const TOFU_LOCK_TIMEOUT = '-lock-timeout=60s';
335362
+ const MAX_APPLY_ATTEMPTS = 3;
335363
+ const TRANSIENT_APPLY_RETRY_DELAY_MS = 1000;
335364
+ const GITHUB_INCONSISTENT_APPLY_SIGNATURE = [
335365
+ 'Provider produced inconsistent result after apply',
335366
+ 'root object was present, but now absent',
335367
+ ];
335368
+ /**
335369
+ * Matches the known GitHub provider eventual-consistency failure only.
335370
+ * Keep both markers so unrelated apply errors fail immediately.
335371
+ */
335372
+ function isGitHubInconsistentApplyError(error) {
335373
+ const text = error.message;
335374
+ return GITHUB_INCONSISTENT_APPLY_SIGNATURE.every((line) => text.includes(line));
335375
+ }
335196
335376
  // ========== NEW HELPERS for workspace reuse validation ==========
335197
335377
  // Returns true iff the rendered provider JSON would not be empty (so the providers file should exist)
335198
335378
 
@@ -335299,7 +335479,25 @@ async function plan(path, secrets, format, args = ['plan'], stream, ctl) {
335299
335479
  }
335300
335480
  async function apply(path, secrets, stream, ctl) {
335301
335481
  terraform_provisioner_src_logger.debug(`Running terraform apply in path ${path}`);
335302
- return await tfExec(path, ['apply', '-auto-approve', TOFU_LOCK_TIMEOUT], secrets, ['-input=false'], stream, ctl);
335482
+ let lastError;
335483
+ for (let attempt = 1; attempt <= MAX_APPLY_ATTEMPTS; attempt++) {
335484
+ try {
335485
+ return await tfExec(path, ['apply', '-auto-approve', TOFU_LOCK_TIMEOUT], secrets, ['-input=false'], stream, ctl);
335486
+ }
335487
+ catch (error) {
335488
+ lastError = error;
335489
+ if (isGitHubInconsistentApplyError(lastError)) {
335490
+ if (attempt < MAX_APPLY_ATTEMPTS) {
335491
+ terraform_provisioner_src_logger.warn(`Transient GitHub provider apply error detected (attempt ${attempt} of ${MAX_APPLY_ATTEMPTS}); retrying after ${TRANSIENT_APPLY_RETRY_DELAY_MS}ms: ${GITHUB_INCONSISTENT_APPLY_SIGNATURE.join(', ')}`);
335492
+ await catalog_common/* default.generic.sleep */.Z.generic.sleep(TRANSIENT_APPLY_RETRY_DELAY_MS);
335493
+ continue;
335494
+ }
335495
+ terraform_provisioner_src_logger.warn(`Transient GitHub provider apply error persisted after ${MAX_APPLY_ATTEMPTS} attempts; giving up.`);
335496
+ }
335497
+ throw lastError;
335498
+ }
335499
+ }
335500
+ throw lastError;
335303
335501
  }
335304
335502
  async function customCommand(path, secrets, args, stream) {
335305
335503
  terraform_provisioner_src_logger.debug(`Running terraform customCommand in path ${path} ${args.join(',')}`);
@@ -337206,12 +337404,13 @@ function extractErrorDetails(error) {
337206
337404
 
337207
337405
 
337208
337406
 
337209
-
337210
337407
  const TF_PROJECTS_PATH = '/tmp/tfworkspaces';
337211
337408
  const TF_CACHES_PATH = '/tmp/tfcaches';
337409
+ function generateSessionId() {
337410
+ return Math.random().toString(36).substring(2, 6).padEnd(4, '0');
337411
+ }
337212
337412
  function processOperation(item, op, handler) {
337213
337413
  try {
337214
- clearLocalTfProject(item);
337215
337414
  const policy = getPolicy(item, 'firestartr.dev/policy');
337216
337415
  const syncPolicy = getPolicy(item, 'firestartr.dev/sync-policy');
337217
337416
  if (!policy || policy === 'observe' || policy === 'observe-only') {
@@ -337252,6 +337451,9 @@ async function* process_operation_observe(item, op, handler) {
337252
337451
  }
337253
337452
  async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) { }) {
337254
337453
  let error = false;
337454
+ let deps;
337455
+ let terraformExecutionStarted = false;
337456
+ const sessionId = generateSessionId();
337255
337457
  try {
337256
337458
  yield {
337257
337459
  item,
@@ -337274,9 +337476,9 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337274
337476
  status: 'True',
337275
337477
  message: 'Planning process started',
337276
337478
  };
337277
- const deps = await handler.resolveReferences();
337479
+ deps = await handler.resolveReferences();
337278
337480
  operator_src_logger.info(`The Terraform processor is planning to assess dependencies for item '${item.kind}/${item.metadata.name}' with dependencies: '${deps}'.`);
337279
- const context = buildProvisionerContext(item, deps);
337481
+ const context = buildProvisionerContext(item, deps, sessionId);
337280
337482
  let planType = 'plan-json';
337281
337483
  if ('deletionTimestamp' in item.metadata) {
337282
337484
  planType = 'plan-destroy-json';
@@ -337284,7 +337486,8 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337284
337486
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
337285
337487
  await addPlanStatusCheck(item.metadata.annotations['firestartr.dev/last-state-pr'], 'Terraform plan in progress...');
337286
337488
  }
337287
- const tfPlan = await runTerraformProvisioner(context, planType, null, {
337489
+ terraformExecutionStarted = true;
337490
+ const tfPlan = await runTerraformProvisioner(context, planType, null, undefined, {
337288
337491
  tfCacheDir: external_path_.join(TF_CACHES_PATH, `slot_${handler.getSlotInfo().slotId}`),
337289
337492
  hardTimeout: handler.recommendedTimeout(),
337290
337493
  processKilled: (killed) => {
@@ -337362,6 +337565,22 @@ async function* doPlanJSONFormat(item, op, handler, setResult = function (_r) {
337362
337565
  }
337363
337566
  }
337364
337567
  finally {
337568
+ // Tear up the session workspace only if the project was created
337569
+ // (Terraform execution started), regardless of its success or failure.
337570
+ if (terraformExecutionStarted) {
337571
+ try {
337572
+ const tearContext = buildProvisionerContext(item, deps, sessionId);
337573
+ await runTerraformProvisioner(tearContext, 'tear-up-project');
337574
+ }
337575
+ catch (tearErr) {
337576
+ if (error) {
337577
+ operator_src_logger.warn(`Workspace cleanup failed after plan error: ${tearErr}`);
337578
+ }
337579
+ else {
337580
+ operator_src_logger.warn(`Workspace cleanup failed: ${tearErr}`);
337581
+ }
337582
+ }
337583
+ }
337365
337584
  if (error) {
337366
337585
  if (op === OperationType.SYNC) {
337367
337586
  // if there is an error on a sync we never put the state on error
@@ -337526,6 +337745,9 @@ async function* process_operation_sync(item, op, handler, syncPolicy, generalPol
337526
337745
  }
337527
337746
  async function* process_operation_markedToDeletion(item, op, handler) {
337528
337747
  let error = false;
337748
+ let deps;
337749
+ let terraformExecutionStarted = false;
337750
+ const sessionId = generateSessionId();
337529
337751
  try {
337530
337752
  const type = 'DELETING';
337531
337753
  yield {
@@ -337580,9 +337802,10 @@ async function* process_operation_markedToDeletion(item, op, handler) {
337580
337802
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
337581
337803
  await addDestroyCommitStatus(item, 'pending', 'Performing destroy operation...', `Terraform Destroy ${item.metadata.name}`);
337582
337804
  }
337583
- const deps = await handler.resolveReferences();
337584
- const context = buildProvisionerContext(item, deps);
337585
- const destroyOutput = await runTerraformProvisioner(context, 'destroy', null, {
337805
+ deps = await handler.resolveReferences();
337806
+ const context = buildProvisionerContext(item, deps, sessionId);
337807
+ terraformExecutionStarted = true;
337808
+ const destroyOutput = await runTerraformProvisioner(context, 'destroy', null, undefined, {
337586
337809
  tfCacheDir: external_path_.join(TF_CACHES_PATH, `slot_${handler.getSlotInfo().slotId}`),
337587
337810
  hardTimeout: handler.recommendedTimeout(),
337588
337811
  processKilled: (killed) => {
@@ -337627,6 +337850,22 @@ async function* process_operation_markedToDeletion(item, op, handler) {
337627
337850
  void handler.error();
337628
337851
  }
337629
337852
  finally {
337853
+ // Tear up the session workspace only if the project was created
337854
+ // (Terraform execution started), regardless of its success or failure.
337855
+ if (terraformExecutionStarted) {
337856
+ try {
337857
+ const tearContext = buildProvisionerContext(item, deps, sessionId);
337858
+ await runTerraformProvisioner(tearContext, 'tear-up-project');
337859
+ }
337860
+ catch (tearErr) {
337861
+ if (error) {
337862
+ operator_src_logger.warn(`Workspace cleanup failed after destroy error: ${tearErr}`);
337863
+ }
337864
+ else {
337865
+ operator_src_logger.warn(`Workspace cleanup failed: ${tearErr}`);
337866
+ }
337867
+ }
337868
+ }
337630
337869
  if (error) {
337631
337870
  yield {
337632
337871
  item,
@@ -337656,6 +337895,9 @@ async function* process_operation_nothing(item, op, handler) {
337656
337895
  async function* doApply(item, op, handler) {
337657
337896
  const checkRunCtl = await TFCheckRun('apply', item);
337658
337897
  let error = false;
337898
+ let deps;
337899
+ let terraformExecutionStarted = false;
337900
+ const sessionId = generateSessionId();
337659
337901
  try {
337660
337902
  yield {
337661
337903
  item,
@@ -337701,10 +337943,11 @@ async function* doApply(item, op, handler) {
337701
337943
  status: 'True',
337702
337944
  message: 'Provisioning process started',
337703
337945
  };
337704
- const deps = await handler.resolveReferences();
337946
+ deps = await handler.resolveReferences();
337705
337947
  operator_src_logger.info(`The Terraform processor is applying and assessing dependencies for item '${item.kind}/${item.metadata.name}' with dependencies: '${deps}'.`);
337706
- const context = buildProvisionerContext(item, deps);
337707
- const applyOutput = await runTerraformProvisioner(context, 'apply', checkRunCtl, {
337948
+ const context = buildProvisionerContext(item, deps, sessionId);
337949
+ terraformExecutionStarted = true;
337950
+ const applyOutput = await runTerraformProvisioner(context, 'apply', checkRunCtl, undefined, {
337708
337951
  tfCacheDir: external_path_.join(TF_CACHES_PATH, `slot_${handler.getSlotInfo().slotId}`),
337709
337952
  hardTimeout: handler.recommendedTimeout(),
337710
337953
  processKilled: (killed) => {
@@ -337716,6 +337959,7 @@ async function* doApply(item, op, handler) {
337716
337959
  }
337717
337960
  },
337718
337961
  });
337962
+ context.reuseExistingProject = true;
337719
337963
  const terraformOutputJson = await runTerraformProvisioner(context, 'output');
337720
337964
  if (!terraformOutputJson) {
337721
337965
  throw new Error(`Terraform output is empty for ${item.kind}/${item.metadata.name}`);
@@ -337762,6 +338006,22 @@ async function* doApply(item, op, handler) {
337762
338006
  }
337763
338007
  }
337764
338008
  finally {
338009
+ // Tear up the session workspace only if the project was created
338010
+ // (Terraform execution started), regardless of its success or failure.
338011
+ if (terraformExecutionStarted) {
338012
+ try {
338013
+ const tearContext = buildProvisionerContext(item, deps, sessionId);
338014
+ await runTerraformProvisioner(tearContext, 'tear-up-project');
338015
+ }
338016
+ catch (tearErr) {
338017
+ if (error) {
338018
+ operator_src_logger.warn(`Workspace cleanup failed after provisioning error: ${tearErr}`);
338019
+ }
338020
+ else {
338021
+ operator_src_logger.warn(`Workspace cleanup failed: ${tearErr}`);
338022
+ }
338023
+ }
338024
+ }
337765
338025
  if (error) {
337766
338026
  yield {
337767
338027
  item,
@@ -337847,7 +338107,7 @@ async function* errorPolicyNotAllowsOp(item, op, handler, msg) {
337847
338107
  * @param item - CR to be applied
337848
338108
  * @param deps - Dependencies
337849
338109
  */
337850
- function buildProvisionerContext(item, deps) {
338110
+ function buildProvisionerContext(item, deps, sessionId) {
337851
338111
  const context = {};
337852
338112
  context['type'] = item.spec.source;
337853
338113
  context['inline'] = item.spec.module;
@@ -337862,7 +338122,21 @@ function buildProvisionerContext(item, deps) {
337862
338122
  context['backend'] = adaptBackend(item, deps);
337863
338123
  context['tfStateKey'] = item.spec.firestartr.tfStateKey;
337864
338124
  context['references'] = resolveReferences(item, deps);
337865
- context['projectPath'] = external_path_.join(TF_PROJECTS_PATH, item.spec.firestartr.tfStateKey);
338125
+ const tfStateKey = item?.spec?.firestartr?.tfStateKey;
338126
+ if (typeof tfStateKey !== 'string' || tfStateKey.trim() === '') {
338127
+ throw new Error(`Invalid terraform state key: ${tfStateKey}`);
338128
+ }
338129
+ if (sessionId) {
338130
+ context['projectPath'] = external_path_.join(TF_PROJECTS_PATH, `${item.kind.toLowerCase()}-${item.metadata.name}-${sessionId}`);
338131
+ }
338132
+ else {
338133
+ const basePath = external_path_.resolve(TF_PROJECTS_PATH);
338134
+ const resolvedPath = external_path_.resolve(basePath, tfStateKey);
338135
+ if (!resolvedPath.startsWith(basePath + external_path_.sep)) {
338136
+ throw new Error(`Invalid terraform state key: ${tfStateKey}`);
338137
+ }
338138
+ context['projectPath'] = resolvedPath;
338139
+ }
337866
338140
  return context;
337867
338141
  }
337868
338142
  function getRefContextFromCr(cr, deps) {
@@ -338001,73 +338275,6 @@ function resolveReferences(item, deps) {
338001
338275
  throw new Error(`resolving references: ${e}`);
338002
338276
  }
338003
338277
  }
338004
- function getValidatedTfProjectPath(item) {
338005
- const tfStateKey = item?.spec?.firestartr?.tfStateKey;
338006
- if (typeof tfStateKey !== 'string' || tfStateKey.trim() === '') {
338007
- throw new Error('Invalid terraform state key');
338008
- }
338009
- if (external_path_.isAbsolute(tfStateKey)) {
338010
- throw new Error(`Invalid terraform state key: ${tfStateKey}`);
338011
- }
338012
- const basePath = external_path_.resolve(TF_PROJECTS_PATH);
338013
- const tfProjectPath = external_path_.resolve(basePath, tfStateKey);
338014
- const relativePath = external_path_.relative(basePath, tfProjectPath);
338015
- if (relativePath === '' ||
338016
- relativePath === '.' ||
338017
- relativePath.startsWith('..') ||
338018
- external_path_.isAbsolute(relativePath)) {
338019
- throw new Error(`Invalid terraform state key: ${tfStateKey}`);
338020
- }
338021
- return tfProjectPath;
338022
- }
338023
- function getValidatedTfProjectsRealPath() {
338024
- const basePath = external_path_.resolve(TF_PROJECTS_PATH);
338025
- external_fs_.mkdirSync(basePath, { recursive: true });
338026
- const realBasePath = external_fs_.realpathSync(basePath);
338027
- if (!external_fs_.statSync(realBasePath).isDirectory()) {
338028
- throw new Error(`Invalid terraform projects path: ${TF_PROJECTS_PATH}`);
338029
- }
338030
- return realBasePath;
338031
- }
338032
- function assertPathWithinBase(candidatePath, realBasePath) {
338033
- const relativePath = external_path_.relative(realBasePath, candidatePath);
338034
- if (relativePath === '' ||
338035
- relativePath === '.' ||
338036
- relativePath.startsWith('..') ||
338037
- external_path_.isAbsolute(relativePath)) {
338038
- throw new Error(`Invalid terraform project path: ${candidatePath}`);
338039
- }
338040
- }
338041
- function assertNoSymlinksInExistingPathComponents(realBasePath, candidatePath) {
338042
- const relativePath = external_path_.relative(realBasePath, candidatePath);
338043
- const pathSegments = relativePath
338044
- .split(external_path_.sep)
338045
- .filter((segment) => segment !== '');
338046
- let currentPath = realBasePath;
338047
- for (const pathSegment of pathSegments) {
338048
- currentPath = external_path_.join(currentPath, pathSegment);
338049
- if (!external_fs_.existsSync(currentPath)) {
338050
- return;
338051
- }
338052
- if (external_fs_.lstatSync(currentPath).isSymbolicLink()) {
338053
- throw new Error(`Invalid terraform project path: symlink component detected at ${currentPath}`);
338054
- }
338055
- }
338056
- }
338057
- function clearLocalTfProject(item) {
338058
- const tfProjectPath = getValidatedTfProjectPath(item);
338059
- const realBasePath = getValidatedTfProjectsRealPath();
338060
- assertNoSymlinksInExistingPathComponents(realBasePath, tfProjectPath);
338061
- let deletePath = tfProjectPath;
338062
- if (external_fs_.existsSync(tfProjectPath)) {
338063
- deletePath = external_fs_.realpathSync(tfProjectPath);
338064
- assertPathWithinBase(deletePath, realBasePath);
338065
- }
338066
- external_fs_.rmSync(deletePath, {
338067
- recursive: true,
338068
- force: true,
338069
- });
338070
- }
338071
338278
  function getErrorOutputMessage(cr, key, ref) {
338072
338279
  if (cr.spec.source === 'Remote') {
338073
338280
  return `
@@ -521423,9 +521630,9 @@ const crsStatusSubcommand = {
521423
521630
  };
521424
521631
 
521425
521632
  ;// CONCATENATED MODULE: ./package.json
521426
- const package_namespaceObject = JSON.parse('{"i8":"2.8.0-snapshot-5"}');
521633
+ const package_namespaceObject = JSON.parse('{"i8":"2.8.0-snapshot-variant-cloning-test-1"}');
521427
521634
  ;// CONCATENATED MODULE: ../../package.json
521428
- const package_namespaceObject_1 = {"i8":"2.7.0"};
521635
+ const package_namespaceObject_1 = {"i8":"2.7.1"};
521429
521636
  ;// CONCATENATED MODULE: ./src/subcommands/index.ts
521430
521637
 
521431
521638
 
@@ -1192,6 +1192,13 @@ declare const schemas: {
1192
1192
  module: {
1193
1193
  type: string;
1194
1194
  };
1195
+ variants: {
1196
+ type: string;
1197
+ items: {
1198
+ $ref: string;
1199
+ };
1200
+ description: string;
1201
+ };
1195
1202
  context: {
1196
1203
  type: string;
1197
1204
  properties: {
@@ -1226,6 +1233,102 @@ declare const schemas: {
1226
1233
  $ref?: undefined;
1227
1234
  })[];
1228
1235
  };
1236
+ TerraformProviderVariantOverride: {
1237
+ $id: string;
1238
+ description: string;
1239
+ type: string;
1240
+ properties: {
1241
+ name: {
1242
+ type: string;
1243
+ description: string;
1244
+ };
1245
+ values: {
1246
+ type: string;
1247
+ additionalProperties: boolean;
1248
+ description: string;
1249
+ };
1250
+ context: {
1251
+ type: string;
1252
+ properties: {
1253
+ providers: {
1254
+ type: string;
1255
+ items: {
1256
+ type: string;
1257
+ properties: {
1258
+ name: {
1259
+ type: string;
1260
+ };
1261
+ };
1262
+ additionalProperties: boolean;
1263
+ };
1264
+ };
1265
+ backend: {
1266
+ type: string;
1267
+ properties: {
1268
+ name: {
1269
+ type: string;
1270
+ };
1271
+ };
1272
+ additionalProperties: boolean;
1273
+ };
1274
+ };
1275
+ additionalProperties: boolean;
1276
+ description: string;
1277
+ };
1278
+ files: {
1279
+ $ref: string;
1280
+ };
1281
+ policy: {
1282
+ type: string;
1283
+ enum: string[];
1284
+ };
1285
+ tfStateKey: {
1286
+ $ref: string;
1287
+ };
1288
+ sync: {
1289
+ type: string;
1290
+ properties: {
1291
+ enabled: {
1292
+ type: string;
1293
+ };
1294
+ period: {
1295
+ type: string;
1296
+ pattern: string;
1297
+ };
1298
+ schedule: {
1299
+ type: string;
1300
+ };
1301
+ schedule_timezone: {
1302
+ type: string;
1303
+ };
1304
+ policy: {
1305
+ type: string;
1306
+ };
1307
+ };
1308
+ additionalProperties: boolean;
1309
+ };
1310
+ valuesSchema: {
1311
+ type: string;
1312
+ };
1313
+ };
1314
+ additionalProperties: boolean;
1315
+ };
1316
+ TerraformProviderVariant: {
1317
+ $id: string;
1318
+ description: string;
1319
+ type: string;
1320
+ properties: {
1321
+ name: {
1322
+ type: string;
1323
+ description: string;
1324
+ };
1325
+ overrides: {
1326
+ $ref: string;
1327
+ };
1328
+ };
1329
+ additionalProperties: boolean;
1330
+ required: string[];
1331
+ };
1229
1332
  };
1230
1333
  }[] | {
1231
1334
  $schema: string;
@@ -97,6 +97,13 @@ export declare const TerraformSchemas: {
97
97
  module: {
98
98
  type: string;
99
99
  };
100
+ variants: {
101
+ type: string;
102
+ items: {
103
+ $ref: string;
104
+ };
105
+ description: string;
106
+ };
100
107
  context: {
101
108
  type: string;
102
109
  properties: {
@@ -131,5 +138,101 @@ export declare const TerraformSchemas: {
131
138
  $ref?: undefined;
132
139
  })[];
133
140
  };
141
+ TerraformProviderVariantOverride: {
142
+ $id: string;
143
+ description: string;
144
+ type: string;
145
+ properties: {
146
+ name: {
147
+ type: string;
148
+ description: string;
149
+ };
150
+ values: {
151
+ type: string;
152
+ additionalProperties: boolean;
153
+ description: string;
154
+ };
155
+ context: {
156
+ type: string;
157
+ properties: {
158
+ providers: {
159
+ type: string;
160
+ items: {
161
+ type: string;
162
+ properties: {
163
+ name: {
164
+ type: string;
165
+ };
166
+ };
167
+ additionalProperties: boolean;
168
+ };
169
+ };
170
+ backend: {
171
+ type: string;
172
+ properties: {
173
+ name: {
174
+ type: string;
175
+ };
176
+ };
177
+ additionalProperties: boolean;
178
+ };
179
+ };
180
+ additionalProperties: boolean;
181
+ description: string;
182
+ };
183
+ files: {
184
+ $ref: string;
185
+ };
186
+ policy: {
187
+ type: string;
188
+ enum: string[];
189
+ };
190
+ tfStateKey: {
191
+ $ref: string;
192
+ };
193
+ sync: {
194
+ type: string;
195
+ properties: {
196
+ enabled: {
197
+ type: string;
198
+ };
199
+ period: {
200
+ type: string;
201
+ pattern: string;
202
+ };
203
+ schedule: {
204
+ type: string;
205
+ };
206
+ schedule_timezone: {
207
+ type: string;
208
+ };
209
+ policy: {
210
+ type: string;
211
+ };
212
+ };
213
+ additionalProperties: boolean;
214
+ };
215
+ valuesSchema: {
216
+ type: string;
217
+ };
218
+ };
219
+ additionalProperties: boolean;
220
+ };
221
+ TerraformProviderVariant: {
222
+ $id: string;
223
+ description: string;
224
+ type: string;
225
+ properties: {
226
+ name: {
227
+ type: string;
228
+ description: string;
229
+ };
230
+ overrides: {
231
+ $ref: string;
232
+ };
233
+ };
234
+ additionalProperties: boolean;
235
+ required: string[];
236
+ };
134
237
  };
135
238
  }[];
@@ -97,6 +97,13 @@ declare const _default: {
97
97
  module: {
98
98
  type: string;
99
99
  };
100
+ variants: {
101
+ type: string;
102
+ items: {
103
+ $ref: string;
104
+ };
105
+ description: string;
106
+ };
100
107
  context: {
101
108
  type: string;
102
109
  properties: {
@@ -131,6 +138,102 @@ declare const _default: {
131
138
  $ref?: undefined;
132
139
  })[];
133
140
  };
141
+ TerraformProviderVariantOverride: {
142
+ $id: string;
143
+ description: string;
144
+ type: string;
145
+ properties: {
146
+ name: {
147
+ type: string;
148
+ description: string;
149
+ };
150
+ values: {
151
+ type: string;
152
+ additionalProperties: boolean;
153
+ description: string;
154
+ };
155
+ context: {
156
+ type: string;
157
+ properties: {
158
+ providers: {
159
+ type: string;
160
+ items: {
161
+ type: string;
162
+ properties: {
163
+ name: {
164
+ type: string;
165
+ };
166
+ };
167
+ additionalProperties: boolean;
168
+ };
169
+ };
170
+ backend: {
171
+ type: string;
172
+ properties: {
173
+ name: {
174
+ type: string;
175
+ };
176
+ };
177
+ additionalProperties: boolean;
178
+ };
179
+ };
180
+ additionalProperties: boolean;
181
+ description: string;
182
+ };
183
+ files: {
184
+ $ref: string;
185
+ };
186
+ policy: {
187
+ type: string;
188
+ enum: string[];
189
+ };
190
+ tfStateKey: {
191
+ $ref: string;
192
+ };
193
+ sync: {
194
+ type: string;
195
+ properties: {
196
+ enabled: {
197
+ type: string;
198
+ };
199
+ period: {
200
+ type: string;
201
+ pattern: string;
202
+ };
203
+ schedule: {
204
+ type: string;
205
+ };
206
+ schedule_timezone: {
207
+ type: string;
208
+ };
209
+ policy: {
210
+ type: string;
211
+ };
212
+ };
213
+ additionalProperties: boolean;
214
+ };
215
+ valuesSchema: {
216
+ type: string;
217
+ };
218
+ };
219
+ additionalProperties: boolean;
220
+ };
221
+ TerraformProviderVariant: {
222
+ $id: string;
223
+ description: string;
224
+ type: string;
225
+ properties: {
226
+ name: {
227
+ type: string;
228
+ description: string;
229
+ };
230
+ overrides: {
231
+ $ref: string;
232
+ };
233
+ };
234
+ additionalProperties: boolean;
235
+ required: string[];
236
+ };
134
237
  };
135
238
  };
136
239
  export default _default;
@@ -9,3 +9,4 @@ export declare function renderClaims(catalogScope: Construct, firestartrScope: C
9
9
  renames?: IRenameResult[];
10
10
  }): Promise<RenderedCrMap>;
11
11
  export declare function renderClaim(catalogScope: Construct, firestartrScope: Construct, claim: any, patches: ICustomResourcePatch[], previousCR?: any | null, claimPath?: string): Promise<IRenderClaimResult>;
12
+ export declare function renameVariantCrFiles(outputDir: string, renderedMap: RenderedCrMap): void;
@@ -1,4 +1,5 @@
1
1
  import { OperationType } from '../informer';
2
+ export declare function generateSessionId(): string;
2
3
  export declare function processOperation(item: any, op: OperationType, handler: any): AsyncGenerator<{
3
4
  item: any;
4
5
  reason: OperationType;
@@ -6,9 +7,22 @@ export declare function processOperation(item: any, op: OperationType, handler:
6
7
  status: string;
7
8
  message: any;
8
9
  }, void, unknown>;
10
+ /**
11
+ *
12
+ * @param {any} item - CR to be applied
13
+ * @param op - Operation type
14
+ * @param handler -
15
+ */
16
+ export declare function doApply(item: any, op: OperationType, handler: any): AsyncGenerator<{
17
+ item: any;
18
+ reason: OperationType;
19
+ type: string;
20
+ status: string;
21
+ message: string;
22
+ }, void, unknown>;
9
23
  /**
10
24
  * @description Adapts the CR to the format expected by the terraform provisioner
11
25
  * @param item - CR to be applied
12
26
  * @param deps - Dependencies
13
27
  */
14
- export declare function buildProvisionerContext(item: any, deps: any): any;
28
+ export declare function buildProvisionerContext(item: any, deps: any, sessionId?: string): any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestartr/cli",
3
- "version": "2.8.0-snapshot-5",
3
+ "version": "2.8.0-snapshot-variant-cloning-test-1",
4
4
  "private": false,
5
5
  "description": "Commandline tool",
6
6
  "main": "build/main.js",