@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.46
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/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/HEALTH.md +468 -0
- package/infrastructure/README.md +51 -0
- package/infrastructure/__tests__/postgres-config.test.js +914 -0
- package/infrastructure/__tests__/template-generation.test.js +687 -0
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-builder.js +809 -0
- package/infrastructure/domains/database/aurora-builder.test.js +950 -0
- package/infrastructure/domains/database/aurora-discovery.js +87 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +633 -0
- package/infrastructure/domains/database/migration-builder.test.js +294 -0
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
- package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
- package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
- package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
- package/infrastructure/domains/health/application/ports/index.js +26 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
- package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
- package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
- package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
- package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
- package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
- package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
- package/infrastructure/domains/health/domain/entities/issue.js +299 -0
- package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
- package/infrastructure/domains/health/domain/entities/resource.js +159 -0
- package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
- package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
- package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
- package/infrastructure/domains/integration/integration-builder.js +397 -0
- package/infrastructure/domains/integration/integration-builder.test.js +593 -0
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-builder.js +1829 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
- package/infrastructure/domains/networking/vpc-discovery.js +177 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +366 -0
- package/infrastructure/domains/security/kms-builder.test.js +374 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +177 -0
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
- package/infrastructure/domains/shared/environment-builder.js +119 -0
- package/infrastructure/domains/shared/environment-builder.test.js +247 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +192 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
- package/infrastructure/domains/shared/types/app-definition.js +205 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
- package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +87 -0
- package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
- package/infrastructure/scripts/build-prisma-layer.js +553 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
- package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/cliIntegration.js +1 -1
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +11 -11
- package/frigg-cli/.eslintrc.js +0 -141
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
- package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
- package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
- package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
- package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
- package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
- package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
- package/frigg-cli/__tests__/utils/test-setup.js +0 -287
- package/frigg-cli/build-command/index.js +0 -65
- package/frigg-cli/db-setup-command/index.js +0 -193
- package/frigg-cli/deploy-command/index.js +0 -175
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
- package/frigg-cli/generate-command/azure-generator.js +0 -43
- package/frigg-cli/generate-command/gcp-generator.js +0 -47
- package/frigg-cli/generate-command/index.js +0 -332
- package/frigg-cli/generate-command/terraform-generator.js +0 -555
- package/frigg-cli/generate-iam-command.js +0 -118
- package/frigg-cli/index.js +0 -75
- package/frigg-cli/index.test.js +0 -158
- package/frigg-cli/init-command/backend-first-handler.js +0 -756
- package/frigg-cli/init-command/index.js +0 -93
- package/frigg-cli/init-command/template-handler.js +0 -143
- package/frigg-cli/install-command/backend-js.js +0 -33
- package/frigg-cli/install-command/commit-changes.js +0 -16
- package/frigg-cli/install-command/environment-variables.js +0 -127
- package/frigg-cli/install-command/environment-variables.test.js +0 -136
- package/frigg-cli/install-command/index.js +0 -54
- package/frigg-cli/install-command/install-package.js +0 -13
- package/frigg-cli/install-command/integration-file.js +0 -30
- package/frigg-cli/install-command/logger.js +0 -12
- package/frigg-cli/install-command/template.js +0 -90
- package/frigg-cli/install-command/validate-package.js +0 -75
- package/frigg-cli/jest.config.js +0 -124
- package/frigg-cli/package.json +0 -54
- package/frigg-cli/start-command/index.js +0 -149
- package/frigg-cli/start-command/start-command.test.js +0 -297
- package/frigg-cli/test/init-command.test.js +0 -180
- package/frigg-cli/test/npm-registry.test.js +0 -319
- package/frigg-cli/ui-command/index.js +0 -154
- package/frigg-cli/utils/app-resolver.js +0 -319
- package/frigg-cli/utils/backend-path.js +0 -25
- package/frigg-cli/utils/database-validator.js +0 -161
- package/frigg-cli/utils/error-messages.js +0 -257
- package/frigg-cli/utils/npm-registry.js +0 -167
- package/frigg-cli/utils/prisma-runner.js +0 -280
- package/frigg-cli/utils/process-manager.js +0 -199
- package/frigg-cli/utils/repo-detection.js +0 -405
- package/infrastructure/aws-discovery.js +0 -1176
- package/infrastructure/aws-discovery.test.js +0 -1220
- package/infrastructure/serverless-template.js +0 -2094
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ImportTemplateGenerator - Generate CloudFormation import templates
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Generate CloudFormation templates for importing existing resources
|
|
5
|
+
* by resolving intrinsic functions (!Ref, !Sub, !GetAtt) with actual AWS values
|
|
6
|
+
* and merging with current stack template.
|
|
7
|
+
*
|
|
8
|
+
* Domain Layer - Service
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
class ImportTemplateGenerator {
|
|
12
|
+
/**
|
|
13
|
+
* Create ImportTemplateGenerator instance
|
|
14
|
+
* @param {object} dependencies - Service dependencies
|
|
15
|
+
* @param {object} dependencies.templateParser - Template parsing service
|
|
16
|
+
* @param {object} dependencies.resourceDetector - AWS resource detection service
|
|
17
|
+
* @param {object} dependencies.stackRepository - CloudFormation stack repository
|
|
18
|
+
*/
|
|
19
|
+
constructor({ templateParser, resourceDetector, stackRepository }) {
|
|
20
|
+
this.templateParser = templateParser;
|
|
21
|
+
this.resourceDetector = resourceDetector;
|
|
22
|
+
this.stackRepository = stackRepository;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate import template by merging build template with AWS state
|
|
27
|
+
*
|
|
28
|
+
* Process:
|
|
29
|
+
* 1. Parse build template to get resource definitions with Refs
|
|
30
|
+
* 2. Get current stack template (if exists)
|
|
31
|
+
* 3. For each resource to import:
|
|
32
|
+
* - Get AWS resource properties via resourceDetector
|
|
33
|
+
* - Generate resource definition with resolved intrinsics
|
|
34
|
+
* - Create resource identifier for import operation
|
|
35
|
+
* 4. Merge with current template (preserve existing resources)
|
|
36
|
+
*
|
|
37
|
+
* @param {object} params - Generation parameters
|
|
38
|
+
* @param {Array} params.resourcesToImport - Resources to import
|
|
39
|
+
* @param {string} params.buildTemplatePath - Path to build template
|
|
40
|
+
* @param {object} params.stackIdentifier - Target stack identifier
|
|
41
|
+
* @returns {Promise<object>} Import template and resource identifiers
|
|
42
|
+
*/
|
|
43
|
+
async generateImportTemplate({
|
|
44
|
+
resourcesToImport,
|
|
45
|
+
buildTemplatePath,
|
|
46
|
+
stackIdentifier,
|
|
47
|
+
}) {
|
|
48
|
+
// 1. Parse build template
|
|
49
|
+
const buildTemplate = this.templateParser.parseTemplate(buildTemplatePath);
|
|
50
|
+
|
|
51
|
+
// 2. Get current stack template (if exists)
|
|
52
|
+
let currentTemplate;
|
|
53
|
+
try {
|
|
54
|
+
currentTemplate = await this.stackRepository.getTemplate(stackIdentifier);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// Stack might not exist yet
|
|
57
|
+
currentTemplate = { Resources: {} };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 3. For each resource to import, get AWS properties
|
|
61
|
+
const resourceDefinitions = {};
|
|
62
|
+
const resourceIdentifiers = [];
|
|
63
|
+
|
|
64
|
+
for (const resource of resourcesToImport) {
|
|
65
|
+
const { logicalId, physicalId, resourceType } = resource;
|
|
66
|
+
|
|
67
|
+
// Get current resource state from AWS
|
|
68
|
+
const awsResourceDetails =
|
|
69
|
+
await this.resourceDetector.getResourceDetails({
|
|
70
|
+
resourceType,
|
|
71
|
+
physicalId,
|
|
72
|
+
region: stackIdentifier.region,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Generate CloudFormation resource definition
|
|
76
|
+
const resourceDef = this._generateResourceDefinition({
|
|
77
|
+
logicalId,
|
|
78
|
+
resourceType,
|
|
79
|
+
physicalId,
|
|
80
|
+
buildTemplate,
|
|
81
|
+
awsResourceDetails,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
resourceDefinitions[logicalId] = resourceDef;
|
|
85
|
+
|
|
86
|
+
// Generate resource identifier for import
|
|
87
|
+
resourceIdentifiers.push({
|
|
88
|
+
ResourceType: resourceType,
|
|
89
|
+
LogicalResourceId: logicalId,
|
|
90
|
+
ResourceIdentifier: this._getResourceIdentifier(
|
|
91
|
+
resourceType,
|
|
92
|
+
physicalId
|
|
93
|
+
),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 4. Merge with current template (keep existing resources)
|
|
98
|
+
const importTemplate = {
|
|
99
|
+
...currentTemplate,
|
|
100
|
+
Resources: {
|
|
101
|
+
...currentTemplate.Resources,
|
|
102
|
+
...resourceDefinitions,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// DEBUG: Write template to file for inspection
|
|
107
|
+
if (process.env.DEBUG_IMPORT_TEMPLATE === 'true') {
|
|
108
|
+
const fs = require('fs');
|
|
109
|
+
const path = require('path');
|
|
110
|
+
const debugDir = path.join(__dirname, '../../debug');
|
|
111
|
+
|
|
112
|
+
// Ensure debug directory exists
|
|
113
|
+
if (!fs.existsSync(debugDir)) {
|
|
114
|
+
fs.mkdirSync(debugDir, { recursive: true });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
118
|
+
const debugFile = path.join(debugDir, `import-template-${timestamp}.json`);
|
|
119
|
+
|
|
120
|
+
const debugData = {
|
|
121
|
+
stackIdentifier,
|
|
122
|
+
resourcesToImport,
|
|
123
|
+
resourceIdentifiers,
|
|
124
|
+
template: importTemplate,
|
|
125
|
+
templateSize: JSON.stringify(importTemplate).length,
|
|
126
|
+
resourceCount: Object.keys(importTemplate.Resources || {}).length,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
fs.writeFileSync(debugFile, JSON.stringify(debugData, null, 2));
|
|
130
|
+
console.log(`[DEBUG] Template written to: ${debugFile}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
template: importTemplate,
|
|
135
|
+
resourceIdentifiers,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Generate CloudFormation resource definition from AWS state
|
|
141
|
+
*
|
|
142
|
+
* Takes build template definition and resolves all intrinsics
|
|
143
|
+
* with actual AWS values to create import-ready definition.
|
|
144
|
+
*
|
|
145
|
+
* @private
|
|
146
|
+
* @param {object} params - Generation parameters
|
|
147
|
+
* @param {string} params.logicalId - CloudFormation logical ID
|
|
148
|
+
* @param {string} params.resourceType - AWS resource type
|
|
149
|
+
* @param {string} params.physicalId - AWS physical resource ID
|
|
150
|
+
* @param {object} params.buildTemplate - Build template with Refs
|
|
151
|
+
* @param {object} params.awsResourceDetails - Current AWS resource state
|
|
152
|
+
* @returns {object} CloudFormation resource definition
|
|
153
|
+
* @throws {Error} If logical ID not found in build template
|
|
154
|
+
*/
|
|
155
|
+
_generateResourceDefinition({
|
|
156
|
+
logicalId,
|
|
157
|
+
resourceType,
|
|
158
|
+
physicalId,
|
|
159
|
+
buildTemplate,
|
|
160
|
+
awsResourceDetails,
|
|
161
|
+
}) {
|
|
162
|
+
// Start with build template definition if available
|
|
163
|
+
const buildResource = buildTemplate.resources?.[logicalId];
|
|
164
|
+
|
|
165
|
+
if (!buildResource) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Logical ID ${logicalId} not found in build template. ` +
|
|
168
|
+
`Cannot generate import definition without template reference.`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Resolve intrinsics with actual AWS values
|
|
173
|
+
const resolvedProperties = this._resolveIntrinsics({
|
|
174
|
+
properties: buildResource.Properties,
|
|
175
|
+
awsResourceDetails,
|
|
176
|
+
resourceType,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
Type: resourceType,
|
|
181
|
+
Properties: resolvedProperties,
|
|
182
|
+
DeletionPolicy: 'Retain', // Required for CloudFormation IMPORT operations
|
|
183
|
+
UpdateReplacePolicy: 'Retain', // Protects old resources during stack updates
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Resolve CloudFormation intrinsics in properties
|
|
189
|
+
*
|
|
190
|
+
* Processes all properties and resolves intrinsic functions
|
|
191
|
+
* (!Ref, !Sub, !GetAtt) with actual AWS values.
|
|
192
|
+
*
|
|
193
|
+
* @private
|
|
194
|
+
* @param {object} params - Resolution parameters
|
|
195
|
+
* @param {object} params.properties - CloudFormation properties
|
|
196
|
+
* @param {object} params.awsResourceDetails - AWS resource state
|
|
197
|
+
* @param {string} params.resourceType - AWS resource type
|
|
198
|
+
* @returns {object} Resolved properties
|
|
199
|
+
*/
|
|
200
|
+
_resolveIntrinsics({ properties, awsResourceDetails, resourceType }) {
|
|
201
|
+
const resolved = {};
|
|
202
|
+
|
|
203
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
204
|
+
resolved[key] = this._resolveValue(
|
|
205
|
+
value,
|
|
206
|
+
awsResourceDetails,
|
|
207
|
+
resourceType
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return resolved;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Recursively resolve a property value
|
|
216
|
+
*
|
|
217
|
+
* Handles:
|
|
218
|
+
* - Intrinsic functions (!Ref, !Sub, !GetAtt)
|
|
219
|
+
* - Nested objects
|
|
220
|
+
* - Arrays
|
|
221
|
+
* - Literal values
|
|
222
|
+
*
|
|
223
|
+
* @private
|
|
224
|
+
* @param {*} value - Property value to resolve
|
|
225
|
+
* @param {object} awsResourceDetails - AWS resource state
|
|
226
|
+
* @param {string} resourceType - AWS resource type
|
|
227
|
+
* @returns {*} Resolved value
|
|
228
|
+
*/
|
|
229
|
+
_resolveValue(value, awsResourceDetails, resourceType) {
|
|
230
|
+
// Handle intrinsic functions
|
|
231
|
+
if (typeof value === 'object' && value !== null) {
|
|
232
|
+
// !Ref
|
|
233
|
+
if (value.Ref) {
|
|
234
|
+
return this._resolveRef(value.Ref, awsResourceDetails, resourceType);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// !Sub
|
|
238
|
+
if (value['Fn::Sub']) {
|
|
239
|
+
return this._resolveSub(value['Fn::Sub'], awsResourceDetails);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// !GetAtt
|
|
243
|
+
if (value['Fn::GetAtt']) {
|
|
244
|
+
return this._resolveGetAtt(value['Fn::GetAtt'], awsResourceDetails);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Recursively process nested objects
|
|
248
|
+
if (Array.isArray(value)) {
|
|
249
|
+
return value.map((v) =>
|
|
250
|
+
this._resolveValue(v, awsResourceDetails, resourceType)
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Recursively process object properties
|
|
255
|
+
const resolved = {};
|
|
256
|
+
for (const [k, v] of Object.entries(value)) {
|
|
257
|
+
resolved[k] = this._resolveValue(v, awsResourceDetails, resourceType);
|
|
258
|
+
}
|
|
259
|
+
return resolved;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Literal value
|
|
263
|
+
return value;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Resolve !Ref to actual AWS value
|
|
268
|
+
*
|
|
269
|
+
* Maps common parameter names and resource references to AWS property values.
|
|
270
|
+
* Supports:
|
|
271
|
+
* - Parameter names (VpcCidr, VpcId, etc.)
|
|
272
|
+
* - Resource logical IDs (FriggVPC, FriggLambdaSecurityGroup, etc.)
|
|
273
|
+
* - Direct property references (Subnet1, Subnet2, etc.)
|
|
274
|
+
*
|
|
275
|
+
* @private
|
|
276
|
+
* @param {string} refName - Reference name
|
|
277
|
+
* @param {object} awsResourceDetails - AWS resource state
|
|
278
|
+
* @param {string} resourceType - AWS resource type
|
|
279
|
+
* @returns {*} Resolved value
|
|
280
|
+
*/
|
|
281
|
+
_resolveRef(refName, awsResourceDetails, resourceType) {
|
|
282
|
+
// Map common parameters to AWS properties
|
|
283
|
+
const refMap = {
|
|
284
|
+
VpcCidr: awsResourceDetails.properties?.CidrBlock,
|
|
285
|
+
VpcId: awsResourceDetails.properties?.VpcId,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
if (refMap[refName] !== undefined) {
|
|
289
|
+
return refMap[refName];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// First, try direct property lookup
|
|
293
|
+
// This handles cases like { Ref: 'Subnet1' } where properties.Subnet1 = 'subnet-111'
|
|
294
|
+
const directValue = awsResourceDetails.properties?.[refName];
|
|
295
|
+
if (directValue !== undefined) {
|
|
296
|
+
return directValue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Check if refName is a resource logical ID that references another resource
|
|
300
|
+
// In this case, the AWS properties will already have the resolved value
|
|
301
|
+
// For example: { Ref: 'FriggVPC' } should resolve to VpcId from properties
|
|
302
|
+
// For example: { Ref: 'FriggLambdaSecurityGroup' } should resolve to GroupId from properties
|
|
303
|
+
if (refName.includes('VPC') && !refName.includes('Endpoint')) {
|
|
304
|
+
// VPC resource reference
|
|
305
|
+
return awsResourceDetails.properties?.VpcId || refName;
|
|
306
|
+
} else if (refName.includes('Subnet')) {
|
|
307
|
+
// Subnet resource reference
|
|
308
|
+
return awsResourceDetails.properties?.SubnetId || refName;
|
|
309
|
+
} else if (refName.includes('SecurityGroup')) {
|
|
310
|
+
// Security Group resource reference
|
|
311
|
+
return awsResourceDetails.properties?.GroupId || refName;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Fallback: return the ref name itself if not found
|
|
315
|
+
return refName;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Resolve !Sub to actual string
|
|
320
|
+
*
|
|
321
|
+
* Replaces CloudFormation pseudo parameters and variables
|
|
322
|
+
* with actual values from AWS resource state.
|
|
323
|
+
*
|
|
324
|
+
* Supports:
|
|
325
|
+
* - ${AWS::StackName}
|
|
326
|
+
* - Custom variables from tags
|
|
327
|
+
*
|
|
328
|
+
* @private
|
|
329
|
+
* @param {string|object} subValue - Sub expression
|
|
330
|
+
* @param {object} awsResourceDetails - AWS resource state
|
|
331
|
+
* @returns {string|object} Resolved value
|
|
332
|
+
*/
|
|
333
|
+
_resolveSub(subValue, awsResourceDetails) {
|
|
334
|
+
if (typeof subValue !== 'string') {
|
|
335
|
+
return subValue;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Replace ${AWS::StackName} with actual stack name
|
|
339
|
+
let resolved = subValue.replace(
|
|
340
|
+
/\$\{AWS::StackName\}/g,
|
|
341
|
+
awsResourceDetails.stackName || ''
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// Replace other variables if present in tags
|
|
345
|
+
if (awsResourceDetails.tags) {
|
|
346
|
+
for (const [key, value] of Object.entries(awsResourceDetails.tags)) {
|
|
347
|
+
resolved = resolved.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return resolved;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Resolve !GetAtt to actual attribute value
|
|
356
|
+
*
|
|
357
|
+
* Gets attribute value from AWS resource properties.
|
|
358
|
+
* When the attribute refers to a different resource's property
|
|
359
|
+
* (e.g., FriggVPC.CidrBlock from a Subnet), we need to look at
|
|
360
|
+
* the actual AWS values in the current resource's properties.
|
|
361
|
+
*
|
|
362
|
+
* The AWS resource details from the detector already contain
|
|
363
|
+
* resolved values. For example, a Subnet may have Tags that
|
|
364
|
+
* include the VPC's CIDR, or properties that include the VPC ID.
|
|
365
|
+
*
|
|
366
|
+
* @private
|
|
367
|
+
* @param {Array} getAttValue - GetAtt expression [ResourceName, AttributeName]
|
|
368
|
+
* @param {object} awsResourceDetails - AWS resource state
|
|
369
|
+
* @returns {*} Attribute value or null
|
|
370
|
+
*/
|
|
371
|
+
_resolveGetAtt([resourceName, attributeName], awsResourceDetails) {
|
|
372
|
+
// First try to get directly from properties
|
|
373
|
+
const directValue = awsResourceDetails.properties?.[attributeName];
|
|
374
|
+
if (directValue !== undefined && directValue !== null) {
|
|
375
|
+
// Check if this is the actual value we want
|
|
376
|
+
// For cross-resource references, we need to be more careful
|
|
377
|
+
// If resourceName refers to a different resource (e.g., FriggVPC from a Subnet),
|
|
378
|
+
// the property might not be the right one
|
|
379
|
+
|
|
380
|
+
// If getting VPC.CidrBlock, but we have Subnet.CidrBlock,
|
|
381
|
+
// we need to look elsewhere
|
|
382
|
+
if (resourceName.includes('VPC') && attributeName === 'CidrBlock') {
|
|
383
|
+
// Check if this is actually a subnet's CIDR (starts with same first two octets + .X.0/24 pattern)
|
|
384
|
+
// If so, we need to look at Tags for VpcCidr
|
|
385
|
+
const tags = awsResourceDetails.properties?.Tags;
|
|
386
|
+
if (Array.isArray(tags)) {
|
|
387
|
+
const vpcCidrTag = tags.find(t => t.Key === 'VpcCidr');
|
|
388
|
+
if (vpcCidrTag) {
|
|
389
|
+
return vpcCidrTag.Value;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return directValue;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Check Tags as fallback
|
|
398
|
+
const tags = awsResourceDetails.properties?.Tags;
|
|
399
|
+
if (Array.isArray(tags)) {
|
|
400
|
+
const tag = tags.find(t => t.Key === attributeName || t.Key === `${resourceName}${attributeName}`);
|
|
401
|
+
if (tag) {
|
|
402
|
+
return tag.Value;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Get resource identifier for import operation
|
|
411
|
+
*
|
|
412
|
+
* Maps resource type to CloudFormation import identifier format.
|
|
413
|
+
* Each AWS resource type has a specific identifier property.
|
|
414
|
+
*
|
|
415
|
+
* @private
|
|
416
|
+
* @param {string} resourceType - AWS resource type
|
|
417
|
+
* @param {string} physicalId - AWS physical resource ID
|
|
418
|
+
* @returns {object} Resource identifier for import
|
|
419
|
+
*/
|
|
420
|
+
_getResourceIdentifier(resourceType, physicalId) {
|
|
421
|
+
const identifierMap = {
|
|
422
|
+
'AWS::EC2::VPC': { VpcId: physicalId },
|
|
423
|
+
'AWS::EC2::Subnet': { SubnetId: physicalId },
|
|
424
|
+
'AWS::EC2::SecurityGroup': { Id: physicalId },
|
|
425
|
+
'AWS::EC2::InternetGateway': { InternetGatewayId: physicalId },
|
|
426
|
+
'AWS::EC2::NatGateway': { NatGatewayId: physicalId },
|
|
427
|
+
'AWS::EC2::RouteTable': { RouteTableId: physicalId },
|
|
428
|
+
'AWS::EC2::VPCEndpoint': { VpcEndpointId: physicalId },
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
return identifierMap[resourceType] || { Id: physicalId };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
module.exports = { ImportTemplateGenerator };
|