cloudmason 0.0.1 → 1.0.2

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 (46) hide show
  1. package/.github/workflows/CODEOWNERS +1 -0
  2. package/.github/workflows/main.yml +27 -27
  3. package/README.md +373 -25
  4. package/build.js +20 -20
  5. package/commands/delete.js +67 -28
  6. package/commands/helpers/cf.js +181 -117
  7. package/commands/helpers/common.js +82 -0
  8. package/commands/helpers/ec2.js +154 -40
  9. package/commands/helpers/params.js +231 -178
  10. package/commands/helpers/s3.js +186 -67
  11. package/commands/helpers/stacks/asg.yaml +420 -224
  12. package/commands/helpers/stacks/infra.yaml +102 -106
  13. package/commands/helpers/stacks.js +25 -25
  14. package/commands/index.html +22 -0
  15. package/commands/init_org.js +54 -61
  16. package/commands/inspect.js +40 -0
  17. package/commands/launch_app.js +80 -57
  18. package/commands/list_apps.js +21 -21
  19. package/commands/new_app.js +44 -50
  20. package/commands/new_instance.js +133 -186
  21. package/commands/reset_stack.js +27 -27
  22. package/commands/starter.js +21 -0
  23. package/commands/starters/asg_node/index.js +62 -0
  24. package/commands/starters/asg_node/mason.txt +1 -0
  25. package/commands/starters/asg_node/modules/appConfig.js +131 -0
  26. package/commands/starters/asg_node/package-lock.json +5877 -0
  27. package/commands/starters/asg_node/package.json +23 -0
  28. package/commands/starters/asg_node/public/css/favicon-16x16.png +0 -0
  29. package/commands/starters/asg_node/public/css/fonts/Lato-Bold.ttf +0 -0
  30. package/commands/starters/asg_node/public/css/fonts/Lato-Regular.ttf +0 -0
  31. package/commands/starters/asg_node/public/css/fonts/Montserrat-Var.ttf +0 -0
  32. package/commands/starters/asg_node/public/css/fonts/OpenSans.ttf +0 -0
  33. package/commands/starters/asg_node/public/css/fonts/bpmn.woff2 +0 -0
  34. package/commands/starters/asg_node/public/css/fonts/fonts.css +17 -0
  35. package/commands/starters/asg_node/public/css/index.css +9 -0
  36. package/commands/starters/asg_node/public/index.html +15 -0
  37. package/commands/starters/asg_node/public/js/index.js +5 -0
  38. package/commands/starters/asg_node/start.sh +4 -0
  39. package/commands/update_app.js +235 -272
  40. package/commands/update_stack.js +27 -0
  41. package/commands/utils.js +32 -32
  42. package/main.js +262 -220
  43. package/package.json +1 -28
  44. package/test.bat +16 -9
  45. package/commands/delete_app.js +0 -28
  46. package/commands/helpers/stacks/asg_draft.json +0 -321
