Skip to content

Commit 971d932

Browse files
author
Oleg Sucharevich
authored
add test cluster cmd (#142)
1 parent 1afe2cb commit 971d932

File tree

9 files changed

+292
-21
lines changed

9 files changed

+292
-21
lines changed

lib/binary/components.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module.exports = {
2+
stevedore: {
3+
name: 'Stevedore',
4+
description: 'Integrate clusters to Codefresh',
5+
version: {
6+
prefix: 'v',
7+
},
8+
local: {
9+
versionFile: 'version.txt',
10+
dir: 'Stevedore',
11+
binary: 'stevedore',
12+
},
13+
remote: {
14+
versionPath: '/',
15+
versionFile: 'VERSION',
16+
branch: 'master',
17+
repo: 'Stevedore',
18+
},
19+
},
20+
venona: {
21+
name: 'venona',
22+
description: 'Install required assets on Kubernetes cluster',
23+
version: {
24+
prefix: '',
25+
},
26+
local: {
27+
versionFile: 'version.txt',
28+
dir: 'agent',
29+
binary: 'venona',
30+
},
31+
remote: {
32+
versionPath: 'venonactl',
33+
versionFile: 'VERSION',
34+
branch: 'release-1.0',
35+
repo: 'venona',
36+
},
37+
},
38+
};

lib/binary/downloader.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
const Promise = require('bluebird');
2+
const _ = require('lodash');
3+
const decompress = require('decompress');
4+
const decompressTargz = require('decompress-targz');
5+
const decompressUnzip = require('decompress-unzip');
6+
const rp = require('request-promise');
7+
const request = require('request');
8+
const compareVersions = require('compare-versions');
9+
const {
10+
resolve, join,
11+
} = require('path');
12+
const {
13+
homedir, arch,
14+
} = require('os');
15+
const {
16+
existsSync, mkdirSync, readFileSync, createWriteStream, writeFile,
17+
} = require('fs');
18+
const { to } = require('./../logic/cli-config/errors/awaitTo');
19+
20+
const CODEFRESH_PATH = resolve(homedir(), '.Codefresh');
21+
22+
function _ensureDirectory(location) {
23+
if (existsSync(location)) {
24+
return Promise.resolve();
25+
}
26+
mkdirSync(location);
27+
return Promise.resolve();
28+
}
29+
30+
async function _getRemoteVersion({
31+
name, branch, path, file,
32+
}) {
33+
const final = branch ? `${name}/${branch}/${path}` : `${name}/${path}`;
34+
const url = `https://raw.githubusercontent.com/codefresh-io/${final}/${file}`;
35+
const req = await rp({
36+
url,
37+
method: 'GET',
38+
headers: { 'User-Agent': 'codefresh' },
39+
});
40+
return req;
41+
}
42+
43+
function _buildDownloadURL({ name, version, binary }) {
44+
return `https://github.com/codefresh-io/${name}/releases/download/${version}/${binary}`;
45+
}
46+
47+
function _getLocalVersion(location) {
48+
if (!existsSync(location)) {
49+
return '0';
50+
}
51+
const content = readFileSync(location, { encoding: 'UTF8' }).trim();
52+
if (content === '') {
53+
return '0';
54+
}
55+
return content;
56+
}
57+
58+
function _buildLocalOSProperties() {
59+
let osType;
60+
let osSuffix;
61+
const { platform } = process;
62+
if (_.isEqual(platform, 'darwin')) {
63+
osType = _.isEqual(arch(), 'x32') ? 'Darwin_i386.tar.gz' : 'Darwin_x86_64.tar.gz';
64+
osSuffix = 'tar.gz';
65+
} else if (_.isEqual(platform, 'linux')) {
66+
osType = _.isEqual(arch(), 'x32') ? 'Linux_i386.tar.gz' : 'Linux_x86_64.tar.gz';
67+
osSuffix = 'tar.gz';
68+
} else if (_.isEqual(platform, 'win32')) {
69+
osType = _.isEqual(arch(), 'x32') ? 'Windows_i386.zip' : 'Windows_x86_64.zip';
70+
osSuffix = 'zip';
71+
}
72+
73+
return {
74+
osType,
75+
osSuffix,
76+
};
77+
}
78+
79+
async function _writeFiles({
80+
zipPath, location, version, versionPath,
81+
}) {
82+
await to(decompress(zipPath, location, {
83+
plugins: [
84+
decompressTargz(),
85+
decompressUnzip(),
86+
],
87+
}));
88+
return Promise.fromCallback(cb => writeFile(versionPath, version, cb));
89+
}
90+
91+
class Downloader {
92+
constructor(options = {}) {
93+
this.location = options.location || CODEFRESH_PATH;
94+
this.logger = options.logger || console;
95+
this.progress = options.progress;
96+
}
97+
98+
async download(component) {
99+
const { location, logger } = this;
100+
_ensureDirectory(location);
101+
const dir = join(location, component.local.dir);
102+
_ensureDirectory(dir);
103+
const compressedBinaryLocation = join(dir, 'data');
104+
105+
const { osType, osSuffix } = _buildLocalOSProperties();
106+
107+
let localVersion = _getLocalVersion(join(dir, component.local.versionFile));
108+
const {
109+
repo: name, branch, versionPath: path, versionFile: file,
110+
} = component.remote;
111+
let remoteVersion = await _getRemoteVersion({
112+
name, branch, path, file,
113+
});
114+
remoteVersion = remoteVersion.trim();
115+
localVersion = localVersion.trim();
116+
117+
if (compareVersions(localVersion, remoteVersion) >= 0) {
118+
// logger.debug(`Download is not required latest-version=${remoteVersion} local-version=${localVersion}`);
119+
return Promise.resolve();
120+
}
121+
logger.debug(`${component.name} component upgrade is required, downloading.`);
122+
123+
124+
const binary = `${name}_${remoteVersion}_${osType}`;
125+
const version = component.version.prefix ? `${component.version.prefix}${remoteVersion}` : remoteVersion;
126+
const url = _buildDownloadURL({ name, version, binary });
127+
const resp = await request(url);
128+
129+
if (this.progress) {
130+
let size = 0;
131+
resp.on('response', (res) => {
132+
size = parseInt(res.headers['content-length'], 10);
133+
this.progress.start(size, 0);
134+
});
135+
136+
resp.on('data', (chunk) => {
137+
size += chunk.length;
138+
this.progress.update(this.progress.value + chunk.length);
139+
if (this.progress.value + chunk.length >= size) {
140+
logger.log('\n');
141+
}
142+
});
143+
}
144+
145+
const zipLocation = `${compressedBinaryLocation}.${osSuffix}`;
146+
resp.pipe(createWriteStream(zipLocation));
147+
148+
return new Promise((resolveFn, rejectFn) => {
149+
resp.on('end', async () => {
150+
const [err] = await to(_writeFiles({
151+
zipPath: zipLocation, location: dir, version: remoteVersion, versionPath: resolve(dir, component.local.versionFile),
152+
}));
153+
if (err) {
154+
rejectFn(err);
155+
return;
156+
}
157+
resolveFn();
158+
});
159+
});
160+
}
161+
}
162+
163+
module.exports = {
164+
CommonProgressFormat: 'downloading [{bar}] {percentage}% | {value}/{total}',
165+
Downloader,
166+
};

lib/binary/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const components = require('./components');
2+
const { Runner } = require('./runner');
3+
const { Downloader, CommonProgressFormat } = require('./downloader');
4+
5+
module.exports = {
6+
components,
7+
Runner,
8+
Downloader,
9+
CommonProgressFormat,
10+
};

lib/binary/runner.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const { spawn } = require('child_process');
2+
const { join, resolve } = require('path');
3+
const { homedir } = require('os');
4+
5+
const CODEFRESH_PATH = resolve(homedir(), '.Codefresh');
6+
7+
class Runner {
8+
constructor(location = CODEFRESH_PATH) {
9+
this.location = location;
10+
}
11+
12+
async run(component, args) {
13+
const dir = join(this.location, component.local.dir);
14+
const path = join(dir, component.local.binary);
15+
const cp = spawn(path, args, {
16+
stdio: [process.stdin, process.stdout, process.stderr],
17+
});
18+
return new Promise((resolveFn, rejectFn) => {
19+
cp.on('exit', (code) => {
20+
if (code !== 0) {
21+
rejectFn(new Error(`Component exited with status code ${code}`));
22+
} else {
23+
resolveFn();
24+
}
25+
});
26+
});
27+
}
28+
}
29+
30+
module.exports = { Runner };

lib/interface/cli/commands/agent/install.cmd.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ const installAgentCmd = new Command({
6969
.option('storage-class-name', {
7070
describe: 'Set a name of your custom storage class, note: this will not install volume provisioning components',
7171
})
72-
.option('skip-cluster-test', {
73-
describe: 'Do not run cluster acceptance test',
74-
})
7572
.option('agent-kube-context-name', {
7673
describe: 'Agent kubernetes context (on attach)',
7774
})
@@ -96,7 +93,6 @@ const installAgentCmd = new Command({
9693
'skip-version-check': skipVersionCheck,
9794
'install-runtime': installRuntime,
9895
'make-default-runtime': shouldMakeDefaultRe,
99-
'skip-cluster-test': skipClusterTest,
10096
'storage-class-name': storageClassName,
10197
verbose,
10298
terminateProcess,
@@ -173,7 +169,6 @@ const installAgentCmd = new Command({
173169
venonaVersion,
174170
kubeConfigPath,
175171
skipVersionCheck,
176-
skipClusterTest,
177172
verbose,
178173
agentId: name,
179174
terminateProcess,
@@ -192,7 +187,6 @@ const installAgentCmd = new Command({
192187
'attach-runtime': true,
193188
'restart-agent': true,
194189
'make-default-runtime': shouldMakeDefaultRe,
195-
'skip-cluster-test': skipClusterTest,
196190
'storage-class-name': storageClassName,
197191
'set-value': setValue,
198192
'set-file': setFile,

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

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@
22
const Command = require('../../Command');
33
const runnerRoot = require('../root/runner.cmd');
44
const inquirer = require('inquirer');
5+
const colors = require('colors');
6+
const figlet = require('figlet');
7+
const _ = require('lodash');
8+
const cliProgress = require('cli-progress');
59
const { getAllKubeContexts, getKubeContext, getAllNamespaces } = require('../../helpers/kubernetes');
610
const installAgent = require('../agent/install.cmd');
711
const installMonitoring = require('../monitor/install.cmd');
812
const createContext = require('../auth/create-context.cmd');
913
const getAgents = require('../agent/get.cmd');
1014
const { getConfigForSdk } = require('../../commad-line-interface');
11-
const colors = require('colors');
1215
const DEFAULTS = require('../../defaults');
1316
const sdk = require('../../../../logic/sdk');
14-
const _ = require('lodash');
1517
const installationProgress = require('./installation-process');
1618
const { to } = require('./../../../../logic/cli-config/errors/awaitTo');
17-
const { createErrorHandler } = require('./helper');
19+
const { createErrorHandler, DefaultLogFormatter } = require('./helper');
1820
const {
1921
getTestPipeline,
2022
createTestPipeline,
2123
executeTestPipeline,
2224
INSTALLATION_DEFAULTS,
2325
} = require('./helper');
24-
const figlet = require('figlet');
26+
const {
27+
components, Runner, Downloader, CommonProgressFormat,
28+
} = require('./../../../../binary');
2529

2630
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')}`);
2731

@@ -113,6 +117,10 @@ const initCmd = new Command({
113117
alias: 'y',
114118
type: 'boolean',
115119
})
120+
.option('skip-cluster-test', {
121+
describe: 'Do not test given kubeconfig context to have all the required permission',
122+
type: 'boolean',
123+
})
116124
.option('set-default-runtime', {
117125
describe: 'Set this as the default runtime environment for your Codefresh account',
118126
type: 'boolean',
@@ -154,6 +162,7 @@ const initCmd = new Command({
154162
token,
155163
'set-value': setValue,
156164
'set-file': setFile,
165+
'skip-cluster-test': skipClusterTest,
157166
} = argv;
158167
let {
159168
'kube-context-name': kubeContextName,
@@ -262,6 +271,33 @@ const initCmd = new Command({
262271

263272
const progressReporter = installationProgress.buildReporter(sdk['runner-installation'], progress);
264273

274+
const downloader = new Downloader({
275+
progress: new cliProgress.SingleBar(
276+
{
277+
stopOnComplete: true,
278+
format: CommonProgressFormat,
279+
},
280+
cliProgress.Presets.shades_classic,
281+
),
282+
});
283+
await downloader.download(components.venona);
284+
const componentRunner = new Runner();
285+
286+
if (skipClusterTest) {
287+
console.log('Skipping cluster requirements tests.');
288+
} else {
289+
const cmd = ['test', '--log-formtter', DefaultLogFormatter];
290+
if (kubeNamespace) {
291+
cmd.push('--kube-namespace');
292+
cmd.push(kubeNamespace);
293+
}
294+
if (kubeConfigPath) {
295+
cmd.push('--kube-config-path');
296+
cmd.push(kubeConfigPath);
297+
}
298+
const [err] = await to(componentRunner.run(components.venona, cmd));
299+
await handleError(err, 'Failed to run cluster test');
300+
}
265301

266302
if (token) {
267303
// Create a new context and switch to that context

lib/interface/cli/commands/runtimeEnvironments/install.cmd.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,6 @@ const installRuntimeCmd = new Command({
110110
.option('make-default-runtime', {
111111
describe: 'should all pipelines run on the this runtime (default is false)',
112112
})
113-
.option('skip-cluster-test', {
114-
describe: 'Do not run cluster acceptance test',
115-
})
116113
.option('verbose', {
117114
describe: 'Print logs',
118115
}),
@@ -133,7 +130,6 @@ const installRuntimeCmd = new Command({
133130
'cluster-service-account': clusterServiceAccount,
134131
'make-default-runtime': shouldMakeDefaultRe,
135132
terminateProcess,
136-
'skip-cluster-test': skipClusterTest,
137133
} = argv;
138134

139135
let {
@@ -258,7 +254,6 @@ const installRuntimeCmd = new Command({
258254
setFile,
259255
terminateProcess: !attachRuntime,
260256
events: runtimeEvents,
261-
skipClusterTest,
262257
storageClassName,
263258
logFormatting: DefaultLogFormatter,
264259
});

0 commit comments

Comments
 (0)