@friggframework/devtools 2.0.0--canary.474.6a0bba7.0 → 2.0.0--canary.474.a794ea3.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.
@@ -0,0 +1,221 @@
1
+ /**
2
+ * ExecuteResourceImportUseCase - Execute CloudFormation Resource Import
3
+ *
4
+ * Application Layer - Use Case
5
+ *
6
+ * Business logic for executing CloudFormation import operations for orphaned resources.
7
+ * Orchestrates the complete import workflow including template generation, change set
8
+ * creation, execution monitoring, and verification.
9
+ *
10
+ * Responsibilities:
11
+ * - Generate import template from resources and build template
12
+ * - Create and execute CloudFormation import change set
13
+ * - Monitor import progress with resource-level updates
14
+ * - Verify imported resources are present in stack
15
+ * - Report detailed progress and results
16
+ *
17
+ * Based on: SPEC-IMPORT-EXECUTION.md (lines 712-867)
18
+ */
19
+
20
+ class ExecuteResourceImportUseCase {
21
+ /**
22
+ * Create use case with required dependencies
23
+ *
24
+ * @param {Object} params
25
+ * @param {Object} params.importTemplateGenerator - Generates import templates
26
+ * @param {Object} params.importProgressMonitor - Monitors import operations
27
+ * @param {Object} params.cloudFormationRepository - CloudFormation operations
28
+ * @param {Object} params.stackRepository - Stack template operations
29
+ */
30
+ constructor({ importTemplateGenerator, importProgressMonitor, cloudFormationRepository, stackRepository }) {
31
+ if (!importTemplateGenerator) {
32
+ throw new Error('importTemplateGenerator is required');
33
+ }
34
+ if (!importProgressMonitor) {
35
+ throw new Error('importProgressMonitor is required');
36
+ }
37
+ if (!cloudFormationRepository) {
38
+ throw new Error('cloudFormationRepository is required');
39
+ }
40
+ if (!stackRepository) {
41
+ throw new Error('stackRepository is required');
42
+ }
43
+
44
+ this.templateGenerator = importTemplateGenerator;
45
+ this.progressMonitor = importProgressMonitor;
46
+ this.cfRepo = cloudFormationRepository;
47
+ this.stackRepo = stackRepository;
48
+ }
49
+
50
+ /**
51
+ * Execute complete CloudFormation import workflow
52
+ *
53
+ * Orchestrates the full import process:
54
+ * 1. Generate import template
55
+ * 2. Create CloudFormation change set
56
+ * 3. Wait for change set to be ready
57
+ * 4. Execute change set
58
+ * 5. Monitor import progress
59
+ * 6. Verify imported resources
60
+ *
61
+ * @param {Object} params
62
+ * @param {Object} params.stackIdentifier - Stack name and region
63
+ * @param {Array<Object>} params.resourcesToImport - Resources to import
64
+ * @param {string} params.buildTemplatePath - Path to build template
65
+ * @param {Function} [params.onProgress] - Progress callback
66
+ * @returns {Promise<Object>} Import result with verification details
67
+ */
68
+ async execute({ stackIdentifier, resourcesToImport, buildTemplatePath, onProgress }) {
69
+ try {
70
+ // Step 1: Generate import template
71
+ if (onProgress) {
72
+ onProgress({ step: 'generate_template', status: 'in_progress' });
73
+ }
74
+
75
+ const { template, resourceIdentifiers } = await this.templateGenerator.generateImportTemplate({
76
+ resourcesToImport,
77
+ buildTemplatePath,
78
+ stackIdentifier,
79
+ });
80
+
81
+ if (onProgress) {
82
+ onProgress({ step: 'generate_template', status: 'complete' });
83
+ }
84
+
85
+ // Step 2: Create CloudFormation change set
86
+ if (onProgress) {
87
+ onProgress({ step: 'create_change_set', status: 'in_progress' });
88
+ }
89
+
90
+ const changeSetName = `import-orphaned-resources-${Date.now()}`;
91
+ const changeSet = await this.cfRepo.createChangeSet({
92
+ stackIdentifier,
93
+ changeSetName,
94
+ changeSetType: 'IMPORT',
95
+ template,
96
+ resourcesToImport: resourceIdentifiers,
97
+ });
98
+
99
+ if (onProgress) {
100
+ onProgress({
101
+ step: 'create_change_set',
102
+ status: 'complete',
103
+ changeSetName,
104
+ changeSetId: changeSet.Id,
105
+ });
106
+ }
107
+
108
+ // Step 3: Wait for change set to be ready
109
+ if (onProgress) {
110
+ onProgress({ step: 'wait_change_set', status: 'in_progress' });
111
+ }
112
+
113
+ await this.cfRepo.waitForChangeSet({ stackIdentifier, changeSetName });
114
+
115
+ if (onProgress) {
116
+ onProgress({ step: 'wait_change_set', status: 'complete' });
117
+ }
118
+
119
+ // Step 4: Execute change set
120
+ if (onProgress) {
121
+ onProgress({ step: 'execute_import', status: 'in_progress' });
122
+ }
123
+
124
+ await this.cfRepo.executeChangeSet({ stackIdentifier, changeSetName });
125
+
126
+ // Step 5: Monitor import progress
127
+ const resourceLogicalIds = resourcesToImport.map((r) => r.logicalId);
128
+ const importResult = await this.progressMonitor.monitorImport({
129
+ stackIdentifier,
130
+ resourceLogicalIds,
131
+ onProgress: (progress) => {
132
+ if (onProgress) {
133
+ onProgress({
134
+ step: 'execute_import',
135
+ status: 'in_progress',
136
+ resourceProgress: progress,
137
+ });
138
+ }
139
+ },
140
+ });
141
+
142
+ if (onProgress) {
143
+ onProgress({ step: 'execute_import', status: 'complete' });
144
+ }
145
+
146
+ // Step 6: Verify imported resources
147
+ if (onProgress) {
148
+ onProgress({ step: 'verify', status: 'in_progress' });
149
+ }
150
+
151
+ const verification = await this._verifyImportedResources({
152
+ stackIdentifier,
153
+ resourceLogicalIds,
154
+ });
155
+
156
+ if (onProgress) {
157
+ onProgress({ step: 'verify', status: 'complete' });
158
+ }
159
+
160
+ // Return success result with verification details
161
+ return {
162
+ success: true,
163
+ importedCount: importResult.importedCount,
164
+ failedCount: importResult.failedCount,
165
+ changeSetName,
166
+ stackStatus: verification.stackStatus,
167
+ verifiedResources: verification.resources,
168
+ };
169
+ } catch (error) {
170
+ // Return error with step information
171
+ return {
172
+ success: false,
173
+ error: error.message,
174
+ step: error.step || 'unknown',
175
+ };
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Verify that imported resources are present in the CloudFormation stack
181
+ *
182
+ * Checks that each logical ID corresponds to an actual resource in the stack
183
+ * and retrieves physical IDs and resource types for verification.
184
+ *
185
+ * @param {Object} params
186
+ * @param {Object} params.stackIdentifier - Stack name and region
187
+ * @param {Array<string>} params.resourceLogicalIds - Logical IDs to verify
188
+ * @returns {Promise<Object>} Verification result with resource details
189
+ * @private
190
+ */
191
+ async _verifyImportedResources({ stackIdentifier, resourceLogicalIds }) {
192
+ // Get all resources from the stack
193
+ const stackResources = await this.cfRepo.getStackResources(stackIdentifier);
194
+
195
+ // Map each logical ID to its verification status
196
+ const verifiedResources = resourceLogicalIds.map((logicalId) => {
197
+ const resource = stackResources.find((r) => r.LogicalResourceId === logicalId);
198
+
199
+ return {
200
+ logicalId,
201
+ verified: !!resource,
202
+ physicalId: resource?.PhysicalResourceId,
203
+ resourceType: resource?.ResourceType,
204
+ };
205
+ });
206
+
207
+ // Check if all resources were verified
208
+ const allVerified = verifiedResources.every((r) => r.verified);
209
+
210
+ // Get current stack status
211
+ const stackStatus = await this.cfRepo.getStackStatus(stackIdentifier);
212
+
213
+ return {
214
+ allVerified,
215
+ resources: verifiedResources,
216
+ stackStatus,
217
+ };
218
+ }
219
+ }
220
+
221
+ module.exports = ExecuteResourceImportUseCase;