Skip to content

Commit

Permalink
report installation progress to codefresh to support idiomatic instal… (
Browse files Browse the repository at this point in the history
#459)

* report installation progress to codefresh to support idiomatic installation

* report failures
  • Loading branch information
Oleg Sucharevich authored May 18, 2020
1 parent 779b013 commit de16efa
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 56 deletions.
129 changes: 75 additions & 54 deletions lib/interface/cli/commands/hybrid/init.cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const colors = require('colors');
const DEFAULTS = require('../../defaults');
const sdk = require('../../../../logic/sdk');
const _ = require('lodash');
const installationProgress = require('./installation-process');
const { to } = require('./../../../../logic/cli-config/errors/awaitTo');

const INSTALLATION_DEFAULTS = {
NAMESPACE: 'codefresh',
Expand Down Expand Up @@ -40,7 +42,18 @@ function prettyError(error) {
}
}

async function createDemoPipeline(runtimeName) {
async function handleError(error, message, progressReporter, event) {
if (!error) {
return;
}
if (progressReporter) {
await to(progressReporter.report(event, installationProgress.status.FAILURE));
}
console.log(`${colors.red('Error: ')} ${message}: ${prettyError(error)}`);
process.exit(1);
}

async function createDemoPipeline(runtimeName, progressReporter) {
const pipeline = await sdk.pipelines.create({ metadata: { name: INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME } });
pipeline.spec.runtimeEnvironment = {
name: runtimeName,
Expand All @@ -63,37 +76,37 @@ async function createDemoPipeline(runtimeName) {
version: pipeline.version,
},
);

await to(progressReporter.report(installationProgress.events.PIPELINE_CREATED, installationProgress.status.SUCCESS));
}

async function createAndExecuteDemoPipeline(runtimeName) {
async function createAndExecuteDemoPipeline(runtimeName, progressReporter) {
let demoPipelineExists = false;

try {
const pipelines = await sdk.pipelines.list({ id: INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME });
if (_.get(pipelines, 'docs.length')) {
demoPipelineExists = true;
}
} catch (error) {
console.log(`Failed to fetch account pipelines, cause: ${error.message}`);
const [getPipelinesError, pipelines] = await to(sdk.pipelines.list({ id: INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME }));
if (getPipelinesError) {
console.log(`Failed to fetch account pipelines, cause: ${getPipelinesError.message}`);
} else if (_.get(pipelines, 'docs.length')) {
demoPipelineExists = true;
}

if (!demoPipelineExists) {
console.log(`Creating demo pipeline with the name: "${colors.cyan(INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME)}"`);
try {
await createDemoPipeline(runtimeName);
} catch (error) {
console.log(`${colors.red('Error: ')} Failed to create demo pipeline, cause: ${prettyError(error)}`);
}
const [createDemoPipelineError] = await to(createDemoPipeline(runtimeName, progressReporter));
await handleError(createDemoPipelineError, 'Failed to create demo pipeline', progressReporter, installationProgress.events.PIPELINE_CREATED);
} else {
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 longer than usual.')}`);
console.log(`Executing pipeline "${colors.cyan(INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME)}"`);
await pipelinesRunCmd.handler({
const [pipelineExecutionError] = await to(pipelinesRunCmd.handler({
name: INSTALLATION_DEFAULTS.DEMO_PIPELINE_NAME,
exitProcess: false,
});
}));
await handleError(pipelineExecutionError, 'Failed to run demo pipeline', progressReporter, installationProgress.events.PIPELINE_EXECUTED);

await to(progressReporter.report(installationProgress.events.PIPELINE_EXECUTED, installationProgress.status.SUCCESS));
}

async function getRecommendedKubeNamespace(kubeconfigPath, kubeContextName) {
Expand Down Expand Up @@ -215,7 +228,6 @@ const initCmd = new Command({
'exec-demo-pipeline': shouldExecutePipeline,
token,
} = argv;

if (_.get(sdk, 'config.context.isNoAuth') && !token) {
console.log('Not authenticated as a Codefresh account: ');
console.log('In order to install a Codefresh Runner you need to provide ' +
Expand Down Expand Up @@ -292,48 +304,55 @@ const initCmd = new Command({
4. Execute demo pipeline after install: ${colors.cyan(!!shouldExecutePipeline)}
`);

const [, progress] = await to(async () => installationProgress.create(sdk['runner-installation'], {
options: {
kubeContextName,
kubeNamespace,
shouldMakeDefaultRe,
shouldExecutePipeline,
},
}));

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


if (token) { // Add context
try {
await createContext.handler({
apiKey: token,
name: INSTALLATION_DEFAULTS.CF_CONTEXT_NAME,
url,
});
const config = await getConfigForSdk();
await sdk.configure(config);
console.log(`A Codefresh context named '${INSTALLATION_DEFAULTS.CF_CONTEXT_NAME}' was added to your "cfconfig" file.`);
} catch (error) {
console.log(`${colors.red('Error:')} Could not use the provided token, failed with error: ${prettyError(error)}`);
process.exit(1);
}
const createContextOptions = {
apiKey: token,
name: INSTALLATION_DEFAULTS.CF_CONTEXT_NAME,
url,
};
const [err] = await to(createContext.handler(createContextOptions));
await handleError(err, 'Failed to use the provided token');
const config = await getConfigForSdk();
await sdk.configure(config);
console.log(`A Codefresh context named '${INSTALLATION_DEFAULTS.CF_CONTEXT_NAME}' was added to your "cfconfig" file.`);
} else {
token = _.get(sdk, 'config.context.token');
}

// Install runner and runtime
let runtimeName;
try {
runtimeName = await installAgent.handler({
name,
'kube-context-name': kubeContextName,
'kube-node-selector': kubeNodeSelector,
'dry-run': dryRun,
'in-cluster': inCluster,
'kube-namespace': kubeNamespace,
'kubernetes-runner-type': kubernetesRunnerType,
tolerations,
'venona-version': venonaVersion,
'kube-config-path': kubeConfigPath,
'skip-version-check': skipVersionCheck,
'install-runtime': true,
verbose,
'make-default-runtime': shouldMakeDefaultRe,
terminateProcess: false,
});
} catch (error) {
console.log(`${colors.red('Error: ')} Runner installation failed with error: ${prettyError(error)}`);
process.exit(1);
}
const agentInstallOptions = {
name,
'kube-context-name': kubeContextName,
'kube-node-selector': kubeNodeSelector,
'dry-run': dryRun,
'in-cluster': inCluster,
'kube-namespace': kubeNamespace,
'kubernetes-runner-type': kubernetesRunnerType,
tolerations,
'venona-version': venonaVersion,
'kube-config-path': kubeConfigPath,
'skip-version-check': skipVersionCheck,
'install-runtime': true,
verbose,
'make-default-runtime': shouldMakeDefaultRe,
terminateProcess: false,
};
const [err, runtimeName] = await to(installAgent.handler(agentInstallOptions));
await handleError(err, 'Runner installation failed', progressReporter, installationProgress.events.RUNNER_INSTALLED);

await to(progressReporter.report(installationProgress.events.RUNNER_INSTALLED, installationProgress.status.SUCCESS));

// Install monitoring
await installMonitoring.handler({
Expand All @@ -345,16 +364,18 @@ const initCmd = new Command({
verbose,
noExit: true, // to prevent if from calling: process.exit()
});
await to(progressReporter.report(installationProgress.events.MONITOR_INSTALLED, installationProgress.status.SUCCESS));

// Post Installation
if (shouldExecutePipeline) {
await createAndExecuteDemoPipeline(runtimeName);
await createAndExecuteDemoPipeline(runtimeName, progressReporter);
}

console.log(colors.green('\nRunner Status:'));
await getAgents.handler({});
console.log(colors.green(`\nDocumenation link: ${colors.blue('https://codefresh.io/docs/docs/enterprise/codefresh-runner/#codefresh-runner-preview-release')}`));
console.log(colors.green(`If you had any issues with the installation please report them at: ${colors.blue('https://github.com/codefresh-io/cli/issues/new')}`));
await to(progressReporter.report(installationProgress.events.FINISHED, installationProgress.status.SUCCESS));
process.exit(); // TODO : This is not needed - needed to be fixed
},
});
Expand Down
35 changes: 35 additions & 0 deletions lib/interface/cli/commands/hybrid/installation-process.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
async function create(installer, event) {
const res = await installer.createNewInstallationProgress(event);
return res.progress;
}

function buildReporter(installer, progress) {
return {
report: (event, status, options = {}) => {
const data = {
event,
content: {
status,
...options,
},
};
return installer.reportInstallationProgressEvent({ id: progress.id }, data);
},
};
}

module.exports = {
create,
buildReporter,
events: {
RUNNER_INSTALLED: 'runner-installed',
MONITOR_INSTALLED: 'monitor-installed',
PIPELINE_EXECUTED: 'demo-pipeline-executed',
PIPELINE_CREATED: 'demo-pipeline-created',
FINISHED: 'finished',
},
status: {
SUCCESS: 'success',
FAILURE: 'failure',
},
};
16 changes: 16 additions & 0 deletions lib/logic/cli-config/errors/awaitTo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
async function to(fn) {
try {
let res;
if (typeof fn === 'function') {
res = await fn();
} else {
res = await fn;
}
return [null, res];
} catch (err) {
return [err, null];
}
}
module.exports = {
to,
};
106 changes: 105 additions & 1 deletion openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -7945,7 +7945,102 @@
"agents"
]
}
}
},
"/runner-installation": {
"post": {
"x-endpoint": {
"isEndpoint": false,
"auth": {
"middleware": [
"auth.isAuthenticated"
]
},
"postMiddleware": [
"global.iseMiddleware"
],
"handler": "runner-installation.createNewInstallationProgress"
},
"responses": {
"201": {
"$ref": "#/components/responses/Json"
}
},
"tags": [
"runner-installation"
],
"operationId": "runner-installation-create",
"summary": "Create new runner installation progress",
"x-sdk-interface": "runner-installation.createNewInstallationProgress",
"requestBody": {
"$ref": "#/components/requestBodies/Json"
}
}
},
"/runner-installation/{id}": {
"get": {
"x-endpoint": {
"isEndpoint": false,
"auth": {
"middleware": [
"auth.isAuthenticated"
]
},
"postMiddleware": [
"global.iseMiddleware"
],
"handler": "runner-installation.getInstallationProgress"
},
"parameters": [
{
"$ref": "#/components/parameters/id"
}
],
"responses": {
"200": {
"$ref": "#/components/responses/Json"
}
},
"tags": [
"runner-installation"
],
"operationId": "runner-installation-get",
"summary": "Get new session of runner installation progress",
"x-sdk-interface": "runner-installation.getInstallationProgress"
},
"patch": {
"parameters": [
{
"$ref": "#/components/parameters/id"
}
],
"x-endpoint": {
"isEndpoint": false,
"auth": {
"middleware": [
"auth.isAuthenticated"
]
},
"postMiddleware": [
"global.iseMiddleware"
],
"handler": "runner-installation.reportInstallationProgressEvent"
},
"responses": {
"200": {
"$ref": "#/components/responses/Json"
}
},
"tags": [
"runner-installation"
],
"operationId": "runner-installation-update",
"summary": "Update runner-installation progress",
"x-sdk-interface": "runner-installation.reportInstallationProgressEvent",
"requestBody": {
"$ref": "#/components/requestBodies/Json"
}
}
}
},
"components": {
"parameters": {
Expand Down Expand Up @@ -8204,6 +8299,15 @@
}
}
}
},
"Json": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/requestBody"
}
}
}
}
},
"securitySchemes": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codefresh",
"version": "0.62.4",
"version": "0.63.0",
"description": "Codefresh command line utility",
"main": "index.js",
"preferGlobal": true,
Expand Down

0 comments on commit de16efa

Please sign in to comment.