Skip to content

Commit

Permalink
fix: Improve custom resource kube methods
Browse files Browse the repository at this point in the history
Signed-off-by: Flavius Lacatusu <[email protected]>
  • Loading branch information
flacatus committed Jun 1, 2021
1 parent 67b5430 commit 338b9e6
Show file tree
Hide file tree
Showing 13 changed files with 58 additions and 103 deletions.
4 changes: 2 additions & 2 deletions src/api/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import * as rimraf from 'rimraf'
import * as unzipper from 'unzipper'

import { OpenShiftHelper } from '../api/openshift'
import { CHE_ROOT_CA_SECRET_NAME, DEFAULT_CA_CERT_FILE_NAME, OPERATOR_TEMPLATE_DIR } from '../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, CHE_ROOT_CA_SECRET_NAME, DEFAULT_CA_CERT_FILE_NAME, OPERATOR_TEMPLATE_DIR } from '../constants'
import { base64Decode, downloadFile } from '../util'

import { CheApiClient } from './che-api-client'
Expand Down Expand Up @@ -214,7 +214,7 @@ export class CheHelper {
let adminUsername
let adminPassword

const cheCluster = await this.kube.getCheCluster(cheNamespace)
const cheCluster = await this.kube.getCustomResource(cheNamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (!cheCluster || cheCluster.spec.auth.externalIdentityProvider) {
return []
}
Expand Down
82 changes: 15 additions & 67 deletions src/api/kube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { merge } from 'lodash'
import * as net from 'net'
import { Writable } from 'stream'

import { CHE_CLUSTER_CRD, DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT, DEFAULT_K8S_POD_WAIT_TIMEOUT, OLM_STABLE_CHANNEL_NAME } from '../constants'
import { DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT, DEFAULT_K8S_POD_WAIT_TIMEOUT, OLM_STABLE_CHANNEL_NAME } from '../constants'
import { getClusterClientCommand, isKubernetesPlatformFamily, safeLoadFromYamlFile } from '../util'

import { V1Certificate } from './typings/cert-manager'
Expand Down Expand Up @@ -1620,12 +1620,12 @@ export class KubeHelper {
}

/**
* Returns `checlusters.org.eclipse.che' in the given namespace.
* Returns custom resource in the given namespace.
*/
async getCheCluster(namespace: string): Promise<any | undefined> {
async getCustomResource(namespace: string, resourceAPIGroup: string, resourceAPIVersion: string, resourcePlural: string): Promise<any | undefined> {
const customObjectsApi = this.kubeConfig.makeApiClient(CustomObjectsApi)
try {
const { body } = await customObjectsApi.listNamespacedCustomObject('org.eclipse.che', 'v1', namespace, 'checlusters')
const { body } = await customObjectsApi.listNamespacedCustomObject(resourceAPIGroup, resourceAPIVersion, namespace, resourcePlural)
if (!(body as any).items) {
return
}
Expand All @@ -1634,106 +1634,54 @@ export class KubeHelper {
if (crs.length === 0) {
return
} else if (crs.length !== 1) {
throw new Error(`Too many resources '${CHE_CLUSTER_CRD}' found in the namespace '${namespace}'`)
throw new Error(`Too many resources of type ${resourcePlural}.${resourceAPIGroup} found in the namespace '${namespace}'`)
}

return crs[0]
} catch (e) {
if (e.response.statusCode === 404) {
// There is no CR 'checluster`
// There is no CRD
return
}
throw this.wrapK8sClientError(e)
}
}

/**
* Returns `che.eclipse.org/v1alpha1' in the given namespace.
* Returns all custom resources
*/
async getCheManagerInstance(namespace: string): Promise<any | undefined> {
async getAllCustomResources(resourceAPIGroup: string, resourceAPIVersion: string, resourcePlural: string): Promise<any[]> {
const customObjectsApi = this.kubeConfig.makeApiClient(CustomObjectsApi)
try {
const { body } = await customObjectsApi.listNamespacedCustomObject('che.eclipse.org', 'v1alpha1', namespace, 'chemanagers')
if (!(body as any).items) {
return
}

const crs = (body as any).items as any[]
if (crs.length === 0) {
return
} else if (crs.length !== 1) {
throw new Error(`Too many resources '${CHE_CLUSTER_CRD}' found in the namespace '${namespace}'`)
}

return crs[0]
} catch (e) {
if (e.response.statusCode === 404) {
// There is no CR 'checluster`
return
}
throw this.wrapK8sClientError(e)
}
}

/**
* Returns all `checlusters.org.eclipse.che' resources
*/
async getAllCheClusters(): Promise<any[]> {
const customObjectsApi = this.kubeConfig.makeApiClient(CustomObjectsApi)
try {
const { body } = await customObjectsApi.listClusterCustomObject('org.eclipse.che', 'v1', 'checlusters')
const { body } = await customObjectsApi.listClusterCustomObject(resourceAPIGroup, resourceAPIVersion, resourcePlural)
return (body as any).items ? (body as any).items : []
} catch (e) {
if (e.response.statusCode === 404) {
// There is no CRD 'checlusters`
// There is no CRD
return []
}
throw this.wrapK8sClientError(e)
}
}

/**
* Deletes `checlusters.org.eclipse.che' resources in the given namespace.
*/
async deleteCheCluster(namespace: string): Promise<void> {
const customObjectsApi = this.kubeConfig.makeApiClient(CustomObjectsApi)
try {
const { body } = await customObjectsApi.listNamespacedCustomObject('org.eclipse.che', 'v1', namespace, 'checlusters')
if (!(body as any).items) {
return
}

const crs = (body as any).items as any[]
for (const cr of crs) {
await customObjectsApi.deleteNamespacedCustomObject('org.eclipse.che', 'v1', namespace, 'checlusters', cr.metadata.name)
}
} catch (e) {
if (e.response.statusCode === 404) {
// There is no CRD 'checlusters`
return
}
throw this.wrapK8sClientError(e)
}
}

/**
* Deletes `che.eclipse.org/v1alpha1' resources in the given namespace.
* Deletes custom resources in the given namespace.
*/
async deleteCheManagerInstance(namespace: string): Promise<void> {
async deleteCustomResource(namespace: string, resourceAPIGroup: string, resourceAPIVersion: string, resourcePlural: string): Promise<void> {
const customObjectsApi = this.kubeConfig.makeApiClient(CustomObjectsApi)
try {
const { body } = await customObjectsApi.listNamespacedCustomObject('che.eclipse.org', 'v1alpha1', namespace, 'checlusters')
const { body } = await customObjectsApi.listNamespacedCustomObject(resourceAPIGroup, resourceAPIVersion, namespace, resourcePlural)
if (!(body as any).items) {
return
}

const crs = (body as any).items as any[]
for (const cr of crs) {
await customObjectsApi.deleteNamespacedCustomObject('che.eclipse.org', 'v1alpha1', namespace, 'checlusters', cr.metadata.name)
await customObjectsApi.deleteNamespacedCustomObject(resourceAPIGroup, resourceAPIVersion, namespace, resourcePlural, cr.metadata.name)
}
} catch (e) {
if (e.response.statusCode === 404) {
// There is no CRD 'checlusters`
// There is no CRD
return
}
throw this.wrapK8sClientError(e)
Expand Down
4 changes: 2 additions & 2 deletions src/api/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Listr = require('listr')
import * as path from 'path'
import * as semver from 'semver'

import { CHECTL_PROJECT_NAME } from '../constants'
import { CHECTL_PROJECT_NAME, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION } from '../constants'
import { CheTasks } from '../tasks/che'
import { getClusterClientCommand, getProjectName, getProjectVersion } from '../util'

Expand Down Expand Up @@ -161,7 +161,7 @@ export namespace VersionHelper {
export async function getCheVersion(flags: any): Promise<string> {
const kube = new KubeHelper(flags)
const cheTasks = new CheTasks(flags)
const cheCluster = await kube.getCheCluster(flags.chenamespace)
const cheCluster = await kube.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (cheCluster && cheCluster.spec.server.cheFlavor !== 'che') {
return cheCluster.status.cheVersion
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/server/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Listr = require('listr')
import { ChectlContext } from '../../api/context'
import { KubeHelper } from '../../api/kube'
import { assumeYes, batch, cheDeployment, cheNamespace, CHE_TELEMETRY, listrRenderer, skipKubeHealthzCheck } from '../../common-flags'
import { DEFAULT_ANALYTIC_HOOK_NAME } from '../../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, DEFAULT_ANALYTIC_HOOK_NAME } from '../../constants'
import { CheTasks } from '../../tasks/che'
import { DevWorkspaceTasks } from '../../tasks/component-installers/devfile-workspace-operator-installer'
import { HelmTasks } from '../../tasks/installers/helm'
Expand Down Expand Up @@ -80,9 +80,9 @@ export default class Delete extends Command {

// Remove devworkspace controller only if there are no more cheClusters after olm/operator tasks
tasks.add({
title: 'Uninstall DevWorkspace Controller',
title: 'Uninstall DevWorkspace Controller and DevWorkspace Che Controller',
task: async (_ctx: any, task: any) => {
const checlusters = await kube.getAllCheClusters()
const checlusters = await kube.getAllCustomResources(CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (checlusters.length === 0) {
return new Listr(devWorkspaceTasks.getUninstallTasks())
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/server/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { ChectlContext } from '../../api/context'
import { KubeHelper } from '../../api/kube'
import { VersionHelper } from '../../api/version'
import { cheNamespace, CHE_TELEMETRY } from '../../common-flags'
import { DEFAULT_ANALYTIC_HOOK_NAME } from '../../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, DEFAULT_ANALYTIC_HOOK_NAME } from '../../constants'
import { findWorkingNamespace } from '../../util'

export default class Status extends Command {
Expand All @@ -39,7 +39,7 @@ export default class Status extends Command {
let openshiftOauth = 'No'

await this.config.runHook(DEFAULT_ANALYTIC_HOOK_NAME, { command: Status.id, flags })
const cr = await kube.getCheCluster(flags.chenamespace)
const cr = await kube.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (cr && cr.spec && cr.spec.auth && cr.spec.auth.openShiftoAuth && await kube.isOpenShift()) {
openshiftOauth = 'Yes'
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/server/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as semver from 'semver'
import { ChectlContext } from '../../api/context'
import { KubeHelper } from '../../api/kube'
import { assumeYes, batch, cheDeployment, cheDeployVersion, cheNamespace, cheOperatorCRPatchYaml, CHE_OPERATOR_CR_PATCH_YAML_KEY, CHE_TELEMETRY, DEPLOY_VERSION_KEY, listrRenderer, skipKubeHealthzCheck } from '../../common-flags'
import { DEFAULT_ANALYTIC_HOOK_NAME, DEFAULT_CHE_OPERATOR_IMAGE_NAME, MIN_CHE_OPERATOR_INSTALLER_VERSION, SUBSCRIPTION_NAME } from '../../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, DEFAULT_ANALYTIC_HOOK_NAME, DEFAULT_CHE_OPERATOR_IMAGE_NAME, MIN_CHE_OPERATOR_INSTALLER_VERSION, SUBSCRIPTION_NAME } from '../../constants'
import { checkChectlAndCheVersionCompatibility, downloadTemplates, getPrintHighlightedMessagesTask } from '../../tasks/installers/common-tasks'
import { InstallerTasks } from '../../tasks/installers/installer'
import { ApiTasks } from '../../tasks/platforms/api'
Expand Down Expand Up @@ -170,7 +170,7 @@ export default class Update extends Command {
*/
private async checkComponentImages(flags: any): Promise<void> {
const kubeHelper = new KubeHelper(flags)
const cheCluster = await kubeHelper.getCheCluster(flags.chenamespace)
const cheCluster = await kubeHelper.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (cheCluster.spec.server.cheImage
|| cheCluster.spec.server.cheImageTag
|| cheCluster.spec.server.devfileRegistryImage
Expand Down Expand Up @@ -364,7 +364,7 @@ export default class Update extends Command {
*/
private async setDomainFlag(flags: any): Promise<void> {
const kubeHelper = new KubeHelper(flags)
const cheCluster = await kubeHelper.getCheCluster(flags.chenamespace)
const cheCluster = await kubeHelper.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (cheCluster && cheCluster.spec.k8s && cheCluster.spec.k8s.ingressDomain) {
flags.domain = cheCluster.spec.k8s.ingressDomain
}
Expand Down
6 changes: 5 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export const CHE_TLS_SECRET_NAME = 'che-tls'
export const CHE_ROOT_CA_SECRET_NAME = 'self-signed-certificate'
export const DEFAULT_CA_CERT_FILE_NAME = 'cheCA.crt'
export const CHE_CLUSTER_CR_NAME = 'eclipse-che'
export const CHE_CLUSTER_CRD = 'checlusters.org.eclipse.che'

// operator
export const OPERATOR_DEPLOYMENT_NAME = 'che-operator'
Expand Down Expand Up @@ -77,3 +76,8 @@ export const DEFAULT_ANALYTIC_HOOK_NAME = 'analytics'
// Timeouts
export const DEFAULT_K8S_POD_WAIT_TIMEOUT = 600000
export const DEFAULT_K8S_POD_ERROR_RECHECK_TIMEOUT = 15000

// Custom Resources names
export const CHE_CLUSTER_CRD = 'checlusters.org.eclipse.che'
export const CHE_CLUSTER_API_GROUP = 'org.eclipse.che'
export const CHE_CLUSTER_API_VERSION = 'v1'
6 changes: 3 additions & 3 deletions src/tasks/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { CheServerLoginManager } from '../api/che-login-manager'
import { KubeHelper } from '../api/kube'
import { OpenShiftHelper } from '../api/openshift'
import { VersionHelper } from '../api/version'
import { CHE_OPERATOR_SELECTOR, DOC_LINK, DOC_LINK_RELEASE_NOTES, OUTPUT_SEPARATOR } from '../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, CHE_OPERATOR_SELECTOR, DOC_LINK, DOC_LINK_RELEASE_NOTES, OUTPUT_SEPARATOR } from '../constants'
import { base64Decode } from '../util'

import { KubeTasks } from './kube'
Expand Down Expand Up @@ -456,7 +456,7 @@ export class CheTasks {
{
title: `Delete consoleLink ${this.cheConsoleLinkName}`,
task: async (_ctx: any, task: any) => {
const checlusters = await this.kube.getAllCheClusters()
const checlusters = await this.kube.getAllCustomResources(CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
// Delete the consoleLink only in case if there no more checluster installed
if (checlusters.length === 0) {
await this.kube.deleteConsoleLink(this.cheConsoleLinkName)
Expand Down Expand Up @@ -669,7 +669,7 @@ export class CheTasks {
const cheUrl = await this.che.cheURL(flags.chenamespace)
messages.push(`Users Dashboard : ${cheUrl}`)

const cr = await this.kube.getCheCluster(flags.chenamespace)
const cr = await this.kube.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (ctx.isOpenShift && cr && cr.spec && cr.spec.auth && cr.spec.auth.openShiftoAuth) {
if (cr.status && cr.status.openShiftOAuthUserCredentialsSecret) {
let user = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,18 @@ export class DevWorkspaceTasks {
{
title: `Delete the Custom Resource of type ${this.cheManagerCRDName}`,
task: async (_ctx: any, task: any) => {
await this.kubeHelper.deleteCheManagerInstance(this.devworkspaceCheNamespace)
// if chemanager instance still exists then remove finalizers and delete again
const chemanager = await this.kubeHelper.getCheManagerInstance(this.devworkspaceCheNamespace)
await this.kubeHelper.deleteCustomResource(this.devworkspaceCheNamespace, this.cheManagerApiGroupName, this.cheManagerApiVersionName, 'chemanagers')

// wait 10 seconds
await cli.wait(10000)

// if chemanager instance still exists then remove finalizers and delete again
const chemanager = await this.kubeHelper.getCustomResource(this.devworkspaceCheNamespace, this.cheManagerApiGroupName, this.cheManagerApiVersionName, 'chemanagers')
if (chemanager) {
try {
await this.kubeHelper.patchCustomResource(chemanager.metadata.name, this.devworkspaceCheNamespace, { metadata: { finalizers: null } }, this.cheManagerApiGroupName, this.cheManagerApiVersionName, 'chemanagers')
} catch (error) {
if (await this.kubeHelper.getCheManagerInstance(this.devworkspaceCheNamespace)) {
if (await this.kubeHelper.getCustomResource(this.devworkspaceCheNamespace, this.cheManagerApiGroupName, this.cheManagerApiVersionName, 'chemanagers')) {
task.title = `${task.title}...OK`
return // successfully removed
}
Expand All @@ -304,7 +307,7 @@ export class DevWorkspaceTasks {
await cli.wait(2000)
}

if (!await this.kubeHelper.getCheManagerInstance(this.devworkspaceCheNamespace)) {
if (!await this.kubeHelper.getCustomResource(this.devworkspaceCheNamespace, this.cheManagerApiGroupName, this.cheManagerApiVersionName, 'chemanagers')) {
task.title = `${task.title}...OK`
} else {
task.title = `${task.title}...Failed`
Expand Down
4 changes: 2 additions & 2 deletions src/tasks/installers/common-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { ChectlContext } from '../../api/context'
import { CheGithubClient } from '../../api/github-client'
import { KubeHelper } from '../../api/kube'
import { VersionHelper } from '../../api/version'
import { CHE_CLUSTER_CRD, DOCS_LINK_IMPORT_CA_CERT_INTO_BROWSER, OPERATOR_TEMPLATE_DIR } from '../../constants'
import { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, CHE_CLUSTER_CRD, DOCS_LINK_IMPORT_CA_CERT_INTO_BROWSER, OPERATOR_TEMPLATE_DIR } from '../../constants'
import { getProjectVersion } from '../../util'

export function createNamespaceTask(namespaceName: string, labels: {}): Listr.ListrTask {
Expand Down Expand Up @@ -165,7 +165,7 @@ export function patchingEclipseCheCluster(flags: any, kube: KubeHelper, command:
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) => {
const cheCluster = await kube.getCheCluster(flags.chenamespace)
const cheCluster = await kube.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (!cheCluster) {
command.error(`Eclipse Che cluster CR is not found in the namespace '${flags.chenamespace}'`)
}
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 @@ -17,7 +17,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 { CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 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 } from '../../util'

import { createEclipseCheCluster, createNamespaceTask, patchingEclipseCheCluster } from './common-tasks'
Expand Down Expand Up @@ -198,7 +198,7 @@ export class OLMTasks {
{
title: 'Prepare Eclipse Che cluster CR',
task: async (ctx: any, task: any) => {
const cheCluster = await kube.getCheCluster(flags.chenamespace)
const cheCluster = await kube.getCustomResource(flags.chenamespace, CHE_CLUSTER_API_GROUP, CHE_CLUSTER_API_VERSION, 'checlusters')
if (cheCluster) {
task.title = `${task.title}...It already exists..`
return
Expand Down
Loading

0 comments on commit 338b9e6

Please sign in to comment.