cloudmason 0.0.1 → 1.0.1
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 +377 -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
package/commands/helpers/cf.js
CHANGED
|
@@ -1,118 +1,182 @@
|
|
|
1
|
-
const { CloudFormationClient, CreateStackCommand,UpdateStackCommand, DeleteStackCommand, ValidateTemplateCommand,DescribeStacksCommand } = require('@aws-sdk/client-cloudformation');
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path')
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.deployOrgStack = async function(
|
|
8
|
-
// Read Stack
|
|
9
|
-
const stackPath = path.resolve(__dirname,'stacks'
|
|
10
|
-
if (!fs.existsSync(stackPath)){
|
|
11
|
-
console.log('Invalid stack type:' + stackType);
|
|
12
|
-
throw { message: 'Invalid stack type', at: 'deployStack'}
|
|
13
|
-
}
|
|
14
|
-
const stackYML = fs.readFileSync(stackPath,'utf-8');
|
|
15
|
-
|
|
16
|
-
// Build Params
|
|
17
|
-
const cfParams = Object.keys(params).map(k=>{ return { ParameterKey: k, ParameterValue: params[k] } })
|
|
18
|
-
|
|
19
|
-
// Deploy Stack
|
|
20
|
-
const client = new CloudFormationClient({ region });
|
|
21
|
-
const input = {
|
|
22
|
-
StackName:
|
|
23
|
-
TemplateBody: stackYML,
|
|
24
|
-
Capabilities: [
|
|
25
|
-
"CAPABILITY_IAM" || "CAPABILITY_NAMED_IAM" || "CAPABILITY_AUTO_EXPAND",
|
|
26
|
-
],
|
|
27
|
-
Parameters: cfParams,
|
|
28
|
-
Tags:
|
|
29
|
-
};
|
|
30
|
-
try{
|
|
31
|
-
const result = await client.send(new CreateStackCommand(input));
|
|
32
|
-
return result.StackId;
|
|
33
|
-
} catch (e){
|
|
34
|
-
if (/AlreadyExistsException/.test(e)){
|
|
35
|
-
console.log('Stack exists ' + stackName);
|
|
36
|
-
return false;
|
|
37
|
-
} else {
|
|
38
|
-
throw new Error(e.message)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
exports.deployS3Stack = async function(stackName,s3Url,params,tag,region){
|
|
44
|
-
// Build Params
|
|
45
|
-
const cfParams = Object.keys(params).map(k=>{ return { ParameterKey: k, ParameterValue: params[k] } })
|
|
46
|
-
const cfTags = Object.keys(tag).map(k=>{ return { Key: k, Value: tag[k] } })
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
1
|
+
const { CloudFormationClient,ListStackResourcesCommand, CreateStackCommand,UpdateStackCommand, DeleteStackCommand, ValidateTemplateCommand,DescribeStacksCommand } = require('@aws-sdk/client-cloudformation');
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
exports.deployOrgStack = async function(region,params){
|
|
8
|
+
// Read Stack
|
|
9
|
+
const stackPath = path.resolve(__dirname,'stacks',`infra.yaml`);
|
|
10
|
+
if (!fs.existsSync(stackPath)){
|
|
11
|
+
console.log('Invalid stack type:' + stackType);
|
|
12
|
+
throw { message: 'Invalid stack type', at: 'deployStack'}
|
|
13
|
+
}
|
|
14
|
+
const stackYML = fs.readFileSync(stackPath,'utf-8');
|
|
15
|
+
|
|
16
|
+
// Build Params
|
|
17
|
+
const cfParams = Object.keys(params).map(k=>{ return { ParameterKey: k, ParameterValue: params[k] } })
|
|
18
|
+
|
|
19
|
+
// Deploy Stack
|
|
20
|
+
const client = new CloudFormationClient({ region });
|
|
21
|
+
const input = {
|
|
22
|
+
StackName: `CoreInfra`,
|
|
23
|
+
TemplateBody: stackYML,
|
|
24
|
+
Capabilities: [
|
|
25
|
+
"CAPABILITY_IAM" || "CAPABILITY_NAMED_IAM" || "CAPABILITY_AUTO_EXPAND",
|
|
26
|
+
],
|
|
27
|
+
Parameters: cfParams,
|
|
28
|
+
Tags: [{ Key: 'purpose', Value: 'infra' }]
|
|
29
|
+
};
|
|
30
|
+
try{
|
|
31
|
+
const result = await client.send(new CreateStackCommand(input));
|
|
32
|
+
return result.StackId;
|
|
33
|
+
} catch (e){
|
|
34
|
+
if (/AlreadyExistsException/.test(e)){
|
|
35
|
+
console.log('Stack exists ' + stackName);
|
|
36
|
+
return false;
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error(e.message)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.deployS3Stack = async function(stackName,s3Url,params,tag,region){
|
|
44
|
+
// Build Params
|
|
45
|
+
const cfParams = Object.keys(params).map(k=>{ return { ParameterKey: k, ParameterValue: params[k] } })
|
|
46
|
+
const cfTags = Object.keys(tag).map(k=>{ return { Key: k, Value: tag[k] } })
|
|
47
|
+
|
|
48
|
+
// Deploy Stack
|
|
49
|
+
const client = new CloudFormationClient({ region });
|
|
50
|
+
const input = {
|
|
51
|
+
StackName: stackName,
|
|
52
|
+
TemplateURL: s3Url,
|
|
53
|
+
OnFailure: 'DELETE',
|
|
54
|
+
Capabilities: [
|
|
55
|
+
"CAPABILITY_IAM" || "CAPABILITY_NAMED_IAM" || "CAPABILITY_AUTO_EXPAND",
|
|
56
|
+
],
|
|
57
|
+
Parameters: cfParams,
|
|
58
|
+
Tags: cfTags
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const result = await client.send(new CreateStackCommand(input));
|
|
62
|
+
return result.StackId;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.updateStack = async function(stackName,s3Url,params,region){
|
|
66
|
+
const client = new CloudFormationClient({ region });
|
|
67
|
+
const cfParams = Object.keys(params).map(k=>{ return { ParameterKey: k, ParameterValue: params[k] } })
|
|
68
|
+
const cmd = {
|
|
69
|
+
StackName: stackName,
|
|
70
|
+
TemplateURL: s3Url,
|
|
71
|
+
Parameters: cfParams,
|
|
72
|
+
Capabilities: ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]
|
|
73
|
+
};
|
|
74
|
+
const command = new UpdateStackCommand(cmd);
|
|
75
|
+
const response = await client.send(command);
|
|
76
|
+
return response.StackId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
exports.validateStack = async function(stack){
|
|
80
|
+
const client = new CloudFormationClient({ region: process.env.orgRegion });
|
|
81
|
+
|
|
82
|
+
const command = new ValidateTemplateCommand({
|
|
83
|
+
TemplateBody: stack,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
try{
|
|
87
|
+
const data = await client.send(command);
|
|
88
|
+
return { ok: true, data: data }
|
|
89
|
+
} catch (e){
|
|
90
|
+
return {ok: false, data: e}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.stackExists = async function(stackName,region){
|
|
95
|
+
const client = new CloudFormationClient({ region });
|
|
96
|
+
const command = new DescribeStacksCommand({ StackName: stackName });
|
|
97
|
+
try {
|
|
98
|
+
|
|
99
|
+
const response = await client.send(command);
|
|
100
|
+
return true;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error.name === 'ValidationError') {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
exports.stackStatus = async function(stackName, region) {
|
|
110
|
+
const client = new CloudFormationClient({ region }); // Replace with your region
|
|
111
|
+
try {
|
|
112
|
+
const command = new DescribeStacksCommand({ StackName: stackName });
|
|
113
|
+
const response = await client.send(command);
|
|
114
|
+
|
|
115
|
+
if (response.Stacks && response.Stacks.length > 0) {
|
|
116
|
+
const stack = response.Stacks[0];
|
|
117
|
+
const status = stack.StackStatus;
|
|
118
|
+
|
|
119
|
+
// Check if status indicates failure
|
|
120
|
+
if (status.includes("FAIL") || status === "DELETE_FAILED") {
|
|
121
|
+
return {
|
|
122
|
+
status: status,
|
|
123
|
+
ok: false,
|
|
124
|
+
failureReason: stack.StackStatusReason
|
|
125
|
+
};
|
|
126
|
+
} else if (status.includes("CREATE_IN_PROGRESS")){
|
|
127
|
+
return {
|
|
128
|
+
status: status,
|
|
129
|
+
ok: null
|
|
130
|
+
};
|
|
131
|
+
} else {
|
|
132
|
+
return {
|
|
133
|
+
status: status,
|
|
134
|
+
ok: true
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
throw new Error("No stack found with the specified name.");
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("Error fetching CloudFormation stack status:", error);
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
exports.getStackResource = async function(resourceType,stackName,region){
|
|
147
|
+
const res = {
|
|
148
|
+
's3': "AWS::S3::Bucket",
|
|
149
|
+
'asg': "AWS::AutoScaling::AutoScalingGroup",
|
|
150
|
+
'ec2': "AWS::EC2::Instance"
|
|
151
|
+
}[resourceType];
|
|
152
|
+
const client = new CloudFormationClient({ region }); // specify your region
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const command = new ListStackResourcesCommand({ StackName: stackName });
|
|
156
|
+
const response = await client.send(command);
|
|
157
|
+
|
|
158
|
+
// Filter the results to find the Auto Scaling group
|
|
159
|
+
const asgResource = response.StackResourceSummaries.find(resource => resource.ResourceType === res);
|
|
160
|
+
|
|
161
|
+
if (asgResource) {
|
|
162
|
+
return asgResource.PhysicalResourceId;
|
|
163
|
+
} else {
|
|
164
|
+
throw new Error("Auto Scaling Group not found in the specified stack.");
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("Error fetching Auto Scaling Group ID:", error);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
exports.delete = async function(stackName,region){
|
|
173
|
+
const client = new CloudFormationClient({ region });
|
|
174
|
+
try {
|
|
175
|
+
const command = new DeleteStackCommand({ StackName: stackName });
|
|
176
|
+
const response = await client.send(command);
|
|
177
|
+
return true;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error("Error deleting the stack:", error);
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
118
182
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const Params = require('./params');
|
|
2
|
+
const EC2 = require('./ec2');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
exports.prune_amis = async function(appName,version,region,removeLatest){
|
|
6
|
+
// Removal Func
|
|
7
|
+
const removeUnused = async function(aN,v,r){
|
|
8
|
+
const app = await Params.getApp(appName);
|
|
9
|
+
const latestBuildAMI = app.versions[version].baseAMI_Name;
|
|
10
|
+
|
|
11
|
+
// All AMIs
|
|
12
|
+
const AMIs = await EC2.listAMIs(`${appName}-v${version}`,region);
|
|
13
|
+
// console.log(`Found ${AMIs.length} AMIs in ${region}`)
|
|
14
|
+
|
|
15
|
+
// Used AMIs
|
|
16
|
+
const regionInstances = app.instances.filter(i=>{ return i.region === region });
|
|
17
|
+
const usedAMIs = regionInstances.map(i=>{ return i.amiName });
|
|
18
|
+
// console.log(`Found ${usedAMIs.length} used AMIs in ${region}`)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
// Remove Unused AMI from Target Region
|
|
22
|
+
let unusedAMIs = AMIs.filter(ami=>{ return !usedAMIs.includes(ami.Name) });
|
|
23
|
+
if (removeLatest !== true){
|
|
24
|
+
console.log('Retaining latest build ', latestBuildAMI, 'in ', region)
|
|
25
|
+
unusedAMIs = unusedAMIs.filter(ami=>{ return ami.Name !== latestBuildAMI })
|
|
26
|
+
} else {
|
|
27
|
+
console.log('Removing latest build ', latestBuildAMI, 'in ', region)
|
|
28
|
+
}
|
|
29
|
+
// console.log(`Found ${unusedAMIs.length} unused AMIs in ${region}`);
|
|
30
|
+
|
|
31
|
+
for (const ami of unusedAMIs){
|
|
32
|
+
console.log(`Deregistering ${ami.Name} in ${region}`)
|
|
33
|
+
await EC2.deleteAMI(ami.ImageId,region);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Remove from target region
|
|
37
|
+
await removeUnused(appName,version,region);
|
|
38
|
+
// Remove from org region
|
|
39
|
+
await removeUnused(appName,version,process.env.orgRegion);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.remove_app_amis = async function(appName,region){
|
|
43
|
+
// All AMIs
|
|
44
|
+
const AMIs = await EC2.listAMIs(`${appName}-v`,region);
|
|
45
|
+
for (const ami of AMIs){
|
|
46
|
+
console.log(`Deregistering ${ami.Name} in ${region}`)
|
|
47
|
+
await EC2.deleteAMI(ami.ImageId,region);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.sleep = async function(s){
|
|
52
|
+
s = s*1000;
|
|
53
|
+
return new Promise(function (resolve, reject) {
|
|
54
|
+
setTimeout(function () { resolve(true);
|
|
55
|
+
}, s);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.formatDate = function(utcMillis){
|
|
60
|
+
let date;
|
|
61
|
+
if (typeof(utcMillis) === 'string'){
|
|
62
|
+
date = new Date(utcMillis);
|
|
63
|
+
} else {
|
|
64
|
+
date = new Date(utcMillis);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Extracting individual components in local time
|
|
68
|
+
const month = date.getMonth() + 1; // getMonth returns month from 0-11
|
|
69
|
+
const day = date.getDate();
|
|
70
|
+
const year = date.getFullYear().toString().substr(-2); // Get last two digits of the year
|
|
71
|
+
const hours = date.getHours();
|
|
72
|
+
const minutes = date.getMinutes();
|
|
73
|
+
|
|
74
|
+
// Formatting each component to ensure two digits
|
|
75
|
+
const formattedMonth = month.toString().padStart(2, '0');
|
|
76
|
+
const formattedDay = day.toString().padStart(2, '0');
|
|
77
|
+
const formattedHours = hours.toString().padStart(2, '0');
|
|
78
|
+
const formattedMinutes = minutes.toString().padStart(2, '0');
|
|
79
|
+
|
|
80
|
+
// Constructing the final string
|
|
81
|
+
return `${formattedMonth}-${formattedDay}-${year} ${formattedHours}:${formattedMinutes}`;
|
|
82
|
+
}
|
package/commands/helpers/ec2.js
CHANGED
|
@@ -1,40 +1,154 @@
|
|
|
1
|
-
const { EC2Client, RunInstancesCommand,CreateImageCommand,TerminateInstancesCommand,DescribeInstanceStatusCommand,DeregisterImageCommand,DescribeImagesCommand,CopyImageCommand } = require("@aws-sdk/client-ec2");
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
const { EC2Client, GetConsoleOutputCommand, RunInstancesCommand,CreateImageCommand,TerminateInstancesCommand,DescribeInstanceStatusCommand,DeregisterImageCommand,DescribeImagesCommand,CopyImageCommand } = require("@aws-sdk/client-ec2");
|
|
2
|
+
const { AutoScalingClient, DescribeAutoScalingGroupsCommand } = require("@aws-sdk/client-auto-scaling");
|
|
3
|
+
|
|
4
|
+
exports.findAMI = async function(image_name,region){
|
|
5
|
+
const client = new EC2Client({ region });
|
|
6
|
+
const input = { // DescribeImagesRequest
|
|
7
|
+
Filters: [ // FilterList
|
|
8
|
+
{ // Filter
|
|
9
|
+
Name: "name",
|
|
10
|
+
Values: [ // ValueStringList
|
|
11
|
+
image_name,
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
IncludeDeprecated: true,
|
|
16
|
+
DryRun: false,
|
|
17
|
+
MaxResults: 6
|
|
18
|
+
};
|
|
19
|
+
const command = new DescribeImagesCommand(input);
|
|
20
|
+
const response = await client.send(command);
|
|
21
|
+
const images = response.Images;
|
|
22
|
+
if (!images[0]){
|
|
23
|
+
console.log('No existing image with name:' + image_name)
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
26
|
+
return images[0].ImageId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.awsLinuxAMI = function(region){
|
|
30
|
+
const ami = {
|
|
31
|
+
"us-east-1": "ami-0759f51a90924c166",
|
|
32
|
+
"us-east-2": "ami-048e636f368eb3006",
|
|
33
|
+
"us-west-1": "ami-0a07b0077b66673f1",
|
|
34
|
+
"us-west-2": "ami-0c00eacddaea828c6",
|
|
35
|
+
"ap-east-1": "",
|
|
36
|
+
"ap-south-1": "",
|
|
37
|
+
"ap-northeast-2": "",
|
|
38
|
+
"ap-southeast-1": "",
|
|
39
|
+
"ap-southeast-2": "",
|
|
40
|
+
"ap-northeast-1": "",
|
|
41
|
+
"ca-central-1": "ami-02d34aedb8fa9c346",
|
|
42
|
+
"eu-central-1": "",
|
|
43
|
+
"eu-west-1": "",
|
|
44
|
+
"eu-west-2": "",
|
|
45
|
+
"eu-west-3": "",
|
|
46
|
+
"eu-north-1": "",
|
|
47
|
+
"me-south-1": "",
|
|
48
|
+
"sa-east-1": "ami-0f4e579ad17e32ab7"
|
|
49
|
+
}[region];
|
|
50
|
+
if (!ami){ throw 'No AMI found for region ' + region };
|
|
51
|
+
return ami;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports.listAMIs = async function(image_name,region){
|
|
55
|
+
const client = new EC2Client({ region });
|
|
56
|
+
image_name = image_name + '*';
|
|
57
|
+
const input = { // DescribeImagesRequest
|
|
58
|
+
Filters: [ // FilterList
|
|
59
|
+
{ // Filter
|
|
60
|
+
Name: "name",
|
|
61
|
+
Values: [ // ValueStringList
|
|
62
|
+
image_name,
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
Owners: [ // OwnerStringList
|
|
67
|
+
"self",
|
|
68
|
+
],
|
|
69
|
+
IncludeDeprecated: false,
|
|
70
|
+
IncludeDisabled: false,
|
|
71
|
+
DryRun: false,
|
|
72
|
+
MaxResults: 6
|
|
73
|
+
};
|
|
74
|
+
const command = new DescribeImagesCommand(input);
|
|
75
|
+
const response = await client.send(command);
|
|
76
|
+
if (response.Images){
|
|
77
|
+
return response.Images.map(i=>{ return { ImageId: i.ImageId, Name: i.Name } });
|
|
78
|
+
} else {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
exports.copyAMI = async function(image_name,src_ami,src_region,dest_region){
|
|
84
|
+
|
|
85
|
+
const destinationEc2Client = new EC2Client({ region: dest_region });
|
|
86
|
+
|
|
87
|
+
const copyImageCommand = new CopyImageCommand({
|
|
88
|
+
SourceRegion: src_region,
|
|
89
|
+
SourceImageId: src_ami,
|
|
90
|
+
Name: image_name,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const { ImageId } = await destinationEc2Client.send(copyImageCommand);
|
|
94
|
+
return ImageId;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
exports.deleteAMI = async function(image_id,region){
|
|
98
|
+
const client = new EC2Client({ region });
|
|
99
|
+
const input = {
|
|
100
|
+
ImageId: image_id,
|
|
101
|
+
DryRun: false
|
|
102
|
+
};
|
|
103
|
+
const command = new DeregisterImageCommand(input);
|
|
104
|
+
const response = await client.send(command);
|
|
105
|
+
return response;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
exports.checkAMIStatus = async function(image_id,region){
|
|
109
|
+
const client = new EC2Client({ region }); // Replace 'your-region' with your AWS region
|
|
110
|
+
|
|
111
|
+
const command = new DescribeImagesCommand({
|
|
112
|
+
ImageIds: [image_id]
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const response = await client.send(command);
|
|
116
|
+
if (response.Images && response.Images.length > 0 && response.Images[0].State.toLowerCase() === 'available') {
|
|
117
|
+
return true;
|
|
118
|
+
} else {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
exports.getConsoleOutput = async function(autoScalingGroupName,region,latest=true){
|
|
125
|
+
const autoScalingClient = new AutoScalingClient({ region }); // specify your region
|
|
126
|
+
const ec2Client = new EC2Client({ region });
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Get instance IDs from Auto Scaling group
|
|
130
|
+
const describeGroupsCommand = new DescribeAutoScalingGroupsCommand({
|
|
131
|
+
AutoScalingGroupNames: [autoScalingGroupName]
|
|
132
|
+
});
|
|
133
|
+
const groupResponse = await autoScalingClient.send(describeGroupsCommand);
|
|
134
|
+
const instances = groupResponse.AutoScalingGroups[0].Instances;
|
|
135
|
+
const instanceIds = instances.map(instance => instance.InstanceId);
|
|
136
|
+
|
|
137
|
+
// Get console output for each instance
|
|
138
|
+
const consoleOutput = [];
|
|
139
|
+
|
|
140
|
+
for (let i=0;i<instanceIds.length;i++){
|
|
141
|
+
const consoleOutputCommand = new GetConsoleOutputCommand({ InstanceId: instanceIds[i],Latest: latest });
|
|
142
|
+
const outputResponse = await ec2Client.send(consoleOutputCommand);
|
|
143
|
+
const output = outputResponse.Output ? Buffer.from(outputResponse.Output, "base64").toString("ascii") : '';
|
|
144
|
+
consoleOutput.push({
|
|
145
|
+
instanceId: instanceIds[i],
|
|
146
|
+
output: output
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return consoleOutput;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error("Error fetching EC2 console outputs:", error);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|