diff --git a/CHANGELOG.md b/CHANGELOG.md index fcd211d..929361a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- use ecosystem-core instead of k8e-ces-setup to install cluster ## [4.4.0](https://github.com/cloudogu/ces-build-lib/releases/tag/4.4.0) - 2025-08-21 ### Changed diff --git a/src/com/cloudogu/ces/cesbuildlib/K3d.groovy b/src/com/cloudogu/ces/cesbuildlib/K3d.groovy index beaaf5f..4c15833 100644 --- a/src/com/cloudogu/ces/cesbuildlib/K3d.groovy +++ b/src/com/cloudogu/ces/cesbuildlib/K3d.groovy @@ -1,6 +1,7 @@ package com.cloudogu.ces.cesbuildlib import com.cloudbees.groovy.cps.NonCPS +import groovy.json.JsonSlurper class K3d { /** @@ -12,9 +13,17 @@ class K3d { */ private static String K3D_VERSION = "5.6.0" private static String K3D_LOG_FILENAME = "k8sLogs" - private static String K3D_SETUP_JSON_FILE = "k3d_setup.json" private static String K3D_VALUES_YAML_FILE = "k3d_values.yaml" + private static String K3D_BLUEPRINT_FILE = "k3d_blueprint.yaml" private static String YQ_VERSION = "4.40.5" + // need to be installed before apply values.yaml + private static String VERSION_ECOSYSTEM_CORE; // e.g. "1.2.0" + private static String VERSION_K8S_COMPONENT_OPERATOR_CRD; // e.g. "1.10.1" + // configured by values.yaml + private static String VERSION_K8S_DOGU_OPERATOR; // e.g. "3.15.0" + private static String VERSION_K8S_DOGU_OPERATOR_CRD; // e.g. "2.10.0" + private static String VERSION_K8S_BLUEPRINT_OPERATOR; // e.g. "3.0.2" + private static String VERSION_K8S_BLUEPRINT_OPERATOR_CRD ; // e.g. "3.1.0" private String clusterName private script @@ -36,14 +45,14 @@ class K3d { adminGroup : "CesAdministrators", dependencies : ["official/ldap", "official/cas", - "k8s/nginx-ingress", - "k8s/nginx-static", "official/postfix", "official/usermgt"], defaultDogu : "", additionalDependencies : [], registryConfig : "", - registryConfigEncrypted: "" + registryConfigEncrypted: "", + "enableBackup" : false, + "enableMonitoring" : false ] String getRegistryName() { @@ -254,40 +263,60 @@ class K3d { } } - void configureSetupJson(config = [:]) { - String setupJsonConfigKey = ".setup_json" - script.echo "configuring setup..." + static void setVersionEcosystemCore(String v) { + VERSION_ECOSYSTEM_CORE = v; + } + static void setVersionComponentOperatorCrd(String v) { + VERSION_K8S_COMPONENT_OPERATOR_CRD = v; + } + static void setVersionDoguOperator(String v) { + VERSION_K8S_DOGU_OPERATOR = v; + } + static void setVersionDoguOperatorCrd(String v) { + VERSION_K8S_DOGU_OPERATOR_CRD = v; + } + static void setVersionBlueprintOperator(String v) { + VERSION_K8S_BLUEPRINT_OPERATOR = v; + } + static void setVersionBlueprintOperatorCrd(String v) { + VERSION_K8S_BLUEPRINT_OPERATOR_CRD = v; + } + + void configureEcosystemCoreValues(config = [:]) { // Merge default config with the one passed as parameter config = defaultSetupConfig << config - writeSetupJson(config) - appendFileToYamlFile(K3D_VALUES_YAML_FILE, setupJsonConfigKey, K3D_SETUP_JSON_FILE) - } + yqEvalYamlFile(K3D_VALUES_YAML_FILE, ".defaultConfig.env.waitTimeoutMinutes = 5") - void configureSetupImage(String image) { - String hostKey = ".setup.image.registry" - String repositoryKey = ".setup.image.repository" - String tagKey = ".setup.image.tag" - def repositorySeparatorIndex = image.indexOf("/") - def tagSeparatorIndex = image.lastIndexOf(":") + if (VERSION_K8S_DOGU_OPERATOR_CRD != null) { + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-dogu-operator-crd.version", VERSION_K8S_DOGU_OPERATOR_CRD) + } + if (VERSION_K8S_DOGU_OPERATOR != null) { + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-dogu-operator.version", VERSION_K8S_DOGU_OPERATOR) + } + if (VERSION_K8S_BLUEPRINT_OPERATOR_CRD != null) { + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-blueprint-operator-crd.version", VERSION_K8S_BLUEPRINT_OPERATOR_CRD) + } + if (VERSION_K8S_BLUEPRINT_OPERATOR != null) { + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-blueprint-operator.version", VERSION_K8S_BLUEPRINT_OPERATOR) + } - appendToYamlFile(K3D_VALUES_YAML_FILE, hostKey, image.substring(0, repositorySeparatorIndex)) - appendToYamlFile(K3D_VALUES_YAML_FILE, repositoryKey, image.substring(repositorySeparatorIndex + 1, tagSeparatorIndex)) - appendToYamlFile(K3D_VALUES_YAML_FILE, tagKey, image.substring(tagSeparatorIndex + 1, image.length())) - } + yqEvalYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-ces-control.disabled = true") - void configureComponentOperatorVersion(String operatorVersion, String crdVersion = operatorVersion, String namespace = "k8s") { - String componentOpKey = ".component_operator_chart" - String componentCRDKey = ".component_operator_crd_chart" + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-service-discovery.valuesObject.loadBalancerService.internalTrafficPolicy", "Cluster") + appendToYamlFile(K3D_VALUES_YAML_FILE, ".components.k8s-service-discovery.valuesObject.loadBalancerService.externalTrafficPolicy", "Cluster") + yqEvalYamlFile(K3D_VALUES_YAML_FILE, ".backup.enabled = ${config.enableBackup}") + yqEvalYamlFile(K3D_VALUES_YAML_FILE, ".monitoring.enabled = ${config.enableMonitoring}") + + script.echo "configuring ecosystem core..." + writeBlueprintYaml(config) + } - def builder = new StringBuilder(namespace) - String operatorValue = builder.append("/k8s-component-operator:").append(operatorVersion).toString() - appendToYamlFile(K3D_VALUES_YAML_FILE, componentOpKey, operatorValue) - builder.delete(0, builder.length()); - String crdValue = builder.append(namespace).append("/k8s-component-operator-crd:").append(crdVersion).toString() - appendToYamlFile(K3D_VALUES_YAML_FILE, componentCRDKey, crdValue) + @Deprecated + void configureSetupJson(config = [:]) { + configureEcosystemCoreValues(config) } void configureComponents(components = [:]) { @@ -308,11 +337,7 @@ class K3d { } } - void configureLogLevel(String loglevel) { - appendToYamlFile(K3D_VALUES_YAML_FILE, ".logLevel", loglevel) - } - - void installAndTriggerSetup(String tag, Integer timeout = 300, Integer interval = 5) { + void installAndTriggerSetup(Integer timeout = 300, Integer interval = 5) { script.echo "Installing setup..." String registryUrl = "registry.cloudogu.com" String registryNamespace = "k8s" @@ -320,51 +345,61 @@ class K3d { helm("registry login ${registryUrl} --username '${script.env.HARBOR_USERNAME}' --password '${script.env.HARBOR_PASSWORD}'") } - helm("install -f ${K3D_VALUES_YAML_FILE} k8s-ces-setup oci://${registryUrl}/${registryNamespace}/k8s-ces-setup --version ${tag} --namespace default") - helm("registry logout ${registryUrl}") + // install crd first + String comp_crd_version = VERSION_K8S_COMPONENT_OPERATOR_CRD == null ? "" : " --version ${VERSION_K8S_COMPONENT_OPERATOR_CRD}" + helm("install k8s-component-operator-crd oci://${registryUrl}/${registryNamespace}/k8s-component-operator-crd ${comp_crd_version} --namespace default") + + kubectl("--namespace default create configmap global-config --from-literal=config.yaml='fqdn: ${externalIP}'") - script.echo "Wait for dogu-operator to be ready..." - waitForDeploymentRollout("k8s-dogu-operator-controller-manager", timeout, interval) + String eco_core_version = VERSION_ECOSYSTEM_CORE == null ? "" : " --version ${VERSION_ECOSYSTEM_CORE}" + helm("install -f ${K3D_VALUES_YAML_FILE} ecosystem-core oci://${registryUrl}/${registryNamespace}/ecosystem-core ${eco_core_version} --namespace default --timeout 15m") - script.echo "Wait for setup-finisher to be executed..." - waitForSetupToFinish(timeout, interval) + script.echo "Wait for blueprint-operator to be ready..." + waitForDeploymentRollout("k8s-blueprint-operator-controller-manager", timeout, interval) + + kubectl("apply -f ${K3D_BLUEPRINT_FILE} --namespace default") + + script.echo "Wait for blueprint to be ready..." + waitForBlueprintToBeReady(timeout, interval) script.echo "Wait for dogus to be ready..." waitForDogusToBeRolledOut(timeout, interval) + + helm("registry logout ${registryUrl}") } void waitForDogusToBeRolledOut(Integer timeout, Integer interval) { String dogus = kubectl("get dogus --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'", true) - String[] doguList = dogus.split("\n") + String[] doguList = dogus.trim().split("\n") for (String dogu : doguList) { script.echo "Wait for $dogu to be rolled out..." waitForDeploymentRollout(dogu, timeout, interval) } } - void waitForSetupToFinish(Integer timeout, Integer interval) { + void waitForBlueprintToBeReady(Integer timeout, Integer interval) { for (int i = 0; i < timeout / interval; i++) { script.sh("sleep ${interval}s") - String deploys = kubectl("get deployments --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'", true) - if (!deploys.contains("k8s-ces-setup")) { + String blueprintReady = kubectl("get blueprint -n=default blueprint-ces-module -o jsonpath='{.status.conditions[?(@.type==\"EcosystemHealthy\")].status}{\" \"}{.status.conditions[?(@.type==\"Completed\")].status}'", true) + script.echo blueprintReady + if (blueprintReady == "True True") { return } } - this.script.error "failed to wait for setup to finish: timeout" + this.script.error "failed to wait for ecosystem-core setup to finish: timeout" } /** - * Installs the setup to the cluster. Creates an example setup.json with usermgt as dogu and executes the setup. - * After that the method will wait until the dogu-operator is ready. - * @param tag Tag of the setup e. g. "v0.6.0" - * @param timout Timeout in seconds for the setup process e. g. 300 + * Installs the ecosystem-core-setup to the cluster. Creates an example values.yaml and a blueprint-file with usermgt as dogu and executes the ecosystem-core-setup. + * After that the method will wait until the blueprint is ready. + * @param timout Timeout in seconds for the installation process e. g. 300 * @param interval Interval in seconds for querying the actual state of the setup e. g. 2 */ - void setup(String tag, config = [:], Integer timout = 300, Integer interval = 5) { + void setup(config = [:], Integer timout = 300, Integer interval = 5) { assignExternalIP() - configureSetupJson(config) - installAndTriggerSetup(tag, timout, interval) + configureEcosystemCoreValues(config) + installAndTriggerSetup(timout, interval) } @@ -606,66 +641,94 @@ data: return [registryIp, registryPort] } - static String formatDependencies(List deps) { + String formatDependencies(List deps) { String formatted = "" - for (int i = 0; i < deps.size(); i++) { - formatted += "\"${deps[i]}\"" - + String[] parts = deps[i].split(":") + String version; + // "latest" needs to be replaced with actual last version + if (parts.length != 2 || parts[1] == "latest") { + version = this.getLatestVersion(parts[0]) + } else { + version = parts[1] + } + formatted += " - name: ${parts[0]}\n" + + " version: ${version}" if ((i + 1) < deps.size()) { - formatted += ', ' + formatted += '\n' } } return formatted } - private void writeSetupJson(config) { - List deps = config.dependencies + config.additionalDependencies - String formattedDeps = formatDependencies(deps) + private String getLatestVersion(String doguName) { + String tags = "{}"; + script.withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: this.backendCredentialsID, usernameVariable: 'TOKEN_ID', passwordVariable: 'TOKEN_SECRET']]) { + tags = this.sh.returnStdOut("curl https://registry.cloudogu.com/v2/${doguName}/tags/list -u ${script.env.TOKEN_ID}:${script.env.TOKEN_SECRET}").trim() + } + def obj = new JsonSlurper().parseText(tags) + return obj.tags.max { t -> parseTag("${t}") } + } + + private String parseTag(String tag) { + def m = (tag =~ /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-(\d+))?$/) + if (!m.matches()) { + // Fallback: set all to 0 to ingnore invalid tags + return "00000.00000.00000.00000" + } + def major = (m[0][1] ?: "0") as int + def minor = (m[0][2] ?: "0") as int + def patch = (m[0][3] ?: "0") as int + def build = (m[0][4] ?: "0") as int - script.writeFile file: K3D_SETUP_JSON_FILE, text: """ -{ - "naming":{ - "fqdn":"${externalIP}", - "hostname":"ces", - "domain":"ces.local", - "certificateType":"selfsigned", - "relayHost":"mail.ces.local", - "completed":true - }, - "dogus":{ - "defaultDogu":"${config.defaultDogu}", - "install":[ - ${formattedDeps} - ], - "completed":true - }, - "admin":{ - "username":"${config.adminUsername}", - "mail":"ces-admin@cloudogu.com", - "password":"${config.adminPassword}", - "adminGroup":"${config.adminGroup}", - "adminMember":true, - "completed":true - }, - "userBackend":{ - "port":"389", - "useUserConnectionToFetchAttributes":true, - "dsType":"embedded", - "attributeID":"uid", - "attributeFullname":"cn", - "attributeMail":"mail", - "attributeGroup":"memberOf", - "searchFilter":"(objectClass=person)", - "host":"ldap", - "completed":true - }, - "registryConfig": {${config.registryConfig}}, - "registryConfigEncrypted": {${config.registryConfigEncrypted}} -}""" + // Zero-padding → lexicographically sortable + return sprintf("%05d.%05d.%05d.%05d", major, minor, patch, build) } + private void writeBlueprintYaml(config) { + List deps = config.dependencies + config.additionalDependencies + String formattedDeps = formatDependencies(deps) + script.writeFile file: K3D_BLUEPRINT_FILE, text: """ +apiVersion: k8s.cloudogu.com/v3 +kind: Blueprint +metadata: + labels: + app: ces + app.kubernetes.io/name: k8s-blueprint-lib + name: blueprint-ces-module + namespace: default +spec: + displayName: "Blueprint K3D CES-Module" + blueprint: + dogus: +${formattedDeps} + config: + dogus: + ldap: + - key: admin_username + value: "${config.adminUsername}" + - key: admin_mail + value: "ces-admin@cloudogu.com" + - key: admin_member + value: "true" + - key: admin_password + value: "${config.adminPassword}" + global: + - key: fqdn + value: "${externalIP}" + - key: domain + value: "ces.local" + - key: certificate/type + value: "selfsigned" + - key: k8s/use_internal_ip + value: "false" + - key: internalIp + value: "" + - key: admin_group + value: "${config.adminGroup}" +""" + } /** * Collects all necessary resources and log information used to identify problems with our kubernetes cluster. @@ -677,7 +740,9 @@ data: script.deleteDir() } script.sh("rm -rf ${K3D_LOG_FILENAME}.zip".toString()) - script.sh("rm -rf ${K3D_SETUP_JSON_FILE}".toString()) + script.archiveArtifacts(artifacts: K3D_BLUEPRINT_FILE) + script.sh("rm -rf ${K3D_BLUEPRINT_FILE}".toString()) + script.archiveArtifacts(artifacts: K3D_VALUES_YAML_FILE) script.sh("rm -rf ${K3D_VALUES_YAML_FILE}".toString()) collectResourcesSummaries() diff --git a/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy b/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy index 60a456e..43020f1 100644 --- a/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy +++ b/test/com/cloudogu/ces/cesbuildlib/K3dTest.groovy @@ -1,5 +1,6 @@ package com.cloudogu.ces.cesbuildlib +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito import org.mockito.invocation.InvocationOnMock @@ -15,6 +16,17 @@ import static groovy.test.GroovyAssert.shouldFail class K3dTest { + @BeforeEach + void beforeTest() { + K3d.@VERSION_ECOSYSTEM_CORE = null; + K3d.@VERSION_K8S_COMPONENT_OPERATOR_CRD = null; + // configured by values.yaml + K3d.@VERSION_K8S_DOGU_OPERATOR = null; + K3d.@VERSION_K8S_DOGU_OPERATOR_CRD = null; + K3d.@VERSION_K8S_BLUEPRINT_OPERATOR = null; + K3d.@VERSION_K8S_BLUEPRINT_OPERATOR_CRD = null; + } + @Test void testCreateClusterName() { K3d sut = new K3d("script", "leWorkSpace", "leK3dWorkSpace", "path") @@ -212,51 +224,50 @@ class K3dTest { void testSetup() { // given def workspaceEnvDir = "leK3dWorkSpace" - String tag = "v0.6.0" def scriptMock = new ScriptMock() + scriptMock.expectedShRetValueForScript.put("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip", "192.168.56.2") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/ldap/tags/list -u null:null", "{\"tags\": [\"1.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/cas/tags/list -u null:null", "{\"tags\": [\"2.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/postfix/tags/list -u null:null", "{\"tags\": [\"3.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/usermgt/tags/list -u null:null", "{\"tags\": [\"4.0.0\"]}") + + scriptMock.expectedShRetValueForScript.put("whoami", "jenkins") scriptMock.expectedShRetValueForScript.put("cat /etc/passwd | grep jenkins", "jenkins:x:1000:1000:jenkins,,,:/home/jenkins:/bin/bash") scriptMock.expectedShRetValueForScript.put("yq -i '.setup_json = load_str(\"k3d_setup.json\")' k3d_values.yaml", "foo") - scriptMock.expectedShRetValueForScript.put("curl -s https://raw.githubusercontent.com/cloudogu/k8s-ces-setup/${tag}/k8s/k8s-ces-setup.yaml".toString(), "fake setup yaml with {{ .Namespace }}") scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/k8s-dogu-operator-controller-manager".toString(), "successfully rolled out") - scriptMock.expectedShRetValueForScript.put("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip", "192.168.56.2") + scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/k8s-blueprint-operator-controller-manager".toString(), "successfully rolled out") + scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get blueprint -n=default blueprint-ces-module -o jsonpath='{.status.conditions[?(@.type==\"EcosystemHealthy\")].status}{\" \"}{.status.conditions[?(@.type==\"Completed\")].status}'".toString(), "True True") + + scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get deployments --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'".toString(), "k8s-dogu-operator\nk8s-service-discovery") - scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get dogus --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'".toString(), "cas\nnginx-ingress") + scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get dogus --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'".toString(), "cas\nldap") scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/cas".toString(), "successfully rolled out") - scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/nginx-ingress".toString(), "successfully rolled out") + scriptMock.expectedShRetValueForScript.put("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/ldap".toString(), "successfully rolled out") K3d sut = new K3d(scriptMock, "leWorkSpace", "leK3dWorkSpace", "path") + // need to be installed before apply values.yaml // when - sut.setup(tag, [:], 1, 1) + sut.setup([:], 1, 1) // then - assertThat(scriptMock.actualEcho.get(0)).isEqualTo("configuring setup...") - assertThat(scriptMock.actualEcho.get(1)).isEqualTo("create values.yaml for setup deployment") - assertThat(scriptMock.actualEcho.get(2)).isEqualTo("Installing setup...") - assertThat(scriptMock.actualEcho.get(3)).isEqualTo("Wait for dogu-operator to be ready...") - assertThat(scriptMock.actualEcho.get(4)).isEqualTo("Wait for setup-finisher to be executed...") - assertThat(scriptMock.actualEcho.get(5)).isEqualTo("Wait for dogus to be ready...") - assertThat(scriptMock.actualEcho.get(6)).isEqualTo("Wait for cas to be rolled out...") - assertThat(scriptMock.actualEcho.get(7)).isEqualTo("Wait for nginx-ingress to be rolled out...") - - assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip") - assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[2].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[3].trim()).isEqualTo("yq -i '.setup_json = load_str(\"k3d_setup.json\")' k3d_values.yaml".trim()) - assertThat(scriptMock.allActualArgs[4].trim()).isEqualTo("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config helm registry login registry.cloudogu.com --username 'null' --password 'null'".trim()) - assertThat(scriptMock.allActualArgs[5].trim()).isEqualTo("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config helm install -f k3d_values.yaml k8s-ces-setup oci://registry.cloudogu.com/k8s/k8s-ces-setup --version v0.6.0 --namespace default".trim()) - assertThat(scriptMock.allActualArgs[6].trim()).isEqualTo("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config helm registry logout registry.cloudogu.com".trim()) - assertThat(scriptMock.allActualArgs[7].trim()).isEqualTo("sleep 1s") - assertThat(scriptMock.allActualArgs[8].trim()).isEqualTo("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/k8s-dogu-operator-controller-manager".trim()) - assertThat(scriptMock.allActualArgs[9].trim()).isEqualTo("sleep 1s") - assertThat(scriptMock.allActualArgs[10].trim()).isEqualTo("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get deployments --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'") - assertThat(scriptMock.allActualArgs[11].trim()).isEqualTo("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl get dogus --template '{{range .items}}{{.metadata.name}}{{\"\\n\"}}{{end}}'") - assertThat(scriptMock.allActualArgs[12].trim()).isEqualTo("sleep 1s") - assertThat(scriptMock.allActualArgs[13].trim()).isEqualTo("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/cas") - assertThat(scriptMock.allActualArgs[14].trim()).isEqualTo("sleep 1s") - assertThat(scriptMock.allActualArgs[15].trim()).isEqualTo("sudo KUBECONFIG=${workspaceEnvDir}/.k3d/.kube/config kubectl rollout status deployment/nginx-ingress") + int i = 0 + assertThat(scriptMock.actualEcho.get(i)).isEqualTo("create values.yaml for setup deployment") + for (i = 0; i < 7; i++) { + if (!"create values.yaml for setup deployment".equals(scriptMock.actualEcho.get(i))) { + break + } + } + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("configuring ecosystem core...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Installing setup...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Wait for blueprint-operator to be ready...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Wait for blueprint to be ready...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("True True") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Wait for dogus to be ready...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Wait for cas to be rolled out...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Wait for ldap to be rolled out...") assertThat(scriptMock.writeFileParams.get(0)).isNotNull() String setupYaml = scriptMock.writeFileParams.get(1) @@ -267,26 +278,38 @@ class K3dTest { @Test void testSetupShouldThrowExceptionOnDoguOperatorRollout() { // given - String tag = "v0.6.0" def scriptMock = new ScriptMock() scriptMock.expectedShRetValueForScript.put("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip", "192.168.56.2") scriptMock.expectedShRetValueForScript.put("whoami", "jenkins") scriptMock.expectedShRetValueForScript.put("cat /etc/passwd | grep jenkins", "jenkins:x:1000:1000:jenkins,,,:/home/jenkins:/bin/bash") scriptMock.expectedShRetValueForScript.put("yq -i '.setup_json = load_str(\"k3d_setup.json\")' k3d_values.yaml", "fake") + scriptMock.expectedShRetValueForScript.put("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip", "192.168.56.2") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/ldap/tags/list -u null:null", "{\"tags\": [\"1.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/cas/tags/list -u null:null", "{\"tags\": [\"2.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/postfix/tags/list -u null:null", "{\"tags\": [\"3.0.0\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/usermgt/tags/list -u null:null", "{\"tags\": [\"4.0.0\"]}") K3d sut = new K3d(scriptMock, "leWorkSpace", "leK3dWorkSpace", "path") // when def errorMsg = shouldFail(RuntimeException) { - sut.setup(tag, [:], 1, 1) + sut.setup([:], 1, 1) } // then - assertThat(errorMsg.getMessage()).isEqualTo("failed to wait for deployment/k8s-dogu-operator-controller-manager rollout: timeout") + assertThat(errorMsg.getMessage()).isEqualTo("failed to wait for deployment/k8s-blueprint-operator-controller-manager rollout: timeout") + + int i = 0 + assertThat(scriptMock.actualEcho.get(i)).isEqualTo("create values.yaml for setup deployment") + for (i = 0; i < 7; i++) { + if (!"create values.yaml for setup deployment".equals(scriptMock.actualEcho.get(i))) { + break + } + } - assertThat(scriptMock.actualEcho.get(0)).isEqualTo("configuring setup...") - assertThat(scriptMock.actualEcho.get(1)).isEqualTo("create values.yaml for setup deployment") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("configuring ecosystem core...") + assertThat(scriptMock.actualEcho.get(i++)).isEqualTo("Installing setup...") assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("curl -H \"Metadata-Flavor: Google\" http://169.254.169.254/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip") assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("whoami".trim()) @@ -433,7 +456,7 @@ spec: int fileCounter = 0 assertThat(scriptMock.allActualArgs[i++].trim()).contains("called deleteDir()") assertThat(scriptMock.allActualArgs[i++].trim()).contains("rm -rf k8sLogs.zip") - assertThat(scriptMock.allActualArgs[i++].trim()).contains("rm -rf k3d_setup.json") + assertThat(scriptMock.allActualArgs[i++].trim()).contains("rm -rf k3d_blueprint.yaml") assertThat(scriptMock.allActualArgs[i++].trim()).contains("rm -rf k3d_values.yaml") assertThat(scriptMock.allActualArgs[i++].trim()).contains("sudo KUBECONFIG=leK3dWorkSpace/.k3d/.kube/config kubectl get persistentvolumeclaim --show-kind --ignore-not-found -l app=ces -o yaml || true") @@ -514,8 +537,10 @@ spec: assertThat(scriptMock.zipParams.size()).isEqualTo(1) assertThat(scriptMock.zipParams[0]).isEqualTo(["archive":"false", "dir":"k8sLogs", "zipFile":"k8sLogs.zip"]) - assertThat(scriptMock.archivedArtifacts.size()).isEqualTo(1) - assertThat(scriptMock.archivedArtifacts[0]).isEqualTo(["allowEmptyArchive":"true", "artifacts":"k8sLogs.zip"]) + assertThat(scriptMock.archivedArtifacts.size()).isEqualTo(3) + assertThat(scriptMock.archivedArtifacts[0]).isEqualTo(["artifacts":"k3d_blueprint.yaml"]) + assertThat(scriptMock.archivedArtifacts[1]).isEqualTo(["artifacts":"k3d_values.yaml"]) + assertThat(scriptMock.archivedArtifacts[2]).isEqualTo(["allowEmptyArchive":"true", "artifacts":"k8sLogs.zip"]) assertThat(scriptMock.allActualArgs.size()).isEqualTo(i) assertThat(scriptMock.writeFileParams.size()).isEqualTo(25) @@ -555,78 +580,48 @@ spec: } @Test - void testK3d_configureSetupImage() { + void testK3d_parseTags() { // given def workspaceDir = "leWorkspace" def k3dWorkspaceDir = "leK3dWorkSpace" def scriptMock = new ScriptMock() K3d sut = new K3d(scriptMock, workspaceDir, k3dWorkspaceDir, "path") - scriptMock.expectedShRetValueForScript.put("whoami".toString(), "jenkins") - scriptMock.expectedShRetValueForScript.put("cat /etc/passwd | grep jenkins", "jenkins:x:1000:1000:jenkins,,,:/home/jenkins:/bin/bash") - scriptMock.expectedShRetValueForScript.put("yq -i \".setup.image.registry = \\\"docker.io\\\"\" k3d_values.yaml", "foo") - scriptMock.expectedShRetValueForScript.put("yq -i \".setup.image.repository = \\\"foo/image\\\"\" k3d_values.yaml", "foo") - scriptMock.expectedShRetValueForScript.put("yq -i \".setup.image.tag = \\\"1.2.3\\\"\" k3d_values.yaml", "foo") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/ldap/tags/list -u null:null", "{\"tags\": [\"1.0.0\", \"1.0.1\"]}") + scriptMock.expectedShRetValueForScript.put("curl https://registry.cloudogu.com/v2/official/cas/tags/list -u null:null", "{\"tags\": [\"2.0.0\", \"invalid\", \"2.0.1\"]}") - // when - sut.configureSetupImage("docker.io/foo/image:1.2.3") - - // then - assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[2].trim()).isEqualTo("yq -i \".setup.image.registry = \\\"docker.io\\\"\" k3d_values.yaml".trim()) - assertThat(scriptMock.allActualArgs[3].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[4].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[5].trim()).isEqualTo("yq -i \".setup.image.repository = \\\"foo/image\\\"\" k3d_values.yaml".trim()) - assertThat(scriptMock.allActualArgs[6].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[7].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[8].trim()).isEqualTo("yq -i \".setup.image.tag = \\\"1.2.3\\\"\" k3d_values.yaml".trim()) - } - - @Test - void testK3d_configureComponentOperatorVersion() { - // given - def workspaceDir = "leWorkspace" - def k3dWorkspaceDir = "leK3dWorkSpace" - def scriptMock = new ScriptMock() - K3d sut = new K3d(scriptMock, workspaceDir, k3dWorkspaceDir, "path") - - scriptMock.expectedShRetValueForScript.put("whoami".toString(), "jenkins") - scriptMock.expectedShRetValueForScript.put("cat /etc/passwd | grep jenkins", "jenkins:x:1000:1000:jenkins,,,:/home/jenkins:/bin/bash") - scriptMock.expectedShRetValueForScript.put("yq -i \".component_operator_chart = \\\"test_ns/k8s-component-operator:1.2.3\\\"\" k3d_values.yaml", "foo") - scriptMock.expectedShRetValueForScript.put("yq -i \".component_operator_crd_chart = \\\"test_ns/k8s-component-operator-crd:4.5.6\\\"\" k3d_values.yaml", "foo") + List deps = new ArrayList<>() + deps.add("official/cas") + deps.add("official/ldap:latest") + deps.add("official/usermgt:3.0.0") // when - sut.configureComponentOperatorVersion('1.2.3', '4.5.6', 'test_ns') + String formatted = sut.formatDependencies(deps) // then - assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[2].trim()).isEqualTo("yq -i \".component_operator_chart = \\\"test_ns/k8s-component-operator:1.2.3\\\"\" k3d_values.yaml".trim()) - assertThat(scriptMock.allActualArgs[3].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[4].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[5].trim()).isEqualTo("yq -i \".component_operator_crd_chart = \\\"test_ns/k8s-component-operator-crd:4.5.6\\\"\" k3d_values.yaml".trim()) + assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("curl https://registry.cloudogu.com/v2/official/cas/tags/list -u null:null".trim()) + assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("curl https://registry.cloudogu.com/v2/official/ldap/tags/list -u null:null".trim()) + assertThat(formatted.contains("cas\n version: 2.0.1")) + assertThat(formatted.contains("ldap\n version: 1.0.1")) + assertThat(formatted.contains("usermgt\n version: 3.0.0")) + } @Test - void testK3d_configureLogLevel() { + void testK3d_setComponentVersion() { // given - def workspaceDir = "leWorkspace" - def k3dWorkspaceDir = "leK3dWorkSpace" - def scriptMock = new ScriptMock() - K3d sut = new K3d(scriptMock, workspaceDir, k3dWorkspaceDir, "path") - - scriptMock.expectedShRetValueForScript.put("whoami".toString(), "jenkins") - scriptMock.expectedShRetValueForScript.put("cat /etc/passwd | grep jenkins", "jenkins:x:1000:1000:jenkins,,,:/home/jenkins:/bin/bash") - scriptMock.expectedShRetValueForScript.put("yq -i \".logLevel = \\\"SUPER_ERROR\\\"\" k3d_values.yaml", "foo") // when - sut.configureLogLevel("SUPER_ERROR") + K3d.setVersionDoguOperator("1.0.0") + K3d.setVersionDoguOperatorCrd("2.0.0") + K3d.setVersionBlueprintOperator("3.0.0") + K3d.setVersionBlueprintOperatorCrd("4.0.0") // then - assertThat(scriptMock.allActualArgs[0].trim()).isEqualTo("whoami".trim()) - assertThat(scriptMock.allActualArgs[1].trim()).isEqualTo("cat /etc/passwd | grep jenkins".trim()) - assertThat(scriptMock.allActualArgs[2].trim()).isEqualTo("yq -i \".logLevel = \\\"SUPER_ERROR\\\"\" k3d_values.yaml".trim()) + assertThat("1.0.0".equals(K3d.@VERSION_K8S_DOGU_OPERATOR)) + assertThat("2.0.0".equals(K3d.@VERSION_K8S_DOGU_OPERATOR_CRD)) + assertThat("3.0.0".equals(K3d.@VERSION_K8S_BLUEPRINT_OPERATOR)) + assertThat("4.0.0".equals(K3d.@VERSION_K8S_BLUEPRINT_OPERATOR_CRD)) } @Test