cloudmason 2.7.49 → 2.7.50
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/commands/helpers/org_config.js +26 -0
- package/commands/init_org.js +5 -12
- package/commands/publish.js +103 -51
- package/main.js +10 -15
- package/org.txt +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIR = path.join(os.homedir(), '.cloudmason');
|
|
6
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const LEGACY_PATH = path.resolve(__dirname, '..', '..', 'org.txt');
|
|
8
|
+
|
|
9
|
+
exports.read = function () {
|
|
10
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
11
|
+
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
12
|
+
}
|
|
13
|
+
if (fs.existsSync(LEGACY_PATH)) {
|
|
14
|
+
const [name, region] = fs.readFileSync(LEGACY_PATH, 'utf-8').split(',');
|
|
15
|
+
const cfg = { name, region };
|
|
16
|
+
exports.write(cfg);
|
|
17
|
+
try { fs.unlinkSync(LEGACY_PATH); } catch (_) {}
|
|
18
|
+
return cfg;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.write = function (cfg) {
|
|
24
|
+
if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
25
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2), 'utf-8');
|
|
26
|
+
};
|
package/commands/init_org.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
1
|
const { S3Client,HeadBucketCommand } = require("@aws-sdk/client-s3");
|
|
4
2
|
const { EC2Client, DescribeVpcsCommand } = require("@aws-sdk/client-ec2");
|
|
5
3
|
|
|
6
4
|
const CF = require('./helpers/cf');
|
|
7
5
|
const Params = require('./helpers/params');
|
|
6
|
+
const OrgConfig = require('./helpers/org_config');
|
|
8
7
|
|
|
9
8
|
exports.main = async function(args){
|
|
10
9
|
console.log(`Setting up ${args.name}@ in ${args.region} with repo ${args.repo}`)
|
|
@@ -23,11 +22,8 @@ exports.main = async function(args){
|
|
|
23
22
|
throw new Error('Org already exists')
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const orgData = `${args.name},${args.region}`;
|
|
29
|
-
fs.writeFileSync(orgPath,orgData,'utf-8')
|
|
30
|
-
console.log('Set up org:',orgData)
|
|
25
|
+
OrgConfig.write({ name: args.name, region: args.region });
|
|
26
|
+
console.log('Set up org:', args.name, args.region)
|
|
31
27
|
return true;
|
|
32
28
|
}
|
|
33
29
|
|
|
@@ -48,11 +44,8 @@ exports.updateOrgStack = async function(args){
|
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
exports.setOrg = async function(args){
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const orgData = `${args.name},${args.region}`;
|
|
54
|
-
fs.writeFileSync(orgPath,orgData,'utf-8')
|
|
55
|
-
console.log('Set org:',orgData)
|
|
47
|
+
OrgConfig.write({ name: args.name, region: args.region });
|
|
48
|
+
console.log('Set org:', args.name, args.region)
|
|
56
49
|
return true;
|
|
57
50
|
}
|
|
58
51
|
|
package/commands/publish.js
CHANGED
|
@@ -28,24 +28,36 @@ exports.main = async function(args){
|
|
|
28
28
|
}
|
|
29
29
|
pubArgs.amiId = instanceVersion.baseAMI_Id;
|
|
30
30
|
pubArgs.arch = instanceVersion.arch || 'x86_64';
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (args.cft){
|
|
32
|
+
pubArgs.cftS3Url = instanceVersion.stackURL;
|
|
33
|
+
if (!pubArgs.cftS3Url){
|
|
34
|
+
console.log('ERR: No stack URL found for version',pubArgs.version);
|
|
35
|
+
throw new Error('No stack URL found for version:' + pubArgs.version);
|
|
36
|
+
}
|
|
37
|
+
console.log('Publishing AMI + CFT:\n\t',Object.entries(pubArgs).map(([k,v])=>{return `${k}:${v}`}).join('\n\t'));
|
|
38
|
+
await exports.updateAmiCft(pubArgs);
|
|
39
|
+
} else {
|
|
40
|
+
if (!args.stack){
|
|
41
|
+
throw new Error('Missing required arg -stack for AMI-only publish');
|
|
42
|
+
}
|
|
43
|
+
console.log('Publishing AMI:\n\t',Object.entries(pubArgs).map(([k,v])=>{return `${k}:${v}`}).join('\n\t'));
|
|
44
|
+
await updateAmiVersion(pubArgs);
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
// -- Get Marketplace AMI IDs
|
|
47
|
+
// AmiAlias: '/aws/service/marketplace/prod-shmtmk4gqrfge/1.2'
|
|
48
|
+
const amiAlias = `/aws/service/marketplace/${pubArgs.productId}/${pubArgs.version}`;
|
|
49
|
+
console.log('AMI Alias:',amiAlias);
|
|
50
|
+
let stackTxt = fs.readFileSync(path.resolve(args.stack),'utf8');
|
|
51
|
+
// stackTxt = stackTxt.replace(`ImageId: !Ref AmiId`,`ImageId: resolve:ssm:${amiAlias}`);
|
|
52
|
+
stackTxt = stackTxt.replace(/^#-Strip.+#-Strip/ms,'');
|
|
36
53
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// stackTxt = stackTxt.replace(`ImageId: !Ref AmiId`,`ImageId: resolve:ssm:${amiAlias}`);
|
|
43
|
-
stackTxt = stackTxt.replace(/^#-Strip.+#-Strip/ms,'');
|
|
54
|
+
// -- Update CF Template with AMI IDs
|
|
55
|
+
// const newFileName = path.resolve(args.out);
|
|
56
|
+
// console.log('Updating Template:',newFileName);
|
|
57
|
+
// fs.writeFileSync(newFileName,stackTxt);
|
|
58
|
+
}
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
const newFileName = path.resolve(args.out);
|
|
47
|
-
console.log('Updating Template:',newFileName);
|
|
48
|
-
fs.writeFileSync(newFileName,stackTxt);
|
|
60
|
+
console.log('----------')
|
|
49
61
|
|
|
50
62
|
// -- Suggest next step
|
|
51
63
|
console.log('\nTo wait for this version to be publicly available in marketplace, run:');
|
|
@@ -156,53 +168,93 @@ const updateAmiVersion = async ({productId, amiId, version, changeDescription, a
|
|
|
156
168
|
};
|
|
157
169
|
|
|
158
170
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
171
|
+
// Update AMI + CloudFormation Template Function
|
|
172
|
+
|
|
173
|
+
exports.updateAmiCft = async ({productId, amiId, version, changeDescription, arch, cftS3Url}) => {
|
|
174
|
+
const client = new MarketplaceCatalogClient({ region: process.env.orgRegion });
|
|
175
|
+
console.log('Updating AMI+CFT version:', productId, amiId, version, changeDescription, cftS3Url);
|
|
176
|
+
try {
|
|
177
|
+
const changeSet = {
|
|
178
|
+
Catalog: "AWSMarketplace",
|
|
179
|
+
Intent: "APPLY",
|
|
180
|
+
ChangeSet: [
|
|
181
|
+
{
|
|
182
|
+
ChangeType: "AddDeliveryOptions",
|
|
183
|
+
Entity: {
|
|
184
|
+
Type: "AmiProduct@1.0",
|
|
185
|
+
Identifier: productId,
|
|
186
|
+
},
|
|
187
|
+
Details: JSON.stringify({
|
|
188
|
+
Version: {
|
|
189
|
+
VersionTitle: version,
|
|
190
|
+
ReleaseNotes: changeDescription,
|
|
191
|
+
},
|
|
192
|
+
DeliveryOptions: [
|
|
193
|
+
{
|
|
194
|
+
DeliveryOptionTitle: "AMI with CloudFormation Template",
|
|
195
|
+
Details: {
|
|
196
|
+
"DeploymentTemplateDeliveryOptionDetails": {
|
|
197
|
+
"UsageInstructions": "Visit Theorim.ai/install for installation instructions",
|
|
198
|
+
"RecommendedInstanceType": arch === 'arm' ? "r8g.medium" : "m6a.large",
|
|
199
|
+
"Template": cftS3Url,
|
|
200
|
+
"TemplateSources": [
|
|
201
|
+
{
|
|
202
|
+
"ParameterName": "AmiId",
|
|
203
|
+
"AmiSource": {
|
|
204
|
+
"AmiId": amiId,
|
|
205
|
+
"AccessRoleArn": "arn:aws:iam::590183947985:role/Theorim_MarketPlaceRole",
|
|
206
|
+
"UserName": "ec2-user",
|
|
207
|
+
"OperatingSystemName": "AMAZONLINUX",
|
|
208
|
+
"OperatingSystemVersion": arch === 'arm'
|
|
209
|
+
? "Amazon Linux 2023 arm64 HVM"
|
|
210
|
+
: "Amazon Linux 2 AMI 2.0.20220207.1 x86_64 HVM gp2"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}),
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
};
|
|
162
222
|
|
|
223
|
+
const startChangeSetCommand = new StartChangeSetCommand(changeSet);
|
|
224
|
+
const startResponse = await client.send(startChangeSetCommand);
|
|
225
|
+
console.log("Change set started:", startResponse);
|
|
163
226
|
|
|
164
|
-
|
|
165
|
-
Catalog: "AWSMarketplace",
|
|
166
|
-
EntityId: productId,
|
|
167
|
-
});
|
|
168
|
-
const response = await client.send(command);
|
|
169
|
-
console.log('dd',response.DetailsDocument);
|
|
170
|
-
console.log('v',response.DetailsDocument.Versions[1].DeliveryOptions[0].AmiAlias);
|
|
171
|
-
return response.DetailsDocument.RegionAvailability.Regions;
|
|
172
|
-
// console.log("Regions:", response.DetailsDocument.Description.RegionAvailability.Regions);
|
|
173
|
-
// console.log("Version:", response.DetailsDocument.Description.RegionAvailability.Regions);
|
|
174
|
-
// Extract AMI details by region
|
|
175
|
-
}
|
|
227
|
+
const changeSetId = startResponse.ChangeSetId;
|
|
176
228
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
229
|
+
let status = "IN_PROGRESS";
|
|
230
|
+
while (status === "IN_PROGRESS") {
|
|
231
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
180
232
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
{
|
|
185
|
-
Name: "name",
|
|
186
|
-
Values: [
|
|
187
|
-
`${productName}-*-${productCode}` // Adjust the filter to match your product naming pattern
|
|
188
|
-
]
|
|
189
|
-
}
|
|
190
|
-
]
|
|
233
|
+
const describeChangeSetCommand = new DescribeChangeSetCommand({
|
|
234
|
+
Catalog: "AWSMarketplace",
|
|
235
|
+
ChangeSetId: changeSetId,
|
|
191
236
|
});
|
|
237
|
+
const describeResponse = await client.send(describeChangeSetCommand);
|
|
192
238
|
|
|
193
|
-
|
|
239
|
+
status = describeResponse.Status;
|
|
240
|
+
console.log("Change set status:", status);
|
|
194
241
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
242
|
+
if (status === "SUCCEEDED") {
|
|
243
|
+
console.log("Change set succeeded:", describeResponse);
|
|
244
|
+
break;
|
|
245
|
+
} else if (status === "FAILED") {
|
|
246
|
+
console.error("Change set failed:", describeResponse);
|
|
247
|
+
throw new Error("Change set failed");
|
|
198
248
|
}
|
|
249
|
+
}
|
|
199
250
|
|
|
200
|
-
return response.Images;
|
|
201
251
|
} catch (error) {
|
|
202
|
-
|
|
203
|
-
|
|
252
|
+
console.error("Error updating AMI+CFT version:", error);
|
|
253
|
+
throw error;
|
|
204
254
|
}
|
|
205
|
-
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
|
|
206
258
|
|
|
207
259
|
|
|
208
260
|
|
package/main.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
|
|
6
3
|
const Params = require('./commands/helpers/params');
|
|
4
|
+
const OrgConfig = require('./commands/helpers/org_config');
|
|
7
5
|
|
|
8
6
|
const Commands = {
|
|
9
7
|
'init-org': {
|
|
@@ -115,8 +113,9 @@ const Commands = {
|
|
|
115
113
|
{n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
|
|
116
114
|
{n: 'desc', desc: 'Description of Changes', r: true},
|
|
117
115
|
{n: 'v', desc: 'Version to launch', pattern: `[0-9]{1,20}`, r: true},
|
|
118
|
-
{n: 'stack', desc: 'Path of stack.yaml', r:
|
|
119
|
-
{n: 'out', desc: 'Output path of marketplace stack', r:
|
|
116
|
+
{n: 'stack', desc: 'Path of stack.yaml (required for AMI-only publish)', r: false},
|
|
117
|
+
{n: 'out', desc: 'Output path of marketplace stack (AMI-only publish)', r: false},
|
|
118
|
+
{n: 'cft', desc: 'Publish as AMI + CloudFormation Template delivery', r: false}
|
|
120
119
|
]
|
|
121
120
|
},
|
|
122
121
|
'await-ami': {
|
|
@@ -257,16 +256,12 @@ function checkNodeVersion() {
|
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
async function readOrgInfo(){
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return true;
|
|
267
|
-
} else {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
259
|
+
const cfg = OrgConfig.read();
|
|
260
|
+
if (!cfg) return false;
|
|
261
|
+
process.env.orgName = cfg.name;
|
|
262
|
+
process.env.orgRegion = cfg.region;
|
|
263
|
+
process.env.orgBucket = await Params.getOrgBucket();
|
|
264
|
+
return true;
|
|
270
265
|
}
|
|
271
266
|
|
|
272
267
|
function parseArgs(){
|
package/org.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
theorim,us-east-1
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"cloudmason","version":"2.7.
|
|
1
|
+
{"name":"cloudmason","version":"2.7.50","description":"","main":"main.js","scripts":{"build":"node build.js"},"bin":{"mason":"./main.js"},"repository":{"type":"git","url":"https://github.com/kai-harvey/cloudmason.git"},"author":"Kai Harvey","license":"ISC","dependencies":{"@aws-sdk/client-acm":"^3.418.0","@aws-sdk/client-auto-scaling":"^3.470.0","@aws-sdk/client-cloudformation":"^3.418.0","@aws-sdk/client-ec2":"^3.864.0","@aws-sdk/client-iam":"^3.864.0","@aws-sdk/client-marketplace-catalog":"^3.716.0","@aws-sdk/client-route-53":"^3.425.0","@aws-sdk/client-s3":"^3.418.0","@aws-sdk/client-ssm":"^3.421.0","adm-zip":"^0.5.10","ssh2":"^1.16.0","yaml":"^2.6.1"}}
|