low-cost-ecs 0.0.6

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.
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.LowCostECS = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const path = require("path");
7
+ const lib = require("aws-cdk-lib");
8
+ const ec2 = require("aws-cdk-lib/aws-ec2");
9
+ const ecs = require("aws-cdk-lib/aws-ecs");
10
+ const aws_efs_1 = require("aws-cdk-lib/aws-efs");
11
+ const aws_events_1 = require("aws-cdk-lib/aws-events");
12
+ const aws_events_targets_1 = require("aws-cdk-lib/aws-events-targets");
13
+ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
14
+ const aws_logs_1 = require("aws-cdk-lib/aws-logs");
15
+ const route53 = require("aws-cdk-lib/aws-route53");
16
+ const aws_sns_1 = require("aws-cdk-lib/aws-sns");
17
+ const sfn = require("aws-cdk-lib/aws-stepfunctions");
18
+ const sfn_tasks = require("aws-cdk-lib/aws-stepfunctions-tasks");
19
+ ;
20
+ class LowCostECS extends lib.Stack {
21
+ constructor(scope, id, props) {
22
+ super(scope, id, props);
23
+ const vpc = props.vpc ??
24
+ new ec2.Vpc(this, 'Vpc', {
25
+ natGateways: 0,
26
+ subnetConfiguration: [
27
+ {
28
+ name: 'PublicSubnet',
29
+ subnetType: ec2.SubnetType.PUBLIC,
30
+ },
31
+ ],
32
+ });
33
+ const cluster = new ecs.Cluster(this, 'Cluster', {
34
+ vpc,
35
+ containerInsights: props.containerInsights,
36
+ });
37
+ const hostAutoScalingGroup = cluster.addCapacity('HostInstanceCapacity', {
38
+ machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.STANDARD, {
39
+ cachedInContext: true,
40
+ }),
41
+ instanceType: new ec2.InstanceType(props.hostInstanceType ?? 't2.micro'),
42
+ spotPrice: props.hostInstanceSpotPrice,
43
+ vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
44
+ associatePublicIpAddress: true,
45
+ minCapacity: 1,
46
+ maxCapacity: 1,
47
+ });
48
+ if (props.securityGroup) {
49
+ hostAutoScalingGroup.addSecurityGroup(props.securityGroup);
50
+ }
51
+ else {
52
+ hostAutoScalingGroup.connections.allowFromAnyIpv4(ec2.Port.tcp(80));
53
+ hostAutoScalingGroup.connections.allowFromAnyIpv4(ec2.Port.tcp(443));
54
+ hostAutoScalingGroup.connections.allowFrom(ec2.Peer.anyIpv6(), ec2.Port.tcp(80));
55
+ hostAutoScalingGroup.connections.allowFrom(ec2.Peer.anyIpv6(), ec2.Port.tcp(443));
56
+ }
57
+ /**
58
+ * Add managed policy to allow ssh through ssm manager
59
+ */
60
+ hostAutoScalingGroup.role.addManagedPolicy(aws_iam_1.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
61
+ /**
62
+ * Add policy to associate elastic ip on startup
63
+ */
64
+ hostAutoScalingGroup.role.addToPrincipalPolicy(new aws_iam_1.PolicyStatement({
65
+ effect: aws_iam_1.Effect.ALLOW,
66
+ actions: ['ec2:DescribeAddresses', 'ec2:AssociateAddress'],
67
+ resources: ['*'],
68
+ }));
69
+ const hostInstanceIp = new ec2.CfnEIP(this, 'HostInstanceIp');
70
+ const tagUniqueId = lib.Names.uniqueId(hostInstanceIp);
71
+ hostInstanceIp.tags.setTag('Name', tagUniqueId);
72
+ const awsCliTag = props.awsCliDockerTag ?? 'latest';
73
+ hostAutoScalingGroup.addUserData('INSTANCE_ID=$(curl --silent http://169.254.169.254/latest/meta-data/instance-id)', `ALLOCATION_ID=$(docker run --net=host amazon/aws-cli:${awsCliTag} ec2 describe-addresses --region ${hostAutoScalingGroup.env.region} --filter Name=tag:Name,Values=${tagUniqueId} --query 'Addresses[].AllocationId' --output text | head)`, `docker run --net=host amazon/aws-cli:${awsCliTag} ec2 associate-address --region ${hostAutoScalingGroup.env.region} --instance-id "$INSTANCE_ID" --allocation-id "$ALLOCATION_ID" --allow-reassociation`);
74
+ const certFileSystem = new aws_efs_1.FileSystem(this, 'FileSystem', {
75
+ vpc,
76
+ encrypted: true,
77
+ securityGroup: new ec2.SecurityGroup(this, 'FileSystemSecurityGroup', {
78
+ vpc,
79
+ allowAllOutbound: false,
80
+ }),
81
+ removalPolicy: props.removalPolicy ?? lib.RemovalPolicy.DESTROY,
82
+ });
83
+ certFileSystem.connections.allowDefaultPortTo(hostAutoScalingGroup);
84
+ certFileSystem.connections.allowDefaultPortFrom(hostAutoScalingGroup);
85
+ /**
86
+ * ARecord to Elastic ip
87
+ */
88
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
89
+ domainName: props.hostedZoneDomain,
90
+ });
91
+ const records = props.recordDomainNames ?? [hostedZone.zoneName];
92
+ records.forEach((record) => new route53.ARecord(this, `ARecord${record}`, {
93
+ zone: hostedZone,
94
+ recordName: record,
95
+ target: route53.RecordTarget.fromIpAddresses(hostInstanceIp.ref),
96
+ }));
97
+ /**
98
+ * Certbot Task Definition
99
+ * Mounts generated certificate to EFS
100
+ */
101
+ const logGroup = props.logGroup ??
102
+ new aws_logs_1.LogGroup(this, 'LogGroup', {
103
+ retention: aws_logs_1.RetentionDays.TWO_YEARS,
104
+ removalPolicy: props.removalPolicy ?? lib.RemovalPolicy.DESTROY,
105
+ });
106
+ const certbotTaskDefinition = new ecs.Ec2TaskDefinition(this, 'CertbotTaskDefinition');
107
+ certbotTaskDefinition.addToTaskRolePolicy(new aws_iam_1.PolicyStatement({
108
+ effect: aws_iam_1.Effect.ALLOW,
109
+ actions: ['route53:ListHostedZones', 'route53:GetChange'],
110
+ resources: ['*'],
111
+ }));
112
+ certbotTaskDefinition.addToTaskRolePolicy(new aws_iam_1.PolicyStatement({
113
+ effect: aws_iam_1.Effect.ALLOW,
114
+ actions: ['route53:ChangeResourceRecordSets'],
115
+ resources: [hostedZone.hostedZoneArn],
116
+ }));
117
+ const certbotTag = props.certbotDockerTag ?? 'v1.29.0';
118
+ const certbotContainer = certbotTaskDefinition.addContainer('CertbotContainer', {
119
+ image: ecs.ContainerImage.fromRegistry(`certbot/dns-route53:${certbotTag}`),
120
+ containerName: 'certbot',
121
+ memoryReservationMiB: 64,
122
+ command: [
123
+ 'certonly',
124
+ '--verbose',
125
+ '--preferred-challenges=dns-01',
126
+ '--dns-route53',
127
+ '--dns-route53-propagation-seconds=300',
128
+ '--non-interactive',
129
+ '--agree-tos',
130
+ '--expand',
131
+ '-m',
132
+ props.email,
133
+ '--cert-name',
134
+ records[0],
135
+ ...records.flatMap((domain) => ['-d', domain]),
136
+ ],
137
+ logging: ecs.LogDriver.awsLogs({
138
+ logGroup,
139
+ streamPrefix: certbotTag,
140
+ }),
141
+ });
142
+ certFileSystem.grant(certbotTaskDefinition.taskRole, 'elasticfilesystem:ClientWrite');
143
+ certbotTaskDefinition.addVolume({
144
+ name: 'certVolume',
145
+ efsVolumeConfiguration: {
146
+ fileSystemId: certFileSystem.fileSystemId,
147
+ },
148
+ });
149
+ certbotContainer.addMountPoints({
150
+ sourceVolume: 'certVolume',
151
+ containerPath: '/etc/letsencrypt',
152
+ readOnly: false,
153
+ });
154
+ /**
155
+ * Schedule Certbot certificate create/renew on Step Functions
156
+ * Sends email notification on certbot failure
157
+ */
158
+ const topic = new aws_sns_1.Topic(this, 'Topic');
159
+ new aws_sns_1.Subscription(this, 'EmailSubscription', {
160
+ topic: topic,
161
+ protocol: aws_sns_1.SubscriptionProtocol.EMAIL,
162
+ endpoint: props.email,
163
+ });
164
+ const certbotRunTask = new sfn_tasks.EcsRunTask(this, 'CreateCertificate', {
165
+ cluster: cluster,
166
+ taskDefinition: certbotTaskDefinition,
167
+ launchTarget: new sfn_tasks.EcsEc2LaunchTarget(),
168
+ integrationPattern: sfn.IntegrationPattern.RUN_JOB,
169
+ });
170
+ certbotRunTask.addCatch(new sfn_tasks.SnsPublish(this, 'SendEmailOnFailure', {
171
+ topic: topic,
172
+ message: sfn.TaskInput.fromJsonPathAt('$'),
173
+ }).next(new sfn.Fail(this, 'Fail')));
174
+ certbotRunTask.addRetry({
175
+ interval: lib.Duration.seconds(20),
176
+ });
177
+ const certbotStateMachine = new sfn.StateMachine(this, 'StateMachine', {
178
+ definition: certbotRunTask,
179
+ });
180
+ new aws_events_1.Rule(this, 'CertbotScheduleRule', {
181
+ schedule: aws_events_1.Schedule.rate(lib.Duration.days(props.certbotScheduleInterval ?? 60)),
182
+ targets: [new aws_events_targets_1.SfnStateMachine(certbotStateMachine)],
183
+ });
184
+ /**
185
+ * Server ECS task
186
+ */
187
+ const serverTaskDefinition = props.serverTaskDefinition ?? this.sampleSeverTask(records, logGroup);
188
+ certFileSystem.grant(serverTaskDefinition.taskRole, 'elasticfilesystem:ClientMount');
189
+ serverTaskDefinition.addVolume({
190
+ name: 'certVolume',
191
+ efsVolumeConfiguration: {
192
+ fileSystemId: certFileSystem.fileSystemId,
193
+ },
194
+ });
195
+ serverTaskDefinition.defaultContainer?.addMountPoints({
196
+ sourceVolume: 'certVolume',
197
+ containerPath: '/etc/letsencrypt',
198
+ readOnly: true,
199
+ });
200
+ /**
201
+ * AWS cli container to execute certbot sfn before the default container startup.
202
+ */
203
+ serverTaskDefinition.defaultContainer?.addContainerDependencies({
204
+ container: serverTaskDefinition.addContainer('AWSCliContainer', {
205
+ image: ecs.ContainerImage.fromRegistry(`amazon/aws-cli:${awsCliTag}`),
206
+ containerName: 'aws-cli',
207
+ memoryReservationMiB: 64,
208
+ entryPoint: ['/bin/bash', '-c'],
209
+ command: [
210
+ `set -eux
211
+ aws configure set region ${certbotStateMachine.env.region} && \\
212
+ aws configure set output text && \\
213
+ EXECUTION_ARN=$(aws stepfunctions start-execution --state-machine-arn ${certbotStateMachine.stateMachineArn} --query executionArn) && \\
214
+ until [ $(aws stepfunctions describe-execution --execution-arn "$EXECUTION_ARN" --query status) != RUNNING ];
215
+ do
216
+ echo "Waiting for $EXECUTION_ARN"
217
+ sleep 10
218
+ done`,
219
+ ],
220
+ essential: false,
221
+ logging: ecs.LogDriver.awsLogs({
222
+ logGroup: logGroup,
223
+ streamPrefix: awsCliTag,
224
+ }),
225
+ }),
226
+ condition: ecs.ContainerDependencyCondition.COMPLETE,
227
+ });
228
+ certbotStateMachine.grantExecution(serverTaskDefinition.taskRole, 'states:DescribeExecution');
229
+ certbotStateMachine.grantStartExecution(serverTaskDefinition.taskRole);
230
+ new ecs.Ec2Service(this, 'Service', {
231
+ cluster: cluster,
232
+ taskDefinition: serverTaskDefinition,
233
+ desiredCount: 1,
234
+ minHealthyPercent: 0,
235
+ maxHealthyPercent: 100,
236
+ circuitBreaker: {
237
+ rollback: true,
238
+ },
239
+ enableExecuteCommand: true,
240
+ });
241
+ }
242
+ sampleSeverTask(records, logGroup) {
243
+ const nginxTaskDefinition = new ecs.Ec2TaskDefinition(this, 'NginxTaskDefinition');
244
+ const nginxContainer = nginxTaskDefinition.addContainer('NginxContainer', {
245
+ image: ecs.ContainerImage.fromAsset(path.join(__dirname, '../containers/nginx-proxy')),
246
+ containerName: 'nginx',
247
+ memoryReservationMiB: 64,
248
+ essential: true,
249
+ environment: {
250
+ SERVER_NAME: records.join(' '),
251
+ CERT_NAME: records[0],
252
+ },
253
+ logging: ecs.LogDrivers.awsLogs({
254
+ logGroup: logGroup,
255
+ streamPrefix: 'nginx-proxy',
256
+ }),
257
+ });
258
+ nginxContainer.addPortMappings({
259
+ hostPort: 80,
260
+ containerPort: 80,
261
+ protocol: ecs.Protocol.TCP,
262
+ }, {
263
+ hostPort: 443,
264
+ containerPort: 443,
265
+ protocol: ecs.Protocol.TCP,
266
+ });
267
+ return nginxTaskDefinition;
268
+ }
269
+ }
270
+ exports.LowCostECS = LowCostECS;
271
+ _a = JSII_RTTI_SYMBOL_1;
272
+ LowCostECS[_a] = { fqn: "low-cost-ecs.LowCostECS", version: "0.0.6" };
273
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG93LWNvc3QtZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2xvdy1jb3N0LWVjcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZCQUE2QjtBQUM3QixtQ0FBbUM7QUFDbkMsMkNBQTJDO0FBQzNDLDJDQUEyQztBQUMzQyxpREFBaUQ7QUFDakQsdURBQXdEO0FBQ3hELHVFQUFpRTtBQUNqRSxpREFBNkU7QUFDN0UsbURBQTBFO0FBQzFFLG1EQUFtRDtBQUNuRCxpREFBZ0Y7QUFDaEYscURBQXFEO0FBQ3JELGlFQUFpRTtBQTRHaEUsQ0FBQztBQUVGLE1BQWEsVUFBVyxTQUFRLEdBQUcsQ0FBQyxLQUFLO0lBQ3ZDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBc0I7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFeEIsTUFBTSxHQUFHLEdBQ1AsS0FBSyxDQUFDLEdBQUc7WUFDVCxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRTtnQkFDdkIsV0FBVyxFQUFFLENBQUM7Z0JBQ2QsbUJBQW1CLEVBQUU7b0JBQ25CO3dCQUNFLElBQUksRUFBRSxjQUFjO3dCQUNwQixVQUFVLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxNQUFNO3FCQUNsQztpQkFDRjthQUNGLENBQUMsQ0FBQztRQUVMLE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFO1lBQy9DLEdBQUc7WUFDSCxpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCO1NBQzNDLENBQUMsQ0FBQztRQUVILE1BQU0sb0JBQW9CLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxzQkFBc0IsRUFBRTtZQUN2RSxZQUFZLEVBQUUsR0FBRyxDQUFDLGlCQUFpQixDQUFDLFlBQVksQ0FDOUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxRQUFR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Q0FDckIsT0FBaUIsRUFDakIsUUFBbUI7UUFFbkIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxpQkFBaUIsQ0FDbkQsSUFBSSxFQUNKLHFCQUFxQixDQUN0QixDQUFDO1FBQ0YsTUFBTSxjQUFjLEdBQUcsbUJBQW1CLENBQUMsWUFBWSxDQUFDLGdCQUFnQixFQUFFO1lBQ3hFLEtBQUssRUFBRSxHQUFHLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FDakMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsMkJBQTJCLENBQUMsQ0FDbEQ7WUFDRCxhQUFhLEVBQUUsT0FBTztZQUN0QixvQkFBb0IsRUFBRSxFQUFFO1lBQ3hCLFNBQVMsRUFBRSxJQUFJO1lBQ2YsV0FBVyxFQUFFO2dCQUNYLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztnQkFDOUIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7YUFDdEI7WUFDRCxPQUFPLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7Z0JBQzlCLFFBQVEsRUFBRSxRQUFRO2dCQUNsQixZQUFZLEVBQUUsYUFBYTthQUM1QixDQUFDO1NBQ0gsQ0FBQyxDQUFDO1FBRUgsY0FBYyxDQUFDLGVBQWUsQ0FDNUI7WUFDRSxRQUFRLEVBQUUsRUFBRTtZQUNaLGFBQWEsRUFBRSxFQUFFO1lBQ2pCLFFBQVEsRUFBRSxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUc7U0FDM0IsRUFDRDtZQUNFLFFBQVEsRUFBRSxHQUFHO1lBQ2IsYUFBYSxFQUFFLEdBQUc7WUFDbEIsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsR0FBRztTQUMzQixDQUNGLENBQUM7UUFFRixPQUFPLG1CQUFtQixDQUFDO0lBQzdCLENBQUM7O0FBeFVILGdDQXlVQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBsaWIgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0ICogYXMgZWNzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1lY3MnO1xuaW1wb3J0IHsgRmlsZVN5c3RlbSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lZnMnO1xuaW1wb3J0IHsgUnVsZSwgU2NoZWR1bGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZXZlbnRzJztcbmltcG9ydCB7IFNmblN0YXRlTWFjaGluZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1ldmVudHMtdGFyZ2V0cyc7XG5pbXBvcnQgeyBFZmZlY3QsIE1hbmFnZWRQb2xpY3ksIFBvbGljeVN0YXRlbWVudCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgSUxvZ0dyb3VwLCBMb2dHcm91cCwgUmV0ZW50aW9uRGF5cyB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCAqIGFzIHJvdXRlNTMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXJvdXRlNTMnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uLCBTdWJzY3JpcHRpb25Qcm90b2NvbCwgVG9waWMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc25zJztcbmltcG9ydCAqIGFzIHNmbiBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc3RlcGZ1bmN0aW9ucyc7XG5pbXBvcnQgKiBhcyBzZm5fdGFza3MgZnJvbSAnYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnMtdGFza3MnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG93Q29zdEVDU1Byb3BzIGV4dGVuZHMgbGliLlN0YWNrUHJvcHMge1xuICAvKipcbiAgICogRG9tYWluIG5hbWUgb2YgdGhlIGhvc3RlZCB6b25lLlxuICAgKi9cbiAgcmVhZG9ubHkgaG9zdGVkWm9uZURvbWFpbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBFbWFpbCBmb3IgZXhwaXJhdGlvbiBlbWFpbHMgdG8gcmVnaXN0ZXIgdG8geW91ciBsZXQncyBlbmNyeXB0IGFjY291bnQuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vbGV0c2VuY3J5cHQub3JnL2RvY3MvZXhwaXJhdGlvbi1lbWFpbHMvXG4gICAqXG4gICAqIEFsc28gcmVnaXN0ZXJlZCBhcyBhIHN1YnNjcmliZXIgb2YgdGhlIHNucyB0b3BpYywgbm90aWZpZWQgb24gY2VydGJvdCB0YXNrIGZhaWx1cmUuXG4gICAqIFN1YnNjcmlwdGlvbiBjb25maXJtYXRpb24gZW1haWwgd291bGQgYmUgc2VudCBvbiBzdGFjayBjcmVhdGlvbi5cbiAgICpcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL3Nucy9sYXRlc3QvZGcvc25zLWVtYWlsLW5vdGlmaWNhdGlvbnMuaHRtbFxuICAgKi9cbiAgcmVhZG9ubHkgZW1haWw6IHN0cmluZztcblxuICAvKipcbiAgICogRG9tYWluIG5hbWVzIGZvciBBIHJlY29yZHMgdG8gZWxhc3RpYyBpcCBvZiBFQ1MgaG9zdCBpbnN0YW5jZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBbIHByb3BzLmhvc3RlZFpvbmUuem9uZU5hbWUgXVxuICAgKi9cbiAgcmVhZG9ubHkgcmVjb3JkRG9tYWluTmFtZXM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVnBjIG9mIHRoZSBFQ1MgaG9zdCBpbnN0YW5jZSBhbmQgY2x1c3Rlci5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBDcmVhdGVzIHZwYyB3aXRoIG9ubHkgcHVibGljIHN1Ym5ldHMgYW5kIG5vIE5BVCBnYXRld2F5cy5cbiAgICovXG4gIHJlYWRvbmx5IHZwYz86IGVjMi5JVnBjO1xuXG4gIC8qKlxuICAgKiBTZWN1cml0eSBncm91cCBvZiB0aGUgRUNTIGhvc3QgaW5zdGFuY2VcbiAgICpcbiAgICogQGRlZmF1bHQgLSBDcmVhdGVzIHNlY3VyaXR5IGdyb3VwIHdpdGggYWxsb3dBbGxPdXRib3VuZCBhbmQgaW5ncmVzcyBydWxlIChpcHY0LCBpcHY2KSA9PiAodGNwIDgwLCA0NDMpLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjdXJpdHlHcm91cD86IGVjMi5TZWN1cml0eUdyb3VwO1xuXG4gIC8qKlxuICAgKiBJbnN0YW5jZSB0eXBlIG9mIHRoZSBFQ1MgaG9zdCBpbnN0YW5jZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSB0Mi5taWNyb1xuICAgKi9cbiAgcmVhZG9ubHkgaG9zdEluc3RhbmNlVHlwZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1heGltdW0gaG91cmx5IHByaWNlIChpbiBVU0QpIHRvIGJlIHBhaWQgZm9yIGFueSBTcG90IEluc3RhbmNlIGxhdW5jaGVkIHRvIGZ1bGZpbGwgdGhlIHJlcXVlc3QuXG4gICAqIEhvc3QgaW5zdGFuY2UgYXNnIHdvdWxkIHVzZSBzcG90IGluc3RhbmNlcyBpZiBob3N0SW5zdGFuY2VTcG90UHJpY2UgaXMgc2V0LlxuICAgKlxuICAgKiBAbGluayBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY2RrL2FwaS92Mi9kb2NzL2F3cy1jZGstbGliLmF3c19lY3MuQWRkQ2FwYWNpdHlPcHRpb25zLmh0bWwjc3BvdHByaWNlXG4gICAqIEBkZWZhdWx0IC0gdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBob3N0SW5zdGFuY2VTcG90UHJpY2U/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExvZyBncm91cCBvZiB0aGUgY2VydGJvdCB0YXNrIGFuZCB0aGUgYXdzLWNsaSB0YXNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIENyZWF0ZXMgZGVmYXVsdCBjZGsgbG9nIGdyb3VwXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cD86IElMb2dHcm91cDtcblxuICAvKipcbiAgICogRG9ja2VyIGltYWdlIHRhZyBvZiBjZXJ0Ym90L2Rucy1yb3V0ZTUzIHRvIGNyZWF0ZSBjZXJ0aWZpY2F0ZXMuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vaHViLmRvY2tlci5jb20vci9jZXJ0Ym90L2Rucy1yb3V0ZTUzL3RhZ3NcbiAgICogQGRlZmF1bHQgLSB2MS4yOS4wXG4gICAqL1xuICByZWFkb25seSBjZXJ0Ym90RG9ja2VyVGFnPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDZXJ0Ym90IHRhc2sgc2NoZWR1bGUgaW50ZXJ2YWwgaW4gZGF5cyB0byByZW5ldyB0aGUgY2VydGlmaWNhdGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gNjBcbiAgICovXG4gIHJlYWRvbmx5IGNlcnRib3RTY2hlZHVsZUludGVydmFsPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBEb2NrZXIgaW1hZ2UgdGFnIG9mIGFtYXpvbi9hd3MtY2xpLlxuICAgKiBUaGlzIGltYWdlIGlzIHVzZWQgdG8gYXNzb2NpYXRlIGVsYXN0aWMgaXAgb24gaG9zdCBpbnN0YW5jZSBzdGFydHVwLCBhbmQgcnVuIGNlcnRib3QgY2ZuIG9uIGVjcyBjb250YWluZXIgc3RhcnR1cC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBsYXRlc3RcbiAgICovXG4gIHJlYWRvbmx5IGF3c0NsaURvY2tlclRhZz86IHN0cmluZztcblxuICAvKipcbiAgICogRW5hYmxlIGNvbnRhaW5lciBpbnNpZ2h0cyBvciBub3RcbiAgICpcbiAgICogQGRlZmF1bHQgLSB1bmRlZmluZWQgKGNvbnRhaW5lciBpbnNpZ2h0cyBkaXNhYmxlZClcbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lckluc2lnaHRzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmVtb3ZhbCBwb2xpY3kgZm9yIHRoZSBmaWxlIHN5c3RlbSBhbmQgbG9nIGdyb3VwIChpZiB1c2luZyBkZWZhdWx0KS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBSZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgICovXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBsaWIuUmVtb3ZhbFBvbGljeTtcblxuICAvKipcbiAgICogVGFzayBkZWZpbml0aW9uIGZvciB0aGUgc2VydmVyIGVjcyB0YXNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5naW54IHNlcnZlciB0YXNrIGRlZmluaXRpb24gZGVmaW5lZCBpbiBzYW1wbGVTZXJ2ZXJUYXNrKClcbiAgICovXG4gIHJlYWRvbmx5IHNlcnZlclRhc2tEZWZpbml0aW9uPzogZWNzLkVjMlRhc2tEZWZpbml0aW9uO1xufTtcblxuZXhwb3J0IGNsYXNzIExvd0Nvc3RFQ1MgZXh0ZW5kcyBsaWIuU3RhY2sge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTG93Q29zdEVDU1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCBwcm9wcyk7XG5cbiAgICBjb25zdCB2cGMgPVxuICAgICAgcHJvcHMudnBjID8/XG4gICAgICBuZXcgZWMyLlZwYyh0aGlzLCAnVnBjJywge1xuICAgICAgICBuYXRHYXRld2F5czogMCxcbiAgICAgICAgc3VibmV0Q29uZmlndXJhdGlvbjogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIG5hbWU6ICdQdWJsaWNTdWJuZXQnLFxuICAgICAgICAgICAgc3VibmV0VHlwZTogZWMyLlN1Ym5ldFR5cGUuUFVCTElDLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgIGNvbnN0IGNsdXN0ZXIgPSBuZXcgZWNzLkNsdXN0ZXIodGhpcywgJ0NsdXN0ZXInLCB7XG4gICAgICB2cGMsXG4gICAgICBjb250YWluZXJJbnNpZ2h0czogcHJvcHMuY29udGFpbmVySW5zaWdodHMsXG4gICAgfSk7XG5cbiAgICBjb25zdCBob3N0QXV0b1NjYWxpbmdHcm91cCA9IGNsdXN0ZXIuYWRkQ2FwYWNpdHkoJ0hvc3RJbnN0YW5jZUNhcGFjaXR5Jywge1xuICAgICAgbWFjaGluZUltYWdlOiBlY3MuRWNzT3B0aW1pemVkSW1hZ2UuYW1hem9uTGludXgyKFxuICAgICAgICBlY3MuQW1pSGFyZHdhcmVUeXBlLlNUQU5EQVJELFxuICAgICAgICB7XG4gICAgICAgICAgY2FjaGVkSW5Db250ZXh0OiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgKSxcbiAgICAgIGluc3RhbmNlVHlwZTogbmV3IGVjMi5JbnN0YW5jZVR5cGUocHJvcHMuaG9zdEluc3RhbmNlVHlwZSA/PyAndDIubWljcm8nKSxcbiAgICAgIHNwb3RQcmljZTogcHJvcHMuaG9zdEluc3RhbmNlU3BvdFByaWNlLFxuICAgICAgdnBjU3VibmV0czogeyBzdWJuZXRUeXBlOiBlYzIuU3VibmV0VHlwZS5QVUJMSUMgfSxcbiAgICAgIGFzc29jaWF0ZVB1YmxpY0lwQWRkcmVzczogdHJ1ZSxcbiAgICAgIG1pbkNhcGFjaXR5OiAxLFxuICAgICAgbWF4Q2FwYWNpdHk6IDEsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMuc2VjdXJpdHlHcm91cCkge1xuICAgICAgaG9zdEF1dG9TY2FsaW5nR3JvdXAuYWRkU2VjdXJpdHlHcm91cChwcm9wcy5zZWN1cml0eUdyb3VwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaG9zdEF1dG9TY2FsaW5nR3JvdXAuY29ubmVjdGlvbnMuYWxsb3dGcm9tQW55SXB2NChlYzIuUG9ydC50Y3AoODApKTtcbiAgICAgIGhvc3RBdXRvU2NhbGluZ0dyb3VwLmNvbm5lY3Rpb25zLmFsbG93RnJvbUFueUlwdjQoZWMyLlBvcnQudGNwKDQ0MykpO1xuICAgICAgaG9zdEF1dG9TY2FsaW5nR3JvdXAuY29ubmVjdGlvbnMuYWxsb3dGcm9tKFxuICAgICAgICBlYzIuUGVlci5hbnlJcHY2KCksXG4gICAgICAgIGVjMi5Qb3J0LnRjcCg4MCksXG4gICAgICApO1xuICAgICAgaG9zdEF1dG9TY2FsaW5nR3JvdXAuY29ubmVjdGlvbnMuYWxsb3dGcm9tKFxuICAgICAgICBlYzIuUGVlci5hbnlJcHY2KCksXG4gICAgICAgIGVjMi5Qb3J0LnRjcCg0NDMpLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgbWFuYWdlZCBwb2xpY3kgdG8gYWxsb3cgc3NoIHRocm91Z2ggc3NtIG1hbmFnZXJcbiAgICAgKi9cbiAgICBob3N0QXV0b1NjYWxpbmdHcm91cC5yb2xlLmFkZE1hbmFnZWRQb2xpY3koXG4gICAgICBNYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnQW1hem9uU1NNTWFuYWdlZEluc3RhbmNlQ29yZScpLFxuICAgICk7XG4gICAgLyoqXG4gICAgICogQWRkIHBvbGljeSB0byBhc3NvY2lhdGUgZWxhc3RpYyBpcCBvbiBzdGFydHVwXG4gICAgICovXG4gICAgaG9zdEF1dG9TY2FsaW5nR3JvdXAucm9sZS5hZGRUb1ByaW5jaXBhbFBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydlYzI6RGVzY3JpYmVBZGRyZXNzZXMnLCAnZWMyOkFzc29jaWF0ZUFkZHJlc3MnXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCBob3N0SW5zdGFuY2VJcCA9IG5ldyBlYzIuQ2ZuRUlQKHRoaXMsICdIb3N0SW5zdGFuY2VJcCcpO1xuICAgIGNvbnN0IHRhZ1VuaXF1ZUlkID0gbGliLk5hbWVzLnVuaXF1ZUlkKGhvc3RJbnN0YW5jZUlwKTtcbiAgICBob3N0SW5zdGFuY2VJcC50YWdzLnNldFRhZygnTmFtZScsIHRhZ1VuaXF1ZUlkKTtcblxuICAgIGNvbnN0IGF3c0NsaVRhZyA9IHByb3BzLmF3c0NsaURvY2tlclRhZyA/PyAnbGF0ZXN0JztcbiAgICBob3N0QXV0b1NjYWxpbmdHcm91cC5hZGRVc2VyRGF0YShcbiAgICAgICdJTlNUQU5DRV9JRD0kKGN1cmwgLS1zaWxlbnQgaHR0cDovLzE2OS4yNTQuMTY5LjI1NC9sYXRlc3QvbWV0YS1kYXRhL2luc3RhbmNlLWlkKScsXG4gICAgICBgQUxMT0NBVElPTl9JRD0kKGRvY2tlciBydW4gLS1uZXQ9aG9zdCBhbWF6b24vYXdzLWNsaToke2F3c0NsaVRhZ30gZWMyIGRlc2NyaWJlLWFkZHJlc3NlcyAtLXJlZ2lvbiAke2hvc3RBdXRvU2NhbGluZ0dyb3VwLmVudi5yZWdpb259IC0tZmlsdGVyIE5hbWU9dGFnOk5hbWUsVmFsdWVzPSR7dGFnVW5pcXVlSWR9IC0tcXVlcnkgJ0FkZHJlc3Nlc1tdLkFsbG9jYXRpb25JZCcgLS1vdXRwdXQgdGV4dCB8IGhlYWQpYCxcbiAgICAgIGBkb2NrZXIgcnVuIC0tbmV0PWhvc3QgYW1hem9uL2F3cy1jbGk6JHthd3NDbGlUYWd9IGVjMiBhc3NvY2lhdGUtYWRkcmVzcyAtLXJlZ2lvbiAke2hvc3RBdXRvU2NhbGluZ0dyb3VwLmVudi5yZWdpb259IC0taW5zdGFuY2UtaWQgXCIkSU5TVEFOQ0VfSURcIiAtLWFsbG9jYXRpb24taWQgXCIkQUxMT0NBVElPTl9JRFwiIC0tYWxsb3ctcmVhc3NvY2lhdGlvbmAsXG4gICAgKTtcblxuICAgIGNvbnN0IGNlcnRGaWxlU3lzdGVtID0gbmV3IEZpbGVTeXN0ZW0odGhpcywgJ0ZpbGVTeXN0ZW0nLCB7XG4gICAgICB2cGMsXG4gICAgICBlbmNyeXB0ZWQ6IHRydWUsXG4gICAgICBzZWN1cml0eUdyb3VwOiBuZXcgZWMyLlNlY3VyaXR5R3JvdXAodGhpcywgJ0ZpbGVTeXN0ZW1TZWN1cml0eUdyb3VwJywge1xuICAgICAgICB2cGMsXG4gICAgICAgIGFsbG93QWxsT3V0Ym91bmQ6IGZhbHNlLFxuICAgICAgfSksXG4gICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5yZW1vdmFsUG9saWN5ID8/IGxpYi5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSk7XG4gICAgY2VydEZpbGVTeXN0ZW0uY29ubmVjdGlvbnMuYWxsb3dEZWZhdWx0UG9ydFRvKGhvc3RBdXRvU2NhbGluZ0dyb3VwKTtcbiAgICBjZXJ0RmlsZVN5c3RlbS5jb25uZWN0aW9ucy5hbGxvd0RlZmF1bHRQb3J0RnJvbShob3N0QXV0b1NjYWxpbmdHcm91cCk7XG5cbiAgICAvKipcbiAgICAgKiBBUmVjb3JkIHRvIEVsYXN0aWMgaXBcbiAgICAgKi9cbiAgICBjb25zdCBob3N0ZWRab25lID0gcm91dGU1My5Ib3N0ZWRab25lLmZyb21Mb29rdXAodGhpcywgJ0hvc3RlZFpvbmUnLCB7XG4gICAgICBkb21haW5OYW1lOiBwcm9wcy5ob3N0ZWRab25lRG9tYWluLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlY29yZHMgPSBwcm9wcy5yZWNvcmREb21haW5OYW1lcyA/PyBbaG9zdGVkWm9uZS56b25lTmFtZV07XG4gICAgcmVjb3Jkcy5mb3JFYWNoKFxuICAgICAgKHJlY29yZCkgPT5cbiAgICAgICAgbmV3IHJvdXRlNTMuQVJlY29yZCh0aGlzLCBgQVJlY29yZCR7cmVjb3JkfWAsIHtcbiAgICAgICAgICB6b25lOiBob3N0ZWRab25lLFxuICAgICAgICAgIHJlY29yZE5hbWU6IHJlY29yZCxcbiAgICAgICAgICB0YXJnZXQ6IHJvdXRlNTMuUmVjb3JkVGFyZ2V0LmZyb21JcEFkZHJlc3Nlcyhob3N0SW5zdGFuY2VJcC5yZWYpLFxuICAgICAgICB9KSxcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICogQ2VydGJvdCBUYXNrIERlZmluaXRpb25cbiAgICAgKiBNb3VudHMgZ2VuZXJhdGVkIGNlcnRpZmljYXRlIHRvIEVGU1xuICAgICAqL1xuICAgIGNvbnN0IGxvZ0dyb3VwID1cbiAgICAgIHByb3BzLmxvZ0dyb3VwID8/XG4gICAgICBuZXcgTG9nR3JvdXAodGhpcywgJ0xvZ0dyb3VwJywge1xuICAgICAgICByZXRlbnRpb246IFJldGVudGlvbkRheXMuVFdPX1lFQVJTLFxuICAgICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5yZW1vdmFsUG9saWN5ID8/IGxpYi5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICB9KTtcblxuICAgIGNvbnN0IGNlcnRib3RUYXNrRGVmaW5pdGlvbiA9IG5ldyBlY3MuRWMyVGFza0RlZmluaXRpb24oXG4gICAgICB0aGlzLFxuICAgICAgJ0NlcnRib3RUYXNrRGVmaW5pdGlvbicsXG4gICAgKTtcbiAgICBjZXJ0Ym90VGFza0RlZmluaXRpb24uYWRkVG9UYXNrUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydyb3V0ZTUzOkxpc3RIb3N0ZWRab25lcycsICdyb3V0ZTUzOkdldENoYW5nZSddLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSksXG4gICAgKTtcbiAgICBjZXJ0Ym90VGFza0RlZmluaXRpb24uYWRkVG9UYXNrUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydyb3V0ZTUzOkNoYW5nZVJlc291cmNlUmVjb3JkU2V0cyddLFxuICAgICAgICByZXNvdXJjZXM6IFtob3N0ZWRab25lLmhvc3RlZFpvbmVBcm5dLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IGNlcnRib3RUYWcgPSBwcm9wcy5jZXJ0Ym90RG9ja2VyVGFnID8/ICd2MS4yOS4wJztcbiAgICBjb25zdCBjZXJ0Ym90Q29udGFpbmVyID0gY2VydGJvdFRhc2tEZWZpbml0aW9uLmFkZENvbnRhaW5lcihcbiAgICAgICdDZXJ0Ym90Q29udGFpbmVyJyxcbiAgICAgIHtcbiAgICAgICAgaW1hZ2U6IGVjcy5Db250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoXG4gICAgICAgICAgYGNlcnRib3QvZG5zLXJvdXRlNTM6JHtjZXJ0Ym90VGFnfWAsXG4gICAgICAgICksXG4gICAgICAgIGNvbnRhaW5lck5hbWU6ICdjZXJ0Ym90JyxcbiAgICAgICAgbWVtb3J5UmVzZXJ2YXRpb25NaUI6IDY0LFxuICAgICAgICBjb21tYW5kOiBbXG4gICAgICAgICAgJ2NlcnRvbmx5JyxcbiAgICAgICAgICAnLS12ZXJib3NlJyxcbiAgICAgICAgICAnLS1wcmVmZXJyZWQtY2hhbGxlbmdlcz1kbnMtMDEnLFxuICAgICAgICAgICctLWRucy1yb3V0ZTUzJyxcbiAgICAgICAgICAnLS1kbnMtcm91dGU1My1wcm9wYWdhdGlvbi1zZWNvbmRzPTMwMCcsXG4gICAgICAgICAgJy0tbm9uLWludGVyYWN0aXZlJyxcbiAgICAgICAgICAnLS1hZ3JlZS10b3MnLFxuICAgICAgICAgICctLWV4cGFuZCcsXG4gICAgICAgICAgJy1tJyxcbiAgICAgICAgICBwcm9wcy5lbWFpbCxcbiAgICAgICAgICAnLS1jZXJ0LW5hbWUnLFxuICAgICAgICAgIHJlY29yZHNbMF0sXG4gICAgICAgICAgLi4ucmVjb3Jkcy5mbGF0TWFwKChkb21haW4pID0+IFsnLWQnLCBkb21haW5dKSxcbiAgICAgICAgXSxcbiAgICAgICAgbG9nZ2luZzogZWNzLkxvZ0RyaXZlci5hd3NMb2dzKHtcbiAgICAgICAgICBsb2dHcm91cCxcbiAgICAgICAgICBzdHJlYW1QcmVmaXg6IGNlcnRib3RUYWcsXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgY2VydEZpbGVTeXN0ZW0uZ3JhbnQoXG4gICAgICBjZXJ0Ym90VGFza0RlZmluaXRpb24udGFza1JvbGUsXG4gICAgICAnZWxhc3RpY2ZpbGVzeXN0ZW06Q2xpZW50V3JpdGUnLFxuICAgICk7XG4gICAgY2VydGJvdFRhc2tEZWZpbml0aW9uLmFkZFZvbHVtZSh7XG4gICAgICBuYW1lOiAnY2VydFZvbHVtZScsXG4gICAgICBlZnNWb2x1bWVDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGZpbGVTeXN0ZW1JZDogY2VydEZpbGVTeXN0ZW0uZmlsZVN5c3RlbUlkLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBjZXJ0Ym90Q29udGFpbmVyLmFkZE1vdW50UG9pbnRzKHtcbiAgICAgIHNvdXJjZVZvbHVtZTogJ2NlcnRWb2x1bWUnLFxuICAgICAgY29udGFpbmVyUGF0aDogJy9ldGMvbGV0c2VuY3J5cHQnLFxuICAgICAgcmVhZE9ubHk6IGZhbHNlLFxuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogU2NoZWR1bGUgQ2VydGJvdCBjZXJ0aWZpY2F0ZSBjcmVhdGUvcmVuZXcgb24gU3RlcCBGdW5jdGlvbnNcbiAgICAgKiBTZW5kcyBlbWFpbCBub3RpZmljYXRpb24gb24gY2VydGJvdCBmYWlsdXJlXG4gICAgICovXG4gICAgY29uc3QgdG9waWMgPSBuZXcgVG9waWModGhpcywgJ1RvcGljJyk7XG4gICAgbmV3IFN1YnNjcmlwdGlvbih0aGlzLCAnRW1haWxTdWJzY3JpcHRpb24nLCB7XG4gICAgICB0b3BpYzogdG9waWMsXG4gICAgICBwcm90b2NvbDogU3Vic2NyaXB0aW9uUHJvdG9jb2wuRU1BSUwsXG4gICAgICBlbmRwb2ludDogcHJvcHMuZW1haWwsXG4gICAgfSk7XG5cbiAgICBjb25zdCBjZXJ0Ym90UnVuVGFzayA9IG5ldyBzZm5fdGFza3MuRWNzUnVuVGFzayh0aGlzLCAnQ3JlYXRlQ2VydGlmaWNhdGUnLCB7XG4gICAgICBjbHVzdGVyOiBjbHVzdGVyLFxuICAgICAgdGFza0RlZmluaXRpb246IGNlcnRib3RUYXNrRGVmaW5pdGlvbixcbiAgICAgIGxhdW5jaFRhcmdldDogbmV3IHNmbl90YXNrcy5FY3NFYzJMYXVuY2hUYXJnZXQoKSxcbiAgICAgIGludGVncmF0aW9uUGF0dGVybjogc2ZuLkludGVncmF0aW9uUGF0dGVybi5SVU5fSk9CLFxuICAgIH0pO1xuICAgIGNlcnRib3RSdW5UYXNrLmFkZENhdGNoKFxuICAgICAgbmV3IHNmbl90YXNrcy5TbnNQdWJsaXNoKHRoaXMsICdTZW5kRW1haWxPbkZhaWx1cmUnLCB7XG4gICAgICAgIHRvcGljOiB0b3BpYyxcbiAgICAgICAgbWVzc2FnZTogc2ZuLlRhc2tJbnB1dC5mcm9tSnNvblBhdGhBdCgnJCcpLFxuICAgICAgfSkubmV4dChuZXcgc2ZuLkZhaWwodGhpcywgJ0ZhaWwnKSksXG4gICAgKTtcbiAgICBjZXJ0Ym90UnVuVGFzay5hZGRSZXRyeSh7XG4gICAgICBpbnRlcnZhbDogbGliLkR1cmF0aW9uLnNlY29uZHMoMjApLFxuICAgIH0pO1xuICAgIGNvbnN0IGNlcnRib3RTdGF0ZU1hY2hpbmUgPSBuZXcgc2ZuLlN0YXRlTWFjaGluZSh0aGlzLCAnU3RhdGVNYWNoaW5lJywge1xuICAgICAgZGVmaW5pdGlvbjogY2VydGJvdFJ1blRhc2ssXG4gICAgfSk7XG5cbiAgICBuZXcgUnVsZSh0aGlzLCAnQ2VydGJvdFNjaGVkdWxlUnVsZScsIHtcbiAgICAgIHNjaGVkdWxlOiBTY2hlZHVsZS5yYXRlKFxuICAgICAgICBsaWIuRHVyYXRpb24uZGF5cyhwcm9wcy5jZXJ0Ym90U2NoZWR1bGVJbnRlcnZhbCA/PyA2MCksXG4gICAgICApLFxuICAgICAgdGFyZ2V0czogW25ldyBTZm5TdGF0ZU1hY2hpbmUoY2VydGJvdFN0YXRlTWFjaGluZSldLFxuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogU2VydmVyIEVDUyB0YXNrXG4gICAgICovXG4gICAgY29uc3Qgc2VydmVyVGFza0RlZmluaXRpb24gPVxuICAgICAgcHJvcHMuc2VydmVyVGFza0RlZmluaXRpb24gPz8gdGhpcy5zYW1wbGVTZXZlclRhc2socmVjb3JkcywgbG9nR3JvdXApO1xuICAgIGNlcnRGaWxlU3lzdGVtLmdyYW50KFxuICAgICAgc2VydmVyVGFza0RlZmluaXRpb24udGFza1JvbGUsXG4gICAgICAnZWxhc3RpY2ZpbGVzeXN0ZW06Q2xpZW50TW91bnQnLFxuICAgICk7XG4gICAgc2VydmVyVGFza0RlZmluaXRpb24uYWRkVm9sdW1lKHtcbiAgICAgIG5hbWU6ICdjZXJ0Vm9sdW1lJyxcbiAgICAgIGVmc1ZvbHVtZUNvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgZmlsZVN5c3RlbUlkOiBjZXJ0RmlsZVN5c3RlbS5maWxlU3lzdGVtSWQsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHNlcnZlclRhc2tEZWZpbml0aW9uLmRlZmF1bHRDb250YWluZXI/LmFkZE1vdW50UG9pbnRzKHtcbiAgICAgIHNvdXJjZVZvbHVtZTogJ2NlcnRWb2x1bWUnLFxuICAgICAgY29udGFpbmVyUGF0aDogJy9ldGMvbGV0c2VuY3J5cHQnLFxuICAgICAgcmVhZE9ubHk6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBBV1MgY2xpIGNvbnRhaW5lciB0byBleGVjdXRlIGNlcnRib3Qgc2ZuIGJlZm9yZSB0aGUgZGVmYXVsdCBjb250YWluZXIgc3RhcnR1cC5cbiAgICAgKi9cbiAgICBzZXJ2ZXJUYXNrRGVmaW5pdGlvbi5kZWZhdWx0Q29udGFpbmVyPy5hZGRDb250YWluZXJEZXBlbmRlbmNpZXMoe1xuICAgICAgY29udGFpbmVyOiBzZXJ2ZXJUYXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoJ0FXU0NsaUNvbnRhaW5lcicsIHtcbiAgICAgICAgaW1hZ2U6IGVjcy5Db250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoYGFtYXpvbi9hd3MtY2xpOiR7YXdzQ2xpVGFnfWApLFxuICAgICAgICBjb250YWluZXJOYW1lOiAnYXdzLWNsaScsXG4gICAgICAgIG1lbW9yeVJlc2VydmF0aW9uTWlCOiA2NCxcbiAgICAgICAgZW50cnlQb2ludDogWycvYmluL2Jhc2gnLCAnLWMnXSxcbiAgICAgICAgY29tbWFuZDogW1xuICAgICAgICAgIGBzZXQgLWV1eFxuICAgICAgICAgIGF3cyBjb25maWd1cmUgc2V0IHJlZ2lvbiAke2NlcnRib3RTdGF0ZU1hY2hpbmUuZW52LnJlZ2lvbn0gJiYgXFxcXFxuICAgICAgICAgIGF3cyBjb25maWd1cmUgc2V0IG91dHB1dCB0ZXh0ICYmIFxcXFxcbiAgICAgICAgICBFWEVDVVRJT05fQVJOPSQoYXdzIHN0ZXBmdW5jdGlvbnMgc3RhcnQtZXhlY3V0aW9uIC0tc3RhdGUtbWFjaGluZS1hcm4gJHtjZXJ0Ym90U3RhdGVNYWNoaW5lLnN0YXRlTWFjaGluZUFybn0gLS1xdWVyeSBleGVjdXRpb25Bcm4pICYmIFxcXFxcbiAgICAgICAgICB1bnRpbCBbICQoYXdzIHN0ZXBmdW5jdGlvbnMgZGVzY3JpYmUtZXhlY3V0aW9uIC0tZXhlY3V0aW9uLWFybiBcIiRFWEVDVVRJT05fQVJOXCIgLS1xdWVyeSBzdGF0dXMpICE9IFJVTk5JTkcgXTtcbiAgICAgICAgICBkb1xuICAgICAgICAgICAgZWNobyBcIldhaXRpbmcgZm9yICRFWEVDVVRJT05fQVJOXCJcbiAgICAgICAgICAgIHNsZWVwIDEwXG4gICAgICAgICAgZG9uZWAsXG4gICAgICAgIF0sXG4gICAgICAgIGVzc2VudGlhbDogZmFsc2UsXG4gICAgICAgIGxvZ2dpbmc6IGVjcy5Mb2dEcml2ZXIuYXdzTG9ncyh7XG4gICAgICAgICAgbG9nR3JvdXA6IGxvZ0dyb3VwLFxuICAgICAgICAgIHN0cmVhbVByZWZpeDogYXdzQ2xpVGFnLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICAgY29uZGl0aW9uOiBlY3MuQ29udGFpbmVyRGVwZW5kZW5jeUNvbmRpdGlvbi5DT01QTEVURSxcbiAgICB9KTtcbiAgICBjZXJ0Ym90U3RhdGVNYWNoaW5lLmdyYW50RXhlY3V0aW9uKFxuICAgICAgc2VydmVyVGFza0RlZmluaXRpb24udGFza1JvbGUsXG4gICAgICAnc3RhdGVzOkRlc2NyaWJlRXhlY3V0aW9uJyxcbiAgICApO1xuICAgIGNlcnRib3RTdGF0ZU1hY2hpbmUuZ3JhbnRTdGFydEV4ZWN1dGlvbihzZXJ2ZXJUYXNrRGVmaW5pdGlvbi50YXNrUm9sZSk7XG5cbiAgICBuZXcgZWNzLkVjMlNlcnZpY2UodGhpcywgJ1NlcnZpY2UnLCB7XG4gICAgICBjbHVzdGVyOiBjbHVzdGVyLFxuICAgICAgdGFza0RlZmluaXRpb246IHNlcnZlclRhc2tEZWZpbml0aW9uLFxuICAgICAgZGVzaXJlZENvdW50OiAxLFxuICAgICAgbWluSGVhbHRoeVBlcmNlbnQ6IDAsXG4gICAgICBtYXhIZWFsdGh5UGVyY2VudDogMTAwLFxuICAgICAgY2lyY3VpdEJyZWFrZXI6IHtcbiAgICAgICAgcm9sbGJhY2s6IHRydWUsXG4gICAgICB9LFxuICAgICAgZW5hYmxlRXhlY3V0ZUNvbW1hbmQ6IHRydWUsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNhbXBsZVNldmVyVGFzayhcbiAgICByZWNvcmRzOiBzdHJpbmdbXSxcbiAgICBsb2dHcm91cDogSUxvZ0dyb3VwLFxuICApOiBlY3MuRWMyVGFza0RlZmluaXRpb24ge1xuICAgIGNvbnN0IG5naW54VGFza0RlZmluaXRpb24gPSBuZXcgZWNzLkVjMlRhc2tEZWZpbml0aW9uKFxuICAgICAgdGhpcyxcbiAgICAgICdOZ2lueFRhc2tEZWZpbml0aW9uJyxcbiAgICApO1xuICAgIGNvbnN0IG5naW54Q29udGFpbmVyID0gbmdpbnhUYXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoJ05naW54Q29udGFpbmVyJywge1xuICAgICAgaW1hZ2U6IGVjcy5Db250YWluZXJJbWFnZS5mcm9tQXNzZXQoXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9jb250YWluZXJzL25naW54LXByb3h5JyksXG4gICAgICApLFxuICAgICAgY29udGFpbmVyTmFtZTogJ25naW54JyxcbiAgICAgIG1lbW9yeVJlc2VydmF0aW9uTWlCOiA2NCxcbiAgICAgIGVzc2VudGlhbDogdHJ1ZSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFNFUlZFUl9OQU1FOiByZWNvcmRzLmpvaW4oJyAnKSxcbiAgICAgICAgQ0VSVF9OQU1FOiByZWNvcmRzWzBdLFxuICAgICAgfSxcbiAgICAgIGxvZ2dpbmc6IGVjcy5Mb2dEcml2ZXJzLmF3c0xvZ3Moe1xuICAgICAgICBsb2dHcm91cDogbG9nR3JvdXAsXG4gICAgICAgIHN0cmVhbVByZWZpeDogJ25naW54LXByb3h5JyxcbiAgICAgIH0pLFxuICAgIH0pO1xuXG4gICAgbmdpbnhDb250YWluZXIuYWRkUG9ydE1hcHBpbmdzKFxuICAgICAge1xuICAgICAgICBob3N0UG9ydDogODAsXG4gICAgICAgIGNvbnRhaW5lclBvcnQ6IDgwLFxuICAgICAgICBwcm90b2NvbDogZWNzLlByb3RvY29sLlRDUCxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGhvc3RQb3J0OiA0NDMsXG4gICAgICAgIGNvbnRhaW5lclBvcnQ6IDQ0MyxcbiAgICAgICAgcHJvdG9jb2w6IGVjcy5Qcm90b2NvbC5UQ1AsXG4gICAgICB9LFxuICAgICk7XG5cbiAgICByZXR1cm4gbmdpbnhUYXNrRGVmaW5pdGlvbjtcbiAgfVxufVxuIl19
package/package.json ADDED
@@ -0,0 +1,139 @@
1
+ {
2
+ "name": "low-cost-ecs",
3
+ "description": "Easy and low-cost ECS on EC2 server without a load balancer",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/rajyan/low-cost-ecs.git"
7
+ },
8
+ "scripts": {
9
+ "build": "npx projen build",
10
+ "bump": "npx projen bump",
11
+ "clobber": "npx projen clobber",
12
+ "compat": "npx projen compat",
13
+ "compile": "npx projen compile",
14
+ "default": "npx projen default",
15
+ "docgen": "npx projen docgen",
16
+ "eject": "npx projen eject",
17
+ "eslint": "npx projen eslint",
18
+ "package": "npx projen package",
19
+ "package-all": "npx projen package-all",
20
+ "package:js": "npx projen package:js",
21
+ "package:python": "npx projen package:python",
22
+ "post-compile": "npx projen post-compile",
23
+ "post-upgrade": "npx projen post-upgrade",
24
+ "pre-compile": "npx projen pre-compile",
25
+ "release": "npx projen release",
26
+ "test": "npx projen test",
27
+ "test:update": "npx projen test:update",
28
+ "test:watch": "npx projen test:watch",
29
+ "unbump": "npx projen unbump",
30
+ "upgrade": "npx projen upgrade",
31
+ "watch": "npx projen watch",
32
+ "projen": "npx projen"
33
+ },
34
+ "author": {
35
+ "name": "Yohta Kimura",
36
+ "email": "kitakita7617@gmail.com",
37
+ "organization": false
38
+ },
39
+ "devDependencies": {
40
+ "@types/jest": "^27",
41
+ "@types/node": "^14",
42
+ "@typescript-eslint/eslint-plugin": "^5",
43
+ "@typescript-eslint/parser": "^5",
44
+ "aws-cdk": "^2.39.0",
45
+ "aws-cdk-lib": "2.37.0",
46
+ "constructs": "10.0.5",
47
+ "eslint": "8.22.0",
48
+ "eslint-import-resolver-node": "^0.3.6",
49
+ "eslint-import-resolver-typescript": "^3.5.0",
50
+ "eslint-plugin-import": "^2.26.0",
51
+ "jest": "^27",
52
+ "jest-junit": "^13",
53
+ "jsii": "^1.65.0",
54
+ "jsii-diff": "^1.65.0",
55
+ "jsii-docgen": "^7.0.73",
56
+ "jsii-pacmak": "^1.65.0",
57
+ "json-schema": "^0.4.0",
58
+ "npm-check-updates": "^15",
59
+ "projen": "^0.61.30",
60
+ "standard-version": "^9",
61
+ "ts-jest": "^27",
62
+ "ts-node": "^10.9.1",
63
+ "typescript": "~4.7.4"
64
+ },
65
+ "peerDependencies": {
66
+ "aws-cdk-lib": "^2.37.0",
67
+ "constructs": "^10.0.5"
68
+ },
69
+ "keywords": [
70
+ "cdk",
71
+ "certbot",
72
+ "ecs",
73
+ "loadbalancer",
74
+ "route53",
75
+ "stepfunctions"
76
+ ],
77
+ "main": "lib/index.js",
78
+ "license": "MIT",
79
+ "version": "0.0.6",
80
+ "jest": {
81
+ "testMatch": [
82
+ "<rootDir>/src/**/__tests__/**/*.ts?(x)",
83
+ "<rootDir>/(test|src)/**/*(*.)@(spec|test).ts?(x)"
84
+ ],
85
+ "clearMocks": true,
86
+ "collectCoverage": true,
87
+ "coverageReporters": [
88
+ "json",
89
+ "lcov",
90
+ "clover",
91
+ "cobertura",
92
+ "text"
93
+ ],
94
+ "coverageDirectory": "coverage",
95
+ "coveragePathIgnorePatterns": [
96
+ "/node_modules/"
97
+ ],
98
+ "testPathIgnorePatterns": [
99
+ "/node_modules/"
100
+ ],
101
+ "watchPathIgnorePatterns": [
102
+ "/node_modules/"
103
+ ],
104
+ "reporters": [
105
+ "default",
106
+ [
107
+ "jest-junit",
108
+ {
109
+ "outputDirectory": "test-reports"
110
+ }
111
+ ]
112
+ ],
113
+ "preset": "ts-jest",
114
+ "globals": {
115
+ "ts-jest": {
116
+ "tsconfig": "tsconfig.dev.json"
117
+ }
118
+ }
119
+ },
120
+ "types": "lib/index.d.ts",
121
+ "stability": "experimental",
122
+ "jsii": {
123
+ "outdir": "dist",
124
+ "targets": {
125
+ "python": {
126
+ "distName": "low-cost-ecs",
127
+ "module": "low_cost_ecs"
128
+ }
129
+ },
130
+ "tsc": {
131
+ "outDir": "lib",
132
+ "rootDir": "src"
133
+ }
134
+ },
135
+ "resolutions": {
136
+ "@types/prettier": "2.6.0"
137
+ },
138
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
139
+ }
package/todo.md ADDED
@@ -0,0 +1,4 @@
1
+ # todo
2
+
3
+ * update Overview
4
+ * add properties to expose