diff --git a/README.md b/README.md index 4bac0ccd3..69d7e777b 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ USAGE * [`chectl server:delete`](#chectl-serverdelete) * [`chectl server:deploy`](#chectl-serverdeploy) * [`chectl server:logs`](#chectl-serverlogs) +* [`chectl server:start`](#chectl-serverstart) * [`chectl server:status`](#chectl-serverstatus) * [`chectl server:stop`](#chectl-serverstop) * [`chectl server:update`](#chectl-serverupdate) @@ -419,7 +420,7 @@ _See code: [src/commands/server/delete.ts](https://github.com/che-incubator/chec ## `chectl server:deploy` -start Eclipse Che server +Deploy Eclipse Che server ``` USAGE @@ -571,9 +572,6 @@ OPTIONS --workspace-pvc-storage-class-name=workspace-pvc-storage-class-name persistent volume(s) storage class name to use to store Eclipse Che workspaces data - -ALIASES - $ chectl server:start ``` _See code: [src/commands/server/deploy.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/server/deploy.ts)_ @@ -600,6 +598,40 @@ OPTIONS _See code: [src/commands/server/logs.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/server/logs.ts)_ +## `chectl server:start` + +start Eclipse Che server + +``` +USAGE + $ chectl server:start + +OPTIONS + -d, --directory=directory Directory to store logs into + -h, --help show CLI help + + -n, --chenamespace=chenamespace [default: che] Kubernetes namespace where Eclipse Che server + is supposed to be deployed + + --deployment-name=deployment-name [default: che] Eclipse Che deployment name + + --k8spoddownloadimagetimeout=k8spoddownloadimagetimeout [default: 600000] Waiting time for Pod downloading image (in + milliseconds) + + --k8spoderrorrechecktimeout=k8spoderrorrechecktimeout [default: 15000] Waiting time for Pod rechecking error (in + milliseconds) + + --k8spodreadytimeout=k8spodreadytimeout [default: 600000] Waiting time for Pod Ready condition (in + milliseconds) + + --k8spodwaittimeout=k8spodwaittimeout [default: 600000] Waiting time for Pod scheduled condition + (in milliseconds) + + --skip-kubernetes-health-check Skip Kubernetes health check +``` + +_See code: [src/commands/server/start.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/server/start.ts)_ + ## `chectl server:status` status Eclipse Che server diff --git a/src/commands/server/deploy.ts b/src/commands/server/deploy.ts index 7436f60f7..d43d95a2a 100644 --- a/src/commands/server/deploy.ts +++ b/src/commands/server/deploy.ts @@ -14,11 +14,10 @@ import { cli } from 'cli-ux' import * as fs from 'fs-extra' import * as Listr from 'listr' import * as notifier from 'node-notifier' -import * as os from 'os' import * as path from 'path' -import { DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT, DEFAULT_K8S_POD_TIMEOUT, KubeHelper } from '../../api/kube' -import { cheDeployment, cheNamespace, cheOperatorCRPatchYaml, cheOperatorCRYaml, CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_OPERATOR_CR_YAML_KEY, devWorkspaceControllerNamespace, listrRenderer, skipKubeHealthzCheck as skipK8sHealthCheck } from '../../common-flags' +import { KubeHelper } from '../../api/kube' +import { cheDeployment, cheNamespace, cheOperatorCRPatchYaml, cheOperatorCRYaml, CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_OPERATOR_CR_YAML_KEY, devWorkspaceControllerNamespace, k8sPodDownloadImageTimeout, K8SPODDOWNLOADIMAGETIMEOUT_KEY, k8sPodErrorRecheckTimeout, K8SPODERRORRECHECKTIMEOUT_KEY, k8sPodReadyTimeout, K8SPODREADYTIMEOUT_KEY, k8sPodWaitTimeout, K8SPODWAITTIMEOUT_KEY, listrRenderer, logsDirectory, LOG_DIRECTORY_KEY, skipKubeHealthzCheck as skipK8sHealthCheck } from '../../common-flags' import { DEFAULT_CHE_OPERATOR_IMAGE, DEFAULT_DEV_WORKSPACE_CONTROLLER_IMAGE, DEFAULT_OLM_SUGGESTED_NAMESPACE, DOCS_LINK_INSTALL_RUNNING_CHE_LOCALLY } from '../../constants' import { CheTasks } from '../../tasks/che' import { DevWorkspaceTasks } from '../../tasks/component-installers/devfile-workspace-operator-installer' @@ -27,11 +26,10 @@ import { InstallerTasks } from '../../tasks/installers/installer' import { ApiTasks } from '../../tasks/platforms/api' import { CommonPlatformTasks } from '../../tasks/platforms/common-platform-tasks' import { PlatformTasks } from '../../tasks/platforms/platform' -import { getCommandSuccessMessage, initializeContext, isOpenshiftPlatformFamily } from '../../util' +import { getCommandErrorMessage, getCommandSuccessMessage, initializeContext, isOpenshiftPlatformFamily } from '../../util' export default class Deploy extends Command { - static description = 'start Eclipse Che server' - static aliases = ['server:start'] + static description = 'Deploy Eclipse Che server' static flags: flags.Input = { help: flags.help({ char: 'h' }), @@ -63,22 +61,11 @@ export default class Deploy extends Command { required: true, env: 'CHE_SERVER_BOOT_TIMEOUT' }), - k8spodwaittimeout: string({ - description: 'Waiting time for Pod scheduled condition (in milliseconds)', - default: `${DEFAULT_K8S_POD_TIMEOUT}` - }), - k8spoddownloadimagetimeout: string({ - description: 'Waiting time for Pod downloading image (in milliseconds)', - default: `${DEFAULT_K8S_POD_TIMEOUT}` - }), - k8spodreadytimeout: string({ - description: 'Waiting time for Pod Ready condition (in milliseconds)', - default: `${DEFAULT_K8S_POD_TIMEOUT}` - }), - k8spoderrorrechecktimeout: string({ - description: 'Waiting time for Pod rechecking error (in milliseconds)', - default: `${DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT}` - }), + [K8SPODWAITTIMEOUT_KEY]: k8sPodWaitTimeout, + [K8SPODREADYTIMEOUT_KEY]: k8sPodReadyTimeout, + [K8SPODDOWNLOADIMAGETIMEOUT_KEY]: k8sPodDownloadImageTimeout, + [K8SPODERRORRECHECKTIMEOUT_KEY]: k8sPodErrorRecheckTimeout, + [LOG_DIRECTORY_KEY]: logsDirectory, multiuser: flags.boolean({ char: 'm', description: 'Starts Eclipse Che in multi-user mode', @@ -133,11 +120,6 @@ export default class Deploy extends Command { description: 'Path to yaml file with Helm Chart values patch. The file format is identical to values.yaml from the chart.', default: '', }), - directory: string({ - char: 'd', - description: 'Directory to store logs into', - env: 'CHE_LOGS' - }), 'workspace-pvc-storage-class-name': string({ description: 'persistent volume(s) storage class name to use to store Eclipse Che workspaces data', env: 'CHE_INFRA_KUBERNETES_PVC_STORAGE__CLASS__NAME', @@ -250,18 +232,6 @@ export default class Deploy extends Command { } } - /** - * Determine if a directory is empty. - */ - async isDirEmpty(dirname: string): Promise { - try { - return fs.readdirSync(dirname).length === 0 - // Fails in case if directory doesn't exist - } catch { - return true - } - } - /** * Checks if TLS is disabled via operator custom resource. * Returns true if TLS is enabled (or omitted) and false if it is explicitly disabled. @@ -352,13 +322,8 @@ export default class Deploy extends Command { } async run() { - if (process.argv.indexOf('server:start') > -1) { - this.warn('\'server:start\' command is deprecated. Use \'server:deploy\' instead.') - } - const { flags } = this.parse(Deploy) const ctx = await initializeContext(flags) - ctx.directory = path.resolve(flags.directory ? flags.directory : path.resolve(os.tmpdir(), 'chectl-logs', Date.now().toString())) if (flags['self-signed-cert']) { this.warn('"self-signed-cert" flag is deprecated and has no effect. Autodetection is used instead.') @@ -391,16 +356,11 @@ export default class Deploy extends Command { let installTasks = new Listr(installerTasks.installTasks(flags, this), ctx.listrOptions) - const startDeployedCheTasks = new Listr([{ - title: '๐Ÿ‘€ Starting already deployed Eclipse Che', - task: () => new Listr(cheTasks.scaleCheUpTasks(this)) - }], ctx.listrOptions) - // Post Install Checks const postInstallTasks = new Listr([ { title: 'โœ… Post installation checklist', - task: () => new Listr(cheTasks.waitDeployedChe(flags, this)) + task: () => new Listr(cheTasks.waitDeployedChe()) }, { title: '๐Ÿงช DevWorkspace engine (experimental / technology preview) ๐Ÿšจ', @@ -415,44 +375,29 @@ export default class Deploy extends Command { ], ctx.listrOptions) const logsTasks = new Listr([{ - title: 'Start following logs', + title: 'Following Eclipse Che logs', task: () => new Listr(cheTasks.serverLogsTasks(flags, true)) }], ctx.listrOptions) - const eventTasks = new Listr([{ - title: 'Start following events', - task: () => new Listr(cheTasks.namespaceEventsTask(flags.chenamespace, this, true)) - }], ctx.listrOptions) - try { await preInstallTasks.run(ctx) - if (!ctx.isCheDeployed) { + if (ctx.isCheDeployed) { + let message = 'Eclipse Che has been already deployed.' + if (!ctx.isCheReady) { + message += ' Use server:start command to start a stopped Eclipse Che instance.' + } + cli.warn(message) + } else { this.checkPlatformCompatibility(flags) await platformCheckTasks.run(ctx) await logsTasks.run(ctx) - await eventTasks.run(ctx) await installTasks.run(ctx) - } else if (!ctx.isCheReady - || (ctx.isPostgresDeployed && !ctx.isPostgresReady) - || (ctx.isKeycloakDeployed && !ctx.isKeycloakReady) - || (ctx.isPluginRegistryDeployed && !ctx.isPluginRegistryReady) - || (ctx.isDevfileRegistryDeployed && !ctx.isDevfileRegistryReady)) { - if (flags.platform || flags.installer) { - this.warn('Deployed Eclipse Che is found and the specified installation parameters will be ignored') - } - // perform Eclipse Che start task if there is any component that is not ready - await startDeployedCheTasks.run(ctx) + await postInstallTasks.run(ctx) + this.log(getCommandSuccessMessage(this, ctx)) } - - await postInstallTasks.run(ctx) - this.log(getCommandSuccessMessage(this, ctx)) } catch (err) { - const isDirEmpty = await this.isDirEmpty(ctx.directory) - if (isDirEmpty) { - this.error(`${err}\nInstallation failed. Error log: ${this.config.errlog}`) - } - this.error(`${err}\nInstallation failed. Error log: ${this.config.errlog}. Eclipse Che logs: ${ctx.directory}`) + this.error(`${err}\n${getCommandErrorMessage(this, ctx)}`) } notifier.notify({ diff --git a/src/commands/server/logs.ts b/src/commands/server/logs.ts index b4c3e1b12..a07b7db91 100644 --- a/src/commands/server/logs.ts +++ b/src/commands/server/logs.ts @@ -12,8 +12,6 @@ import { Command, flags } from '@oclif/command' import { string } from '@oclif/parser/lib/flags' import * as Listr from 'listr' import * as notifier from 'node-notifier' -import * as os from 'os' -import * as path from 'path' import { cheDeployment, cheNamespace, listrRenderer, skipKubeHealthzCheck } from '../../common-flags' import { CheTasks } from '../../tasks/che' @@ -39,7 +37,6 @@ export default class Logs extends Command { async run() { const { flags } = this.parse(Logs) const ctx = await initializeContext(flags) - ctx.directory = path.resolve(flags.directory ? flags.directory : path.resolve(os.tmpdir(), 'chectl-logs', Date.now().toString())) const cheTasks = new CheTasks(flags) const apiTasks = new ApiTasks() const tasks = new Listr([], { renderer: flags['listr-renderer'] as any }) @@ -47,7 +44,6 @@ export default class Logs extends Command { tasks.add(apiTasks.testApiTasks(flags, this)) tasks.add(cheTasks.verifyCheNamespaceExistsTask(flags, this)) tasks.add(cheTasks.serverLogsTasks(flags, false)) - tasks.add(cheTasks.namespaceEventsTask(flags.chenamespace, this, false)) try { this.log(`Eclipse Che logs will be available in '${ctx.directory}'`) diff --git a/src/commands/server/start.ts b/src/commands/server/start.ts new file mode 100644 index 000000000..5c420ec0e --- /dev/null +++ b/src/commands/server/start.ts @@ -0,0 +1,86 @@ +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { Command, flags } from '@oclif/command' +import { cli } from 'cli-ux' +import * as Listr from 'listr' +import * as notifier from 'node-notifier' + +import { cheDeployment, cheNamespace, k8sPodDownloadImageTimeout, K8SPODDOWNLOADIMAGETIMEOUT_KEY, k8sPodErrorRecheckTimeout, K8SPODERRORRECHECKTIMEOUT_KEY, k8sPodReadyTimeout, K8SPODREADYTIMEOUT_KEY, k8sPodWaitTimeout, K8SPODWAITTIMEOUT_KEY, listrRenderer, logsDirectory, LOG_DIRECTORY_KEY, skipKubeHealthzCheck } from '../../common-flags' +import { CheTasks } from '../../tasks/che' +import { ApiTasks } from '../../tasks/platforms/api' +import { getCommandErrorMessage, getCommandSuccessMessage, initializeContext } from '../../util' + +export default class Start extends Command { + static description = 'Start Eclipse Che server' + + static flags: flags.Input = { + help: flags.help({ char: 'h' }), + chenamespace: cheNamespace, + 'listr-renderer': listrRenderer, + 'deployment-name': cheDeployment, + [K8SPODWAITTIMEOUT_KEY]: k8sPodWaitTimeout, + [K8SPODREADYTIMEOUT_KEY]: k8sPodReadyTimeout, + [K8SPODDOWNLOADIMAGETIMEOUT_KEY]: k8sPodDownloadImageTimeout, + [K8SPODERRORRECHECKTIMEOUT_KEY]: k8sPodErrorRecheckTimeout, + [LOG_DIRECTORY_KEY]: logsDirectory, + 'skip-kubernetes-health-check': skipKubeHealthzCheck, + } + + async run() { + const { flags } = this.parse(Start) + const ctx = await initializeContext(flags) + + const cheTasks = new CheTasks(flags) + const apiTasks = new ApiTasks() + + // Checks if Eclipse Che is already deployed + const preInstallTasks = new Listr([ + apiTasks.testApiTasks(flags, this), + { + title: '๐Ÿ‘€ Looking for an already existing Eclipse Che instance', + task: () => new Listr(cheTasks.checkIfCheIsInstalledTasks(flags, this)) + }], ctx.listrOptions) + + const logsTasks = new Listr([{ + title: 'Following Eclipse Che logs', + task: () => new Listr(cheTasks.serverLogsTasks(flags, true)) + }], ctx.listrOptions) + + const startCheTasks = new Listr([{ + title: 'Starting Eclipse Che', + task: () => new Listr(cheTasks.scaleCheUpTasks()) + }], ctx.listrOptions) + + try { + await preInstallTasks.run(ctx) + + if (!ctx.isCheDeployed) { + cli.warn('Eclipse Che has not been deployed yet. Use server:deploy command to deploy a new Eclipse Che instance.') + } else if (ctx.isCheReady) { + cli.info('Eclipse Che has been already started.') + } else { + await logsTasks.run(ctx) + await startCheTasks.run(ctx) + this.log(getCommandSuccessMessage(this, ctx)) + } + } catch (err) { + this.error(`${err}\n${getCommandErrorMessage(this, ctx)}`) + } + + notifier.notify({ + title: 'chectl', + message: getCommandSuccessMessage(this, ctx) + }) + + this.exit(0) + } + +} diff --git a/src/common-flags.ts b/src/common-flags.ts index 8c95276e0..33dcf93f8 100644 --- a/src/common-flags.ts +++ b/src/common-flags.ts @@ -9,6 +9,7 @@ **********************************************************************/ import { boolean, string } from '@oclif/parser/lib/flags' +import { DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT, DEFAULT_K8S_POD_TIMEOUT } from './api/kube' import { DEFAULT_DEV_WORKSPACE_CONTROLLER_NAMESPACE, DOC_LINK_OBTAIN_ACCESS_TOKEN, DOC_LINK_OBTAIN_ACCESS_TOKEN_OAUTH } from './constants' export const cheNamespace = string({ @@ -81,3 +82,34 @@ export const username = string({ env: 'CHE_USER_NAME', required: false, }) + +export const K8SPODWAITTIMEOUT_KEY = 'k8spodwaittimeout' +export const k8sPodWaitTimeout = string({ + description: 'Waiting time for Pod scheduled condition (in milliseconds)', + default: `${DEFAULT_K8S_POD_TIMEOUT}` +}) + +export const K8SPODDOWNLOADIMAGETIMEOUT_KEY = 'k8spoddownloadimagetimeout' +export const k8sPodDownloadImageTimeout = string({ + description: 'Waiting time for Pod downloading image (in milliseconds)', + default: `${DEFAULT_K8S_POD_TIMEOUT}` +}) + +export const K8SPODREADYTIMEOUT_KEY = 'k8spodreadytimeout' +export const k8sPodReadyTimeout = string({ + description: 'Waiting time for Pod Ready condition (in milliseconds)', + default: `${DEFAULT_K8S_POD_TIMEOUT}` +}) + +export const K8SPODERRORRECHECKTIMEOUT_KEY = 'k8spoderrorrechecktimeout' +export const k8sPodErrorRecheckTimeout = string({ + description: 'Waiting time for Pod rechecking error (in milliseconds)', + default: `${DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT}` +}) + +export const LOG_DIRECTORY_KEY = 'directory' +export const logsDirectory = string({ + char: 'd', + description: 'Directory to store logs into', + env: 'CHE_LOGS' +}) diff --git a/src/tasks/che.ts b/src/tasks/che.ts index 2926a7c99..e9c8c6357 100644 --- a/src/tasks/che.ts +++ b/src/tasks/che.ts @@ -67,17 +67,15 @@ export class CheTasks { * * @see che.checkIfCheIsInstalledTasks */ - waitDeployedChe(flags: any, _command: Command): ReadonlyArray { + waitDeployedChe(): ReadonlyArray { return [ { title: 'PostgreSQL pod bootstrap', - skip: () => !flags.multiuser, enabled: ctx => ctx.isPostgresDeployed && !ctx.isPostgresReady, task: () => this.kubeTasks.podStartTasks(this.postgresSelector, this.cheNamespace) }, { title: 'Keycloak pod bootstrap', - skip: () => !flags.multiuser, enabled: ctx => ctx.isKeycloakDeployed && !ctx.isKeycloakReady, task: () => this.kubeTasks.podStartTasks(this.keycloakSelector, this.cheNamespace) }, @@ -207,43 +205,54 @@ export class CheTasks { } /** - * Returns tasks list which scale down all Eclipse Che components which are deployed. + * Returns tasks list which scale up all Eclipse Che components which are deployed. * It requires {@link this#checkIfCheIsInstalledTasks} to be executed before. * * @see [CheTasks](#checkIfCheIsInstalledTasks) */ - scaleCheUpTasks(_command: Command): ReadonlyArray { + scaleCheUpTasks(): ReadonlyArray { return [ { - title: 'Scaling up Eclipse Che Deployments', - enabled: (ctx: any) => ctx.isCheDeployed, - task: async (ctx: any, task: any) => { - if (ctx.isPostgresDeployed) { - await this.kube.scaleDeployment(this.postgresDeploymentName, this.cheNamespace, 1) - } - if (ctx.isKeycloakDeployed) { - await this.kube.scaleDeployment(this.keycloakDeploymentName, this.cheNamespace, 1) - } - if (ctx.isPluginRegistryDeployed) { - await this.kube.scaleDeployment(this.pluginRegistryDeploymentName, this.cheNamespace, 1) - } - if (ctx.isDevfileRegistryDeployed) { - await this.kube.scaleDeployment(this.devfileRegistryDeploymentName, this.cheNamespace, 1) - } - await this.kube.scaleDeployment(this.cheDeploymentName, this.cheNamespace, 1) - task.title = `${task.title}...done.` + title: 'PostgreSQL pod bootstrap', + enabled: ctx => ctx.isPostgresDeployed && !ctx.isPostgresReady, + task: async () => { + await this.kube.scaleDeployment(this.postgresDeploymentName, this.cheNamespace, 1) + return this.kubeTasks.podStartTasks(this.postgresSelector, this.cheNamespace) } }, { - title: `Eclipse Che is already running in namespace \"${this.cheNamespace}\".`, - enabled: (ctx: any) => (ctx.isCheDeployed && ctx.isCheAvailable), - task: async (ctx: any, task: any) => { - ctx.cheDeploymentExist = true - ctx.cheIsAlreadyRunning = true - ctx.cheURL = await this.che.cheURL(this.cheNamespace) - task.title = await `${task.title}...it's URL is ${ctx.cheURL}` + title: 'Keycloak pod bootstrap', + enabled: ctx => ctx.isKeycloakDeployed && !ctx.isKeycloakReady, + task: async () => { + await this.kube.scaleDeployment(this.keycloakDeploymentName, this.cheNamespace, 1) + return this.kubeTasks.podStartTasks(this.keycloakSelector, this.cheNamespace) } - } + }, + { + title: 'Devfile registry pod bootstrap', + enabled: ctx => ctx.isDevfileRegistryDeployed && !ctx.isDevfileRegistryReady, + task: async () => { + await this.kube.scaleDeployment(this.devfileRegistryDeploymentName, this.cheNamespace, 1) + return this.kubeTasks.podStartTasks(this.devfileRegistrySelector, this.cheNamespace) + } + }, + { + title: 'Plugin registry pod bootstrap', + enabled: ctx => ctx.isPluginRegistryDeployed && !ctx.isPluginRegistryReady, + task: async () => { + await this.kube.scaleDeployment(this.pluginRegistryDeploymentName, this.cheNamespace, 1) + return this.kubeTasks.podStartTasks(this.pluginRegistrySelector, this.cheNamespace) + } + }, + { + title: 'Eclipse Che pod bootstrap', + enabled: ctx => ctx.isCheDeployed && !ctx.isCheReady, + task: async () => { + await this.kube.scaleDeployment(this.cheDeploymentName, this.cheNamespace, 1) + return this.kubeTasks.podStartTasks(this.cheSelector, this.cheNamespace) + } + }, + ...this.checkEclipseCheStatus() ] } @@ -525,14 +534,14 @@ export class CheTasks { return [ { title: `${follow ? 'Start following' : 'Read'} Operator logs`, - skip: () => flags.installer !== 'operator' && flags.installer !== 'olm', + skip: () => flags.installer === 'helm', task: async (ctx: any, task: any) => { await this.che.readPodLog(flags.chenamespace, CHE_OPERATOR_SELECTOR, ctx.directory, follow) task.title = `${task.title}...done` } }, { - title: `${follow ? 'Start following' : 'Read'} Eclipse Che logs`, + title: `${follow ? 'Start following' : 'Read'} Eclipse Che server logs`, task: async (ctx: any, task: any) => { await this.che.readPodLog(flags.chenamespace, this.cheSelector, ctx.directory, follow) task.title = await `${task.title}...done` @@ -565,16 +574,11 @@ export class CheTasks { await this.che.readPodLog(flags.chenamespace, this.devfileRegistrySelector, ctx.directory, follow) task.title = await `${task.title}...done` } - } - ] - } - - namespaceEventsTask(namespace: string, command: Command, follow: boolean): ReadonlyArray { - return [ + }, { title: `${follow ? 'Start following' : 'Read'} namespace events`, task: async (ctx: any, task: any) => { - await this.che.readNamespaceEvents(namespace, ctx.directory, follow).catch(e => command.error(e.message)) + await this.che.readNamespaceEvents(flags.chenamespace, ctx.directory, follow) task.title = await `${task.title}...done` } } @@ -667,8 +671,9 @@ export class CheTasks { return [ { title: 'Eclipse Che status check', - task: async ctx => { + task: async (ctx, task) => { const cheApi = CheApiClient.getInstance(ctx.cheURL + '/api') + task.title = `${task.title}...done` return cheApi.isCheServerReady() } } diff --git a/src/util.ts b/src/util.ts index 747810940..b5fde5ecb 100644 --- a/src/util.ts +++ b/src/util.ts @@ -10,9 +10,11 @@ import { Command } from '@oclif/command' import * as commandExists from 'command-exists' -import { existsSync, readFileSync } from 'fs-extra' +import * as fs from 'fs-extra' import * as yaml from 'js-yaml' import Listr = require('listr') +import * as os from 'os' +import * as path from 'path' import { KubeHelper } from './api/kube' import { CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_OPERATOR_CR_YAML_KEY } from './common-flags' @@ -114,6 +116,7 @@ export async function initializeContext(flags?: any): Promise { ctx.startTime = Date.now() ctx.customCR = readCRFile(flags, CHE_OPERATOR_CR_YAML_KEY) ctx.crPatch = readCRFile(flags, CHE_OPERATOR_CR_PATCH_YAML_KEY) + ctx.directory = path.resolve(flags.directory ? flags.directory : path.resolve(os.tmpdir(), 'chectl-logs', Date.now().toString())) if (flags['listr-renderer'] as any) { ctx.listrOptions = { renderer: (flags['listr-renderer'] as any), collapse: false } as Listr.ListrOptions } @@ -132,8 +135,8 @@ export function readCRFile(flags: any, CRKey: string): any { return } - if (existsSync(CRFilePath)) { - return yaml.safeLoad(readFileSync(CRFilePath).toString()) + if (fs.existsSync(CRFilePath)) { + return yaml.safeLoad(fs.readFileSync(CRFilePath).toString()) } throw new Error(`Unable to find file defined in the flag '--${CRKey}'`) @@ -158,3 +161,27 @@ export function getCommandSuccessMessage(command: Command, ctx: any): string { return `Command ${command.id} has completed successfully.` } + +/** + * Determine if a directory is empty. + */ +export function isDirEmpty(dirname: string): boolean { + try { + return fs.readdirSync(dirname).length === 0 + // Fails in case if directory doesn't exist + } catch { + return true + } +} + +/** + * Returns command success message with execution time. + */ +export function getCommandErrorMessage(command: Command, ctx: any): string { + let message = `Command ${command.id} failed. Error log: ${command.config.errlog}` + if (ctx.directory && isDirEmpty(ctx.directory)) { + message += ` Eclipse Che logs: ${ctx.directory}` + } + + return message +} diff --git a/yarn.lock b/yarn.lock index 8dde985a6..ccdccc376 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2134,11 +2134,11 @@ ecc-jsbn@~0.1.1: "eclipse-che-operator@git://github.com/eclipse/che-operator#master": version "0.0.0" - resolved "git://github.com/eclipse/che-operator#2e0bfecd456e20e2c289533fe40f05e5c5d78f3e" + resolved "git://github.com/eclipse/che-operator#2e957457f5ab5a9fd370f8915ffedd0c321af240" "eclipse-che@git://github.com/eclipse/che#master": version "0.0.0" - resolved "git://github.com/eclipse/che#74e4f757166d30a19dd296dfa601cdd0f30d05b0" + resolved "git://github.com/eclipse/che#c1353d3d97f64583ed7e4f4fffe79771e0a746c5" editorconfig@^0.15.0: version "0.15.3"