cloudmason 1.0.9 → 1.0.11
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/build.js +2 -1
- package/commands/get_stack.js +30 -0
- package/commands/helpers/cf.js +1 -1
- package/commands/helpers/s3.js +21 -0
- package/commands/helpers/stacks/asg.yaml +3 -0
- package/commands/helpers/stacks/infra.yaml +32 -1
- package/commands/init_org.js +2 -2
- package/commands/launch_app.js +2 -2
- package/commands/update_app.js +3 -2
- package/main.js +12 -1
- package/package.json +1 -1
- package/test.bat +0 -16
package/build.js
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
console.log(args)
|
|
22
|
+
const outputPath = path.resolve(args.out);
|
|
23
|
+
if (!fs.statSync(outputPath).isDirectory()){ throw new Error("Invalid Output Path:" + args.out)}
|
|
24
|
+
|
|
25
|
+
console.log(`Pulling stack for v${args.v || 'Default'} ${args.app}`);
|
|
26
|
+
const stackKey = args.default === null ? `apps/${args.app}/default_stack.yaml` : `apps/${args.app}/${args.v}/stack.yaml`;
|
|
27
|
+
const stackText = await S3.getInfraFile(stackKey);
|
|
28
|
+
const outputFilePath = path.join(outputPath,`${args.app}_v${args.v || 'default'}_stack.yaml`);
|
|
29
|
+
fs.writeFileSync(outputFilePath,stackText,{ encoding: "utf8" });
|
|
30
|
+
}
|
package/commands/helpers/cf.js
CHANGED
|
@@ -22,7 +22,7 @@ exports.deployOrgStack = async function(region,params){
|
|
|
22
22
|
StackName: `CoreInfra`,
|
|
23
23
|
TemplateBody: stackYML,
|
|
24
24
|
Capabilities: [
|
|
25
|
-
"CAPABILITY_IAM"
|
|
25
|
+
"CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND",
|
|
26
26
|
],
|
|
27
27
|
Parameters: cfParams,
|
|
28
28
|
Tags: [{ Key: 'purpose', Value: 'infra' }]
|
package/commands/helpers/s3.js
CHANGED
|
@@ -68,6 +68,27 @@ exports.copyInfraFile = async function(srcKey,destKey){
|
|
|
68
68
|
return true;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
exports.getInfraFile = async function(fileKey){
|
|
72
|
+
const client = new S3Client({ region: process.env.orgRegion });
|
|
73
|
+
const params = {
|
|
74
|
+
Bucket: process.env.orgBucket,
|
|
75
|
+
Key: fileKey.toLowerCase(),
|
|
76
|
+
};
|
|
77
|
+
const command = new GetObjectCommand(params);
|
|
78
|
+
const response = await client.send(command);
|
|
79
|
+
|
|
80
|
+
const streamToString = (stream) =>
|
|
81
|
+
new Promise((resolve, reject) => {
|
|
82
|
+
const chunks = [];
|
|
83
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
84
|
+
stream.on("error", reject);
|
|
85
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const fileContent = await streamToString(response.Body);
|
|
89
|
+
return fileContent;
|
|
90
|
+
}
|
|
91
|
+
|
|
71
92
|
exports.emptyBucket = async function(bucketName,region){
|
|
72
93
|
await emptyS3Bucket(bucketName,region)
|
|
73
94
|
return true;
|
|
@@ -8,6 +8,9 @@ Parameters:
|
|
|
8
8
|
VpcId:
|
|
9
9
|
Type: String
|
|
10
10
|
Description: Org VPC
|
|
11
|
+
GitHubRepoName:
|
|
12
|
+
Type: String
|
|
13
|
+
Description: "GitHub repository name in the format owner/repo"
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
Resources:
|
|
@@ -99,4 +102,32 @@ Resources:
|
|
|
99
102
|
Properties:
|
|
100
103
|
Name: '/infra/infraBucket'
|
|
101
104
|
Type: 'String'
|
|
102
|
-
Value: !Ref InfraBucket
|
|
105
|
+
Value: !Ref InfraBucket
|
|
106
|
+
# Github Repo
|
|
107
|
+
GitHubActionsRole:
|
|
108
|
+
Type: "AWS::IAM::Role"
|
|
109
|
+
Properties:
|
|
110
|
+
RoleName: "GitHubActionsRole"
|
|
111
|
+
AssumeRolePolicyDocument:
|
|
112
|
+
Version: "2012-10-17"
|
|
113
|
+
Statement:
|
|
114
|
+
- Effect: "Allow"
|
|
115
|
+
Principal:
|
|
116
|
+
Federated: !Sub "arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com"
|
|
117
|
+
Action: "sts:AssumeRoleWithWebIdentity"
|
|
118
|
+
Condition:
|
|
119
|
+
StringEquals:
|
|
120
|
+
"token.actions.githubusercontent.com:sub": !Sub "repo:${GitHubRepoName}:*"
|
|
121
|
+
Policies:
|
|
122
|
+
- PolicyName: "GitHubActionsPolicy"
|
|
123
|
+
PolicyDocument:
|
|
124
|
+
Version: "2012-10-17"
|
|
125
|
+
Statement:
|
|
126
|
+
- Effect: "Allow"
|
|
127
|
+
Action: "*"
|
|
128
|
+
Resource: "*"
|
|
129
|
+
|
|
130
|
+
Outputs:
|
|
131
|
+
GithubRoleArn:
|
|
132
|
+
Description: "ARN of the GitHub Actions IAM Role"
|
|
133
|
+
Value: !GetAtt GitHubActionsRole.Arn
|
package/commands/init_org.js
CHANGED
|
@@ -7,14 +7,14 @@ const CF = require('./helpers/cf');
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
exports.main = async function(args){
|
|
10
|
-
console.log(`Setting up ${args.name}@ in ${args.region}`)
|
|
10
|
+
console.log(`Setting up ${args.name}@ in ${args.region} with repo ${args.repo}`)
|
|
11
11
|
|
|
12
12
|
// Get VPC ID
|
|
13
13
|
const VpcId = await getDefaultVPC(args.region);
|
|
14
14
|
console.log(`Default VPC: ${VpcId}`);
|
|
15
15
|
|
|
16
16
|
// Deploy Stack
|
|
17
|
-
const success = await CF.deployOrgStack(args.region, {orgName: args.name, VpcId: VpcId})
|
|
17
|
+
const success = await CF.deployOrgStack(args.region, {orgName: args.name, VpcId: VpcId, GitHubRepoName: args.repo})
|
|
18
18
|
if (success === false){
|
|
19
19
|
console.log('ERR: Org already exists. Only one org permitted per account');
|
|
20
20
|
throw new Error('Org already exists')
|
package/commands/launch_app.js
CHANGED
|
@@ -33,7 +33,7 @@ exports.main = async function(args){
|
|
|
33
33
|
// I.I WAIT FOR AMI TO BE AVAILABLE
|
|
34
34
|
console.log(`Waiting for AMI ${targetAMI} to be available`);
|
|
35
35
|
let isAvailable = false;
|
|
36
|
-
for (let i = 0; i <
|
|
36
|
+
for (let i = 0; i < 40; i++){
|
|
37
37
|
const status = await EC2.checkAMIStatus(targetAMI,targetRegion);
|
|
38
38
|
if (status === true){
|
|
39
39
|
console.log(`AMI ${targetAMI} available after ${i*30}s`);
|
|
@@ -43,7 +43,7 @@ exports.main = async function(args){
|
|
|
43
43
|
console.log(`\tAMI Status Check ${i} @${i*30}s : Not Available`);
|
|
44
44
|
await Common.sleep(30);
|
|
45
45
|
}
|
|
46
|
-
if (!isAvailable){ throw new Error(
|
|
46
|
+
if (!isAvailable){ throw new Error(`AMI not available after 20 minutes. Try again in a few minutes.`) }
|
|
47
47
|
|
|
48
48
|
// --- II DEPLOY CF STACK ---
|
|
49
49
|
// Get Stack URL
|
package/commands/update_app.js
CHANGED
|
@@ -29,7 +29,8 @@ exports.main = async function(args){
|
|
|
29
29
|
|
|
30
30
|
// --- I PREP ZIP ---
|
|
31
31
|
const zipPath = path.resolve(args.path);
|
|
32
|
-
if (!fs.existsSync(zipPath)){ throw new Error("Path not found:" +
|
|
32
|
+
if (!fs.existsSync(zipPath)){ throw new Error("Path not found:" + zipPath)}
|
|
33
|
+
|
|
33
34
|
const zipFilePath = await prepZip(zipPath);
|
|
34
35
|
await S3.uploadInfraFile(`apps/${args.app}/${args.v}/app.zip`,zipFilePath);
|
|
35
36
|
|
|
@@ -174,7 +175,7 @@ async function waitUntilInstanceReady(instance_id,region){
|
|
|
174
175
|
let totalSleepTime = 0;
|
|
175
176
|
let ok = false;
|
|
176
177
|
const command = new DescribeInstanceStatusCommand(input);
|
|
177
|
-
for (let i=0; i<
|
|
178
|
+
for (let i=0; i<100; i++){
|
|
178
179
|
const response = await client.send(command);
|
|
179
180
|
const status = response.InstanceStatuses[0].InstanceStatus.Status;
|
|
180
181
|
console.log(`\tCheck ${i+1} @ ${totalSleepTime}s: EC2 Status is ${status}`)
|
package/main.js
CHANGED
|
@@ -11,7 +11,8 @@ const Commands = {
|
|
|
11
11
|
exec: require('./commands/init_org').main,
|
|
12
12
|
args: [
|
|
13
13
|
{n: 'name', desc: 'Unique org Name. Letters only', r: true, pattern: `[A-Za-z]{2,20}`},
|
|
14
|
-
{n: 'region', desc: 'AWS Region for Core Assets. Default us-east-1', r: false}
|
|
14
|
+
{n: 'region', desc: 'AWS Region for Core Assets. Default us-east-1', r: false},
|
|
15
|
+
{n: 'repo', desc: 'Github repo name', r: false}
|
|
15
16
|
]
|
|
16
17
|
},
|
|
17
18
|
'set-org': {
|
|
@@ -65,6 +66,16 @@ const Commands = {
|
|
|
65
66
|
{n: 'stack', desc: 'Path to updated JSON or YML stack', r: false}
|
|
66
67
|
]
|
|
67
68
|
},
|
|
69
|
+
'get-stack': {
|
|
70
|
+
desc: 'Get stack',
|
|
71
|
+
exec: require('./commands/get_stack').main,
|
|
72
|
+
args: [
|
|
73
|
+
{n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
|
|
74
|
+
{n: 'v', desc: 'Version to update', pattern: `[0-9]{1,20}`, r: false},
|
|
75
|
+
{n: 'default', desc: 'Update default version', r: false},
|
|
76
|
+
{n: 'out', desc: 'Path to output stack file', r: true}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
68
79
|
'launch': {
|
|
69
80
|
desc: 'Launch application version to an instance',
|
|
70
81
|
exec: require('./commands/launch_app').main,
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"cloudmason","version":"1.0.
|
|
1
|
+
{"name":"cloudmason","version":"1.0.11","description":"","main":"main.js","scripts":{"build":"node build.js"},"bin":{"mason":"./main.js"},"repository":{"type":"git","url":"https://github.com/kai-harvey/secure-saas.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.416.0","@aws-sdk/client-iam":"^3.418.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"}}
|
package/test.bat
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
@REM node main.js init-org -name orgTheorem -region us-west-2
|
|
2
|
-
node main.js list-apps
|
|
3
|
-
@REM node main.js new-app -name ot -type asg
|
|
4
|
-
@REM node main.js new-instance -app ot -domain local.elmnts.xyz -region us-west-2 -admin kkh@kkh.io -env local
|
|
5
|
-
@REM node main.js update-app -app ot -v 1.0 -path ./commands/starters/asg_node
|
|
6
|
-
@REM node main.js update-stack -app ot -v 1.0 -stack ./commands/helpers/stacks/asg.yaml
|
|
7
|
-
@REM node main.js launch -app ot -v 1.0 -domain local.elmnts.xyz
|
|
8
|
-
@REM node main.js inspect -app ot -domain local.elmnts.xyz -run
|
|
9
|
-
@REM node main.js isvalid -p ./commands/helpers/stacks/asg.yaml
|
|
10
|
-
|
|
11
|
-
@REM node main.js reset-stack -app meantto
|
|
12
|
-
@REM node main.js delete-instance -app ot -domain ot.elmnts.xyz
|
|
13
|
-
@REM node main.js delete-app -app inc
|
|
14
|
-
@REM aws ec2 get-console-output --instance-id i-0fba7c360fc2de96f --region us-west-2 --latest
|
|
15
|
-
|
|
16
|
-
@REM node main.js starter -type asg -l node -p ../../myfirstapp
|