Skip to content

Commit

Permalink
Saas 7153 prevent runner name collisions (#458)
Browse files Browse the repository at this point in the history
  • Loading branch information
roi-codefresh authored May 18, 2020
1 parent 70cbfbe commit 1340745
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 24 deletions.
55 changes: 40 additions & 15 deletions lib/interface/cli/commands/hybrid/init.cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const Command = require('../../Command');
const runnerRoot = require('../root/runner.cmd');
const inquirer = require('inquirer');
const { getAllKubeContexts, getKubeContext } = require('../../helpers/kubernetes');
const { getAllKubeContexts, getKubeContext, getAllNamespaces } = require('../../helpers/kubernetes');
const installAgent = require('../agent/install.cmd');
const pipelinesRunCmd = require('../pipeline/run.cmd');
const installMonitoring = require('../monitor/install.cmd');
Expand All @@ -18,7 +18,7 @@ const INSTALLATION_DEFAULTS = {
NAMESPACE: 'codefresh',
MAKE_DEFAULT_RE: true,
RUN_DEMO_PIPELINE: true,
DEMO_PIPELINE_NAME: 'Hello Codefresh',
DEMO_PIPELINE_NAME: 'Codefresh-Runner Demo',
CF_CONTEXT_NAME: 'cf-runner',
};

Expand All @@ -29,7 +29,12 @@ function prettyError(error) {
if (typeof errObj === 'string') {
errObj = JSON.parse(errObj);
}
return _.get(errObj, 'message', error);

if (!errObj.message) {
return error;
}

return errObj.code ? `${errObj.message} [code: ${errObj.code}]` : errObj.message;
} catch (e) {
return _.get(error, 'message', JSON.stringify(error));
}
Expand All @@ -45,8 +50,8 @@ async function createDemoPipeline(runtimeName) {
pipeline.spec.steps.test = {
stage: 'test',
title: 'test',
image: 'ubuntu:latest',
commands: ['echo hello codefresh'],
image: 'alpine:latest',
commands: ['echo hello codefresh runner!'],
};

await sdk.pipelines.replace(
Expand Down Expand Up @@ -83,14 +88,33 @@ async function createAndExecuteDemoPipeline(runtimeName) {
console.log(`Demo pipeline with the name: "${colors.cyan(INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME)}" already exists`);
}

console.log(`${colors.yellow('*NOTE* Running a pipeline for the first time might take a longer than usual')}`);
console.log(`${colors.yellow('*NOTE* Running a pipeline for the first time might take longer than usual.')}`);
console.log(`Executing pipeline "${colors.cyan(INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME)}"`);
await pipelinesRunCmd.handler({
name: INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME,
exitProcess: false,
});
}

async function getRecommendedKubeNamespace(kubeconfigPath, kubeContextName) {
const defaultName = INSTALLATION_DEFAULTS.NAMESPACE;
const namespaces = await getAllNamespaces(kubeconfigPath, kubeContextName);
let name;

if (!_.isArray(namespaces) || !_.find(namespaces, ns => ns === defaultName)) {
name = defaultName; // use the default name if there are no collisions
} else {
const namespacesSet = new Set(namespaces); // for fast lookup
let i = 1;
while (namespacesSet.has(`${defaultName}-${i}`)) {
i += 1;
}
name = `${defaultName}-${i}`;
}

return name;
}

const initCmd = new Command({
root: false,
parent: runnerRoot,
Expand Down Expand Up @@ -194,28 +218,30 @@ const initCmd = new Command({
if (noQuestions) {
// set defaults
kubeContextName = getKubeContext(kubeConfigPath);
kubeNamespace = INSTALLATION_DEFAULTS.NAMESPACE;
kubeNamespace = await getRecommendedKubeNamespace(kubeConfigPath, kubeContextName);
shouldMakeDefaultRe = INSTALLATION_DEFAULTS.MAKE_DEFAULT_RE;
shouldExecutePipeline = INSTALLATION_DEFAULTS.RUN_DEMO_PIPELINE;
} else {
const questions = [];
console.log(colors.green('This installer will guide you through the Codefresh Runner installation process'));
if (!kubeContextName && !noQuestions) {
const contexts = getAllKubeContexts(kubeConfigPath);
const currentKubeContext = getKubeContext(kubeConfigPath);

questions.push({
const answer = await inquirer.prompt({
type: 'list',
name: 'context',
message: 'Name of Kubernetes context to use',
default: currentKubeContext,
choices: contexts,
});
kubeContextName = answer.context;
}
const questions = [];
if (!kubeNamespace && !noQuestions) {
questions.push({
type: 'input',
name: 'namespace',
default: INSTALLATION_DEFAULTS.NAMESPACE,
default: await getRecommendedKubeNamespace(kubeConfigPath, kubeContextName),
message: 'Kubernetes namespace to install into (will be created if it does not exist)',
validate: value => (value !== undefined && value !== '') || 'Please enter namespace\'s name',
});
Expand All @@ -239,19 +265,18 @@ const initCmd = new Command({
});
}

console.log(colors.green('This installer will guide you through the Codefresh Runner installation process'));
const answers = await inquirer.prompt(questions);
kubeContextName = kubeContextName || answers.context;
kubeNamespace = kubeNamespace || answers.namespace;
shouldMakeDefaultRe = shouldMakeDefaultRe || answers.shouldMakeDefaultRe;
shouldExecutePipeline = shouldExecutePipeline || answers.shouldExecutePipeline;
shouldMakeDefaultRe = _.isUndefined(shouldMakeDefaultRe) ? answers.shouldMakeDefaultRe : shouldMakeDefaultRe;
shouldExecutePipeline = _.isUndefined(shouldExecutePipeline) ? answers.shouldExecutePipeline : shouldExecutePipeline;
}

console.log(`\n${colors.green('Installation options summary:')}
1. Kubernetes Context: ${colors.cyan(kubeContextName)}
2. Kubernetes Namespace: ${colors.cyan(kubeNamespace)}
3. Set this as default account runtime-environment: ${colors.cyan(shouldMakeDefaultRe)}
4. Execute demo pipeline after install: ${colors.cyan(shouldExecutePipeline)}
3. Set this as default account runtime-environment: ${colors.cyan(!!shouldMakeDefaultRe)}
4. Execute demo pipeline after install: ${colors.cyan(!!shouldExecutePipeline)}
`);

if (token) { // Add context
Expand Down
21 changes: 20 additions & 1 deletion lib/interface/cli/helpers/kubernetes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const path = require('path');
const { KubeConfig } = require('kubernetes-client');
const { KubeConfig, Client } = require('kubernetes-client');
const Request = require('kubernetes-client/backends/request');
const _ = require('lodash');

const getKubeContext = (kubeconfigPath) => {
// eslint-disable-next-line global-require
Expand All @@ -23,8 +25,25 @@ const getAllKubeContexts = (kubeconfigPath) => {
}, []);
}
};
const getAllNamespaces = async (kubeconfigPath, kubeContextName) => {
// eslint-disable-next-line global-require
const homedir = require('os').homedir();
const kubePath = kubeconfigPath || process.env.KUBECONFIG || path.join(homedir, '.kube', 'config');
const kubeconfig = new KubeConfig();
kubeconfig.loadFromFile(kubePath);
kubeconfig.setCurrentContext(kubeContextName);
const backend = new Request({ kubeconfig });
const client = new Client({ backend, version: 1.13 });
const resp = await client.api.v1.namespaces.get();
if (resp.statusCode === 200) {
const nsObjs = _.get(resp, 'body.items');
return _.map(nsObjs, ns => _.get(ns, 'metadata.name'));
}
return [];
};

module.exports = {
getKubeContext,
getAllKubeContexts,
getAllNamespaces,
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codefresh",
"version": "0.60.2",
"version": "0.62.0",
"description": "Codefresh command line utility",
"main": "index.js",
"preferGlobal": true,
Expand Down Expand Up @@ -55,7 +55,7 @@
"js-yaml": "^3.10.0",
"jsonwebtoken": "^8.1.0",
"kefir": "^3.8.1",
"kubernetes-client": "^8.3.6",
"kubernetes-client": "^9.0.0",
"lodash": "^4.17.4",
"mkdirp": "^0.5.1",
"moment": "^2.19.4",
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4164,10 +4164,10 @@ kleur@^2.0.1:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300"
integrity sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==

kubernetes-client@^8.3.6:
version "8.3.7"
resolved "https://registry.yarnpkg.com/kubernetes-client/-/kubernetes-client-8.3.7.tgz#017692c7cfcc2c142502bad8dee9c6e92c57c4f2"
integrity sha512-A0rvfQAvwAuPTooBOSErpTcnwcQxhkmawjOm/gUdGDWCUZoYmAVgVGFnc/klda+X1tvHwleavDsLqmqaYscH2w==
kubernetes-client@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/kubernetes-client/-/kubernetes-client-9.0.0.tgz#f72e6c71aaa20548b3d6466f1dc88dfa61fb3ba4"
integrity sha512-Qy8o42dZVHB9P+cIiKdWpQbz/65l/qW1fDYvlzzeSLftmL1Ne3HEiM+0TmKAwNuRW0pTJN2tRWhcccToclxJ8g==
dependencies:
"@kubernetes/client-node" "0.10.2"
camelcase "^6.0.0"
Expand All @@ -4179,7 +4179,7 @@ kubernetes-client@^8.3.6:
pump "^3.0.0"
qs "^6.9.0"
request "^2.88.2"
swagger-fluent "^5.0.1"
swagger-fluent "^5.0.3"
url-join "^4.0.1"
ws "^7.2.3"

Expand Down Expand Up @@ -6513,7 +6513,7 @@ swagger-client@^3.8.22:
utf8-bytes "0.0.1"
utfstring "^2.0.0"

swagger-fluent@^5.0.1:
swagger-fluent@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/swagger-fluent/-/swagger-fluent-5.0.3.tgz#48564e1ae4f3430488b00be40ffeab257a6f14c0"
integrity sha512-i43ADMtPi7dxAN75Lw50SlncMB31FgaVwXqKioR8SWs+Yon2RbiLU1J1PGMXA4N8cSt9Vz5RHzaoKjz/+iW88g==
Expand Down

0 comments on commit 1340745

Please sign in to comment.