Skip to content

Commit

Permalink
feat: Allow to debug Eclipse Che Server locally (che-incubator#477)
Browse files Browse the repository at this point in the history
* Allow to debug Eclipse Che Server locally

Signed-off-by: Anatoliy Bazko <[email protected]>
  • Loading branch information
tolusha authored Feb 4, 2020
1 parent d8a5d77 commit 370a015
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 10 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ USAGE
* [`chectl autocomplete [SHELL]`](#chectl-autocomplete-shell)
* [`chectl devfile:generate`](#chectl-devfilegenerate)
* [`chectl help [COMMAND]`](#chectl-help-command)
* [`chectl server:debug`](#chectl-serverdebug)
* [`chectl server:delete`](#chectl-serverdelete)
* [`chectl server:logs`](#chectl-serverlogs)
* [`chectl server:start`](#chectl-serverstart)
Expand Down Expand Up @@ -168,6 +169,27 @@ OPTIONS

_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v2.2.1/src/commands/help.ts)_

## `chectl server:debug`

Enable local debug of Eclipse Che server

```
USAGE
$ chectl server:debug
OPTIONS
-h, --help show CLI help
-n, --chenamespace=chenamespace [default: che] Kubernetes namespace where Che server is supposed to be
deployed
--debug-port=debug-port [default: 8000] Eclipse Che Server debug port
--listr-renderer=default|silent|verbose [default: default] Listr renderer
```

_See code: [src/commands/server/debug.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/server/debug.ts)_

## `chectl server:delete`

delete any Eclipse Che related resource: Kubernetes/OpenShift/Helm
Expand Down Expand Up @@ -263,6 +285,9 @@ OPTIONS
[default: quay.io/eclipse/che-operator:nightly] Container image of the operator. This parameter is used only when
the installer is the operator
--debug
Enables the debug mode for Che server. To debug Eclipse Che Server from localhost use 'server:debug' command.
--deployment-name=deployment-name
[default: che] Eclipse Che deployment name
Expand Down
27 changes: 23 additions & 4 deletions src/api/kube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { ApiextensionsV1beta1Api, ApisApi, AppsV1Api, CoreV1Api, CustomObjectsApi, ExtensionsV1beta1Api, KubeConfig, Log, RbacAuthorizationV1Api, V1beta1CustomResourceDefinition, V1beta1IngressList, V1ClusterRole, V1ClusterRoleBinding, V1ConfigMap, V1ConfigMapEnvSource, V1Container, V1DeleteOptions, V1Deployment, V1DeploymentList, V1DeploymentSpec, V1EnvFromSource, V1LabelSelector, V1NamespaceList, V1ObjectMeta, V1PersistentVolumeClaimList, V1Pod, V1PodList, V1PodSpec, V1PodTemplateSpec, V1Role, V1RoleBinding, V1RoleRef, V1Secret, V1ServiceAccount, V1ServiceList, V1Subject } from '@kubernetes/client-node'
import { ApiextensionsV1beta1Api, ApisApi, AppsV1Api, CoreV1Api, CustomObjectsApi, ExtensionsV1beta1Api, KubeConfig, Log, PortForward, RbacAuthorizationV1Api, V1beta1CustomResourceDefinition, V1beta1IngressList, V1ClusterRole, V1ClusterRoleBinding, V1ConfigMap, V1ConfigMapEnvSource, V1Container, V1DeleteOptions, V1Deployment, V1DeploymentList, V1DeploymentSpec, V1EnvFromSource, V1LabelSelector, V1NamespaceList, V1ObjectMeta, V1PersistentVolumeClaimList, V1Pod, V1PodList, V1PodSpec, V1PodTemplateSpec, V1Role, V1RoleBinding, V1RoleRef, V1Secret, V1ServiceAccount, V1ServiceList, V1Subject } from '@kubernetes/client-node'
import { Context } from '@kubernetes/client-node/dist/config_types'
import axios from 'axios'
import { cli } from 'cli-ux'
import * as fs from 'fs'
import https = require('https')
import * as yaml from 'js-yaml'
import * as net from 'net'
import { Writable } from 'stream'

import { DEFAULT_CHE_IMAGE } from '../constants'

export class KubeHelper {
kc = new KubeConfig()
portForwardHelper = new PortForward(this.kc, true)
logHelper = new Log(this.kc)

podWaitTimeout: number
Expand Down Expand Up @@ -387,13 +389,13 @@ export class KubeHelper {
}
}

async configMapExist(name = '', namespace = ''): Promise<boolean> {
async getConfigMap(name = '', namespace = ''): Promise<V1ConfigMap | undefined> {
const k8sCoreApi = this.kc.makeApiClient(CoreV1Api)
try {
const { body } = await k8sCoreApi.readNamespacedConfigMap(name, namespace)
return this.compare(body, name)
return this.compare(body, name) && body
} catch {
return false
return
}
}

Expand Down Expand Up @@ -956,6 +958,7 @@ export class KubeHelper {
const imageAndTag = cheImage.split(':', 2)
yamlCr.spec.server.cheImage = imageAndTag[0]
yamlCr.spec.server.cheImageTag = imageAndTag.length === 2 ? imageAndTag[1] : 'latest'
yamlCr.spec.server.cheDebug = flags.debug ? flags.debug.toString() : 'false'

yamlCr.spec.auth.openShiftoAuth = flags['os-oauth']
yamlCr.spec.server.tlsSupport = flags.tls
Expand Down Expand Up @@ -1311,6 +1314,22 @@ export class KubeHelper {
})
}

/**
* Forwards port, based on the example
* https://github.com/kubernetes-client/javascript/blob/master/examples/typescript/port-forward/port-forward.ts
*/
async portForward(podName: string, namespace: string, port: number): Promise<void> {
try {
const server = net.createServer(async socket => {
await this.portForwardHelper.portForward(namespace, podName, [port], socket, null, socket)
})
server.listen(port, 'localhost')
return
} catch (e) {
throw this.wrapK8sClientError(e)
}
}

/**
* Checks if message is present and returns error with it
* or returns error with the specified error if message is not found.
Expand Down
52 changes: 52 additions & 0 deletions src/commands/server/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*********************************************************************
* Copyright (c) 2019 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { Command, flags } from '@oclif/command'
import { integer } from '@oclif/parser/lib/flags'
import * as Listr from 'listr'

import { cheNamespace, listrRenderer } from '../../common-flags'
import { CheTasks } from '../../tasks/che'
import { K8sTasks } from '../../tasks/platforms/k8s'

export default class Debug extends Command {
static description = 'Enable local debug of Eclipse Che server'

static flags = {
help: flags.help({ char: 'h' }),
chenamespace: cheNamespace,
'listr-renderer': listrRenderer,
'debug-port': integer({
description: 'Eclipse Che Server debug port',
default: 8000
})
}

async run() {
const { flags } = this.parse(Debug)
const ctx: any = {}

const cheTasks = new CheTasks(flags)
const k8sTasks = new K8sTasks()
const tasks = new Listr([], { renderer: flags['listr-renderer'] as any })

tasks.add(k8sTasks.testApiTasks(flags, this))
tasks.add(cheTasks.verifyCheNamespaceExistsTask(flags, this))
tasks.add(cheTasks.debugTask(flags))

try {
await tasks.run(ctx)
this.log(`Eclipse Che Server debug is available on localhost:${flags['debug-port']}.`)
this.log('The program keeps running to enable port forwarding.')
} catch (error) {
this.error(error)
}
}
}
6 changes: 5 additions & 1 deletion src/commands/server/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**********************************************************************/

import { Command, flags } from '@oclif/command'
import { string } from '@oclif/parser/lib/flags'
import { boolean, string } from '@oclif/parser/lib/flags'
import * as fs from 'fs-extra'
import * as Listr from 'listr'
import * as notifier from 'node-notifier'
Expand Down Expand Up @@ -98,6 +98,10 @@ export default class Start extends Command {
description: 'Domain of the Kubernetes cluster (e.g. example.k8s-cluster.com or <local-ip>.nip.io)',
default: ''
}),
debug: boolean({
description: 'Enables the debug mode for Che server. To debug Eclipse Che Server from localhost use \'server:debug\' command.',
default: false
}),
'os-oauth': flags.boolean({
description: 'Enable use of OpenShift credentials to log into Eclipse Che',
default: false
Expand Down
1 change: 0 additions & 1 deletion src/commands/workspace/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export default class Start extends Command {
let ctx = await tasks.run()
this.log('\nWorkspace IDE URL:')
cli.url(ctx.workspaceIdeURL, ctx.workspaceIdeURL)
cli.info("To start collecting logs run 'chectl workspace:logs --follow'")
} catch (err) {
this.error(err)
}
Expand Down
38 changes: 36 additions & 2 deletions src/tasks/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,10 @@ export class CheTasks {
{
title: 'Delete configmaps che and che-operator',
task: async (_ctx: any, task: any) => {
if (await this.kube.configMapExist('che', flags.chenamespace)) {
if (await this.kube.getConfigMap('che', flags.chenamespace)) {
await this.kube.deleteConfigMap('che', flags.chenamespace)
}
if (await this.kube.configMapExist('che-operator', flags.chenamespace)) {
if (await this.kube.getConfigMap('che-operator', flags.chenamespace)) {
await this.kube.deleteConfigMap('che-operator', flags.chenamespace)
}
task.title = await `${task.title}...OK`
Expand Down Expand Up @@ -554,4 +554,38 @@ export class CheTasks {
}
]
}

debugTask(flags: any): ReadonlyArray<Listr.ListrTask> {
return [
{
title: 'Find Che Server pod',
task: async (ctx: any, task: any) => {
const chePods = await this.kube.listNamespacedPod(flags.chenamespace, undefined, this.cheSelector)
if (chePods.items.length === 0) {
throw new Error(`Che Server pod not found in the namespace '${flags.chenamespace}'`)
}
ctx.podName = chePods.items[0].metadata!.name!
task.title = `${task.title}...done`
}
},
{
title: 'Check if debug mode is enabled',
task: async (task: any) => {
const configMap = await this.kube.getConfigMap('che', flags.chenamespace)
if (!configMap || configMap.data!.CHE_DEBUG_SERVER !== 'true') {
throw new Error('Che Server should be redeployed with \'--debug\' flag')
}

task.title = `${task.title}...done`
}
},
{
title: `Forward port '${flags['debug-port']}'`,
task: async (ctx: any, task: any) => {
await this.kube.portForward(ctx.podName, flags.chenamespace, flags['debug-port'])
task.title = `${task.title}...done`
}
}
]
}
}
1 change: 1 addition & 0 deletions src/tasks/installers/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ error: E_COMMAND_FAILED`)

setOptions.push(`--set global.ingressDomain=${flags.domain}`)
setOptions.push(`--set cheImage=${flags.cheimage}`)
setOptions.push(`--set che.disableProbes=${flags.debug}`)

let command = `helm upgrade --install che --force --namespace ${flags.chenamespace} ${setOptions.join(' ')} ${multiUserFlag} ${tlsFlag} ${destDir}`

Expand Down
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1677,11 +1677,11 @@ ecc-jsbn@~0.1.1:

"eclipse-che-operator@git://github.com/eclipse/che-operator#master":
version "0.0.0"
resolved "git://github.com/eclipse/che-operator#9332233235843963488193b9f69985372f87d8e6"
resolved "git://github.com/eclipse/che-operator#5039e1fdb2860d660285f4e45f75449f29c93542"

"eclipse-che@git://github.com/eclipse/che#master":
version "0.0.0"
resolved "git://github.com/eclipse/che#a5f510162c8e5cf7d886246278193c1289a28b1f"
resolved "git://github.com/eclipse/che#45604b90ef68caea3238f2bc8faf9759c6828d60"

editorconfig@^0.15.0:
version "0.15.3"
Expand Down

0 comments on commit 370a015

Please sign in to comment.