@kensio/yulin 1.21.14 → 1.21.16
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/service/cloudformation/changeset/sim-cfn-change-set-changes.js +1 -1
- package/dist/service/cloudformation/resource/factory/sim-cfn-resource-factory.type.d.ts +25 -1
- package/dist/service/cloudformation/resource/resolve/service/sim-cfn-resource-service-factory.d.ts +18 -0
- package/dist/service/cloudformation/resource/resolve/service/sim-cfn-resource-service-factory.js +30 -0
- package/dist/service/cloudformation/resource/sim-cfn-resource.type.d.ts +18 -0
- package/dist/service/cloudformation/resource/update/sim-cfn-resource-in-place-updater.d.ts +35 -0
- package/dist/service/cloudformation/resource/update/sim-cfn-resource-in-place-updater.js +61 -0
- package/dist/service/cloudformation/resource/update/sim-cfn-resource-update-error.d.ts +9 -0
- package/dist/service/cloudformation/resource/update/sim-cfn-resource-update-error.js +14 -0
- package/dist/service/cloudformation/resource/update/sim-cfn-resource-update-validator.js +5 -18
- package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.d.ts +7 -2
- package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.js +16 -12
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-change-pairs.d.ts +12 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-change-pairs.js +18 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-changes.d.ts +52 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-changes.js +86 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-updates.d.ts +42 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-updates.js +70 -0
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-update-plan.d.ts +25 -18
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-update-plan.js +43 -32
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-updater.d.ts +7 -5
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-updater.js +12 -7
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-change.d.ts +19 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-change.js +39 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-deleter.d.ts +23 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-deleter.js +23 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-template.test-support.d.ts +21 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-template.test-support.js +64 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-update.test-support.d.ts +18 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-update.test-support.js +39 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-updater.d.ts +37 -0
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-updater.js +66 -0
- package/dist/service/secretsmanager/cfn/sim-cfn-secrets-manager-resource-factory.d.ts +20 -10
- package/dist/service/secretsmanager/cfn/sim-cfn-secrets-manager-resource-factory.js +41 -27
- package/dist/service/secretsmanager/cfn/sim-cfn-secrets-manager-resource-type.d.ts +12 -0
- package/dist/service/secretsmanager/cfn/sim-cfn-secrets-manager-resource-type.js +22 -0
- package/dist/util/background/background-clock-waits.d.ts +10 -3
- package/dist/util/background/background-clock-waits.js +11 -4
- package/dist/util/background/background-pending-tasks.d.ts +15 -9
- package/dist/util/background/background-pending-tasks.js +18 -12
- package/dist/util/background/background.d.ts +11 -3
- package/dist/util/background/background.js +14 -4
- package/dist/util/background/non-deterministic-background.d.ts +4 -0
- package/dist/util/background/non-deterministic-background.js +5 -1
- package/dist/util/clock/sim-clock.d.ts +16 -0
- package/dist/util/clock/sim-clock.js +4 -0
- package/dist/util/clock/sim-controllable-clock.d.ts +11 -0
- package/dist/util/clock/sim-controllable-clock.js +13 -0
- package/docs/services/cloudformation/README.md +21 -3
- package/docs/services/lambda/README.md +11 -0
- package/docs/services/secretsmanager/README.md +35 -1
- package/docs/time/README.md +7 -0
- package/package.json +1 -1
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-replaced-resources.d.ts +0 -21
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-replaced-resources.js +0 -51
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { makeSimCfnStackResourceMap } from "../stack/resource-map/sim-cfn-stack-resource-map.js";
|
|
2
|
-
import { simCfnStackReplacedLogicalIds } from "../stack/update/sim-cfn-stack-
|
|
2
|
+
import { simCfnStackReplacedLogicalIds } from "../stack/update/sim-cfn-stack-resource-changes.js";
|
|
3
3
|
/**
|
|
4
4
|
* What executing a change set would do to the Stack it is held against.
|
|
5
5
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SimCfnResource, SimCloudFormationResourceCreateContext, SimCloudFormationResourceDeleteContext } from "../sim-cfn-resource.js";
|
|
2
|
-
import type { SimCloudFormationResourceUpdateContext } from "../sim-cfn-resource.type.js";
|
|
2
|
+
import type { SimCloudFormationResourceInPlaceUpdateContext, SimCloudFormationResourceUpdateContext } from "../sim-cfn-resource.type.js";
|
|
3
3
|
export interface SimCfnServiceResourceFactory {
|
|
4
4
|
create(resourceTypeName: string, resource: SimCfnResource, context: SimCloudFormationResourceCreateContext): Promise<object | undefined>;
|
|
5
5
|
/**
|
|
@@ -24,6 +24,30 @@ export interface SimCfnServiceResourceFactory {
|
|
|
24
24
|
* create request cannot check.
|
|
25
25
|
*/
|
|
26
26
|
assertUpdateAllowed?(resourceTypeName: string, current: SimCfnResource, updated: SimCfnResource, context: SimCloudFormationResourceUpdateContext): Promise<void> | void;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a change between two definitions of this Resource can be applied
|
|
29
|
+
* to the deployed Resource, leaving it where it is.
|
|
30
|
+
*
|
|
31
|
+
* Sim CloudFormation replaces a changed Resource unless a service says
|
|
32
|
+
* otherwise, which is the safe reading for one with no way to change a
|
|
33
|
+
* deployed Resource. A service answers true for the changes real
|
|
34
|
+
* CloudFormation applies with no interruption, and carries them out in
|
|
35
|
+
* `updateInPlace`.
|
|
36
|
+
*
|
|
37
|
+
* Answering true keeps the Resource's physical name, so nothing naming it is
|
|
38
|
+
* replaced either.
|
|
39
|
+
*/
|
|
40
|
+
updatesInPlace?(resourceTypeName: string, current: SimCfnResource, updated: SimCfnResource): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Apply a change to the deployed Resource.
|
|
43
|
+
*
|
|
44
|
+
* Called only for a change `updatesInPlace` claimed, and before the update
|
|
45
|
+
* deletes or creates anything. The deployed simulated AWS object is on
|
|
46
|
+
* `current`, and `updated` carries the new definition. What it returns
|
|
47
|
+
* becomes the Resource's simulated AWS object, which is usually the deployed
|
|
48
|
+
* one it was given.
|
|
49
|
+
*/
|
|
50
|
+
updateInPlace?(resourceTypeName: string, current: SimCfnResource, updated: SimCfnResource, context: SimCloudFormationResourceInPlaceUpdateContext): Promise<object | undefined>;
|
|
27
51
|
}
|
|
28
52
|
export interface SimCloudFormationParsedResourceType {
|
|
29
53
|
readonly providerName: string;
|
package/dist/service/cloudformation/resource/resolve/service/sim-cfn-resource-service-factory.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SimAws } from "../../../../aws/sim-aws.js";
|
|
2
|
+
import type { SimCfnServiceResourceFactory } from "../../factory/sim-cfn-resource-factory.type.js";
|
|
3
|
+
import type { SimCfnResource } from "../../sim-cfn-resource.js";
|
|
4
|
+
/**
|
|
5
|
+
* A Resource's service factory, and the type name that factory knows it by.
|
|
6
|
+
*/
|
|
7
|
+
export interface SimCfnResourceServiceFactory {
|
|
8
|
+
readonly factory: SimCfnServiceResourceFactory;
|
|
9
|
+
readonly resourceTypeName: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The service factory owning a Resource, where a service owns it.
|
|
13
|
+
*
|
|
14
|
+
* An untyped Resource and one whose type no service simulates both come back
|
|
15
|
+
* undefined. Update work asks this before a Stack is changed, and a Resource
|
|
16
|
+
* nothing can create is a Resource nothing can update either.
|
|
17
|
+
*/
|
|
18
|
+
export declare function simCfnResourceServiceFactory(simAws: SimAws, resource: SimCfnResource): SimCfnResourceServiceFactory | undefined;
|
package/dist/service/cloudformation/resource/resolve/service/sim-cfn-resource-service-factory.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { parseSimCloudFormationResourceType } from "../../parser/sim-cfn-resource-parser.js";
|
|
2
|
+
import { isSimCfnUnsupportedResourceError } from "../../unsupported/sim-cfn-unsupported-resource.js";
|
|
3
|
+
import { resolveSimCloudFormationServiceResourceFactory } from "./sim-cfn-service-resolver.js";
|
|
4
|
+
/**
|
|
5
|
+
* The service factory owning a Resource, where a service owns it.
|
|
6
|
+
*
|
|
7
|
+
* An untyped Resource and one whose type no service simulates both come back
|
|
8
|
+
* undefined. Update work asks this before a Stack is changed, and a Resource
|
|
9
|
+
* nothing can create is a Resource nothing can update either.
|
|
10
|
+
*/
|
|
11
|
+
export function simCfnResourceServiceFactory(simAws, resource) {
|
|
12
|
+
const { type } = resource;
|
|
13
|
+
if (type === undefined) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const resourceType = parseSimCloudFormationResourceType(type);
|
|
17
|
+
try {
|
|
18
|
+
return {
|
|
19
|
+
factory: resolveSimCloudFormationServiceResourceFactory(simAws, resource.accountRegionScope, resourceType),
|
|
20
|
+
resourceTypeName: resourceType.resourceTypeName,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (isSimCfnUnsupportedResourceError(error)) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/* v8 ignore next -- defensive: the resolver refuses with nothing else */
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -94,6 +94,24 @@ export interface SimCloudFormationResourceDeleteContext {
|
|
|
94
94
|
*/
|
|
95
95
|
readonly retention?: SimCfnResourceRetention | undefined;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* What a service is given to apply a change to a Resource it created, without
|
|
99
|
+
* replacing it.
|
|
100
|
+
*
|
|
101
|
+
* Both property sets are resolved against the Resources the Stack holds now,
|
|
102
|
+
* so a Ref reaches the physical name of a deployed Resource. The old set is
|
|
103
|
+
* there because a service often has to know which property changed. Secrets
|
|
104
|
+
* Manager writes a new secret version for a changed value and leaves the
|
|
105
|
+
* version alone for a changed description.
|
|
106
|
+
*/
|
|
107
|
+
export interface SimCloudFormationResourceInPlaceUpdateContext {
|
|
108
|
+
readonly simAws: SimAws;
|
|
109
|
+
readonly resources: ReadonlyMap<string, SimCfnResource>;
|
|
110
|
+
readonly currentResolvedProperties: SimCfnTemplateValueRecord;
|
|
111
|
+
readonly updatedResolvedProperties: SimCfnTemplateValueRecord;
|
|
112
|
+
/** The principal the update runs as, as creation carries it. */
|
|
113
|
+
readonly caller?: SimAwsCaller | undefined;
|
|
114
|
+
}
|
|
97
115
|
/**
|
|
98
116
|
* The two resolved Resource definitions available to update validation.
|
|
99
117
|
*/
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SimAws } from "../../../aws/sim-aws.js";
|
|
2
|
+
import type { SimAwsCaller } from "../../../aws/caller/sim-aws-caller.js";
|
|
3
|
+
import type { SimCfnResource } from "../sim-cfn-resource.js";
|
|
4
|
+
interface SimCfnResourceInPlaceUpdaterProperties {
|
|
5
|
+
readonly current: SimCfnResource;
|
|
6
|
+
readonly updated: SimCfnResource;
|
|
7
|
+
}
|
|
8
|
+
interface ApplySimCfnResourceInPlaceUpdateProperties {
|
|
9
|
+
readonly simAws: SimAws;
|
|
10
|
+
readonly resources: ReadonlyMap<string, SimCfnResource>;
|
|
11
|
+
readonly caller?: SimAwsCaller | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Applies one Resource change to the deployed Resource, without replacing it.
|
|
15
|
+
*
|
|
16
|
+
* The new Resource record takes the deployed simulated AWS object on from the
|
|
17
|
+
* one it replaces in the Stack's map. That is what carries the bucket's
|
|
18
|
+
* contents or the secret's versions across an update, and what leaves the
|
|
19
|
+
* Resource reporting CREATE_COMPLETE rather than starting again as pending.
|
|
20
|
+
*
|
|
21
|
+
* Both property sets are resolved against the Resources the Stack holds now.
|
|
22
|
+
* Nothing has been deleted or created at this point, so a Ref reaches a
|
|
23
|
+
* deployed Resource's physical name from either side.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SimCfnResourceInPlaceUpdater {
|
|
26
|
+
private readonly current;
|
|
27
|
+
private readonly updated;
|
|
28
|
+
constructor(properties: SimCfnResourceInPlaceUpdaterProperties);
|
|
29
|
+
/**
|
|
30
|
+
* Apply the change, and move the new Resource record on to what it left in
|
|
31
|
+
* simulated AWS.
|
|
32
|
+
*/
|
|
33
|
+
apply(properties: ApplySimCfnResourceInPlaceUpdateProperties): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { assertDefined } from "../../../../util/type-guard/defined.js";
|
|
2
|
+
import { simCfnResourceServiceFactory } from "../resolve/service/sim-cfn-resource-service-factory.js";
|
|
3
|
+
import { simCfnResourceUpdateError } from "./sim-cfn-resource-update-error.js";
|
|
4
|
+
/**
|
|
5
|
+
* Applies one Resource change to the deployed Resource, without replacing it.
|
|
6
|
+
*
|
|
7
|
+
* The new Resource record takes the deployed simulated AWS object on from the
|
|
8
|
+
* one it replaces in the Stack's map. That is what carries the bucket's
|
|
9
|
+
* contents or the secret's versions across an update, and what leaves the
|
|
10
|
+
* Resource reporting CREATE_COMPLETE rather than starting again as pending.
|
|
11
|
+
*
|
|
12
|
+
* Both property sets are resolved against the Resources the Stack holds now.
|
|
13
|
+
* Nothing has been deleted or created at this point, so a Ref reaches a
|
|
14
|
+
* deployed Resource's physical name from either side.
|
|
15
|
+
*/
|
|
16
|
+
export class SimCfnResourceInPlaceUpdater {
|
|
17
|
+
current;
|
|
18
|
+
updated;
|
|
19
|
+
constructor(properties) {
|
|
20
|
+
this.current = properties.current;
|
|
21
|
+
this.updated = properties.updated;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Apply the change, and move the new Resource record on to what it left in
|
|
25
|
+
* simulated AWS.
|
|
26
|
+
*/
|
|
27
|
+
async apply(properties) {
|
|
28
|
+
const { current, updated } = this;
|
|
29
|
+
const { simAws, resources, caller } = properties;
|
|
30
|
+
const service = simCfnResourceServiceFactory(simAws, updated);
|
|
31
|
+
// The plan only lists a Resource whose service has both update hooks.
|
|
32
|
+
assertDefined(service, `sim CloudFormation service for Resource ${updated.logicalId} to update`);
|
|
33
|
+
const { factory, resourceTypeName } = service;
|
|
34
|
+
const updateInPlace = factory.updateInPlace?.bind(factory);
|
|
35
|
+
assertDefined(updateInPlace, `sim CloudFormation in-place update for Resource ${updated.logicalId}`);
|
|
36
|
+
updated.markCreateInProgress();
|
|
37
|
+
try {
|
|
38
|
+
const simResource = await updateInPlace(resourceTypeName, current, updated, {
|
|
39
|
+
simAws,
|
|
40
|
+
resources,
|
|
41
|
+
currentResolvedProperties: await current.resolvedProperties({
|
|
42
|
+
simAws,
|
|
43
|
+
resources,
|
|
44
|
+
caller,
|
|
45
|
+
}),
|
|
46
|
+
updatedResolvedProperties: await updated.resolvedProperties({
|
|
47
|
+
simAws,
|
|
48
|
+
resources,
|
|
49
|
+
caller,
|
|
50
|
+
}),
|
|
51
|
+
caller,
|
|
52
|
+
});
|
|
53
|
+
updated.markCreateComplete(simResource);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const updateError = simCfnResourceUpdateError(updated, error);
|
|
57
|
+
updated.markCreateFailed(updateError);
|
|
58
|
+
throw updateError;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SimCfnResource } from "../sim-cfn-resource.js";
|
|
2
|
+
/**
|
|
3
|
+
* The error a failed in-place update reports, naming the Resource it stopped
|
|
4
|
+
* on.
|
|
5
|
+
*
|
|
6
|
+
* An Error is given the prefix and passed on, so a service's own error type and
|
|
7
|
+
* its stack survive to the Stack that reads it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function simCfnResourceUpdateError(resource: SimCfnResource, error: unknown): Error;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error a failed in-place update reports, naming the Resource it stopped
|
|
3
|
+
* on.
|
|
4
|
+
*
|
|
5
|
+
* An Error is given the prefix and passed on, so a service's own error type and
|
|
6
|
+
* its stack survive to the Stack that reads it.
|
|
7
|
+
*/
|
|
8
|
+
export function simCfnResourceUpdateError(resource, error) {
|
|
9
|
+
const messagePrefix = `Sim CloudFormation Resource ${resource.logicalId} update failed`;
|
|
10
|
+
/* v8 ignore next -- defensive: a service refuses with an Error */
|
|
11
|
+
const refusal = error instanceof Error ? error : new Error(String(error));
|
|
12
|
+
refusal.message = `${messagePrefix}: ${refusal.message}`;
|
|
13
|
+
return refusal;
|
|
14
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { resolveSimCloudFormationServiceResourceFactory } from "../resolve/service/sim-cfn-service-resolver.js";
|
|
3
|
-
import { isSimCfnUnsupportedResourceError } from "../unsupported/sim-cfn-unsupported-resource.js";
|
|
1
|
+
import { simCfnResourceServiceFactory } from "../resolve/service/sim-cfn-resource-service-factory.js";
|
|
4
2
|
/**
|
|
5
3
|
* Runs service-specific validation for one Resource replacement.
|
|
6
4
|
*/
|
|
@@ -17,25 +15,14 @@ export class SimCfnResourceUpdateValidator {
|
|
|
17
15
|
async assertAllowed(properties) {
|
|
18
16
|
const { current, updated } = this;
|
|
19
17
|
const { simAws, currentResources, updatedResources, caller } = properties;
|
|
20
|
-
|
|
21
|
-
if (type === undefined || current.type !== type) {
|
|
18
|
+
if (updated.type === undefined || current.type !== updated.type) {
|
|
22
19
|
return;
|
|
23
20
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
factory = resolveSimCloudFormationServiceResourceFactory(simAws, updated.accountRegionScope, resourceType);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (isSimCfnUnsupportedResourceError(error)) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
if (factory.assertUpdateAllowed === undefined) {
|
|
21
|
+
const service = simCfnResourceServiceFactory(simAws, updated);
|
|
22
|
+
if (service?.factory.assertUpdateAllowed === undefined) {
|
|
36
23
|
return;
|
|
37
24
|
}
|
|
38
|
-
await factory.assertUpdateAllowed(
|
|
25
|
+
await service.factory.assertUpdateAllowed(service.resourceTypeName, current, updated, {
|
|
39
26
|
simAws,
|
|
40
27
|
currentResources,
|
|
41
28
|
updatedResources,
|
|
@@ -10,7 +10,7 @@ import { SimCfnResourceRetention } from "../resource/delete/sim-cfn-resource-ret
|
|
|
10
10
|
import type { SimCfnTemplate } from "../template/sim-cfn-template.js";
|
|
11
11
|
import type { SimCfnResourceOrder } from "./deploy/sim-cfn-resource-order.js";
|
|
12
12
|
import { SimCfnStackUpdater } from "./update/sim-cfn-stack-updater.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { SimCfnStackResourceChange } from "./update/sim-cfn-stack-resource-change-pairs.js";
|
|
14
14
|
import type { SimCloudFormationStackName } from "./sim-cfn-stack.js";
|
|
15
15
|
interface SimCfnStackUpdateProperties {
|
|
16
16
|
readonly background: BackgroundScheduler;
|
|
@@ -104,7 +104,11 @@ export declare class SimCfnStackResourceOperations {
|
|
|
104
104
|
/**
|
|
105
105
|
* Validate every Resource replacement before the update changes the Stack.
|
|
106
106
|
*/
|
|
107
|
-
assertUpdatesAllowed(currentResources: ReadonlyMap<string, SimCfnResource>, updatedResources: ReadonlyMap<string, SimCfnResource>, replacements: readonly
|
|
107
|
+
assertUpdatesAllowed(currentResources: ReadonlyMap<string, SimCfnResource>, updatedResources: ReadonlyMap<string, SimCfnResource>, replacements: readonly SimCfnStackResourceChange[]): Promise<void>;
|
|
108
|
+
/** Whether the service owning a Resource can apply this change to it. */
|
|
109
|
+
updatesInPlace(current: SimCfnResource, updated: SimCfnResource): boolean;
|
|
110
|
+
/** Apply the given Resource changes to the deployed Resources. */
|
|
111
|
+
updateInPlace(resources: ReadonlyMap<string, SimCfnResource>, updates: readonly SimCfnStackResourceChange[]): Promise<void>;
|
|
108
112
|
/**
|
|
109
113
|
* An update of this Stack from a changed template, in the same scope.
|
|
110
114
|
*/
|
|
@@ -130,6 +134,7 @@ export declare class SimCfnStackResourceOperations {
|
|
|
130
134
|
*/
|
|
131
135
|
private teardownRetention;
|
|
132
136
|
private publishAssets;
|
|
137
|
+
private resourceUpdates;
|
|
133
138
|
private creator;
|
|
134
139
|
private deleter;
|
|
135
140
|
}
|
|
@@ -5,7 +5,7 @@ import { simCfnStackRetainedLogicalIds } from "./teardown/sim-cfn-stack-retained
|
|
|
5
5
|
import { SimCfnStackResourceCreator } from "./deploy/sim-cfn-stack-resource-creator.js";
|
|
6
6
|
import { SimCfnStackResourceDeleter } from "./teardown/sim-cfn-stack-resource-deleter.js";
|
|
7
7
|
import { SimCfnStackUpdater } from "./update/sim-cfn-stack-updater.js";
|
|
8
|
-
import {
|
|
8
|
+
import { SimCfnStackResourceUpdates } from "./update/sim-cfn-stack-resource-updates.js";
|
|
9
9
|
/**
|
|
10
10
|
* What a Stack can ask simulated AWS to do with its Resources.
|
|
11
11
|
*
|
|
@@ -98,17 +98,15 @@ export class SimCfnStackResourceOperations {
|
|
|
98
98
|
* Validate every Resource replacement before the update changes the Stack.
|
|
99
99
|
*/
|
|
100
100
|
async assertUpdatesAllowed(currentResources, updatedResources, replacements) {
|
|
101
|
-
await
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
111
|
-
}));
|
|
101
|
+
await this.resourceUpdates().assertAllowed(currentResources, updatedResources, replacements);
|
|
102
|
+
}
|
|
103
|
+
/** Whether the service owning a Resource can apply this change to it. */
|
|
104
|
+
updatesInPlace(current, updated) {
|
|
105
|
+
return this.resourceUpdates().claimed(current, updated);
|
|
106
|
+
}
|
|
107
|
+
/** Apply the given Resource changes to the deployed Resources. */
|
|
108
|
+
async updateInPlace(resources, updates) {
|
|
109
|
+
await this.resourceUpdates().apply(resources, updates);
|
|
112
110
|
}
|
|
113
111
|
/**
|
|
114
112
|
* An update of this Stack from a changed template, in the same scope.
|
|
@@ -163,6 +161,12 @@ export class SimCfnStackResourceOperations {
|
|
|
163
161
|
assetsCaller: this.context.publishingCaller(),
|
|
164
162
|
}).publish();
|
|
165
163
|
}
|
|
164
|
+
resourceUpdates() {
|
|
165
|
+
return new SimCfnStackResourceUpdates({
|
|
166
|
+
simAws: this.simAws,
|
|
167
|
+
caller: this.context.caller,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
166
170
|
creator(resources) {
|
|
167
171
|
return new SimCfnStackResourceCreator({
|
|
168
172
|
simAws: this.simAws,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SimCfnResource } from "../../resource/sim-cfn-resource.js";
|
|
2
|
+
/**
|
|
3
|
+
* The deployed and new halves of one Resource an update changes.
|
|
4
|
+
*/
|
|
5
|
+
export interface SimCfnStackResourceChange {
|
|
6
|
+
readonly current: SimCfnResource;
|
|
7
|
+
readonly updated: SimCfnResource;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The deployed and new halves of each of the given logical IDs.
|
|
11
|
+
*/
|
|
12
|
+
export declare function simCfnStackResourceChangePairs(current: ReadonlyMap<string, SimCfnResource>, updated: ReadonlyMap<string, SimCfnResource>, logicalIds: ReadonlySet<string>): readonly SimCfnStackResourceChange[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deployed and new halves of each of the given logical IDs.
|
|
3
|
+
*/
|
|
4
|
+
export function simCfnStackResourceChangePairs(current, updated, logicalIds) {
|
|
5
|
+
return logicalIds
|
|
6
|
+
.values()
|
|
7
|
+
.map((logicalId) => {
|
|
8
|
+
const currentResource = current.get(logicalId);
|
|
9
|
+
const updatedResource = updated.get(logicalId);
|
|
10
|
+
/* v8 ignore next 5 -- defensive: a changed logical ID is one both maps
|
|
11
|
+
hold */
|
|
12
|
+
if (currentResource === undefined || updatedResource === undefined) {
|
|
13
|
+
throw new Error(`CloudFormation change ${logicalId} is missing one of its Resource definitions`);
|
|
14
|
+
}
|
|
15
|
+
return { current: currentResource, updated: updatedResource };
|
|
16
|
+
})
|
|
17
|
+
.toArray();
|
|
18
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SimCfnResource } from "../../resource/sim-cfn-resource.js";
|
|
2
|
+
/**
|
|
3
|
+
* Who decides whether a change can be applied to the deployed Resource.
|
|
4
|
+
* Answering false replaces the Resource.
|
|
5
|
+
*/
|
|
6
|
+
export interface SimCfnStackInPlaceUpdates {
|
|
7
|
+
updatesInPlace(current: SimCfnResource, updated: SimCfnResource): boolean;
|
|
8
|
+
}
|
|
9
|
+
interface SimCfnStackResourceChangesProperties {
|
|
10
|
+
readonly current: ReadonlyMap<string, SimCfnResource>;
|
|
11
|
+
readonly updated: ReadonlyMap<string, SimCfnResource>;
|
|
12
|
+
/**
|
|
13
|
+
* Which changes the owning service can apply to the deployed Resource.
|
|
14
|
+
* Omitted, every changed Resource is replaced.
|
|
15
|
+
*/
|
|
16
|
+
readonly inPlaceUpdates?: SimCfnStackInPlaceUpdates | undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What an update does to each Resource a Stack and its new template share.
|
|
20
|
+
*/
|
|
21
|
+
export interface SimCfnStackResourceChanges {
|
|
22
|
+
/** The logical IDs to delete and create again from the new template. */
|
|
23
|
+
readonly replaced: ReadonlySet<string>;
|
|
24
|
+
/** The logical IDs to change where they are. */
|
|
25
|
+
readonly updatedInPlace: ReadonlySet<string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* How an update reconciles each changed Resource, given the Stack's deployed
|
|
29
|
+
* Resources and the ones its new template describes.
|
|
30
|
+
*
|
|
31
|
+
* A Resource whose resolved template entry changed is replaced, which means
|
|
32
|
+
* deleting it and creating it again from the new template. The service owning
|
|
33
|
+
* the Resource can claim the change instead, for the properties real
|
|
34
|
+
* CloudFormation applies with no interruption.
|
|
35
|
+
*
|
|
36
|
+
* A Resource that names a replaced Resource is replaced too, all the way up the
|
|
37
|
+
* dependency chain. Real CloudFormation hands the dependent the new physical
|
|
38
|
+
* name instead, but nothing here can rewrite an already created simulated
|
|
39
|
+
* Resource, and leaving the dependent alone would leave it pointing at a
|
|
40
|
+
* Resource that has gone. That reaches a claimed Resource as well, and takes
|
|
41
|
+
* the claim back. An in-place update never starts a spread of its own, since
|
|
42
|
+
* the Resource keeps the physical name its dependents already hold.
|
|
43
|
+
*/
|
|
44
|
+
export declare function simCfnStackResourceChanges(properties: SimCfnStackResourceChangesProperties): SimCfnStackResourceChanges;
|
|
45
|
+
/**
|
|
46
|
+
* The logical IDs an update has to replace.
|
|
47
|
+
*
|
|
48
|
+
* Kept for the change set, which reports what an update would do without
|
|
49
|
+
* knowing which service owns each Resource.
|
|
50
|
+
*/
|
|
51
|
+
export declare function simCfnStackReplacedLogicalIds(properties: SimCfnStackResourceChangesProperties): ReadonlySet<string>;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { simCfnTemplateSignature } from "./sim-cfn-template-signature.js";
|
|
2
|
+
/**
|
|
3
|
+
* How an update reconciles each changed Resource, given the Stack's deployed
|
|
4
|
+
* Resources and the ones its new template describes.
|
|
5
|
+
*
|
|
6
|
+
* A Resource whose resolved template entry changed is replaced, which means
|
|
7
|
+
* deleting it and creating it again from the new template. The service owning
|
|
8
|
+
* the Resource can claim the change instead, for the properties real
|
|
9
|
+
* CloudFormation applies with no interruption.
|
|
10
|
+
*
|
|
11
|
+
* A Resource that names a replaced Resource is replaced too, all the way up the
|
|
12
|
+
* dependency chain. Real CloudFormation hands the dependent the new physical
|
|
13
|
+
* name instead, but nothing here can rewrite an already created simulated
|
|
14
|
+
* Resource, and leaving the dependent alone would leave it pointing at a
|
|
15
|
+
* Resource that has gone. That reaches a claimed Resource as well, and takes
|
|
16
|
+
* the claim back. An in-place update never starts a spread of its own, since
|
|
17
|
+
* the Resource keeps the physical name its dependents already hold.
|
|
18
|
+
*/
|
|
19
|
+
export function simCfnStackResourceChanges(properties) {
|
|
20
|
+
const { current, updated, inPlaceUpdates } = properties;
|
|
21
|
+
const changed = changedLogicalIds({ current, updated });
|
|
22
|
+
const updatedInPlace = new Set(changed.values().filter((logicalId) => {
|
|
23
|
+
const currentResource = current.get(logicalId);
|
|
24
|
+
const updatedResource = updated.get(logicalId);
|
|
25
|
+
return (currentResource !== undefined &&
|
|
26
|
+
updatedResource !== undefined &&
|
|
27
|
+
inPlaceUpdates?.updatesInPlace(currentResource, updatedResource) ===
|
|
28
|
+
true);
|
|
29
|
+
}));
|
|
30
|
+
const replaced = new Set(changed.values().filter((logicalId) => !updatedInPlace.has(logicalId)));
|
|
31
|
+
spreadToDependents({ updated, current, replaced });
|
|
32
|
+
// A claimed Resource the spread reached is replaced after all. Its
|
|
33
|
+
// dependency is being deleted and created again, and an update applied
|
|
34
|
+
// before that would have read the deployed Resource on its way out.
|
|
35
|
+
for (const logicalId of replaced) {
|
|
36
|
+
updatedInPlace.delete(logicalId);
|
|
37
|
+
}
|
|
38
|
+
return { replaced, updatedInPlace };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The logical IDs an update has to replace.
|
|
42
|
+
*
|
|
43
|
+
* Kept for the change set, which reports what an update would do without
|
|
44
|
+
* knowing which service owns each Resource.
|
|
45
|
+
*/
|
|
46
|
+
export function simCfnStackReplacedLogicalIds(properties) {
|
|
47
|
+
return simCfnStackResourceChanges(properties).replaced;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Replace every Resource naming a replaced one, and every Resource naming
|
|
51
|
+
* those.
|
|
52
|
+
*/
|
|
53
|
+
function spreadToDependents(properties) {
|
|
54
|
+
const { current, updated, replaced } = properties;
|
|
55
|
+
// Each pass replaces the Resources naming one already being replaced, until a
|
|
56
|
+
// pass finds none, which is the end of the dependency chain.
|
|
57
|
+
let spreading = true;
|
|
58
|
+
while (spreading) {
|
|
59
|
+
spreading = false;
|
|
60
|
+
for (const [logicalId, resource] of updated) {
|
|
61
|
+
const spreads = current.has(logicalId) &&
|
|
62
|
+
!replaced.has(logicalId) &&
|
|
63
|
+
resource.dependencies().some((dependency) => replaced.has(dependency));
|
|
64
|
+
if (spreads) {
|
|
65
|
+
replaced.add(logicalId);
|
|
66
|
+
spreading = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The logical IDs whose resolved template entry differs from the deployed one.
|
|
73
|
+
*/
|
|
74
|
+
function changedLogicalIds(properties) {
|
|
75
|
+
const { current, updated } = properties;
|
|
76
|
+
const changed = new Set();
|
|
77
|
+
for (const [logicalId, resource] of updated) {
|
|
78
|
+
const deployed = current.get(logicalId);
|
|
79
|
+
if (deployed !== undefined &&
|
|
80
|
+
simCfnTemplateSignature(deployed.template) !==
|
|
81
|
+
simCfnTemplateSignature(resource.template)) {
|
|
82
|
+
changed.add(logicalId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return changed;
|
|
86
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { SimAws } from "../../../aws/sim-aws.js";
|
|
2
|
+
import type { SimAwsCaller } from "../../../aws/caller/sim-aws-caller.js";
|
|
3
|
+
import type { SimCfnResource } from "../../resource/sim-cfn-resource.js";
|
|
4
|
+
import type { SimCfnStackResourceChange } from "./sim-cfn-stack-resource-change-pairs.js";
|
|
5
|
+
interface SimCfnStackResourceUpdatesProperties {
|
|
6
|
+
readonly simAws: SimAws;
|
|
7
|
+
/** The principal the update runs as, as creation carries it. */
|
|
8
|
+
readonly caller?: SimAwsCaller | undefined;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The Resource changes a Stack update applies to the deployed Resources,
|
|
12
|
+
* rather than by replacing them.
|
|
13
|
+
*
|
|
14
|
+
* Which changes those are is the owning service's answer, given before the
|
|
15
|
+
* update touches anything. A service with no way to change a deployed Resource
|
|
16
|
+
* answers nothing, and every change to its Resources is a replacement.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SimCfnStackResourceUpdates {
|
|
19
|
+
private readonly simAws;
|
|
20
|
+
private readonly caller;
|
|
21
|
+
constructor(properties: SimCfnStackResourceUpdatesProperties);
|
|
22
|
+
/**
|
|
23
|
+
* Whether the service owning a Resource can apply this change to the
|
|
24
|
+
* deployed Resource.
|
|
25
|
+
*
|
|
26
|
+
* A Resource type no service simulates cannot be updated where it is. Its
|
|
27
|
+
* creation was skipped, so there is nothing deployed to change.
|
|
28
|
+
*/
|
|
29
|
+
claimed(current: SimCfnResource, updated: SimCfnResource): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Validate every Resource replacement before the update changes the Stack.
|
|
32
|
+
*/
|
|
33
|
+
assertAllowed(currentResources: ReadonlyMap<string, SimCfnResource>, updatedResources: ReadonlyMap<string, SimCfnResource>, replacements: readonly SimCfnStackResourceChange[]): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Apply the given changes to the deployed Resources.
|
|
36
|
+
*
|
|
37
|
+
* Each one is independent of the others, since none of them creates or
|
|
38
|
+
* deletes anything another could be waiting on.
|
|
39
|
+
*/
|
|
40
|
+
apply(resources: ReadonlyMap<string, SimCfnResource>, updates: readonly SimCfnStackResourceChange[]): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { SimCfnResourceInPlaceUpdater } from "../../resource/update/sim-cfn-resource-in-place-updater.js";
|
|
2
|
+
import { simCfnResourceServiceFactory } from "../../resource/resolve/service/sim-cfn-resource-service-factory.js";
|
|
3
|
+
import { SimCfnResourceUpdateValidator } from "../../resource/update/sim-cfn-resource-update-validator.js";
|
|
4
|
+
/**
|
|
5
|
+
* The Resource changes a Stack update applies to the deployed Resources,
|
|
6
|
+
* rather than by replacing them.
|
|
7
|
+
*
|
|
8
|
+
* Which changes those are is the owning service's answer, given before the
|
|
9
|
+
* update touches anything. A service with no way to change a deployed Resource
|
|
10
|
+
* answers nothing, and every change to its Resources is a replacement.
|
|
11
|
+
*/
|
|
12
|
+
export class SimCfnStackResourceUpdates {
|
|
13
|
+
simAws;
|
|
14
|
+
caller;
|
|
15
|
+
constructor(properties) {
|
|
16
|
+
this.simAws = properties.simAws;
|
|
17
|
+
this.caller = properties.caller;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Whether the service owning a Resource can apply this change to the
|
|
21
|
+
* deployed Resource.
|
|
22
|
+
*
|
|
23
|
+
* A Resource type no service simulates cannot be updated where it is. Its
|
|
24
|
+
* creation was skipped, so there is nothing deployed to change.
|
|
25
|
+
*/
|
|
26
|
+
claimed(current, updated) {
|
|
27
|
+
if (updated.type === undefined || current.type !== updated.type) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const service = simCfnResourceServiceFactory(this.simAws, updated);
|
|
31
|
+
// Both halves or neither. A service that can recognise a change it can
|
|
32
|
+
// apply but cannot apply it would leave the update with nothing to run.
|
|
33
|
+
if (service?.factory.updatesInPlace === undefined ||
|
|
34
|
+
service.factory.updateInPlace === undefined) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return service.factory.updatesInPlace(service.resourceTypeName, current, updated);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate every Resource replacement before the update changes the Stack.
|
|
41
|
+
*/
|
|
42
|
+
async assertAllowed(currentResources, updatedResources, replacements) {
|
|
43
|
+
await Promise.all(replacements.map(async ({ current, updated }) => {
|
|
44
|
+
await new SimCfnResourceUpdateValidator({
|
|
45
|
+
current,
|
|
46
|
+
updated,
|
|
47
|
+
}).assertAllowed({
|
|
48
|
+
simAws: this.simAws,
|
|
49
|
+
currentResources,
|
|
50
|
+
updatedResources,
|
|
51
|
+
caller: this.caller,
|
|
52
|
+
});
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Apply the given changes to the deployed Resources.
|
|
57
|
+
*
|
|
58
|
+
* Each one is independent of the others, since none of them creates or
|
|
59
|
+
* deletes anything another could be waiting on.
|
|
60
|
+
*/
|
|
61
|
+
async apply(resources, updates) {
|
|
62
|
+
await Promise.all(updates.map(async ({ current, updated }) => {
|
|
63
|
+
await new SimCfnResourceInPlaceUpdater({ current, updated }).apply({
|
|
64
|
+
simAws: this.simAws,
|
|
65
|
+
resources,
|
|
66
|
+
caller: this.caller,
|
|
67
|
+
});
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|