@@ -1,106 +1,102 @@
1
- AWSTemplateFormatVersion: '2010-09-09'
2
- Description: Org Cloudformation Template
3
-
4
- Parameters:
5
- orgName:
6
- Type: String
7
- Description: Unique name of organization
8
- orgDomain:
9
- Type: String
10
- Description: Organization domain name
11
- VpcId:
12
- Type: String
13
- Description: Org VPC
14
-
15
-
16
- Resources:
17
- # S3 Bucket
18
- InfraBucket:
19
- Type: AWS::S3::Bucket
20
- Properties:
21
- BucketName: !Sub 'infra.${orgDomain}'
22
- VersioningConfiguration:
23
- Status: Enabled
24
- # IAM Policies for Ec2 Build Access
25
- InfraBuildRole:
26
- Type: 'AWS::IAM::Role'
27
- Properties:
28
- AssumeRolePolicyDocument:
29
- Version: "2012-10-17"
30
- Statement:
31
- - Effect: Allow
32
- Principal:
33
- Service:
34
- - ec2.amazonaws.com
35
- Action:
36
- - 'sts:AssumeRole'
37
- Path: /infra/
38
- Policies:
39
- - PolicyName: root
40
- PolicyDocument:
41
- Version: "2012-10-17"
42
- Statement:
43
- - Effect: Allow
44
- Action:
45
- - s3:GetObject
46
- - s3:ListBucket
47
- Resource:
48
- - !Sub arn:aws:s3:::${InfraBucket}
49
- - !Sub arn:aws:s3:::${InfraBucket}/*
50
- InfraInstanceProfile:
51
- Type: 'AWS::IAM::InstanceProfile'
52
- Properties:
53
- Path: /infra/
54
- Roles:
55
- - !Ref InfraBuildRole
56
- # Ec2 security group
57
- BuildSecGroup:
58
- Type: 'AWS::EC2::SecurityGroup'
59
- Properties:
60
- GroupDescription: Security group for build AMI
61
- SecurityGroupEgress:
62
- - IpProtocol: '-1'
63
- CidrIp: '0.0.0.0/0'
64
- VpcId: !Ref VpcId
65
- # Bucket Policy
66
- InfraBucketPolicy:
67
- Type: AWS::S3::BucketPolicy
68
- Properties:
69
- Bucket: !Ref InfraBucket
70
- PolicyDocument:
71
- Version: '2012-10-17'
72
- Statement:
73
- - Effect: Allow
74
- Principal:
75
- AWS:
76
- - !GetAtt InfraBuildRole.Arn
77
- Action:
78
- - 's3:GetObject'
79
- Resource:
80
- - !Sub arn:aws:s3:::${InfraBucket}
81
- - !Sub arn:aws:s3:::${InfraBucket}/*
82
- # Org Params
83
- ParamOrgInfo:
84
- Type: 'AWS::SSM::Parameter'
85
- Properties:
86
- Name: '/infra/orgName'
87
- Type: 'String'
88
- Value: !Ref orgName
89
- ParamOrgDomain:
90
- Type: 'AWS::SSM::Parameter'
91
- Properties:
92
- Name: '/infra/orgDomain'
93
- Type: 'String'
94
- Value: !Ref orgDomain
95
- ParamInstanceProfile:
96
- Type: 'AWS::SSM::Parameter'
97
- Properties:
98
- Name: '/infra/buildInstanceProfile'
99
- Type: 'String'
100
- Value: !GetAtt InfraInstanceProfile.Arn
101
- ParamIAM:
102
- Type: 'AWS::SSM::Parameter'
103
- Properties:
104
- Name: '/infra/buildSecGroup'
105
- Type: 'String'
106
- Value: !GetAtt buildSecGroup.GroupId
1
+ AWSTemplateFormatVersion: '2010-09-09'
2
+ Description: Org Cloudformation Template
3
+
4
+ Parameters:
5
+ orgName:
6
+ Type: String
7
+ Description: Unique name of organization
8
+ VpcId:
9
+ Type: String
10
+ Description: Org VPC
11
+
12
+
13
+ Resources:
14
+ # S3 Bucket
15
+ InfraBucket:
16
+ Type: AWS::S3::Bucket
17
+ Properties:
18
+ VersioningConfiguration:
19
+ Status: Enabled
20
+ # IAM Policies for Ec2 Build Access
21
+ InfraBuildRole:
22
+ Type: 'AWS::IAM::Role'
23
+ Properties:
24
+ AssumeRolePolicyDocument:
25
+ Version: "2012-10-17"
26
+ Statement:
27
+ - Effect: Allow
28
+ Principal:
29
+ Service:
30
+ - ec2.amazonaws.com
31
+ Action:
32
+ - 'sts:AssumeRole'
33
+ Path: /infra/
34
+ Policies:
35
+ - PolicyName: root
36
+ PolicyDocument:
37
+ Version: "2012-10-17"
38
+ Statement:
39
+ - Effect: Allow
40
+ Action:
41
+ - s3:GetObject
42
+ - s3:ListBucket
43
+ Resource:
44
+ - !Sub arn:aws:s3:::${InfraBucket}
45
+ - !Sub arn:aws:s3:::${InfraBucket}/*
46
+ InfraInstanceProfile:
47
+ Type: 'AWS::IAM::InstanceProfile'
48
+ Properties:
49
+ Path: /infra/
50
+ Roles:
51
+ - !Ref InfraBuildRole
52
+ # Ec2 security group
53
+ BuildSecGroup:
54
+ Type: 'AWS::EC2::SecurityGroup'
55
+ Properties:
56
+ GroupDescription: Security group for build AMI
57
+ SecurityGroupEgress:
58
+ - IpProtocol: '-1'
59
+ CidrIp: '0.0.0.0/0'
60
+ VpcId: !Ref VpcId
61
+ # Bucket Policy
62
+ InfraBucketPolicy:
63
+ Type: AWS::S3::BucketPolicy
64
+ Properties:
65
+ Bucket: !Ref InfraBucket
66
+ PolicyDocument:
67
+ Version: '2012-10-17'
68
+ Statement:
69
+ - Effect: Allow
70
+ Principal:
71
+ AWS:
72
+ - !GetAtt InfraBuildRole.Arn
73
+ Action:
74
+ - 's3:GetObject'
75
+ Resource:
76
+ - !Sub arn:aws:s3:::${InfraBucket}
77
+ - !Sub arn:aws:s3:::${InfraBucket}/*
78
+ # Org Params
79
+ ParamOrgInfo:
80
+ Type: 'AWS::SSM::Parameter'
81
+ Properties:
82
+ Name: '/infra/orgName'
83
+ Type: 'String'
84
+ Value: !Ref orgName
85
+ ParamInstanceProfile:
86
+ Type: 'AWS::SSM::Parameter'
87
+ Properties:
88
+ Name: '/infra/buildInstanceProfile'
89
+ Type: 'String'
90
+ Value: !GetAtt InfraInstanceProfile.Arn
91
+ ParamIAM:
92
+ Type: 'AWS::SSM::Parameter'
93
+ Properties:
94
+ Name: '/infra/buildSecGroup'
95
+ Type: 'String'
96
+ Value: !GetAtt BuildSecGroup.GroupId
97
+ ParamBucket:
98
+ Type: 'AWS::SSM::Parameter'
99
+ Properties:
100
+ Name: '/infra/infraBucket'
101
+ Type: 'String'
102
+ Value: !Ref InfraBucket
@@ -1,26 +1,26 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
-
4
- const Stacks = {};
5
-
6
- exports.get = function(stackType,params){
7
- const stackPath = path.resolve(__dirname, 'stacks', `${stackType}.yaml`);
8
-
9
- if (!fs.existsSync(stackPath)){ throw new Error('Invalid stack ' + stackType); }
10
-
11
- const stackText = fs.readFileSync(stackPath, 'utf-8');
12
- return Stacks[stackType](stackText,params)
13
- }
14
-
15
- Stacks.asg = function(stackText,params){
16
- let bootScript = `#!/bin/bash -xe\ncd /home/ec2-user/app\n`;
17
- if (params.lang == 'py'){
18
- bootScript += 'py start .'
19
- } else {
20
- bootScript += `npm run start .`
21
- }
22
-
23
- const b64Script = Buffer.from(bootScript, 'utf8').toString('base64');
24
- stackText = stackText.replace(/{{user_data}}/, b64Script);
25
- return stackText;
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ const Stacks = {};
5
+
6
+ exports.get = function(stackType,params){
7
+ const stackPath = path.resolve(__dirname, 'stacks', `${stackType}.yaml`);
8
+
9
+ if (!fs.existsSync(stackPath)){ throw new Error('Invalid stack ' + stackType); }
10
+
11
+ const stackText = fs.readFileSync(stackPath, 'utf-8');
12
+ return Stacks[stackType](stackText,params)
13
+ }
14
+
15
+ Stacks.asg = function(stackText,params){
16
+ let bootScript = `#!/bin/bash -xe\ncd /home/ec2-user/app\n`;
17
+ if (params.lang == 'py'){
18
+ bootScript += 'py start .'
19
+ } else {
20
+ bootScript += `npm run start .`
21
+ }
22
+
23
+ const b64Script = Buffer.from(bootScript, 'utf8').toString('base64');
24
+ stackText = stackText.replace(/{{user_data}}/, b64Script);
25
+ return stackText;
26
26
  }
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>{org}Theorem</title>
7
+ <link rel="icon" type="image/png" href="./css/favicon-16x16.png">
8
+ <link rel="stylesheet" build="fonts" href="./css/fonts/fonts.css">
9
+ <link rel="stylesheet" build="index.css" href="./css/base.css">
10
+ <link rel="stylesheet" build="index.css" href="./css/index.css">
11
+ <link rel="stylesheet" build="inline" href="./css/grids.css">
12
+ <script build="elmnts.js" src="./js/elmnts/0_base.js"></script>
13
+ <script build="main.js" src="./js/components/menubar.js"></script>
14
+ <script build="main.js" src="./js/main.js" async defer></script>
15
+ <script build="inline" src="./js/config.js"></script>
16
+ <script build="inline" src="./js/login.js"></script>
17
+ </head>
18
+ <body>
19
+ <menu-bar></menu-bar>
20
+ <div class="hello-world">Hello World6</div>
21
+ </body>
22
+ </html>
@@ -1,61 +1,54 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { S3Client,HeadBucketCommand } = require("@aws-sdk/client-s3");
4
- const { EC2Client, DescribeVpcsCommand } = require("@aws-sdk/client-ec2");
5
-
6
- const CF = require('./helpers/cf');
7
-
8
-
9
- exports.main = async function(args){
10
- console.log(`Setting up ${args.name}@ ${args.domain} in ${args.region}`)
11
-
12
- // Check if bucket exists
13
- const isBucket = await bucketExists(`infra.${args.domain}`);
14
- if (isBucket.name){
15
- console.log('ERR: Bucket infra.${args.domain} already exists in ${existingBucket.region}')
16
- console.log('Org already set up or rollback still in progress')
17
- throw {message: 'Org exists', at: 'init_org check for existing org'}
18
- }
19
-
20
- // Get VPC ID
21
- const VpcId = await getDefaultVPC(args.region);
22
-
23
- // Deploy Stack
24
- const success = await CF.deployOrgStack('infra', 'infra',args.region, {orgName: args.name, orgDomain: args.domain, VpcId: VpcId}, {purpose: 'infra'})
25
- if (success === false){
26
- console.log('ERR: Org already exists. Only one org permitted per account');
27
- throw new Error('Org already exists')
28
- }
29
-
30
- // Set org.txt
31
- const orgPath = path.resolve(__dirname,'..','org.txt');
32
- const orgData = `${args.name},${args.region},infra.${args.domain}`;
33
- fs.writeFileSync(orgPath,orgData,'utf-8')
34
- console.log('Set up org:',orgData)
35
- return true;
36
- }
37
-
38
-
39
- /////////////////////////////////////////
40
- ////////////// FUNCS ////////////////////
41
- ////////////////////////////////////////
42
-
43
- async function bucketExists(bucketName,region){
44
- const client = new S3Client({region});
45
- try {
46
- await client.send(new HeadBucketCommand({ Bucket: bucketName }));
47
- return true;
48
- } catch (e){
49
- return false;
50
- }
51
- }
52
-
53
- async function getDefaultVPC(region){
54
- const ec2Client = new EC2Client({ region });
55
- const response = await ec2Client.send(new DescribeVpcsCommand({ Filters: [{ Name: "isDefault", Values: ["true"] }] }));
56
- return response.Vpcs[0].VpcId;
57
- }
58
-
59
-
60
-
61
-
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { S3Client,HeadBucketCommand } = require("@aws-sdk/client-s3");
4
+ const { EC2Client, DescribeVpcsCommand } = require("@aws-sdk/client-ec2");
5
+
6
+ const CF = require('./helpers/cf');
7
+
8
+
9
+ exports.main = async function(args){
10
+ console.log(`Setting up ${args.name}@ in ${args.region}`)
11
+
12
+ // Get VPC ID
13
+ const VpcId = await getDefaultVPC(args.region);
14
+ console.log(`Default VPC: ${VpcId}`);
15
+
16
+ // Deploy Stack
17
+ const success = await CF.deployOrgStack(args.region, {orgName: args.name, VpcId: VpcId})
18
+ if (success === false){
19
+ console.log('ERR: Org already exists. Only one org permitted per account');
20
+ throw new Error('Org already exists')
21
+ }
22
+
23
+ // Set org.txt
24
+ const orgPath = path.resolve(__dirname,'..','org.txt');
25
+ const orgData = `${args.name},${args.region}`;
26
+ fs.writeFileSync(orgPath,orgData,'utf-8')
27
+ console.log('Set up org:',orgData)
28
+ return true;
29
+ }
30
+
31
+
32
+ /////////////////////////////////////////
33
+ ////////////// FUNCS ////////////////////
34
+ ////////////////////////////////////////
35
+
36
+ async function bucketExists(bucketName,region){
37
+ const client = new S3Client({region});
38
+ try {
39
+ await client.send(new HeadBucketCommand({ Bucket: bucketName }));
40
+ return true;
41
+ } catch (e){
42
+ return false;
43
+ }
44
+ }
45
+
46
+ async function getDefaultVPC(region){
47
+ const ec2Client = new EC2Client({ region });
48
+ const response = await ec2Client.send(new DescribeVpcsCommand({ Filters: [{ Name: "isDefault", Values: ["true"] }] }));
49
+ return response.Vpcs[0].VpcId;
50
+ }
51
+
52
+
53
+
54
+
@@ -0,0 +1,40 @@
1
+ const Params = require('./helpers/params');
2
+ const EC2 = require('./helpers/ec2');
3
+ const CF = require('./helpers/cf');
4
+ const S3 = require('./helpers/s3');
5
+ const Common = require('./helpers/common');
6
+
7
+ exports.main = async function(args){
8
+ const logType = args.build === null ? 'build' : args.boot === null ? 'boot' : 'run';
9
+ const getLatest = args.boot === null ? false : true;
10
+
11
+ console.log(`Inspecting ${args.app} instance ${args.domain} ${logType} logs`);
12
+ // Get App
13
+ const app = await Params.getApp(args.app);
14
+ if (!app){ console.log('Err: No app named ' + args.app); return false;}
15
+ const instance = app.instances.find(ins=>{ return ins.domain.toLowerCase() == args.domain.toLowerCase() });
16
+ if (!instance){ console.log(`No instance of ${args.app} named ${args.domain}`); throw new Error('Invalid Instance')}
17
+
18
+ // Check Stack
19
+ const stackStatus = await CF.stackStatus(instance.stackName, instance.region);
20
+ console.log("STACK STATUS:", stackStatus.status);
21
+ if (stackStatus.ok === null){
22
+ return
23
+ } else if (stackStatus.ok === false){
24
+ console.log("\tSTACK FAILURE REASON:", stackStatus.failureReason);
25
+ return
26
+ }
27
+
28
+
29
+ const asgId = await CF.getStackResource('asg',instance.stackName,instance.region);
30
+ console.log("Auto Scaling Group ID:", asgId);
31
+ const consoleOutputs = await EC2.getConsoleOutput(asgId,instance.region,getLatest);
32
+ console.log(`================= ${logType.toUpperCase()} LOGS =================`);
33
+ consoleOutputs.forEach(output => {
34
+ console.log("---- EC2 ID:", output.instanceId, "----");
35
+ console.log( output.output );
36
+ console.log('======================= END =========================');
37
+ });
38
+ return
39
+ }
40
+
@@ -1,57 +1,80 @@
1
- const Params = require('./helpers/params');
2
- const EC2 = require('./helpers/ec2');
3
- const CF = require('./helpers/cf')
4
-
5
- exports.main = async function(args){
6
- const app = await Params.getApp(args.app);
7
- if (!app){ console.log('No app named ' + args.app); throw new Error('Invalid App Name')}
8
-
9
- const targetInstance = app.instances.find(ins=>{ return ins.name.toLowerCase() == args.i.toLowerCase() });
10
- const targetVersion = app.versions[args.v];
11
-
12
- if (!targetInstance){ console.log(`No instance of ${args.app} named ${args.i}`); throw new Error('Invalid Instance')}
13
- if (!targetVersion){ console.log(`No version ${args.v} of ${args.app}`); throw new Error('Invalid Version')}
14
-
15
- // --- I GET AMI ---
16
- // Get Instance Region
17
- const targetRegion = targetInstance.region;
18
- // Get Latest AMI Build
19
- const latestBuild = targetVersion.baseAMI_Name;
20
- // Check for AMI Build in Instance Region
21
- let targetAMI = await EC2.findAMI(latestBuild,targetRegion);
22
- // Copy AMI from Org Region to Instance Region
23
- if (!targetAMI){
24
- console.log(`Copying ${latestBuild} from ${process.env.orgRegion} to ${targetRegion}`);
25
- targetAMI = await EC2.copyAMI(latestBuild,targetVersion.baseAMI_Id,process.env.orgRegion,targetRegion)
26
- } else {
27
- console.log('Found existing image ' + targetAMI)
28
- }
29
- // Update Instance CF Params to Instance Region AMI ID
30
- targetInstance.cfParams.AmiId = targetAMI;
31
- await Params.editInstance(args.app,args.i,latestBuild,targetInstance.cfParams);
32
- // console.log(targetInstance.cfParams);
33
-
34
- // --- II DEPLOY CF STACK ---
35
- // Get Stack URL
36
- // https://s3.us-east-2.amazonaws.com/infra.orgtheorem.xyz/apps/ssdemo/1/stack.json
37
- const stackName = (`${args.app}-${args.i}`).toLowerCase();
38
- const stackURL = `https://s3.${process.env.orgRegion}.amazonaws.com/${process.env.orgBucket}/apps/${args.app.toLowerCase()}/${args.v}/stack.yaml`
39
-
40
- // Check whether stack exists
41
- const stackExists = await CF.stackExists(stackName,targetRegion);
42
- // console.log(stackName,stackURL,targetInstance.cfParams,targetRegion);
43
-
44
- // Update Stack
45
- let stackId;
46
- if (stackExists){
47
- console.log(`Updating stack ${stackName} in ${targetRegion}`);
48
- stackId = await CF.updateStack(stackName,stackURL,targetInstance.cfParams,targetRegion);
49
- // Deploy Stack
50
- } else {
51
- console.log(`Deploying stack ${stackName} in ${targetRegion}`);
52
- const tags = {purpose: 'app', app: args.app, instance: args.i};
53
- stackId = await CF.deployS3Stack(stackName,stackURL,targetInstance.cfParams,tags,targetRegion)
54
- }
55
- console.log('Deployed stack ' + stackId)
56
- return true;
57
- }
1
+ const Params = require('./helpers/params');
2
+ const EC2 = require('./helpers/ec2');
3
+ const CF = require('./helpers/cf');
4
+ const Common = require('./helpers/common');
5
+
6
+ exports.main = async function(args){
7
+ const app = await Params.getApp(args.app);
8
+ if (!app){ console.log('No app named ' + args.app); throw new Error('Invalid App Name')}
9
+
10
+ const targetInstance = app.instances.find(ins=>{ return ins.domain.toLowerCase() == args.domain.toLowerCase() });
11
+ const targetVersion = app.versions[args.v];
12
+
13
+ if (!targetInstance){ console.log(`No instance of ${args.app} named ${args.domain}`); throw new Error('Invalid Instance')}
14
+ if (!targetVersion){ console.log(`No version ${args.v} of ${args.app}`); throw new Error('Invalid Version')}
15
+
16
+ console.log(`Launching ${args.app} ${args.v}.${targetVersion.currentBuild} to ${targetInstance.domain} in ${targetInstance.region}`)
17
+
18
+ // --- I GET AMI ---
19
+ // Get Instance Region
20
+ const targetRegion = targetInstance.region;
21
+ // Get Latest AMI Build
22
+ const latestBuild = targetVersion.baseAMI_Name;
23
+ // Check for AMI Build in Instance Region
24
+ let targetAMI = await EC2.findAMI(latestBuild,targetRegion);
25
+ // Copy AMI from Org Region to Instance Region
26
+ if (!targetAMI){
27
+ console.log(`Copying ${latestBuild} from ${process.env.orgRegion} to ${targetRegion}`);
28
+ targetAMI = await EC2.copyAMI(latestBuild,targetVersion.baseAMI_Id,process.env.orgRegion,targetRegion)
29
+ } else {
30
+ console.log('Found existing image ' + targetAMI)
31
+ }
32
+
33
+ // I.I WAIT FOR AMI TO BE AVAILABLE
34
+ console.log(`Waiting for AMI ${targetAMI} to be available`);
35
+ let isAvailable = false;
36
+ for (let i = 0; i < 15; i++){
37
+ const status = await EC2.checkAMIStatus(targetAMI,targetRegion);
38
+ if (status === true){
39
+ console.log(`AMI ${targetAMI} available after ${i*30}s`);
40
+ isAvailable = true;
41
+ break;
42
+ }
43
+ console.log(`\tAMI Status Check ${i} @${i*30}s : Not Available`);
44
+ await Common.sleep(30);
45
+ }
46
+ if (!isAvailable){ throw new Error('AMI not available after 7 minutes. Try again in a few minutes.') }
47
+
48
+ // --- II DEPLOY CF STACK ---
49
+ // Get Stack URL
50
+ const stackName = targetInstance.stackName;
51
+ const stackURL = targetVersion.stackURL;
52
+
53
+ // Update Instance CF Params to Instance Region AMI ID
54
+ targetInstance.cfParams.AmiId = targetAMI;
55
+ targetInstance.cfParams.AppVersion = `${args.v}.${targetVersion.currentBuild}`;
56
+ await Params.updateInstanceV(args.app,args.domain,args.v,targetVersion.currentBuild,targetAMI,targetVersion.baseAMI_Name);
57
+
58
+ // Check whether stack exists
59
+ const stackExists = await CF.stackExists(stackName,targetRegion);
60
+
61
+ // Update Stack
62
+ let stackId;
63
+ if (stackExists){
64
+ const stackStatus = await CF.stackStatus(stackName,targetRegion);
65
+ if (stackStatus.ok !== true){
66
+ console.log(`Stack ${stackName} in ${targetRegion} is ${stackStatus.status}. Wait for completion before relaunching`);
67
+ return false;
68
+ }
69
+ console.log(`Updating stack ${stackName} in ${targetRegion}`);
70
+ stackId = await CF.updateStack(stackName,stackURL,targetInstance.cfParams,targetRegion);
71
+ // Deploy Stack
72
+ } else {
73
+ console.log(`Syncing stack ${stackName} to ${targetRegion}`);
74
+ const tags = {purpose: 'app', app: args.app, instance: args.domain};
75
+ stackId = await CF.deployS3Stack(stackName,stackURL,targetInstance.cfParams,tags,targetRegion)
76
+ }
77
+ // console.log('Deployed stack ' + stackId);
78
+ await Common.prune_amis(args.app,args.v,targetRegion);
79
+ return true;
80
+ }
@@ -1,22 +1,22 @@
1
- const Params = require('./helpers/params');
2
-
3
-
4
- exports.main = async function(){
5
- const apps = await Params.listApps();
6
- for(let i=0; i<apps.length; i++){
7
- const app = apps[i];
8
- console.log(`${app.name} <${app.stack}>`);
9
- console.log('\tVERSIONS')
10
- const spaces = 10;
11
- Object.entries(app.versions).forEach((k)=>{
12
- const s = k[0].length > 5 ? 1 : (5 - k[0].length);
13
- console.log(`\t\t[${k[0]}]${' '.repeat(s)}ami:${k[1].baseAMI_Name} | build: ${k[1].currentBuild} `)
14
- })
15
- console.log('\tINSTANCES')
16
- app.instances.forEach(ins=>{
17
- const s = ins.name.length > 7 ? 1 : (7 - ins.name.length);
18
- console.log(`\t\t[${ins.name}]${' '.repeat(s)}domain:${ins.domain} | region:${ins.region} | version:${ins.version}`)
19
- })
20
- console.log('--------------')
21
- }
1
+ const EC2 = require('./helpers/ec2');
2
+ const Params = require('./helpers/params');
3
+
4
+
5
+ exports.main = async function(){
6
+ const apps = await Params.listApps();
7
+ for(let i=0; i<apps.length; i++){
8
+ const app = apps[i];
9
+ console.log(`${app.name} <${app.stack}>`);
10
+ console.log('\tVERSIONS')
11
+ Object.entries(app.versions).forEach((k)=>{
12
+ const s = k[0].length > 5 ? 1 : (5 - k[0].length);
13
+ console.log(`\t\t[${k[0]}]${' '.repeat(s)}ami:${k[1].baseAMI_Name} | build: ${k[1].currentBuild} | updated: ${new Date(k[1].updated).toLocaleString()} `)
14
+ })
15
+ console.log('\tINSTANCES')
16
+ app.instances.forEach(ins=>{
17
+ const s = ins.domain.length > 20 ? 1 : (20 - ins.domain.length);
18
+ console.log(`\t\t[${ins.domain}]${' '.repeat(s)} version:${ins.version} | region:${ins.region} | ami: ${ins.amiName} | stack: ${ins.stackName} | lastDeploy: ${Date(ins.lastDeploy).toLocaleString()} `)
19
+ })
20
+ console.log('--------------')
21
+ }
22
22
  }