@quadnix/octo 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -21
- package/dist/app.type.d.ts +141 -22
- package/dist/app.type.js.map +1 -1
- package/dist/decorators/model.decorator.d.ts +3 -5
- package/dist/decorators/model.decorator.js +1 -6
- package/dist/decorators/model.decorator.js.map +1 -1
- package/dist/decorators/on-event.decorator.d.ts +2 -2
- package/dist/decorators/on-event.decorator.js.map +1 -1
- package/dist/decorators/resource.decorator.d.ts +50 -1
- package/dist/decorators/resource.decorator.js +38 -1
- package/dist/decorators/resource.decorator.js.map +1 -1
- package/dist/errors/schema.error.d.ts +8 -1
- package/dist/errors/schema.error.js +5 -1
- package/dist/errors/schema.error.js.map +1 -1
- package/dist/errors/terraform.error.d.ts +4 -3
- package/dist/errors/terraform.error.js +4 -3
- package/dist/errors/terraform.error.js.map +1 -1
- package/dist/errors/transaction.error.d.ts +32 -2
- package/dist/errors/transaction.error.js +22 -0
- package/dist/errors/transaction.error.js.map +1 -1
- package/dist/events/action.event.d.ts +8 -2
- package/dist/events/action.event.js +2 -2
- package/dist/events/action.event.js.map +1 -1
- package/dist/events/command.event.d.ts +43 -0
- package/dist/events/command.event.js +33 -0
- package/dist/events/command.event.js.map +1 -0
- package/dist/events/event.model.d.ts +7 -5
- package/dist/events/event.model.js +5 -3
- package/dist/events/event.model.js.map +1 -1
- package/dist/events/hook/commit.hook.event.d.ts +1 -1
- package/dist/events/hook/commit.hook.event.js.map +1 -1
- package/dist/events/hook/hook.event.d.ts +1 -1
- package/dist/events/hook/hook.event.js.map +1 -1
- package/dist/events/hook/model.hook.event.d.ts +1 -1
- package/dist/events/hook/model.hook.event.js.map +1 -1
- package/dist/events/hook/resource.hook.event.d.ts +1 -1
- package/dist/events/hook/resource.hook.event.js.map +1 -1
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/mode-result.event.d.ts +1 -1
- package/dist/events/mode-result.event.js.map +1 -1
- package/dist/events/mode.event.d.ts +8 -4
- package/dist/events/mode.event.js.map +1 -1
- package/dist/events/module.event.d.ts +7 -3
- package/dist/events/module.event.js +3 -2
- package/dist/events/module.event.js.map +1 -1
- package/dist/events/registration.event.d.ts +1 -1
- package/dist/events/registration.event.js.map +1 -1
- package/dist/events/serialization.event.d.ts +1 -1
- package/dist/events/serialization.event.js.map +1 -1
- package/dist/events/state.event.d.ts +102 -0
- package/dist/events/state.event.js +69 -0
- package/dist/events/state.event.js.map +1 -0
- package/dist/events/terraform.event.d.ts +37 -1
- package/dist/events/terraform.event.js +24 -0
- package/dist/events/terraform.event.js.map +1 -1
- package/dist/events/transaction.event.d.ts +3 -3
- package/dist/events/transaction.event.js +1 -1
- package/dist/events/transaction.event.js.map +1 -1
- package/dist/functions/container/container.js +1 -1
- package/dist/functions/container/container.js.map +1 -1
- package/dist/functions/container/test-container.js +2 -2
- package/dist/functions/container/test-container.js.map +1 -1
- package/dist/functions/dependency/dependency.d.ts +9 -22
- package/dist/functions/dependency/dependency.js +5 -1
- package/dist/functions/dependency/dependency.js.map +1 -1
- package/dist/functions/diff/diff.d.ts +14 -7
- package/dist/functions/diff/diff.js.map +1 -1
- package/dist/functions/node/node-action.abstract.d.ts +8 -10
- package/dist/functions/node/node-action.abstract.js +10 -16
- package/dist/functions/node/node-action.abstract.js.map +1 -1
- package/dist/functions/node/node.abstract.js +21 -10
- package/dist/functions/node/node.abstract.js.map +1 -1
- package/dist/functions/node/node.interface.d.ts +2 -1
- package/dist/functions/schema/schema.js +1 -1
- package/dist/functions/schema/schema.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/index.type.d.ts +5 -0
- package/dist/index.type.js +2 -0
- package/dist/index.type.js.map +1 -0
- package/dist/main.d.ts +4 -3
- package/dist/main.js +27 -11
- package/dist/main.js.map +1 -1
- package/dist/models/account/account.model.d.ts +6 -0
- package/dist/models/account/account.model.js +16 -0
- package/dist/models/account/account.model.js.map +1 -1
- package/dist/models/app/app.model.d.ts +0 -10
- package/dist/models/app/app.model.js +0 -30
- package/dist/models/app/app.model.js.map +1 -1
- package/dist/models/deployment/deployment.schema.d.ts +4 -0
- package/dist/models/deployment/deployment.schema.js +4 -0
- package/dist/models/deployment/deployment.schema.js.map +1 -1
- package/dist/models/environment/environment.model.d.ts +2 -2
- package/dist/models/environment/environment.model.js +2 -2
- package/dist/models/execution/execution.model.d.ts +1 -1
- package/dist/models/execution/execution.model.js +1 -1
- package/dist/models/image/image.model.d.ts +4 -3
- package/dist/models/image/image.model.js +7 -6
- package/dist/models/image/image.model.js.map +1 -1
- package/dist/models/model.abstract.js +1 -1
- package/dist/models/model.abstract.js.map +1 -1
- package/dist/models/pipeline/pipeline.model.d.ts +1 -1
- package/dist/models/pipeline/pipeline.model.js +1 -1
- package/dist/models/server/server.model.d.ts +2 -2
- package/dist/models/server/server.model.js +2 -2
- package/dist/models/service/service.model.d.ts +28 -11
- package/dist/models/service/service.model.js +56 -16
- package/dist/models/service/service.model.js.map +1 -1
- package/dist/models/service/service.schema.d.ts +46 -2
- package/dist/models/service/service.schema.js +54 -2
- package/dist/models/service/service.schema.js.map +1 -1
- package/dist/modes/commit.mode.d.ts +2 -2
- package/dist/modes/commit.mode.js +2 -2
- package/dist/modes/generate.mode.d.ts +2 -1
- package/dist/modes/generate.mode.js +3 -2
- package/dist/modes/generate.mode.js.map +1 -1
- package/dist/modes/run-action.mode.d.ts +1 -1
- package/dist/modes/run-action.mode.js +1 -1
- package/dist/modes/validate.mode.d.ts +24 -0
- package/dist/modes/validate.mode.js +89 -11
- package/dist/modes/validate.mode.js.map +1 -1
- package/dist/modules/module.container.d.ts +7 -1
- package/dist/modules/module.container.js +41 -5
- package/dist/modules/module.container.js.map +1 -1
- package/dist/modules/test-module.container.js +35 -83
- package/dist/modules/test-module.container.js.map +1 -1
- package/dist/overlays/overlay.abstract.js +1 -1
- package/dist/overlays/overlay.abstract.js.map +1 -1
- package/dist/resources/resource-action.interface.d.ts +4 -2
- package/dist/resources/resource.abstract.d.ts +50 -8
- package/dist/resources/resource.abstract.js +63 -32
- package/dist/resources/resource.abstract.js.map +1 -1
- package/dist/resources/resource.interface.d.ts +0 -2
- package/dist/resources/resource.schema.d.ts +11 -1
- package/dist/resources/resource.schema.js +11 -1
- package/dist/resources/resource.schema.js.map +1 -1
- package/dist/services/event/event.service.d.ts +2 -2
- package/dist/services/event/event.service.js.map +1 -1
- package/dist/services/input/input.service.d.ts +30 -2
- package/dist/services/input/input.service.js +71 -4
- package/dist/services/input/input.service.js.map +1 -1
- package/dist/services/serialization/model/model-serialization.service.d.ts +4 -6
- package/dist/services/serialization/model/model-serialization.service.js +20 -17
- package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
- package/dist/services/serialization/resource/resource-serialization.service.d.ts +7 -6
- package/dist/services/serialization/resource/resource-serialization.service.js +25 -12
- package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
- package/dist/services/state-management/local.state-provider.d.ts +25 -9
- package/dist/services/state-management/local.state-provider.js +127 -21
- package/dist/services/state-management/local.state-provider.js.map +1 -1
- package/dist/services/state-management/remote.state-provider.d.ts +216 -0
- package/dist/services/state-management/remote.state-provider.js +645 -0
- package/dist/services/state-management/remote.state-provider.js.map +1 -0
- package/dist/services/state-management/state-management.service.d.ts +83 -40
- package/dist/services/state-management/state-management.service.js +130 -26
- package/dist/services/state-management/state-management.service.js.map +1 -1
- package/dist/services/state-management/state-provider.interface.d.ts +50 -9
- package/dist/services/state-management/state-provider.interface.js +14 -1
- package/dist/services/state-management/state-provider.interface.js.map +1 -1
- package/dist/services/state-management/terraform-state.service.d.ts +32 -9
- package/dist/services/state-management/terraform-state.service.js +64 -21
- package/dist/services/state-management/terraform-state.service.js.map +1 -1
- package/dist/services/state-management/test.state-provider.d.ts +11 -10
- package/dist/services/state-management/test.state-provider.js +35 -14
- package/dist/services/state-management/test.state-provider.js.map +1 -1
- package/dist/services/terraform/terraform.service.d.ts +57 -3
- package/dist/services/terraform/terraform.service.js +95 -8
- package/dist/services/terraform/terraform.service.js.map +1 -1
- package/dist/services/terraform/terraform.type.js +1 -1
- package/dist/services/terraform/terraform.type.js.map +1 -1
- package/dist/services/transaction/transaction.service.d.ts +29 -5
- package/dist/services/transaction/transaction.service.js +198 -34
- package/dist/services/transaction/transaction.service.js.map +1 -1
- package/dist/services/validation/validation.service.d.ts +2 -2
- package/dist/{functions → utilities}/diff/diff.utility.d.ts +2 -1
- package/dist/{functions → utilities}/diff/diff.utility.js +4 -3
- package/dist/utilities/diff/diff.utility.js.map +1 -0
- package/dist/utilities/file/file.utility.d.ts +6 -7
- package/dist/utilities/file/file.utility.js +13 -68
- package/dist/utilities/file/file.utility.js.map +1 -1
- package/dist/utilities/hcl/hcl.utility.d.ts +83 -16
- package/dist/utilities/hcl/hcl.utility.js +200 -27
- package/dist/utilities/hcl/hcl.utility.js.map +1 -1
- package/dist/utilities/http/http.utility.d.ts +57 -0
- package/dist/utilities/http/http.utility.js +98 -0
- package/dist/utilities/http/http.utility.js.map +1 -0
- package/dist/utilities/string/string.utility.d.ts +23 -3
- package/dist/utilities/string/string.utility.js +29 -3
- package/dist/utilities/string/string.utility.js.map +1 -1
- package/dist/utilities/terraform/terraform.utility.d.ts +70 -21
- package/dist/utilities/terraform/terraform.utility.js +255 -66
- package/dist/utilities/terraform/terraform.utility.js.map +1 -1
- package/dist/utilities/test-helpers/test-classes.d.ts +19 -0
- package/dist/utilities/test-helpers/test-classes.js +22 -0
- package/dist/utilities/test-helpers/test-classes.js.map +1 -1
- package/dist/utilities/test-helpers/test-models.d.ts +8 -1
- package/dist/utilities/test-helpers/test-models.js +25 -12
- package/dist/utilities/test-helpers/test-models.js.map +1 -1
- package/dist/utilities/test-helpers/test-modes.d.ts +1 -1
- package/dist/utilities/test-helpers/test-modes.js +36 -13
- package/dist/utilities/test-helpers/test-modes.js.map +1 -1
- package/dist/utilities/test-helpers/test-modules.d.ts +6 -0
- package/dist/utilities/test-helpers/test-modules.js +6 -0
- package/dist/utilities/test-helpers/test-modules.js.map +1 -1
- package/dist/utilities/test-helpers/test-overlays.d.ts +3 -1
- package/dist/utilities/test-helpers/test-overlays.js +8 -2
- package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
- package/dist/utilities/test-helpers/test-resources.d.ts +4 -2
- package/dist/utilities/test-helpers/test-resources.js +22 -20
- package/dist/utilities/test-helpers/test-resources.js.map +1 -1
- package/package.json +7 -2
- package/dist/functions/diff/diff.utility.js.map +0 -1
- package/dist/services/state-management/file-app-lock.utility.d.ts +0 -43
- package/dist/services/state-management/file-app-lock.utility.js +0 -124
- package/dist/services/state-management/file-app-lock.utility.js.map +0 -1
- package/dist/services/state-management/local-encryption.state-provider.d.ts +0 -71
- package/dist/services/state-management/local-encryption.state-provider.js +0 -116
- package/dist/services/state-management/local-encryption.state-provider.js.map +0 -1
|
@@ -16,6 +16,7 @@ import { StateManagementService } from './state-management.service.js';
|
|
|
16
16
|
*/
|
|
17
17
|
export declare class TerraformStateService {
|
|
18
18
|
private checkInQueue;
|
|
19
|
+
private isPeriodicCheckInRunning;
|
|
19
20
|
private periodicCheckIn;
|
|
20
21
|
private readonly stateManagementService;
|
|
21
22
|
/**
|
|
@@ -23,11 +24,13 @@ export declare class TerraformStateService {
|
|
|
23
24
|
*/
|
|
24
25
|
constructor(stateManagementService: StateManagementService);
|
|
25
26
|
/**
|
|
26
|
-
* Writes every module folder's terraform state to the state provider.
|
|
27
|
+
* Writes every module folder's terraform state to the state provider, as one change.
|
|
27
28
|
*
|
|
28
29
|
* A folder holding no state file, or one recording no resources, has its state **deleted** rather
|
|
29
30
|
* than written - that is a module terraform has destroyed, and a file recording nothing is a file
|
|
30
|
-
* worth nobody's history.
|
|
31
|
+
* worth nobody's history. A file that does not parse is left out, keeping the provider's copy:
|
|
32
|
+
* terraform rewrites the file in place, so a check-in during a command can read it empty or half
|
|
33
|
+
* written.
|
|
31
34
|
*
|
|
32
35
|
* Check-ins are serialized, so the one on a command's return never races the one on the timer.
|
|
33
36
|
*/
|
|
@@ -36,23 +39,43 @@ export declare class TerraformStateService {
|
|
|
36
39
|
* Writes the state provider's terraform state into every module folder.
|
|
37
40
|
*
|
|
38
41
|
* A module the provider holds nothing for keeps whatever its folder already has, which is what
|
|
39
|
-
* adopts the state of a stack that ran with a local backend until now.
|
|
40
|
-
*
|
|
42
|
+
* adopts the state of a stack that ran with a local backend until now. A folder whose state is
|
|
43
|
+
* ahead of the provider's keeps it too, which is what a run killed before its last check-in
|
|
44
|
+
* leaves behind. The check-in that follows hands either to the provider.
|
|
41
45
|
*/
|
|
42
46
|
checkOut(terragruntDir: string, moduleIds: string[]): Promise<void>;
|
|
43
47
|
/**
|
|
44
|
-
*
|
|
48
|
+
* The state moves the last generate recorded, each from one module folder into another.
|
|
45
49
|
*/
|
|
46
|
-
|
|
50
|
+
getRecordedMoves(): Promise<{
|
|
51
|
+
addresses: {
|
|
52
|
+
from: string;
|
|
53
|
+
to: string;
|
|
54
|
+
}[];
|
|
55
|
+
fromModuleId: string;
|
|
56
|
+
moduleId: string;
|
|
57
|
+
outputs: {
|
|
58
|
+
from: string;
|
|
59
|
+
to: string;
|
|
60
|
+
}[];
|
|
61
|
+
}[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Starts checking state in every `intervalInMs`, bounding what a killed runner loses to one interval.
|
|
64
|
+
*/
|
|
65
|
+
startPeriodicCheckIn(terragruntDir: string, moduleIds: string[], intervalInMs: number): void;
|
|
47
66
|
/**
|
|
48
67
|
* Stops the timer {@link TerraformStateService.startPeriodicCheckIn} started.
|
|
49
68
|
*/
|
|
50
69
|
stopPeriodicCheckIn(): void;
|
|
51
70
|
/**
|
|
52
|
-
* Whether
|
|
53
|
-
*
|
|
71
|
+
* Whether the folder's terraform state is a later write of the same state the provider holds: the
|
|
72
|
+
* same `lineage`, and a higher `serial`. State that cannot be read or parsed is never ahead.
|
|
73
|
+
*/
|
|
74
|
+
private isFolderStateAhead;
|
|
75
|
+
/**
|
|
76
|
+
* A terraform state file's contents, or `undefined` when it does not parse.
|
|
54
77
|
*/
|
|
55
|
-
private
|
|
78
|
+
private parseState;
|
|
56
79
|
/**
|
|
57
80
|
* The name one module's terraform state is stored under, alongside Octo's own state files.
|
|
58
81
|
*/
|
|
@@ -10,7 +10,6 @@ import { join } from 'node:path';
|
|
|
10
10
|
import { Factory } from '../../decorators/factory.decorator.js';
|
|
11
11
|
import { Container } from '../../functions/container/container.js';
|
|
12
12
|
import { StateManagementService } from './state-management.service.js';
|
|
13
|
-
const CHECK_IN_INTERVAL_IN_MS = 60 * 1000;
|
|
14
13
|
const TERRAFORM_STATE_FILE_NAME = 'terraform.tfstate';
|
|
15
14
|
/**
|
|
16
15
|
* Moves each module folder's `terraform.tfstate` in and out of Octo's {@link IStateProvider}.
|
|
@@ -33,14 +32,17 @@ export class TerraformStateService {
|
|
|
33
32
|
*/
|
|
34
33
|
constructor(stateManagementService) {
|
|
35
34
|
this.checkInQueue = Promise.resolve();
|
|
35
|
+
this.isPeriodicCheckInRunning = false;
|
|
36
36
|
this.stateManagementService = stateManagementService;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Writes every module folder's terraform state to the state provider.
|
|
39
|
+
* Writes every module folder's terraform state to the state provider, as one change.
|
|
40
40
|
*
|
|
41
41
|
* A folder holding no state file, or one recording no resources, has its state **deleted** rather
|
|
42
42
|
* than written - that is a module terraform has destroyed, and a file recording nothing is a file
|
|
43
|
-
* worth nobody's history.
|
|
43
|
+
* worth nobody's history. A file that does not parse is left out, keeping the provider's copy:
|
|
44
|
+
* terraform rewrites the file in place, so a check-in during a command can read it empty or half
|
|
45
|
+
* written.
|
|
44
46
|
*
|
|
45
47
|
* Check-ins are serialized, so the one on a command's return never races the one on the timer.
|
|
46
48
|
*/
|
|
@@ -52,8 +54,9 @@ export class TerraformStateService {
|
|
|
52
54
|
* Writes the state provider's terraform state into every module folder.
|
|
53
55
|
*
|
|
54
56
|
* A module the provider holds nothing for keeps whatever its folder already has, which is what
|
|
55
|
-
* adopts the state of a stack that ran with a local backend until now.
|
|
56
|
-
*
|
|
57
|
+
* adopts the state of a stack that ran with a local backend until now. A folder whose state is
|
|
58
|
+
* ahead of the provider's keeps it too, which is what a run killed before its last check-in
|
|
59
|
+
* leaves behind. The check-in that follows hands either to the provider.
|
|
57
60
|
*/
|
|
58
61
|
async checkOut(terragruntDir, moduleIds) {
|
|
59
62
|
for (const moduleId of moduleIds) {
|
|
@@ -67,21 +70,41 @@ export class TerraformStateService {
|
|
|
67
70
|
}
|
|
68
71
|
throw error;
|
|
69
72
|
}
|
|
70
|
-
|
|
73
|
+
const stateFilePath = join(terragruntDir, moduleId, TERRAFORM_STATE_FILE_NAME);
|
|
74
|
+
if (await this.isFolderStateAhead(stateFilePath, data)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
await writeFile(stateFilePath, data);
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
/**
|
|
74
|
-
*
|
|
81
|
+
* The state moves the last generate recorded, each from one module folder into another.
|
|
82
|
+
*/
|
|
83
|
+
async getRecordedMoves() {
|
|
84
|
+
const { userData } = await this.stateManagementService.getModelState(this.stateManagementService.modelStateFileName);
|
|
85
|
+
return (userData.terraformFolders ?? []).flatMap(({ moduleId, moves = [] }) => moves.map(({ addresses, fromModuleId, outputs }) => ({ addresses, fromModuleId, moduleId, outputs })));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Starts checking state in every `intervalInMs`, bounding what a killed runner loses to one interval.
|
|
75
89
|
*/
|
|
76
|
-
startPeriodicCheckIn(terragruntDir, moduleIds) {
|
|
90
|
+
startPeriodicCheckIn(terragruntDir, moduleIds, intervalInMs) {
|
|
77
91
|
if (this.periodicCheckIn) {
|
|
78
92
|
return;
|
|
79
93
|
}
|
|
80
94
|
this.periodicCheckIn = setInterval(() => {
|
|
95
|
+
// Skip the tick while the last one is still checking in, rather than waiting behind it.
|
|
96
|
+
if (this.isPeriodicCheckInRunning) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.isPeriodicCheckInRunning = true;
|
|
81
100
|
// A tick that fails is not worth aborting the terraform command that is still running - the
|
|
82
101
|
// check-in on its return reports the failure instead.
|
|
83
|
-
void this.checkIn(terragruntDir, moduleIds)
|
|
84
|
-
|
|
102
|
+
void this.checkIn(terragruntDir, moduleIds)
|
|
103
|
+
.catch(() => { })
|
|
104
|
+
.finally(() => {
|
|
105
|
+
this.isPeriodicCheckInRunning = false;
|
|
106
|
+
});
|
|
107
|
+
}, intervalInMs);
|
|
85
108
|
}
|
|
86
109
|
/**
|
|
87
110
|
* Stops the timer {@link TerraformStateService.startPeriodicCheckIn} started.
|
|
@@ -93,18 +116,33 @@ export class TerraformStateService {
|
|
|
93
116
|
}
|
|
94
117
|
}
|
|
95
118
|
/**
|
|
96
|
-
* Whether
|
|
97
|
-
*
|
|
119
|
+
* Whether the folder's terraform state is a later write of the same state the provider holds: the
|
|
120
|
+
* same `lineage`, and a higher `serial`. State that cannot be read or parsed is never ahead.
|
|
98
121
|
*/
|
|
99
|
-
|
|
122
|
+
async isFolderStateAhead(stateFilePath, providerData) {
|
|
100
123
|
try {
|
|
101
|
-
const
|
|
102
|
-
|
|
124
|
+
const folderState = JSON.parse(await readFile(stateFilePath, 'utf-8'));
|
|
125
|
+
const providerState = JSON.parse(providerData.toString());
|
|
126
|
+
return (typeof folderState.serial === 'number' &&
|
|
127
|
+
typeof providerState.serial === 'number' &&
|
|
128
|
+
folderState.lineage === providerState.lineage &&
|
|
129
|
+
folderState.serial > providerState.serial);
|
|
103
130
|
}
|
|
104
131
|
catch {
|
|
105
132
|
return false;
|
|
106
133
|
}
|
|
107
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* A terraform state file's contents, or `undefined` when it does not parse.
|
|
137
|
+
*/
|
|
138
|
+
parseState(data) {
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(data.toString());
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
108
146
|
/**
|
|
109
147
|
* The name one module's terraform state is stored under, alongside Octo's own state files.
|
|
110
148
|
*/
|
|
@@ -115,21 +153,26 @@ export class TerraformStateService {
|
|
|
115
153
|
* The body of a check-in, run one at a time through {@link TerraformStateService.checkIn}.
|
|
116
154
|
*/
|
|
117
155
|
async writeStates(terragruntDir, moduleIds) {
|
|
156
|
+
const stateFiles = [];
|
|
118
157
|
for (const moduleId of moduleIds) {
|
|
119
158
|
const stateFilePath = join(terragruntDir, moduleId, TERRAFORM_STATE_FILE_NAME);
|
|
120
159
|
const stateFileName = this.stateFileName(moduleId);
|
|
160
|
+
// Delete the state of a module with no state file.
|
|
121
161
|
if (!existsSync(stateFilePath)) {
|
|
122
|
-
|
|
162
|
+
stateFiles.push({ data: undefined, stateFileName });
|
|
123
163
|
continue;
|
|
124
164
|
}
|
|
165
|
+
// Skip a file terraform is still writing.
|
|
125
166
|
const data = await readFile(stateFilePath);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
else {
|
|
130
|
-
await this.stateManagementService.saveState(stateFileName, data);
|
|
167
|
+
const state = this.parseState(data);
|
|
168
|
+
if (!state) {
|
|
169
|
+
continue;
|
|
131
170
|
}
|
|
171
|
+
// Delete the state of a module recording no resources, and write every other.
|
|
172
|
+
const holdsNoResources = Array.isArray(state.resources) && state.resources.length === 0;
|
|
173
|
+
stateFiles.push({ data: holdsNoResources ? undefined : data, stateFileName });
|
|
132
174
|
}
|
|
175
|
+
await this.stateManagementService.saveStates(stateFiles);
|
|
133
176
|
}
|
|
134
177
|
}
|
|
135
178
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terraform-state.service.js","sourceRoot":"","sources":["../../../src/services/state-management/terraform-state.service.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,MAAM,
|
|
1
|
+
{"version":3,"file":"terraform-state.service.js","sourceRoot":"","sources":["../../../src/services/state-management/terraform-state.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,10 +9,6 @@ import type { IStateProvider } from './state-provider.interface.js';
|
|
|
9
9
|
export declare class TestStateProvider implements IStateProvider {
|
|
10
10
|
private readonly localState;
|
|
11
11
|
private lockId;
|
|
12
|
-
/**
|
|
13
|
-
* Deletes a state file. Deleting one that is not there is not an error.
|
|
14
|
-
*/
|
|
15
|
-
deleteState(stateFileName: string): Promise<void>;
|
|
16
12
|
/**
|
|
17
13
|
* The id of the lock currently held, or `undefined` when the app is unlocked.
|
|
18
14
|
*/
|
|
@@ -34,17 +30,22 @@ export declare class TestStateProvider implements IStateProvider {
|
|
|
34
30
|
*/
|
|
35
31
|
listStates(prefix: string): Promise<string[]>;
|
|
36
32
|
/**
|
|
37
|
-
* Takes the app lock.
|
|
33
|
+
* Takes the app lock. With `lockId`, resumes the run already holding it.
|
|
38
34
|
*
|
|
39
|
-
* @throws {@link TransactionError} When a lock is held, naming the id that holds it.
|
|
35
|
+
* @throws {@link TransactionError} When a lock is held, naming the id that holds it. When `lockId`
|
|
36
|
+
* is given and is not the lock held.
|
|
37
|
+
*/
|
|
38
|
+
lockApp(lockId?: string): ReturnType<IStateProvider['lockApp']>;
|
|
39
|
+
/**
|
|
40
|
+
* Does nothing: the state lives in this process alone, so it is always the newest.
|
|
40
41
|
*/
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
refreshState(): Promise<{
|
|
43
|
+
replaced: boolean;
|
|
43
44
|
}>;
|
|
44
45
|
/**
|
|
45
|
-
* Writes
|
|
46
|
+
* Writes state files, overwriting whatever was there and deleting each one given no `data`.
|
|
46
47
|
*/
|
|
47
|
-
|
|
48
|
+
saveStates(stateFiles: Parameters<IStateProvider['saveStates']>[0]): Promise<void>;
|
|
48
49
|
/**
|
|
49
50
|
* Releases the app lock.
|
|
50
51
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { AppLockError, TransactionError } from '../../errors/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* Keeps state in memory, and discards it when the process ends. For tests.
|
|
5
6
|
*
|
|
@@ -12,12 +13,6 @@ export class TestStateProvider {
|
|
|
12
13
|
this.localState = {};
|
|
13
14
|
this.lockId = undefined;
|
|
14
15
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Deletes a state file. Deleting one that is not there is not an error.
|
|
17
|
-
*/
|
|
18
|
-
async deleteState(stateFileName) {
|
|
19
|
-
delete this.localState[stateFileName];
|
|
20
|
-
}
|
|
21
16
|
/**
|
|
22
17
|
* The id of the lock currently held, or `undefined` when the app is unlocked.
|
|
23
18
|
*/
|
|
@@ -56,22 +51,48 @@ export class TestStateProvider {
|
|
|
56
51
|
return Object.keys(this.localState).filter((stateFileName) => stateFileName.startsWith(prefix));
|
|
57
52
|
}
|
|
58
53
|
/**
|
|
59
|
-
* Takes the app lock.
|
|
54
|
+
* Takes the app lock. With `lockId`, resumes the run already holding it.
|
|
60
55
|
*
|
|
61
|
-
* @throws {@link TransactionError} When a lock is held, naming the id that holds it.
|
|
56
|
+
* @throws {@link TransactionError} When a lock is held, naming the id that holds it. When `lockId`
|
|
57
|
+
* is given and is not the lock held.
|
|
62
58
|
*/
|
|
63
|
-
async lockApp() {
|
|
59
|
+
async lockApp(lockId) {
|
|
60
|
+
if (lockId) {
|
|
61
|
+
if (this.lockId !== lockId) {
|
|
62
|
+
throw new AppLockError(`App is not locked with lock ID "${lockId}"!`, { reason: 'not-held' });
|
|
63
|
+
}
|
|
64
|
+
return { lockId };
|
|
65
|
+
}
|
|
64
66
|
if (this.lockId) {
|
|
65
|
-
throw new
|
|
67
|
+
throw new AppLockError(`App already locked with lock ID "${this.lockId}"!`, {
|
|
68
|
+
holder: { lockId: this.lockId },
|
|
69
|
+
reason: 'held',
|
|
70
|
+
});
|
|
66
71
|
}
|
|
67
72
|
this.lockId = randomUUID();
|
|
68
73
|
return { lockId: this.lockId };
|
|
69
74
|
}
|
|
70
75
|
/**
|
|
71
|
-
*
|
|
76
|
+
* Does nothing: the state lives in this process alone, so it is always the newest.
|
|
72
77
|
*/
|
|
73
|
-
async
|
|
74
|
-
|
|
78
|
+
async refreshState() {
|
|
79
|
+
return { replaced: false };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Writes state files, overwriting whatever was there and deleting each one given no `data`.
|
|
83
|
+
*/
|
|
84
|
+
async saveStates(stateFiles) {
|
|
85
|
+
for (const stateFile of stateFiles) {
|
|
86
|
+
if ('filePath' in stateFile) {
|
|
87
|
+
this.localState[stateFile.stateFileName] = await readFile(stateFile.filePath);
|
|
88
|
+
}
|
|
89
|
+
else if (stateFile.data === undefined) {
|
|
90
|
+
delete this.localState[stateFile.stateFileName];
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.localState[stateFile.stateFileName] = stateFile.data;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
75
96
|
}
|
|
76
97
|
/**
|
|
77
98
|
* Releases the app lock.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/test.state-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"test.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/test.state-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,10 @@ import { HclExpression, TerraformData, type TerraformLiteralType, TerraformResou
|
|
|
7
7
|
* - Commit (tfstate outputs -> response population).
|
|
8
8
|
*/
|
|
9
9
|
interface OctoTerraformResourceMapping {
|
|
10
|
+
/**
|
|
11
|
+
* Whether destroying the octo resource loses data, as its class declares.
|
|
12
|
+
*/
|
|
13
|
+
destroyLosesData: boolean;
|
|
10
14
|
/**
|
|
11
15
|
* Set for external resources only: the single output carrying the entire response map.
|
|
12
16
|
*/
|
|
@@ -53,8 +57,15 @@ export interface OctoTerraformResourceScope<TResponse extends BaseResourceSchema
|
|
|
53
57
|
* Emits one `resource "<type>" "<name>"` block for this octo resource.
|
|
54
58
|
* Multiple calls chain via `depends_on` in call order.
|
|
55
59
|
* The provider alias is applied automatically when the resource was registered with a provider context.
|
|
60
|
+
*
|
|
61
|
+
* Pass `options.chain: false` to keep a block out of the chain: it depends on neither the block
|
|
62
|
+
* before it nor is depended on by the block after it, and waits only on what its attributes
|
|
63
|
+
* reference. Use it for a block emitted once per item, like a file upload, where a chain would run
|
|
64
|
+
* the items one at a time and store every earlier address in each item's terraform state.
|
|
56
65
|
*/
|
|
57
|
-
addTerraformResource(type: string, name: string, spec?: Record<string, unknown
|
|
66
|
+
addTerraformResource(type: string, name: string, spec?: Record<string, unknown>, options?: {
|
|
67
|
+
chain?: boolean;
|
|
68
|
+
}): TerraformResource;
|
|
58
69
|
/**
|
|
59
70
|
* Declares the outputs for this resource — one entry per response key.
|
|
60
71
|
* Every response key must be declared; the commit phase reads exactly these outputs to
|
|
@@ -119,6 +130,18 @@ export interface TerraformModuleScope {
|
|
|
119
130
|
*/
|
|
120
131
|
getRef<T extends UnknownResource>(resource: T, key: keyof ResourceSchema<T>['response'] & string): HclExpression;
|
|
121
132
|
getRef<S extends BaseResourceSchema>(resource: MatchingResource<S>, key: keyof S['response'] & string): HclExpression;
|
|
133
|
+
/**
|
|
134
|
+
* Joins text and references into one quoted terraform string, for when a value is another
|
|
135
|
+
* resource's output with text of this resource's own around it. Each reference resolves as
|
|
136
|
+
* {@link TerraformModuleScope.getRef} does, so a producer in another folder is still wired in.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* // "https://${var.distribution_DomainName}/api/orders"
|
|
141
|
+
* terraform.interpolate('https://', terraform.getRef(distribution, 'DomainName'), '/api/orders');
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
interpolate(...parts: (string | HclExpression)[]): HclExpression;
|
|
122
145
|
/**
|
|
123
146
|
* Wraps a value in a `jsonencode(...)` call.
|
|
124
147
|
*/
|
|
@@ -262,12 +285,25 @@ export declare class TerraformService {
|
|
|
262
285
|
* expected rather than unattributed.
|
|
263
286
|
*/
|
|
264
287
|
getResourceReferrers(): Map<string, Set<string>>;
|
|
288
|
+
/**
|
|
289
|
+
* Records that a resource takes over the terraform state of a resource octo committed, so terraform
|
|
290
|
+
* updates or replaces the infrastructure in place instead of creating the new resource beside the old.
|
|
291
|
+
* Within one folder, the folder renders a `moved` block from each of the old resource's addresses to
|
|
292
|
+
* the new one's. Between folders, the folder record lists the move, and `TerraformUtility`
|
|
293
|
+
* moves the state before terraform runs.
|
|
294
|
+
*/
|
|
295
|
+
moveResource(fromModuleId: string, fromResourceId: string, toModuleId: string, toResourceId: string): void;
|
|
265
296
|
/**
|
|
266
297
|
* Phase 2 of rendering: prints the four files of every folder from the wiring computed in
|
|
267
298
|
* phase 1. Makes no decisions — when a {@link RefHclNode} renders, its answer is looked up in the
|
|
268
299
|
* folder's precomputed `resolvedRefs`. Cross-folder dependency cycles throw (in phase 1).
|
|
300
|
+
*
|
|
301
|
+
* A folder also keeps every provider block `previousFolders` recorded for it that none of its
|
|
302
|
+
* resources use any more, so terraform can still destroy what that provider created. A resource
|
|
303
|
+
* whose id moved to another account, for one, leaves its old address in the folder's state, bound
|
|
304
|
+
* to the old account's provider.
|
|
269
305
|
*/
|
|
270
|
-
renderAllModules(): Map<string, TerraformModuleFiles>;
|
|
306
|
+
renderAllModules(previousFolders?: TerraformFolderOutput[]): Map<string, TerraformModuleFiles>;
|
|
271
307
|
/**
|
|
272
308
|
* Prints the four files of an **empty** folder from a recorded folder: a `main.tf` with the
|
|
273
309
|
* config block rebuilt from the recorded `required_providers` entries (plus null/external when
|
|
@@ -346,6 +382,20 @@ export declare class TerraformService {
|
|
|
346
382
|
* registered wins, since the alias only routes the region.
|
|
347
383
|
*/
|
|
348
384
|
private findProvider;
|
|
385
|
+
/**
|
|
386
|
+
* The moves of a folder's record: the resources whose state moves in from another folder, with the
|
|
387
|
+
* outputs their consumers in other folders read.
|
|
388
|
+
*/
|
|
389
|
+
private getFolderMoves;
|
|
390
|
+
/**
|
|
391
|
+
* The addresses a resource's state moves between. A block named `<resourceId><suffix>` moves from the
|
|
392
|
+
* block the old resource named `<its resourceId><suffix>`; a `from` the state does not hold moves nothing.
|
|
393
|
+
*/
|
|
394
|
+
private getMoveAddresses;
|
|
395
|
+
/**
|
|
396
|
+
* The `moved` addresses of a folder, for the resources taking over a state the same folder holds.
|
|
397
|
+
*/
|
|
398
|
+
private getMovedAddresses;
|
|
349
399
|
/**
|
|
350
400
|
* @internal
|
|
351
401
|
*/
|
|
@@ -354,6 +404,10 @@ export declare class TerraformService {
|
|
|
354
404
|
* @internal
|
|
355
405
|
*/
|
|
356
406
|
private getRef;
|
|
407
|
+
/**
|
|
408
|
+
* @internal
|
|
409
|
+
*/
|
|
410
|
+
private interpolate;
|
|
357
411
|
/**
|
|
358
412
|
* @internal
|
|
359
413
|
*/
|
|
@@ -388,7 +442,7 @@ export declare class TerraformService {
|
|
|
388
442
|
private renderConfigBlock;
|
|
389
443
|
/**
|
|
390
444
|
* Prints one folder's `terragrunt.hcl`: a `dependency` block per producer folder (with
|
|
391
|
-
* `mock_outputs`, shallow-merged over any applied state, so `run
|
|
445
|
+
* `mock_outputs`, shallow-merged over any applied state, so `run --all -- plan` works both before the
|
|
392
446
|
* first apply and when intent renames a producer resource), and the `inputs` map wiring each auto
|
|
393
447
|
* variable to the producer's output.
|
|
394
448
|
*/
|