diff --git a/frontend.dev b/frontend.dev deleted file mode 100644 index 9053b46..0000000 --- a/frontend.dev +++ /dev/null @@ -1,21 +0,0 @@ -AMPLIFY_DIFF_BACKEND=true -AMPLIFY_GOOGLE_CLIENT_ID=141056236022-f640rlkf9cr2r3a9o8ba58dtteq3cs9s.apps.googleusercontent.com -AMPLIFY_GOOGLE_CLIENT_SECRET=Mx477vqrCkzXq6B8ccWUZWbd -AMPLIFY_NATIVECLIENT_ID=7cp07ec16vfmqg5ac630s7qi0i -AMPLIFY_WEBCLIENT_ID=ihfvv9e562fgcbl1tuea216qc -AWS_APP_ID=d1vkfq768q89l8 -BADGR_API_URL=https://api.badgr.io -BADGR_PASSWORD=^4dcnjGkEr@H7v -BADGR_USERNAME=cwd@opentorc.com -USER_BRANCH=develop -AMPLIFY_BACKEND_PULL_ONLY=true -AMPLIFY_IDENTITYPOOL_ID=us-east-1:a07db0fb-2a62-4c81-a46d-4b7126aba2ec -AMPLIFY_USERPOOL_ID=us-east-1_FCiHbcBEu -BADGR_ISSUER_ID=AcaNX4OCQXO603pfaCg0dw -REACT_APP_CLOUDINARY_CLOUDNAME=torc -REACT_APP_GITHUB_PROVIDER_NAME=Github -USERTABLE=User-dns4s6up3nedtbiyf2zninqmm4-dev -USER_POOL_ID=us-east-1_cww7yGrWB -VIRAL_LOOPS_API_KEY=qwT8fHeH9tZg4tnCtTmaEH8WH0A -VIRAL_LOOPS_API_URL=https://app.viral-loops.com/api/v2 -REACT_APP_CLOUDINARY_UPLOAD_PRESET=torc-dev \ No newline at end of file diff --git a/package.json b/package.json index dd9bc15..6a536b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@opentorc/config-wrapper", - "version": "1.1.3", + "version": "1.2.0", "description": "config management wrapper", "main": "./src/index.js", "bin": { diff --git a/src/cli.js b/src/cli.js index 46b3cca..58da4c0 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,9 +1,11 @@ +const fs = require('fs/promises') const arg = require('arg') const inquirer = require('inquirer') const chalk = require('chalk') let pkg = require('../package.json'); -const configWrapper = require('./index') +const configWrapper = require('./index'); +const { mkdir } = require('fs'); function parseArgumentsIntoOptions(rawArgs) { @@ -13,6 +15,7 @@ function parseArgumentsIntoOptions(rawArgs) { '--oldprefix': String, '--newprefix': String, '--env': String, + '--folder': String, '--service': String, '--overwrite': Boolean, '--encrypt': Boolean, @@ -20,6 +23,7 @@ function parseArgumentsIntoOptions(rawArgs) { '-o': '--outfile', '-i': '--infile', '-e': '--env', + '-f': '--folder', '-s': '--service', '-h': '--help' },{ @@ -37,6 +41,7 @@ function parseArgumentsIntoOptions(rawArgs) { overwrite: args['--overwrite'] || false, encrypt: args['--encrypt'] || false, env: args['--env'], + folder: args['--folder'] || '', help: args['--help'] || false, command: args._[0] || '' } @@ -64,6 +69,9 @@ function displayHelp() { {bold.blue * --service} aws application service {bold.blue * --overwrite} optional flag to overwrite existing parameters {bold.blue * --encrypt} optional flag to encrypt the parameters +{underline.green exportAllParams:} export all parameters from AWS Parameter Store to hierachical folders + {bold.blue * --folder} folder to save parameters to + {bold.blue * --env} optional aws application environment `) } @@ -107,6 +115,48 @@ async function putToAWSFromFile(config) { const results = await configWrapper.awsManager.setParametersByService(params, env, service) console.log(chalk.green(`Saved ${results.length} parameters to AWS for "/torc/${env}/${service}"`)) } +async function exportAllParams(config) { + // console.log(config) + const rootFolder = config?.folder || './params' + await fs.mkdir(rootFolder, { recursive: true }) + let params = {} + const allParams = await configWrapper.awsManager.getAllOrgParams(true) + + if (config?.env) { + Object.keys(allParams).forEach((key) => { + if (key === config.env) { + console.log(`adding params for: ${key}`) + params[key] = allParams[key] + } + }) + } else { + params = allParams + } + + // console.log(params) + const envs = Object.keys(params) + + for (let i = 0; i < envs.length; ++i) { + const env = envs[i] + await fs.mkdir(`${rootFolder}/${env}`) + const services = Object.keys(params[env]) + + for (let j = 0; j < services.length; ++j) { + const service = services[j] + const aEnvVars = [] + const vars = Object.keys(params[env][service]) + + for (let k = 0; k < vars.length; ++k) { + const key = vars[k] + const param = params[env][service][key] + aEnvVars.push(`${key}=${param.value}`) + } + + console.log(`writing ${aEnvVars.length} params for ${env}/${service} to ${rootFolder}/${env}/${service}.env`) + await fs.writeFile(`${rootFolder}/${env}/${service}.env`, aEnvVars.join('\n')) + } + } + } async function promptForMissingOptions(options) { let commandFunc = null @@ -205,6 +255,18 @@ async function promptForMissingOptions(options) { } break } + case 'exportAllParams': { + commandFunc = exportAllParams + if (!options.folder) { + questions.push({ + type: 'input', + name: 'folder', + message: 'Folder: ', + default: './params', + }) + } + break + } default: { commandFunc = displayHelp return { commandFunc } diff --git a/src/lib/awsManager.js b/src/lib/awsManager.js index e11fb45..8cb35dc 100644 --- a/src/lib/awsManager.js +++ b/src/lib/awsManager.js @@ -93,10 +93,107 @@ async function setParametersByService(params, env, service) { return data } +async function getEnvironments() { + console.log(`Getting environments descending from ${BASE_PATH}`) + var config = { + Path: BASE_PATH, + Recursive: true + }; + + const envs = {} + let nextToken = null + + do { + let params = await ssm.getParametersByPath(config).promise() + + for (let i = 0; i < params.Parameters.length; i++) { + const param = params.Parameters[i] + const name = param.Name.split('/') + const env = name[2] + envs[env] = envs[env]? envs[env]+1 : 1 + } + + params = await ssm.getParametersByPath(config).promise() + nextToken = params.NextToken + config.NextToken = nextToken + } while (nextToken) + + return envs +} + +async function getServicesForEnvironment(env) { + const Path = BASE_PATH + '/' + env + console.log(`Getting services descending from the environment ${Path}`) + var config = { + Path, + Recursive: true + }; + + const svcs = {} + let nextToken = null + + do { + let params = await ssm.getParametersByPath(config).promise() + + for (let i = 0; i < params.Parameters.length; i++) { + const param = params.Parameters[i] + const name = param.Name.split('/') + const svc = name[3] + svcs[svc] = svcs[svc] ? svcs[svc] + 1 : 1 + } + + params = await ssm.getParametersByPath(config).promise() + nextToken = params.NextToken + config.NextToken = nextToken + } while (nextToken) + + return svcs +} + +async function getAllOrgParams(isEncrypted) { + console.log(`Getting all parameters under ${BASE_PATH}`) + var config = { + Path: BASE_PATH, + Recursive: true, + WithDecryption: isEncrypted + }; + + const convertedParams = {} + let nextToken = null + + do { + let params = await ssm.getParametersByPath(config).promise() + + for (let i = 0; i < params.Parameters.length; i++) { + const param = restructureParam(params.Parameters[i]) + const name = params.Parameters[i].Name.split('/') + + if (!convertedParams[name[2]]) { + convertedParams[name[2]] = {} + } + + if (!convertedParams[name[2]][name[3]]) { + convertedParams[name[2]][name[3]] = {} + } + + convertedParams[name[2]][name[3]][param.name] = param + } + + params = await ssm.getParametersByPath(config).promise() + nextToken = params.NextToken + config.NextToken = nextToken + } while (nextToken) + + return convertedParams +} + module.exports = { constructParamPath, getParameter, getParametersByService, setParameter, - setParametersByService + setParametersByService, + getEnvironments, + getServicesForEnvironment, + getAllOrgParams } \ No newline at end of file diff --git a/tests/index.js b/tests/index.js index f81a515..70d57bc 100644 --- a/tests/index.js +++ b/tests/index.js @@ -152,6 +152,36 @@ describe('awsManager', async () => { } }) }) + + describe('getEnvironments', async () => { + it('should get all the environments', async () => { + const envs = await awsManager.getEnvironments() + console.log(envs) + should.exist(envs.test) + envs.test.should.equal(4) + }) + }) + + describe('getServicesForEnvironment', async () => { + it('should get all the services in an environment', async () => { + const svcs = await awsManager.getServicesForEnvironment('test') + console.log(svcs) + should.exist(svcs['config-wrapper']) + svcs['config-wrapper'].should.equal(4) + }) + }) + + describe('getAllOrgParams', async () => { + it('should get all the org parameters', async () => { + const params = await awsManager.getAllOrgParams() + console.log(params) + should.exist(params.test) + should.exist(params.test['config-wrapper']) + Object.keys(params.test['config-wrapper']).should.have.lengthOf(4) + params.test['config-wrapper'].should.have.property('testParam01') + params.test['config-wrapper'].should.have.property('secretParam01') + }) + }) })