diff --git a/prepare-che-operator-templates.js b/prepare-che-operator-templates.js index 0adb7eb2d..61cb1449f 100644 --- a/prepare-che-operator-templates.js +++ b/prepare-che-operator-templates.js @@ -44,6 +44,13 @@ function prepareTemplates() { fs.copySync( path.join(deployFolder, platform, 'objects', 'che-operator-service.Service.yaml'), path.join(cheOperatorTemplates, platform, 'webhook-service.yaml')) + + const validatingWebhookConfigurationPath = path.join(deployFolder, platform, 'objects', 'org.eclipse.che.ValidatingWebhookConfiguration.yaml') + if (fs.existsSync(validatingWebhookConfigurationPath)) { + fs.copySync( + validatingWebhookConfigurationPath, + path.join(cheOperatorTemplates, platform, 'org.eclipse.che.ValidatingWebhookConfiguration.yaml')) + } } fs.copySync( diff --git a/src/api/kube.ts b/src/api/kube.ts index 644805916..98dbe187d 100644 --- a/src/api/kube.ts +++ b/src/api/kube.ts @@ -47,7 +47,7 @@ import { V1ServiceAccount, V1ServiceList, Watch, - V1CustomResourceDefinition, + V1CustomResourceDefinition, V1ValidatingWebhookConfiguration, } from '@kubernetes/client-node' import { Cluster } from '@kubernetes/client-node/dist/config_types' import axios, { AxiosRequestConfig } from 'axios' @@ -360,6 +360,38 @@ export class KubeHelper { } } + async isValidatingWebhookConfigurationExists(name: string): Promise { + const k8sAdmissionApi = this.kubeConfig.makeApiClient(AdmissionregistrationV1Api) + try { + await k8sAdmissionApi.readValidatingWebhookConfiguration(name) + return true + } catch (e: any) { + if (e.response && e.response.statusCode === 404) { + return false + } + + throw this.wrapK8sClientError(e) + } + } + + async replaceValidatingWebhookConfiguration(name: string, webhook: V1ValidatingWebhookConfiguration): Promise { + const k8sAdmissionApi = this.kubeConfig.makeApiClient(AdmissionregistrationV1Api) + try { + await k8sAdmissionApi.replaceValidatingWebhookConfiguration(name, webhook) + } catch (e: any) { + throw this.wrapK8sClientError(e) + } + } + + async createValidatingWebhookConfiguration(webhook: V1ValidatingWebhookConfiguration): Promise { + const k8sAdmissionApi = this.kubeConfig.makeApiClient(AdmissionregistrationV1Api) + try { + await k8sAdmissionApi.createValidatingWebhookConfiguration(webhook) + } catch (e: any) { + throw this.wrapK8sClientError(e) + } + } + async deleteValidatingWebhookConfiguration(name: string): Promise { const k8sAdmissionApi = this.kubeConfig.makeApiClient(AdmissionregistrationV1Api) try { diff --git a/src/tasks/installers/operator.ts b/src/tasks/installers/operator.ts index 65b0ee248..06f77707a 100644 --- a/src/tasks/installers/operator.ts +++ b/src/tasks/installers/operator.ts @@ -34,6 +34,7 @@ import {V1Certificate} from '../../api/types/cert-manager' import {OpenShiftHelper} from '../../api/openshift' export class OperatorTasks { + private static readonly VALIDATING_WEBHOOK = 'org.eclipse.che' private static readonly WEBHOOK_SERVICE = 'che-operator-service' private static readonly CERTIFICATE = 'che-operator-serving-cert' private static readonly ISSUER = 'che-operator-selfsigned-issuer' @@ -281,6 +282,24 @@ export class OperatorTasks { title: 'Operator pod bootstrap', task: () => kubeTasks.podStartTasks(CHE_OPERATOR_SELECTOR, this.flags.chenamespace), }, + { + title: `Create ValidatingWebhookConfiguration ${OperatorTasks.VALIDATING_WEBHOOK}`, + task: async (ctx: any, task: any) => { + const exists = await this.kh.isValidatingWebhookConfigurationExists(OperatorTasks.VALIDATING_WEBHOOK) + if (exists) { + task.title = `${task.title}...[Exists]` + } else { + const webhookPath = this.getResourcePath('org.eclipse.che.ValidatingWebhookConfiguration.yaml') + if (fs.existsSync(webhookPath)) { + const webhook = this.kh.safeLoadFromYamlFile(webhookPath) + await this.kh.createValidatingWebhookConfiguration(webhook) + task.title = `${task.title}...[OK: created]` + } else { + task.title = `${task.title}...[Not found]` + } + } + }, + }, createEclipseCheClusterTask(this.flags, kube), ] } @@ -464,6 +483,24 @@ export class OperatorTasks { await this.kh.waitLatestReplica(OPERATOR_DEPLOYMENT_NAME, this.flags.chenamespace) }, }, + { + title: `Update ValidatingWebhookConfiguration ${OperatorTasks.VALIDATING_WEBHOOK}`, + task: async (ctx: any, task: any) => { + const webhookPath = this.getResourcePath('org.eclipse.che.ValidatingWebhookConfiguration.yaml') + if (fs.existsSync(webhookPath)) { + const webhook = this.kh.safeLoadFromYamlFile(webhookPath) + const exists = await this.kh.isValidatingWebhookConfigurationExists(OperatorTasks.VALIDATING_WEBHOOK) + if (exists) { + task.title = `${task.title}...[Ok: updated]` + } else { + await this.kh.replaceValidatingWebhookConfiguration(OperatorTasks.VALIDATING_WEBHOOK, webhook) + task.title = `${task.title}...[OK: created]` + } + } else { + task.title = `${task.title}...[Not found]` + } + }, + }, patchingEclipseCheCluster(this.flags, this.kh), ] } @@ -474,6 +511,17 @@ export class OperatorTasks { getDeleteTasks(flags: any): ReadonlyArray { const kh = new KubeHelper(flags) return [ + { + title: `Delete ValidatingWebhookConfiguration ${OperatorTasks.VALIDATING_WEBHOOK}`, + task: async (_ctx: any, task: any) => { + try { + await kh.deleteValidatingWebhookConfiguration(OperatorTasks.VALIDATING_WEBHOOK) + task.title = `${task.title}...[Ok]` + } catch (e: any) { + task.title = `${task.title}...[Failed: ${e.message}]` + } + }, + }, { title: `Delete Issuer ${OperatorTasks.ISSUER}`, task: async (_ctx: any, task: any) => { diff --git a/yarn.lock b/yarn.lock index ecce21b05..6cc3cd7a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2517,8 +2517,7 @@ ecc-jsbn@~0.1.1: "eclipse-che-operator@https://github.com/eclipse-che/che-operator#main": version "0.0.0" - uid "35bd69184c08e98fe2410d334f11d344443f628b" - resolved "https://github.com/eclipse-che/che-operator#35bd69184c08e98fe2410d334f11d344443f628b" + resolved "https://github.com/eclipse-che/che-operator#47a99988457aa60351098c13e62a3acd5ca386c7" editorconfig@^0.15.0: version "0.15.3"