Skip to content

Commit cdbf0fd

Browse files
Cr 1885 release2 (#605)
* Revert "Cr 1885 revert3 (#604)" This reverts commit 0c31cc1 * install gitops codefresh * release-2, tests * update branch * format * СК-1885 * CR-1885 * CR-1885 * CR-1885 * CR-1885 * CR-1885 * fix test Co-authored-by: olegz-codefresh <olegz@codefresh.io>
1 parent e3a987e commit cdbf0fd

File tree

6 files changed

+269
-19
lines changed

6 files changed

+269
-19
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ module.exports = {
1010
'code': 140,
1111
'ignoreComments': true
1212
}],
13-
'no-console': 0
13+
'no-console': 0,
14+
'object-curly-newline': 0,
1415
},
1516
'env': {
1617
'jest': true,
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
const cp = require('child_process');
2+
const rp = require('request-promise');
3+
const promiseRetry = require('promise-retry');
4+
5+
const getExternalIp = namespace => async (retry) => {
6+
process.stdout.write('.');
7+
const ip = cp.execSync(
8+
`kubectl get svc argocd-server -n ${namespace} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}'`,
9+
{ encoding: 'utf-8' },
10+
);
11+
if (ip) {
12+
return ip;
13+
}
14+
15+
return retry(new Error('Can\'t get argocd external-ip address'));
16+
};
17+
18+
async function install({ installManifest, kubeNamespace, setArgoPassword }) {
19+
// sanitizing
20+
const namespace = kubeNamespace.replace('"', '');
21+
const manifest = installManifest.replace('"', '');
22+
const password = setArgoPassword.replace('"', '');
23+
24+
try {
25+
console.log(`Creating namespace ${namespace}...`);
26+
cp.execSync(`kubectl create ns "${namespace}"`);
27+
console.log(`\u2705 Created namespace ${namespace}`);
28+
} catch (err) {
29+
if (!err.message.match(/AlreadyExists/)) {
30+
process.exit(err.status);
31+
}
32+
}
33+
34+
try {
35+
console.log('Creating argocd resources...');
36+
cp.execSync(`kubectl apply -n "${namespace}" -f "${manifest}"`, { stdio: 'inherit' });
37+
console.log('\u2705 Created argocd resources');
38+
} catch (err) {
39+
process.exit(err.status);
40+
}
41+
42+
let host;
43+
try {
44+
console.log('Changing service type to "LoadBalancer"...');
45+
cp.execSync(
46+
`kubectl patch svc argocd-server -n "${namespace}" -p '{"spec": {"type": "LoadBalancer"}}'`,
47+
{ stdio: 'inherit' },
48+
);
49+
console.log('\u2705 Changed service type to "LoadBalancer"');
50+
51+
process.stdout.write('Getting argocd ip address...');
52+
host = `https://${await promiseRetry(getExternalIp(namespace), { retries: 100, factor: 1, minTimeout: 5000 })}`;
53+
console.log(`\n\u2705 Argocd ip address is ${host}`);
54+
} catch (err) {
55+
console.error(err.message);
56+
process.exit(err.status);
57+
}
58+
59+
// get autogenerated password
60+
let autogenerated;
61+
try {
62+
console.log('Getting autogenerated password...');
63+
autogenerated = cp.execSync(
64+
`kubectl get pods -n "${namespace}" -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2 | xargs echo -n`,
65+
{ encoding: 'utf-8' },
66+
);
67+
console.log('\u2705 Got autogenerated password');
68+
} catch (err) {
69+
console.error(err.message);
70+
process.exit(err.status);
71+
}
72+
73+
// update password
74+
try {
75+
console.log('Getting argocd token...');
76+
const argocdToken = await rp({
77+
method: 'POST',
78+
uri: `${host}/api/v1/session`,
79+
body: {
80+
username: 'admin',
81+
password: autogenerated,
82+
},
83+
json: true,
84+
});
85+
console.log('\u2705 Got argocd token');
86+
87+
console.log('Updating admin password...');
88+
await rp({
89+
method: 'PUT',
90+
uri: `${host}/api/v1/account/password`,
91+
headers: {
92+
Authorization: `Bearer ${argocdToken.token}`,
93+
},
94+
body: {
95+
currentPassword: autogenerated,
96+
name: 'admin',
97+
newPassword: password,
98+
},
99+
json: true,
100+
});
101+
console.log('\u2705 Updated admin password');
102+
} catch (err) {
103+
console.error(err.message);
104+
process.exit(err.status);
105+
}
106+
107+
return {
108+
host,
109+
};
110+
}
111+
112+
module.exports = {
113+
install,
114+
};

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

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ const installRoot = require('../root/install.cmd');
55
const { detectProxy } = require('../../helpers/general');
66
const { downloadProvider } = require('../hybrid/helper');
77
const { Runner, components } = require('../../../../binary');
8+
const { install: installArgocd } = require('./install-codefresh');
89

910
const installArgoCmd = new Command({
1011
root: false,
1112
parent: installRoot,
1213
command: 'gitops <provider>',
13-
description: 'Install gitops agent',
14+
description: 'Install gitops',
1415
webDocs: {
1516
category: 'Gitops',
1617
title: 'Install',
@@ -20,14 +21,14 @@ const installArgoCmd = new Command({
2021
.env('CF_ARG_')
2122
.positional('provider', {
2223
describe: 'Gitops provider',
23-
choices: ['argocd-agent'],
24+
choices: ['codefresh', 'argocd-agent'],
2425
required: true,
2526
})
2627
.option('git-integration', {
2728
describe: 'Name of git integration in Codefresh',
2829
})
2930
.option('codefresh-integration', {
30-
describe: 'Name of argocd integration in Codefresh',
31+
describe: 'Name of gitops integration in Codefresh',
3132
})
3233
.option('argo-host', {
3334
describe: 'Host of argocd installation',
@@ -36,13 +37,13 @@ const installArgoCmd = new Command({
3637
describe: 'Token of argocd installation. Preferred auth method',
3738
})
3839
.option('argo-username', {
39-
describe: 'Username of argocd installation. Should be used with argo-password',
40+
describe: 'Username of existing argocd installation. Should be used with argo-password',
4041
})
4142
.option('argo-password', {
42-
describe: 'Username of argocd installation. Should be used with argo-username',
43+
describe: 'Password of existing argocd installation. Should be used with argo-username',
4344
})
4445
.option('update', {
45-
describe: 'Update argocd integration if exists',
46+
describe: 'Update gitops integration if exists',
4647
})
4748
.option('kube-config-path', {
4849
describe: 'Path to kubeconfig file (default is $HOME/.kube/config)',
@@ -70,16 +71,41 @@ const installArgoCmd = new Command({
7071
})
7172
.option('https-proxy', {
7273
describe: 'https proxy to be used in the runner',
74+
})
75+
// argocd options
76+
.option('install-manifest', {
77+
describe: 'Url of argocd install manifest',
78+
default: 'https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml',
79+
})
80+
.option('set-argo-password', {
81+
describe: 'Set password for admin user of new argocd installation',
7382
}),
7483
handler: async (argv) => {
75-
let {
76-
// eslint-disable-next-line prefer-const
77-
'kube-config-path': kubeConfigPath,
78-
// eslint-disable-next-line prefer-const
79-
provider,
80-
'http-proxy': httpProxy,
81-
'https-proxy': httpsProxy,
82-
} = argv;
84+
let { provider, httpProxy, httpsProxy, argoHost, argoUsername, argoPassword } = argv;
85+
const { kubeConfigPath, installManifest, kubeNamespace, setArgoPassword } = argv;
86+
87+
if (provider === 'codefresh') {
88+
if (!setArgoPassword) {
89+
console.error('\nMissing required argument: set-argo-password');
90+
process.exit(1);
91+
}
92+
93+
if (!kubeNamespace) {
94+
console.error('\nMissing required argument: kube-namespace');
95+
process.exit(1);
96+
}
97+
98+
const result = await installArgocd({
99+
installManifest,
100+
kubeNamespace,
101+
setArgoPassword,
102+
});
103+
104+
provider = 'argocd-agent';
105+
argoHost = result.host;
106+
argoUsername = 'admin';
107+
argoPassword = setArgoPassword;
108+
}
83109

84110
const binLocation = await downloadProvider({ provider });
85111
const componentRunner = new Runner(binLocation);
@@ -93,10 +119,13 @@ const installArgoCmd = new Command({
93119
commands.push(kubeConfigPath);
94120
}
95121

96-
const installOptions = _.pick(argv, ['git-integration', 'codefresh-integration', 'argo-host', 'argo-token', 'output',
97-
'argo-username', 'argo-password', 'update', 'kube-context-name', 'kube-namespace', 'sync-mode', 'sync-apps']);
122+
const installOptions = _.pick(argv, ['git-integration', 'codefresh-integration', 'argo-token', 'output',
123+
'update', 'kube-context-name', 'kube-namespace', 'sync-mode', 'sync-apps']);
124+
installOptions['argo-host'] = argoHost;
125+
installOptions['argo-username'] = argoUsername;
126+
installOptions['argo-password'] = argoPassword;
98127

99-
_.forEach(installOptions, (value, key) => {
128+
_.forEach(_.pickBy(installOptions, _.identity), (value, key) => {
100129
if (_.isArray(value)) {
101130
value.forEach((item) => {
102131
commands.push(`--${key}`);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const installCmd = require('./install.cmd').toCommand();
2+
const { Runner } = require('../../../../binary');
3+
const yargs = require('yargs');
4+
5+
jest.mock('./install-codefresh', () => ({
6+
install: async () => ({ host: 'host' }),
7+
}));
8+
9+
jest.mock('../hybrid/helper', () => ({
10+
downloadProvider: async () => {},
11+
}));
12+
13+
jest.mock('../../../../binary');
14+
15+
describe('install gitops', () => {
16+
beforeEach(async () => {
17+
Runner.mockClear();
18+
});
19+
20+
it('install gitops argocd-agent w/o arguments', async () => {
21+
const argv = { provider: 'argocd-agent' };
22+
await installCmd.handler(argv);
23+
const { calls } = Runner.mock.instances[0].run.mock;
24+
expect(calls).toHaveLength(1);
25+
const [component, commands] = calls[0];
26+
expect(component.name).toEqual('gitops');
27+
expect(commands).toEqual(['install']);
28+
});
29+
30+
it('install gitops argocd-agent with arguments', async () => {
31+
const argv = {
32+
provider: 'argocd-agent',
33+
'git-integration': 'gitIntegration',
34+
'codefresh-integration': 'codefreshIntegration',
35+
'kube-context-name': 'kubeContextName',
36+
'kube-namespace': 'kubeNamespace',
37+
'sync-mode': 'SELECT',
38+
'sync-apps': 'syncApps',
39+
};
40+
await installCmd.handler(argv);
41+
const { calls } = Runner.mock.instances[0].run.mock;
42+
expect(calls).toHaveLength(1);
43+
const [component, commands] = calls[0];
44+
expect(component.name).toEqual('gitops');
45+
expect(commands).toEqual([
46+
'install',
47+
'--git-integration',
48+
'gitIntegration',
49+
'--codefresh-integration',
50+
'codefreshIntegration',
51+
'--kube-context-name',
52+
'kubeContextName',
53+
'--kube-namespace',
54+
'kubeNamespace',
55+
'--sync-mode',
56+
'SELECT',
57+
'--sync-apps',
58+
'syncApps',
59+
]);
60+
});
61+
62+
it('install gitops codefresh with required arguments', async () => {
63+
const argv = {
64+
provider: 'codefresh',
65+
'set-argo-password': 'pass',
66+
setArgoPassword: 'pass',
67+
'kube-namespace': 'ns',
68+
kubeNamespace: 'ns',
69+
};
70+
await installCmd.handler(argv);
71+
const { calls } = Runner.mock.instances[0].run.mock;
72+
expect(calls).toHaveLength(1);
73+
const [component, commands] = calls[0];
74+
expect(component.name).toEqual('gitops');
75+
expect(commands).toEqual([
76+
'install',
77+
'--kube-namespace',
78+
'ns',
79+
'--argo-host',
80+
'host',
81+
'--argo-username',
82+
'admin',
83+
'--argo-password',
84+
'pass',
85+
]);
86+
});
87+
});

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codefresh",
3-
"version": "0.73.32",
3+
"version": "0.73.33",
44
"description": "Codefresh command line utility",
55
"main": "index.js",
66
"preferGlobal": true,
@@ -64,6 +64,7 @@
6464
"mongodb": "^3.0.1",
6565
"ora": "^3.0.0",
6666
"prettyjson": "^1.2.1",
67+
"promise-retry": "^2.0.1",
6768
"recursive-readdir": "^2.2.1",
6869
"request": "^2.88.0",
6970
"request-promise": "^4.2.2",

yarn.lock

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
19241924
dependencies:
19251925
once "^1.4.0"
19261926

1927+
err-code@^2.0.2:
1928+
version "2.0.3"
1929+
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
1930+
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
1931+
19271932
error-ex@^1.2.0:
19281933
version "1.3.2"
19291934
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -5462,6 +5467,14 @@ progress@2.0.3, progress@^2.0.0, progress@~2.0.0:
54625467
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
54635468
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
54645469

5470+
promise-retry@^2.0.1:
5471+
version "2.0.1"
5472+
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
5473+
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
5474+
dependencies:
5475+
err-code "^2.0.2"
5476+
retry "^0.12.0"
5477+
54655478
prompts@^0.1.9:
54665479
version "0.1.14"
54675480
resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2"
@@ -5971,6 +5984,11 @@ retry@^0.10.0:
59715984
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
59725985
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
59735986

5987+
retry@^0.12.0:
5988+
version "0.12.0"
5989+
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
5990+
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
5991+
59745992
rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
59755993
version "2.7.1"
59765994
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"

0 commit comments

Comments
 (0)