codify-plugin-lib 1.0.177 → 1.0.178
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/messages/sender.d.ts +1 -0
- package/dist/messages/sender.js +10 -0
- package/dist/resource/resource-controller.d.ts +1 -1
- package/dist/resource/resource-controller.js +10 -10
- package/package.json +2 -2
- package/src/messages/sender.ts +13 -0
- package/src/resource/resource-controller.ts +11 -11
- package/dist/entities/change-set.d.ts +0 -24
- package/dist/entities/change-set.js +0 -152
- package/dist/entities/errors.d.ts +0 -4
- package/dist/entities/errors.js +0 -7
- package/dist/entities/plan-types.d.ts +0 -25
- package/dist/entities/plan-types.js +0 -1
- package/dist/entities/plan.d.ts +0 -15
- package/dist/entities/plan.js +0 -127
- package/dist/entities/plugin.d.ts +0 -16
- package/dist/entities/plugin.js +0 -80
- package/dist/entities/resource-options.d.ts +0 -31
- package/dist/entities/resource-options.js +0 -76
- package/dist/entities/resource-types.d.ts +0 -11
- package/dist/entities/resource-types.js +0 -1
- package/dist/entities/resource.d.ts +0 -42
- package/dist/entities/resource.js +0 -303
- package/dist/entities/stateful-parameter.d.ts +0 -29
- package/dist/entities/stateful-parameter.js +0 -46
- package/dist/entities/transform-parameter.d.ts +0 -4
- package/dist/entities/transform-parameter.js +0 -2
- package/dist/pty/vitest.config.d.ts +0 -2
- package/dist/pty/vitest.config.js +0 -11
- package/dist/resource/stateful-parameter.d.ts +0 -165
- package/dist/resource/stateful-parameter.js +0 -94
- package/dist/utils/spawn-2.d.ts +0 -5
- package/dist/utils/spawn-2.js +0 -7
- package/dist/utils/spawn.d.ts +0 -29
- package/dist/utils/spawn.js +0 -124
package/dist/entities/plugin.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { splitUserConfig } from '../utils/utils.js';
|
|
2
|
-
import { Plan } from './plan.js';
|
|
3
|
-
export class Plugin {
|
|
4
|
-
name;
|
|
5
|
-
resources;
|
|
6
|
-
planStorage;
|
|
7
|
-
static create(name, resources) {
|
|
8
|
-
const resourceMap = new Map(resources.map((r) => [r.typeId, r]));
|
|
9
|
-
return new Plugin(name, resourceMap);
|
|
10
|
-
}
|
|
11
|
-
constructor(name, resources) {
|
|
12
|
-
this.name = name;
|
|
13
|
-
this.resources = resources;
|
|
14
|
-
this.planStorage = new Map();
|
|
15
|
-
}
|
|
16
|
-
async initialize() {
|
|
17
|
-
for (const resource of this.resources.values()) {
|
|
18
|
-
await resource.onInitialize();
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
resourceDefinitions: [...this.resources.values()]
|
|
22
|
-
.map((r) => ({
|
|
23
|
-
dependencies: r.dependencies,
|
|
24
|
-
type: r.typeId,
|
|
25
|
-
}))
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
async validate(data) {
|
|
29
|
-
const validationResults = [];
|
|
30
|
-
for (const config of data.configs) {
|
|
31
|
-
if (!this.resources.has(config.type)) {
|
|
32
|
-
throw new Error(`Resource type not found: ${config.type}`);
|
|
33
|
-
}
|
|
34
|
-
const { parameters, resourceMetadata } = splitUserConfig(config);
|
|
35
|
-
const validation = await this.resources
|
|
36
|
-
.get(config.type)
|
|
37
|
-
.validate(parameters, resourceMetadata);
|
|
38
|
-
validationResults.push(validation);
|
|
39
|
-
}
|
|
40
|
-
await this.crossValidateResources(data.configs);
|
|
41
|
-
return {
|
|
42
|
-
resourceValidations: validationResults
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
async plan(data) {
|
|
46
|
-
const type = data.desired?.type ?? data.state?.type;
|
|
47
|
-
if (!type || !this.resources.has(type)) {
|
|
48
|
-
throw new Error(`Resource type not found: ${type}`);
|
|
49
|
-
}
|
|
50
|
-
const plan = await this.resources.get(type).plan(data.desired ?? null, data.state ?? null, data.isStateful);
|
|
51
|
-
this.planStorage.set(plan.id, plan);
|
|
52
|
-
return plan.toResponse();
|
|
53
|
-
}
|
|
54
|
-
async apply(data) {
|
|
55
|
-
if (!data.planId && !data.plan) {
|
|
56
|
-
throw new Error('For applies either plan or planId must be supplied');
|
|
57
|
-
}
|
|
58
|
-
const plan = this.resolvePlan(data);
|
|
59
|
-
const resource = this.resources.get(plan.getResourceType());
|
|
60
|
-
if (!resource) {
|
|
61
|
-
throw new Error('Malformed plan with resource that cannot be found');
|
|
62
|
-
}
|
|
63
|
-
await resource.apply(plan);
|
|
64
|
-
}
|
|
65
|
-
resolvePlan(data) {
|
|
66
|
-
const { plan: planRequest, planId } = data;
|
|
67
|
-
if (planId) {
|
|
68
|
-
if (!this.planStorage.has(planId)) {
|
|
69
|
-
throw new Error(`Plan with id: ${planId} was not found`);
|
|
70
|
-
}
|
|
71
|
-
return this.planStorage.get(planId);
|
|
72
|
-
}
|
|
73
|
-
if (!planRequest?.resourceType || !this.resources.has(planRequest.resourceType)) {
|
|
74
|
-
throw new Error('Malformed plan. Resource type must be supplied or resource type was not found');
|
|
75
|
-
}
|
|
76
|
-
const resource = this.resources.get(planRequest.resourceType);
|
|
77
|
-
return Plan.fromResponse(planRequest, resource.defaultValues);
|
|
78
|
-
}
|
|
79
|
-
async crossValidateResources(configs) { }
|
|
80
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { StringIndexedObject } from 'codify-schemas';
|
|
2
|
-
import { ParameterOptions } from './plan-types.js';
|
|
3
|
-
import { ResourceParameterOptions } from './resource-types.js';
|
|
4
|
-
import { StatefulParameter } from './stateful-parameter.js';
|
|
5
|
-
import { TransformParameter } from './transform-parameter.js';
|
|
6
|
-
export interface ResourceOptions<T extends StringIndexedObject> {
|
|
7
|
-
callStatefulParameterRemoveOnDestroy?: boolean;
|
|
8
|
-
dependencies?: string[];
|
|
9
|
-
parameterOptions?: Partial<Record<keyof T, ResourceParameterOptions | ResourceStatefulParameterOptions<T> | ResourceTransformParameterOptions<T>>>;
|
|
10
|
-
schema?: unknown;
|
|
11
|
-
type: string;
|
|
12
|
-
}
|
|
13
|
-
export interface ResourceStatefulParameterOptions<T extends StringIndexedObject> {
|
|
14
|
-
order?: number;
|
|
15
|
-
statefulParameter: StatefulParameter<T, T[keyof T]>;
|
|
16
|
-
}
|
|
17
|
-
export interface ResourceTransformParameterOptions<T extends StringIndexedObject> {
|
|
18
|
-
order?: number;
|
|
19
|
-
transformParameter: TransformParameter<T>;
|
|
20
|
-
}
|
|
21
|
-
export declare class ResourceOptionsParser<T extends StringIndexedObject> {
|
|
22
|
-
private options;
|
|
23
|
-
constructor(options: ResourceOptions<T>);
|
|
24
|
-
get statefulParameters(): Map<keyof T, StatefulParameter<T, T[keyof T]>>;
|
|
25
|
-
get transformParameters(): Map<keyof T, TransformParameter<T>>;
|
|
26
|
-
get resourceParameters(): Map<keyof T, ResourceParameterOptions>;
|
|
27
|
-
get changeSetParameterOptions(): Record<keyof T, ParameterOptions>;
|
|
28
|
-
get defaultValues(): Partial<Record<keyof T, unknown>>;
|
|
29
|
-
get statefulParameterOrder(): Map<keyof T, number>;
|
|
30
|
-
get transformParameterOrder(): Map<keyof T, number>;
|
|
31
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
export class ResourceOptionsParser {
|
|
2
|
-
options;
|
|
3
|
-
constructor(options) {
|
|
4
|
-
this.options = options;
|
|
5
|
-
}
|
|
6
|
-
get statefulParameters() {
|
|
7
|
-
const statefulParameters = Object.entries(this.options.parameterOptions ?? {})
|
|
8
|
-
.filter(([, p]) => p?.hasOwnProperty('statefulParameter'))
|
|
9
|
-
.map(([k, v]) => [k, v])
|
|
10
|
-
.map(([k, v]) => [k, v.statefulParameter]);
|
|
11
|
-
return new Map(statefulParameters);
|
|
12
|
-
}
|
|
13
|
-
get transformParameters() {
|
|
14
|
-
const transformParameters = Object.entries(this.options.parameterOptions ?? {})
|
|
15
|
-
.filter(([, p]) => p?.hasOwnProperty('transformParameter'))
|
|
16
|
-
.map(([k, v]) => [k, v])
|
|
17
|
-
.map(([k, v]) => [k, v.transformParameter]);
|
|
18
|
-
return new Map(transformParameters);
|
|
19
|
-
}
|
|
20
|
-
get resourceParameters() {
|
|
21
|
-
const resourceParameters = Object.entries(this.options.parameterOptions ?? {})
|
|
22
|
-
.filter(([, p]) => !(p?.hasOwnProperty('statefulParameter') || p?.hasOwnProperty('transformParameter')))
|
|
23
|
-
.map(([k, v]) => [k, v]);
|
|
24
|
-
return new Map(resourceParameters);
|
|
25
|
-
}
|
|
26
|
-
get changeSetParameterOptions() {
|
|
27
|
-
const resourceParameters = Object.fromEntries([...this.resourceParameters.entries()]
|
|
28
|
-
.map(([name, value]) => ([name, { ...value, isStatefulParameter: false }])));
|
|
29
|
-
const statefulParameters = [...this.statefulParameters.entries()]
|
|
30
|
-
?.reduce((obj, sp) => ({
|
|
31
|
-
...obj,
|
|
32
|
-
[sp[0]]: {
|
|
33
|
-
...sp[1].options,
|
|
34
|
-
isStatefulParameter: true,
|
|
35
|
-
}
|
|
36
|
-
}), {});
|
|
37
|
-
return {
|
|
38
|
-
...resourceParameters,
|
|
39
|
-
...statefulParameters,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
get defaultValues() {
|
|
43
|
-
if (!this.options.parameterOptions) {
|
|
44
|
-
return {};
|
|
45
|
-
}
|
|
46
|
-
return Object.fromEntries([...this.resourceParameters.entries()]
|
|
47
|
-
.filter(([, rp]) => rp.default !== undefined)
|
|
48
|
-
.map(([name, rp]) => [name, rp.default]));
|
|
49
|
-
}
|
|
50
|
-
get statefulParameterOrder() {
|
|
51
|
-
const entries = Object.entries(this.options.parameterOptions ?? {})
|
|
52
|
-
.filter(([, v]) => v?.hasOwnProperty('statefulParameter'))
|
|
53
|
-
.map(([k, v]) => [k, v]);
|
|
54
|
-
const orderedEntries = entries.filter(([, v]) => v.order !== undefined);
|
|
55
|
-
const unorderedEntries = entries.filter(([, v]) => v.order === undefined);
|
|
56
|
-
orderedEntries.sort((a, b) => a[1].order - b[1].order);
|
|
57
|
-
const resultArray = [
|
|
58
|
-
...orderedEntries.map(([k]) => k),
|
|
59
|
-
...unorderedEntries.map(([k]) => k)
|
|
60
|
-
];
|
|
61
|
-
return new Map(resultArray.map((key, idx) => [key, idx]));
|
|
62
|
-
}
|
|
63
|
-
get transformParameterOrder() {
|
|
64
|
-
const entries = Object.entries(this.options.parameterOptions ?? {})
|
|
65
|
-
.filter(([, v]) => v?.hasOwnProperty('transformParameter'))
|
|
66
|
-
.map(([k, v]) => [k, v]);
|
|
67
|
-
const orderedEntries = entries.filter(([, v]) => v.order !== undefined);
|
|
68
|
-
const unorderedEntries = entries.filter(([, v]) => v.order === undefined);
|
|
69
|
-
orderedEntries.sort((a, b) => a[1].order - b[1].order);
|
|
70
|
-
const resultArray = [
|
|
71
|
-
...orderedEntries.map(([k]) => k),
|
|
72
|
-
...unorderedEntries.map(([k]) => k)
|
|
73
|
-
];
|
|
74
|
-
return new Map(resultArray.map((key, idx) => [key, idx]));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type ErrorMessage = string;
|
|
2
|
-
export interface ResourceParameterOptions {
|
|
3
|
-
default?: unknown;
|
|
4
|
-
isEqual?: (desired: any, current: any) => boolean;
|
|
5
|
-
modifyOnChange?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export interface ResourceDefinition {
|
|
8
|
-
[x: string]: {
|
|
9
|
-
type: string;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Ajv, ValidateFunction } from 'ajv';
|
|
2
|
-
import { ResourceConfig, StringIndexedObject, ValidateResponseData } from 'codify-schemas';
|
|
3
|
-
import { ParameterChange } from './change-set.js';
|
|
4
|
-
import { Plan } from './plan.js';
|
|
5
|
-
import { CreatePlan, DestroyPlan, ModifyPlan, ParameterOptions } from './plan-types.js';
|
|
6
|
-
import { ResourceOptions } from './resource-options.js';
|
|
7
|
-
import { ResourceParameterOptions } from './resource-types.js';
|
|
8
|
-
import { StatefulParameter } from './stateful-parameter.js';
|
|
9
|
-
import { TransformParameter } from './transform-parameter.js';
|
|
10
|
-
export declare abstract class Resource<T extends StringIndexedObject> {
|
|
11
|
-
readonly typeId: string;
|
|
12
|
-
readonly statefulParameters: Map<keyof T, StatefulParameter<T, T[keyof T]>>;
|
|
13
|
-
readonly transformParameters: Map<keyof T, TransformParameter<T>>;
|
|
14
|
-
readonly resourceParameters: Map<keyof T, ResourceParameterOptions>;
|
|
15
|
-
readonly statefulParameterOrder: Map<keyof T, number>;
|
|
16
|
-
readonly transformParameterOrder: Map<keyof T, number>;
|
|
17
|
-
readonly dependencies: string[];
|
|
18
|
-
readonly parameterOptions: Record<keyof T, ParameterOptions>;
|
|
19
|
-
readonly options: ResourceOptions<T>;
|
|
20
|
-
readonly defaultValues: Partial<Record<keyof T, unknown>>;
|
|
21
|
-
protected ajv?: Ajv;
|
|
22
|
-
protected schemaValidator?: ValidateFunction;
|
|
23
|
-
protected constructor(options: ResourceOptions<T>);
|
|
24
|
-
onInitialize(): Promise<void>;
|
|
25
|
-
validate(parameters: Partial<T>, resourceMetaData: ResourceConfig): Promise<ValidateResponseData['resourceValidations'][0]>;
|
|
26
|
-
plan(desiredConfig: Partial<T> & ResourceConfig | null, currentConfig?: Partial<T> & ResourceConfig | null, statefulMode?: boolean): Promise<Plan<T>>;
|
|
27
|
-
apply(plan: Plan<T>): Promise<void>;
|
|
28
|
-
private _applyCreate;
|
|
29
|
-
private _applyModify;
|
|
30
|
-
private _applyDestroy;
|
|
31
|
-
private validateRefreshResults;
|
|
32
|
-
private applyTransformParameters;
|
|
33
|
-
private addDefaultValues;
|
|
34
|
-
private refreshNonStatefulParameters;
|
|
35
|
-
private refreshStatefulParameters;
|
|
36
|
-
private validatePlanInputs;
|
|
37
|
-
customValidation(parameters: Partial<T>): Promise<void>;
|
|
38
|
-
abstract refresh(parameters: Partial<T>): Promise<Partial<T> | null>;
|
|
39
|
-
abstract applyCreate(plan: CreatePlan<T>): Promise<void>;
|
|
40
|
-
applyModify(pc: ParameterChange<T>, plan: ModifyPlan<T>): Promise<void>;
|
|
41
|
-
abstract applyDestroy(plan: DestroyPlan<T>): Promise<void>;
|
|
42
|
-
}
|
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { Ajv } from 'ajv';
|
|
2
|
-
import { ParameterOperation, ResourceOperation, } from 'codify-schemas';
|
|
3
|
-
import { setsEqual, splitUserConfig } from '../utils/utils.js';
|
|
4
|
-
import { Plan } from './plan.js';
|
|
5
|
-
import { ResourceOptionsParser } from './resource-options.js';
|
|
6
|
-
export class Resource {
|
|
7
|
-
typeId;
|
|
8
|
-
statefulParameters;
|
|
9
|
-
transformParameters;
|
|
10
|
-
resourceParameters;
|
|
11
|
-
statefulParameterOrder;
|
|
12
|
-
transformParameterOrder;
|
|
13
|
-
dependencies;
|
|
14
|
-
parameterOptions;
|
|
15
|
-
options;
|
|
16
|
-
defaultValues;
|
|
17
|
-
ajv;
|
|
18
|
-
schemaValidator;
|
|
19
|
-
constructor(options) {
|
|
20
|
-
this.typeId = options.type;
|
|
21
|
-
this.dependencies = options.dependencies ?? [];
|
|
22
|
-
this.options = options;
|
|
23
|
-
if (this.options.schema) {
|
|
24
|
-
this.ajv = new Ajv({
|
|
25
|
-
allErrors: true,
|
|
26
|
-
strict: true,
|
|
27
|
-
strictRequired: false,
|
|
28
|
-
});
|
|
29
|
-
this.schemaValidator = this.ajv.compile(this.options.schema);
|
|
30
|
-
}
|
|
31
|
-
const parser = new ResourceOptionsParser(options);
|
|
32
|
-
this.statefulParameters = parser.statefulParameters;
|
|
33
|
-
this.transformParameters = parser.transformParameters;
|
|
34
|
-
this.resourceParameters = parser.resourceParameters;
|
|
35
|
-
this.parameterOptions = parser.changeSetParameterOptions;
|
|
36
|
-
this.defaultValues = parser.defaultValues;
|
|
37
|
-
this.statefulParameterOrder = parser.statefulParameterOrder;
|
|
38
|
-
this.transformParameterOrder = parser.transformParameterOrder;
|
|
39
|
-
}
|
|
40
|
-
async onInitialize() { }
|
|
41
|
-
async validate(parameters, resourceMetaData) {
|
|
42
|
-
if (this.schemaValidator) {
|
|
43
|
-
const isValid = this.schemaValidator(parameters);
|
|
44
|
-
if (!isValid) {
|
|
45
|
-
return {
|
|
46
|
-
isValid: false,
|
|
47
|
-
resourceName: resourceMetaData.name,
|
|
48
|
-
resourceType: resourceMetaData.type,
|
|
49
|
-
schemaValidationErrors: this.schemaValidator?.errors ?? [],
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
let isValid = true;
|
|
54
|
-
let customValidationErrorMessage;
|
|
55
|
-
try {
|
|
56
|
-
await this.customValidation(parameters);
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
isValid = false;
|
|
60
|
-
customValidationErrorMessage = error.message;
|
|
61
|
-
}
|
|
62
|
-
if (!isValid) {
|
|
63
|
-
return {
|
|
64
|
-
customValidationErrorMessage,
|
|
65
|
-
isValid: false,
|
|
66
|
-
resourceName: resourceMetaData.name,
|
|
67
|
-
resourceType: resourceMetaData.type,
|
|
68
|
-
schemaValidationErrors: this.schemaValidator?.errors ?? [],
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
isValid: true,
|
|
73
|
-
resourceName: resourceMetaData.name,
|
|
74
|
-
resourceType: resourceMetaData.type,
|
|
75
|
-
schemaValidationErrors: [],
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async plan(desiredConfig, currentConfig = null, statefulMode = false) {
|
|
79
|
-
this.validatePlanInputs(desiredConfig, currentConfig, statefulMode);
|
|
80
|
-
const planOptions = {
|
|
81
|
-
parameterOptions: this.parameterOptions,
|
|
82
|
-
statefulMode,
|
|
83
|
-
};
|
|
84
|
-
this.addDefaultValues(desiredConfig);
|
|
85
|
-
await this.applyTransformParameters(desiredConfig);
|
|
86
|
-
const parsedConfig = new ConfigParser(desiredConfig, currentConfig, this.statefulParameters, this.transformParameters);
|
|
87
|
-
const { desiredParameters, nonStatefulParameters, resourceMetadata, statefulParameters, } = parsedConfig;
|
|
88
|
-
const currentParameters = await this.refreshNonStatefulParameters(nonStatefulParameters);
|
|
89
|
-
if (currentParameters === null || currentParameters === undefined) {
|
|
90
|
-
return Plan.create(desiredParameters, null, resourceMetadata, planOptions);
|
|
91
|
-
}
|
|
92
|
-
const statefulCurrentParameters = await this.refreshStatefulParameters(statefulParameters, planOptions.statefulMode);
|
|
93
|
-
return Plan.create(desiredParameters, { ...currentParameters, ...statefulCurrentParameters }, resourceMetadata, planOptions);
|
|
94
|
-
}
|
|
95
|
-
async apply(plan) {
|
|
96
|
-
if (plan.getResourceType() !== this.typeId) {
|
|
97
|
-
throw new Error(`Internal error: Plan set to wrong resource during apply. Expected ${this.typeId} but got: ${plan.getResourceType()}`);
|
|
98
|
-
}
|
|
99
|
-
switch (plan.changeSet.operation) {
|
|
100
|
-
case ResourceOperation.CREATE: {
|
|
101
|
-
return this._applyCreate(plan);
|
|
102
|
-
}
|
|
103
|
-
case ResourceOperation.MODIFY: {
|
|
104
|
-
return this._applyModify(plan);
|
|
105
|
-
}
|
|
106
|
-
case ResourceOperation.RECREATE: {
|
|
107
|
-
await this._applyDestroy(plan);
|
|
108
|
-
return this._applyCreate(plan);
|
|
109
|
-
}
|
|
110
|
-
case ResourceOperation.DESTROY: {
|
|
111
|
-
return this._applyDestroy(plan);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
async _applyCreate(plan) {
|
|
116
|
-
await this.applyCreate(plan);
|
|
117
|
-
const statefulParameterChanges = plan.changeSet.parameterChanges
|
|
118
|
-
.filter((pc) => this.statefulParameters.has(pc.name))
|
|
119
|
-
.sort((a, b) => this.statefulParameterOrder.get(a.name) - this.statefulParameterOrder.get(b.name));
|
|
120
|
-
for (const parameterChange of statefulParameterChanges) {
|
|
121
|
-
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
122
|
-
await statefulParameter.applyAdd(parameterChange.newValue, plan);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
async _applyModify(plan) {
|
|
126
|
-
const parameterChanges = plan
|
|
127
|
-
.changeSet
|
|
128
|
-
.parameterChanges
|
|
129
|
-
.filter((c) => c.operation !== ParameterOperation.NOOP);
|
|
130
|
-
const statelessParameterChanges = parameterChanges
|
|
131
|
-
.filter((pc) => !this.statefulParameters.has(pc.name));
|
|
132
|
-
for (const pc of statelessParameterChanges) {
|
|
133
|
-
await this.applyModify(pc, plan);
|
|
134
|
-
}
|
|
135
|
-
const statefulParameterChanges = parameterChanges
|
|
136
|
-
.filter((pc) => this.statefulParameters.has(pc.name))
|
|
137
|
-
.sort((a, b) => this.statefulParameterOrder.get(a.name) - this.statefulParameterOrder.get(b.name));
|
|
138
|
-
for (const parameterChange of statefulParameterChanges) {
|
|
139
|
-
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
140
|
-
switch (parameterChange.operation) {
|
|
141
|
-
case ParameterOperation.ADD: {
|
|
142
|
-
await statefulParameter.applyAdd(parameterChange.newValue, plan);
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
case ParameterOperation.MODIFY: {
|
|
146
|
-
await statefulParameter.applyModify(parameterChange.newValue, parameterChange.previousValue, false, plan);
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
case ParameterOperation.REMOVE: {
|
|
150
|
-
await statefulParameter.applyRemove(parameterChange.previousValue, plan);
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
async _applyDestroy(plan) {
|
|
157
|
-
if (this.options.callStatefulParameterRemoveOnDestroy) {
|
|
158
|
-
const statefulParameterChanges = plan.changeSet.parameterChanges
|
|
159
|
-
.filter((pc) => this.statefulParameters.has(pc.name))
|
|
160
|
-
.sort((a, b) => this.statefulParameterOrder.get(a.name) - this.statefulParameterOrder.get(b.name));
|
|
161
|
-
for (const parameterChange of statefulParameterChanges) {
|
|
162
|
-
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
163
|
-
await statefulParameter.applyRemove(parameterChange.previousValue, plan);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
await this.applyDestroy(plan);
|
|
167
|
-
}
|
|
168
|
-
validateRefreshResults(refresh, desired) {
|
|
169
|
-
if (!refresh) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const desiredKeys = new Set(Object.keys(refresh));
|
|
173
|
-
const refreshKeys = new Set(Object.keys(refresh));
|
|
174
|
-
if (!setsEqual(desiredKeys, refreshKeys)) {
|
|
175
|
-
throw new Error(`Resource ${this.typeId}
|
|
176
|
-
refresh() must return back exactly the keys that were provided
|
|
177
|
-
Missing: ${[...desiredKeys].filter((k) => !refreshKeys.has(k))};
|
|
178
|
-
Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
async applyTransformParameters(desired) {
|
|
182
|
-
if (!desired) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
const transformParameters = [...this.transformParameters.entries()]
|
|
186
|
-
.sort(([keyA], [keyB]) => this.transformParameterOrder.get(keyA) - this.transformParameterOrder.get(keyB));
|
|
187
|
-
for (const [key, transformParameter] of transformParameters) {
|
|
188
|
-
if (desired[key] === undefined) {
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
const transformedValue = await transformParameter.transform(desired[key]);
|
|
192
|
-
if (Object.keys(transformedValue).some((k) => desired[k] !== undefined)) {
|
|
193
|
-
throw new Error(`Transform parameter ${key} is attempting to override existing values ${JSON.stringify(transformedValue, null, 2)}`);
|
|
194
|
-
}
|
|
195
|
-
delete desired[key];
|
|
196
|
-
for (const [tvKey, tvValue] of Object.entries(transformedValue)) {
|
|
197
|
-
desired[tvKey] = tvValue;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
addDefaultValues(desired) {
|
|
202
|
-
if (!desired) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
for (const [key, defaultValue] of Object.entries(this.defaultValues)) {
|
|
206
|
-
if (defaultValue !== undefined && desired[key] === undefined) {
|
|
207
|
-
desired[key] = defaultValue;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
async refreshNonStatefulParameters(resourceParameters) {
|
|
212
|
-
const currentParameters = await this.refresh(resourceParameters);
|
|
213
|
-
this.validateRefreshResults(currentParameters, resourceParameters);
|
|
214
|
-
return currentParameters;
|
|
215
|
-
}
|
|
216
|
-
async refreshStatefulParameters(statefulParametersConfig, isStatefulMode) {
|
|
217
|
-
const currentParameters = {};
|
|
218
|
-
const sortedEntries = Object.entries(statefulParametersConfig)
|
|
219
|
-
.sort(([key1], [key2]) => this.statefulParameterOrder.get(key1) - this.statefulParameterOrder.get(key2));
|
|
220
|
-
for (const [key, desiredValue] of sortedEntries) {
|
|
221
|
-
const statefulParameter = this.statefulParameters.get(key);
|
|
222
|
-
if (!statefulParameter) {
|
|
223
|
-
throw new Error(`Stateful parameter ${key} was not found`);
|
|
224
|
-
}
|
|
225
|
-
let currentValue = await statefulParameter.refresh(desiredValue ?? null);
|
|
226
|
-
if (Array.isArray(currentValue)
|
|
227
|
-
&& Array.isArray(desiredValue)
|
|
228
|
-
&& !isStatefulMode
|
|
229
|
-
&& !statefulParameter.options.disableStatelessModeArrayFiltering) {
|
|
230
|
-
currentValue = currentValue.filter((c) => desiredValue?.some((d) => {
|
|
231
|
-
const parameterOptions = statefulParameter.options;
|
|
232
|
-
if (parameterOptions && parameterOptions.isElementEqual) {
|
|
233
|
-
return parameterOptions.isElementEqual(d, c);
|
|
234
|
-
}
|
|
235
|
-
return d === c;
|
|
236
|
-
}));
|
|
237
|
-
}
|
|
238
|
-
currentParameters[key] = currentValue;
|
|
239
|
-
}
|
|
240
|
-
return currentParameters;
|
|
241
|
-
}
|
|
242
|
-
validatePlanInputs(desired, current, statefulMode) {
|
|
243
|
-
if (!desired && !current) {
|
|
244
|
-
throw new Error('Desired config and current config cannot both be missing');
|
|
245
|
-
}
|
|
246
|
-
if (!statefulMode && !desired) {
|
|
247
|
-
throw new Error('Desired config must be provided in non-stateful mode');
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
async customValidation(parameters) { }
|
|
251
|
-
;
|
|
252
|
-
async applyModify(pc, plan) { }
|
|
253
|
-
;
|
|
254
|
-
}
|
|
255
|
-
class ConfigParser {
|
|
256
|
-
desiredConfig;
|
|
257
|
-
currentConfig;
|
|
258
|
-
statefulParametersMap;
|
|
259
|
-
transformParametersMap;
|
|
260
|
-
constructor(desiredConfig, currentConfig, statefulParameters, transformParameters) {
|
|
261
|
-
this.desiredConfig = desiredConfig;
|
|
262
|
-
this.currentConfig = currentConfig;
|
|
263
|
-
this.statefulParametersMap = statefulParameters;
|
|
264
|
-
this.transformParametersMap = transformParameters;
|
|
265
|
-
}
|
|
266
|
-
get resourceMetadata() {
|
|
267
|
-
const desiredMetadata = this.desiredConfig ? splitUserConfig(this.desiredConfig).resourceMetadata : undefined;
|
|
268
|
-
const currentMetadata = this.currentConfig ? splitUserConfig(this.currentConfig).resourceMetadata : undefined;
|
|
269
|
-
if (!desiredMetadata && !currentMetadata) {
|
|
270
|
-
throw new Error(`Unable to parse resource metadata from ${this.desiredConfig}, ${this.currentConfig}`);
|
|
271
|
-
}
|
|
272
|
-
if (currentMetadata && desiredMetadata && (Object.keys(desiredMetadata).length !== Object.keys(currentMetadata).length
|
|
273
|
-
|| Object.entries(desiredMetadata).some(([key, value]) => currentMetadata[key] !== value))) {
|
|
274
|
-
throw new Error(`The metadata for the current config does not match the desired config.
|
|
275
|
-
Desired metadata:
|
|
276
|
-
${JSON.stringify(desiredMetadata, null, 2)}
|
|
277
|
-
|
|
278
|
-
Current metadata:
|
|
279
|
-
${JSON.stringify(currentMetadata, null, 2)}`);
|
|
280
|
-
}
|
|
281
|
-
return desiredMetadata ?? currentMetadata;
|
|
282
|
-
}
|
|
283
|
-
get desiredParameters() {
|
|
284
|
-
if (!this.desiredConfig) {
|
|
285
|
-
return null;
|
|
286
|
-
}
|
|
287
|
-
const { parameters } = splitUserConfig(this.desiredConfig);
|
|
288
|
-
return parameters;
|
|
289
|
-
}
|
|
290
|
-
get parameters() {
|
|
291
|
-
const desiredParameters = this.desiredConfig ? splitUserConfig(this.desiredConfig).parameters : undefined;
|
|
292
|
-
const currentParameters = this.currentConfig ? splitUserConfig(this.currentConfig).parameters : undefined;
|
|
293
|
-
return { ...desiredParameters, ...currentParameters };
|
|
294
|
-
}
|
|
295
|
-
get nonStatefulParameters() {
|
|
296
|
-
const { parameters } = this;
|
|
297
|
-
return Object.fromEntries(Object.entries(parameters).filter(([key]) => !(this.statefulParametersMap.has(key) || this.transformParametersMap.has(key))));
|
|
298
|
-
}
|
|
299
|
-
get statefulParameters() {
|
|
300
|
-
const { parameters } = this;
|
|
301
|
-
return Object.fromEntries(Object.entries(parameters).filter(([key]) => this.statefulParametersMap.has(key)));
|
|
302
|
-
}
|
|
303
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Plan } from './plan.js';
|
|
2
|
-
import { StringIndexedObject } from 'codify-schemas';
|
|
3
|
-
export interface StatefulParameterOptions<V> {
|
|
4
|
-
isEqual?: (desired: any, current: any) => boolean;
|
|
5
|
-
disableStatelessModeArrayFiltering?: boolean;
|
|
6
|
-
default?: V;
|
|
7
|
-
}
|
|
8
|
-
export interface ArrayStatefulParameterOptions<V> extends StatefulParameterOptions<V> {
|
|
9
|
-
isEqual?: (desired: any[], current: any[]) => boolean;
|
|
10
|
-
isElementEqual?: (desired: any, current: any) => boolean;
|
|
11
|
-
}
|
|
12
|
-
export declare abstract class StatefulParameter<T extends StringIndexedObject, V extends T[keyof T]> {
|
|
13
|
-
readonly options: StatefulParameterOptions<V>;
|
|
14
|
-
constructor(options?: StatefulParameterOptions<V>);
|
|
15
|
-
abstract refresh(desired: V | null): Promise<V | null>;
|
|
16
|
-
abstract applyAdd(valueToAdd: V, plan: Plan<T>): Promise<void>;
|
|
17
|
-
abstract applyModify(newValue: V, previousValue: V, allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
18
|
-
abstract applyRemove(valueToRemove: V, plan: Plan<T>): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
export declare abstract class ArrayStatefulParameter<T extends StringIndexedObject, V> extends StatefulParameter<T, any> {
|
|
21
|
-
options: ArrayStatefulParameterOptions<V>;
|
|
22
|
-
constructor(options?: ArrayStatefulParameterOptions<V>);
|
|
23
|
-
applyAdd(valuesToAdd: V[], plan: Plan<T>): Promise<void>;
|
|
24
|
-
applyModify(newValues: V[], previousValues: V[], allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
25
|
-
applyRemove(valuesToRemove: V[], plan: Plan<T>): Promise<void>;
|
|
26
|
-
abstract refresh(desired: V[] | null): Promise<V[] | null>;
|
|
27
|
-
abstract applyAddItem(item: V, plan: Plan<T>): Promise<void>;
|
|
28
|
-
abstract applyRemoveItem(item: V, plan: Plan<T>): Promise<void>;
|
|
29
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export class StatefulParameter {
|
|
2
|
-
options;
|
|
3
|
-
constructor(options = {}) {
|
|
4
|
-
this.options = options;
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
export class ArrayStatefulParameter extends StatefulParameter {
|
|
8
|
-
options;
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
super(options);
|
|
11
|
-
this.options = options;
|
|
12
|
-
}
|
|
13
|
-
async applyAdd(valuesToAdd, plan) {
|
|
14
|
-
for (const value of valuesToAdd) {
|
|
15
|
-
await this.applyAddItem(value, plan);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
async applyModify(newValues, previousValues, allowDeletes, plan) {
|
|
19
|
-
const options = this.options;
|
|
20
|
-
const valuesToAdd = newValues.filter((n) => !previousValues.some((p) => {
|
|
21
|
-
if (options.isElementEqual) {
|
|
22
|
-
return options.isElementEqual(n, p);
|
|
23
|
-
}
|
|
24
|
-
return n === p;
|
|
25
|
-
}));
|
|
26
|
-
const valuesToRemove = previousValues.filter((p) => !newValues.some((n) => {
|
|
27
|
-
if (options.isElementEqual) {
|
|
28
|
-
return options.isElementEqual(n, p);
|
|
29
|
-
}
|
|
30
|
-
return n === p;
|
|
31
|
-
}));
|
|
32
|
-
for (const value of valuesToAdd) {
|
|
33
|
-
await this.applyAddItem(value, plan);
|
|
34
|
-
}
|
|
35
|
-
if (allowDeletes) {
|
|
36
|
-
for (const value of valuesToRemove) {
|
|
37
|
-
await this.applyRemoveItem(value, plan);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async applyRemove(valuesToRemove, plan) {
|
|
42
|
-
for (const value of valuesToRemove) {
|
|
43
|
-
await this.applyRemoveItem(value, plan);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|