From 9b8b105eff3e993817324a1cea72ce73585fb6c5 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 10:09:37 +0200 Subject: [PATCH 1/7] Add namespace detection --- lib/utils/deployment.js | 23 +++++++++++++++++++---- lib/utils/schemas.js | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/utils/deployment.js b/lib/utils/deployment.js index 78e0a69..266663a 100644 --- a/lib/utils/deployment.js +++ b/lib/utils/deployment.js @@ -32,12 +32,13 @@ const buildSSLManifest = domain => { const buildDeploymentRoutingManifest = config => { const { deployment } = config; const { routing } = deployment; + const namespace = config.namespace || 'applications'; return { apiVersion: 'extensions/v1beta1', kind: 'Ingress', metadata: { name: `${deployment.name}-routing`, - namespace: 'applications', + namespace, annotations: { 'kubernetes.io/ingress.class': 'nginx', ...(routing.ssl @@ -78,12 +79,13 @@ const buildDeploymentRoutingManifest = config => { const buildGlobalRoutingManifest = config => { const { routing } = config; + const namespace = config.namespace || 'applications'; return { apiVersion: 'extensions/v1beta1', kind: 'Ingress', metadata: { name: `${routing.domain}-routing`, - namespace: 'applications', + namespace, annotations: { 'kubernetes.io/ingress.class': 'nginx', ...(routing.ssl @@ -122,6 +124,7 @@ const buildGlobalRoutingManifest = config => { const buildDeploymentManifests = (config, envList = []) => { const data = config.deployment; + const namespace = config.namespace || 'applications'; const passedEnvs = envList .filter(item => /^([A-Z_0-9]+)=([\w\W]+)$/.test(item)) .map(item => item.split('=')) @@ -148,7 +151,7 @@ const buildDeploymentManifests = (config, envList = []) => { metadata: { labels: { app: data.name, role: 'service' }, name: data.name, - namespace: 'applications' + namespace }, spec: { replicas: Number(data.replicas) || 1, @@ -180,7 +183,7 @@ const buildDeploymentManifests = (config, envList = []) => { metadata: { labels: { app: data.name }, name: data.name, - namespace: 'applications' + namespace }, spec: { ports: [{ name: 'http', port: data.containerPort }], @@ -190,8 +193,20 @@ const buildDeploymentManifests = (config, envList = []) => { ]; }; +const buildNamespaceManifest = namespace => ({ + apiVersion: 'v1', + kind: 'Namespace', + metadata: { + name: namespace + } +}); + exports.getKubernetesManifest = (config, envList = []) => { const manifests = []; + const namespace = config.namespace || 'applications'; + + // Push namespace, so if it's not there should be created + manifests.push(buildNamespaceManifest(namespace)); // Single deployment if (config.deployment) { diff --git a/lib/utils/schemas.js b/lib/utils/schemas.js index 3185bcf..69fee13 100644 --- a/lib/utils/schemas.js +++ b/lib/utils/schemas.js @@ -57,6 +57,7 @@ const rootRoutingSchema = Joi.object().keys({ }); exports.deploymentManifestSchema = Joi.object().keys({ + namespace: Joi.string().default('applications'), deployment: deploymentSchema, routing: rootRoutingSchema }); From 98fa5fd444f1e479ec3881d9274a586e26d73da6 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 10:11:10 +0200 Subject: [PATCH 2/7] 0.11.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66de54e..b56a249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cxcloud", - "version": "0.10.0", + "version": "0.11.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 76bbb3a..fb70a32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cxcloud", - "version": "0.10.0", + "version": "0.11.0", "description": "CXCloud command line tools", "license": "MIT", "repository": "cxcloud/cxcloud-cli", From 9148784269008da4939b1e785ddff03aaae8768b Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 10:51:56 +0200 Subject: [PATCH 3/7] Add more environment variables --- lib/utils/deployment.js | 9 ++++++--- lib/utils/env.js | 25 +++++++++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/utils/deployment.js b/lib/utils/deployment.js index 266663a..fa89975 100644 --- a/lib/utils/deployment.js +++ b/lib/utils/deployment.js @@ -1,11 +1,12 @@ const YAML = require('js-yaml'); const { showError } = require('./'); -const buildSSLManifest = domain => { +const buildSSLManifest = (domain, namespace) => { return { apiVersion: 'certmanager.k8s.io/v1alpha1', kind: 'Certificate', metadata: { + namespace, name: domain }, spec: { @@ -216,7 +217,9 @@ exports.getKubernetesManifest = (config, envList = []) => { // Deployment specific routing if (config.deployment && config.deployment.routing) { if (config.deployment.routing.ssl) { - manifests.push(buildSSLManifest(config.deployment.routing.domain)); + manifests.push( + buildSSLManifest(config.deployment.routing.domain, namespace) + ); } manifests.push(buildDeploymentRoutingManifest(config)); } @@ -224,7 +227,7 @@ exports.getKubernetesManifest = (config, envList = []) => { // Global routing if (config.routing) { if (config.routing.ssl) { - manifests.push(buildSSLManifest(config.routing.domain)); + manifests.push(buildSSLManifest(config.routing.domain, namespace)); } manifests.push(buildGlobalRoutingManifest(config)); } diff --git a/lib/utils/env.js b/lib/utils/env.js index 2b3aab7..41149fc 100644 --- a/lib/utils/env.js +++ b/lib/utils/env.js @@ -13,7 +13,7 @@ const getBinPath = bin => path.join(__dirname, '../../.env/bin', bin); const envAWSKeysExist = function() { const { AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY } = process.env; return AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY; -} +}; const installEnvironment = async () => { if (await fs.pathExists(path.join(__dirname, '../../.env'))) { @@ -30,7 +30,9 @@ const installEnvironment = async () => { const installRequirements = async () => { if (envAWSKeysExist()) { - logOperation('AWS API key environment variables is set, `awsudo` not needed.'); + logOperation( + 'AWS API key environment variables is set, `awsudo` not needed.' + ); return; } if (await fs.pathExists(getBinPath('awsudo'))) { @@ -46,6 +48,18 @@ const installRequirements = async () => { ]); }; +const getEnvironmentMacros = async () => { + return { + GIT_BRANCH: await execa.stdout('git', [ + 'rev-parse', + '--abbrev-ref', + 'HEAD' + ]), + GIT_COMMIT_ID: await execa.stdout('git', ['rev-parse', 'HEAD']), + GIT_SHORT_COMMIT_ID: await execa.stdout('git', ['describe', '--always']) + }; +}; + exports.checkEnvironment = async () => { if (!process.env.AWS_PROFILE && !envAWSKeysExist()) { return showError( @@ -60,9 +74,7 @@ exports.checkEnvironment = async () => { exports.runCommandWithAWSCredentials = (cmd, args) => { if (envAWSKeysExist()) { - return execa(getBinPath(cmd), [ - ...args - ]); + return execa(getBinPath(cmd), [...args]); } else { return execa(getBinPath('awsudo'), [ '-u', @@ -71,7 +83,7 @@ exports.runCommandWithAWSCredentials = (cmd, args) => { ...args ]); } -} +}; exports.getBinPath = getBinPath; @@ -104,6 +116,7 @@ exports.readDeploymentManifest = async () => { const macros = { APP_VERSION: pkg.version, APP_NAME: pkg.name, + ...(await getEnvironmentMacros()), ...process.env }; Object.keys(macros).forEach(key => { From b439336a4b331df945556e9c44441869b1971911 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 11:29:28 +0200 Subject: [PATCH 4/7] Install AWS if it's not installed --- lib/utils/env.js | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/utils/env.js b/lib/utils/env.js index 41149fc..267d641 100644 --- a/lib/utils/env.js +++ b/lib/utils/env.js @@ -33,19 +33,29 @@ const installRequirements = async () => { logOperation( 'AWS API key environment variables is set, `awsudo` not needed.' ); - return; - } - if (await fs.pathExists(getBinPath('awsudo'))) { + } else if (await fs.pathExists(getBinPath('awsudo'))) { logOperation('`awsudo` exists, skipping installation.'); - return; + } else { + logOperation('Installing `awsudo`...'); + await runCommand(getBinPath('pip'), [ + '-q', + 'install', + '--upgrade', + 'git+https://github.com/makethunder/awsudo.git' + ]); + } + + if (await fs.pathExists(getBinPath('aws'))) { + logOperation('`aws` exists, skipping installation.'); + } else { + logOperation('Installing AWS CLI...'); + await runCommand(getBinPath('pip'), [ + '-q', + 'install', + '--upgrade', + 'awscli' + ]); } - logOperation('Installing `awsudo`...'); - await runCommand(getBinPath('pip'), [ - '-q', - 'install', - '--upgrade', - 'git+https://github.com/makethunder/awsudo.git' - ]); }; const getEnvironmentMacros = async () => { From c093744cf14a518e1ce842243ae16f4db6755693 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 11:54:58 +0200 Subject: [PATCH 5/7] Purge deployment action --- lib/cxcloud-deploy.js | 9 +++++++++ lib/cxcloud.js | 2 +- lib/utils/kube.js | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/cxcloud-deploy.js b/lib/cxcloud-deploy.js index 26a8b3e..98a5bdb 100644 --- a/lib/cxcloud-deploy.js +++ b/lib/cxcloud-deploy.js @@ -14,6 +14,14 @@ async function deploy(cmd) { const config = await env.readDeploymentManifest(); + // Purge action + if (cmd.purge) { + logOperation('Purging deployment...'); + kube.deleteService(config, cmd.env); + return; + } + + // Deployment action if (config.deployment) { await env.ensureDeployEnvironment(); await docker.dockerLogin(); @@ -46,5 +54,6 @@ program 'Comma separated list of environment variables', input => input.split(',') ) + .option('-p, --purge', 'Purge the deployment') .action(deploy) .parse(process.argv); diff --git a/lib/cxcloud.js b/lib/cxcloud.js index f0a33af..d3ff426 100755 --- a/lib/cxcloud.js +++ b/lib/cxcloud.js @@ -7,6 +7,6 @@ const pkg = require('../package.json'); program .version(pkg.version) .command('generate [type]', 'code generator') - .command('deploy', 'deploy the current application or service'); + .command('deploy [action]', 'deploy the current application or service'); program.parse(process.argv); diff --git a/lib/utils/kube.js b/lib/utils/kube.js index 8cf6365..6614895 100644 --- a/lib/utils/kube.js +++ b/lib/utils/kube.js @@ -104,6 +104,14 @@ exports.deployService = async (config, envList) => { }); }; +exports.deleteService = async (config, envList) => { + logOperation('Deploying to cluster...'); + const manifest = getKubernetesManifest(config, envList); + return runCommand('kubectl', ['delete', '-f', '-'], { + input: manifest + }); +}; + exports.getIngressInfo = async config => { const { name } = config.deployment; return runCommand('kubectl', [ From a133934fc45a24f0ddf9ffc45d431e59e1cc6d50 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 12:24:49 +0200 Subject: [PATCH 6/7] Purge services --- lib/cxcloud-deploy.js | 5 +++-- lib/utils/deployment.js | 12 +++++------- lib/utils/kube.js | 8 +++++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/cxcloud-deploy.js b/lib/cxcloud-deploy.js index 98a5bdb..1d83731 100644 --- a/lib/cxcloud-deploy.js +++ b/lib/cxcloud-deploy.js @@ -15,9 +15,9 @@ async function deploy(cmd) { const config = await env.readDeploymentManifest(); // Purge action - if (cmd.purge) { + if (cmd.purge || cmd.purgeAll) { logOperation('Purging deployment...'); - kube.deleteService(config, cmd.env); + await kube.deleteService(config, cmd.env, cmd.purgeAll); return; } @@ -55,5 +55,6 @@ program input => input.split(',') ) .option('-p, --purge', 'Purge the deployment') + .option('-x, --purge-all', 'Purge the deployment and namespace') .action(deploy) .parse(process.argv); diff --git a/lib/utils/deployment.js b/lib/utils/deployment.js index fa89975..72b76a5 100644 --- a/lib/utils/deployment.js +++ b/lib/utils/deployment.js @@ -232,11 +232,9 @@ exports.getKubernetesManifest = (config, envList = []) => { manifests.push(buildGlobalRoutingManifest(config)); } - return manifests - .map(json => - YAML.safeDump(json, { - lineWidth: 200 - }) - ) - .join('\n---\n'); + return manifests.map(json => + YAML.safeDump(json, { + lineWidth: 200 + }) + ); }; diff --git a/lib/utils/kube.js b/lib/utils/kube.js index 6614895..ce5e219 100644 --- a/lib/utils/kube.js +++ b/lib/utils/kube.js @@ -100,15 +100,17 @@ exports.deployService = async (config, envList) => { logOperation('Deploying to cluster...'); const manifest = getKubernetesManifest(config, envList); return runCommand('kubectl', ['apply', '-f', '-'], { - input: manifest + input: manifest.join('\n---\n') }); }; -exports.deleteService = async (config, envList) => { +exports.deleteService = async (config, envList, purgeNamespace = false) => { logOperation('Deploying to cluster...'); const manifest = getKubernetesManifest(config, envList); + const [_, ...rest] = manifest; + return runCommand('kubectl', ['delete', '-f', '-'], { - input: manifest + input: (purgeNamespace === true ? manifest : rest).join('\n---\n') }); }; From 91d274626a328123b2a838c16f4c4d30c9a0bcf9 Mon Sep 17 00:00:00 2001 From: Sallar Kaboli Date: Tue, 29 Jan 2019 12:26:54 +0200 Subject: [PATCH 7/7] Remove extra flag --- lib/cxcloud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cxcloud.js b/lib/cxcloud.js index d3ff426..f0a33af 100755 --- a/lib/cxcloud.js +++ b/lib/cxcloud.js @@ -7,6 +7,6 @@ const pkg = require('../package.json'); program .version(pkg.version) .command('generate [type]', 'code generator') - .command('deploy [action]', 'deploy the current application or service'); + .command('deploy', 'deploy the current application or service'); program.parse(process.argv);