Skip to content

Commit 9f17f57

Browse files
Cr 1077 - delete runner should delete runtime (#588)
1 parent 4937c22 commit 9f17f57

File tree

5 files changed

+212
-109
lines changed

5 files changed

+212
-109
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const Command = require('../../Command');
22
const CFError = require('cf-errors');
3+
const colors = require('colors');
34
const { sdk } = require('../../../../logic');
45
const deleteRoot = require('../root/delete.cmd');
56
const { ignoreHttpError } = require('../../helpers/general');
@@ -32,7 +33,7 @@ const command = new Command({
3233
}
3334

3435
await sdk.agents.delete({ agentId: agent.id });
35-
console.log(`Agent '${name || id}' deleted.`);
36+
console.log(`Agent "${colors.cyan(name || id)}" deleted.`);
3637
},
3738
});
3839

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

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ const colors = require('colors');
1010
const DEFAULTS = require('../../defaults');
1111
const sdk = require('../../../../logic/sdk');
1212
const _ = require('lodash');
13-
const YAML = require('yaml');
14-
const fs = require('fs');
1513
const { to } = require('./../../../../logic/cli-config/errors/awaitTo');
1614
const {
1715
createErrorHandler,
1816
getRelatedAgents,
1917
getRelatedNamespaces,
2018
drawCodefreshFiglet,
2119
unInstallAppProxy,
20+
mergeValuesFromValuesFile,
21+
INSTALLATION_DEFAULTS,
2222
} = require('./helper');
2323

