Skip to content

Commit

Permalink
Merge pull request #116 from cloudogu/feature/115_install_helm_in_k3d
Browse files Browse the repository at this point in the history
#115 add helm installation
  • Loading branch information
nhinze23 authored Nov 30, 2023
2 parents 603c02d + 0a91f7e commit a99f5c4
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 31 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


## [Unreleased]
### Added
- Add Helm installation with `k3d.installHelm()`; #115

## [1.67.0](https://github.com/cloudogu/ces-build-lib/releases/tag/1.67.0) - 2023-09-04
### Changed
- Switch to hadolint Dockerfile linter; #111
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ if (response.status == '201' && response.content-type == 'application/json') {

# K3d

`K3d` provides functions to set up and administer a lokal k3s cluster in Docker.
`K3d` provides functions to set up and administer a local k3s cluster in Docker.

Example:

Expand All @@ -1082,6 +1082,9 @@ try {
stage('Do something with your cluster') {
k3d.kubectl("get nodes")
}
stage('Apply your Helm chart') {
k3d.helm("install path/to/your/chart")
}
stage('build and push development artefact') {
String myCurrentArtefactVersion = "yourTag-1.2.3-dev"
Expand Down
31 changes: 31 additions & 0 deletions src/com/cloudogu/ces/cesbuildlib/K3d.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class K3d {
installLocalRegistry()
initializeCluster()
installKubectl()
installHelm()
loginBackend()
}
}
Expand Down Expand Up @@ -189,6 +190,23 @@ class K3d {
return script.sh(script: "sudo KUBECONFIG=${k3dDir}/.kube/config kubectl ${command}", returnStdout: returnStdout)
}

/**
* Runs any helm command.
* @param command must contain all necessary arguments and flags.
*/
void helm(command) {
helm(command, false)
}

/**
* Runs any helm command and returns the generated output if configured.
* @param command must contain all necessary arguments and flags.
* @param returnStdout if set to true this method returns the standard output stream generated by helm.
*/
String helm(command, returnStdout) {
return script.sh(script: "sudo KUBECONFIG=${k3dDir}/.kube/config helm ${command}", returnStdout: returnStdout)
}

String kubectlHideCommand(command, returnStdout) {
return script.sh(script: "set +x; sudo KUBECONFIG=${k3dDir}/.kube/config kubectl ${command}", returnStdout: returnStdout)
}
Expand Down Expand Up @@ -359,6 +377,19 @@ spec:
script.echo "Installing kubectl..."
script.sh script: "sudo snap install kubectl --classic"
}
/**
* Installs helm
*/
void installHelm() {
def helmStatusCode = script.sh script: "snap list helm", returnStatus: true
if (helmStatusCode == 0 || helmStatusCode.equals("0")) {
script.echo "helm already installed"
return
}

script.echo "Installing helm..."
script.sh script: "sudo snap install helm --classic"
}

private String getExecPodName(String dogu, Integer timeout, Integer interval) {
for (int i = 0; i < timeout / interval; i++) {
Expand Down
94 changes: 64 additions & 30 deletions test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class K3dTest extends GroovyTestCase {
sut.deleteK3d()

// then
assertThat(scriptMock.allActualArgs[20].trim()).contains("k3d registry delete citest-")
assertThat(scriptMock.allActualArgs[21].trim()).contains("k3d cluster delete citest-")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(22)
assertThat(scriptMock.allActualArgs[22].trim()).contains("k3d registry delete citest-")
assertThat(scriptMock.allActualArgs[23].trim()).contains("k3d cluster delete citest-")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(24)
}

void testKubectl() {
Expand All @@ -53,6 +53,36 @@ class K3dTest extends GroovyTestCase {
assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config kubectl get nodes".trim())
assertThat(scriptMock.allActualArgs.size()).isEqualTo(1)
}
void testHelm() {
// given
String workspaceDir = "leWorkspace"
def scriptMock = new ScriptMock()
K3d sut = new K3d(scriptMock, workspaceDir, "leK3dWorkSpace", "path")

// when
sut.helm("install path/to/chart/")

// then
assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config helm install path/to/chart/".trim())
assertThat(scriptMock.allActualArgs.size()).isEqualTo(1)
}

// we cannot test lazy-installation because the mock is incapable of mocking the right types, the right values
// and thus repeated calls to the same script with different results.
void testInstallHelm_initially() {
// given
String workspaceDir = "leWorkspace"
def scriptMock = new ScriptMock()
K3d sut = new K3d(scriptMock, workspaceDir, "leK3dWorkSpace", "path")

// when
sut.installHelm()

// then
assertThat(scriptMock.allActualArgs.size()).isEqualTo(2)
assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("snap list helm".trim())
assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("sudo snap install helm --classic".trim())
}

void testStartK3d() {
def workspaceDir = "leWorkspace"
Expand All @@ -74,19 +104,21 @@ class K3dTest extends GroovyTestCase {
assertThat(scriptMock.allActualArgs[5].trim()).startsWith("k3d cluster create citest-")
assertThat(scriptMock.allActualArgs[6].trim()).startsWith("k3d kubeconfig merge citest-")
assertThat(scriptMock.allActualArgs[7].trim()).startsWith("snap list kubectl")
assertThat(scriptMock.allActualArgs[8].trim()).startsWith("sudo snap install kubectl")
assertThat(scriptMock.allActualArgs[9].trim()).startsWith("echo \"Using credentials: cesmarvin-setup\"")
assertThat(scriptMock.allActualArgs[10].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-dogu-registry || true")
assertThat(scriptMock.allActualArgs[11].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-docker-registry || true")
assertThat(scriptMock.allActualArgs[12].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret generic k8s-dogu-operator-dogu-registry --from-literal=endpoint=\"https://dogu.cloudogu.com/api/v2/dogus\" --from-literal=username=\"null\" --from-literal=password=\"null\"")
assertThat(scriptMock.allActualArgs[13].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret docker-registry k8s-dogu-operator-docker-registry --docker-server=\"registry.cloudogu.com\" --docker-username=\"null\" --docker-email=\"a@b.c\" --docker-password=\"null\"")
assertThat(scriptMock.allActualArgs[14].trim()).startsWith("echo \"Using credentials: harborhelmchartpush\"")
assertThat(scriptMock.allActualArgs[15].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete configmap component-operator-helm-repository || true")
assertThat(scriptMock.allActualArgs[16].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret component-operator-helm-registry || true")
assertThat(scriptMock.allActualArgs[17].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create configmap component-operator-helm-repository --from-literal=endpoint=\"registry.cloudogu.com\" --from-literal=schema=\"oci\" --from-literal=plainHttp=\"false\"")
assertThat(scriptMock.allActualArgs[18].trim()).startsWith("printf '%s:%s' 'null' 'null' | base64")
assertThat(scriptMock.allActualArgs[19].trim()).startsWith("set +x; sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config kubectl create secret generic component-operator-helm-registry --from-literal=config.json='{\"auths\": {\"registry.cloudogu.com\": {\"auth\": \"null\"}}}'")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(20)
assertThat(scriptMock.allActualArgs[8].trim()).startsWith("sudo snap install kubectl --classic")
assertThat(scriptMock.allActualArgs[9].trim()).startsWith("snap list helm")
assertThat(scriptMock.allActualArgs[10].trim()).startsWith("sudo snap install helm --classic")
assertThat(scriptMock.allActualArgs[11].trim()).startsWith("echo \"Using credentials: cesmarvin-setup\"")
assertThat(scriptMock.allActualArgs[12].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-dogu-registry || true")
assertThat(scriptMock.allActualArgs[13].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-docker-registry || true")
assertThat(scriptMock.allActualArgs[14].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret generic k8s-dogu-operator-dogu-registry --from-literal=endpoint=\"https://dogu.cloudogu.com/api/v2/dogus\" --from-literal=username=\"null\" --from-literal=password=\"null\"")
assertThat(scriptMock.allActualArgs[15].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret docker-registry k8s-dogu-operator-docker-registry --docker-server=\"registry.cloudogu.com\" --docker-username=\"null\" --docker-email=\"a@b.c\" --docker-password=\"null\"")
assertThat(scriptMock.allActualArgs[16].trim()).startsWith("echo \"Using credentials: harborhelmchartpush\"")
assertThat(scriptMock.allActualArgs[17].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete configmap component-operator-helm-repository || true")
assertThat(scriptMock.allActualArgs[18].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret component-operator-helm-registry || true")
assertThat(scriptMock.allActualArgs[19].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create configmap component-operator-helm-repository --from-literal=endpoint=\"registry.cloudogu.com\" --from-literal=schema=\"oci\" --from-literal=plainHttp=\"false\"")
assertThat(scriptMock.allActualArgs[20].trim()).startsWith("printf '%s:%s' 'null' 'null' | base64")
assertThat(scriptMock.allActualArgs[21].trim()).startsWith("set +x; sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config kubectl create secret generic component-operator-helm-registry --from-literal=config.json='{\"auths\": {\"registry.cloudogu.com\": {\"auth\": \"null\"}}}'")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(22)
}

void testStartK3dWithCustomCredentials() {
Expand All @@ -110,18 +142,20 @@ class K3dTest extends GroovyTestCase {
assertThat(scriptMock.allActualArgs[6].trim()).startsWith("k3d kubeconfig merge citest-")
assertThat(scriptMock.allActualArgs[7].trim()).startsWith("snap list kubectl")
assertThat(scriptMock.allActualArgs[8].trim()).startsWith("sudo snap install kubectl")
assertThat(scriptMock.allActualArgs[9].trim()).startsWith("echo \"Using credentials: myBackendCredentialsID\"")
assertThat(scriptMock.allActualArgs[10].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-dogu-registry || true")
assertThat(scriptMock.allActualArgs[11].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-docker-registry || true")
assertThat(scriptMock.allActualArgs[12].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret generic k8s-dogu-operator-dogu-registry --from-literal=endpoint=\"https://dogu.cloudogu.com/api/v2/dogus\" --from-literal=username=\"null\" --from-literal=password=\"null\"")
assertThat(scriptMock.allActualArgs[13].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret docker-registry k8s-dogu-operator-docker-registry --docker-server=\"registry.cloudogu.com\" --docker-username=\"null\" --docker-email=\"a@b.c\" --docker-password=\"null\"")
assertThat(scriptMock.allActualArgs[14].trim()).startsWith("echo \"Using credentials: myHarborCredentials\"")
assertThat(scriptMock.allActualArgs[15].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete configmap component-operator-helm-repository || true")
assertThat(scriptMock.allActualArgs[16].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret component-operator-helm-registry || true")
assertThat(scriptMock.allActualArgs[17].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create configmap component-operator-helm-repository --from-literal=endpoint=\"registry.cloudogu.com\" --from-literal=schema=\"oci\" --from-literal=plainHttp=\"false\"")
assertThat(scriptMock.allActualArgs[18].trim()).startsWith("printf '%s:%s' 'null' 'null' | base64")
assertThat(scriptMock.allActualArgs[19].trim()).startsWith("set +x; sudo KUBECONFIG=path/.k3d/.kube/config kubectl create secret generic component-operator-helm-registry --from-literal=config.json='{\"auths\": {\"registry.cloudogu.com\": {\"auth\": \"null\"}}}'")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(20)
assertThat(scriptMock.allActualArgs[9].trim()).startsWith("snap list helm")
assertThat(scriptMock.allActualArgs[10].trim()).startsWith("sudo snap install helm")
assertThat(scriptMock.allActualArgs[11].trim()).startsWith("echo \"Using credentials: myBackendCredentialsID\"")
assertThat(scriptMock.allActualArgs[12].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-dogu-registry || true")
assertThat(scriptMock.allActualArgs[13].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret k8s-dogu-operator-docker-registry || true")
assertThat(scriptMock.allActualArgs[14].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret generic k8s-dogu-operator-dogu-registry --from-literal=endpoint=\"https://dogu.cloudogu.com/api/v2/dogus\" --from-literal=username=\"null\" --from-literal=password=\"null\"")
assertThat(scriptMock.allActualArgs[15].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create secret docker-registry k8s-dogu-operator-docker-registry --docker-server=\"registry.cloudogu.com\" --docker-username=\"null\" --docker-email=\"a@b.c\" --docker-password=\"null\"")
assertThat(scriptMock.allActualArgs[16].trim()).startsWith("echo \"Using credentials: myHarborCredentials\"")
assertThat(scriptMock.allActualArgs[17].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete configmap component-operator-helm-repository || true")
assertThat(scriptMock.allActualArgs[18].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl delete secret component-operator-helm-registry || true")
assertThat(scriptMock.allActualArgs[19].trim()).startsWith("sudo KUBECONFIG=${k3dWorkspaceDir}/.k3d/.kube/config kubectl create configmap component-operator-helm-repository --from-literal=endpoint=\"registry.cloudogu.com\" --from-literal=schema=\"oci\" --from-literal=plainHttp=\"false\"")
assertThat(scriptMock.allActualArgs[20].trim()).startsWith("printf '%s:%s' 'null' 'null' | base64")
assertThat(scriptMock.allActualArgs[21].trim()).startsWith("set +x; sudo KUBECONFIG=path/.k3d/.kube/config kubectl create secret generic component-operator-helm-registry --from-literal=config.json='{\"auths\": {\"registry.cloudogu.com\": {\"auth\": \"null\"}}}'")
assertThat(scriptMock.allActualArgs.size()).isEqualTo(22)
}

void testBuildAndPush() {
Expand Down Expand Up @@ -156,8 +190,8 @@ class K3dTest extends GroovyTestCase {
sut.buildAndPushToLocalRegistry(imageName, imageTag)

// then
assertThat(scriptMock.allActualArgs[20].trim()).isEqualTo("image pushed".toString())
assertThat(scriptMock.allActualArgs.size()).isEqualTo(21)
assertThat(scriptMock.allActualArgs[22].trim()).isEqualTo("image pushed".toString())
assertThat(scriptMock.allActualArgs.size()).isEqualTo(23)
}

void testSetup() {
Expand Down

0 comments on commit a99f5c4

Please sign in to comment.