Skip to content

Commit b277710

Browse files
authored
Merge pull request #13 from cxcloud/deployment-improvements
Deployment improvements
2 parents fc81dd7 + 91d2746 commit b277710

File tree

7 files changed

+94
-34
lines changed

7 files changed

+94
-34
lines changed

lib/cxcloud-deploy.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ async function deploy(cmd) {
1414

1515
const config = await env.readDeploymentManifest();
1616

17+
// Purge action
18+
if (cmd.purge || cmd.purgeAll) {
19+
logOperation('Purging deployment...');
20+
await kube.deleteService(config, cmd.env, cmd.purgeAll);
21+
return;
22+
}
23+
24+
// Deployment action
1725
if (config.deployment) {
1826
await env.ensureDeployEnvironment();
1927
await docker.dockerLogin();
@@ -46,5 +54,7 @@ program
4654
'Comma separated list of environment variables',
4755
input => input.split(',')
4856
)
57+
.option('-p, --purge', 'Purge the deployment')
58+
.option('-x, --purge-all', 'Purge the deployment and namespace')
4959
.action(deploy)
5060
.parse(process.argv);

lib/utils/deployment.js

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const YAML = require('js-yaml');
22
const { showError } = require('./');
33

4-
const buildSSLManifest = domain => {
4+
const buildSSLManifest = (domain, namespace) => {
55
return {
66
apiVersion: 'certmanager.k8s.io/v1alpha1',
77
kind: 'Certificate',
88
metadata: {
9+
namespace,
910
name: domain
1011
},
1112
spec: {
@@ -32,12 +33,13 @@ const buildSSLManifest = domain => {
3233
const buildDeploymentRoutingManifest = config => {
3334
const { deployment } = config;
3435
const { routing } = deployment;
36+
const namespace = config.namespace || 'applications';
3537
return {
3638
apiVersion: 'extensions/v1beta1',
3739
kind: 'Ingress',
3840
metadata: {
3941
name: `${deployment.name}-routing`,
40-
namespace: 'applications',
42+
namespace,
4143
annotations: {
4244
'kubernetes.io/ingress.class': 'nginx',
4345
...(routing.ssl
@@ -78,12 +80,13 @@ const buildDeploymentRoutingManifest = config => {
7880

7981
const buildGlobalRoutingManifest = config => {
8082
const { routing } = config;
83+
const namespace = config.namespace || 'applications';
8184
return {
8285
apiVersion: 'extensions/v1beta1',
8386
kind: 'Ingress',
8487
metadata: {
8588
name: `${routing.domain}-routing`,
86-
namespace: 'applications',
89+
namespace,
8790
annotations: {
8891
'kubernetes.io/ingress.class': 'nginx',
8992
...(routing.ssl
@@ -122,6 +125,7 @@ const buildGlobalRoutingManifest = config => {
122125

123126
const buildDeploymentManifests = (config, envList = []) => {
124127
const data = config.deployment;
128+
const namespace = config.namespace || 'applications';
125129
const passedEnvs = envList
126130
.filter(item => /^([A-Z_0-9]+)=([\w\W]+)$/.test(item))
127131
.map(item => item.split('='))
@@ -148,7 +152,7 @@ const buildDeploymentManifests = (config, envList = []) => {
148152
metadata: {
149153
labels: { app: data.name, role: 'service' },
150154
name: data.name,
151-
namespace: 'applications'
155+
namespace
152156
},
153157
spec: {
154158
replicas: Number(data.replicas) || 1,
@@ -180,7 +184,7 @@ const buildDeploymentManifests = (config, envList = []) => {
180184
metadata: {
181185
labels: { app: data.name },
182186
name: data.name,
183-
namespace: 'applications'
187+
namespace
184188
},
185189
spec: {
186190
ports: [{ name: 'http', port: data.containerPort }],
@@ -190,8 +194,20 @@ const buildDeploymentManifests = (config, envList = []) => {
190194
];
191195
};
192196

197+
const buildNamespaceManifest = namespace => ({
198+
apiVersion: 'v1',
199+
kind: 'Namespace',
200+
metadata: {
201+
name: namespace
202+
}
203+
});
204+
193205
exports.getKubernetesManifest = (config, envList = []) => {
194206
const manifests = [];
207+
const namespace = config.namespace || 'applications';
208+
209+
// Push namespace, so if it's not there should be created
210+
manifests.push(buildNamespaceManifest(namespace));
195211

196212
// Single deployment
197213
if (config.deployment) {
@@ -201,24 +217,24 @@ exports.getKubernetesManifest = (config, envList = []) => {
201217
// Deployment specific routing
202218
if (config.deployment && config.deployment.routing) {
203219
if (config.deployment.routing.ssl) {
204-
manifests.push(buildSSLManifest(config.deployment.routing.domain));
220+
manifests.push(
221+
buildSSLManifest(config.deployment.routing.domain, namespace)
222+
);
205223
}
206224
manifests.push(buildDeploymentRoutingManifest(config));
207225
}
208226

209227
// Global routing
210228
if (config.routing) {
211229
if (config.routing.ssl) {
212-
manifests.push(buildSSLManifest(config.routing.domain));
230+
manifests.push(buildSSLManifest(config.routing.domain, namespace));
213231
}
214232
manifests.push(buildGlobalRoutingManifest(config));
215233
}
216234

217-
return manifests
218-
.map(json =>
219-
YAML.safeDump(json, {
220-
lineWidth: 200
221-
})
222-
)
223-
.join('\n---\n');
235+
return manifests.map(json =>
236+
YAML.safeDump(json, {
237+
lineWidth: 200
238+
})
239+
);
224240
};

lib/utils/env.js

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const getBinPath = bin => path.join(__dirname, '../../.env/bin', bin);
1313
const envAWSKeysExist = function() {
1414
const { AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY } = process.env;
1515
return AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY;
16-
}
16+
};
1717

1818
const installEnvironment = async () => {
1919
if (await fs.pathExists(path.join(__dirname, '../../.env'))) {
@@ -30,20 +30,44 @@ const installEnvironment = async () => {
3030

3131
const installRequirements = async () => {
3232
if (envAWSKeysExist()) {
33-
logOperation('AWS API key environment variables is set, `awsudo` not needed.');
34-
return;
35-
}
36-
if (await fs.pathExists(getBinPath('awsudo'))) {
33+
logOperation(
34+
'AWS API key environment variables is set, `awsudo` not needed.'
35+
);
36+
} else if (await fs.pathExists(getBinPath('awsudo'))) {
3737
logOperation('`awsudo` exists, skipping installation.');
38-
return;
38+
} else {
39+
logOperation('Installing `awsudo`...');
40+
await runCommand(getBinPath('pip'), [
41+
'-q',
42+
'install',
43+
'--upgrade',
44+
'git+https://github.com/makethunder/awsudo.git'
45+
]);
46+
}
47+
48+
if (await fs.pathExists(getBinPath('aws'))) {
49+
logOperation('`aws` exists, skipping installation.');
50+
} else {
51+
logOperation('Installing AWS CLI...');
52+
await runCommand(getBinPath('pip'), [
53+
'-q',
54+
'install',
55+
'--upgrade',
56+
'awscli'
57+
]);
3958
}
40-
logOperation('Installing `awsudo`...');
41-
await runCommand(getBinPath('pip'), [
42-
'-q',
43-
'install',
44-
'--upgrade',
45-
'git+https://github.com/makethunder/awsudo.git'
46-
]);
59+
};
60+
61+
const getEnvironmentMacros = async () => {
62+
return {
63+
GIT_BRANCH: await execa.stdout('git', [
64+
'rev-parse',
65+
'--abbrev-ref',
66+
'HEAD'
67+
]),
68+
GIT_COMMIT_ID: await execa.stdout('git', ['rev-parse', 'HEAD']),
69+
GIT_SHORT_COMMIT_ID: await execa.stdout('git', ['describe', '--always'])
70+
};
4771
};
4872

4973
exports.checkEnvironment = async () => {
@@ -60,9 +84,7 @@ exports.checkEnvironment = async () => {
6084

6185
exports.runCommandWithAWSCredentials = (cmd, args) => {
6286
if (envAWSKeysExist()) {
63-
return execa(getBinPath(cmd), [
64-
...args
65-
]);
87+
return execa(getBinPath(cmd), [...args]);
6688
} else {
6789
return execa(getBinPath('awsudo'), [
6890
'-u',
@@ -71,7 +93,7 @@ exports.runCommandWithAWSCredentials = (cmd, args) => {
7193
...args
7294
]);
7395
}
74-
}
96+
};
7597

7698
exports.getBinPath = getBinPath;
7799

@@ -104,6 +126,7 @@ exports.readDeploymentManifest = async () => {
104126
const macros = {
105127
APP_VERSION: pkg.version,
106128
APP_NAME: pkg.name,
129+
...(await getEnvironmentMacros()),
107130
...process.env
108131
};
109132
Object.keys(macros).forEach(key => {

lib/utils/kube.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,17 @@ exports.deployService = async (config, envList) => {
100100
logOperation('Deploying to cluster...');
101101
const manifest = getKubernetesManifest(config, envList);
102102
return runCommand('kubectl', ['apply', '-f', '-'], {
103-
input: manifest
103+
input: manifest.join('\n---\n')
104+
});
105+
};
106+
107+
exports.deleteService = async (config, envList, purgeNamespace = false) => {
108+
logOperation('Deploying to cluster...');
109+
const manifest = getKubernetesManifest(config, envList);
110+
const [_, ...rest] = manifest;
111+
112+
return runCommand('kubectl', ['delete', '-f', '-'], {
113+
input: (purgeNamespace === true ? manifest : rest).join('\n---\n')
104114
});
105115
};
106116

lib/utils/schemas.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const rootRoutingSchema = Joi.object().keys({
5757
});
5858

5959
exports.deploymentManifestSchema = Joi.object().keys({
60+
namespace: Joi.string().default('applications'),
6061
deployment: deploymentSchema,
6162
routing: rootRoutingSchema
6263
});

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cxcloud",
3-
"version": "0.10.0",
3+
"version": "0.11.0",
44
"description": "CXCloud command line tools",
55
"license": "MIT",
66
"repository": "cxcloud/cxcloud-cli",

0 commit comments

Comments
 (0)