codify-plugin-lib 1.0.77 → 1.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plan/change-set.d.ts +11 -1
- package/dist/plan/change-set.js +15 -5
- package/dist/plan/plan.d.ts +1 -1
- package/dist/plan/plan.js +2 -2
- package/dist/resource/resource-controller.js +4 -2
- package/dist/resource/resource-settings.d.ts +3 -3
- package/dist/utils/spawn-2.d.ts +5 -0
- package/dist/utils/spawn-2.js +7 -0
- package/dist/utils/spawn.d.ts +29 -0
- package/dist/utils/spawn.js +124 -0
- package/package.json +1 -1
- package/src/plan/change-set.ts +18 -8
- package/src/plan/plan.ts +3 -3
- package/src/resource/parsed-resource-settings.ts +1 -1
- package/src/resource/resource-controller.ts +6 -3
- package/src/resource/resource-settings.ts +3 -3
|
@@ -30,7 +30,17 @@ export declare class ChangeSet<T extends StringIndexedObject> {
|
|
|
30
30
|
static empty<T extends StringIndexedObject>(): ChangeSet<T>;
|
|
31
31
|
static create<T extends StringIndexedObject>(desired: Partial<T>): ChangeSet<T>;
|
|
32
32
|
static destroy<T extends StringIndexedObject>(current: Partial<T>): ChangeSet<T>;
|
|
33
|
-
static calculateModification<T extends StringIndexedObject>(desired: Partial<T>, current: Partial<T>, parameterSettings?: Partial<Record<keyof T, ParameterSetting>>): ChangeSet<T
|
|
33
|
+
static calculateModification<T extends StringIndexedObject>(desired: Partial<T>, current: Partial<T>, parameterSettings?: Partial<Record<keyof T, ParameterSetting>>): Promise<ChangeSet<T>>;
|
|
34
|
+
/**
|
|
35
|
+
* Calculates the differences between the desired and current parameters,
|
|
36
|
+
* and returns a list of parameter changes that describe what needs to be added,
|
|
37
|
+
* removed, or modified to match the desired state.
|
|
38
|
+
*
|
|
39
|
+
* @param {Partial<T>} desiredParameters - The desired target state of the parameters.
|
|
40
|
+
* @param {Partial<T>} currentParameters - The current state of the parameters.
|
|
41
|
+
* @param {Partial<Record<keyof T, ParameterSetting>>} [parameterOptions] - Optional settings used when comparing parameters.
|
|
42
|
+
* @return {ParameterChange<T>[]} A list of changes required to transition from the current state to the desired state.
|
|
43
|
+
*/
|
|
34
44
|
private static calculateParameterChanges;
|
|
35
45
|
private static combineResourceOperations;
|
|
36
46
|
private static isSame;
|
package/dist/plan/change-set.js
CHANGED
|
@@ -45,8 +45,8 @@ export class ChangeSet {
|
|
|
45
45
|
}));
|
|
46
46
|
return new ChangeSet(ResourceOperation.DESTROY, parameterChanges);
|
|
47
47
|
}
|
|
48
|
-
static calculateModification(desired, current, parameterSettings = {}) {
|
|
49
|
-
const pc = ChangeSet.calculateParameterChanges(desired, current, parameterSettings);
|
|
48
|
+
static async calculateModification(desired, current, parameterSettings = {}) {
|
|
49
|
+
const pc = await ChangeSet.calculateParameterChanges(desired, current, parameterSettings);
|
|
50
50
|
const statefulParameterKeys = new Set(Object.entries(parameterSettings)
|
|
51
51
|
.filter(([, v]) => v?.type === 'stateful')
|
|
52
52
|
.map(([k]) => k));
|
|
@@ -67,7 +67,17 @@ export class ChangeSet {
|
|
|
67
67
|
}, ResourceOperation.NOOP);
|
|
68
68
|
return new ChangeSet(resourceOperation, pc);
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Calculates the differences between the desired and current parameters,
|
|
72
|
+
* and returns a list of parameter changes that describe what needs to be added,
|
|
73
|
+
* removed, or modified to match the desired state.
|
|
74
|
+
*
|
|
75
|
+
* @param {Partial<T>} desiredParameters - The desired target state of the parameters.
|
|
76
|
+
* @param {Partial<T>} currentParameters - The current state of the parameters.
|
|
77
|
+
* @param {Partial<Record<keyof T, ParameterSetting>>} [parameterOptions] - Optional settings used when comparing parameters.
|
|
78
|
+
* @return {ParameterChange<T>[]} A list of changes required to transition from the current state to the desired state.
|
|
79
|
+
*/
|
|
80
|
+
static async calculateParameterChanges(desiredParameters, currentParameters, parameterOptions) {
|
|
71
81
|
const parameterChangeSet = new Array();
|
|
72
82
|
// Filter out null and undefined values or else the diff below will not work
|
|
73
83
|
const desired = Object.fromEntries(Object.entries(desiredParameters).filter(([, v]) => v !== null && v !== undefined));
|
|
@@ -83,7 +93,7 @@ export class ChangeSet {
|
|
|
83
93
|
delete current[k];
|
|
84
94
|
continue;
|
|
85
95
|
}
|
|
86
|
-
if (!ChangeSet.isSame(desired[k], current[k], parameterOptions?.[k])) {
|
|
96
|
+
if (!await ChangeSet.isSame(desired[k], current[k], parameterOptions?.[k])) {
|
|
87
97
|
parameterChangeSet.push({
|
|
88
98
|
name: k,
|
|
89
99
|
previousValue: v ?? null,
|
|
@@ -128,7 +138,7 @@ export class ChangeSet {
|
|
|
128
138
|
const indexNext = orderOfOperations.indexOf(next);
|
|
129
139
|
return orderOfOperations[Math.max(indexPrev, indexNext)];
|
|
130
140
|
}
|
|
131
|
-
static isSame(desired, current, setting) {
|
|
141
|
+
static async isSame(desired, current, setting) {
|
|
132
142
|
switch (setting?.type) {
|
|
133
143
|
case 'stateful': {
|
|
134
144
|
const statefulSetting = setting.definition.getSettings();
|
package/dist/plan/plan.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare class Plan<T extends StringIndexedObject> {
|
|
|
41
41
|
coreParameters: ResourceConfig;
|
|
42
42
|
settings: ParsedResourceSettings<T>;
|
|
43
43
|
statefulMode: boolean;
|
|
44
|
-
}): Plan<T
|
|
44
|
+
}): Promise<Plan<T>>;
|
|
45
45
|
/**
|
|
46
46
|
* Only keep relevant params for the plan. We don't want to change settings that were not already
|
|
47
47
|
* defined.
|
package/dist/plan/plan.js
CHANGED
|
@@ -70,7 +70,7 @@ export class Plan {
|
|
|
70
70
|
getResourceType() {
|
|
71
71
|
return this.coreParameters.type;
|
|
72
72
|
}
|
|
73
|
-
static calculate(params) {
|
|
73
|
+
static async calculate(params) {
|
|
74
74
|
const { desiredParameters, currentParametersArray, stateParameters, coreParameters, settings, statefulMode } = params;
|
|
75
75
|
const currentParameters = Plan.matchCurrentParameters({
|
|
76
76
|
desiredParameters,
|
|
@@ -99,7 +99,7 @@ export class Plan {
|
|
|
99
99
|
return new Plan(uuidV4(), ChangeSet.destroy(filteredCurrentParameters), coreParameters);
|
|
100
100
|
}
|
|
101
101
|
// NO-OP, MODIFY or RE-CREATE
|
|
102
|
-
const changeSet = ChangeSet.calculateModification(desiredParameters, filteredCurrentParameters, settings.parameterSettings);
|
|
102
|
+
const changeSet = await ChangeSet.calculateModification(desiredParameters, filteredCurrentParameters, settings.parameterSettings);
|
|
103
103
|
return new Plan(uuidV4(), changeSet, coreParameters);
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Ajv } from 'ajv';
|
|
2
2
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
3
3
|
import { Plan } from '../plan/plan.js';
|
|
4
|
+
import { splitUserConfig } from '../utils/utils.js';
|
|
4
5
|
import { ConfigParser } from './config-parser.js';
|
|
5
6
|
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
6
7
|
export class ResourceController {
|
|
@@ -193,9 +194,10 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
193
194
|
desired[key] = await inputTransformation(desired[key]);
|
|
194
195
|
}
|
|
195
196
|
if (this.settings.inputTransformation) {
|
|
196
|
-
const
|
|
197
|
+
const { parameters, coreParameters } = splitUserConfig(desired);
|
|
198
|
+
const transformed = await this.settings.inputTransformation(parameters);
|
|
197
199
|
Object.keys(desired).forEach((k) => delete desired[k]);
|
|
198
|
-
Object.assign(desired, transformed);
|
|
200
|
+
Object.assign(desired, transformed, coreParameters);
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
203
|
addDefaultValues(desired) {
|
|
@@ -86,7 +86,7 @@ export interface DefaultParameterSetting {
|
|
|
86
86
|
*
|
|
87
87
|
* @param input The original parameter value from the desired config.
|
|
88
88
|
*/
|
|
89
|
-
inputTransformation?: (input: any) => Promise<any> |
|
|
89
|
+
inputTransformation?: (input: any) => Promise<any> | any;
|
|
90
90
|
/**
|
|
91
91
|
* Customize the equality comparison for a parameter. This is used in the diffing algorithm for generating the plan.
|
|
92
92
|
* This value will override the pre-set equality function from the type. Return true if the desired value is
|
|
@@ -97,7 +97,7 @@ export interface DefaultParameterSetting {
|
|
|
97
97
|
*
|
|
98
98
|
* @return Return true if equal
|
|
99
99
|
*/
|
|
100
|
-
isEqual?: (desired: any, current: any) => boolean;
|
|
100
|
+
isEqual?: (desired: any, current: any) => Promise<boolean> | boolean;
|
|
101
101
|
/**
|
|
102
102
|
* Chose if the resource can be modified instead of re-created when there is a change to this parameter.
|
|
103
103
|
* Defaults to false (re-create).
|
|
@@ -123,7 +123,7 @@ export interface ArrayParameterSetting extends DefaultParameterSetting {
|
|
|
123
123
|
*
|
|
124
124
|
* @return Return true if desired is equivalent to current.
|
|
125
125
|
*/
|
|
126
|
-
isElementEqual?: (desired: any, current: any) => boolean;
|
|
126
|
+
isElementEqual?: (desired: any, current: any) => Promise<boolean> | boolean;
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
129
|
* Stateful parameter type specific settings. A stateful parameter is a sub-resource that can hold its own
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { SpawnOptions } from 'node:child_process';
|
|
3
|
+
export declare enum SpawnStatus {
|
|
4
|
+
SUCCESS = "success",
|
|
5
|
+
ERROR = "error"
|
|
6
|
+
}
|
|
7
|
+
export interface SpawnResult {
|
|
8
|
+
status: SpawnStatus;
|
|
9
|
+
data: string;
|
|
10
|
+
}
|
|
11
|
+
type CodifySpawnOptions = {
|
|
12
|
+
cwd?: string;
|
|
13
|
+
throws?: boolean;
|
|
14
|
+
requiresRoot?: boolean;
|
|
15
|
+
} & Omit<SpawnOptions, 'detached' | 'shell' | 'stdio'>;
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* @param cmd Command to run. Ex: `rm -rf`
|
|
19
|
+
* @param opts Standard options for node spawn. Additional argument:
|
|
20
|
+
* throws determines if a shell will throw a JS error. Defaults to true
|
|
21
|
+
*
|
|
22
|
+
* @see promiseSpawn
|
|
23
|
+
* @see spawn
|
|
24
|
+
*
|
|
25
|
+
* @returns SpawnResult { status: SUCCESS | ERROR; data: string }
|
|
26
|
+
*/
|
|
27
|
+
export declare function $(cmd: string, opts?: CodifySpawnOptions): Promise<SpawnResult>;
|
|
28
|
+
export declare function isDebug(): boolean;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Ajv } from 'ajv';
|
|
2
|
+
import { MessageCmd, SudoRequestResponseDataSchema } from 'codify-schemas';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { SudoError } from '../errors.js';
|
|
5
|
+
const ajv = new Ajv({
|
|
6
|
+
strict: true,
|
|
7
|
+
});
|
|
8
|
+
const validateSudoRequestResponse = ajv.compile(SudoRequestResponseDataSchema);
|
|
9
|
+
export var SpawnStatus;
|
|
10
|
+
(function (SpawnStatus) {
|
|
11
|
+
SpawnStatus["SUCCESS"] = "success";
|
|
12
|
+
SpawnStatus["ERROR"] = "error";
|
|
13
|
+
})(SpawnStatus || (SpawnStatus = {}));
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param cmd Command to run. Ex: `rm -rf`
|
|
17
|
+
* @param opts Standard options for node spawn. Additional argument:
|
|
18
|
+
* throws determines if a shell will throw a JS error. Defaults to true
|
|
19
|
+
*
|
|
20
|
+
* @see promiseSpawn
|
|
21
|
+
* @see spawn
|
|
22
|
+
*
|
|
23
|
+
* @returns SpawnResult { status: SUCCESS | ERROR; data: string }
|
|
24
|
+
*/
|
|
25
|
+
export async function $(cmd, opts) {
|
|
26
|
+
const throws = opts?.throws ?? true;
|
|
27
|
+
console.log(`Running command: ${cmd}`);
|
|
28
|
+
try {
|
|
29
|
+
// TODO: Need to benchmark the effects of using sh vs zsh for shell.
|
|
30
|
+
// Seems like zsh shells run slower
|
|
31
|
+
let result;
|
|
32
|
+
if (!opts?.requiresRoot) {
|
|
33
|
+
result = await internalSpawn(cmd, opts ?? {});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result = await externalSpawnWithSudo(cmd, opts);
|
|
37
|
+
}
|
|
38
|
+
if (result.status !== SpawnStatus.SUCCESS) {
|
|
39
|
+
throw new Error(result.data);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (isDebug()) {
|
|
45
|
+
console.error(`CodifySpawn error for command ${cmd}`, error);
|
|
46
|
+
}
|
|
47
|
+
if (error.message?.startsWith('sudo:')) {
|
|
48
|
+
throw new SudoError(cmd);
|
|
49
|
+
}
|
|
50
|
+
if (throws) {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
if (error instanceof Error) {
|
|
54
|
+
return {
|
|
55
|
+
status: SpawnStatus.ERROR,
|
|
56
|
+
data: error.message,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
status: SpawnStatus.ERROR,
|
|
61
|
+
data: error + '',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function internalSpawn(cmd, opts) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const output = [];
|
|
68
|
+
// Source start up shells to emulate a users environment vs. a non-interactive non-login shell script
|
|
69
|
+
// Ignore all stdin
|
|
70
|
+
const _process = spawn(`source ~/.zshrc; ${cmd}`, [], {
|
|
71
|
+
...opts,
|
|
72
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
73
|
+
shell: 'zsh',
|
|
74
|
+
});
|
|
75
|
+
const { stdout, stderr, stdin } = _process;
|
|
76
|
+
stdout.setEncoding('utf8');
|
|
77
|
+
stderr.setEncoding('utf8');
|
|
78
|
+
stdout.on('data', (data) => {
|
|
79
|
+
output.push(data.toString());
|
|
80
|
+
});
|
|
81
|
+
stderr.on('data', (data) => {
|
|
82
|
+
output.push(data.toString());
|
|
83
|
+
});
|
|
84
|
+
_process.on('error', (data) => {
|
|
85
|
+
});
|
|
86
|
+
// please node that this is not a full replacement for 'inherit'
|
|
87
|
+
// the child process can and will detect if stdout is a pty and change output based on it
|
|
88
|
+
// the terminal context is lost & ansi information (coloring) etc will be lost
|
|
89
|
+
if (stdout && stderr) {
|
|
90
|
+
stdout.pipe(process.stdout);
|
|
91
|
+
stderr.pipe(process.stderr);
|
|
92
|
+
}
|
|
93
|
+
_process.on('close', (code) => {
|
|
94
|
+
resolve({
|
|
95
|
+
status: code === 0 ? SpawnStatus.SUCCESS : SpawnStatus.ERROR,
|
|
96
|
+
data: output.join('\n'),
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function externalSpawnWithSudo(cmd, opts) {
|
|
102
|
+
return await new Promise((resolve) => {
|
|
103
|
+
const listener = (data) => {
|
|
104
|
+
if (data.cmd === MessageCmd.SUDO_REQUEST + '_Response') {
|
|
105
|
+
process.removeListener('message', listener);
|
|
106
|
+
if (!validateSudoRequestResponse(data.data)) {
|
|
107
|
+
throw new Error(`Invalid response for sudo request: ${JSON.stringify(validateSudoRequestResponse.errors, null, 2)}`);
|
|
108
|
+
}
|
|
109
|
+
resolve(data.data);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
process.on('message', listener);
|
|
113
|
+
process.send({
|
|
114
|
+
cmd: MessageCmd.SUDO_REQUEST,
|
|
115
|
+
data: {
|
|
116
|
+
command: cmd,
|
|
117
|
+
options: opts ?? {},
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
export function isDebug() {
|
|
123
|
+
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
|
|
124
|
+
}
|
package/package.json
CHANGED
package/src/plan/change-set.ts
CHANGED
|
@@ -85,12 +85,12 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
85
85
|
return new ChangeSet(ResourceOperation.DESTROY, parameterChanges);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
static calculateModification<T extends StringIndexedObject>(
|
|
88
|
+
static async calculateModification<T extends StringIndexedObject>(
|
|
89
89
|
desired: Partial<T>,
|
|
90
90
|
current: Partial<T>,
|
|
91
91
|
parameterSettings: Partial<Record<keyof T, ParameterSetting>> = {},
|
|
92
|
-
): ChangeSet<T
|
|
93
|
-
const pc = ChangeSet.calculateParameterChanges(desired, current, parameterSettings);
|
|
92
|
+
): Promise<ChangeSet<T>> {
|
|
93
|
+
const pc = await ChangeSet.calculateParameterChanges(desired, current, parameterSettings);
|
|
94
94
|
|
|
95
95
|
const statefulParameterKeys = new Set(
|
|
96
96
|
Object.entries(parameterSettings)
|
|
@@ -116,11 +116,21 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
116
116
|
return new ChangeSet<T>(resourceOperation, pc);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Calculates the differences between the desired and current parameters,
|
|
121
|
+
* and returns a list of parameter changes that describe what needs to be added,
|
|
122
|
+
* removed, or modified to match the desired state.
|
|
123
|
+
*
|
|
124
|
+
* @param {Partial<T>} desiredParameters - The desired target state of the parameters.
|
|
125
|
+
* @param {Partial<T>} currentParameters - The current state of the parameters.
|
|
126
|
+
* @param {Partial<Record<keyof T, ParameterSetting>>} [parameterOptions] - Optional settings used when comparing parameters.
|
|
127
|
+
* @return {ParameterChange<T>[]} A list of changes required to transition from the current state to the desired state.
|
|
128
|
+
*/
|
|
129
|
+
private static async calculateParameterChanges<T extends StringIndexedObject>(
|
|
120
130
|
desiredParameters: Partial<T>,
|
|
121
131
|
currentParameters: Partial<T>,
|
|
122
132
|
parameterOptions?: Partial<Record<keyof T, ParameterSetting>>,
|
|
123
|
-
): ParameterChange<T>[] {
|
|
133
|
+
): Promise<ParameterChange<T>[]> {
|
|
124
134
|
const parameterChangeSet = new Array<ParameterChange<T>>();
|
|
125
135
|
|
|
126
136
|
// Filter out null and undefined values or else the diff below will not work
|
|
@@ -145,7 +155,7 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
145
155
|
continue;
|
|
146
156
|
}
|
|
147
157
|
|
|
148
|
-
if (!ChangeSet.isSame(desired[k], current[k], parameterOptions?.[k])) {
|
|
158
|
+
if (!await ChangeSet.isSame(desired[k], current[k], parameterOptions?.[k])) {
|
|
149
159
|
parameterChangeSet.push({
|
|
150
160
|
name: k,
|
|
151
161
|
previousValue: v ?? null,
|
|
@@ -200,11 +210,11 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
200
210
|
return orderOfOperations[Math.max(indexPrev, indexNext)];
|
|
201
211
|
}
|
|
202
212
|
|
|
203
|
-
private static isSame(
|
|
213
|
+
private static async isSame(
|
|
204
214
|
desired: unknown,
|
|
205
215
|
current: unknown,
|
|
206
216
|
setting?: ParameterSetting,
|
|
207
|
-
): boolean {
|
|
217
|
+
): Promise<boolean> {
|
|
208
218
|
switch (setting?.type) {
|
|
209
219
|
case 'stateful': {
|
|
210
220
|
const statefulSetting = (setting as StatefulParameterSetting).definition.getSettings()
|
package/src/plan/plan.ts
CHANGED
|
@@ -105,14 +105,14 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
105
105
|
return this.coreParameters.type
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
static calculate<T extends StringIndexedObject>(params: {
|
|
108
|
+
static async calculate<T extends StringIndexedObject>(params: {
|
|
109
109
|
desiredParameters: Partial<T> | null,
|
|
110
110
|
currentParametersArray: Partial<T>[] | null,
|
|
111
111
|
stateParameters: Partial<T> | null,
|
|
112
112
|
coreParameters: ResourceConfig,
|
|
113
113
|
settings: ParsedResourceSettings<T>,
|
|
114
114
|
statefulMode: boolean,
|
|
115
|
-
}): Plan<T
|
|
115
|
+
}): Promise<Plan<T>> {
|
|
116
116
|
const {
|
|
117
117
|
desiredParameters,
|
|
118
118
|
currentParametersArray,
|
|
@@ -166,7 +166,7 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// NO-OP, MODIFY or RE-CREATE
|
|
169
|
-
const changeSet = ChangeSet.calculateModification(
|
|
169
|
+
const changeSet = await ChangeSet.calculateModification(
|
|
170
170
|
desiredParameters!,
|
|
171
171
|
filteredCurrentParameters!,
|
|
172
172
|
settings.parameterSettings,
|
|
@@ -154,7 +154,7 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
|
|
|
154
154
|
// The rest of the types have defaults set already
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
private resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => boolean {
|
|
157
|
+
private resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => Promise<boolean> | boolean {
|
|
158
158
|
if (parameter.type === 'array') {
|
|
159
159
|
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter as ArrayParameterSetting)
|
|
160
160
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { ParameterChange } from '../plan/change-set.js';
|
|
11
11
|
import { Plan } from '../plan/plan.js';
|
|
12
12
|
import { CreatePlan, DestroyPlan, ModifyPlan } from '../plan/plan-types.js';
|
|
13
|
+
import { splitUserConfig } from '../utils/utils.js';
|
|
13
14
|
import { ConfigParser } from './config-parser.js';
|
|
14
15
|
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
15
16
|
import { Resource } from './resource.js';
|
|
@@ -250,7 +251,7 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
250
251
|
}
|
|
251
252
|
}
|
|
252
253
|
|
|
253
|
-
private async applyTransformParameters(desired: Partial<T> | null): Promise<void> {
|
|
254
|
+
private async applyTransformParameters(desired: Partial<T> & ResourceConfig | null): Promise<void> {
|
|
254
255
|
if (!desired) {
|
|
255
256
|
return;
|
|
256
257
|
}
|
|
@@ -264,9 +265,11 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
if (this.settings.inputTransformation) {
|
|
267
|
-
const
|
|
268
|
+
const { parameters, coreParameters } = splitUserConfig(desired);
|
|
269
|
+
|
|
270
|
+
const transformed = await this.settings.inputTransformation(parameters)
|
|
268
271
|
Object.keys(desired).forEach((k) => delete desired[k])
|
|
269
|
-
Object.assign(desired, transformed);
|
|
272
|
+
Object.assign(desired, transformed, coreParameters);
|
|
270
273
|
}
|
|
271
274
|
}
|
|
272
275
|
|
|
@@ -115,7 +115,7 @@ export interface DefaultParameterSetting {
|
|
|
115
115
|
*
|
|
116
116
|
* @param input The original parameter value from the desired config.
|
|
117
117
|
*/
|
|
118
|
-
inputTransformation?: (input: any) => Promise<any> |
|
|
118
|
+
inputTransformation?: (input: any) => Promise<any> | any;
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
121
|
* Customize the equality comparison for a parameter. This is used in the diffing algorithm for generating the plan.
|
|
@@ -127,7 +127,7 @@ export interface DefaultParameterSetting {
|
|
|
127
127
|
*
|
|
128
128
|
* @return Return true if equal
|
|
129
129
|
*/
|
|
130
|
-
isEqual?: (desired: any, current: any) => boolean;
|
|
130
|
+
isEqual?: (desired: any, current: any) => Promise<boolean> | boolean;
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Chose if the resource can be modified instead of re-created when there is a change to this parameter.
|
|
@@ -156,7 +156,7 @@ export interface ArrayParameterSetting extends DefaultParameterSetting {
|
|
|
156
156
|
*
|
|
157
157
|
* @return Return true if desired is equivalent to current.
|
|
158
158
|
*/
|
|
159
|
-
isElementEqual?: (desired: any, current: any) => boolean
|
|
159
|
+
isElementEqual?: (desired: any, current: any) => Promise<boolean> | boolean;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|