diff --git a/README.md b/README.md index a0ac0608d..65c467587 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,10 @@ USAGE # Commands * [`chectl autocomplete [SHELL]`](#chectl-autocomplete-shell) +* [`chectl cacert:get`](#chectl-cacertget) * [`chectl dashboard:open`](#chectl-dashboardopen) * [`chectl devfile:generate`](#chectl-devfilegenerate) * [`chectl help [COMMAND]`](#chectl-help-command) -* [`chectl server:certificate`](#chectl-servercertificate) * [`chectl server:debug`](#chectl-serverdebug) * [`chectl server:delete`](#chectl-serverdelete) * [`chectl server:logs`](#chectl-serverlogs) @@ -124,6 +124,37 @@ EXAMPLES _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v0.1.5/src/commands/autocomplete/index.ts)_ +## `chectl cacert:get` + +Retrieves Eclipse Che self-signed certificate + +``` +USAGE + $ chectl cacert:get + +OPTIONS + -d, --destination=destination + [default: ~] Destination where to store Che certificate. + If the destination is a file (might not exist), then the certificate will be saved there in PEM + format. + If the destination is a directory, then cheCA.crt file will be created there with Che + certificate in PEM format. + If this option is ommited, then Che certificate will be stored in user's home directory as + cheCA.crt + + -h, --help + show CLI help + + -n, --chenamespace=chenamespace + [default: che] Kubernetes namespace where Eclipse Che server is supposed to be deployed + + -p, --platform=minikube|minishift|k8s|openshift|microk8s|docker-desktop|crc + Type of Kubernetes platform. Valid values are "minikube", "minishift", "k8s (for kubernetes)", "openshift", "crc + (for CodeReady Containers)", "microk8s". +``` + +_See code: [src/commands/cacert/get.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/cacert/get.ts)_ + ## `chectl dashboard:open` Open Eclipse Che dashboard @@ -190,40 +221,6 @@ OPTIONS _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v2.2.3/src/commands/help.ts)_ -## `chectl server:certificate` - -Retrieves Eclipse Che self-signed certificate - -``` -USAGE - $ chectl server:certificate - -OPTIONS - -d, --destination=destination - [default: ~] Destination where to store Che certificate. - If the destination is a file (might not exist), then the certificate will be saved there in PEM - format. - If the destination is a directory, then cheCA.crt file will be created there with Che - certificate in PEM format. - If this option is ommited, then Che certificate will be stored in user's home directory as - cheCA.crt - - -h, --help - show CLI help - - -n, --chenamespace=chenamespace - [default: che] Kubernetes namespace where Eclipse Che server is supposed to be deployed - - -p, --platform=minikube|minishift|k8s|openshift|microk8s|docker-desktop|crc - Type of Kubernetes platform. Valid values are "minikube", "minishift", "k8s (for kubernetes)", "openshift", "crc - (for CodeReady Containers)", "microk8s". - - --make-path - Creates path specified in "destination" parameter if it doesn't exist. -``` - -_See code: [src/commands/server/certificate.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/server/certificate.ts)_ - ## `chectl server:debug` Enable local debug of Eclipse Che server diff --git a/src/api/che.ts b/src/api/che.ts index 5041d2862..95fbbde72 100644 --- a/src/api/che.ts +++ b/src/api/che.ts @@ -20,6 +20,7 @@ import * as yaml from 'js-yaml' import * as path from 'path' import { OpenShiftHelper } from '../api/openshift' +import { CHE_ROOT_CA_SECRET_NAME } from '../constants' import { Devfile } from './devfile' import { KubeHelper } from './kube' @@ -107,6 +108,22 @@ export class CheHelper { } } + /** + * Gets self-signed Che CA certificate from 'self-signed-certificate' secret. The secret should exist. + */ + async retrieveEclipseCheCaCert(cheNamespace: string): Promise { + const cheCaSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, cheNamespace) + if (!cheCaSecret) { + throw new Error('Local Che CA self-signed certificate not found. Are you using self-signed certificate?') + } + + if (cheCaSecret.data && cheCaSecret.data['ca.crt']) { + return Buffer.from(cheCaSecret.data['ca.crt'], 'base64').toString('ascii') + } + + throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" has invalid format.`) + } + async cheK8sURL(namespace = ''): Promise { const ingress_names = ['che', 'che-ingress'] for (const ingress_name of ingress_names) { diff --git a/src/commands/server/certificate.ts b/src/commands/cacert/get.ts similarity index 73% rename from src/commands/server/certificate.ts rename to src/commands/cacert/get.ts index 458269a33..1b31d6a0e 100644 --- a/src/commands/server/certificate.ts +++ b/src/commands/cacert/get.ts @@ -9,12 +9,13 @@ **********************************************************************/ import { Command, flags } from '@oclif/command' -import { boolean, string } from '@oclif/parser/lib/flags' +import { string } from '@oclif/parser/lib/flags' import * as fs from 'fs' import * as Listr from 'listr' import * as os from 'os' import * as path from 'path' +import { CheHelper } from '../../api/che' import { cheNamespace } from '../../common-flags' import { CheTasks } from '../../tasks/che' import { ApiTasks } from '../../tasks/platforms/api' @@ -22,7 +23,7 @@ import { PlatformTasks } from '../../tasks/platforms/platform' const DEFAULT_CA_CERT_FILE_NAME = 'cheCA.crt' -export default class Certificate extends Command { +export default class Get extends Command { static description = 'Retrieves Eclipse Che self-signed certificate' static flags = { @@ -42,30 +43,27 @@ export default class Certificate extends Command { env: 'CHE_CA_CERT_LOCATION', default: '~' }), - 'make-path': boolean({ - description: 'Creates path specified in "destination" parameter if it doesn\'t exist.', - default: false - }), } async run() { - const { flags } = this.parse(Certificate) + const { flags } = this.parse(Get) const ctx: any = {} + const cheHelper = new CheHelper(flags) const platformTasks = new PlatformTasks() const cheTasks = new CheTasks(flags) const apiTasks = new ApiTasks() const tasks = new Listr([], { renderer: 'silent' }) - const targetFile = this.prepareTarget(flags.destination, flags['make-path']) - ctx.cheCaCertFile = targetFile + const targetFile = this.prepareTarget(flags.destination) tasks.add(platformTasks.preflightCheckTasks(flags, this)) tasks.add(apiTasks.testApiTasks(flags, this)) tasks.add(cheTasks.verifyCheNamespaceExistsTask(flags, this)) - tasks.add(cheTasks.retrieveEclipseCheCaCert(flags)) try { await tasks.run(ctx) + const cheCaCert = await cheHelper.retrieveEclipseCheCaCert(flags.chenamespace) + fs.writeFileSync(targetFile, cheCaCert) this.log(`Eclipse Che self-signed CA certificate is exported to ${targetFile}`) } catch (error) { this.error(error) @@ -75,7 +73,7 @@ export default class Certificate extends Command { /** * Handles certificate target location and returns string which points to the target file. */ - private prepareTarget(destinaton: string, makePath = false): string { + private prepareTarget(destinaton: string): string { if (destinaton === '~') { return path.join(os.homedir(), DEFAULT_CA_CERT_FILE_NAME) } @@ -84,22 +82,7 @@ export default class Certificate extends Command { return fs.lstatSync(destinaton).isDirectory() ? path.join(destinaton, DEFAULT_CA_CERT_FILE_NAME) : destinaton } - const baseDirectory = path.dirname(destinaton) - if (fs.existsSync(baseDirectory)) { - return destinaton - } - - if (makePath) { - if (destinaton.endsWith('/')) { - fs.mkdirSync(destinaton, { recursive: true }) - return path.join(destinaton, DEFAULT_CA_CERT_FILE_NAME) - } else { - fs.mkdirSync(baseDirectory, { recursive: true }) - return destinaton - } - } else { - throw new Error(`Base directory "${baseDirectory}" doesn't exist.`) - } + throw new Error('Given certificate path doesn\'t exist.') } } diff --git a/src/tasks/che.ts b/src/tasks/che.ts index abe8860ee..1d176665b 100644 --- a/src/tasks/che.ts +++ b/src/tasks/che.ts @@ -8,13 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import { Command } from '@oclif/command' -import * as fs from 'fs' import * as Listr from 'listr' import { CheHelper } from '../api/che' import { KubeHelper } from '../api/kube' import { OpenShiftHelper } from '../api/openshift' -import { CHE_ROOT_CA_SECRET_NAME } from '../constants' import { KubeTasks } from './kube' @@ -606,45 +604,6 @@ export class CheTasks { ] } - /** - * Saves self-signed Che CA certificate into file. 'self-signed-certificate' secret should exist. - */ - retrieveEclipseCheCaCert(flags: any): ReadonlyArray { - return [ - { - title: 'Retrieving self-signed Eclipse Che CA certificate', - task: async (ctx: any, task: any) => { - const cheCaSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, flags.chenamespace) - if (!cheCaSecret) { - throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" not found.`) - } - if (cheCaSecret.data && cheCaSecret.data['ca.crt']) { - ctx.cheCaCert = Buffer.from(cheCaSecret.data['ca.crt'], 'base64').toString('ascii') - } else { - throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" has invalid format.`) - } - - task.title = `${task.title}... done` - } - }, - { - title: 'Saving self-signed Eclipse Che CA certificate', - task: async (ctx: any, task: any) => { - if (!ctx.cheCaCert) { - throw new Error('Che CA certificate is not present in the context.') - } - if (!ctx.cheCaCertFile) { - throw new Error('Target file for Che CA certificate is not present in the context.') - } - - fs.writeFileSync(ctx.cheCaCertFile, ctx.cheCaCert) - - task.title = `Eclipse Che self-signed CA certificate is saved at ${ctx.cheCaCertFile}` - } - } - ] - } - checkEclipseCheStatus(): ReadonlyArray { return [ {