Skip to content

Commit bcf321f

Browse files
Cr 4204 helm values (#649)
Helm value flag for hybrid agent installation.
1 parent 0bec1be commit bcf321f

File tree

4 files changed

+183
-7
lines changed

4 files changed

+183
-7
lines changed

lib/interface/cli/commands/hybrid/init.cmd.js

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* eslint-disable max-len */
2+
const fs = require('fs');
3+
24
const Command = require('../../Command');
35
const runnerRoot = require('../root/runner.cmd');
46
const inquirer = require('inquirer');
@@ -36,13 +38,14 @@ const {
3638
INSTALLATION_DEFAULTS,
3739
} = require('./helper');
3840
const InstallationPlan = require('./InstallationPlan');
41+
const { produceVenonaKeys } = require('./key-helper');
3942
const { array } = require('yargs');
4043

4144
const defaultDockerRegistry = 'quay.io';
4245
const handleError = createErrorHandler(`\nIf you had any issues with the installation please report them at: ${colors.blue('https://github.com/codefresh-io/cli/issues/new')}`);
4346

4447
async function isNewAccount() {
45-
const [pipelines, err] = await to(sdk.pipelines.list({ }));
48+
const [pipelines, err] = await to(sdk.pipelines.list({}));
4649
if (!err && _.isArray(_.get(pipelines, 'docs'))) {
4750
return !pipelines.docs.length;
4851
}
@@ -61,6 +64,7 @@ function printInstallationOptionsSummary({
6164
appProxy,
6265
appProxyHost,
6366
dryRun,
67+
shouldUseHelm,
6468
}) {
6569
let summary = `\n${colors.green('Installation options summary:')}
6670
1. Kubernetes Context: ${colors.cyan(kubeContextName)}
@@ -78,6 +82,9 @@ function printInstallationOptionsSummary({
7882
if (dryRun) {
7983
summary += '**** running in dry-run mode ****';
8084
}
85+
if (shouldUseHelm) {
86+
summary += '**** running in helm values generation mode ****';
87+
}
8188
console.log(summary);
8289
}
8390

@@ -104,6 +111,10 @@ const initCmd = new Command({
104111
.option('url', {
105112
describe: 'Codefresh system custom url',
106113
})
114+
.option('generate-helm-values-file', {
115+
describe: 'Path to the new generated helm values file',
116+
type: 'string',
117+
})
107118
.option('kube-context-name', {
108119
describe: 'Name of the Kubernetes context on which runner should be installed [$CF_ARG_KUBE_CONTEXT_NAME]',
109120
})
@@ -246,6 +257,7 @@ const initCmd = new Command({
246257
const {
247258
'kube-node-selector': kubeNodeSelector,
248259
'build-node-selector': buildNodeSelector,
260+
'generate-helm-values-file': helmValuesFile,
249261
tolerations,
250262
'kube-config-path': kubeConfigPath,
251263
'storage-class-name': storageClassName,
@@ -274,6 +286,9 @@ const initCmd = new Command({
274286
'dry-run': dryRun,
275287
'bypass-download': bypassDownload
276288
} = _argv;
289+
290+
const shouldUseHelm = !!helmValuesFile;
291+
277292
let {
278293
'kube-context-name': kubeContextName,
279294
'kube-namespace': kubeNamespace,
@@ -303,6 +318,10 @@ const initCmd = new Command({
303318
httpsProxy = httpsProxy || detectedProxyVars.httpsProxy;
304319
noProxy = noProxy || detectedProxyVars.noProxy;
305320

321+
if (shouldUseHelm) {
322+
shouldExecutePipeline = false;
323+
}
324+
306325
if (noQuestions) {
307326
// use defaults
308327
kubeContextName = kubeContextName || getKubeContext(kubeConfigPath);
@@ -420,6 +439,7 @@ const initCmd = new Command({
420439
appProxy,
421440
appProxyHost,
422441
dryRun,
442+
shouldUseHelm,
423443
});
424444

425445
if (token) {
@@ -538,6 +558,7 @@ const initCmd = new Command({
538558
},
539559
installationEvent: installationProgress.events.AGENT_INSTALLED,
540560
executeOnDryRun: true,
561+
condition: !shouldUseHelm,
541562
});
542563

543564
// generate new runtime name
@@ -709,6 +730,7 @@ const initCmd = new Command({
709730
},
710731
installationEvent: installationProgress.events.RUNTIME_INSTALLED,
711732
executeOnDryRun: true,
733+
condition: !shouldUseHelm,
712734
});
713735

714736
installationPlan.addStep({
@@ -733,7 +755,7 @@ const initCmd = new Command({
733755
installationPlan.addContext('appProxyIP', `${appProxyUrl}`);
734756
},
735757
installationEvent: installationProgress.events.APP_PROXY_INSTALLED,
736-
condition: !!appProxy,
758+
condition: !!appProxy && !shouldUseHelm,
737759
executeOnDryRun: true,
738760
});
739761

@@ -751,7 +773,13 @@ const initCmd = new Command({
751773
await sdk.runtimeEnvs.update({ name: reName }, _.merge(re, body));
752774
console.log(`Runtime environment "${colors.cyan(reName)}" has been updated with the app proxy`);
753775
},
754-
condition: async () => installationPlan.getContext('appProxyIP'),
776+
condition: async () => {
777+
if (shouldUseHelm) {
778+
return false;
779+
}
780+
781+
return installationPlan.getContext('appProxyIP');
782+
},
755783
});
756784

757785
// update agent with new runtime
@@ -802,6 +830,7 @@ const initCmd = new Command({
802830
},
803831
installationEvent: installationProgress.events.RUNNER_INSTALLED,
804832
executeOnDryRun: true,
833+
condition: !shouldUseHelm,
805834
});
806835

807836
// install monitoring
@@ -829,6 +858,10 @@ const initCmd = new Command({
829858
installationEvent: installationProgress.events.MONITOR_INSTALLED,
830859
executeOnDryRun: true,
831860
condition: async () => {
861+
if (shouldUseHelm) {
862+
return false;
863+
}
864+
832865
if (!installMonitor) {
833866
return false;
834867
}
@@ -842,10 +875,47 @@ const initCmd = new Command({
842875
},
843876
});
844877

878+
// helm value files if its enabled
879+
installationPlan.addStep({
880+
name: 'generate helm value files',
881+
func: async () => {
882+
const runtimeNameContext = installationPlan.getContext('runtimeName');
883+
const agent = installationPlan.getContext('agent');
884+
885+
const keys = await produceVenonaKeys(
886+
_.get(sdk, 'config.context.token'),
887+
kubeNamespace,
888+
);
889+
890+
const global = {
891+
namespace: kubeNamespace,
892+
codefreshHost: sdk.config.context.url,
893+
agentToken: agent.token,
894+
agentId: agent.id,
895+
agentName: agent.name,
896+
accountId: agent.account,
897+
runtimeName: runtimeNameContext,
898+
keys,
899+
};
900+
901+
const content = JSON.stringify({ global }, null, 4);
902+
903+
fs.writeFileSync(
904+
helmValuesFile,
905+
content,
906+
{
907+
encoding: 'utf8',
908+
},
909+
);
910+
},
911+
condition: shouldUseHelm,
912+
});
913+
845914
// Post Installation
846915
if (shouldExecutePipeline) {
847916
const pipelines = await sdk.pipelines.list({ id: `${INSTALLATION_DEFAULTS.PROJECT_NAME}/${INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME}` });
848917
const testPipelineExists = !!_.get(pipelines, 'docs.length');
918+
849919
if (!testPipelineExists) {
850920
installationPlan.addStep({
851921
name: 'create test pipeline',
@@ -876,6 +946,7 @@ const initCmd = new Command({
876946
exitOnError: false,
877947
});
878948
}
949+
879950
installationPlan.addStep({
880951
name: 'execute test pipeline',
881952
func: async () => {
@@ -891,9 +962,12 @@ const initCmd = new Command({
891962

892963
await installationPlan.execute();
893964

894-
console.log(colors.green('\nRunner Status:'));
895-
await getAgents.handler({});
896-
console.log('');
965+
if (!shouldUseHelm) {
966+
console.log(colors.green('\nRunner Status:'));
967+
await getAgents.handler({});
968+
console.log('');
969+
}
970+
897971
if (installMonitor) {
898972
console.log(`Go to ${colors.blue('https://g.codefresh.io/kubernetes/services/')} to view your cluster in Codefresh dashbaord`);
899973
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
const forge = require('node-forge');
2+
const rp = require('request-promise');
3+
const AdmZip = require('adm-zip');
4+
5+
const sdk = require('../../../../logic/sdk');
6+
// eslint-disable-next-line prefer-destructuring
7+
const pki = forge.pki;
8+
// eslint-disable-next-line prefer-destructuring
9+
const rsa = pki.rsa;
10+
11+
const defaultCertCN = 'docker.codefresh.io';
12+
13+
function generateKeys() {
14+
return new Promise((resolve, reject) => {
15+
function keyGenerated(err, { publicKey, privateKey }) {
16+
if (err) {
17+
reject(err);
18+
return;
19+
}
20+
21+
const csr = pki.createCertificationRequest();
22+
csr.publicKey = publicKey;
23+
csr.setSubject([{
24+
name: 'commonName',
25+
value: defaultCertCN,
26+
}]);
27+
csr.sign(privateKey);
28+
29+
resolve({
30+
key: pki.privateKeyToPem(privateKey),
31+
csr: pki.certificationRequestToPem(csr),
32+
});
33+
}
34+
35+
rsa.generateKeyPair({
36+
bits: 2048,
37+
}, keyGenerated);
38+
});
39+
}
40+
41+
function extractZipCerts(zip) {
42+
const data = {};
43+
const admZip = new AdmZip(zip);
44+
admZip.forEach(e => {
45+
if (e.entryName === 'cf-ca.pem') {
46+
data.ca = admZip.readAsText(e);
47+
}
48+
if (e.entryName === 'cf-server-cert.pem') {
49+
data.serverCert = admZip.readAsText(e);
50+
}
51+
});
52+
return data;
53+
}
54+
55+
async function produceVenonaKeys(namespace) {
56+
const keys = await generateKeys();
57+
const body = JSON.stringify({
58+
reqSubjectAltName: `IP:127.0.0.1,DNS:dind,DNS:*.dind.${namespace},DNS:*.dind.${namespace}.svc,DNS:*.cf-cd.com,DNS:*.codefresh.io`,
59+
csr: keys.csr,
60+
});
61+
62+
const zip = await rp.post({
63+
uri: `${sdk.config.context.url}/api/custom_clusters/signServerCerts`,
64+
body,
65+
encoding: null,
66+
headers: {
67+
'Content-type': 'application/json',
68+
Authorization: sdk.config.context.token,
69+
},
70+
});
71+
72+
const allKeys = {
73+
...keys,
74+
...extractZipCerts(zip),
75+
};
76+
77+
return allKeys;
78+
}
79+
80+
module.exports = {
81+
produceVenonaKeys,
82+
};

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codefresh",
3-
"version": "0.75.13",
3+
"version": "0.75.14",
44
"description": "Codefresh command line utility",
55
"main": "index.js",
66
"preferGlobal": true,
@@ -31,6 +31,7 @@
3131
},
3232
"dependencies": {
3333
"@codefresh-io/docker-reference": "^0.0.5",
34+
"adm-zip": "^0.5.5",
3435
"ajv": "^6.6.1",
3536
"bluebird": "^3.5.1",
3637
"cf-errors": "^0.1.12",
@@ -61,6 +62,7 @@
6162
"mkdirp": "^0.5.1",
6263
"moment": "^2.19.4",
6364
"mongodb": "^3.0.1",
65+
"node-forge": "^0.10.0",
6466
"ora": "^3.0.0",
6567
"prettyjson": "^1.2.1",
6668
"promise-retry": "^2.0.1",
@@ -76,6 +78,7 @@
7678
"yargs-parser": "^13.0.0"
7779
},
7880
"devDependencies": {
81+
"@types/node-forge": "^0.9.7",
7982
"eslint": "^4.11.0",
8083
"eslint-config-airbnb-base": "^12.1.0",
8184
"eslint-plugin-import": "^2.8.0",

yarn.lock

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@
128128
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
129129
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
130130

131+
"@types/node-forge@^0.9.7":
132+
version "0.9.7"
133+
resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.9.7.tgz#948f7b52d352a6c4ab22d3328c206f0870672db5"
134+
integrity sha512-AX7Mqk5ztzSvxqsA/q8y0k0/znJpW6QAqnoLQMEi7A3tio+laRmC/8Q3gbATHT4kZnvhnDmGAy1CpWFzlzCfeA==
135+
dependencies:
136+
"@types/node" "*"
137+
131138
"@types/node@*":
132139
version "14.0.1"
133140
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c"
@@ -230,6 +237,11 @@ acorn@^6.0.1:
230237
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
231238
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
232239

240+
adm-zip@^0.5.5:
241+
version "0.5.5"
242+
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.5.tgz#b6549dbea741e4050309f1bb4d47c47397ce2c4f"
243+
integrity sha512-IWwXKnCbirdbyXSfUDvCCrmYrOHANRZcc8NcRrvTlIApdl7PwE9oGcsYvNeJPAVY1M+70b4PxXGKIf8AEuiQ6w==
244+
233245
aggregate-error@^3.0.0:
234246
version "3.0.1"
235247
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0"
@@ -3984,6 +3996,11 @@ node-fetch@2.6.1:
39843996
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
39853997
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
39863998

3999+
node-forge@^0.10.0:
4000+
version "0.10.0"
4001+
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
4002+
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
4003+
39874004
node-int64@^0.4.0:
39884005
version "0.4.0"
39894006
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"

0 commit comments

Comments
 (0)