Skip to content

Commit

Permalink
feat(helm): Add support for helm v3
Browse files Browse the repository at this point in the history
fix eclipse-che/che#15235

Change-Id: If48ecd53baaf4bdca70cfbbd3175c97f73592afd
Signed-off-by: Florent Benoit <[email protected]>
  • Loading branch information
benoitf committed Nov 27, 2019
1 parent 73962e0 commit b768811
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/tasks/installers/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { copy, mkdirp, remove } from 'fs-extra'
import * as Listr from 'listr'
import * as path from 'path'

import { CheHelper } from '../../api/che'
import { KubeHelper } from '../../api/kube'

export class HelmTasks {
Expand All @@ -28,6 +29,33 @@ export class HelmTasks {
title: 'Verify if helm is installed',
task: () => { if (!commandExists.sync('helm')) { command.error('E_REQUISITE_NOT_FOUND') } }
},
{
title: 'Check Helm Version',
task: async (ctx: any, task: any) => {
try {
const version = await this.getVersion()
if (version.startsWith('v3.')) {
ctx.isHelmV3 = true
}
task.title = await `${task.title}: Found ${version}`
} catch (error) {
command.error(`Unable to get helm version. ${error.message}`)
}
}
},
{
title: `Create Namespace (${flags.chenamespace})`,
task: async (_ctx: any, task: any) => {
const che = new CheHelper(flags)
const exist = await che.cheNamespaceExist(flags.chenamespace)
if (exist) {
task.title = `${task.title}...does already exist.`
} else {
await execa(`kubectl create namespace ${flags.chenamespace}`, { shell: true })
task.title = `${task.title}...done.`
}
}
},
{
title: 'Check for TLS secret prerequisites',
// Check only if TLS is enabled
Expand Down Expand Up @@ -72,6 +100,8 @@ export class HelmTasks {
},
{
title: 'Create Tiller Role Binding',
// Tiller is not used anymore in helm v3
enabled: (ctx: any) => !ctx.isHelmV3,
task: async (_ctx: any, task: any) => {
const roleBindingExist = await this.tillerRoleBindingExist()
if (roleBindingExist) {
Expand All @@ -82,8 +112,24 @@ export class HelmTasks {
}
}
},
{
title: 'Check Cluster Role Binding',
// For helm v3 check for cluster role and delete it if exists
enabled: (ctx: any) => ctx.isHelmV3,
task: async (_ctx: any, task: any) => {
const roleBindingExist = await this.clusterRoleBindingExist(flags.chenamespace)
if (!roleBindingExist) {
task.title = `${task.title}...does not exists.`
} else {
await this.removeClusterRoleBinding(flags.chenamespace)
task.title = `${task.title}...done.`
}
}
},
{
title: 'Create Tiller Service Account',
// Tiller is not used anymore in helm v3
enabled: (ctx: any) => !ctx.isHelmV3,
task: async (_ctx: any, task: any) => {
const tillerServiceAccountExist = await this.tillerServiceAccountExist()
if (tillerServiceAccountExist) {
Expand All @@ -96,9 +142,13 @@ export class HelmTasks {
},
{
title: 'Create Tiller RBAC',
// Tiller is not used anymore in helm v3
enabled: (ctx: any) => !ctx.isHelmV3,
task: async () => this.createTillerRBAC(flags.templates)
},
{
// Tiller is not used anymore in helm v3
enabled: (ctx: any) => !ctx.isHelmV3,
title: 'Create Tiller Service',
task: async (_ctx: any, task: any) => {
const tillerServiceExist = await this.tillerServiceExist()
Expand Down Expand Up @@ -152,6 +202,16 @@ export class HelmTasks {
}]
}

async clusterRoleBindingExist(cheNamespace: string, execTimeout = 30000): Promise<boolean> {
const { exitCode } = await execa('kubectl', ['get', 'clusterrolebinding', `${cheNamespace}-che-clusterrole-binding`], { timeout: execTimeout, reject: false })
if (exitCode === 0) { return true } else { return false }
}

async removeClusterRoleBinding(cheNamespace: string, execTimeout = 30000): Promise<boolean> {
const { exitCode } = await execa('kubectl', ['delete', 'clusterrolebinding', `${cheNamespace}-che-clusterrole-binding`], { timeout: execTimeout, reject: false })
if (exitCode === 0) { return true } else { return false }
}

async tillerRoleBindingExist(execTimeout = 30000): Promise<boolean> {
const { exitCode } = await execa('kubectl', ['get', 'clusterrolebinding', 'add-on-cluster-admin'], { timeout: execTimeout, reject: false })
if (exitCode === 0) { return true } else { return false }
Expand Down Expand Up @@ -182,6 +242,12 @@ export class HelmTasks {
if (exitCode === 0) { return true } else { return false }
}

async getVersion(execTimeout = 10000): Promise<string> {
const { stdout, exitCode } = await execa('helm', ['version', '--short'], { timeout: execTimeout, reject: false })
if (exitCode === 0) { return stdout }
throw new Error('Unable to get version')
}

async createTillerService(execTimeout = 120000) {
const { command, exitCode, stderr, stdout, timedOut } =
await execa('helm', ['init', '--service-account', 'tiller', '--wait'], { timeout: execTimeout, reject: false })
Expand Down
28 changes: 28 additions & 0 deletions test/tasks/installers/helm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*********************************************************************
* 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
**********************************************************************/
// tslint:disable:object-curly-spacing
import { expect, fancy } from 'fancy-test'
import * as execa from 'execa'

import { HelmTasks } from '../../../src/tasks/installers/helm'

jest.mock('execa')

let helmTasks = new HelmTasks()
describe('Helm helper', () => {

fancy
.it('check get v3 version', async () => {
const helmVersionOutput = 'v3.0.0+ge29ce2a';
(execa as any).mockResolvedValue({ exitCode: 0, stdout: helmVersionOutput })
const version = await helmTasks.getVersion();
expect(version).to.equal('v3.0.0+ge29ce2a')
})
})

0 comments on commit b768811

Please sign in to comment.