From 300e8927119e80c2dfb39e784daf6a0a04944d3f Mon Sep 17 00:00:00 2001 From: Anatolii Bazko Date: Tue, 17 Nov 2020 12:11:00 +0200 Subject: [PATCH] Split server:deploy and server:start commands Signed-off-by: Anatolii Bazko --- package.json | 3 +- src/commands/server/deploy.ts | 78 +++++++++----------------------- src/commands/server/logs.ts | 4 -- src/tasks/che.ts | 85 ++++++++++++++++++----------------- src/util.ts | 33 ++++++++++++-- yarn.lock | 6 +-- 6 files changed, 100 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index 3c11c293d..6b2d6b5fc 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,8 @@ "e2e-minikube-helm": "export PLATFORM=minikube && export INSTALLER=helm && yarn jest ./test/e2e/e2e.test.ts --testRegex='/test/(e2e)/.*.test.ts'", "e2e-minikube-operator": "export PLATFORM=minikube && export INSTALLER=operator && yarn jest ./test/e2e/e2e.test.ts --testRegex='/test/(e2e)/.*.test.ts'", "e2e-minishift": "export PLATFORM=minishift && export INSTALLER=operator && yarn jest ./test/e2e/e2e.test.ts --testRegex='/test/(e2e)/.*.test.ts'", - "e2e-openshift": "export PLATFORM=openshift && export INSTALLER=operator && yarn jest ./test/e2e/e2e.test.ts --testRegex='/test/(e2e)/.*.test.ts'", "prepack": "rm -rf lib && rm -rf tsconfig.tsbuildinfo && tsc -b && oclif-dev manifest && oclif-dev readme", + "e2e-openshift": "export PLATFORM=openshift && export INSTALLER=operator && yarn jest ./test/e2e/e2e.test.ts --testRegex='/test/(e2e)/.*.test.ts'", + "prepack": "rm -rf lib && rm -rf tsconfig.tsbuildinfo && tsc -b && oclif-dev manifest && oclif-dev readme", "pack-binaries": "oclif-dev pack", "postpack": "rm -f oclif.manifest.json", "format": "tsfmt -r --useTsfmt tsfmt.json", diff --git a/src/commands/server/deploy.ts b/src/commands/server/deploy.ts index 99fc08c89..7c86dfeb7 100644 --- a/src/commands/server/deploy.ts +++ b/src/commands/server/deploy.ts @@ -14,7 +14,6 @@ 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' @@ -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 { getCommandFailMessage, 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' }), @@ -250,18 +248,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,18 +338,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.installer === 'olm' && flags['olm-suggested-namespace']) { - flags.chenamespace = DEFAULT_OLM_SUGGESTED_NAMESPACE - cli.info(` ❕olm-suggested-namespace flag is turned on. Eclipse Che will be deployed in namespace: ${DEFAULT_OLM_SUGGESTED_NAMESPACE}.`) - } if (flags['self-signed-cert']) { this.warn('"self-signed-cert" flag is deprecated and has no effect. Autodetection is used instead.') @@ -388,18 +364,19 @@ export default class Deploy extends Command { }) await this.setPlaformDefaults(flags, ctx) - 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) + if (flags.installer === 'olm' && flags['olm-suggested-namespace']) { + flags.chenamespace = DEFAULT_OLM_SUGGESTED_NAMESPACE + cli.info(` ❕olm-suggested-namespace flag is turned on. Eclipse Che will be deployed in namespace: ${DEFAULT_OLM_SUGGESTED_NAMESPACE}.`) + } + + let installTasks = new Listr(installerTasks.installTasks(flags, 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) 🚨', @@ -414,44 +391,29 @@ export default class Deploy extends Command { ], ctx.listrOptions) const logsTasks = new Listr([{ - title: 'Start following logs', + title: 'Start 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 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${getCommandFailMessage(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/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..b0a5394e4 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 getCommandFailMessage(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 2a3310ce4..56bedef85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2126,7 +2126,7 @@ ecc-jsbn@~0.1.1: "eclipse-che-devfile-workspace-operator@git://github.com/devfile/devworkspace-operator#master": version "0.0.0" - resolved "git://github.com/devfile/devworkspace-operator#58b0bc3a8ca3f5266bde3eb1090cf131b3d0b9cf" + resolved "git://github.com/devfile/devworkspace-operator#a00c5c16a36183a9092daebaf9d233c08278d54e" "eclipse-che-minishift@git://github.com/minishift/minishift#master": version "0.0.0" @@ -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#a6c758062caa30a4244c6a28f1f6378e6ba94f06" + resolved "git://github.com/eclipse/che-operator#4c194ddeb57e0717b8de7083efdf40cd43634a93" "eclipse-che@git://github.com/eclipse/che#master": version "0.0.0" - resolved "git://github.com/eclipse/che#dc43120bc53353556f647e67d2346cb1d4debf6e" + resolved "git://github.com/eclipse/che#b7c71e0b2b21836ff46411f973a1129fe75d69f2" editorconfig@^0.15.0: version "0.15.3"