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.
- package/.github/workflows/CODEOWNERS +1 -0
- package/.github/workflows/main.yml +27 -27
- package/README.md +373 -25
- package/build.js +20 -20
- package/commands/delete.js +67 -28
- package/commands/helpers/cf.js +181 -117
- package/commands/helpers/common.js +82 -0
- package/commands/helpers/ec2.js +154 -40
- package/commands/helpers/params.js +231 -178
- package/commands/helpers/s3.js +186 -67
- package/commands/helpers/stacks/asg.yaml +420 -224
- package/commands/helpers/stacks/infra.yaml +102 -106
- package/commands/helpers/stacks.js +25 -25
- package/commands/index.html +22 -0
- package/commands/init_org.js +54 -61
- package/commands/inspect.js +40 -0
- package/commands/launch_app.js +80 -57
- package/commands/list_apps.js +21 -21
- package/commands/new_app.js +44 -50
- package/commands/new_instance.js +133 -186
- package/commands/reset_stack.js +27 -27
- package/commands/starter.js +21 -0
- package/commands/starters/asg_node/index.js +62 -0
- package/commands/starters/asg_node/mason.txt +1 -0
- package/commands/starters/asg_node/modules/appConfig.js +131 -0
- package/commands/starters/asg_node/package-lock.json +5877 -0
- package/commands/starters/asg_node/package.json +23 -0
- package/commands/starters/asg_node/public/css/favicon-16x16.png +0 -0
- package/commands/starters/asg_node/public/css/fonts/Lato-Bold.ttf +0 -0
- package/commands/starters/asg_node/public/css/fonts/Lato-Regular.ttf +0 -0
- package/commands/starters/asg_node/public/css/fonts/Montserrat-Var.ttf +0 -0
- package/commands/starters/asg_node/public/css/fonts/OpenSans.ttf +0 -0
- package/commands/starters/asg_node/public/css/fonts/bpmn.woff2 +0 -0
- package/commands/starters/asg_node/public/css/fonts/fonts.css +17 -0
- package/commands/starters/asg_node/public/css/index.css +9 -0
- package/commands/starters/asg_node/public/index.html +15 -0
- package/commands/starters/asg_node/public/js/index.js +5 -0
- package/commands/starters/asg_node/start.sh +4 -0
- package/commands/update_app.js +235 -272
- package/commands/update_stack.js +27 -0
- package/commands/utils.js +32 -32
- package/main.js +262 -220
- package/package.json +1 -28
- package/test.bat +16 -9
- package/commands/delete_app.js +0 -28
- 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
|
-
|
|
9
|
-
Type: String
|
|
10
|
-
Description:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- s3
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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>
|
package/commands/init_org.js
CHANGED
|
@@ -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}@
|
|
11
|
-
|
|
12
|
-
//
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
+
|
package/commands/launch_app.js
CHANGED
|
@@ -1,57 +1,80 @@
|
|
|
1
|
-
const Params = require('./helpers/params');
|
|
2
|
-
const EC2 = require('./helpers/ec2');
|
|
3
|
-
const CF = require('./helpers/cf')
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (!
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
}
|
package/commands/list_apps.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
console.log(
|
|
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.
|
|
18
|
-
console.log(`\t\t[${ins.
|
|
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
|
}
|