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
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "cloudmason_demo",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "start": "node index.js"
8
+ },
9
+ "author": "",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "2": "^3.0.0",
13
+ "@aws-sdk/client-dynamodb": "^3.478.0",
14
+ "@aws-sdk/client-s3": "^3.476.0",
15
+ "@aws-sdk/client-ssm": "^3.476.0",
16
+ "@aws-sdk/lib-dynamodb": "^3.478.0",
17
+ "aws-jwt-verify": "^4.0.0",
18
+ "express": "^4.18.2",
19
+ "jsonwebtoken": "^9.0.2",
20
+ "jws": "^4.0.0",
21
+ "node-fetch": "^2.7.0"
22
+ }
23
+ }
@@ -0,0 +1,17 @@
1
+ /* Fonts */
2
+ @font-face {
3
+ font-family: 'bpmn';
4
+ font-weight: normal;
5
+ font-style: normal;
6
+ src: url('./bpmn.woff2') format('woff2');
7
+ }
8
+
9
+ @font-face {
10
+ font-family: 'Montserrat';
11
+ src: url('./Montserrat-Var.ttf');
12
+ }
13
+ @font-face {
14
+ font-family: 'OpenSans';
15
+ src: url('./OpenSans.ttf');
16
+ font-weight: 1 1000;
17
+ }
@@ -0,0 +1,9 @@
1
+ .hello-world{
2
+ height: 100%;
3
+ overflow: hidden;
4
+ display: flex;
5
+ justify-content: center;
6
+ align-items: center;
7
+ padding-bottom: 40vh;
8
+ box-sizing: border-box;
9
+ }
@@ -0,0 +1,15 @@
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>CloudMason</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/index.css">
10
+ <script build="inline" src="./js/index.js"></script>
11
+ </head>
12
+ <body>
13
+ <div class="hello-world">Hello World5</div>
14
+ </body>
15
+ </html>
@@ -0,0 +1,5 @@
1
+ async function main(){
2
+ console.log('Main Controller Function')
3
+ }
4
+
5
+ main();
@@ -0,0 +1,4 @@
1
+ #!/bin/bash -xe
2
+
3
+ echo "Running 'npm run start'..."
4
+ npm run start
@@ -1,272 +1,235 @@
1
- const path = require('path');
2
- const fs = require('fs')
3
- const { EC2Client, RunInstancesCommand,CreateImageCommand,TerminateInstancesCommand,DescribeInstanceStatusCommand,DeregisterImageCommand,DescribeImagesCommand,CopyImageCommand } = require("@aws-sdk/client-ec2");
4
-
5
- const AdmZip = require("adm-zip");
6
-
7
- const Params = require('./helpers/params')
8
- const S3 = require('./helpers/s3');
9
-
10
-
11
- const INSTANCE_TYPE="t2.micro"
12
-
13
- exports.main = async function(args){
14
- console.log(`Updating ${args.app} v${args.v}`)
15
-
16
- // Get App
17
- const app = await Params.getApp(args.app);
18
- if (!app){
19
- console.log('Err: No app named ' + args.app);
20
- throw new Error('Err: No app named ' + args.app)
21
- }
22
-
23
- // --- I PREP ZIP ---
24
- const zipPath = path.resolve(args.path);
25
- if (!fs.existsSync(zipPath)){ throw new Error("Path not found:" + args.path)}
26
- const zipFilePath = await prepZip(zipPath);
27
- await S3.uploadInfraFile(`apps/${args.app}/${args.v}/app.zip`,zipFilePath);
28
-
29
- // --- II UPDATE STACK ---
30
- // If stack arg, upload stack
31
- const stackKey = `apps/${args.app}/${args.v}/stack.yaml`;
32
- if (args.stack){
33
- console.log(`Upating stack: ${stackPath} to ${stackKey}`)
34
- const stackPath = path.resolve(args.stack);
35
- if (!fs.existsSync(stackPath)){ throw new Error("Stack file not found:" + args.stack)}
36
- await S3.uploadInfraFile(stackKey,stackPath)
37
- } else {
38
- // If no stack arg, upload default stack if none exists
39
- const stackExists = await S3.infraFileExists(stackKey)
40
- if (!stackExists){
41
- console.log('Using default stack');
42
- await S3.copyInfraFile(app.stackKey,stackKey)
43
- } else {
44
- console.log('Skipping stack update')
45
- }
46
- }
47
-
48
- // --- III BUILD IMAGE ---
49
- // Launch ec2
50
- const orgParams = await Params.getOrgConfig();
51
-
52
- const awsLinuxAMI = await findLinuxAMI(process.env.orgRegion);
53
- const instance_id = await launchInstance({
54
- app: app.name,
55
- linuxAMI: awsLinuxAMI,
56
- version: args.v,
57
- sec_group: orgParams.buildSecGroup,
58
- iam: orgParams.buildInstanceProfile
59
- });
60
-
61
- await waitUntilInstanceReady(instance_id,process.env.orgRegion);
62
-
63
- // Create AMI
64
- const buildNumber = (app.versions[args.v]?.currentBuild || 0) + 1;
65
- const appVID = `${app.name}-v${args.v}.${buildNumber}`;
66
- console.log(appVID);
67
-
68
- var success = false;
69
- let ami_id;
70
- try {
71
- ami_id = await createAMI(instance_id, appVID,process.env.orgRegion)
72
- success = true;
73
- } catch(e){
74
- console.log("Error Creating AMI:" + e)
75
- }
76
- await terminateInstance(instance_id,process.env.orgRegion)
77
- if (success === false){ throw new Error("Error - Build Not Complete") }
78
-
79
- // --- IV UPDATE PARAMS ---
80
- const versionInfo = {
81
- baseAMI_Name: appVID,
82
- baseAMI_Id: ami_id,
83
- currentBuild: buildNumber,
84
- updated: Date.now()
85
- }
86
- await Params.updateAppV(app.name,args.v,versionInfo);
87
- return true;
88
- }
89
-
90
-
91
-
92
- ///////////////////////////////////////////////
93
- ///////////////////////////////////////////////
94
- ///////////////////////////////////////////////
95
-
96
- async function prepZip(appPath){
97
- console.log('Zipping ' + appPath);
98
- const inPath = path.resolve(appPath);
99
- let zipPath = path.resolve(`./app.zip`);
100
-
101
- const pathStat = fs.statSync(inPath);
102
- // If dir, zip
103
- if (!pathStat.isFile()){
104
- const zip = new AdmZip();
105
- zip.addLocalFolder(inPath);
106
- zip.writeZip(zipPath);
107
- } else {
108
- // If not zip, throw error
109
- if (path.extname(inPath) !== '.zip'){
110
- console.log('ERROR:Not a .zip file >>' + inPath)
111
- throw 'ERROR:Not a .zip file >>' + inPath;
112
- }
113
- // Copy .zip file
114
- fs.copyFileSync(inPath,zipPath);
115
- }
116
- process.on('exit', function(){ fs.unlinkSync(zipPath) });
117
- return zipPath;
118
- }
119
-
120
- async function findLinuxAMI(region){
121
- // aws ec2 describe-images --owners amazon --filters "Name=name,Values=amzn*" --query 'sort_by(Images, &CreationDate)[].Name'
122
- console.log('Locating AMI for AWS Linux in ' + region)
123
- const client = new EC2Client({region});
124
- const input = { // DescribeImagesRequest
125
- Owners: ['amazon'],
126
- Filters: [
127
- {
128
- Name: "name",
129
- Values: ["al2023-ami-2023.2.20230920.1-kernel-6.1-x86_64"], // Pattern for Amazon Linux 2 AMI
130
- },
131
- {
132
- Name: "state",
133
- Values: ["available"],
134
- },
135
- {
136
- Name: "architecture",
137
- Values: [ "x86_64" ],
138
- },
139
- {
140
- Name: "virtualization-type",
141
- Values: ["hvm"]
142
- }
143
- ],
144
- // al2023-ami-2023.2.20230920.1-kernel-6.1-x86_64
145
- // ImageIds: ['ami-03a6eaae9938c858c'],
146
- IncludeDeprecated: false,
147
- DryRun: false,
148
- // MaxResults: 16
149
- };
150
- const command = new DescribeImagesCommand(input);
151
- const response = await client.send(command);
152
- const images = response.Images;
153
-
154
- if (!images[0]){
155
- console.log('Could not find AWS Linux 2023 base image')
156
- throw 'Could not find AWS Linux 2023 base image'
157
- };
158
-
159
- return images[0].ImageId;
160
- }
161
-
162
- async function launchInstance(launchParams){
163
- console.log('Launching Instance in ' + process.env.orgRegion);
164
-
165
- const user_data = [
166
- `#!/bin/bash -xe`,
167
- `yum -y install nodejs`,
168
- `yum -y install unzip`,
169
- `cd /home/ec2-user`,
170
- `aws s3 cp s3://${process.env.orgBucket}/apps/${launchParams.app.toLowerCase()}/${launchParams.version}/app.zip .`,
171
- `unzip app.zip -d app`,
172
- `rm -r app.zip`
173
- ].join('\n')
174
-
175
- const ud_b64 = Buffer.from(user_data).toString('base64');
176
-
177
- const client = new EC2Client({region: process.env.orgRegion });
178
-
179
- const createInstanceParams = {
180
- ImageId: launchParams.linuxAMI,
181
- InstanceType: INSTANCE_TYPE,
182
- SecurityGroupIds: [
183
- launchParams.sec_group
184
- ],
185
- MinCount: 1,
186
- MaxCount: 1,
187
- UserData: ud_b64,
188
- IamInstanceProfile: {
189
- Arn: launchParams.iam
190
- }
191
- };
192
- const command = new RunInstancesCommand(createInstanceParams);
193
- const response = await client.send(command);
194
- const instance_id = response.Instances[0].InstanceId
195
-
196
- console.log('Instance Launched:',instance_id);
197
- return instance_id;
198
- }
199
-
200
- async function waitUntilInstanceReady(instance_id,region){
201
- console.log(`Awaiting ${instance_id} status of ok`)
202
- const client = new EC2Client({region});
203
- const input = { // DescribeInstanceStatusRequest
204
- InstanceIds: [ // InstanceIdStringList
205
- instance_id
206
- ],
207
- DryRun: false,
208
- IncludeAllInstances: true
209
- };
210
-
211
- let totalSleepTime = 0;
212
- let ok = false;
213
- const command = new DescribeInstanceStatusCommand(input);
214
- for (let i=0; i<50; i++){
215
- const response = await client.send(command);
216
- const status = response.InstanceStatuses[0].InstanceStatus.Status;
217
- console.log(`\tCheck ${i+1} @ ${totalSleepTime}s: EC2 Status is ${status}`)
218
- if (status !== 'ok'){
219
- await sleep(10000);
220
- totalSleepTime += 10;
221
- } else {
222
- console.log('Ec2 Instance Ready:' + status);
223
- ok = true;
224
- break;
225
- }
226
- }
227
-
228
- if (ok === false){
229
- console.log('ERR:::', `Ec2 Instance Not Ready After ${totalSleepTime}s`)
230
- throw `Ec2 Instance Not Ready After ${totalSleepTime}s`
231
- } else {
232
- console.log(`Instance Ready After ${totalSleepTime}s. Waiting 30s to Proceed`);
233
- await sleep(30);
234
- }
235
- return true;
236
- }
237
-
238
- async function createAMI(instance_id,image_name,region){
239
- console.log(`Building ${image_name} in ${region}`)
240
- const client = new EC2Client({region});
241
- const input = { // CreateImageRequest
242
- Description: `Base Application Image`,
243
- DryRun: false,
244
- InstanceId: instance_id, // required
245
- Name: image_name, // required
246
- NoReboot: true
247
- };
248
- const command = new CreateImageCommand(input);
249
- const response = await client.send(command);
250
- console.log(`Created Image ${image_name} ID:${response.ImageId}`)
251
- return response.ImageId;
252
- }
253
-
254
- async function terminateInstance(instance_id,region){
255
- console.log('Terminating Instance ' + instance_id)
256
- const client = new EC2Client({region});
257
- const input = { // TerminateInstancesRequest
258
- InstanceIds: [ instance_id ],
259
- DryRun: false,
260
- };
261
- const command = new TerminateInstancesCommand(input);
262
- const response = await client.send(command);
263
- return true;
264
- }
265
-
266
-
267
- async function sleep(time){
268
- return new Promise(function (resolve, reject) {
269
- setTimeout(function () { resolve(true);
270
- }, time);
271
- });
272
- }
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const EC2 = require('./helpers/ec2');
4
+ const { EC2Client, RunInstancesCommand,CreateImageCommand,TerminateInstancesCommand,DescribeInstanceStatusCommand,DeregisterImageCommand,DescribeImagesCommand,CopyImageCommand } = require("@aws-sdk/client-ec2");
5
+
6
+ const AdmZip = require("adm-zip");
7
+
8
+ const Params = require('./helpers/params')
9
+ const S3 = require('./helpers/s3');
10
+
11
+
12
+ const INSTANCE_TYPE="t2.micro"
13
+
14
+ exports.main = async function(args){
15
+ console.log(`Updating ${args.app} v${args.v}`);
16
+
17
+ // Check Version Format
18
+ if (!args.v.match(/^[1-9][0-9]{0,4}\.[0-9]{0,4}$/)){
19
+ console.log('Invalid Version Format. Use format [major].[minor] without leading 0s')
20
+ throw new Error('Invalid Version Format');
21
+ }
22
+
23
+ // Get App
24
+ const app = await Params.getApp(args.app);
25
+ if (!app){
26
+ console.log('Err: No app named ' + args.app);
27
+ throw new Error('Err: No app named ' + args.app)
28
+ }
29
+
30
+ // --- I PREP ZIP ---
31
+ const zipPath = path.resolve(args.path);
32
+ if (!fs.existsSync(zipPath)){ throw new Error("Path not found:" + args.path)}
33
+ const zipFilePath = await prepZip(zipPath);
34
+ await S3.uploadInfraFile(`apps/${args.app}/${args.v}/app.zip`,zipFilePath);
35
+
36
+ // --- II UPDATE STACK ---
37
+ // If stack arg, upload stack
38
+ const stackKey = `apps/${args.app}/${args.v}/stack.yaml`;
39
+ // If no stack arg, upload default stack if none exists
40
+ const stackExists = await S3.infraFileExists(stackKey)
41
+ if (!stackExists){
42
+ console.log('Copying default stack to ' + `apps/${args.app}/${args.v}`);
43
+ await S3.copyInfraFile(app.stackKey,stackKey)
44
+ }
45
+
46
+ // --- III BUILD IMAGE ---
47
+ // Launch ec2
48
+ const orgParams = await Params.getOrgConfig();
49
+
50
+ // const awsLinuxAMI = await findLinuxAMI(process.env.orgRegion);
51
+ const awsLinuxAMI = EC2.awsLinuxAMI(process.env.orgRegion);
52
+ const instance_id = await launchInstance({
53
+ app: app.name,
54
+ linuxAMI: awsLinuxAMI,
55
+ version: args.v,
56
+ sec_group: orgParams.buildSecGroup,
57
+ iam: orgParams.buildInstanceProfile,
58
+ node: app.nodeV,
59
+ py: app.pyV
60
+ });
61
+
62
+ await waitUntilInstanceReady(instance_id,process.env.orgRegion);
63
+
64
+ // Create AMI
65
+ const buildNumber = (app.versions[args.v]?.currentBuild || 0) + 1;
66
+ const appVID = `${app.name.toLowerCase()}-v${args.v}.${buildNumber}`;
67
+
68
+ var success = false;
69
+ let ami_id;
70
+ try {
71
+ ami_id = await createAMI(instance_id, appVID,process.env.orgRegion)
72
+ success = true;
73
+ } catch(e){
74
+ console.log("Error Creating AMI:" + e)
75
+ }
76
+ await terminateInstance(instance_id,process.env.orgRegion)
77
+ if (success === false){ throw new Error("Error - Build Not Complete") }
78
+
79
+ // --- IV UPDATE PARAMS ---
80
+ const versionInfo = {
81
+ baseAMI_Name: appVID,
82
+ stackPath: stackKey,
83
+ stackURL: `https://s3.${process.env.orgRegion}.amazonaws.com/${process.env.orgBucket}/apps/${args.app.toLowerCase()}/${args.v}/stack.yaml`,
84
+ baseAMI_Id: ami_id,
85
+ currentBuild: buildNumber,
86
+ updated: Date.now()
87
+ }
88
+ await Params.updateAppV(app.name,args.v,versionInfo);
89
+
90
+ return true;
91
+ }
92
+
93
+
94
+
95
+ ///////////////////////////////////////////////
96
+ ///////////////////////////////////////////////
97
+ ///////////////////////////////////////////////
98
+
99
+ async function prepZip(appPath){
100
+ console.log('Zipping ' + appPath);
101
+ const inPath = path.resolve(appPath);
102
+ let zipPath = path.resolve(`./app.zip`);
103
+
104
+ const pathStat = fs.statSync(inPath);
105
+ // If dir, zip
106
+ if (!pathStat.isFile()){
107
+ const zip = new AdmZip();
108
+ zip.addLocalFolder(inPath);
109
+ zip.writeZip(zipPath);
110
+ } else {
111
+ // If not zip, throw error
112
+ if (path.extname(inPath) !== '.zip'){
113
+ console.log('ERROR:Not a .zip file >>' + inPath)
114
+ throw 'ERROR:Not a .zip file >>' + inPath;
115
+ }
116
+ // Copy .zip file
117
+ fs.copyFileSync(inPath,zipPath);
118
+ }
119
+ process.on('exit', function(){ fs.unlinkSync(zipPath) });
120
+ return zipPath;
121
+ }
122
+
123
+ async function launchInstance(launchParams){
124
+ console.log('Launching Instance in ' + process.env.orgRegion);
125
+ const nodeRepo = launchParams.node === '' ? 'echo default_version' : `https://rpm.nodesource.com/setup_${launchParams.node}.x | sudo bash -`;
126
+ const user_data = [
127
+ `#!/bin/bash -xe`,
128
+ nodeRepo,
129
+ `yum -y install nodejs`,
130
+ `yum -y install python3`,
131
+ `yum -y install unzip`,
132
+ `cd /home/ec2-user`,
133
+ `aws s3 cp s3://${process.env.orgBucket}/apps/${launchParams.app.toLowerCase()}/${launchParams.version}/app.zip .`,
134
+ `unzip app.zip -d app`,
135
+ `rm -r app.zip`
136
+ ].join('\n')
137
+
138
+ const ud_b64 = Buffer.from(user_data).toString('base64');
139
+
140
+ const client = new EC2Client({region: process.env.orgRegion });
141
+
142
+ const createInstanceParams = {
143
+ ImageId: launchParams.linuxAMI,
144
+ InstanceType: INSTANCE_TYPE,
145
+ SecurityGroupIds: [
146
+ launchParams.sec_group
147
+ ],
148
+ MinCount: 1,
149
+ MaxCount: 1,
150
+ UserData: ud_b64,
151
+ IamInstanceProfile: {
152
+ Arn: launchParams.iam
153
+ }
154
+ };
155
+ const command = new RunInstancesCommand(createInstanceParams);
156
+ const response = await client.send(command);
157
+ const instance_id = response.Instances[0].InstanceId
158
+
159
+ console.log('Instance Launched:',instance_id);
160
+ return instance_id;
161
+ }
162
+
163
+ async function waitUntilInstanceReady(instance_id,region){
164
+ console.log(`Awaiting ${instance_id} status of ok`)
165
+ const client = new EC2Client({region});
166
+ const input = { // DescribeInstanceStatusRequest
167
+ InstanceIds: [ // InstanceIdStringList
168
+ instance_id
169
+ ],
170
+ DryRun: false,
171
+ IncludeAllInstances: true
172
+ };
173
+
174
+ let totalSleepTime = 0;
175
+ let ok = false;
176
+ const command = new DescribeInstanceStatusCommand(input);
177
+ for (let i=0; i<50; i++){
178
+ const response = await client.send(command);
179
+ const status = response.InstanceStatuses[0].InstanceStatus.Status;
180
+ console.log(`\tCheck ${i+1} @ ${totalSleepTime}s: EC2 Status is ${status}`)
181
+ if (status !== 'ok'){
182
+ await sleep(10000);
183
+ totalSleepTime += 10;
184
+ } else {
185
+ console.log('Ec2 Instance Ready:' + status);
186
+ ok = true;
187
+ break;
188
+ }
189
+ }
190
+
191
+ if (ok === false){
192
+ console.log('ERR:::', `Ec2 Instance Not Ready After ${totalSleepTime}s`)
193
+ throw `Ec2 Instance Not Ready After ${totalSleepTime}s`
194
+ } else {
195
+ console.log(`Instance Ready After ${totalSleepTime}s. Waiting 30s to Proceed`);
196
+ await sleep(30);
197
+ }
198
+ return true;
199
+ }
200
+
201
+ async function createAMI(instance_id,image_name,region){
202
+ console.log(`Building ${image_name} in ${region}`)
203
+ const client = new EC2Client({region});
204
+ const input = { // CreateImageRequest
205
+ Description: `Base Application Image`,
206
+ DryRun: false,
207
+ InstanceId: instance_id, // required
208
+ Name: image_name, // required
209
+ NoReboot: true
210
+ };
211
+ const command = new CreateImageCommand(input);
212
+ const response = await client.send(command);
213
+ console.log(`Created Image ${image_name} ID:${response.ImageId}`)
214
+ return response.ImageId;
215
+ }
216
+
217
+ async function terminateInstance(instance_id,region){
218
+ console.log('Terminating Instance ' + instance_id)
219
+ const client = new EC2Client({region});
220
+ const input = { // TerminateInstancesRequest
221
+ InstanceIds: [ instance_id ],
222
+ DryRun: false,
223
+ };
224
+ const command = new TerminateInstancesCommand(input);
225
+ const response = await client.send(command);
226
+ return true;
227
+ }
228
+
229
+
230
+ async function sleep(time){
231
+ return new Promise(function (resolve, reject) {
232
+ setTimeout(function () { resolve(true);
233
+ }, time);
234
+ });
235
+ }
@@ -0,0 +1,27 @@
1
+ const S3 = require('./helpers/s3');
2
+ const Params = require('./helpers/params');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ exports.main = async function(args){
7
+ // Get App
8
+ const app = await Params.getApp(args.app);
9
+ if (!app){
10
+ console.log('Err: No app named ' + args.app);
11
+ throw new Error('Err: No app named ' + args.app)
12
+ }
13
+ if (args.default === undefined && !app.versions[args.v]){
14
+ console.log('Err: No app version ' + args.app + ' ' + args.v);
15
+ throw new Error('Err: No app version ' + args.app + ' ' + args.v)
16
+ }
17
+ if (args.default === null && args.v){
18
+ console.log('Err: Cannot set default and specify version');
19
+ throw new Error('Err: Cannot set default version and specify version')
20
+ }
21
+ const stackPath = path.resolve(args.stack);
22
+ if (!fs.existsSync(stackPath)){ throw new Error("Stack file not found:" + args.stack)}
23
+
24
+ console.log(`Upating v${args.v || 'Default'} stack for ${args.app}`);
25
+ const stackKey = args.default === null ? `apps/${args.app}/default_stack.yaml` : `apps/${args.app}/${args.v}/stack.yaml`;
26
+ await S3.uploadInfraFile(stackKey,stackPath);
27
+ }