diff --git a/src/api/context.ts b/src/api/context.ts index 6ce765846..183e96d89 100644 --- a/src/api/context.ts +++ b/src/api/context.ts @@ -16,7 +16,7 @@ import * as os from 'os' import * as path from 'path' import { CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_OPERATOR_CR_YAML_KEY, LOG_DIRECTORY_KEY } from '../common-flags' -import { CHECTL_PROJECT_NAME } from '../constants' +import { CHECTL_PROJECT_NAME, DEFAULT_CHE_NAMESPACE, DEFAULT_OPENSHIFT_OPERATORS_NS_NAME, STABLE_ALL_NAMESPACES_CHANNEL_NAME } from '../constants' import { getProjectName, getProjectVersion, readCRFile } from '../util' import { CHECTL_DEVELOPMENT_VERSION } from './version' @@ -45,11 +45,15 @@ export namespace ChectlContext { export async function init(flags: any, command: Command): Promise { ctx.isChectl = getProjectName() === CHECTL_PROJECT_NAME ctx.isDevVersion = getProjectVersion().includes('next') || getProjectVersion() === CHECTL_DEVELOPMENT_VERSION - + ctx.operatorNamespace = flags.chenamespace || DEFAULT_CHE_NAMESPACE if (flags['listr-renderer'] as any) { ctx.listrOptions = { renderer: (flags['listr-renderer'] as any), collapse: false } as Listr.ListrOptions } + if (flags['olm-channel'] === STABLE_ALL_NAMESPACES_CHANNEL_NAME) { + ctx.operatorNamespace = DEFAULT_OPENSHIFT_OPERATORS_NS_NAME + } + ctx.highlightedMessages = [] as string[] ctx[START_TIME] = Date.now() diff --git a/src/api/kube.ts b/src/api/kube.ts index 30912f0c2..b62ab6045 100644 --- a/src/api/kube.ts +++ b/src/api/kube.ts @@ -2033,9 +2033,10 @@ export class KubeHelper { try { await customObjectsApi.deleteNamespacedCustomObject('operators.coreos.com', 'v1alpha1', namespace, 'subscriptions', operatorSubscriptionName) } catch (e) { - if (e.response.statusCode !== 404) { - throw this.wrapK8sClientError(e) + if (e.response.statusCode === 404) { + return } + throw this.wrapK8sClientError(e) } } diff --git a/src/commands/server/deploy.ts b/src/commands/server/deploy.ts index f625cbef8..43780707b 100644 --- a/src/commands/server/deploy.ts +++ b/src/commands/server/deploy.ts @@ -19,7 +19,7 @@ import * as semver from 'semver' import { ChectlContext } from '../../api/context' import { KubeHelper } from '../../api/kube' import { batch, cheDeployment, cheDeployVersion, cheNamespace, cheOperatorCRPatchYaml, cheOperatorCRYaml, CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_OPERATOR_CR_YAML_KEY, CHE_TELEMETRY, DEPLOY_VERSION_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_ANALYTIC_HOOK_NAME, DEFAULT_CHE_NAMESPACE, DEFAULT_OLM_SUGGESTED_NAMESPACE, DOCS_LINK_INSTALL_RUNNING_CHE_LOCALLY, MIN_CHE_OPERATOR_INSTALLER_VERSION, MIN_HELM_INSTALLER_VERSION, MIN_OLM_INSTALLER_VERSION } from '../../constants' +import { DEFAULT_ANALYTIC_HOOK_NAME, DEFAULT_CHE_NAMESPACE, DEFAULT_OLM_SUGGESTED_NAMESPACE, DOCS_LINK_INSTALL_RUNNING_CHE_LOCALLY, MIN_CHE_OPERATOR_INSTALLER_VERSION, MIN_HELM_INSTALLER_VERSION, MIN_OLM_INSTALLER_VERSION, STABLE_ALL_NAMESPACES_CHANNEL_NAME } from '../../constants' import { CheTasks } from '../../tasks/che' import { DevWorkspaceTasks } from '../../tasks/component-installers/devfile-workspace-operator-installer' import { checkChectlAndCheVersionCompatibility, downloadTemplates, getPrintHighlightedMessagesTask, getRetrieveKeycloakCredentialsTask, retrieveCheCaCertificateTask } from '../../tasks/installers/common-tasks' @@ -296,6 +296,10 @@ export default class Deploy extends Command { this.error(`🛑 The specified installer ${flags.installer} does not support Minishift`) } + if (flags['olm-channel'] === STABLE_ALL_NAMESPACES_CHANNEL_NAME && isKubernetesPlatformFamily(flags.platform)) { + this.error('"stable-all-namespaces" channel is supported only in "openshift" platform') + } + if (flags['catalog-source-name'] && flags['catalog-source-yaml']) { this.error('should be provided only one argument: "catalog-source-name" or "catalog-source-yaml"') } diff --git a/src/constants.ts b/src/constants.ts index 6628c38f8..7e5ac2022 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -90,3 +90,6 @@ export const CHE_CLUSTER_BACKUP_CRD = 'checlusterbackups.org.eclipse.che' export const CHE_CLUSTER_BACKUP_KIND_PLURAL = 'checlusterbackups' export const CHE_CLUSTER_RESTORE_CRD = 'checlusterrestores.org.eclipse.che' export const CHE_CLUSTER_RESTORE_KIND_PLURAL = 'checlusterrestores' + +export const DEFAULT_OPENSHIFT_OPERATORS_NS_NAME = 'openshift-operators' +export const STABLE_ALL_NAMESPACES_CHANNEL_NAME = 'stable-all-namespaces' diff --git a/src/tasks/installers/olm.ts b/src/tasks/installers/olm.ts index 7fff587e9..2651c0131 100644 --- a/src/tasks/installers/olm.ts +++ b/src/tasks/installers/olm.ts @@ -19,7 +19,7 @@ import * as path from 'path' import { KubeHelper } from '../../api/kube' import { CatalogSource, Subscription } from '../../api/typings/olm' import { VersionHelper } from '../../api/version' -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 { CUSTOM_CATALOG_SOURCE_NAME, CVS_PREFIX, DEFAULT_CHE_NAMESPACE, DEFAULT_CHE_OLM_PACKAGE_NAME, DEFAULT_OLM_KUBERNETES_NAMESPACE, DEFAULT_OPENSHIFT_MARKET_PLACE_NAMESPACE, DEFAULT_OPENSHIFT_OPERATORS_NS_NAME, KUBERNETES_OLM_CATALOG, NIGHTLY_CATALOG_SOURCE_NAME, OLM_NIGHTLY_CHANNEL_NAME, OLM_STABLE_CHANNEL_NAME, OPENSHIFT_OLM_CATALOG, OPERATOR_GROUP_NAME, STABLE_ALL_NAMESPACES_CHANNEL_NAME, SUBSCRIPTION_NAME } from '../../constants' import { isKubernetesPlatformFamily } from '../../util' import { createEclipseCheCluster, createNamespaceTask, patchingEclipseCheCluster } from './common-tasks' @@ -68,6 +68,8 @@ export class OLMTasks { }, { title: 'Create operator group', + // 'stable-all-namespaces' channel install the operator in openshift-operators namespace and there already exists a pre-created operator-group. + enabled: (ctx: any) => ctx.operatorNamespace !== DEFAULT_OPENSHIFT_OPERATORS_NS_NAME, task: async (_ctx: any, task: any) => { if (await kube.operatorGroupExists(OPERATOR_GROUP_NAME, flags.chenamespace)) { task.title = `${task.title}...It already exists.` @@ -142,20 +144,23 @@ export class OLMTasks { { title: 'Create operator subscription', task: async (ctx: any, task: any) => { - if (await kube.operatorSubscriptionExists(SUBSCRIPTION_NAME, flags.chenamespace)) { + if (await kube.operatorSubscriptionExists(SUBSCRIPTION_NAME, ctx.operatorNamespace)) { task.title = `${task.title}...It already exists.` } else { let subscription: Subscription if (flags['catalog-source-yaml'] || flags['catalog-source-name']) { // custom Che CatalogSource - const catalogSourceNamespace = flags['catalog-source-namespace'] || flags.chenamespace - subscription = this.constructSubscription(SUBSCRIPTION_NAME, flags['package-manifest-name'], flags.chenamespace, catalogSourceNamespace, flags['olm-channel'], ctx.sourceName, ctx.approvalStarategy, ctx.startingCSV) + const catalogSourceNamespace = flags['catalog-source-namespace'] || ctx.operatorNamespace + subscription = this.constructSubscription(SUBSCRIPTION_NAME, flags['package-manifest-name'], ctx.operatorNamespace, catalogSourceNamespace, flags['olm-channel'], ctx.sourceName, ctx.approvalStarategy, ctx.startingCSV) } else if (VersionHelper.isDeployingStableVersion(flags) || flags['olm-channel'] === OLM_STABLE_CHANNEL_NAME) { // stable Che CatalogSource - subscription = this.constructSubscription(SUBSCRIPTION_NAME, DEFAULT_CHE_OLM_PACKAGE_NAME, flags.chenamespace, ctx.defaultCatalogSourceNamespace, OLM_STABLE_CHANNEL_NAME, ctx.catalogSourceNameStable, ctx.approvalStarategy, ctx.startingCSV) + subscription = this.constructSubscription(SUBSCRIPTION_NAME, DEFAULT_CHE_OLM_PACKAGE_NAME, ctx.operatorNamespace, ctx.defaultCatalogSourceNamespace, OLM_STABLE_CHANNEL_NAME, ctx.catalogSourceNameStable, ctx.approvalStarategy, ctx.startingCSV) + } else if (flags['olm-channel'] === STABLE_ALL_NAMESPACES_CHANNEL_NAME) { + // stable Che CatalogSource + subscription = this.constructSubscription(SUBSCRIPTION_NAME, DEFAULT_CHE_OLM_PACKAGE_NAME, ctx.operatorNamespace, ctx.defaultCatalogSourceNamespace, STABLE_ALL_NAMESPACES_CHANNEL_NAME, ctx.catalogSourceNameStable, ctx.approvalStarategy, ctx.startingCSV) } else { // nightly Che CatalogSource - subscription = this.constructSubscription(SUBSCRIPTION_NAME, `eclipse-che-preview-${ctx.generalPlatformName}`, flags.chenamespace, flags.chenamespace, OLM_NIGHTLY_CHANNEL_NAME, NIGHTLY_CATALOG_SOURCE_NAME, ctx.approvalStarategy, ctx.startingCSV) + subscription = this.constructSubscription(SUBSCRIPTION_NAME, `eclipse-che-preview-${ctx.generalPlatformName}`, ctx.operatorNamespace, ctx.operatorNamespace, OLM_NIGHTLY_CHANNEL_NAME, NIGHTLY_CATALOG_SOURCE_NAME, ctx.approvalStarategy, ctx.startingCSV) } await kube.createOperatorSubscription(subscription) task.title = `${task.title}...created new one.` @@ -165,7 +170,7 @@ export class OLMTasks { { title: 'Wait while subscription is ready', task: async (ctx: any, task: any) => { - const installPlan = await kube.waitOperatorSubscriptionReadyForApproval(flags.chenamespace, SUBSCRIPTION_NAME, 600) + const installPlan = await kube.waitOperatorSubscriptionReadyForApproval(ctx.operatorNamespace, SUBSCRIPTION_NAME, 600) ctx.installPlanName = installPlan.name task.title = `${task.title}...done.` }, @@ -174,14 +179,14 @@ export class OLMTasks { title: 'Approve installation', enabled: ctx => ctx.approvalStarategy === 'Manual', task: async (ctx: any, task: any) => { - await kube.approveOperatorInstallationPlan(ctx.installPlanName, flags.chenamespace) + await kube.approveOperatorInstallationPlan(ctx.installPlanName, ctx.operatorNamespace) task.title = `${task.title}...done.` }, }, { title: 'Wait while operator installed', task: async (ctx: any, task: any) => { - await kube.waitUntilOperatorIsInstalled(ctx.installPlanName, flags.chenamespace) + await kube.waitUntilOperatorIsInstalled(ctx.installPlanName, ctx.operatorNamespace) task.title = `${task.title}...done.` }, }, @@ -225,8 +230,8 @@ export class OLMTasks { this.isOlmPreInstalledTask(command, kube), { title: 'Check if operator group exists', - task: async (_ctx: any, task: any) => { - if (!await kube.operatorGroupExists(OPERATOR_GROUP_NAME, flags.chenamespace)) { + task: async (ctx: any, task: any) => { + if (!await kube.operatorGroupExists(OPERATOR_GROUP_NAME, ctx.operatorNamespace)) { command.error(`Unable to find operator group ${OPERATOR_GROUP_NAME}`) } task.title = `${task.title}...done.` @@ -234,8 +239,8 @@ export class OLMTasks { }, { title: 'Check if operator subscription exists', - task: async (_ctx: any, task: any) => { - if (!await kube.operatorSubscriptionExists(SUBSCRIPTION_NAME, flags.chenamespace)) { + task: async (ctx: any, task: any) => { + if (!await kube.operatorSubscriptionExists(SUBSCRIPTION_NAME, ctx.operatorNamespace)) { command.error(`Unable to find operator subscription ${SUBSCRIPTION_NAME}`) } task.title = `${task.title}...done.` @@ -250,7 +255,7 @@ export class OLMTasks { { title: 'Get operator installation plan', task: async (ctx: any, task: any) => { - const subscription: Subscription = await kube.getOperatorSubscription(SUBSCRIPTION_NAME, flags.chenamespace) + const subscription: Subscription = await kube.getOperatorSubscription(SUBSCRIPTION_NAME, ctx.operatorNamespace) if (subscription.status) { if (subscription.status.state === 'AtLatestKnown') { @@ -286,7 +291,7 @@ export class OLMTasks { title: 'Approve installation', enabled: (ctx: any) => ctx.installPlanName, task: async (ctx: any, task: any) => { - await kube.approveOperatorInstallationPlan(ctx.installPlanName, flags.chenamespace) + await kube.approveOperatorInstallationPlan(ctx.installPlanName, ctx.operatorNamespace) task.title = `${task.title}...done.` }, }, @@ -294,7 +299,7 @@ export class OLMTasks { title: 'Wait while newer operator installed', enabled: (ctx: any) => ctx.installPlanName, task: async (ctx: any, task: any) => { - await kube.waitUntilOperatorIsInstalled(ctx.installPlanName, flags.chenamespace, 60) + await kube.waitUntilOperatorIsInstalled(ctx.installPlanName, ctx.operatorNamespace, 60) ctx.highlightedMessages.push(`Operator is updated from ${ctx.currentVersion} to ${ctx.nextVersion} version`) task.title = `${task.title}...done.` }, @@ -313,11 +318,23 @@ export class OLMTasks { task.title = `${task.title}: ${ctx.isPreInstalledOLM}...OK` }, }, + { + title: `Check if operator is installed in ${DEFAULT_OPENSHIFT_OPERATORS_NS_NAME} namespace`, + task: async (ctx: any, task: any) => { + if (await kube.operatorSubscriptionExists(SUBSCRIPTION_NAME, DEFAULT_OPENSHIFT_OPERATORS_NS_NAME)) { + ctx.operatorNamespace = DEFAULT_OPENSHIFT_OPERATORS_NS_NAME + task.title = `${task.title}...Found` + } else { + ctx.operatorNamespace = flags.chenamespace || DEFAULT_CHE_NAMESPACE + task.title = `${task.title}...Not Found` + } + }, + }, { title: `Delete(OLM) operator subscription ${SUBSCRIPTION_NAME}`, enabled: ctx => ctx.isPreInstalledOLM, - task: async (_ctx: any, task: any) => { - await kube.deleteOperatorSubscription(SUBSCRIPTION_NAME, flags.chenamespace) + task: async (ctx: any, task: any) => { + await kube.deleteOperatorSubscription(SUBSCRIPTION_NAME, ctx.operatorNamespace) task.title = `${task.title}...OK` }, }, @@ -334,22 +351,22 @@ export class OLMTasks { { title: `Delete(OLM) operator group ${OPERATOR_GROUP_NAME}`, enabled: ctx => ctx.isPreInstalledOLM, - task: async (_ctx: any, task: any) => { - await kube.deleteOperatorGroup(OPERATOR_GROUP_NAME, flags.chenamespace) + task: async (ctx: any, task: any) => { + await kube.deleteOperatorGroup(OPERATOR_GROUP_NAME, ctx.operatorNamespace) task.title = `${task.title}...OK` }, }, { title: `Delete(OLM) custom catalog source ${CUSTOM_CATALOG_SOURCE_NAME}`, - task: async (_ctx: any, task: any) => { - await kube.deleteCatalogSource(flags.chenamespace, CUSTOM_CATALOG_SOURCE_NAME) + task: async (ctx: any, task: any) => { + await kube.deleteCatalogSource(ctx.operatorNamespace, CUSTOM_CATALOG_SOURCE_NAME) task.title = `${task.title}...OK` }, }, { title: `Delete(OLM) nigthly catalog source ${NIGHTLY_CATALOG_SOURCE_NAME}`, - task: async (_ctx: any, task: any) => { - await kube.deleteCatalogSource(flags.chenamespace, NIGHTLY_CATALOG_SOURCE_NAME) + task: async (ctx: any, task: any) => { + await kube.deleteCatalogSource(ctx.operatorNamespace, NIGHTLY_CATALOG_SOURCE_NAME) task.title = `${task.title}...OK` }, }, diff --git a/test/e2e/e2e-upgrade.test.ts b/test/e2e/e2e-upgrade.test.ts index db3b09b89..3684b7408 100644 --- a/test/e2e/e2e-upgrade.test.ts +++ b/test/e2e/e2e-upgrade.test.ts @@ -30,7 +30,7 @@ const INSTALLER = 'operator' const UPDATE_CHE_TIMEOUT_MS = 5 * 60 * 1000 const WORKSPACE_START_TIMEOUT_MS = 10 * 60 * 1000 -const CHE_VERSION_TIMEOUT_MS = 3 * 60 * 1000 +const CHE_VERSION_TIMEOUT_MS = 5 * 60 * 1000 describe('Test Che upgrade', () => { let cheVersion: string