@ashishpandeyone/cdk-lambda-web-function 0.1.1 → 0.1.3
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/.jsii +1520 -130
- package/.jsii.tabl.json +1 -1
- package/API.md +1612 -124
- package/README.md +151 -7
- package/assets/web-function-deployment/index.js +58 -0
- package/assets/web-function-provider/index.js +26 -26
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/nodejs-web-function.js +1 -1
- package/lib/private/metrics.d.ts +23 -0
- package/lib/private/metrics.js +49 -0
- package/lib/private/provider-protocol.d.ts +57 -0
- package/lib/private/provider-protocol.js +13 -2
- package/lib/private/provider.d.ts +3 -3
- package/lib/private/provider.js +16 -6
- package/lib/private/regional-alarm.d.ts +23 -0
- package/lib/private/regional-alarm.js +40 -0
- package/lib/private/revision-cleanup.d.ts +19 -0
- package/lib/private/revision-cleanup.js +38 -0
- package/lib/private/rollback.d.ts +9 -0
- package/lib/private/rollback.js +3 -0
- package/lib/private/traffic-shift.d.ts +22 -0
- package/lib/private/traffic-shift.js +144 -0
- package/lib/web-function-deployment.d.ts +153 -0
- package/lib/web-function-deployment.js +125 -0
- package/lib/web-function-endpoint.d.ts +168 -19
- package/lib/web-function-endpoint.js +292 -18
- package/lib/web-function-grants.d.ts +2 -2
- package/lib/web-function-grants.js +4 -4
- package/lib/web-function-revision.d.ts +45 -0
- package/lib/web-function-revision.js +40 -0
- package/lib/web-function.d.ts +69 -9
- package/lib/web-function.js +130 -26
- package/package.json +5 -2
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TrafficShift = void 0;
|
|
37
|
+
const node_crypto_1 = require("node:crypto");
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
|
+
const iam = __importStar(require("aws-cdk-lib/aws-iam"));
|
|
41
|
+
const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
|
|
42
|
+
const logs = __importStar(require("aws-cdk-lib/aws-logs"));
|
|
43
|
+
const cr = __importStar(require("aws-cdk-lib/custom-resources"));
|
|
44
|
+
const constructs_1 = require("constructs");
|
|
45
|
+
const provider_protocol_1 = require("./provider-protocol");
|
|
46
|
+
/** The Provider framework gives up after this long and fails the deployment (with a message), before CloudFormation's own 1-hour limit. */
|
|
47
|
+
const TOTAL_TIMEOUT = aws_cdk_lib_1.Duration.minutes(55);
|
|
48
|
+
const PROVIDER_ID = 'LambdaWebDeploymentProvider';
|
|
49
|
+
/**
|
|
50
|
+
* The stack's deployment provider: a CDK Provider framework (a Step Functions waiter) around `onEvent` and `isComplete`
|
|
51
|
+
* from `handlers/web-function-deployment`, because a canary or linear deployment can run for up to an hour.
|
|
52
|
+
* One per stack, shared by every endpoint that deploys in steps.
|
|
53
|
+
*/
|
|
54
|
+
class DeploymentProvider extends constructs_1.Construct {
|
|
55
|
+
static of(scope) {
|
|
56
|
+
const stack = aws_cdk_lib_1.Stack.of(scope);
|
|
57
|
+
return stack.node.tryFindChild(PROVIDER_ID) ?? new DeploymentProvider(stack, PROVIDER_ID);
|
|
58
|
+
}
|
|
59
|
+
serviceToken;
|
|
60
|
+
role;
|
|
61
|
+
granted = new Set();
|
|
62
|
+
constructor(scope, id) {
|
|
63
|
+
super(scope, id);
|
|
64
|
+
this.role = new iam.Role(this, 'Role', {
|
|
65
|
+
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
|
|
66
|
+
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
|
|
67
|
+
});
|
|
68
|
+
// Rollback detection: is the stack rolling back? (the provider's own stack only).
|
|
69
|
+
this.grant({ actions: ['cloudformation:DescribeStacks'], resources: [aws_cdk_lib_1.Stack.of(this).stackId] });
|
|
70
|
+
// Composite alarms are only returned with DescribeAlarms on '*'.
|
|
71
|
+
this.grant({ actions: ['cloudwatch:DescribeAlarms'], resources: ['*'] });
|
|
72
|
+
const logGroup = new logs.LogGroup(this, 'Logs', { retention: logs.RetentionDays.ONE_MONTH, removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY });
|
|
73
|
+
const handler = (name, handlerName, description) => new lambda.Function(this, name, {
|
|
74
|
+
runtime: lambda.Runtime.NODEJS_24_X,
|
|
75
|
+
architecture: lambda.Architecture.ARM_64,
|
|
76
|
+
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'assets', 'web-function-deployment')),
|
|
77
|
+
handler: `index.${handlerName}`,
|
|
78
|
+
role: this.role,
|
|
79
|
+
// isComplete waits up to 5 minutes for a restore to reach every region before failing the deployment.
|
|
80
|
+
timeout: aws_cdk_lib_1.Duration.minutes(7),
|
|
81
|
+
memorySize: 256,
|
|
82
|
+
logGroup,
|
|
83
|
+
description,
|
|
84
|
+
});
|
|
85
|
+
const provider = new cr.Provider(this, 'Provider', {
|
|
86
|
+
onEventHandler: handler('OnEvent', 'onEvent', 'Starts canary and linear deployments of Lambda Web Function endpoints'),
|
|
87
|
+
isCompleteHandler: handler('IsComplete', 'isComplete', 'Moves Lambda Web Function endpoint traffic step by step and watches alarms'),
|
|
88
|
+
queryInterval: aws_cdk_lib_1.Duration.seconds(15),
|
|
89
|
+
totalTimeout: TOTAL_TIMEOUT,
|
|
90
|
+
logGroup,
|
|
91
|
+
});
|
|
92
|
+
this.serviceToken = provider.serviceToken;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Adds a statement to the handlers' role, once. Like the shared provider's grants, they must be stable across
|
|
96
|
+
* updates (prefixes, not names that change) and never reference attributes of resources that use the provider.
|
|
97
|
+
*/
|
|
98
|
+
grant(statement) {
|
|
99
|
+
const key = JSON.stringify(aws_cdk_lib_1.Stack.of(this).resolve(statement));
|
|
100
|
+
if (this.granted.has(key))
|
|
101
|
+
return;
|
|
102
|
+
this.granted.add(key);
|
|
103
|
+
this.role.addToPrincipalPolicy(new iam.PolicyStatement(statement));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Moves an endpoint's traffic to `revisionId` in steps before CloudFormation updates the endpoint (which must depend on it).
|
|
108
|
+
*/
|
|
109
|
+
class TrafficShift extends constructs_1.Construct {
|
|
110
|
+
resource;
|
|
111
|
+
constructor(scope, id, props) {
|
|
112
|
+
super(scope, id);
|
|
113
|
+
const stack = aws_cdk_lib_1.Stack.of(this);
|
|
114
|
+
const provider = DeploymentProvider.of(this);
|
|
115
|
+
const functionArn = stack.formatArn({
|
|
116
|
+
service: 'lambda', resource: 'web-function', resourceName: props.functionName, arnFormat: aws_cdk_lib_1.ArnFormat.SLASH_RESOURCE_NAME,
|
|
117
|
+
});
|
|
118
|
+
// Stable grant (see grantToProvider): every endpoint and revision of the function.
|
|
119
|
+
provider.grant({
|
|
120
|
+
actions: ['lambda:GetWebFunctionEndpoint', 'lambda:UpdateWebFunctionEndpoint'],
|
|
121
|
+
resources: [functionArn, `${functionArn}/endpoint/*`, `${functionArn}/revision/*`],
|
|
122
|
+
});
|
|
123
|
+
const deployment = props.deployment;
|
|
124
|
+
const alarmArns = [...deployment._alarms.map((a) => a.alarmArn), ...(props.alarmArns ?? [])];
|
|
125
|
+
const properties = {
|
|
126
|
+
FunctionArn: props.functionArn,
|
|
127
|
+
EndpointName: props.endpointName,
|
|
128
|
+
RevisionId: props.revisionId,
|
|
129
|
+
Steps: deployment._steps.join(','),
|
|
130
|
+
WaitSeconds: String(deployment._waitSeconds),
|
|
131
|
+
AlarmArns: alarmArns.length > 0 ? alarmArns : undefined,
|
|
132
|
+
EndpointConfig: (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(stack.resolve(props.endpointConfig))).digest('hex').slice(0, 16),
|
|
133
|
+
};
|
|
134
|
+
this.resource = new aws_cdk_lib_1.CustomResource(this, 'Resource', {
|
|
135
|
+
serviceToken: provider.serviceToken,
|
|
136
|
+
resourceType: provider_protocol_1.TRAFFIC_SHIFT_RESOURCE_TYPE,
|
|
137
|
+
properties: { ...properties },
|
|
138
|
+
// CloudFormation's maximum; the provider fails the deployment itself after 55 minutes.
|
|
139
|
+
serviceTimeout: aws_cdk_lib_1.Duration.hours(1),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.TrafficShift = TrafficShift;
|
|
144
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhZmZpYy1zaGlmdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcml2YXRlL3RyYWZmaWMtc2hpZnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsNkNBQXlDO0FBQ3pDLGdEQUFrQztBQUNsQyw2Q0FBd0Y7QUFDeEYseURBQTJDO0FBQzNDLCtEQUFpRDtBQUNqRCwyREFBNkM7QUFDN0MsaUVBQW1EO0FBQ25ELDJDQUF1QztBQUN2QywyREFBK0Y7QUFHL0YsMklBQTJJO0FBQzNJLE1BQU0sYUFBYSxHQUFHLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNDLE1BQU0sV0FBVyxHQUFHLDZCQUE2QixDQUFDO0FBRWxEOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFtQixTQUFRLHNCQUFTO0lBQ2pDLE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBZ0I7UUFDL0IsTUFBTSxLQUFLLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUIsT0FBUSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQW9DLElBQUksSUFBSSxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDaEksQ0FBQztJQUVlLFlBQVksQ0FBUztJQUNwQixJQUFJLENBQVc7SUFDZixPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUU3QyxZQUFvQixLQUFnQixFQUFFLEVBQVU7UUFDOUMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFO1lBQ3JDLFNBQVMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQztZQUMzRCxlQUFlLEVBQUUs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Q0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVM7WUFDdkQsY0FBYyxFQUFFLElBQUEsd0JBQVUsRUFBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO1NBQzVILENBQUM7UUFDRixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksNEJBQWMsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBQ25ELFlBQVksRUFBRSxRQUFRLENBQUMsWUFBWTtZQUNuQyxZQUFZLEVBQUUsK0NBQTJCO1lBQ3pDLFVBQVUsRUFBRSxFQUFFLEdBQUcsVUFBVSxFQUFFO1lBQzdCLHVGQUF1RjtZQUN2RixjQUFjLEVBQUUsc0JBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1NBQ2xDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQW5DRCxvQ0FtQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgQXJuRm9ybWF0LCBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFJlbW92YWxQb2xpY3ksIFN0YWNrIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0ICogYXMgbG9ncyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG5pbXBvcnQgKiBhcyBjciBmcm9tICdhd3MtY2RrLWxpYi9jdXN0b20tcmVzb3VyY2VzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgVFJBRkZJQ19TSElGVF9SRVNPVVJDRV9UWVBFLCB0eXBlIFRyYWZmaWNTaGlmdFByb3BlcnRpZXMgfSBmcm9tICcuL3Byb3ZpZGVyLXByb3RvY29sJztcbmltcG9ydCB0eXBlIHsgV2ViRnVuY3Rpb25EZXBsb3ltZW50IH0gZnJvbSAnLi4vd2ViLWZ1bmN0aW9uLWRlcGxveW1lbnQnO1xuXG4vKiogVGhlIFByb3ZpZGVyIGZyYW1ld29yayBnaXZlcyB1cCBhZnRlciB0aGlzIGxvbmcgYW5kIGZhaWxzIHRoZSBkZXBsb3ltZW50ICh3aXRoIGEgbWVzc2FnZSksIGJlZm9yZSBDbG91ZEZvcm1hdGlvbidzIG93biAxLWhvdXIgbGltaXQuICovXG5jb25zdCBUT1RBTF9USU1FT1VUID0gRHVyYXRpb24ubWludXRlcyg1NSk7XG5jb25zdCBQUk9WSURFUl9JRCA9ICdMYW1iZGFXZWJEZXBsb3ltZW50UHJvdmlkZXInO1xuXG4vKipcbiAqIFRoZSBzdGFjaydzIGRlcGxveW1lbnQgcHJvdmlkZXI6IGEgQ0RLIFByb3ZpZGVyIGZyYW1ld29yayAoYSBTdGVwIEZ1bmN0aW9ucyB3YWl0ZXIpIGFyb3VuZCBgb25FdmVudGAgYW5kIGBpc0NvbXBsZXRlYFxuICogZnJvbSBgaGFuZGxlcnMvd2ViLWZ1bmN0aW9uLWRlcGxveW1lbnRgLCBiZWNhdXNlIGEgY2FuYXJ5IG9yIGxpbmVhciBkZXBsb3ltZW50IGNhbiBydW4gZm9yIHVwIHRvIGFuIGhvdXIuXG4gKiBPbmUgcGVyIHN0YWNrLCBzaGFyZWQgYnkgZXZlcnkgZW5kcG9pbnQgdGhhdCBkZXBsb3lzIGluIHN0ZXBzLlxuICovXG5jbGFzcyBEZXBsb3ltZW50UHJvdmlkZXIgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgc3RhdGljIG9mKHNjb3BlOiBDb25zdHJ1Y3QpOiBEZXBsb3ltZW50UHJvdmlkZXIge1xuICAgIGNvbnN0IHN0YWNrID0gU3RhY2sub2Yoc2NvcGUpO1xuICAgIHJldHVybiAoc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoUFJPVklERVJfSUQpIGFzIERlcGxveW1lbnRQcm92aWRlciB8IHVuZGVmaW5lZCkgPz8gbmV3IERlcGxveW1lbnRQcm92aWRlcihzdGFjaywgUFJPVklERVJfSUQpO1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VUb2tlbjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHJvbGU6IGlhbS5Sb2xlO1xuICBwcml2YXRlIHJlYWRvbmx5IGdyYW50ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCAnUm9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdzZXJ2aWNlLXJvbGUvQVdTTGFtYmRhQmFzaWNFeGVjdXRpb25Sb2xlJyldLFxuICAgIH0pO1xuICAgIC8vIFJvbGxiYWNrIGRldGVjdGlvbjogaXMgdGhlIHN0YWNrIHJvbGxpbmcgYmFjaz8gKHRoZSBwcm92aWRlcidzIG93biBzdGFjayBvbmx5KS5cbiAgICB0aGlzLmdyYW50KHsgYWN0aW9uczogWydjbG91ZGZvcm1hdGlvbjpEZXNjcmliZVN0YWNrcyddLCByZXNvdXJjZXM6IFtTdGFjay5vZih0aGlzKS5zdGFja0lkXSB9KTtcbiAgICAvLyBDb21wb3NpdGUgYWxhcm1zIGFyZSBvbmx5IHJldHVybmVkIHdpdGggRGVzY3JpYmVBbGFybXMgb24gJyonLlxuICAgIHRoaXMuZ3JhbnQoeyBhY3Rpb25zOiBbJ2Nsb3Vkd2F0Y2g6RGVzY3JpYmVBbGFybXMnXSwgcmVzb3VyY2VzOiBbJyonXSB9KTtcblxuICAgIGNvbnN0IGxvZ0dyb3VwID0gbmV3IGxvZ3MuTG9nR3JvdXAodGhpcywgJ0xvZ3MnLCB7IHJldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9NT05USCwgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZIH0pO1xuICAgIGNvbnN0IGhhbmRsZXIgPSAobmFtZTogc3RyaW5nLCBoYW5kbGVyTmFtZTogc3RyaW5nLCBkZXNjcmlwdGlvbjogc3RyaW5nKSA9PiBuZXcgbGFtYmRhLkZ1bmN0aW9uKHRoaXMsIG5hbWUsIHtcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yNF9YLFxuICAgICAgYXJjaGl0ZWN0dXJlOiBsYW1iZGEuQXJjaGl0ZWN0dXJlLkFSTV82NCxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnYXNzZXRzJywgJ3dlYi1mdW5jdGlvbi1kZXBsb3ltZW50JykpLFxuICAgICAgaGFuZGxlcjogYGluZGV4LiR7aGFuZGxlck5hbWV9YCxcbiAgICAgIHJvbGU6IHRoaXMucm9sZSxcbiAgICAgIC8vIGlzQ29tcGxldGUgd2FpdHMgdXAgdG8gNSBtaW51dGVzIGZvciBhIHJlc3RvcmUgdG8gcmVhY2ggZXZlcnkgcmVnaW9uIGJlZm9yZSBmYWlsaW5nIHRoZSBkZXBsb3ltZW50LlxuICAgICAgdGltZW91dDogRHVyYXRpb24ubWludXRlcyg3KSxcbiAgICAgIG1lbW9yeVNpemU6IDI1NixcbiAgICAgIGxvZ0dyb3VwLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgfSk7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBuZXcgY3IuUHJvdmlkZXIodGhpcywgJ1Byb3ZpZGVyJywge1xuICAgICAgb25FdmVudEhhbmRsZXI6IGhhbmRsZXIoJ09uRXZlbnQnLCAnb25FdmVudCcsICdTdGFydHMgY2FuYXJ5IGFuZCBsaW5lYXIgZGVwbG95bWVudHMgb2YgTGFtYmRhIFdlYiBGdW5jdGlvbiBlbmRwb2ludHMnKSxcbiAgICAgIGlzQ29tcGxldGVIYW5kbGVyOiBoYW5kbGVyKCdJc0NvbXBsZXRlJywgJ2lzQ29tcGxldGUnLCAnTW92ZXMgTGFtYmRhIFdlYiBGdW5jdGlvbiBlbmRwb2ludCB0cmFmZmljIHN0ZXAgYnkgc3RlcCBhbmQgd2F0Y2hlcyBhbGFybXMnKSxcbiAgICAgIHF1ZXJ5SW50ZXJ2YWw6IER1cmF0aW9uLnNlY29uZHMoMTUpLFxuICAgICAgdG90YWxUaW1lb3V0OiBUT1RBTF9USU1FT1VULFxuICAgICAgbG9nR3JvdXAsXG4gICAgfSk7XG4gICAgdGhpcy5zZXJ2aWNlVG9rZW4gPSBwcm92aWRlci5zZXJ2aWNlVG9rZW47XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0YXRlbWVudCB0byB0aGUgaGFuZGxlcnMnIHJvbGUsIG9uY2UuIExpa2UgdGhlIHNoYXJlZCBwcm92aWRlcidzIGdyYW50cywgdGhleSBtdXN0IGJlIHN0YWJsZSBhY3Jvc3NcbiAgICogdXBkYXRlcyAocHJlZml4ZXMsIG5vdCBuYW1lcyB0aGF0IGNoYW5nZSkgYW5kIG5ldmVyIHJlZmVyZW5jZSBhdHRyaWJ1dGVzIG9mIHJlc291cmNlcyB0aGF0IHVzZSB0aGUgcHJvdmlkZXIuXG4gICAqL1xuICBwdWJsaWMgZ3JhbnQoc3RhdGVtZW50OiB7IGFjdGlvbnM6IHN0cmluZ1tdOyByZXNvdXJjZXM6IHN0cmluZ1tdIH0pOiB2b2lkIHtcbiAgICBjb25zdCBrZXkgPSBKU09OLnN0cmluZ2lmeShTdGFjay5vZih0aGlzKS5yZXNvbHZlKHN0YXRlbWVudCkpO1xuICAgIGlmICh0aGlzLmdyYW50ZWQuaGFzKGtleSkpIHJldHVybjtcbiAgICB0aGlzLmdyYW50ZWQuYWRkKGtleSk7XG4gICAgdGhpcy5yb2xlLmFkZFRvUHJpbmNpcGFsUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHN0YXRlbWVudCkpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhZmZpY1NoaWZ0UHJvcHMge1xuICAvKiogTGl0ZXJhbCBmdW5jdGlvbiBuYW1lLCBmb3Igc3RhYmxlIElBTSBncmFudHMuICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICByZWFkb25seSBmdW5jdGlvbkFybjogc3RyaW5nO1xuICByZWFkb25seSBlbmRwb2ludE5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgcmV2aXNpb25JZDogc3RyaW5nO1xuICByZWFkb25seSBkZXBsb3ltZW50OiBXZWJGdW5jdGlvbkRlcGxveW1lbnQ7XG4gIC8qKiBBUk5zIG9mIGFsYXJtcyB0aGUgZW5kcG9pbnQgY3JlYXRlZCAoYHJvbGxiYWNrT25gKSwgd2F0Y2hlZCB3aXRoIHRoZSBkZXBsb3ltZW50J3Mgb3duIGBhbGFybXNgLiAqL1xuICByZWFkb25seSBhbGFybUFybnM/OiBzdHJpbmdbXTtcbiAgLyoqIFRoZSBlbmRwb2ludCdzIG90aGVyIHNldHRpbmdzOiBhbnkgY2hhbmdlIG1ha2VzIHRoZSBzaGlmdCBydW4sIHNvIGl0IGNhbiByZS1jaGVjayB0aGUgdHJhZmZpYyBiZWZvcmUgQ2xvdWRGb3JtYXRpb24gd3JpdGVzIGl0LiAqL1xuICByZWFkb25seSBlbmRwb2ludENvbmZpZzogdW5rbm93bjtcbn1cblxuLyoqXG4gKiBNb3ZlcyBhbiBlbmRwb2ludCdzIHRyYWZmaWMgdG8gYHJldmlzaW9uSWRgIGluIHN0ZXBzIGJlZm9yZSBDbG91ZEZvcm1hdGlvbiB1cGRhdGVzIHRoZSBlbmRwb2ludCAod2hpY2ggbXVzdCBkZXBlbmQgb24gaXQpLlxuICovXG5leHBvcnQgY2xhc3MgVHJhZmZpY1NoaWZ0IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHJlYWRvbmx5IHJlc291cmNlOiBDdXN0b21SZXNvdXJjZTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogVHJhZmZpY1NoaWZ0UHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIGNvbnN0IHN0YWNrID0gU3RhY2sub2YodGhpcyk7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBEZXBsb3ltZW50UHJvdmlkZXIub2YodGhpcyk7XG4gICAgY29uc3QgZnVuY3Rpb25Bcm4gPSBzdGFjay5mb3JtYXRBcm4oe1xuICAgICAgc2VydmljZTogJ2xhbWJkYScsIHJlc291cmNlOiAnd2ViLWZ1bmN0aW9uJywgcmVzb3VyY2VOYW1lOiBwcm9wcy5mdW5jdGlvbk5hbWUsIGFybkZvcm1hdDogQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUsXG4gICAgfSk7XG4gICAgLy8gU3RhYmxlIGdyYW50IChzZWUgZ3JhbnRUb1Byb3ZpZGVyKTogZXZlcnkgZW5kcG9pbnQgYW5kIHJldmlzaW9uIG9mIHRoZSBmdW5jdGlvbi5cbiAgICBwcm92aWRlci5ncmFudCh7XG4gICAgICBhY3Rpb25zOiBbJ2xhbWJkYTpHZXRXZWJGdW5jdGlvbkVuZHBvaW50JywgJ2xhbWJkYTpVcGRhdGVXZWJGdW5jdGlvbkVuZHBvaW50J10sXG4gICAgICByZXNvdXJjZXM6IFtmdW5jdGlvbkFybiwgYCR7ZnVuY3Rpb25Bcm59L2VuZHBvaW50LypgLCBgJHtmdW5jdGlvbkFybn0vcmV2aXNpb24vKmBdLFxuICAgIH0pO1xuXG4gICAgY29uc3QgZGVwbG95bWVudCA9IHByb3BzLmRlcGxveW1lbnQ7XG4gICAgY29uc3QgYWxhcm1Bcm5zID0gWy4uLmRlcGxveW1lbnQuX2FsYXJtcy5tYXAoKGEpID0+IGEuYWxhcm1Bcm4pLCAuLi4ocHJvcHMuYWxhcm1Bcm5zID8/IFtdKV07XG4gICAgY29uc3QgcHJvcGVydGllczogVHJhZmZpY1NoaWZ0UHJvcGVydGllcyA9IHtcbiAgICAgIEZ1bmN0aW9uQXJuOiBwcm9wcy5mdW5jdGlvbkFybixcbiAgICAgIEVuZHBvaW50TmFtZTogcHJvcHMuZW5kcG9pbnROYW1lLFxuICAgICAgUmV2aXNpb25JZDogcHJvcHMucmV2aXNpb25JZCxcbiAgICAgIFN0ZXBzOiBkZXBsb3ltZW50Ll9zdGVwcy5qb2luKCcsJyksXG4gICAgICBXYWl0U2Vjb25kczogU3RyaW5nKGRlcGxveW1lbnQuX3dhaXRTZWNvbmRzKSxcbiAgICAgIEFsYXJtQXJuczogYWxhcm1Bcm5zLmxlbmd0aCA+IDAgPyBhbGFybUFybnMgOiB1bmRlZmluZWQsXG4gICAgICBFbmRwb2ludENvbmZpZzogY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKEpTT04uc3RyaW5naWZ5KHN0YWNrLnJlc29sdmUocHJvcHMuZW5kcG9pbnRDb25maWcpKSkuZGlnZXN0KCdoZXgnKS5zbGljZSgwLCAxNiksXG4gICAgfTtcbiAgICB0aGlzLnJlc291cmNlID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIHNlcnZpY2VUb2tlbjogcHJvdmlkZXIuc2VydmljZVRva2VuLFxuICAgICAgcmVzb3VyY2VUeXBlOiBUUkFGRklDX1NISUZUX1JFU09VUkNFX1RZUEUsXG4gICAgICBwcm9wZXJ0aWVzOiB7IC4uLnByb3BlcnRpZXMgfSxcbiAgICAgIC8vIENsb3VkRm9ybWF0aW9uJ3MgbWF4aW11bTsgdGhlIHByb3ZpZGVyIGZhaWxzIHRoZSBkZXBsb3ltZW50IGl0c2VsZiBhZnRlciA1NSBtaW51dGVzLlxuICAgICAgc2VydmljZVRpbWVvdXQ6IER1cmF0aW9uLmhvdXJzKDEpLFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Duration } from 'aws-cdk-lib';
|
|
2
|
+
import type * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
|
|
3
|
+
import type { ResolvedRollbackOptions } from './private/rollback';
|
|
4
|
+
/**
|
|
5
|
+
* Alarms an endpoint creates on its own metrics to stop a canary or linear deployment.
|
|
6
|
+
*
|
|
7
|
+
* The endpoint creates one alarm per threshold in every region it serves from (metrics are published
|
|
8
|
+
* in the region that served the request, and an alarm can only watch metrics in its own region).
|
|
9
|
+
* Lambda Web Function metrics have no revision dimension, so the alarms watch the whole endpoint: while
|
|
10
|
+
* the new revision gets 10% of the traffic, its errors are about a tenth of the endpoint's.
|
|
11
|
+
*/
|
|
12
|
+
export interface WebFunctionRollbackOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Roll back when more than this percent of the endpoint's requests get a 5XX response (0-100).
|
|
15
|
+
*
|
|
16
|
+
* 5XX includes the platform's 503s while an endpoint scales up for a sudden burst, not only your application's errors.
|
|
17
|
+
*
|
|
18
|
+
* @default - no server error alarm
|
|
19
|
+
*/
|
|
20
|
+
readonly serverErrorRate?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Roll back when more than this percent of the endpoint's requests get a 4XX response (0-100).
|
|
23
|
+
* Requests over `rateLimit` or `maxEnvironments` get 429, which counts here.
|
|
24
|
+
*
|
|
25
|
+
* @default - no client error alarm
|
|
26
|
+
*/
|
|
27
|
+
readonly clientErrorRate?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Periods with fewer requests than this don't count, so one failed request out of two doesn't roll back.
|
|
30
|
+
*
|
|
31
|
+
* @default 10
|
|
32
|
+
*/
|
|
33
|
+
readonly minimumRequests?: number;
|
|
34
|
+
/**
|
|
35
|
+
* The period each rate is measured over (at least 1 minute, in whole minutes).
|
|
36
|
+
*
|
|
37
|
+
* @default Duration.minutes(1)
|
|
38
|
+
*/
|
|
39
|
+
readonly period?: Duration;
|
|
40
|
+
/**
|
|
41
|
+
* How many consecutive periods must breach a threshold before the deployment rolls back.
|
|
42
|
+
*
|
|
43
|
+
* @default 2
|
|
44
|
+
*/
|
|
45
|
+
readonly evaluationPeriods?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Options for a canary deployment.
|
|
49
|
+
*/
|
|
50
|
+
export interface WebFunctionCanaryDeploymentOptions {
|
|
51
|
+
/**
|
|
52
|
+
* The share of traffic, in whole percent (1-99), that the new revision gets first.
|
|
53
|
+
*/
|
|
54
|
+
readonly percent: number;
|
|
55
|
+
/**
|
|
56
|
+
* How long the new revision serves `percent` before it gets all traffic (1-45 minutes).
|
|
57
|
+
* Make it longer than the time your alarms need to fire (period × evaluation periods).
|
|
58
|
+
*/
|
|
59
|
+
readonly bake: Duration;
|
|
60
|
+
/**
|
|
61
|
+
* Alarms that stop the deployment: if one is in ALARM, the endpoint goes back to the previous
|
|
62
|
+
* revision and the deployment fails, so CloudFormation rolls the stack back.
|
|
63
|
+
*
|
|
64
|
+
* They're checked before traffic moves, during the bake, and once the new revision has all traffic.
|
|
65
|
+
* Use alarms in any region (by ARN), including composite alarms.
|
|
66
|
+
*
|
|
67
|
+
* @default - no alarms: traffic moves on a timer
|
|
68
|
+
*/
|
|
69
|
+
readonly alarms?: cloudwatch.IAlarm[];
|
|
70
|
+
/**
|
|
71
|
+
* Alarms on the endpoint's own error rates, created by the endpoint in every region it serves from.
|
|
72
|
+
* They stop the deployment like `alarms` (both can be used together).
|
|
73
|
+
*
|
|
74
|
+
* @default - no endpoint alarms
|
|
75
|
+
*/
|
|
76
|
+
readonly rollbackOn?: WebFunctionRollbackOptions;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Options for a linear deployment.
|
|
80
|
+
*/
|
|
81
|
+
export interface WebFunctionLinearDeploymentOptions {
|
|
82
|
+
/**
|
|
83
|
+
* The share of traffic, in whole percent (5-50), that moves to the new revision at each step.
|
|
84
|
+
*/
|
|
85
|
+
readonly percent: number;
|
|
86
|
+
/**
|
|
87
|
+
* How long each step serves before the next one (at least 1 minute, and at most 45 minutes in total).
|
|
88
|
+
*/
|
|
89
|
+
readonly interval: Duration;
|
|
90
|
+
/**
|
|
91
|
+
* Alarms that stop the deployment: if one is in ALARM, the endpoint goes back to the previous
|
|
92
|
+
* revision and the deployment fails, so CloudFormation rolls the stack back.
|
|
93
|
+
*
|
|
94
|
+
* They're checked before traffic moves, during every step, and once the new revision has all traffic.
|
|
95
|
+
* Use alarms in any region (by ARN), including composite alarms.
|
|
96
|
+
*
|
|
97
|
+
* @default - no alarms: traffic moves on a timer
|
|
98
|
+
*/
|
|
99
|
+
readonly alarms?: cloudwatch.IAlarm[];
|
|
100
|
+
/**
|
|
101
|
+
* Alarms on the endpoint's own error rates, created by the endpoint in every region it serves from.
|
|
102
|
+
* They stop the deployment like `alarms` (both can be used together).
|
|
103
|
+
*
|
|
104
|
+
* @default - no endpoint alarms
|
|
105
|
+
*/
|
|
106
|
+
readonly rollbackOn?: WebFunctionRollbackOptions;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* How an endpoint moves its traffic to a new revision.
|
|
110
|
+
*/
|
|
111
|
+
export declare class WebFunctionDeployment {
|
|
112
|
+
/**
|
|
113
|
+
* All traffic moves to the new revision at once, as soon as it's ready (the default).
|
|
114
|
+
*/
|
|
115
|
+
static allAtOnce(): WebFunctionDeployment;
|
|
116
|
+
/**
|
|
117
|
+
* The new revision first gets `percent` of the traffic for `bake`, then all of it.
|
|
118
|
+
*/
|
|
119
|
+
static canary(options: WebFunctionCanaryDeploymentOptions): WebFunctionDeployment;
|
|
120
|
+
/**
|
|
121
|
+
* The new revision gets `percent` more of the traffic every `interval` until it has all of it.
|
|
122
|
+
*/
|
|
123
|
+
static linear(options: WebFunctionLinearDeploymentOptions): WebFunctionDeployment;
|
|
124
|
+
/**
|
|
125
|
+
* The new revision's share of traffic at each step, in percent; the last is 100.
|
|
126
|
+
*
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
readonly _steps: number[];
|
|
130
|
+
/**
|
|
131
|
+
* Seconds each step serves before the next.
|
|
132
|
+
*
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
readonly _waitSeconds: number;
|
|
136
|
+
/** @internal */
|
|
137
|
+
readonly _alarms: cloudwatch.IAlarm[];
|
|
138
|
+
/** @internal */
|
|
139
|
+
readonly _kind: string;
|
|
140
|
+
/**
|
|
141
|
+
* Thresholds for the alarms the endpoint creates, with defaults applied.
|
|
142
|
+
*
|
|
143
|
+
* @internal
|
|
144
|
+
*/
|
|
145
|
+
readonly _rollbackOn?: ResolvedRollbackOptions;
|
|
146
|
+
private constructor();
|
|
147
|
+
/**
|
|
148
|
+
* Whether traffic moves in steps (canary or linear) rather than all at once.
|
|
149
|
+
*
|
|
150
|
+
* @internal
|
|
151
|
+
*/
|
|
152
|
+
get _gradual(): boolean;
|
|
153
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebFunctionDeployment = void 0;
|
|
4
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
/** Longest total wait of a deployment: the deployment step must finish within CloudFormation's 1-hour custom resource limit. */
|
|
7
|
+
const MAX_TOTAL_WAIT_MINUTES = 45;
|
|
8
|
+
/** Most traffic steps: each one also waits for the endpoint to update in every region. */
|
|
9
|
+
const MAX_STEPS = 20;
|
|
10
|
+
/**
|
|
11
|
+
* How an endpoint moves its traffic to a new revision.
|
|
12
|
+
*/
|
|
13
|
+
class WebFunctionDeployment {
|
|
14
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "@ashishpandeyone/cdk-lambda-web-function.WebFunctionDeployment", version: "0.1.3" };
|
|
15
|
+
/**
|
|
16
|
+
* All traffic moves to the new revision at once, as soon as it's ready (the default).
|
|
17
|
+
*/
|
|
18
|
+
static allAtOnce() {
|
|
19
|
+
return new WebFunctionDeployment('allAtOnce', [100], 0, [], undefined);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The new revision first gets `percent` of the traffic for `bake`, then all of it.
|
|
23
|
+
*/
|
|
24
|
+
static canary(options) {
|
|
25
|
+
const percent = wholePercent('canary', 'percent', options.percent, 1, 99);
|
|
26
|
+
const bake = minutes('canary', 'bake', options.bake, MAX_TOTAL_WAIT_MINUTES);
|
|
27
|
+
return new WebFunctionDeployment('canary', [percent, 100], bake.toSeconds(), options.alarms ?? [], rollbackOn('canary', options.rollbackOn));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The new revision gets `percent` more of the traffic every `interval` until it has all of it.
|
|
31
|
+
*/
|
|
32
|
+
static linear(options) {
|
|
33
|
+
const percent = wholePercent('linear', 'percent', options.percent, 100 / MAX_STEPS, 50);
|
|
34
|
+
const interval = minutes('linear', 'interval', options.interval, MAX_TOTAL_WAIT_MINUTES);
|
|
35
|
+
const steps = [];
|
|
36
|
+
for (let p = percent; p < 100; p += percent)
|
|
37
|
+
steps.push(p);
|
|
38
|
+
steps.push(100);
|
|
39
|
+
const total = interval.toSeconds() * (steps.length - 1);
|
|
40
|
+
if (total > MAX_TOTAL_WAIT_MINUTES * 60) {
|
|
41
|
+
throw new Error(`WebFunctionDeployment.linear: ${steps.length - 1} intervals of ${interval.toHumanString()} take ${total / 60} minutes; at most ${MAX_TOTAL_WAIT_MINUTES} are allowed`);
|
|
42
|
+
}
|
|
43
|
+
return new WebFunctionDeployment('linear', steps, interval.toSeconds(), options.alarms ?? [], rollbackOn('linear', options.rollbackOn));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The new revision's share of traffic at each step, in percent; the last is 100.
|
|
47
|
+
*
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
_steps;
|
|
51
|
+
/**
|
|
52
|
+
* Seconds each step serves before the next.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
_waitSeconds;
|
|
57
|
+
/** @internal */
|
|
58
|
+
_alarms;
|
|
59
|
+
/** @internal */
|
|
60
|
+
_kind;
|
|
61
|
+
/**
|
|
62
|
+
* Thresholds for the alarms the endpoint creates, with defaults applied.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
_rollbackOn;
|
|
67
|
+
constructor(kind, steps, waitSeconds, alarms, rollback) {
|
|
68
|
+
this._kind = kind;
|
|
69
|
+
this._steps = steps;
|
|
70
|
+
this._waitSeconds = waitSeconds;
|
|
71
|
+
this._alarms = alarms;
|
|
72
|
+
this._rollbackOn = rollback;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether traffic moves in steps (canary or linear) rather than all at once.
|
|
76
|
+
*
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
get _gradual() {
|
|
80
|
+
return this._steps.length > 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.WebFunctionDeployment = WebFunctionDeployment;
|
|
84
|
+
function wholePercent(kind, name, value, min, max) {
|
|
85
|
+
if (aws_cdk_lib_1.Token.isUnresolved(value) || !Number.isInteger(value) || value < min || value > max) {
|
|
86
|
+
throw new Error(`WebFunctionDeployment.${kind}: ${name} must be a whole number from ${Math.ceil(min)} to ${max}, got ${value}`);
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
function minutes(kind, name, value, maxMinutes) {
|
|
91
|
+
const seconds = value.toSeconds();
|
|
92
|
+
if (aws_cdk_lib_1.Token.isUnresolved(seconds) || seconds < 60 || seconds > maxMinutes * 60) {
|
|
93
|
+
throw new Error(`WebFunctionDeployment.${kind}: ${name} must be from 1 to ${maxMinutes} minutes, got ${aws_cdk_lib_1.Token.isUnresolved(seconds) ? 'a token' : value.toHumanString()}`);
|
|
94
|
+
}
|
|
95
|
+
return aws_cdk_lib_1.Duration.seconds(seconds);
|
|
96
|
+
}
|
|
97
|
+
function rollbackOn(kind, options) {
|
|
98
|
+
if (options === undefined)
|
|
99
|
+
return undefined;
|
|
100
|
+
const fail = (message) => {
|
|
101
|
+
throw new Error(`WebFunctionDeployment.${kind}: rollbackOn.${message}`);
|
|
102
|
+
};
|
|
103
|
+
if (options.serverErrorRate === undefined && options.clientErrorRate === undefined) {
|
|
104
|
+
fail('serverErrorRate or rollbackOn.clientErrorRate is required');
|
|
105
|
+
}
|
|
106
|
+
for (const [name, rate] of [['serverErrorRate', options.serverErrorRate], ['clientErrorRate', options.clientErrorRate]]) {
|
|
107
|
+
if (rate !== undefined && (aws_cdk_lib_1.Token.isUnresolved(rate) || !(rate >= 0 && rate < 100)))
|
|
108
|
+
fail(`${name} must be a percentage from 0 to below 100, got ${rate}`);
|
|
109
|
+
}
|
|
110
|
+
const minimumRequests = options.minimumRequests ?? 10;
|
|
111
|
+
if (aws_cdk_lib_1.Token.isUnresolved(minimumRequests) || !Number.isInteger(minimumRequests) || minimumRequests < 1) {
|
|
112
|
+
fail(`minimumRequests must be a whole number from 1, got ${minimumRequests}`);
|
|
113
|
+
}
|
|
114
|
+
const period = options.period ?? aws_cdk_lib_1.Duration.minutes(1);
|
|
115
|
+
const seconds = period.toSeconds();
|
|
116
|
+
if (aws_cdk_lib_1.Token.isUnresolved(seconds) || seconds < 60 || seconds % 60 !== 0) {
|
|
117
|
+
fail(`period must be whole minutes, at least 1, got ${aws_cdk_lib_1.Token.isUnresolved(seconds) ? 'a token' : period.toHumanString()}`);
|
|
118
|
+
}
|
|
119
|
+
const evaluationPeriods = options.evaluationPeriods ?? 2;
|
|
120
|
+
if (aws_cdk_lib_1.Token.isUnresolved(evaluationPeriods) || !Number.isInteger(evaluationPeriods) || evaluationPeriods < 1) {
|
|
121
|
+
fail(`evaluationPeriods must be a whole number from 1, got ${evaluationPeriods}`);
|
|
122
|
+
}
|
|
123
|
+
return { serverErrorRate: options.serverErrorRate, clientErrorRate: options.clientErrorRate, minimumRequests, period, evaluationPeriods };
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViLWZ1bmN0aW9uLWRlcGxveW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvd2ViLWZ1bmN0aW9uLWRlcGxveW1lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLDZDQUE4QztBQUk5QyxnSUFBZ0k7QUFDaEksTUFBTSxzQkFBc0IsR0FBRyxFQUFFLENBQUM7QUFDbEMsMEZBQTBGO0FBQzFGLE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQztBQXVIckI7O0dBRUc7QUFDSCxNQUFhLHFCQUFxQjs7SUFDaEM7O09BRUc7SUFDSSxNQUFNLENBQUMsU0FBUztRQUNyQixPQUFPLElBQUkscUJBQXFCLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRUQ7O09BRUc7SUFDSSxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQTJDO1FBQzlELE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUM3RSxPQUFPLElBQUkscUJBQXFCLENBQUMsUUFBUSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQy9JLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBMkM7UUFDOUQsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLFFBQVEsRUFB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LGVBQWUsRUFBRSxlQUFlLEVBQUUsTUFBTSxFQUFFLGlCQUFpQixFQUFFLENBQUM7QUFDNUksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IER1cmF0aW9uLCBUb2tlbiB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB0eXBlICogYXMgY2xvdWR3YXRjaCBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2xvdWR3YXRjaCc7XG5pbXBvcnQgdHlwZSB7IFJlc29sdmVkUm9sbGJhY2tPcHRpb25zIH0gZnJvbSAnLi9wcml2YXRlL3JvbGxiYWNrJztcblxuLyoqIExvbmdlc3QgdG90YWwgd2FpdCBvZiBhIGRlcGxveW1lbnQ6IHRoZSBkZXBsb3ltZW50IHN0ZXAgbXVzdCBmaW5pc2ggd2l0aGluIENsb3VkRm9ybWF0aW9uJ3MgMS1ob3VyIGN1c3RvbSByZXNvdXJjZSBsaW1pdC4gKi9cbmNvbnN0IE1BWF9UT1RBTF9XQUlUX01JTlVURVMgPSA0NTtcbi8qKiBNb3N0IHRyYWZmaWMgc3RlcHM6IGVhY2ggb25lIGFsc28gd2FpdHMgZm9yIHRoZSBlbmRwb2ludCB0byB1cGRhdGUgaW4gZXZlcnkgcmVnaW9uLiAqL1xuY29uc3QgTUFYX1NURVBTID0gMjA7XG5cbi8qKlxuICogQWxhcm1zIGFuIGVuZHBvaW50IGNyZWF0ZXMgb24gaXRzIG93biBtZXRyaWNzIHRvIHN0b3AgYSBjYW5hcnkgb3IgbGluZWFyIGRlcGxveW1lbnQuXG4gKlxuICogVGhlIGVuZHBvaW50IGNyZWF0ZXMgb25lIGFsYXJtIHBlciB0aHJlc2hvbGQgaW4gZXZlcnkgcmVnaW9uIGl0IHNlcnZlcyBmcm9tIChtZXRyaWNzIGFyZSBwdWJsaXNoZWRcbiAqIGluIHRoZSByZWdpb24gdGhhdCBzZXJ2ZWQgdGhlIHJlcXVlc3QsIGFuZCBhbiBhbGFybSBjYW4gb25seSB3YXRjaCBtZXRyaWNzIGluIGl0cyBvd24gcmVnaW9uKS5cbiAqIExhbWJkYSBXZWIgRnVuY3Rpb24gbWV0cmljcyBoYXZlIG5vIHJldmlzaW9uIGRpbWVuc2lvbiwgc28gdGhlIGFsYXJtcyB3YXRjaCB0aGUgd2hvbGUgZW5kcG9pbnQ6IHdoaWxlXG4gKiB0aGUgbmV3IHJldmlzaW9uIGdldHMgMTAlIG9mIHRoZSB0cmFmZmljLCBpdHMgZXJyb3JzIGFyZSBhYm91dCBhIHRlbnRoIG9mIHRoZSBlbmRwb2ludCdzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYkZ1bmN0aW9uUm9sbGJhY2tPcHRpb25zIHtcbiAgLyoqXG4gICAqIFJvbGwgYmFjayB3aGVuIG1vcmUgdGhhbiB0aGlzIHBlcmNlbnQgb2YgdGhlIGVuZHBvaW50J3MgcmVxdWVzdHMgZ2V0IGEgNVhYIHJlc3BvbnNlICgwLTEwMCkuXG4gICAqXG4gICAqIDVYWCBpbmNsdWRlcyB0aGUgcGxhdGZvcm0ncyA1MDNzIHdoaWxlIGFuIGVuZHBvaW50IHNjYWxlcyB1cCBmb3IgYSBzdWRkZW4gYnVyc3QsIG5vdCBvbmx5IHlvdXIgYXBwbGljYXRpb24ncyBlcnJvcnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gc2VydmVyIGVycm9yIGFsYXJtXG4gICAqL1xuICByZWFkb25seSBzZXJ2ZXJFcnJvclJhdGU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFJvbGwgYmFjayB3aGVuIG1vcmUgdGhhbiB0aGlzIHBlcmNlbnQgb2YgdGhlIGVuZHBvaW50J3MgcmVxdWVzdHMgZ2V0IGEgNFhYIHJlc3BvbnNlICgwLTEwMCkuXG4gICAqIFJlcXVlc3RzIG92ZXIgYHJhdGVMaW1pdGAgb3IgYG1heEVudmlyb25tZW50c2AgZ2V0IDQyOSwgd2hpY2ggY291bnRzIGhlcmUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gY2xpZW50IGVycm9yIGFsYXJtXG4gICAqL1xuICByZWFkb25seSBjbGllbnRFcnJvclJhdGU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFBlcmlvZHMgd2l0aCBmZXdlciByZXF1ZXN0cyB0aGFuIHRoaXMgZG9uJ3QgY291bnQsIHNvIG9uZSBmYWlsZWQgcmVxdWVzdCBvdXQgb2YgdHdvIGRvZXNuJ3Qgcm9sbCBiYWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMFxuICAgKi9cbiAgcmVhZG9ubHkgbWluaW11bVJlcXVlc3RzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgcGVyaW9kIGVhY2ggcmF0ZSBpcyBtZWFzdXJlZCBvdmVyIChhdCBsZWFzdCAxIG1pbnV0ZSwgaW4gd2hvbGUgbWludXRlcykuXG4gICAqXG4gICAqIEBkZWZhdWx0IER1cmF0aW9uLm1pbnV0ZXMoMSlcbiAgICovXG4gIHJlYWRvbmx5IHBlcmlvZD86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBIb3cgbWFueSBjb25zZWN1dGl2ZSBwZXJpb2RzIG11c3QgYnJlYWNoIGEgdGhyZXNob2xkIGJlZm9yZSB0aGUgZGVwbG95bWVudCByb2xscyBiYWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAyXG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBhIGNhbmFyeSBkZXBsb3ltZW50LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYkZ1bmN0aW9uQ2FuYXJ5RGVwbG95bWVudE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIHNoYXJlIG9mIHRyYWZmaWMsIGluIHdob2xlIHBlcmNlbnQgKDEtOTkpLCB0aGF0IHRoZSBuZXcgcmV2aXNpb24gZ2V0cyBmaXJzdC5cbiAgICovXG4gIHJlYWRvbmx5IHBlcmNlbnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogSG93IGxvbmcgdGhlIG5ldyByZXZpc2lvbiBzZXJ2ZXMgYHBlcmNlbnRgIGJlZm9yZSBpdCBnZXRzIGFsbCB0cmFmZmljICgxLTQ1IG1pbnV0ZXMpLlxuICAgKiBNYWtlIGl0IGxvbmdlciB0aGFuIHRoZSB0aW1lIHlvdXIgYWxhcm1zIG5lZWQgdG8gZmlyZSAocGVyaW9kIMOXIGV2YWx1YXRpb24gcGVyaW9kcykuXG4gICAqL1xuICByZWFkb25seSBiYWtlOiBEdXJhdGlvbjtcblxuICAvKipcbiAgICogQWxhcm1zIHRoYXQgc3RvcCB0aGUgZGVwbG95bWVudDogaWYgb25lIGlzIGluIEFMQVJNLCB0aGUgZW5kcG9pbnQgZ29lcyBiYWNrIHRvIHRoZSBwcmV2aW91c1xuICAgKiByZXZpc2lvbiBhbmQgdGhlIGRlcGxveW1lbnQgZmFpbHMsIHNvIENsb3VkRm9ybWF0aW9uIHJvbGxzIHRoZSBzdGFjayBiYWNrLlxuICAgKlxuICAgKiBUaGV5J3JlIGNoZWNrZWQgYmVmb3JlIHRyYWZmaWMgbW92ZXMsIGR1cmluZyB0aGUgYmFrZSwgYW5kIG9uY2UgdGhlIG5ldyByZXZpc2lvbiBoYXMgYWxsIHRyYWZmaWMuXG4gICAqIFVzZSBhbGFybXMgaW4gYW55IHJlZ2lvbiAoYnkgQVJOKSwgaW5jbHVkaW5nIGNvbXBvc2l0ZSBhbGFybXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYWxhcm1zOiB0cmFmZmljIG1vdmVzIG9uIGEgdGltZXJcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtcz86IGNsb3Vkd2F0Y2guSUFsYXJtW107XG5cbiAgLyoqXG4gICAqIEFsYXJtcyBvbiB0aGUgZW5kcG9pbnQncyBvd24gZXJyb3IgcmF0ZXMsIGNyZWF0ZWQgYnkgdGhlIGVuZHBvaW50IGluIGV2ZXJ5IHJlZ2lvbiBpdCBzZXJ2ZXMgZnJvbS5cbiAgICogVGhleSBzdG9wIHRoZSBkZXBsb3ltZW50IGxpa2UgYGFsYXJtc2AgKGJvdGggY2FuIGJlIHVzZWQgdG9nZXRoZXIpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGVuZHBvaW50IGFsYXJtc1xuICAgKi9cbiAgcmVhZG9ubHkgcm9sbGJhY2tPbj86IFdlYkZ1bmN0aW9uUm9sbGJhY2tPcHRpb25zO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGEgbGluZWFyIGRlcGxveW1lbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2ViRnVuY3Rpb25MaW5lYXJEZXBsb3ltZW50T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgc2hhcmUgb2YgdHJhZmZpYywgaW4gd2hvbGUgcGVyY2VudCAoNS01MCksIHRoYXQgbW92ZXMgdG8gdGhlIG5ldyByZXZpc2lvbiBhdCBlYWNoIHN0ZXAuXG4gICAqL1xuICByZWFkb25seSBwZXJjZW50OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEhvdyBsb25nIGVhY2ggc3RlcCBzZXJ2ZXMgYmVmb3JlIHRoZSBuZXh0IG9uZSAoYXQgbGVhc3QgMSBtaW51dGUsIGFuZCBhdCBtb3N0IDQ1IG1pbnV0ZXMgaW4gdG90YWwpLlxuICAgKi9cbiAgcmVhZG9ubHkgaW50ZXJ2YWw6IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBBbGFybXMgdGhhdCBzdG9wIHRoZSBkZXBsb3ltZW50OiBpZiBvbmUgaXMgaW4gQUxBUk0sIHRoZSBlbmRwb2ludCBnb2VzIGJhY2sgdG8gdGhlIHByZXZpb3VzXG4gICAqIHJldmlzaW9uIGFuZCB0aGUgZGVwbG95bWVudCBmYWlscywgc28gQ2xvdWRGb3JtYXRpb24gcm9sbHMgdGhlIHN0YWNrIGJhY2suXG4gICAqXG4gICAqIFRoZXkncmUgY2hlY2tlZCBiZWZvcmUgdHJhZmZpYyBtb3ZlcywgZHVyaW5nIGV2ZXJ5IHN0ZXAsIGFuZCBvbmNlIHRoZSBuZXcgcmV2aXNpb24gaGFzIGFsbCB0cmFmZmljLlxuICAgKiBVc2UgYWxhcm1zIGluIGFueSByZWdpb24gKGJ5IEFSTiksIGluY2x1ZGluZyBjb21wb3NpdGUgYWxhcm1zLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGFsYXJtczogdHJhZmZpYyBtb3ZlcyBvbiBhIHRpbWVyXG4gICAqL1xuICByZWFkb25seSBhbGFybXM/OiBjbG91ZHdhdGNoLklBbGFybVtdO1xuXG4gIC8qKlxuICAgKiBBbGFybXMgb24gdGhlIGVuZHBvaW50J3Mgb3duIGVycm9yIHJhdGVzLCBjcmVhdGVkIGJ5IHRoZSBlbmRwb2ludCBpbiBldmVyeSByZWdpb24gaXQgc2VydmVzIGZyb20uXG4gICAqIFRoZXkgc3RvcCB0aGUgZGVwbG95bWVudCBsaWtlIGBhbGFybXNgIChib3RoIGNhbiBiZSB1c2VkIHRvZ2V0aGVyKS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBlbmRwb2ludCBhbGFybXNcbiAgICovXG4gIHJlYWRvbmx5IHJvbGxiYWNrT24/OiBXZWJGdW5jdGlvblJvbGxiYWNrT3B0aW9ucztcbn1cblxuLyoqXG4gKiBIb3cgYW4gZW5kcG9pbnQgbW92ZXMgaXRzIHRyYWZmaWMgdG8gYSBuZXcgcmV2aXNpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBXZWJGdW5jdGlvbkRlcGxveW1lbnQge1xuICAvKipcbiAgICogQWxsIHRyYWZmaWMgbW92ZXMgdG8gdGhlIG5ldyByZXZpc2lvbiBhdCBvbmNlLCBhcyBzb29uIGFzIGl0J3MgcmVhZHkgKHRoZSBkZWZhdWx0KS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYWxsQXRPbmNlKCk6IFdlYkZ1bmN0aW9uRGVwbG95bWVudCB7XG4gICAgcmV0dXJuIG5ldyBXZWJGdW5jdGlvbkRlcGxveW1lbnQoJ2FsbEF0T25jZScsIFsxMDBdLCAwLCBbXSwgdW5kZWZpbmVkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbmV3IHJldmlzaW9uIGZpcnN0IGdldHMgYHBlcmNlbnRgIG9mIHRoZSB0cmFmZmljIGZvciBgYmFrZWAsIHRoZW4gYWxsIG9mIGl0LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjYW5hcnkob3B0aW9uczogV2ViRnVuY3Rpb25DYW5hcnlEZXBsb3ltZW50T3B0aW9ucyk6IFdlYkZ1bmN0aW9uRGVwbG95bWVudCB7XG4gICAgY29uc3QgcGVyY2VudCA9IHdob2xlUGVyY2VudCgnY2FuYXJ5JywgJ3BlcmNlbnQnLCBvcHRpb25zLnBlcmNlbnQsIDEsIDk5KTtcbiAgICBjb25zdCBiYWtlID0gbWludXRlcygnY2FuYXJ5JywgJ2Jha2UnLCBvcHRpb25zLmJha2UsIE1BWF9UT1RBTF9XQUlUX01JTlVURVMpO1xuICAgIHJldHVybiBuZXcgV2ViRnVuY3Rpb25EZXBsb3ltZW50KCdjYW5hcnknLCBbcGVyY2VudCwgMTAwXSwgYmFrZS50b1NlY29uZHMoKSwgb3B0aW9ucy5hbGFybXMgPz8gW10sIHJvbGxiYWNrT24oJ2NhbmFyeScsIG9wdGlvbnMucm9sbGJhY2tPbikpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBuZXcgcmV2aXNpb24gZ2V0cyBgcGVyY2VudGAgbW9yZSBvZiB0aGUgdHJhZmZpYyBldmVyeSBgaW50ZXJ2YWxgIHVudGlsIGl0IGhhcyBhbGwgb2YgaXQuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGxpbmVhcihvcHRpb25zOiBXZWJGdW5jdGlvbkxpbmVhckRlcGxveW1lbnRPcHRpb25zKTogV2ViRnVuY3Rpb25EZXBsb3ltZW50IHtcbiAgICBjb25zdCBwZXJjZW50ID0gd2hvbGVQZXJjZW50KCdsaW5lYXInLCAncGVyY2VudCcsIG9wdGlvbnMucGVyY2VudCwgMTAwIC8gTUFYX1NURVBTLCA1MCk7XG4gICAgY29uc3QgaW50ZXJ2YWwgPSBtaW51dGVzKCdsaW5lYXInLCAnaW50ZXJ2YWwnLCBvcHRpb25zLmludGVydmFsLCBNQVhfVE9UQUxfV0FJVF9NSU5VVEVTKTtcbiAgICBjb25zdCBzdGVwczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBwID0gcGVyY2VudDsgcCA8IDEwMDsgcCArPSBwZXJjZW50KSBzdGVwcy5wdXNoKHApO1xuICAgIHN0ZXBzLnB1c2goMTAwKTtcbiAgICBjb25zdCB0b3RhbCA9IGludGVydmFsLnRvU2Vjb25kcygpICogKHN0ZXBzLmxlbmd0aCAtIDEpO1xuICAgIGlmICh0b3RhbCA+IE1BWF9UT1RBTF9XQUlUX01JTlVURVMgKiA2MCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBXZWJGdW5jdGlvbkRlcGxveW1lbnQubGluZWFyOiAke3N0ZXBzLmxlbmd0aCAtIDF9IGludGVydmFscyBvZiAke2ludGVydmFsLnRvSHVtYW5TdHJpbmcoKX0gdGFrZSAke3RvdGFsIC8gNjB9IG1pbnV0ZXM7IGF0IG1vc3QgJHtNQVhfVE9UQUxfV0FJVF9NSU5VVEVTfSBhcmUgYWxsb3dlZGApO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFdlYkZ1bmN0aW9uRGVwbG95bWVudCgnbGluZWFyJywgc3RlcHMsIGludGVydmFsLnRvU2Vjb25kcygpLCBvcHRpb25zLmFsYXJtcyA/PyBbXSwgcm9sbGJhY2tPbignbGluZWFyJywgb3B0aW9ucy5yb2xsYmFja09uKSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIG5ldyByZXZpc2lvbidzIHNoYXJlIG9mIHRyYWZmaWMgYXQgZWFjaCBzdGVwLCBpbiBwZXJjZW50OyB0aGUgbGFzdCBpcyAxMDAuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IF9zdGVwczogbnVtYmVyW107XG5cbiAgLyoqXG4gICAqIFNlY29uZHMgZWFjaCBzdGVwIHNlcnZlcyBiZWZvcmUgdGhlIG5leHQuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IF93YWl0U2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgcHVibGljIHJlYWRvbmx5IF9hbGFybXM6IGNsb3Vkd2F0Y2guSUFsYXJtW107XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBwdWJsaWMgcmVhZG9ubHkgX2tpbmQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhyZXNob2xkcyBmb3IgdGhlIGFsYXJtcyB0aGUgZW5kcG9pbnQgY3JlYXRlcywgd2l0aCBkZWZhdWx0cyBhcHBsaWVkLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBfcm9sbGJhY2tPbj86IFJlc29sdmVkUm9sbGJhY2tPcHRpb25zO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoXG4gICAga2luZDogc3RyaW5nLCBzdGVwczogbnVtYmVyW10sIHdhaXRTZWNvbmRzOiBudW1iZXIsIGFsYXJtczogY2xvdWR3YXRjaC5JQWxhcm1bXSwgcm9sbGJhY2s6IFJlc29sdmVkUm9sbGJhY2tPcHRpb25zIHwgdW5kZWZpbmVkLFxuICApIHtcbiAgICB0aGlzLl9raW5kID0ga2luZDtcbiAgICB0aGlzLl9zdGVwcyA9IHN0ZXBzO1xuICAgIHRoaXMuX3dhaXRTZWNvbmRzID0gd2FpdFNlY29uZHM7XG4gICAgdGhpcy5fYWxhcm1zID0gYWxhcm1zO1xuICAgIHRoaXMuX3JvbGxiYWNrT24gPSByb2xsYmFjaztcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRyYWZmaWMgbW92ZXMgaW4gc3RlcHMgKGNhbmFyeSBvciBsaW5lYXIpIHJhdGhlciB0aGFuIGFsbCBhdCBvbmNlLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBnZXQgX2dyYWR1YWwoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX3N0ZXBzLmxlbmd0aCA+IDE7XG4gIH1cbn1cblxuZnVuY3Rpb24gd2hvbGVQZXJjZW50KGtpbmQ6IHN0cmluZywgbmFtZTogc3RyaW5nLCB2YWx1ZTogbnVtYmVyLCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIpOiBudW1iZXIge1xuICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHZhbHVlKSB8fCAhTnVtYmVyLmlzSW50ZWdlcih2YWx1ZSkgfHwgdmFsdWUgPCBtaW4gfHwgdmFsdWUgPiBtYXgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFdlYkZ1bmN0aW9uRGVwbG95bWVudC4ke2tpbmR9OiAke25hbWV9IG11c3QgYmUgYSB3aG9sZSBudW1iZXIgZnJvbSAke01hdGguY2VpbChtaW4pfSB0byAke21heH0sIGdvdCAke3ZhbHVlfWApO1xuICB9XG4gIHJldHVybiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gbWludXRlcyhraW5kOiBzdHJpbmcsIG5hbWU6IHN0cmluZywgdmFsdWU6IER1cmF0aW9uLCBtYXhNaW51dGVzOiBudW1iZXIpOiBEdXJhdGlvbiB7XG4gIGNvbnN0IHNlY29uZHMgPSB2YWx1ZS50b1NlY29uZHMoKTtcbiAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChzZWNvbmRzKSB8fCBzZWNvbmRzIDwgNjAgfHwgc2Vjb25kcyA+IG1heE1pbnV0ZXMgKiA2MCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgV2ViRnVuY3Rpb25EZXBsb3ltZW50LiR7a2luZH06ICR7bmFtZX0gbXVzdCBiZSBmcm9tIDEgdG8gJHttYXhNaW51dGVzfSBtaW51dGVzLCBnb3QgJHtUb2tlbi5pc1VucmVzb2x2ZWQoc2Vjb25kcykgPyAnYSB0b2tlbicgOiB2YWx1ZS50b0h1bWFuU3RyaW5nKCl9YCk7XG4gIH1cbiAgcmV0dXJuIER1cmF0aW9uLnNlY29uZHMoc2Vjb25kcyk7XG59XG5cbmZ1bmN0aW9uIHJvbGxiYWNrT24oa2luZDogc3RyaW5nLCBvcHRpb25zOiBXZWJGdW5jdGlvblJvbGxiYWNrT3B0aW9ucyB8IHVuZGVmaW5lZCk6IFJlc29sdmVkUm9sbGJhY2tPcHRpb25zIHwgdW5kZWZpbmVkIHtcbiAgaWYgKG9wdGlvbnMgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgZmFpbCA9IChtZXNzYWdlOiBzdHJpbmcpID0+IHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFdlYkZ1bmN0aW9uRGVwbG95bWVudC4ke2tpbmR9OiByb2xsYmFja09uLiR7bWVzc2FnZX1gKTtcbiAgfTtcbiAgaWYgKG9wdGlvbnMuc2VydmVyRXJyb3JSYXRlID09PSB1bmRlZmluZWQgJiYgb3B0aW9ucy5jbGllbnRFcnJvclJhdGUgPT09IHVuZGVmaW5lZCkge1xuICAgIGZhaWwoJ3NlcnZlckVycm9yUmF0ZSBvciByb2xsYmFja09uLmNsaWVudEVycm9yUmF0ZSBpcyByZXF1aXJlZCcpO1xuICB9XG4gIGZvciAoY29uc3QgW25hbWUsIHJhdGVdIG9mIFtbJ3NlcnZlckVycm9yUmF0ZScsIG9wdGlvbnMuc2VydmVyRXJyb3JSYXRlXSwgWydjbGllbnRFcnJvclJhdGUnLCBvcHRpb25zLmNsaWVudEVycm9yUmF0ZV1dIGFzIGNvbnN0KSB7XG4gICAgaWYgKHJhdGUgIT09IHVuZGVmaW5lZCAmJiAoVG9rZW4uaXNVbnJlc29sdmVkKHJhdGUpIHx8ICEocmF0ZSA+PSAwICYmIHJhdGUgPCAxMDApKSkgZmFpbChgJHtuYW1lfSBtdXN0IGJlIGEgcGVyY2VudGFnZSBmcm9tIDAgdG8gYmVsb3cgMTAwLCBnb3QgJHtyYXRlfWApO1xuICB9XG4gIGNvbnN0IG1pbmltdW1SZXF1ZXN0cyA9IG9wdGlvbnMubWluaW11bVJlcXVlc3RzID8/IDEwO1xuICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKG1pbmltdW1SZXF1ZXN0cykgfHwgIU51bWJlci5pc0ludGVnZXIobWluaW11bVJlcXVlc3RzKSB8fCBtaW5pbXVtUmVxdWVzdHMgPCAxKSB7XG4gICAgZmFpbChgbWluaW11bVJlcXVlc3RzIG11c3QgYmUgYSB3aG9sZSBudW1iZXIgZnJvbSAxLCBnb3QgJHttaW5pbXVtUmVxdWVzdHN9YCk7XG4gIH1cbiAgY29uc3QgcGVyaW9kID0gb3B0aW9ucy5wZXJpb2QgPz8gRHVyYXRpb24ubWludXRlcygxKTtcbiAgY29uc3Qgc2Vjb25kcyA9IHBlcmlvZC50b1NlY29uZHMoKTtcbiAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChzZWNvbmRzKSB8fCBzZWNvbmRzIDwgNjAgfHwgc2Vjb25kcyAlIDYwICE9PSAwKSB7XG4gICAgZmFpbChgcGVyaW9kIG11c3QgYmUgd2hvbGUgbWludXRlcywgYXQgbGVhc3QgMSwgZ290ICR7VG9rZW4uaXNVbnJlc29sdmVkKHNlY29uZHMpID8gJ2EgdG9rZW4nIDogcGVyaW9kLnRvSHVtYW5TdHJpbmcoKX1gKTtcbiAgfVxuICBjb25zdCBldmFsdWF0aW9uUGVyaW9kcyA9IG9wdGlvbnMuZXZhbHVhdGlvblBlcmlvZHMgPz8gMjtcbiAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChldmFsdWF0aW9uUGVyaW9kcykgfHwgIU51bWJlci5pc0ludGVnZXIoZXZhbHVhdGlvblBlcmlvZHMpIHx8IGV2YWx1YXRpb25QZXJpb2RzIDwgMSkge1xuICAgIGZhaWwoYGV2YWx1YXRpb25QZXJpb2RzIG11c3QgYmUgYSB3aG9sZSBudW1iZXIgZnJvbSAxLCBnb3QgJHtldmFsdWF0aW9uUGVyaW9kc31gKTtcbiAgfVxuICByZXR1cm4geyBzZXJ2ZXJFcnJvclJhdGU6IG9wdGlvbnMuc2VydmVyRXJyb3JSYXRlLCBjbGllbnRFcnJvclJhdGU6IG9wdGlvbnMuY2xpZW50RXJyb3JSYXRlLCBtaW5pbXVtUmVxdWVzdHMsIHBlcmlvZCwgZXZhbHVhdGlvblBlcmlvZHMgfTtcbn1cbiJdfQ==
|