cloudmason 0.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.
@@ -0,0 +1,33 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const CF = require('./helpers/cf')
4
+ const AdmZip = require("adm-zip");
5
+
6
+ exports.checkValidCF = async function(args){
7
+ const stackPath = path.resolve(args.p);
8
+ console.log('Checking ', stackPath);
9
+ if (!fs.existsSync(stackPath)){
10
+ console.log('Invalid path');
11
+ return
12
+ }
13
+ const stackStr = fs.readFileSync(stackPath,'utf-8');
14
+ const result = await CF.validateStack(stackStr);
15
+ if (result.ok){
16
+ console.log('Template seems good')
17
+ } else {
18
+ console.log(result.data)
19
+ console.log('Is not good')
20
+ }
21
+ }
22
+
23
+ exports.zip = async function(args){
24
+ const inPath = path.resolve(args.p);
25
+ if (!fs.existsSync(inPath)){
26
+ console.log('Not a valid path ' + args.p);
27
+ return
28
+ }
29
+ const zip = new AdmZip();
30
+ zip.addLocalFolder(inPath);
31
+ const outPath = path.resolve(args.o)
32
+ zip.writeZip(outPath);
33
+ }
package/main.js ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path')
4
+ const fs = require('fs')
5
+
6
+ const Commands = {
7
+ 'init-org': {
8
+ desc: "Set up a new organization",
9
+ exec: require('./commands/init_org').main,
10
+ args: [
11
+ {n: 'name', desc: 'Unique org Name. Letters only', r: true, pattern: `[A-Za-z]{2,20}`},
12
+ {n: 'domain', desc: 'Org domain. Must be valid and owned by you', r: true, pattern: `^(?!-)[a-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$`},
13
+ {n: 'region', desc: 'AWS Region for Core Assets. Default us-east-1', r: false}
14
+ ]
15
+ },
16
+ 'new-app': {
17
+ desc: 'Add a new application',
18
+ exec: require('./commands/new_app').main,
19
+ args: [
20
+ {n: 'name', desc: 'Application name (letters only)', pattern: `[A-Za-z]{2,20}`, r: true},
21
+ {n: 'type', desc: 'Architecture type: asg | static', r: true},
22
+ {n: 'node', desc: 'Nodejs version. If set, app will run using nodejs', r: false},
23
+ {n: 'py', desc: 'Python version. If set, app will run using python', r: false}
24
+ ]
25
+ },
26
+ 'new-instance': {
27
+ desc: 'Add an instance of an existing app',
28
+ exec: require('./commands/new_instance').main,
29
+ args: [
30
+ {n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
31
+ {n: 'name', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
32
+ {n: 'domain', desc: 'Domain to deploy instance behind', r: true},
33
+ {n: 'region', desc: 'Region to deploy instance in', r: true}
34
+ ]
35
+ },
36
+ 'update-app': {
37
+ desc: 'Update application',
38
+ exec: require('./commands/update_app').main,
39
+ args: [
40
+ {n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
41
+ {n: 'v', desc: 'Version to update', pattern: `[0-9]{1,20}`, r: true},
42
+ {n: 'path', desc: 'Path to app zip file or folder', r: true},
43
+ {n: 'stack', desc: 'Path to updated JSON or YML stack', r: false}
44
+ ]
45
+ },
46
+ 'launch': {
47
+ desc: 'Launch application version to an instance',
48
+ exec: require('./commands/launch_app').main,
49
+ args: [
50
+ {n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
51
+ {n: 'i', desc: 'Instance name', r: true},
52
+ {n: 'v', desc: 'Version to launch', pattern: `[0-9]{1,20}`, r: true}
53
+ ]
54
+ },
55
+ /////
56
+ 'delete-instance': {
57
+ desc: 'Delete instance',
58
+ exec: require('./commands/delete').delete_instance,
59
+ args: [
60
+ {n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true},
61
+ {n: 'i', desc: 'Instance name', r: true},
62
+ ]
63
+ },
64
+ 'reset-stack': {
65
+ desc: 'Reset app stack to default',
66
+ exec: require('./commands/reset_stack').main,
67
+ args: [
68
+ {n: 'app', desc: 'Name of existing app', pattern: `[A-Za-z]{2,20}`, r: true}
69
+ ]
70
+ },
71
+ 'list-apps': {
72
+ desc: 'List all apps',
73
+ exec: require('./commands/list_apps').main
74
+ },
75
+ 'isvalid': {
76
+ desc: 'Check if a cloudformation template is valid',
77
+ exec: require('./commands/utils').checkValidCF,
78
+ args: [
79
+ {n: 'p', desc: 'Path to cloudformation template', r: true}
80
+ ]
81
+ },
82
+ 'zip': {
83
+ desc: 'Zip a folder',
84
+ exec: require('./commands/utils').zip,
85
+ args: [
86
+ {n: 'p', desc: 'Path to folder', r: true},
87
+ {n: 'o', desc: 'Output path', r: true}
88
+ ]
89
+ }
90
+ }
91
+
92
+ async function main(){
93
+ const orgExists = readOrgInfo();
94
+ if (orgExists){
95
+ console.log(`>>>> ${process.env.orgName} <<<<`);
96
+ } else {
97
+ console.log(`No organization found. Use init-org or set-org`);
98
+ }
99
+ const args = parseArgs();
100
+ // Print info if no command given
101
+ if (!args.cmd){
102
+ printAllInfo();
103
+ return;
104
+ }
105
+ // Check for valid command
106
+ if (!Commands[args.cmd]){
107
+ console.log('Invalid command. Run without args to list commands');
108
+ return;
109
+ }
110
+ // If Command has args, but none are give, print info
111
+ if (Commands[args.cmd].args && Object.keys(args.args).length == 0){
112
+ printCmdInfo(args.cmd);
113
+ return
114
+ }
115
+
116
+ // Validate args
117
+ const valid = validateArgs(args);
118
+ if (!valid){
119
+ console.log('FAILED:Invalid Arguments')
120
+ process.exit(1);
121
+ }
122
+ // If init or set, set ENV vars
123
+ if (args.cmd == 'init-org' || args.cmd == 'set-org'){
124
+ args.args.region = process.env.orgRegion = args.args.region || 'us-east-1';
125
+ process.env.orgName = args.args.name;
126
+ process.env.orgId = args.args.domain;
127
+ } else if (!orgExists){
128
+ console.log('Run init-org or set-org first');
129
+ return
130
+ }
131
+
132
+ // Exec Command
133
+ try{
134
+ await Commands[args.cmd].exec(args.args);
135
+ } catch (e){
136
+ const errLocation = e.stack ? e.stack.split('\n')[1].replace(/.*\\/,'') : e.at;
137
+ console.log('FAILED>>' + e.message + ' @ ' + errLocation);
138
+ process.exit(1)
139
+ }
140
+ console.log('SUCCESS')
141
+ }
142
+
143
+
144
+ /////////////////////////////////
145
+ ////////////////////////////////
146
+
147
+
148
+ function readOrgInfo(){
149
+ const orgPath = path.resolve(__dirname,'org.txt');
150
+ if (fs.existsSync(orgPath)){
151
+ const orgInfo = fs.readFileSync(orgPath,'utf-8').split(',');
152
+ process.env.orgName = orgInfo[0];
153
+ process.env.orgRegion = orgInfo[1];
154
+ process.env.orgBucket = orgInfo[2];
155
+ return true;
156
+ } else {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ function parseArgs(){
162
+ var args = {
163
+ cmd: process.argv[2],
164
+ args: {}
165
+ };
166
+ for (let i=0;i<process.argv.length; i++){
167
+ if (process.argv[i][0] === '-'){
168
+ args.args[process.argv[i].replace('-','')] = null;
169
+ if (process.argv[i+1] && process.argv[i+1][0] !== '-'){
170
+ args.args[process.argv[i].replace('-','')] = process.argv[i+1];
171
+ i += 1
172
+ }
173
+ }
174
+ }
175
+ return args;
176
+ }
177
+
178
+ function printAllInfo(){
179
+ Object.entries(Commands).forEach((c)=>{
180
+ console.log(`| ${c[0]} ${c[1].desc}`)
181
+ c[1].args.forEach(a=>{
182
+ const argName = a.r ? `${a.n}*` : a.n;
183
+ console.log(`\t-${argName}: ${a.desc}`)
184
+ })
185
+ console.log('-------\n');
186
+ })
187
+ console.log('\n*required')
188
+ }
189
+
190
+ function printCmdInfo(cmd){
191
+ const comm = Commands[cmd].args;
192
+ console.log('\n' + cmd)
193
+ comm.forEach(a=>{
194
+ const argName = a.r ? `${a.n}*` : a.n;
195
+ console.log(`\t-${argName}: ${a.desc}`)
196
+ })
197
+ console.log('-------\n');
198
+ }
199
+
200
+ function validateArgs(args){
201
+ const command = Commands[args.cmd];
202
+ if (!command.args){ return true }
203
+ for (let i=0; i<command.args.length;i++){
204
+ let carg = command.args[i];
205
+ const userArg = args.args[carg.n]
206
+ if (carg.pattern && userArg){
207
+ const rgx = new RegExp(carg.pattern);
208
+ if (!rgx.test(userArg)){
209
+ console.log(`Arg ${carg.n} does not match pattern ${carg.pattern}`);
210
+ return false;
211
+ }
212
+ }
213
+ if (carg.r && !userArg){
214
+ console.log('Missing required arg ' + carg.n);
215
+ return false;
216
+ }
217
+ }
218
+ return true;
219
+ }
220
+
221
+ main();
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "cloudmason",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "main": "main.js",
6
+ "scripts": {
7
+ "build": "node build.js"
8
+ },
9
+ "bin": {
10
+ "mason": "./main.js"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/kai-harvey/secure-saas.git"
15
+ },
16
+ "author": "Kai Harvey",
17
+ "license": "ISC",
18
+ "dependencies": {
19
+ "@aws-sdk/client-acm": "^3.418.0",
20
+ "@aws-sdk/client-cloudformation": "^3.418.0",
21
+ "@aws-sdk/client-ec2": "^3.416.0",
22
+ "@aws-sdk/client-iam": "^3.418.0",
23
+ "@aws-sdk/client-route-53": "^3.425.0",
24
+ "@aws-sdk/client-s3": "^3.418.0",
25
+ "@aws-sdk/client-ssm": "^3.421.0",
26
+ "adm-zip": "^0.5.10"
27
+ }
28
+ }
package/test.bat ADDED
@@ -0,0 +1,9 @@
1
+ @REM node main.js init-org -name orgTheorem -domain orgtheorem.xyz -region us-east-2
2
+ @REM node main.js new-app -name meantto -type asg
3
+ @REM node main.js list-apps
4
+ @REM node main.js new-instance -app meantto -name test -domain mtest.orgtheorem.io -region us-east-1
5
+ @REM node main.js update-app -app meantto -v 1 -path ../SecureSaaSDemo
6
+ @REM node main.js isvalid -p ./commands/helpers/stacks/asg.yaml
7
+ @REM node main.js launch -app meantto -v 1 -i test
8
+ @REM node main.js reset-stack -app meantto
9
+ @REM node main.js delete-instance -app ssdemo -i uat