diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0286193..1c91cdf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+
+## [1.68.0](https://github.com/cloudogu/ces-build-lib/releases/tag/1.68.0) - 2023-11-30
+### 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
diff --git a/README.md b/README.md
index f8d2dc1..4c9158e 100644
--- a/README.md
+++ b/README.md
@@ -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:
@@ -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"
diff --git a/pom.xml b/pom.xml
index be79365..1d02b1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
com.cloudogu.ces
ces-build-lib
ces-build-lib
- 1.67.0
+ 1.68.0
diff --git a/src/com/cloudogu/ces/cesbuildlib/K3d.groovy b/src/com/cloudogu/ces/cesbuildlib/K3d.groovy
index 09177e6..36517d4 100644
--- a/src/com/cloudogu/ces/cesbuildlib/K3d.groovy
+++ b/src/com/cloudogu/ces/cesbuildlib/K3d.groovy
@@ -91,6 +91,7 @@ class K3d {
installLocalRegistry()
initializeCluster()
installKubectl()
+ installHelm()
loginBackend()
}
}
@@ -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)
}
@@ -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++) {
diff --git a/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy b/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy
index 80a78ef..2263994 100644
--- a/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy
+++ b/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy
@@ -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() {
@@ -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"
@@ -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() {
@@ -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() {
@@ -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() {