@fishawack/lab-env 4.26.0 → 4.28.0

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/_Test/provision.js +39 -16
  3. package/_Test/s3.js +35 -0
  4. package/_Test/utilities.js +35 -1
  5. package/cli.js +0 -2
  6. package/commands/create/cmds/deprovision.js +31 -19
  7. package/commands/create/cmds/provision.js +47 -26
  8. package/commands/create/libs/prompts.js +18 -0
  9. package/commands/create/libs/utilities.js +32 -1
  10. package/commands/create/libs/vars.js +332 -1
  11. package/commands/create/services/aws/cloudfront.js +6 -13
  12. package/commands/create/services/aws/ec2.js +17 -0
  13. package/commands/create/services/aws/elasticbeanstalk.js +96 -0
  14. package/commands/create/services/aws/iam.js +123 -4
  15. package/commands/create/services/aws/index.js +98 -3
  16. package/commands/create/services/aws/misc.js +2 -0
  17. package/commands/create/services/aws/s3.js +48 -5
  18. package/commands/create/services/email.js +20 -23
  19. package/commands/create/templates/elasticbeanstalk/.ebextensions/{apache → httpd}/auto-ssl.config +18 -6
  20. package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/software.config +1 -12
  21. package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/enable-https-lb.config +9 -0
  22. package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/s3-env.config +41 -0
  23. package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/setvars.config +8 -2
  24. package/commands/create/templates/elasticbeanstalk/.ebextensions/nginx/alb-health.config +28 -0
  25. package/commands/create/templates/elasticbeanstalk/.ebextensions/nginx/auto-ssl.config +19 -7
  26. package/commands/create/templates/elasticbeanstalk/.ebextensions/wordpress/alb-health.config +28 -0
  27. package/commands/create/templates/elasticbeanstalk/.ebextensions/wordpress/cron.config +42 -0
  28. package/commands/create/templates/elasticbeanstalk/.ebextensions/wordpress/environment.config +3 -1
  29. package/commands/create/templates/elasticbeanstalk/.ebextensions/wordpress/post-deploy.config +11 -8
  30. package/commands/create/templates/elasticbeanstalk/.ebextensions/wordpress/software.config +1 -3
  31. package/commands/create/templates/elasticbeanstalk/.elasticbeanstalk/config.yml +7 -0
  32. package/commands/create/templates/elasticbeanstalk/.platform/confighooks/postdeploy/rewrite-flush.sh +4 -0
  33. package/commands/create/templates/elasticbeanstalk/.platform/hooks/postdeploy/rewrite-flush.sh +4 -0
  34. package/commands/create/templates/elasticbeanstalk/.platform/hooks/postdeploy/s3-env.sh +7 -0
  35. package/commands/create/templates/elasticbeanstalk/.platform/hooks/predeploy/deactivate-plugins-single.sh +30 -0
  36. package/commands/create/templates/elasticbeanstalk/.platform/hooks/predeploy/deactivate-plugins.sh +55 -0
  37. package/commands/create/templates/elasticbeanstalk/.platform/httpd/conf.d/elasticbeanstalk/80/forward-https-proto.conf +3 -0
  38. package/commands/create/templates/elasticbeanstalk/.platform/httpd/conf.d/elasticbeanstalk/z-wordpress-htpasswd.conf +13 -0
  39. package/commands/create/templates/elasticbeanstalk/.platform/httpd/conf.d/security_headers-wordpress.conf +11 -0
  40. package/commands/create/templates/elasticbeanstalk/.platform/nginx/conf.d/elasticbeanstalk/health.conf +4 -0
  41. package/commands/create/templates/elasticbeanstalk/.platform/nginx/conf.d/elasticbeanstalk/htpasswd.conf +2 -0
  42. package/globals.js +2 -0
  43. package/package.json +6 -1
  44. /package/commands/create/templates/elasticbeanstalk/.platform/httpd/conf.d/elasticbeanstalk/{443 → 80}/www-to-nonwww-redirection.conf +0 -0
