@fishawack/lab-env 5.7.0-beta.2 → 5.7.0-beta.4
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/CHANGELOG.md +51 -0
- package/_Test/provision.js +1 -8
- package/_Test/prune.js +8 -5
- package/bitbucket-pipelines.yml +2 -2
- package/cli.js +1 -0
- package/commands/create/cmds/dekey.js +13 -9
- package/commands/create/cmds/deprovision.js +29 -0
- package/commands/create/cmds/key.js +60 -41
- package/commands/create/cmds/provision.js +425 -55
- package/commands/create/cmds/rekey.js +218 -0
- package/commands/create/libs/output-credentials.js +59 -0
- package/commands/create/libs/parallel-runner.js +204 -0
- package/commands/create/libs/resolve-operator.js +59 -0
- package/commands/create/libs/utilities.js +71 -8
- package/commands/create/libs/vars.js +70 -86
- package/commands/create/services/aws/acm.js +4 -2
- package/commands/create/services/aws/cloudfront.js +51 -45
- package/commands/create/services/aws/ec2.js +132 -53
- package/commands/create/services/aws/elasticache.js +159 -0
- package/commands/create/services/aws/elasticbeanstalk.js +141 -60
- package/commands/create/services/aws/iam.js +178 -98
- package/commands/create/services/aws/index.js +1202 -466
- package/commands/create/services/aws/opensearch.js +25 -17
- package/commands/create/services/aws/rds.js +22 -34
- package/commands/create/services/aws/s3.js +14 -27
- package/commands/create/services/aws/secretsmanager.js +8 -15
- package/commands/create/services/aws/ses.js +195 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/cron.config +45 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/queue-worker.config +29 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/software.config +12 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/setvars.config +2 -16
- package/commands/create/templates/elasticbeanstalk/.platform/confighooks/postdeploy/rewrite-flush.sh +1 -1
- package/commands/create/templates/elasticbeanstalk/.platform/confighooks/postdeploy/setvars.sh +19 -0
- package/commands/create/templates/elasticbeanstalk/.platform/hooks/postdeploy/restart_queue.sh +4 -0
- package/commands/create/templates/elasticbeanstalk/.platform/hooks/prebuild/setvars.sh +19 -0
- package/commands/scan.js +1 -1
- package/package.json +5 -2
|
@@ -20,14 +20,15 @@ const {
|
|
|
20
20
|
DescribeInternetGatewaysCommand,
|
|
21
21
|
} = require("@aws-sdk/client-ec2");
|
|
22
22
|
const { Spinner, poll } = require("../../libs/utilities");
|
|
23
|
+
const { awsClientConfig } = require("../../libs/vars");
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
const client = new EC2Client({});
|
|
25
|
+
const getClient = () => new EC2Client(awsClientConfig);
|
|
26
26
|
|
|
27
|
+
module.exports.getKeyPair = async (KeyName) => {
|
|
27
28
|
let res = await Spinner.prototype.simple(
|
|
28
29
|
`Retrieving the KeyPair ${KeyName}`,
|
|
29
30
|
() => {
|
|
30
|
-
return
|
|
31
|
+
return getClient().send(
|
|
31
32
|
new DescribeKeyPairsCommand({ KeyNames: [KeyName] }),
|
|
32
33
|
);
|
|
33
34
|
},
|
|
@@ -37,15 +38,13 @@ module.exports.getKeyPair = async (KeyName) => {
|
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
module.exports.createRDSSecurityGroup = async (name, tags = []) => {
|
|
40
|
-
const client = new EC2Client({});
|
|
41
|
-
|
|
42
41
|
const groupName = `${name}-rds`;
|
|
43
42
|
|
|
44
43
|
try {
|
|
45
44
|
const sg = await Spinner.prototype.simple(
|
|
46
45
|
`Creating security group ${groupName}`,
|
|
47
46
|
() => {
|
|
48
|
-
return
|
|
47
|
+
return getClient().send(
|
|
49
48
|
new CreateSecurityGroupCommand({
|
|
50
49
|
GroupName: groupName,
|
|
51
50
|
Description: `RDS access for ${name}`,
|
|
@@ -84,12 +83,10 @@ module.exports.authorizeRDSIngress = async (
|
|
|
84
83
|
rdsSecurityGroupId,
|
|
85
84
|
sourceSecurityGroupId,
|
|
86
85
|
) => {
|
|
87
|
-
const client = new EC2Client({});
|
|
88
|
-
|
|
89
86
|
await Spinner.prototype.simple(
|
|
90
87
|
`Adding MySQL inbound rule from EB security group`,
|
|
91
88
|
() => {
|
|
92
|
-
return
|
|
89
|
+
return getClient().send(
|
|
93
90
|
new AuthorizeSecurityGroupIngressCommand({
|
|
94
91
|
GroupId: rdsSecurityGroupId,
|
|
95
92
|
IpPermissions: [
|
|
@@ -116,12 +113,10 @@ module.exports.revokeRDSIngress = async (
|
|
|
116
113
|
rdsSecurityGroupId,
|
|
117
114
|
sourceSecurityGroupId,
|
|
118
115
|
) => {
|
|
119
|
-
const client = new EC2Client({});
|
|
120
|
-
|
|
121
116
|
await Spinner.prototype.simple(
|
|
122
117
|
`Removing MySQL inbound rule from RDS security group`,
|
|
123
118
|
() => {
|
|
124
|
-
return
|
|
119
|
+
return getClient().send(
|
|
125
120
|
new RevokeSecurityGroupIngressCommand({
|
|
126
121
|
GroupId: rdsSecurityGroupId,
|
|
127
122
|
IpPermissions: [
|
|
@@ -143,15 +138,13 @@ module.exports.revokeRDSIngress = async (
|
|
|
143
138
|
};
|
|
144
139
|
|
|
145
140
|
module.exports.createOpenSearchSecurityGroup = async (name, tags = []) => {
|
|
146
|
-
const client = new EC2Client({});
|
|
147
|
-
|
|
148
141
|
const groupName = `${name}-os`;
|
|
149
142
|
|
|
150
143
|
try {
|
|
151
144
|
const sg = await Spinner.prototype.simple(
|
|
152
145
|
`Creating security group ${groupName}`,
|
|
153
146
|
() => {
|
|
154
|
-
return
|
|
147
|
+
return getClient().send(
|
|
155
148
|
new CreateSecurityGroupCommand({
|
|
156
149
|
GroupName: groupName,
|
|
157
150
|
Description: `OpenSearch access for ${name}`,
|
|
@@ -190,12 +183,10 @@ module.exports.authorizeOpenSearchIngress = async (
|
|
|
190
183
|
osSecurityGroupId,
|
|
191
184
|
sourceSecurityGroupId,
|
|
192
185
|
) => {
|
|
193
|
-
const client = new EC2Client({});
|
|
194
|
-
|
|
195
186
|
await Spinner.prototype.simple(
|
|
196
187
|
`Adding HTTPS inbound rule from EB security group`,
|
|
197
188
|
() => {
|
|
198
|
-
return
|
|
189
|
+
return getClient().send(
|
|
199
190
|
new AuthorizeSecurityGroupIngressCommand({
|
|
200
191
|
GroupId: osSecurityGroupId,
|
|
201
192
|
IpPermissions: [
|
|
@@ -222,12 +213,10 @@ module.exports.revokeOpenSearchIngress = async (
|
|
|
222
213
|
osSecurityGroupId,
|
|
223
214
|
sourceSecurityGroupId,
|
|
224
215
|
) => {
|
|
225
|
-
const client = new EC2Client({});
|
|
226
|
-
|
|
227
216
|
await Spinner.prototype.simple(
|
|
228
217
|
`Removing HTTPS inbound rule from OpenSearch security group`,
|
|
229
218
|
() => {
|
|
230
|
-
return
|
|
219
|
+
return getClient().send(
|
|
231
220
|
new RevokeSecurityGroupIngressCommand({
|
|
232
221
|
GroupId: osSecurityGroupId,
|
|
233
222
|
IpPermissions: [
|
|
@@ -248,13 +237,111 @@ module.exports.revokeOpenSearchIngress = async (
|
|
|
248
237
|
);
|
|
249
238
|
};
|
|
250
239
|
|
|
251
|
-
module.exports.
|
|
252
|
-
const
|
|
240
|
+
module.exports.createCacheSecurityGroup = async (name, tags = []) => {
|
|
241
|
+
const groupName = `${name}-cache`;
|
|
253
242
|
|
|
243
|
+
try {
|
|
244
|
+
const sg = await Spinner.prototype.simple(
|
|
245
|
+
`Creating security group ${groupName}`,
|
|
246
|
+
() => {
|
|
247
|
+
return getClient().send(
|
|
248
|
+
new CreateSecurityGroupCommand({
|
|
249
|
+
GroupName: groupName,
|
|
250
|
+
Description: `ElastiCache access for ${name}`,
|
|
251
|
+
TagSpecifications: [
|
|
252
|
+
{
|
|
253
|
+
ResourceType: "security-group",
|
|
254
|
+
Tags: [
|
|
255
|
+
{
|
|
256
|
+
Key: "Name",
|
|
257
|
+
Value: groupName,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
Key: "client",
|
|
261
|
+
Value: process.env.AWS_PROFILE,
|
|
262
|
+
},
|
|
263
|
+
].concat(tags),
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
}),
|
|
267
|
+
);
|
|
268
|
+
},
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
return sg.GroupId;
|
|
272
|
+
} catch (e) {
|
|
273
|
+
if (e.Code === "InvalidGroup.Duplicate") {
|
|
274
|
+
const existing =
|
|
275
|
+
await module.exports.findSecurityGroupByName(groupName);
|
|
276
|
+
return existing.GroupId;
|
|
277
|
+
}
|
|
278
|
+
throw e;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
module.exports.authorizeCacheIngress = async (
|
|
283
|
+
cacheSecurityGroupId,
|
|
284
|
+
sourceSecurityGroupId,
|
|
285
|
+
) => {
|
|
286
|
+
await Spinner.prototype.simple(
|
|
287
|
+
`Adding Redis inbound rule from EB security group`,
|
|
288
|
+
() => {
|
|
289
|
+
return getClient().send(
|
|
290
|
+
new AuthorizeSecurityGroupIngressCommand({
|
|
291
|
+
GroupId: cacheSecurityGroupId,
|
|
292
|
+
IpPermissions: [
|
|
293
|
+
{
|
|
294
|
+
IpProtocol: "tcp",
|
|
295
|
+
FromPort: 6380,
|
|
296
|
+
ToPort: 6380,
|
|
297
|
+
UserIdGroupPairs: [
|
|
298
|
+
{
|
|
299
|
+
GroupId: sourceSecurityGroupId,
|
|
300
|
+
Description:
|
|
301
|
+
"Redis/Valkey access for EB instances",
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
},
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
module.exports.revokeCacheIngress = async (
|
|
313
|
+
cacheSecurityGroupId,
|
|
314
|
+
sourceSecurityGroupId,
|
|
315
|
+
) => {
|
|
316
|
+
await Spinner.prototype.simple(
|
|
317
|
+
`Removing Redis inbound rule from cache security group`,
|
|
318
|
+
() => {
|
|
319
|
+
return getClient().send(
|
|
320
|
+
new RevokeSecurityGroupIngressCommand({
|
|
321
|
+
GroupId: cacheSecurityGroupId,
|
|
322
|
+
IpPermissions: [
|
|
323
|
+
{
|
|
324
|
+
IpProtocol: "tcp",
|
|
325
|
+
FromPort: 6380,
|
|
326
|
+
ToPort: 6380,
|
|
327
|
+
UserIdGroupPairs: [
|
|
328
|
+
{
|
|
329
|
+
GroupId: sourceSecurityGroupId,
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
module.exports.findSecurityGroupByTag = async (filters = []) => {
|
|
254
341
|
const res = await Spinner.prototype.simple(
|
|
255
342
|
`Looking up security group by filters`,
|
|
256
343
|
() => {
|
|
257
|
-
return
|
|
344
|
+
return getClient().send(
|
|
258
345
|
new DescribeSecurityGroupsCommand({
|
|
259
346
|
Filters: filters,
|
|
260
347
|
}),
|
|
@@ -266,12 +353,10 @@ module.exports.findSecurityGroupByTag = async (filters = []) => {
|
|
|
266
353
|
};
|
|
267
354
|
|
|
268
355
|
module.exports.findSecurityGroupByName = async (name) => {
|
|
269
|
-
const client = new EC2Client({});
|
|
270
|
-
|
|
271
356
|
const res = await Spinner.prototype.simple(
|
|
272
357
|
`Looking up security group ${name}`,
|
|
273
358
|
() => {
|
|
274
|
-
return
|
|
359
|
+
return getClient().send(
|
|
275
360
|
new DescribeSecurityGroupsCommand({
|
|
276
361
|
Filters: [{ Name: "group-name", Values: [name] }],
|
|
277
362
|
}),
|
|
@@ -283,23 +368,21 @@ module.exports.findSecurityGroupByName = async (name) => {
|
|
|
283
368
|
};
|
|
284
369
|
|
|
285
370
|
module.exports.deleteSecurityGroup = async (groupId) => {
|
|
286
|
-
const client = new EC2Client({});
|
|
287
|
-
|
|
288
371
|
await Spinner.prototype.simple(`Deleting security group ${groupId}`, () => {
|
|
289
|
-
return
|
|
372
|
+
return getClient().send(
|
|
290
373
|
new DeleteSecurityGroupCommand({ GroupId: groupId }),
|
|
291
374
|
);
|
|
292
375
|
});
|
|
293
376
|
};
|
|
294
377
|
|
|
295
|
-
const discoverPublicSubnets = async (
|
|
296
|
-
const { Subnets: allSubnets } = await
|
|
378
|
+
const discoverPublicSubnets = async (vpcId, excludeIds, azs) => {
|
|
379
|
+
const { Subnets: allSubnets } = await getClient().send(
|
|
297
380
|
new DescribeSubnetsCommand({
|
|
298
381
|
Filters: [{ Name: "vpc-id", Values: [vpcId] }],
|
|
299
382
|
}),
|
|
300
383
|
);
|
|
301
384
|
|
|
302
|
-
const { RouteTables } = await
|
|
385
|
+
const { RouteTables } = await getClient().send(
|
|
303
386
|
new DescribeRouteTablesCommand({
|
|
304
387
|
Filters: [{ Name: "vpc-id", Values: [vpcId] }],
|
|
305
388
|
}),
|
|
@@ -334,10 +417,8 @@ const discoverPublicSubnets = async (client, vpcId, excludeIds, azs) => {
|
|
|
334
417
|
};
|
|
335
418
|
|
|
336
419
|
module.exports.ensurePrivateSubnets = async () => {
|
|
337
|
-
const client = new EC2Client({});
|
|
338
|
-
|
|
339
420
|
// Get default VPC
|
|
340
|
-
const { Vpcs } = await
|
|
421
|
+
const { Vpcs } = await getClient().send(
|
|
341
422
|
new DescribeVpcsCommand({
|
|
342
423
|
Filters: [{ Name: "isDefault", Values: ["true"] }],
|
|
343
424
|
}),
|
|
@@ -351,7 +432,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
351
432
|
const vpcId = vpc.VpcId;
|
|
352
433
|
|
|
353
434
|
// Preflight: check all private networking resources
|
|
354
|
-
const { Subnets: existingSubnets } = await
|
|
435
|
+
const { Subnets: existingSubnets } = await getClient().send(
|
|
355
436
|
new DescribeSubnetsCommand({
|
|
356
437
|
Filters: [
|
|
357
438
|
{ Name: "vpc-id", Values: [vpcId] },
|
|
@@ -360,7 +441,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
360
441
|
}),
|
|
361
442
|
);
|
|
362
443
|
|
|
363
|
-
const { NatGateways: allNats } = await
|
|
444
|
+
const { NatGateways: allNats } = await getClient().send(
|
|
364
445
|
new DescribeNatGatewaysCommand({
|
|
365
446
|
Filter: [
|
|
366
447
|
{ Name: "vpc-id", Values: [vpcId] },
|
|
@@ -372,7 +453,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
372
453
|
(n) => n.State !== "deleted" && n.State !== "deleting",
|
|
373
454
|
);
|
|
374
455
|
|
|
375
|
-
const { RouteTables: existingRtbs } = await
|
|
456
|
+
const { RouteTables: existingRtbs } = await getClient().send(
|
|
376
457
|
new DescribeRouteTablesCommand({
|
|
377
458
|
Filters: [
|
|
378
459
|
{ Name: "vpc-id", Values: [vpcId] },
|
|
@@ -409,7 +490,6 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
409
490
|
// All resources exist — nothing to do
|
|
410
491
|
if (!needsSubnets && !needsNats && !needsRtbs) {
|
|
411
492
|
const publicSubnetIds = await discoverPublicSubnets(
|
|
412
|
-
client,
|
|
413
493
|
vpcId,
|
|
414
494
|
existingSubnets.map((s) => s.SubnetId),
|
|
415
495
|
existingSubnets.slice(0, 2).map((s) => s.AvailabilityZone),
|
|
@@ -430,7 +510,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
430
510
|
azs = existingSubnets.slice(0, 2).map((s) => s.AvailabilityZone);
|
|
431
511
|
} else {
|
|
432
512
|
spinner.ora.text = "Discovering availability zones";
|
|
433
|
-
const { AvailabilityZones } = await
|
|
513
|
+
const { AvailabilityZones } = await getClient().send(
|
|
434
514
|
new DescribeAvailabilityZonesCommand({
|
|
435
515
|
Filters: [{ Name: "state", Values: ["available"] }],
|
|
436
516
|
}),
|
|
@@ -446,7 +526,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
446
526
|
let privateSubnetIds;
|
|
447
527
|
if (needsSubnets) {
|
|
448
528
|
spinner.ora.text = "Discovering available CIDR blocks";
|
|
449
|
-
const { Subnets: allSubnets } = await
|
|
529
|
+
const { Subnets: allSubnets } = await getClient().send(
|
|
450
530
|
new DescribeSubnetsCommand({
|
|
451
531
|
Filters: [{ Name: "vpc-id", Values: [vpcId] }],
|
|
452
532
|
}),
|
|
@@ -504,7 +584,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
504
584
|
privateSubnetIds = [];
|
|
505
585
|
for (let i = 0; i < 2; i++) {
|
|
506
586
|
spinner.ora.text = `Creating private subnet in ${azs[i]}`;
|
|
507
|
-
const subnet = await
|
|
587
|
+
const subnet = await getClient().send(
|
|
508
588
|
new CreateSubnetCommand({
|
|
509
589
|
VpcId: vpcId,
|
|
510
590
|
CidrBlock: availableBlocks[i],
|
|
@@ -534,7 +614,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
534
614
|
if (needsNats) {
|
|
535
615
|
// Find public subnets per AZ
|
|
536
616
|
spinner.ora.text = "Identifying public subnets";
|
|
537
|
-
const { InternetGateways } = await
|
|
617
|
+
const { InternetGateways } = await getClient().send(
|
|
538
618
|
new DescribeInternetGatewaysCommand({
|
|
539
619
|
Filters: [{ Name: "attachment.vpc-id", Values: [vpcId] }],
|
|
540
620
|
}),
|
|
@@ -544,13 +624,13 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
544
624
|
throw new Error("No Internet Gateway found on default VPC");
|
|
545
625
|
}
|
|
546
626
|
|
|
547
|
-
const { Subnets: vpcSubnets } = await
|
|
627
|
+
const { Subnets: vpcSubnets } = await getClient().send(
|
|
548
628
|
new DescribeSubnetsCommand({
|
|
549
629
|
Filters: [{ Name: "vpc-id", Values: [vpcId] }],
|
|
550
630
|
}),
|
|
551
631
|
);
|
|
552
632
|
|
|
553
|
-
const { RouteTables } = await
|
|
633
|
+
const { RouteTables } = await getClient().send(
|
|
554
634
|
new DescribeRouteTablesCommand({
|
|
555
635
|
Filters: [{ Name: "vpc-id", Values: [vpcId] }],
|
|
556
636
|
}),
|
|
@@ -597,7 +677,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
597
677
|
natGatewayIds = [];
|
|
598
678
|
for (let i = 0; i < 2; i++) {
|
|
599
679
|
spinner.ora.text = `Allocating Elastic IP for NAT gateway in ${azs[i]}`;
|
|
600
|
-
const eip = await
|
|
680
|
+
const eip = await getClient().send(
|
|
601
681
|
new AllocateAddressCommand({
|
|
602
682
|
Domain: "vpc",
|
|
603
683
|
TagSpecifications: [
|
|
@@ -616,7 +696,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
616
696
|
);
|
|
617
697
|
|
|
618
698
|
spinner.ora.text = `Creating NAT gateway in ${azs[i]}`;
|
|
619
|
-
const nat = await
|
|
699
|
+
const nat = await getClient().send(
|
|
620
700
|
new CreateNatGatewayCommand({
|
|
621
701
|
SubnetId: publicSubnetsByAz[azs[i]],
|
|
622
702
|
AllocationId: eip.AllocationId,
|
|
@@ -642,7 +722,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
642
722
|
spinner.ora.text = `Waiting for NAT gateway in ${azs[i]} to become available`;
|
|
643
723
|
await poll(
|
|
644
724
|
async () => {
|
|
645
|
-
const res = await
|
|
725
|
+
const res = await getClient().send(
|
|
646
726
|
new DescribeNatGatewaysCommand({
|
|
647
727
|
NatGatewayIds: [natGatewayIds[i]],
|
|
648
728
|
}),
|
|
@@ -660,7 +740,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
660
740
|
if (needsRtbs) {
|
|
661
741
|
for (let i = 0; i < 2; i++) {
|
|
662
742
|
spinner.ora.text = `Creating route table for ${azs[i]}`;
|
|
663
|
-
const rt = await
|
|
743
|
+
const rt = await getClient().send(
|
|
664
744
|
new CreateRouteTableCommand({
|
|
665
745
|
VpcId: vpcId,
|
|
666
746
|
TagSpecifications: [
|
|
@@ -679,7 +759,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
679
759
|
);
|
|
680
760
|
|
|
681
761
|
spinner.ora.text = `Adding NAT gateway route for ${azs[i]}`;
|
|
682
|
-
await
|
|
762
|
+
await getClient().send(
|
|
683
763
|
new CreateRouteCommand({
|
|
684
764
|
RouteTableId: rt.RouteTable.RouteTableId,
|
|
685
765
|
DestinationCidrBlock: "0.0.0.0/0",
|
|
@@ -688,7 +768,7 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
688
768
|
);
|
|
689
769
|
|
|
690
770
|
spinner.ora.text = `Associating route table with private subnet in ${azs[i]}`;
|
|
691
|
-
await
|
|
771
|
+
await getClient().send(
|
|
692
772
|
new AssociateRouteTableCommand({
|
|
693
773
|
RouteTableId: rt.RouteTable.RouteTableId,
|
|
694
774
|
SubnetId: privateSubnetIds[i],
|
|
@@ -700,7 +780,6 @@ module.exports.ensurePrivateSubnets = async () => {
|
|
|
700
780
|
spinner.ora.succeed("Private subnets configured");
|
|
701
781
|
|
|
702
782
|
const publicSubnetIds = await discoverPublicSubnets(
|
|
703
|
-
client,
|
|
704
783
|
vpcId,
|
|
705
784
|
privateSubnetIds,
|
|
706
785
|
azs,
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const {
|
|
2
|
+
ElastiCacheClient,
|
|
3
|
+
CreateCacheSubnetGroupCommand,
|
|
4
|
+
CreateReplicationGroupCommand,
|
|
5
|
+
DeleteReplicationGroupCommand,
|
|
6
|
+
DescribeCacheSubnetGroupsCommand,
|
|
7
|
+
DescribeReplicationGroupsCommand,
|
|
8
|
+
} = require("@aws-sdk/client-elasticache");
|
|
9
|
+
const { Spinner, poll } = require("../../libs/utilities");
|
|
10
|
+
const { awsClientConfig } = require("../../libs/vars");
|
|
11
|
+
|
|
12
|
+
const getClient = () => new ElastiCacheClient(awsClientConfig);
|
|
13
|
+
|
|
14
|
+
module.exports.ensureCacheSubnetGroup = async (privateSubnetIds) => {
|
|
15
|
+
const name = "fw-auto-private-cache-subnet-group";
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
await getClient().send(
|
|
19
|
+
new DescribeCacheSubnetGroupsCommand({
|
|
20
|
+
CacheSubnetGroupName: name,
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return name;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
if (e.name !== "CacheSubnetGroupNotFoundFault") {
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await Spinner.prototype.simple(
|
|
32
|
+
`Creating cache subnet group ${name}`,
|
|
33
|
+
() => {
|
|
34
|
+
return getClient().send(
|
|
35
|
+
new CreateCacheSubnetGroupCommand({
|
|
36
|
+
CacheSubnetGroupName: name,
|
|
37
|
+
CacheSubnetGroupDescription:
|
|
38
|
+
"Private subnets for lab-env ElastiCache clusters",
|
|
39
|
+
SubnetIds: privateSubnetIds,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return name;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
module.exports.createCacheCluster = async (
|
|
49
|
+
name,
|
|
50
|
+
securityGroupId,
|
|
51
|
+
subnetGroupName,
|
|
52
|
+
authToken,
|
|
53
|
+
tags = [],
|
|
54
|
+
) => {
|
|
55
|
+
const res = await Spinner.prototype.simple(
|
|
56
|
+
`Creating ElastiCache cluster ${name}`,
|
|
57
|
+
() => {
|
|
58
|
+
return getClient().send(
|
|
59
|
+
new CreateReplicationGroupCommand({
|
|
60
|
+
ReplicationGroupId: name,
|
|
61
|
+
ReplicationGroupDescription: `lab-env Valkey cluster for ${name}`,
|
|
62
|
+
Engine: "valkey",
|
|
63
|
+
EngineVersion: "8.0",
|
|
64
|
+
CacheNodeType: "cache.t3.small",
|
|
65
|
+
NumCacheClusters: 1,
|
|
66
|
+
Port: 6380,
|
|
67
|
+
TransitEncryptionEnabled: true,
|
|
68
|
+
AuthToken: authToken,
|
|
69
|
+
CacheSubnetGroupName: subnetGroupName,
|
|
70
|
+
SecurityGroupIds: [securityGroupId],
|
|
71
|
+
Tags: [
|
|
72
|
+
{ Key: "client", Value: process.env.AWS_PROFILE },
|
|
73
|
+
].concat(tags),
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return res;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
module.exports.waitForCacheCluster = async (name) => {
|
|
83
|
+
const res = await Spinner.prototype.simple(
|
|
84
|
+
`Waiting for ElastiCache cluster to become available`,
|
|
85
|
+
(spinner) => {
|
|
86
|
+
return poll(
|
|
87
|
+
async () => {
|
|
88
|
+
const { ReplicationGroups } = await getClient().send(
|
|
89
|
+
new DescribeReplicationGroupsCommand({
|
|
90
|
+
ReplicationGroupId: name,
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
return ReplicationGroups[0];
|
|
94
|
+
},
|
|
95
|
+
(group) => group.Status !== "available",
|
|
96
|
+
undefined,
|
|
97
|
+
spinner,
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return res;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
module.exports.describeCacheCluster = async (name) => {
|
|
106
|
+
const res = await Spinner.prototype.simple(
|
|
107
|
+
`Describing ElastiCache cluster ${name}`,
|
|
108
|
+
() => {
|
|
109
|
+
return getClient().send(
|
|
110
|
+
new DescribeReplicationGroupsCommand({
|
|
111
|
+
ReplicationGroupId: name,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return res.ReplicationGroups[0];
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
module.exports.deleteCacheCluster = async (name) => {
|
|
121
|
+
await Spinner.prototype.simple(
|
|
122
|
+
`Deleting ElastiCache cluster ${name}`,
|
|
123
|
+
() => {
|
|
124
|
+
return getClient().send(
|
|
125
|
+
new DeleteReplicationGroupCommand({
|
|
126
|
+
ReplicationGroupId: name,
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
module.exports.waitForCacheDeletion = async (name) => {
|
|
134
|
+
await Spinner.prototype.simple(
|
|
135
|
+
`Waiting for ElastiCache cluster to be deleted`,
|
|
136
|
+
(spinner) => {
|
|
137
|
+
return poll(
|
|
138
|
+
async () => {
|
|
139
|
+
try {
|
|
140
|
+
const { ReplicationGroups } = await getClient().send(
|
|
141
|
+
new DescribeReplicationGroupsCommand({
|
|
142
|
+
ReplicationGroupId: name,
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
return ReplicationGroups[0];
|
|
146
|
+
} catch (e) {
|
|
147
|
+
if (e.name === "ReplicationGroupNotFoundFault") {
|
|
148
|
+
return { deleted: true };
|
|
149
|
+
}
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
(group) => !group.deleted,
|
|
154
|
+
undefined,
|
|
155
|
+
spinner,
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
};
|