cloudmason 2.7.50 → 2.7.51

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.
@@ -1,9 +1,37 @@
1
1
  const { MarketplaceCatalogClient, StartChangeSetCommand, DescribeChangeSetCommand } = require("@aws-sdk/client-marketplace-catalog");
2
2
  const { EC2Client, DescribeImagesCommand } = require("@aws-sdk/client-ec2");
3
+ const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
3
4
  const fs = require('fs');
4
5
  const path = require('path');
5
6
  const Params = require('./helpers/params');
6
7
 
8
+ // Parse path-style, virtual-hosted, or s3:// URLs into {bucket, key, region}
9
+ function parseS3Url(url){
10
+ if (!url){ throw new Error('Missing S3 URL'); }
11
+ let m;
12
+ if ((m = url.match(/^s3:\/\/([^/]+)\/(.+)$/))) { return { bucket: m[1], key: m[2], region: null }; }
13
+ if ((m = url.match(/^https:\/\/s3\.([^.]+)\.amazonaws\.com\/([^/]+)\/(.+)$/))) { return { bucket: m[2], key: m[3], region: m[1] }; }
14
+ if ((m = url.match(/^https:\/\/s3\.amazonaws\.com\/([^/]+)\/(.+)$/))) { return { bucket: m[1], key: m[2], region: null }; }
15
+ if ((m = url.match(/^https:\/\/([^.]+)\.s3\.([^.]+)\.amazonaws\.com\/(.+)$/))) { return { bucket: m[1], key: m[3], region: m[2] }; }
16
+ if ((m = url.match(/^https:\/\/([^.]+)\.s3\.amazonaws\.com\/(.+)$/))) { return { bucket: m[1], key: m[2], region: null }; }
17
+ throw new Error('Unrecognized S3 URL format: ' + url);
18
+ }
19
+
20
+ // AWS Marketplace requires virtual-hosted-style URLs for Template/ArchitectureDiagram
21
+ function toVirtualHostedUrl(url){
22
+ const { bucket, key, region } = parseS3Url(url);
23
+ return region
24
+ ? `https://${bucket}.s3.${region}.amazonaws.com/${key}`
25
+ : `https://${bucket}.s3.amazonaws.com/${key}`;
26
+ }
27
+
28
+ async function readS3Text(url){
29
+ const { bucket, key, region } = parseS3Url(url);
30
+ const client = new S3Client({ region: region || process.env.orgRegion });
31
+ const resp = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
32
+ return await resp.Body.transformToString();
33
+ }
34
+
7
35
  exports.add_listing = async function(args){
8
36
  console.log('Adding Listing>>', args.app, args.pid);
9
37
  await Params.addPid(args.app,args.pid.trim());
@@ -34,6 +62,13 @@ exports.main = async function(args){
34
62
  console.log('ERR: No stack URL found for version',pubArgs.version);
35
63
  throw new Error('No stack URL found for version:' + pubArgs.version);
36
64
  }
65
+ const missing = ['short','long','diagram'].filter(k => !args[k]);
66
+ if (missing.length){
67
+ throw new Error('Missing required CFT args: ' + missing.map(k=>'-'+k).join(', '));
68
+ }
69
+ pubArgs.shortDescS3Url = args.short;
70
+ pubArgs.longDescS3Url = args.long;
71
+ pubArgs.archDiagramS3Url = args.diagram;
37
72
  console.log('Publishing AMI + CFT:\n\t',Object.entries(pubArgs).map(([k,v])=>{return `${k}:${v}`}).join('\n\t'));
38
73
  await exports.updateAmiCft(pubArgs);
39
74
  } else {
@@ -170,9 +205,15 @@ const updateAmiVersion = async ({productId, amiId, version, changeDescription, a
170
205
 
171
206
  // Update AMI + CloudFormation Template Function
172
207
 
173
- exports.updateAmiCft = async ({productId, amiId, version, changeDescription, arch, cftS3Url}) => {
208
+ exports.updateAmiCft = async ({productId, amiId, version, changeDescription, arch, cftS3Url, shortDescS3Url, longDescS3Url, archDiagramS3Url}) => {
174
209
  const client = new MarketplaceCatalogClient({ region: process.env.orgRegion });
175
210
  console.log('Updating AMI+CFT version:', productId, amiId, version, changeDescription, cftS3Url);
211
+
212
+ const shortDescription = await readS3Text(shortDescS3Url);
213
+ const longDescription = await readS3Text(longDescS3Url);
214
+ const templateUrl = toVirtualHostedUrl(cftS3Url);
215
+ const diagramUrl = toVirtualHostedUrl(archDiagramS3Url);
216
+
176
217
  try {
177
218
  const changeSet = {
178
219
  Catalog: "AWSMarketplace",
@@ -194,9 +235,12 @@ exports.updateAmiCft = async ({productId, amiId, version, changeDescription, arc
194
235
  DeliveryOptionTitle: "AMI with CloudFormation Template",
195
236
  Details: {
196
237
  "DeploymentTemplateDeliveryOptionDetails": {
238
+ "ShortDescription": shortDescription,
239
+ "LongDescription": longDescription,
197
240
  "UsageInstructions": "Visit Theorim.ai/install for installation instructions",
198
241
  "RecommendedInstanceType": arch === 'arm' ? "r8g.medium" : "m6a.large",
199
- "Template": cftS3Url,
242
+ "ArchitectureDiagram": diagramUrl,
243
+ "Template": templateUrl,
200
244
  "TemplateSources": [
201
245
  {
202
246
  "ParameterName": "AmiId",
package/main.js CHANGED
@@ -115,7 +115,10 @@ const Commands = {
115
115
  {n: 'v', desc: 'Version to launch', pattern: `[0-9]{1,20}`, r: true},
116
116
  {n: 'stack', desc: 'Path of stack.yaml (required for AMI-only publish)', r: false},
117
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}
118
+ {n: 'cft', desc: 'Publish as AMI + CloudFormation Template delivery', r: false},
119
+ {n: 'short', desc: 'S3 URL of short-description text file (required when -cft is set)', r: false},
120
+ {n: 'long', desc: 'S3 URL of long-description text file (required when -cft is set)', r: false},
121
+ {n: 'diagram', desc: 'S3 URL of architecture diagram image (required when -cft is set)', r: false}
119
122
  ]
120
123
  },
121
124
  'await-ami': {
package/package.json CHANGED
@@ -1 +1 @@
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"}}
1
+ {"name":"cloudmason","version":"2.7.51","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"}}