@@ -2,6 +2,8 @@ const os = require('os');
2
2
  const path = require("path");
3
3
  const { encode } = require('./utilities');
4
4
  const fs = require("fs");
5
+ const generator = require("generate-password");
6
+ const { template } = require('lodash');
5
7
 
6
8
  var miscFile;
7
9
 
@@ -115,4 +117,333 @@ module.exports.templates = [
115
117
  "project": "PLAN",
116
118
  "prefix": "plant"
117
119
  }
118
- ];
120
+ ];
121
+
122
+ module.exports.frameworks = [
123
+ {
124
+ "name": "wordpress",
125
+ "value": "wordpress"
126
+ },
127
+ {
128
+ "name": "laravel",
129
+ "value": "laravel"
130
+ },
131
+ {
132
+ "name": "drupal",
133
+ "value": "drupal"
134
+ },
135
+ ];
136
+
137
+ // Elasticbeanstlak configs based on preconfigurations
138
+ module.exports.eb = {
139
+ environments: {
140
+ php: {
141
+ shared: [],
142
+ low: [],
143
+ high: [],
144
+ },
145
+ nginx: {
146
+ shared: [],
147
+ low: [],
148
+ high: [],
149
+ },
150
+ httpd: {
151
+ shared: [
152
+ {
153
+ OptionName: 'ProxyServer',
154
+ Value: 'apache',
155
+ Namespace: 'aws:elasticbeanstalk:environment:proxy'
156
+ },
157
+ ],
158
+ low: [],
159
+ high: [],
160
+ },
161
+ default: {
162
+ shared: [],
163
+ low: [],
164
+ high: []
165
+ },
166
+ wordpress: {
167
+ shared: [
168
+ {
169
+ OptionName: 'AUTH_KEY',
170
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
171
+ Namespace: 'aws:elasticbeanstalk:application:environment'
172
+ },
173
+ {
174
+ OptionName: 'SECURE_AUTH_KEY',
175
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
176
+ Namespace: 'aws:elasticbeanstalk:application:environment'
177
+ },
178
+ {
179
+ OptionName: 'LOGGED_IN_KEY',
180
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
181
+ Namespace: 'aws:elasticbeanstalk:application:environment'
182
+ },
183
+ {
184
+ OptionName: 'NONCE_KEY',
185
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
186
+ Namespace: 'aws:elasticbeanstalk:application:environment'
187
+ },
188
+ {
189
+ OptionName: 'AUTH_SALT',
190
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
191
+ Namespace: 'aws:elasticbeanstalk:application:environment'
192
+ },
193
+ {
194
+ OptionName: 'SECURE_AUTH_SALT',
195
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
196
+ Namespace: 'aws:elasticbeanstalk:application:environment'
197
+ },
198
+ {
199
+ OptionName: 'LOGGED_IN_SALT',
200
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
201
+ Namespace: 'aws:elasticbeanstalk:application:environment'
202
+ },
203
+ {
204
+ OptionName: 'NONCE_SALT',
205
+ Value: generator.generate({ length: 64, numbers: true, symbols: true }),
206
+ Namespace: 'aws:elasticbeanstalk:application:environment'
207
+ },
208
+ { OptionName: 'S3_UPLOADS_BUCKET', Value: "<%= s3Slug %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
209
+ { OptionName: 'S3_UPLOADS_REGION', Value: "<%= AWS_REGION %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
210
+ { OptionName: 'S3_UPLOADS_KEY', Value: "<%= AccessKeyId %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
211
+ { OptionName: 'S3_UPLOADS_SECRET', Value: "<%= SecretAccessKey %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
212
+ ],
213
+ low: [],
214
+ high: []
215
+ },
216
+ laravel: {
217
+ shared: [
218
+ {
219
+ OptionName: 'APP_ENV',
220
+ Value: 'production',
221
+ Namespace: 'aws:elasticbeanstalk:application:environment'
222
+ },
223
+ {
224
+ OptionName: 'APP_KEY',
225
+ Value: `base64:${Buffer.from(generator.generate({ length: 32, numbers: true, symbols: true })).toString('base64')}`,
226
+ Namespace: 'aws:elasticbeanstalk:application:environment'
227
+ },
228
+ {
229
+ OptionName: 'APP_DEBUG',
230
+ Value: 'false',
231
+ Namespace: 'aws:elasticbeanstalk:application:environment'
232
+ },
233
+ {
234
+ OptionName: 'APP_URL',
235
+ Value: 'https://<%= DOMAIN_LINK %>',
236
+ Namespace: 'aws:elasticbeanstalk:application:environment'
237
+ },
238
+ { OptionName: 'AWS_BUCKET', Value: "<%= s3Slug %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
239
+ { OptionName: 'AWS_DEFAULT_REGION', Value: "<%= AWS_REGION %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
240
+ { OptionName: 'AWS_ACCESS_KEY_ID', Value: "<%= AccessKeyId %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
241
+ { OptionName: 'AWS_SECRET_ACCESS_KEY', Value: "<%= SecretAccessKey %>", Namespace: 'aws:elasticbeanstalk:application:environment' },
242
+ { OptionName: 'FILESYSTEM_DISK', Value: "s3", Namespace: 'aws:elasticbeanstalk:application:environment' },
243
+ { OptionName: 'FILESYSTEM_DISK_PUBLIC', Value: "s3-public", Namespace: 'aws:elasticbeanstalk:application:environment' },
244
+ ],
245
+ low: [],
246
+ high: [
247
+ { OptionName: 'SESSION_DRIVER', Value: "cookie", Namespace: 'aws:elasticbeanstalk:application:environment' },
248
+ { OptionName: 'SESSION_SECURE_COOKIE', Value: "true", Namespace: 'aws:elasticbeanstalk:application:environment' },
249
+ ]
250
+ },
251
+ drupal: {
252
+ shared: [],
253
+ low: [],
254
+ high: []
255
+ },
256
+ shared: [
257
+ {
258
+ OptionName: 'IamInstanceProfile',
259
+ Value: 'aws-elasticbeanstalk-ec2-role',
260
+ Namespace: 'aws:autoscaling:launchconfiguration'
261
+ },
262
+ {
263
+ OptionName: 'HasCoupledDatabase',
264
+ Value: 'true',
265
+ Namespace: 'aws:rds:dbinstance'
266
+ },
267
+ {
268
+ OptionName: 'DBEngineVersion',
269
+ Value: '8.0.32',
270
+ Namespace: 'aws:rds:dbinstance'
271
+ },
272
+ {
273
+ OptionName: 'DBPassword',
274
+ Value: generator.generate({ length: 10, numbers: true }),
275
+ Namespace: 'aws:rds:dbinstance'
276
+ }
277
+ ],
278
+ low: [
279
+ {
280
+ OptionName: 'EnvironmentType',
281
+ Value: 'SingleInstance',
282
+ Namespace: 'aws:elasticbeanstalk:environment'
283
+ },
284
+ {
285
+ OptionName: 'DOMAIN_LINK',
286
+ Value: "<%= DOMAIN_LINK %>",
287
+ Namespace: 'aws:elasticbeanstalk:application:environment'
288
+ },
289
+ {
290
+ OptionName: 'EMAIL_LINK',
291
+ Value: "mike.mellor@fishawack.com",
292
+ Namespace: 'aws:elasticbeanstalk:application:environment'
293
+ },
294
+ ],
295
+ high: [
296
+ {
297
+ OptionName: 'ManagedActionsEnabled',
298
+ Value: 'true',
299
+ Namespace: 'aws:elasticbeanstalk:managedactions'
300
+ },
301
+ {
302
+ OptionName: 'ServiceRoleForManagedUpdates',
303
+ Value: 'AWSServiceRoleForElasticBeanstalkManagedUpdates',
304
+ Namespace: 'aws:elasticbeanstalk:managedactions'
305
+ },
306
+ {
307
+ OptionName: 'PreferredStartTime',
308
+ Value: 'Mon:06:00',
309
+ Namespace: 'aws:elasticbeanstalk:managedactions'
310
+ },
311
+ {
312
+ OptionName: 'UpdateLevel',
313
+ Value: 'minor',
314
+ Namespace: 'aws:elasticbeanstalk:managedactions:platformupdate'
315
+ },
316
+ {
317
+ OptionName: 'DeploymentPolicy',
318
+ Value: 'RollingWithAdditionalBatch',
319
+ Namespace: 'aws:elasticbeanstalk:command'
320
+ },
321
+ {
322
+ OptionName: 'BatchSize',
323
+ Value: '25',
324
+ Namespace: 'aws:elasticbeanstalk:command'
325
+ },
326
+ {
327
+ OptionName: 'MinSize',
328
+ Value: '2',
329
+ Namespace: 'aws:autoscaling:asg'
330
+ },
331
+ {
332
+ OptionName: 'LoadBalancerType',
333
+ Value: 'application',
334
+ Namespace: 'aws:elasticbeanstalk:environment'
335
+ },
336
+ ],
337
+ },
338
+ configurations: {
339
+ php: {
340
+ shared: [
341
+ '.ebextensions/php/ini.config',
342
+ ],
343
+ low: [],
344
+ high: [],
345
+ },
346
+ nginx: {
347
+ shared: [
348
+ '.platform/nginx/conf.d/buffer_size.conf',
349
+ '.platform/nginx/conf.d/upload_size.conf',
350
+ '.platform/nginx/conf.d/security_headers.conf',
351
+ '.platform/nginx/conf.d/elasticbeanstalk/www-to-nonwww-redirection.conf',
352
+ ],
353
+ low: [
354
+ '.platform/nginx/conf.d/elasticbeanstalk/http-https-redirection.conf',
355
+ '.platform/nginx/conf.d/ssl.conf',
356
+ '.ebextensions/nginx/auto-ssl.config',
357
+ ],
358
+ high: [
359
+ '.platform/nginx/conf.d/elasticbeanstalk/health.conf',
360
+ '.ebextensions/nginx/alb-health.config',
361
+ ],
362
+ },
363
+ httpd: {
364
+ shared: [
365
+ '.platform/httpd/conf.d/virtualhost-80.conf',
366
+ '.platform/httpd/conf.d/elasticbeanstalk/80/www-to-nonwww-redirection.conf',
367
+ ],
368
+ low: [
369
+ '.platform/httpd/conf.d/elasticbeanstalk/80/http-https-redirection.conf',
370
+ '.platform/httpd/conf.d/virtualhost-443.conf',
371
+ '.platform/httpd/conf.d/elasticbeanstalk/443/ssl.conf',
372
+ '.ebextensions/httpd/auto-ssl.config',
373
+ ],
374
+ high: [
375
+ '.platform/httpd/conf.d/elasticbeanstalk/80/forward-https-proto.conf',
376
+ '.ebextensions/wordpress/alb-health.config',
377
+ ],
378
+ },
379
+ default: {
380
+ platform: "nginx",
381
+ language: "php",
382
+ shared: [],
383
+ low: [],
384
+ high: [],
385
+ },
386
+ wordpress: {
387
+ platform: "httpd",
388
+ language: "php",
389
+ shared: [
390
+ '.platform/httpd/conf.d/security_headers-wordpress.conf',
391
+ '.platform/confighooks/postdeploy/rewrite-flush.sh',
392
+ '.platform/hooks/postdeploy/rewrite-flush.sh',
393
+ '.ebextensions/wordpress/cron.config',
394
+ '.ebextensions/wordpress/environment.config',
395
+ '.ebextensions/wordpress/post-deploy.config',
396
+ '.ebextensions/wordpress/software.config',
397
+ ],
398
+ low: [
399
+ '.platform/hooks/predeploy/deactivate-plugins-single.sh',
400
+ ],
401
+ high: [
402
+ '.platform/hooks/predeploy/deactivate-plugins.sh',
403
+ ],
404
+ },
405
+ laravel: {
406
+ platform: "nginx",
407
+ language: "php",
408
+ shared: [
409
+ '.platform/nginx/conf.d/elasticbeanstalk/laravel.conf',
410
+ '.ebextensions/laravel/post-deploy.config',
411
+ '.ebextensions/laravel/software.config',
412
+ ],
413
+ low: [],
414
+ high: [],
415
+ },
416
+ drupal: {
417
+ platform: "httpd",
418
+ language: "php",
419
+ shared: [],
420
+ low: [],
421
+ high: [],
422
+ },
423
+ shared: [
424
+ '.ebextensions/misc/setvars.config',
425
+ ],
426
+ low: [
427
+ '.ebextensions/misc/enable-https.config',
428
+ ],
429
+ high: [
430
+ '.ebextensions/misc/alb-http-to-https-redirection.config',
431
+ '.ebextensions/misc/enable-https-lb.config',
432
+ ],
433
+ },
434
+ merge(type, {framework, availability = 'low', platform, language}, data = {}){
435
+ return JSON.parse(template(JSON.stringify([].concat(
436
+ this[type].shared,
437
+ this[type][availability],
438
+ this[type][platform]?.shared,
439
+ this[type][platform]?.[availability],
440
+ this[type][language]?.shared,
441
+ this[type][language]?.[availability],
442
+ this[type][framework]?.shared,
443
+ this[type][framework]?.[availability]
444
+ ).filter(Boolean)))({...process.env, ...data}));
445
+ },
446
+ config(){
447
+ return template(fs.readFileSync(`${__dirname}/../templates/elasticbeanstalk/.elasticbeanstalk/config.yml`, {encoding: 'utf8'}))(process.env);
448
+ }
449
+ };
@@ -1,6 +1,6 @@
1
1
  const { CloudFrontClient, CreateDistributionWithTagsCommand, CreateCloudFrontOriginAccessIdentityCommand, DeleteDistributionCommand , DeleteCloudFrontOriginAccessIdentityCommand, GetDistributionCommand, UpdateDistributionCommand, GetCloudFrontOriginAccessIdentityCommand, CreateFunctionCommand, GetFunctionCommand, UpdateFunctionCommand, PublishFunctionCommand, DeleteFunctionCommand, DescribeFunctionCommand } = require("@aws-sdk/client-cloudfront");
2
2
  const fs = require('fs');
3
- const { Spinner } = require('../../libs/utilities');
3
+ const { Spinner, poll } = require('../../libs/utilities');
4
4
  const { createClient } = require('./misc.js');
5
5
 
6
6
  module.exports.createCloudFrontDistribution = async (name, account, tags = [], FunctionARN = null, region = 'us-east-1') => {
@@ -136,19 +136,12 @@ module.exports.removeCloudFrontDistribution = async (Id, account) => {
136
136
  module.exports.waitForCloudFrontDistribution = async (Id, account) => {
137
137
  const client = createClient(CloudFrontClient, account);
138
138
 
139
- let status;
140
-
141
- do{
142
- await new Promise((resolve) => setTimeout(() => resolve(), 5000));
143
-
144
- await Spinner.prototype.ping();
145
-
146
- let check = await client.send(
139
+ await poll(
140
+ async () => await client.send(
147
141
  new GetDistributionCommand({ Id })
148
- );
149
-
150
- status = check.Distribution.Status;
151
- } while(status !== 'Deployed')
142
+ ),
143
+ res => res.Distribution.Status !== "Deployed"
144
+ );
152
145
  }
153
146
 
154
147
  module.exports.createCloudFrontFunction = async (name, account, fn, config) => {
@@ -0,0 +1,17 @@
1
+ const { EC2Client, DescribeKeyPairsCommand } = require("@aws-sdk/client-ec2");
2
+ const { Spinner } = require('../../libs/utilities');
3
+ const { createClient } = require('./misc.js');
4
+
5
+ module.exports.getKeyPair = async (KeyName, account) => {
6
+ const client = createClient(EC2Client, account);
7
+
8
+ let res = await Spinner.prototype.simple(`Retrieving the KeyPair ${KeyName}`, () => {
9
+ return client.send(
10
+ new DescribeKeyPairsCommand({ KeyNames: [
11
+ KeyName
12
+ ] })
13
+ );
14
+ });
15
+
16
+ return res;
17
+ };
@@ -0,0 +1,96 @@
1
+ const fs = require("fs-extra");
2
+ const glob = require("glob");
3
+ const { ElasticBeanstalkClient, CreateApplicationCommand, DeleteApplicationCommand, CreateEnvironmentCommand, TerminateEnvironmentCommand, DescribeEnvironmentsCommand, ListAvailableSolutionStacksCommand } = require("@aws-sdk/client-elastic-beanstalk");
4
+ const { Spinner, poll } = require('../../libs/utilities');
5
+ const { eb } = require('../../libs/vars');
6
+ const { createClient } = require('./misc.js');
7
+
8
+ module.exports.createElasticBeanstalkApplication = async (name, account) => {
9
+ const client = createClient(ElasticBeanstalkClient, account);
10
+
11
+ let res = await Spinner.prototype.simple(`Creating elasticbeanstalk application ${name}`, () => {
12
+ return client.send(
13
+ new CreateApplicationCommand({ApplicationName: name})
14
+ );
15
+ });
16
+
17
+ return res;
18
+ }
19
+
20
+ module.exports.createElasticBeanstalkEnvironment = async (name, account, ApplicationName, OptionSettings, CNAMEPrefix, tags = []) => {
21
+ const client = createClient(ElasticBeanstalkClient, account);
22
+
23
+ const solutions = await Spinner.prototype.simple(`Retrieving available solution stacks`, () => {
24
+ return client.send(
25
+ new ListAvailableSolutionStacksCommand()
26
+ );
27
+ });
28
+
29
+ await Spinner.prototype.simple(`Creating elasticbeanstalk environment ${name}`, () => {
30
+ return client.send(
31
+ new CreateEnvironmentCommand({
32
+ ApplicationName,
33
+ EnvironmentName: name,
34
+ SolutionStackName: solutions.SolutionStacks.filter(d => d.includes('PHP 8.1') && d.includes('Amazon Linux 2 '))[0],
35
+ OptionSettings,
36
+ CNAMEPrefix,
37
+ Tags: [{Key: 'client', Value: account}].concat(tags)
38
+ })
39
+ );
40
+ });
41
+
42
+ const res = await Spinner.prototype.simple(`Waiting for elasticbeanstalk environment to deploy`, () => {
43
+ return module.exports.waitForElasticBeanstalkEnvironment(name, account, "Ready", "Terminated");
44
+ });
45
+
46
+ return res;
47
+ }
48
+
49
+ module.exports.waitForElasticBeanstalkEnvironment = async (name, account, waitFor = "Ready", failIf) => {
50
+ const client = createClient(ElasticBeanstalkClient, account);
51
+
52
+ const res = await poll(
53
+ async () => (await client.send(
54
+ new DescribeEnvironmentsCommand({ EnvironmentNames: [name] })
55
+ )).Environments[0],
56
+ ({ Status }) => Status !== waitFor,
57
+ ({ Status }) => Status === failIf
58
+ );
59
+
60
+ return res;
61
+ }
62
+
63
+ module.exports.removeElasticBeanstalkApplication = async (name, account) => {
64
+ const client = createClient(ElasticBeanstalkClient, account);
65
+
66
+ await Spinner.prototype.simple(`Removing elasticbeanstalk application ${name}`, () => {
67
+ return client.send(
68
+ new DeleteApplicationCommand({ ApplicationName: name })
69
+ );
70
+ });
71
+ }
72
+
73
+ module.exports.removeElasticBeanstalkEnvironment = async (name, account) => {
74
+ const client = createClient(ElasticBeanstalkClient, account);
75
+
76
+ await Spinner.prototype.simple(`Removing elasticbeanstalk environment ${name}`, () => {
77
+ return client.send(
78
+ new TerminateEnvironmentCommand({ EnvironmentName: name })
79
+ );
80
+ });
81
+
82
+ await Spinner.prototype.simple(`Waiting for elasticbeanstalk environment to terminate`, () => {
83
+ return module.exports.waitForElasticBeanstalkEnvironment(name, account, "Terminated");
84
+ });
85
+ }
86
+
87
+ module.exports.copyElasticBeanstalkConfigs = async (configurations) => {
88
+ const templates = `${__dirname}/../../templates/elasticbeanstalk`;
89
+
90
+ configurations.forEach(globbed => {
91
+ glob.sync(globbed, {cwd: `${templates}`})
92
+ .forEach(config => fs.copySync(`${templates}/${config}`, config));
93
+ });
94
+
95
+ fs.outputFileSync(`.elasticbeanstalk/config.yml`, eb.config());
96
+ }
@@ -1,8 +1,8 @@
1
- const { IAMClient, CreateUserCommand, GetUserCommand, DeleteUserCommand, AttachUserPolicyCommand, ListAttachedUserPoliciesCommand, DetachUserPolicyCommand, CreateAccessKeyCommand, DeleteAccessKeyCommand, ListAccessKeysCommand } = require("@aws-sdk/client-iam");
1
+ const { IAMClient, CreateUserCommand, GetUserCommand, DeleteUserCommand, AttachUserPolicyCommand, ListAttachedUserPoliciesCommand, DetachUserPolicyCommand, CreateAccessKeyCommand, DeleteAccessKeyCommand, ListAccessKeysCommand, GetRoleCommand, CreateRoleCommand, AttachRolePolicyCommand, CreateInstanceProfileCommand, AddRoleToInstanceProfileCommand, PutRolePolicyCommand } = require("@aws-sdk/client-iam");
2
2
  const { Spinner } = require('../../libs/utilities');
3
3
  const { createClient } = require('./misc.js');
4
4
 
5
- module.exports.createIAMUser = async (UserName, account) => {
5
+ module.exports.createIAMUser = async (UserName, account, tags = []) => {
6
6
  const client = createClient(IAMClient, account);
7
7
 
8
8
  let res;
@@ -10,7 +10,7 @@ module.exports.createIAMUser = async (UserName, account) => {
10
10
  try{
11
11
  res = await Spinner.prototype.simple(`Creating IAM user ${UserName}`, () => {
12
12
  return client.send(
13
- new CreateUserCommand({ UserName })
13
+ new CreateUserCommand({ UserName, Tags: [{Key: 'client', Value: account}].concat(tags) })
14
14
  );
15
15
  });
16
16
  } catch(e){
@@ -167,4 +167,123 @@ module.exports.createAccessKeySafe = async (UserName, account) => {
167
167
  }
168
168
 
169
169
  return res;
170
- };
170
+ };
171
+
172
+ module.exports.getRole = async (RoleName, account) => {
173
+ const client = createClient(IAMClient, account);
174
+
175
+ let res = await Spinner.prototype.simple(`Retrieving the role ${RoleName}`, () => {
176
+ return client.send(
177
+ new GetRoleCommand({ RoleName })
178
+ );
179
+ });
180
+
181
+ return res;
182
+ };
183
+
184
+ module.exports.createRole = async (RoleName, account, AssumeRolePolicyDocument) => {
185
+ const client = createClient(IAMClient, account);
186
+
187
+ let res = await Spinner.prototype.simple(`Creating the role ${RoleName}`, () => {
188
+ return client.send(
189
+ new CreateRoleCommand({ RoleName, AssumeRolePolicyDocument })
190
+ );
191
+ });
192
+
193
+ return res;
194
+ };
195
+
196
+ module.exports.createInstanceProfile = async (InstanceProfileName, account) => {
197
+ const client = createClient(IAMClient, account);
198
+
199
+ let res = await Spinner.prototype.simple(`Creating the instance profile ${InstanceProfileName}`, () => {
200
+ return client.send(
201
+ new CreateInstanceProfileCommand({ InstanceProfileName })
202
+ );
203
+ });
204
+
205
+ return res;
206
+ };
207
+
208
+ module.exports.attachRoleToInstanceProfile = async (RoleName, InstanceProfileName, account) => {
209
+ const client = createClient(IAMClient, account);
210
+
211
+ let res = await Spinner.prototype.simple(`Attaching role ${RoleName} to the instance profile ${InstanceProfileName}`, () => {
212
+ return client.send(
213
+ new AddRoleToInstanceProfileCommand({ RoleName, InstanceProfileName })
214
+ );
215
+ });
216
+
217
+ return res;
218
+ };
219
+
220
+ module.exports.attachRolePolicy = async (RoleName, account, PolicyArn) => {
221
+ const client = createClient(IAMClient, account);
222
+
223
+ let res = await Spinner.prototype.simple(`Attaching Role policy ${PolicyArn}`, () => {
224
+ return client.send(
225
+ new AttachRolePolicyCommand({ RoleName, PolicyArn })
226
+ );
227
+ });
228
+
229
+ return res;
230
+ };
231
+
232
+ module.exports.attachInlineRolePolicy = async (RoleName, account, PolicyName, PolicyDocument) => {
233
+ const client = createClient(IAMClient, account);
234
+
235
+ let res = await Spinner.prototype.simple(`Attaching Inline Role policy ${PolicyName}`, () => {
236
+ return client.send(
237
+ new PutRolePolicyCommand({ RoleName, PolicyName, PolicyDocument })
238
+ );
239
+ });
240
+
241
+ return res;
242
+ };
243
+
244
+ module.exports.ensureEBInstanceProfileExists = async (account) => {
245
+ const role = "aws-elasticbeanstalk-ec2-role";
246
+
247
+ try {
248
+ await module.exports.getRole(role, account);
249
+ } catch (e) {
250
+ await module.exports.createRole(role, account, JSON.stringify({
251
+ "Version": "2012-10-17",
252
+ "Statement": [
253
+ {
254
+ "Effect": "Allow",
255
+ "Action": [
256
+ "sts:AssumeRole"
257
+ ],
258
+ "Principal": {
259
+ "Service": [
260
+ "ec2.amazonaws.com"
261
+ ]
262
+ }
263
+ }
264
+ ]
265
+ }));
266
+
267
+ await module.exports.createInstanceProfile(role, account);
268
+ await module.exports.attachRoleToInstanceProfile(role, role, account);
269
+ }
270
+
271
+ await module.exports.attachRolePolicy(role, account, "arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier");
272
+ await module.exports.attachRolePolicy(role, account, "arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier");
273
+ await module.exports.attachRolePolicy(role, account, "arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker");
274
+ await module.exports.attachInlineRolePolicy(role, account, "lab-env-elasticbeanstalk-describe-env", JSON.stringify({
275
+ "Version": "2012-10-17",
276
+ "Statement": [
277
+ {
278
+ "Sid": "VisualEditor0",
279
+ "Effect": "Allow",
280
+ "Action": [
281
+ "ec2:DescribeTags",
282
+ "autoscaling:DescribeAutoScalingGroups",
283
+ "elasticbeanstalk:DescribeEvents"
284
+ ],
285
+ "Resource": "*"
286
+ }
287
+ ]
288
+ }));
289
+ }