Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve messages in server:update command #1022

Merged
merged 6 commits into from
Dec 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 112 additions & 26 deletions src/commands/server/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { string } from '@oclif/parser/lib/flags'
import { cli } from 'cli-ux'
import * as fs from 'fs-extra'
import * as Listr from 'listr'
import { merge } from 'lodash'
import * as path from 'path'

import { ChectlContext } from '../../api/context'
Expand All @@ -23,11 +24,20 @@ import { getPrintHighlightedMessagesTask } from '../../tasks/installers/common-t
import { InstallerTasks } from '../../tasks/installers/installer'
import { ApiTasks } from '../../tasks/platforms/api'
import { CommonPlatformTasks } from '../../tasks/platforms/common-platform-tasks'
import { getCommandErrorMessage, getCommandSuccessMessage, getImageTag, notifyCommandCompletedSuccessfully } from '../../util'
import { getCommandErrorMessage, getCommandSuccessMessage, getCurrentChectlName, getCurrentChectlVersion, getImageTag, getLatestChectlVersion, notifyCommandCompletedSuccessfully } from '../../util'

export default class Update extends Command {
static description = 'Update Eclipse Che server.'

static examples = [
'# Update Eclipse Che:\n' +
'chectl server:update',
'\n\n# Update Eclipse Che in \'eclipse-che\' namespace:' +
'chectl server:update -n eclipse-che',
'\n\n# Update Eclipse Che and update its configuration in the custom resource:' +
`chectl server:update --${CHE_OPERATOR_CR_PATCH_YAML_KEY} patch.yaml`,
]

static flags: flags.Input<any> = {
installer: string({
char: 'a',
Expand Down Expand Up @@ -110,40 +120,116 @@ export default class Update extends Command {

try {
await preUpdateTasks.run(ctx)
} catch (err) {
this.error(getCommandErrorMessage(err))
}

if (!flags.yes) {
cli.info(`Existed Eclipse Che operator: ${ctx.deployedCheOperatorImage}:${ctx.deployedCheOperatorTag}.`)
cli.info(`New Eclipse Che operator : ${ctx.newCheOperatorImage}:${ctx.newCheOperatorTag}.`)
if (flags.installer === 'operator') {
const existedOperatorImage = `${ctx.deployedCheOperatorImage}:${ctx.deployedCheOperatorTag}`
const newOperatorImage = `${ctx.newCheOperatorImage}:${ctx.newCheOperatorTag}`
cli.info(`Existed Eclipse Che operator: ${existedOperatorImage}.`)
cli.info(`New Eclipse Che operator : ${newOperatorImage}.`)

if (flags['che-operator-image'] !== DEFAULT_CHE_OPERATOR_IMAGE) {
cli.warn(`This command updates Eclipse Che to ${getImageTag(DEFAULT_CHE_OPERATOR_IMAGE)} version, but custom operator image is specified.`)
cli.warn('Make sure that the new version of the Eclipse Che is corresponding to the version of the tool you use.')
cli.warn('Consider using \'chectl update [stable|next]\' to update to the latest version of chectl.')
}
const defaultOperatorImageTag = getImageTag(DEFAULT_CHE_OPERATOR_IMAGE)
const chectlChannel = defaultOperatorImageTag === 'nightly' ? 'next' : 'stable'
const currentChectlVersion = getCurrentChectlVersion()
const latestChectlVersion = await getLatestChectlVersion(chectlChannel)
const chectlName = getCurrentChectlName()

const cheCluster = await kubeHelper.getCheCluster(flags.chenamespace)
if (cheCluster.spec.server.cheImage
|| cheCluster.spec.server.cheImageTag
|| cheCluster.spec.server.devfileRegistryImage
|| cheCluster.spec.database.postgresImage
|| cheCluster.spec.server.pluginRegistryImage
|| cheCluster.spec.auth.identityProviderImage) {
cli.warn(`In order to update Eclipse Che the images defined in the '${cheCluster.metadata.name}'
Custom Resource of the namespace '${flags.chenamespace}' will be cleaned up:`)
cheCluster.spec.server.cheImageTag && cli.warn(`Eclipse Che server image tag [${cheCluster.spec.server.cheImageTag}]`)
cheCluster.spec.server.cheImage && cli.warn(`Eclipse Che server [${cheCluster.spec.server.cheImage}]`)
cheCluster.spec.database.postgresImage && cli.warn(`Database [${cheCluster.spec.database.postgresImage}]`)
cheCluster.spec.server.devfileRegistryImage && cli.warn(`Devfile registry [${cheCluster.spec.server.devfileRegistryImage}]`)
cheCluster.spec.server.pluginRegistryImage && cli.warn(`Plugin registry [${cheCluster.spec.server.pluginRegistryImage}]`)
cheCluster.spec.auth.identityProviderImage && cli.warn(`Identity provider [${cheCluster.spec.auth.identityProviderImage}]`)
// the same version is already installed
if (newOperatorImage === existedOperatorImage) {
if (chectlName === 'chectl' && latestChectlVersion) {
// suggest update chectl first
if (currentChectlVersion !== latestChectlVersion) {
cli.warn(`It is not possible to update Eclipse Che to a newer version
using the current '${currentChectlVersion}' version of chectl. Please, update 'chectl'
to a newer version '${latestChectlVersion}' with the command 'chectl update ${chectlChannel}'
and then try again.`)
Comment on lines +144 to +147
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move into a function with args that returns the message? Then block below will not be duplicated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is slightly different.

} else if (!flags[CHE_OPERATOR_CR_PATCH_YAML_KEY]) {
// same version, no patch then nothing to update
cli.info('Eclipse Che is already up to date.')
this.exit(0)
}
} else {
// unknown project, no patch file then suggest to update
if (!flags[CHE_OPERATOR_CR_PATCH_YAML_KEY]) {
cli.warn(`It is not possible to update Eclipse Che to a newer version
using the current '${currentChectlVersion}' version of '${getCurrentChectlName()}'.
Please, update '${getCurrentChectlName()}' and then try again.`)
this.exit(0)
}
}
// custom operator image is used
} else if (newOperatorImage !== DEFAULT_CHE_OPERATOR_IMAGE) {
cli.warn(`Eclipse Che operator deployment will be updated with the provided image,
but other Eclipse Che components will be updated to the ${defaultOperatorImageTag} version.
Consider removing '--che-operator-image' to update Eclipse Che operator to the same version.`)
}

if (!flags.yes && !await cli.confirm('If you want to continue - press Y')) {
cli.info('Update cancelled by user.')
this.exit(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice to print something into output, like Update cancelled by user

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

}
}

const cheCluster = await kubeHelper.getCheCluster(flags.chenamespace)
if (cheCluster.spec.server.cheImage
|| cheCluster.spec.server.cheImageTag
|| cheCluster.spec.server.devfileRegistryImage
|| cheCluster.spec.database.postgresImage
|| cheCluster.spec.server.pluginRegistryImage
|| cheCluster.spec.auth.identityProviderImage) {
let imagesListMsg = ''

const crPatch = ctx[ChectlContext.CR_PATCH] || {}
if (cheCluster.spec.server.pluginRegistryImage
&& (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.pluginRegistryImage)) {
imagesListMsg += `\n - Plugin registry image: ${cheCluster.spec.server.pluginRegistryImage}`
merge(crPatch, { spec: { server: { pluginRegistryImage: '' } } })
}

const confirmed = await cli.confirm('If you want to continue - press Y')
if (!confirmed) {
if (cheCluster.spec.server.devfileRegistryImage
&& (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.devfileRegistryImage)) {
imagesListMsg += `\n - Devfile registry image: ${cheCluster.spec.server.devfileRegistryImage}`
merge(crPatch, { spec: { server: { devfileRegistryImage: '' } } })
}

if (cheCluster.spec.server.postgresImage
&& (!crPatch.spec || !crPatch.spec.database || !crPatch.spec.database.postgresImage)) {
imagesListMsg += `\n - Postgres image: ${cheCluster.spec.database.postgresImage}`
merge(crPatch, { spec: { database: { postgresImage: '' } } })
}

if (cheCluster.spec.server.identityProviderImage
&& (!crPatch.spec || !crPatch.spec.auth || !crPatch.spec.auth.identityProviderImage)) {
imagesListMsg += `\n - Identity provider image: ${cheCluster.spec.auth.identityProviderImage}`
merge(crPatch, { spec: { auth: { identityProviderImage: '' } } })
}

if (cheCluster.spec.server.cheImage
&& (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.cheImage)) {
imagesListMsg += `\n - Eclipse Che server image name: ${cheCluster.spec.server.cheImage}`
merge(crPatch, { spec: { server: { cheImage: '' } } })
}

if (cheCluster.spec.server.cheImageTag
&& (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.cheImageTag)) {
imagesListMsg += `\n - Eclipse Che server image tag: ${cheCluster.spec.server.cheImageTag}`
merge(crPatch, { spec: { server: { cheImageTag: '' } } })
}
ctx[ChectlContext.CR_PATCH] = crPatch

if (imagesListMsg) {
cli.warn(`In order to update Eclipse Che to a newer version the fields defining the images in the '${cheCluster.metadata.name}'
Custom Resource in the '${flags.chenamespace}' namespace will be cleaned up:${imagesListMsg}`)
if (!flags.yes && !await cli.confirm('If you want to continue - press Y')) {
cli.info('Update cancelled by user.')
this.exit(0)
mmorhun marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

try {
await updateTasks.run(ctx)
await postUpdateTasks.run(ctx)

Expand Down
31 changes: 7 additions & 24 deletions src/tasks/installers/common-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import Command from '@oclif/command'
import ansi = require('ansi-colors')
import { copy, mkdirp, remove } from 'fs-extra'
import * as Listr from 'listr'
import { merge } from 'lodash'
import { isEmpty } from 'lodash'
import * as path from 'path'

import { CheHelper } from '../../api/che'
import { ChectlContext } from '../../api/context'
import { KubeHelper } from '../../api/kube'
import { CHE_CLUSTER_CRD, DOCS_LINK_IMPORT_CA_CERT_INTO_BROWSER } from '../../constants'

Expand Down Expand Up @@ -97,34 +98,16 @@ export function createEclipseCheCluster(flags: any, kube: KubeHelper): Listr.Lis
* @param kube - kubeHelper util
* @param command - parent command
*/
export function updateEclipseCheCluster(flags: any, kube: KubeHelper, command: Command): Listr.ListrTask {
export function patchingEclipseCheCluster(flags: any, kube: KubeHelper, command: Command): Listr.ListrTask {
return {
title: `Update the Custom Resource of type ${CHE_CLUSTER_CRD} in the namespace ${flags.chenamespace}`,
title: `Patching the Custom Resource of type '${CHE_CLUSTER_CRD}' in the namespace '${flags.chenamespace}'`,
skip: (ctx: any) => isEmpty(ctx[ChectlContext.CR_PATCH]),
task: async (ctx: any, task: any) => {
let crPatch: any = ctx.crPatch || {}

const cheCluster = await kube.getCheCluster(flags.chenamespace)
if (!cheCluster) {
command.error(`Eclipse Che cluster CR was not found in the namespace ${flags.chenamespace}`)
}

if (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.pluginRegistryImage) {
merge(crPatch, { spec: { server: { pluginRegistryImage: '' } } })
}
if (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.devfileRegistryImage) {
merge(crPatch, { spec: { server: { devfileRegistryImage: '' } } })
command.error(`Eclipse Che cluster CR is not found in the namespace '${flags.chenamespace}'`)
}
if (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.identityProviderImage) {
merge(crPatch, { spec: { server: { identityProviderImage: '' } } })
}
if (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.cheImage) {
merge(crPatch, { spec: { server: { cheImage: '' } } })
}
if (!crPatch.spec || !crPatch.spec.server || !crPatch.spec.server.cheImageTag) {
merge(crPatch, { spec: { server: { cheImageTag: '' } } })
}

await kube.patchCheCluster(cheCluster.metadata.name, flags.chenamespace, crPatch)
await kube.patchCheCluster(cheCluster.metadata.name, flags.chenamespace, ctx[ChectlContext.CR_PATCH])
task.title = `${task.title}...done.`
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/tasks/installers/olm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { CatalogSource, Subscription } from '../../api/typings/olm'
import { CUSTOM_CATALOG_SOURCE_NAME, CVS_PREFIX, DEFAULT_CHE_OLM_PACKAGE_NAME, DEFAULT_OLM_KUBERNETES_NAMESPACE, DEFAULT_OPENSHIFT_MARKET_PLACE_NAMESPACE, KUBERNETES_OLM_CATALOG, NIGHTLY_CATALOG_SOURCE_NAME, OLM_NIGHTLY_CHANNEL_NAME, OLM_STABLE_CHANNEL_NAME, OPENSHIFT_OLM_CATALOG, OPERATOR_GROUP_NAME, SUBSCRIPTION_NAME } from '../../constants'
import { isKubernetesPlatformFamily, isStableVersion } from '../../util'

import { createEclipseCheCluster, createNamespaceTask, updateEclipseCheCluster } from './common-tasks'
import { createEclipseCheCluster, createNamespaceTask, patchingEclipseCheCluster } from './common-tasks'

export class OLMTasks {
prometheusRoleName = 'prometheus-k8s'
Expand Down Expand Up @@ -269,7 +269,7 @@ export class OLMTasks {
task.title = `${task.title}...done.`
}
},
updateEclipseCheCluster(flags, kube, command)
patchingEclipseCheCluster(flags, kube, command)
], { renderer: flags['listr-renderer'] as any })
}

Expand Down
4 changes: 2 additions & 2 deletions src/tasks/installers/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { CHE_CLUSTER_CRD, CHE_OPERATOR_SELECTOR, OPERATOR_DEPLOYMENT_NAME } from
import { isStableVersion } from '../../util'
import { KubeTasks } from '../kube'

import { copyOperatorResources, createEclipseCheCluster, createNamespaceTask, updateEclipseCheCluster } from './common-tasks'
import { copyOperatorResources, createEclipseCheCluster, createNamespaceTask, patchingEclipseCheCluster } from './common-tasks'

export class OperatorTasks {
operatorServiceAccount = 'che-operator'
Expand Down Expand Up @@ -380,7 +380,7 @@ export class OperatorTasks {
await kube.waitLatestReplica(OPERATOR_DEPLOYMENT_NAME, flags.chenamespace)
}
},
updateEclipseCheCluster(flags, kube, command),
patchingEclipseCheCluster(flags, kube, command),
], { renderer: flags['listr-renderer'] as any })
}

Expand Down
38 changes: 38 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import axios from 'axios'
import * as commandExists from 'command-exists'
import * as fs from 'fs-extra'
import * as https from 'https'
import * as yaml from 'js-yaml'
import * as notifier from 'node-notifier'

import * as pjson from '../package.json'

import { ChectlContext } from './api/context'
import { DEFAULT_CHE_OPERATOR_IMAGE } from './constants'

Expand Down Expand Up @@ -174,3 +178,37 @@ export function getCommandErrorMessage(err: Error): string {

return message
}

/**
* Returns current chectl version defined in package.json.
*/
export function getCurrentChectlVersion(): string {
return pjson.version
}

/**
* Returns current chectl version defined in package.json.
*/
export function getCurrentChectlName(): string {
return pjson.name
}

/**
* Returns latest chectl version for the given channel.
*/
export async function getLatestChectlVersion(channel: string): Promise<string | undefined> {
if (getCurrentChectlName() !== 'chectl') {
return
}

const axiosInstance = axios.create({
httpsAgent: new https.Agent({})
})

try {
const { data } = await axiosInstance.get(`https://che-incubator.github.io/chectl/channels/${channel}/linux-x64`)
return data.version
} catch {
return
}
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"module": "commonjs",
"moduleResolution": "node",
"target": "es6",
"sourceMap": true
"sourceMap": true,
"resolveJsonModule": true
},
"include": [
"src"
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2126,19 +2126,19 @@ 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#55769df6e901c37b38384dc231e4abc5fbcdb96e"
resolved "git://github.com/devfile/devworkspace-operator#488c2a00590dab1378e4eb498ff889021c4268ba"

"eclipse-che-minishift@git://github.com/minishift/minishift#master":
version "0.0.0"
resolved "git://github.com/minishift/minishift#4b58f8954421fcbb7996ca67cba7ed8c58092a88"

"eclipse-che-operator@git://github.com/eclipse/che-operator#master":
version "0.0.0"
resolved "git://github.com/eclipse/che-operator#ed3df35359b648d19a5a775f3a2e140f5da96933"
resolved "git://github.com/eclipse/che-operator#9eee2bfc6f7791e85675bc95d76d556025132cb5"

"eclipse-che@git://github.com/eclipse/che#master":
version "0.0.0"
resolved "git://github.com/eclipse/che#6e6b773e060bd04d876b150fa7470637496e675f"
resolved "git://github.com/eclipse/che#7061f06ab1e13b947967878b0a96391ad29d7e59"

editorconfig@^0.15.0:
version "0.15.3"
Expand Down