2424
const defaultNamespace = 'codefresh';
@@ -29,14 +29,34 @@ async function promptConfirmationMessage({
2929
agentName,
3030
kubeNamespace,
3131
attachedRuntimes,
32+
defaultRuntime,
33+
clustersToDelete,
34+
appProxyToDelete,
3235
}) {
36+
const note = colors.underline(colors.yellow('Note'));
37+
let newDefaultRuntime = defaultRuntime;
38+
3339
// prompt confirmation message
3440
console.log(`${colors.red('This process will attempt to delete the following:')}`);
3541
console.log(`\u2022 Codefresh runner with the name "${colors.cyan(agentName)}"`);
36-
attachedRuntimes.forEach((reName) => { console.log(`\u2022 Codefresh runtime with the name "${colors.cyan(reName)}"`); });
42+
attachedRuntimes.forEach((reName) => { console.log(`\u2022 Codefresh runtime with the name "${colors.cyan(reName)}"${defaultRuntime === reName ? ' [default runtime]' : ''}`); });
3743
console.log('\u2022 Codefresh runner monitor component');
38-
console.log('\u2022 Codefresh App-Proxy component (if exists)');
39-
console.log(`* The kubernetes namespace "${colors.cyan(kubeNamespace)}" will ${colors.underline('not')} be deleted\n`);
44+
clustersToDelete.forEach((cluster) => { console.log(`\u2022 Codefresh cluster integration: "${colors.cyan(cluster.selector)}"`); });
45+
appProxyToDelete.forEach((appProxy) => { console.log(`\u2022 App-Proxy component: "${colors.cyan(appProxy)}"`); });
46+
47+
// if this includes your default runtime
48+
if (attachedRuntimes.length > 0) {
49+
if (defaultRuntime && attachedRuntimes.includes(defaultRuntime)) {
50+
newDefaultRuntime = INSTALLATION_DEFAULTS.SAAS_RUNTIME;
51+
console.log(`* ${note}: "${colors.cyan(defaultRuntime)}" is set as your default runtime-environment,`
52+
+ ` if you delete this runtime your new default runtime will be: "${colors.cyan(newDefaultRuntime)}"`);
53+
}
54+
55+
console.log(`* ${note}: any pipeline set to run on one of the above runtime environments will be moved to`
56+
+ ` run on your ${newDefaultRuntime !== defaultRuntime ? 'new ' : ''}default runtime environment: "${colors.cyan(newDefaultRuntime)}"`);
57+
}
58+
59+
console.log(`* ${note}: The kubernetes namespace "${colors.cyan(kubeNamespace)}" will ${colors.underline('not')} be deleted\n`);
4060

4161
const answer = await inquirer.prompt({
4262
type: 'confirm',
@@ -50,6 +70,27 @@ async function promptConfirmationMessage({
5070
}
5171
}
5272

73+
// returns the clusters that are referenced by the runtimesToDelete and not referenced by runtimesToKeep
74+
function getClustersToDelete(clusters, runtimes, runtimesToDelete) {
75+
const potentialClustersNames = _(runtimesToDelete).map(re => _.get(re, 'runtimeScheduler.cluster.clusterProvider.selector')).compact().value();
76+
const runtimesToDeleteNames = _(runtimesToDelete).map(re => _.get(re, 'metadata.name')).compact().value();
77+
78+
const potentialClustersToDelete = _.filter(clusters, c => potentialClustersNames.includes(c.selector));
79+
const runtimesToKeep = _.filter(runtimes, re => !runtimesToDeleteNames.includes(_.get(re, 'metadata.name')));
80+
81+
return _.filter(potentialClustersToDelete, c => !_.find(runtimesToKeep, re => _.get(re, 'runtimeScheduler.cluster.clusterProvider.selector') === c.selector));
82+
}
83+
84+
function getAppProxyToDelete(runtimesToDelete) {
85+
return _.reduce(runtimesToDelete, (acc, re) => {
86+
const appProxy = _.get(re, 'appProxy.externalIP');
87+
if (appProxy) {
88+
acc.push(appProxy);
89+
}
90+
return acc;
91+
}, []);
92+
}
93+
5394
const deleteCmd = new Command({
5495
root: false,
5596
parent: runnerRoot,
@@ -90,50 +131,39 @@ const deleteCmd = new Command({
90131
describe: 'Print logs',
91132
}),
92133
handler: async (argv) => {
134+
let _argv = argv;
135+
136+
// read values from values file
137+
if (argv.values) {
138+
_argv = mergeValuesFromValuesFile(_argv, _argv.values, handleError);
139+
}
140+
93141
const {
94142
verbose,
95-
} = argv;
96-
let {
143+
force,
97144
'kube-config-path': kubeConfigPath,
98-
url, force,
145+
} = _argv;
146+
let {
147+
url,
99148
'kube-context-name': kubeContextName,
100149
'kube-namespace': kubeNamespace,
101150
name: agentName,
102-
values: valuesFile,
103-
} = argv;
151+
} = _argv;
104152

105153
const [listReErr, runtimes] = await to(sdk.runtimeEnvs.list({ }));
106154
await handleError(listReErr, 'Failed to get runtime environments');
107155
const [listAgentsErr, agents] = await to(sdk.agents.list({ }));
108156
await handleError(listAgentsErr, 'Failed to get agents');
157+
const [listClustersErr, clusters] = await to(sdk.clusters.list());
158+
await handleError(listClustersErr, 'Failed to get cluster integrations');
109159

110-
if (!agents.length) {
160+
if (!agents || !agents.length) {
111161
console.log('No runners found on your codefresh account');
112162
process.exit(0);
113163
}
114164

115165
console.log(colors.green('This uninstaller will guide you through the runner uninstallation process'));
116-
if (valuesFile) {
117-
const valuesFileStr = fs.readFileSync(valuesFile, 'utf8');
118-
valuesObj = YAML.parse(valuesFileStr);
119-
120-
if (!kubeConfigPath && valuesObj.ConfigPath) {
121-
kubeConfigPath = valuesObj.ConfigPath;
122-
}
123-
if (!kubeNamespace && valuesObj.Namespace) {
124-
kubeNamespace = valuesObj.Namespace;
125-
}
126-
if (!kubeContextName && valuesObj.Context) {
127-
kubeContextName = valuesObj.Context;
128-
}
129-
if (!url && valuesObj.CodefreshHost) {
130-
url = valuesObj.CodefreshHost;
131-
}
132166

133-
if (!agentName && valuesObj.AgentId) {
134-
agentName = valuesObj.AgentId;
135-
}
136-
}
137167
if (!url) {
138168
url = DEFAULTS.URL;
139169
}
@@ -216,9 +246,21 @@ const deleteCmd = new Command({
216246
`);
217247

218248
const attachedRuntimes = agent.runtimes || [];
249+
const runtimesToDelete = _.filter(runtimes, re => attachedRuntimes.includes(_.get(re, 'metadata.name')));
250+
const defaultRuntime = _.get(_.find(runtimes, re => re.default), 'metadata.name');
251+
252+
const clustersToDelete = getClustersToDelete(clusters, runtimes, runtimesToDelete);
253+
const appProxyToDelete = getAppProxyToDelete(runtimesToDelete);
219254

220255
if (!force) {
221-
await promptConfirmationMessage({ agentName, kubeNamespace, attachedRuntimes });
256+
await promptConfirmationMessage({
257+
agentName,
258+
kubeNamespace,
259+
attachedRuntimes,
260+
defaultRuntime,
261+
clustersToDelete,
262+
appProxyToDelete,
263+
});
222264
}
223265

224266
await Promise.all(attachedRuntimes.map(async (reName) => {
@@ -233,16 +275,36 @@ const deleteCmd = new Command({
233275
verbose,
234276
};
235277
const re = runtimes.find(runtime => runtime.metadata.name === reName);
278+
if (!re) {
279+
// re already deleted
280+
return;
281+
}
282+
283+
// remove runtime cluster components
284+
console.log(`Deleting runtime-environment: ${colors.cyan(reName)} from cluster`);
285+
const [uninstallReErr] = await to(unInstallRuntime.handler(uninstallRuntimeOptions));
286+
handleError(uninstallReErr, `Failed to uninstall runtime-environment "${colors.cyan(reName)}"`);
287+
288+
// delete codefresh entity
289+
console.log(`Deleting runtime-environment: "${colors.cyan(reName)}" from codefresh`);
290+
await to(sdk.runtimeEnvs.delete({ name: reName, force: true })); // also delete default runtime
291+
236292
if (re.appProxy) {
237-
await unInstallAppProxy({
293+
const [uninstallAppProxyErr] = await to(unInstallAppProxy({
238294
kubeConfigPath,
239295
kubeContextName,
240296
kubeNamespace,
241297
verbose,
242-
});
298+
}));
299+
handleError(uninstallAppProxyErr, 'Failed to uninstall app-proxy');
300+
console.log('App-Proxy uninstalled successfully');
243301
}
244-
const [uninstallReErr] = await to(unInstallRuntime.handler(uninstallRuntimeOptions));
245-
handleError(uninstallReErr, `Failed to uninstall runtime-environment "${colors.cyan(reName)}"`);
302+
}));
303+
304+
await Promise.all(clustersToDelete.map(async (cluster) => {
305+
console.log(`Deleting cluster integration: "${colors.cyan(cluster.selector)}"`);
306+
const [clusterDeleteErr] = await to(sdk.clusters.delete({ id: cluster._id, provider: cluster.provider }));
307+
handleError(clusterDeleteErr, 'Failed to delete cluster integration');
246308
}));
247309

248310
const uninstallAgentOptions = {

lib/interface/cli/commands/hybrid/helper.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ const {
1818
} = require('./../../../../binary');
1919
const { pathExists } = require('../../helpers/general');
2020
const Promise = require('bluebird');
21+
const YAML = require('yaml');
22+
const fs = require('fs');
2123

2224
const INSTALLATION_DEFAULTS = {
2325
NAMESPACE: 'codefresh',
@@ -31,6 +33,7 @@ const INSTALLATION_DEFAULTS = {
3133
RESUME_OLD_INSTALLATION: true,
3234
COMPONENTS_FOLDER: 'components',
3335
KUBECONFIG_PATH: path.join(homedir(), '.kube', 'config'),
36+
SAAS_RUNTIME: 'SAAS runtime',
3437
};
3538

3639
const RUNTIME_IMAGES = {
@@ -1006,6 +1009,71 @@ function getRuntimeImagesWithRegistryUrl(registry) {
10061009
}, {});
10071010
}
10081011

1012+
function mergeValuesFromValuesFile(argv, valuesFile, handleError) {
1013+
const valuesFileStr = fs.readFileSync(valuesFile, 'utf8');
1014+
const valuesObj = YAML.parse(valuesFileStr);
1015+
const _argv = _.cloneDeep(argv);
1016+
1017+
_argv.yes = true; // don't ask any questions
1018+
1019+
if (!_.has(_argv, 'kube-config-path') && _.has(valuesObj, 'ConfigPath')) {
1020+
_.set(_argv, 'kube-config-path', valuesObj.ConfigPath);
1021+
}
1022+
if (!_.has(_argv, 'kube-context-name') && _.has(valuesObj, 'Context')) {
1023+
_.set(_argv, 'kube-context-name', valuesObj.Context);
1024+
}
1025+
if (!_.has(_argv, 'kube-namespace') && _.has(valuesObj, 'Namespace')) {
1026+
_.set(_argv, 'kube-namespace', valuesObj.Namespace);
1027+
}
1028+
if (!_.has(_argv, 'url') && _.has(valuesObj, 'CodefreshHost')) {
1029+
_.set(_argv, 'url', valuesObj.CodefreshHost);
1030+
}
1031+
if (!_.has(_argv, 'token') && _.has(valuesObj, 'Token')) {
1032+
_.set(_argv, 'token', valuesObj.Token);
1033+
}
1034+
if (!_.has(_argv, 'name') && _.has(valuesObj, 'AgentId')) {
1035+
_.set(_argv, 'name', valuesObj.AgentId);
1036+
}
1037+
if (!_.has(_argv, 'install-monitor') && _.has(valuesObj, 'Monitor.Enabled')) {
1038+
_.set(_argv, 'install-monitor', valuesObj.Monitor.Enabled);
1039+
}
1040+
if (_.get(valuesObj, 'AppProxy')) {
1041+
_.set(_argv, 'app-proxy', true);
1042+
}
1043+
if (!_.has(_argv, 'app-proxy-host') && _.get(valuesObj, 'AppProxy.Ingress.Host')) {
1044+
_.set(_argv, 'app-proxy-host', valuesObj.AppProxy.Ingress.Host);
1045+
}
1046+
if (_argv.appProxy && !_argv['app-proxy-host']) {
1047+
handleError(new Error('no hostname provided'), 'cannot install app-proxy component without a hostname', undefined, undefined, true);
1048+
}
1049+
if (!_.has(_argv, 'app-proxy-path-prefix') && _.get(valuesObj, 'AppProxy.Ingress.PathPrefix')) {
1050+
_.set(_argv, 'app-proxy-path-prefix', valuesObj.AppProxy.Ingress.PathPrefix);
1051+
}
1052+
if (!_.has(_argv, 'docker-daemon-access') && _.has(valuesObj, 'dockerDaemonScheduler.userAccess')) {
1053+
_.set(_argv, 'docker-daemon-access', valuesObj.dockerDaemonScheduler.userAccess);
1054+
}
1055+
if (_.get(_argv, 'envVars.length') === 0 && _.has(valuesObj, 'EnvVars')) {
1056+
_argv.envVars.push(...objectToKeyValueArray(_.get(valuesObj, 'EnvVars')));
1057+
}
1058+
if (!_.has(_argv, 'docker-registry') && _.has(valuesObj, 'DockerRegistry')) {
1059+
_.set(_argv, 'docker-registry', valuesObj.DockerRegistry);
1060+
}
1061+
if (!_.has(_argv, 'skip-cluster-test') && _.has(valuesObj, 'SkipClusterTest')) {
1062+
_.set(_argv, 'skip-cluster-test', valuesObj.SkipClusterTest);
1063+
}
1064+
if (_.has(valuesObj, 'RuntimeEnvironmentName')) {
1065+
_.set(_argv, 'runtimeName', valuesObj.RuntimeEnvironmentName);
1066+
}
1067+
if (_.has(valuesObj, 'Runtime.AdditionalEnvVars')) {
1068+
_.set(_argv, 'reEnvVars', valuesObj.Runtime.AdditionalEnvVars);
1069+
}
1070+
if (_.has(valuesObj, 'Runtime.resources')) {
1071+
_.set(_argv, 'reResources', valuesObj.Runtime.resources);
1072+
}
1073+
1074+
return _argv;
1075+
}
1076+
10091077
module.exports = {
10101078
getRelatedAgents,
10111079
createErrorHandler,
@@ -1042,6 +1110,7 @@ module.exports = {
10421110
installAppProxy,
10431111
unInstallAppProxy,
10441112
upgradeAppProxy,
1113+
mergeValuesFromValuesFile,
10451114
INSTALLATION_DEFAULTS,
10461115
DefaultLogFormatter,
10471116
};

0 commit comments

Comments
 (0)