From de16efa389fff384d6b42764c4c6ff704f5031fa Mon Sep 17 00:00:00 2001 From: Oleg Sucharevich Date: Mon, 18 May 2020 17:31:55 +0300 Subject: [PATCH] =?UTF-8?q?report=20installation=20progress=20to=20codefre?= =?UTF-8?q?sh=20to=20support=20idiomatic=20instal=E2=80=A6=20(#459)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * report installation progress to codefresh to support idiomatic installation * report failures --- lib/interface/cli/commands/hybrid/init.cmd.js | 129 ++++++++++-------- .../commands/hybrid/installation-process.js | 35 +++++ lib/logic/cli-config/errors/awaitTo.js | 16 +++ openapi.json | 106 +++++++++++++- package.json | 2 +- 5 files changed, 232 insertions(+), 56 deletions(-) create mode 100644 lib/interface/cli/commands/hybrid/installation-process.js create mode 100644 lib/logic/cli-config/errors/awaitTo.js diff --git a/lib/interface/cli/commands/hybrid/init.cmd.js b/lib/interface/cli/commands/hybrid/init.cmd.js index 0fe9fee26..b56c4c324 100644 --- a/lib/interface/cli/commands/hybrid/init.cmd.js +++ b/lib/interface/cli/commands/hybrid/init.cmd.js @@ -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', @@ -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, @@ -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) { @@ -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 ' + @@ -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({ @@ -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 }, }); diff --git a/lib/interface/cli/commands/hybrid/installation-process.js b/lib/interface/cli/commands/hybrid/installation-process.js new file mode 100644 index 000000000..6d5645ecb --- /dev/null +++ b/lib/interface/cli/commands/hybrid/installation-process.js @@ -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', + }, +}; diff --git a/lib/logic/cli-config/errors/awaitTo.js b/lib/logic/cli-config/errors/awaitTo.js new file mode 100644 index 000000000..63d9bdb3d --- /dev/null +++ b/lib/logic/cli-config/errors/awaitTo.js @@ -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, +}; diff --git a/openapi.json b/openapi.json index a40d6d895..f91dacd0d 100644 --- a/openapi.json +++ b/openapi.json @@ -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": { @@ -8204,6 +8299,15 @@ } } } + }, + "Json": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/requestBody" + } + } + } } }, "securitySchemes": { diff --git a/package.json b/package.json index 5985218cf..175b623f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codefresh", - "version": "0.62.4", + "version": "0.63.0", "description": "Codefresh command line utility", "main": "index.js", "preferGlobal": true,