From b04198f15f9d9ba3c3148b45ee7fdf1d4922ce6a Mon Sep 17 00:00:00 2001 From: aleskandro Date: Wed, 26 Jun 2024 11:56:01 +0100 Subject: [PATCH 1/3] Native multi-arch ClusterBuildStrategy This commits adds a sample multi-arch native ClusterBuildStrategy. The ClusterBuildStrategy runs as a main orchestrator pod. It creates one slave job for each architecture requested by the Build. The slave jobs are responsible for building the container image and coordinate with the orchestrator pod via messages in FIFO pipes sent through the kubectl client. The slave jobs run through the following coordination barriers: 1. Wait for the assets to be uploaded (source code, pull secrets, etc...) 2. Waiting for the image download to start 3. Waiting for the image download to finish The orchestrator pod: 1. Create the slave jobs 2. Upload the assets and signal the completion of the assets upload through a write to the FIFO pipe in each slave job 3. Start the download of the oci archive 4. Inform the slave jobs the download is completed 5. Creates a manifest-list and push it to the final registry. The service account that runs the strategy must be able to list, get and watch jobs and pods. It also needs to be allowed the create verb for the pods/exec resource, and create for the jobs one. In OKD/Openshift, the service account must also be able to create pods requiring the privileged SecurityContextConstraints. --- ...dstrategy_multiarch_native_buildah_cr.yaml | 545 ++++++++++++++++++ .../role_multiarch_native_buildah_cr.yaml | 28 + ...lebinding_multiarch_native_buildah_cr.yaml | 11 + ...g_multiarch_native_buildah_scc_okd_cr.yaml | 14 + .../build_multiarch_native_buildah_cr.yaml | 29 + 5 files changed, 627 insertions(+) create mode 100644 samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml create mode 100644 samples/v1beta1/buildstrategy/multiarch-native-buildah/role_multiarch_native_buildah_cr.yaml create mode 100644 samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_cr.yaml create mode 100644 samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_scc_okd_cr.yaml create mode 100644 test/data/v1beta1/build_multiarch_native_buildah_cr.yaml diff --git a/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml b/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml new file mode 100644 index 0000000000..dd80c0c329 --- /dev/null +++ b/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml @@ -0,0 +1,545 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: multiarch-native-buildah +spec: + volumes: + - name: oci-archive-storage + emptyDir: {} + overridable: true + - name: additional-bins + emptyDir: {} + steps: + - name: prepare-build + image: quay.io/centos/centos:stream9 + workingDir: $(params.shp-source-root) + volumeMounts: + - mountPath: /usr/local/bin + name: additional-bins + resources: + requests: + cpu: 100m + memory: 16Mi + limits: + memory: 256Mi + command: + - /bin/bash + args: + - -c + - | + #!/bin/bash + set -Eueo pipefail + trap 'CHILDREN=$(jobs -p); if test -n "${CHILDREN}"; then kill ${CHILDREN} && wait; fi' TERM ERR + + # Parse parameters + context="" dockerfile="" runtime_stage_from_image="" image="" status="" + registriesBlock="" registriesInsecure="" registriesSearch="" + request_cpu="" request_memory="" limit_cpu="" limit_memory="" + declare -a architectures buildArgs + + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [ "${arg}" == "--context" ]; then + status= + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + status= + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + status= + image="$1" + shift + elif [ "${arg}" == "--request-cpu" ]; then + status= + [ "${#1}" -gt 0 ] && request_cpu="${1}" + shift + elif [ "${arg}" == "--request-memory" ]; then + status= + [ "${#1}" -gt 0 ] && request_memory="${1}" + shift + elif [ "${arg}" == "--limit-cpu" ]; then + status= + [ "${#1}" -gt 0 ] && limit_cpu="${1}" + shift + elif [ "${arg}" == "--limit-memory" ]; then + status= + [ "${#1}" -gt 0 ] && limit_memory="${1}" + shift + elif [ "${arg}" == "--from" ]; then + status= + [ "${#1}" -gt 0 ] && buildArgs+=("--from" "$1") + shift + elif [ "${arg}" == "--runtime-stage-from" ]; then + status= + runtime_stage_from_image="$1" + shift + elif [ "${arg}" == "--architectures" ]; then + status="parse_architectures" + elif [ "${arg}" == "--build-args" ]; then + status="parse_build_args" + elif [ "${arg}" == "--build-contexts" ]; then + status="parse_build_contexts" + elif [ "${arg}" == "--registries-block" ]; then + status="parse_registries_block" + elif [ "${arg}" == "--registries-insecure" ]; then + status="parse_registries_insecure" + elif [ "${arg}" == "--registries-search" ]; then + status="parse_registries_search" + elif [[ "${arg}" == --* ]]; then + echo "[ERROR] Invalid usage" + exit 1 + elif [ "${status}" == "parse_architectures" ]; then + architectures+=("${arg}") + elif [ "${status}" == "parse_build_args" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${status}" == "parse_build_contexts" ]; then + buildArgs+=("--build-context" "${arg}") + elif [ "${status}" == "parse_registries_block" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${status}" == "parse_registries_insecure" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${status}" == "parse_registries_search" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "[ERROR] Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "[ERROR] The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "[ERROR] The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + echo "[INFO] Creating registries config file..." + touch /tmp/registries.conf + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + EOF + fi + + if [ "${#runtime_stage_from_image}" -gt 0 ]; then + echo "[INFO] Replacing the runtime stage image to extend from" + buildArgs+=("--build-context" "$(tac "${dockerfile}" | grep -m1 -i -E '^[ ]*FROM' | \ + sed -n '0,/p/s/^[ ]*from[ ]\+\([^ ]*\)[ ]*\(as.*$\)\{0,1\}$/\1/Ip')=${runtime_stage_from_image}") + fi + # TODO: what image including kubectl can we use? + echo "[INFO] Downloading kubectl..." + kube_version=$(curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ + "https:${KUBERNETES_PORT#tcp:}/version" | sed -n 's/^.*gitVersion.*"v\(.*\)\+".*$/\1/p' | cut -f1 -d'+') + arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + curl -L -o /usr/local/bin/kubectl \ + "https://storage.googleapis.com/kubernetes-release/release/v${kube_version}/bin/linux/${arch}/kubectl" + chmod +x /usr/local/bin/kubectl + task_run_pod=${HOSTNAME} + task_run_name=${task_run_pod%-pod} + name=${task_run_name}-job + namespace=$(/dev/null || ret=$? + if printf '%s\0' "${failure_pids[@]}" | grep -Fxqz -- "${finished_job}"; then + echo "[ERROR] A failure condition has been met while waiting for the jobs to initialize" + exit 1 + elif printf '%s\0' "${success_pids[@]}" | grep -Fxqz -- "${finished_job}"; then + # shellcheck disable=SC2206 + # It's safe to ignore the double quotes here, as the array keeps the ids of the jobs and ignoring them + # allows us to ignore the empty array + success_pids=( ${success_pids[@]/${finished_job}} ) + fi + [ ${#success_pids[@]} -eq 0 ] && break + done + echo "[INFO] All the jobs' pods started" + echo "[INFO] Uploading the assets to the build pods" + + function upload_assets { + pod_name=$(kubectl get pod -l "job-name=$1" -o jsonpath='{.items[0].metadata.name}') + tar czpf - . | kubectl exec -i "$pod_name" -- tar xzpf - -C /var/workdir/context/ + kubectl cp /tmp/registries.conf "$pod_name":/var/workdir/registries.conf + kubectl exec "$pod_name" -- bash -c "echo -n > /tmp/pipe" + } + + success_pids=() + + for arch in "${architectures[@]}"; do + upload_assets "${name}-${arch}" & + success_pids+=($!) + done + ret=0 + while [ ${ret} -eq 0 ]; do + wait -n "${success_pids[@]}" 2>/dev/null || ret=$? + if [ ${ret} -ne 0 ] && [ "${ret}" -ne 127 ]; then + echo "[ERROR] An error occurred while uploading the assets" + exit 1 + fi + done + echo "[INFO] All the assets have been uploaded. Continuing." + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(params.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --architectures + - $(params.architectures[*]) + - --from + - $(params.from) + - --runtime-stage-from + - $(params.runtime-stage-from) + - --build-contexts + - $(params.build-contexts[*]) + - --request-cpu + - '$(params.request-cpu)' + - --request-memory + - '$(params.request-memory)' + - --limit-cpu + - '$(params.limit-cpu)' + - --limit-memory + - '$(params.limit-memory)' + - name: wait-manifests-complete + image: quay.io/centos/centos:stream9 + workingDir: /tmp + volumeMounts: + - mountPath: /var/oci-archive-storage + name: oci-archive-storage + - mountPath: /usr/local/bin + name: additional-bins + resources: + requests: + cpu: 50m + memory: 16Mi + limits: + memory: 256Mi + command: + - bash + args: + - -c + - | + #!/bin/bash + set -Eueo pipefail + trap 'CHILDREN=$(jobs -p); if test -n "${CHILDREN}"; then kill ${CHILDREN} && wait; fi' TERM ERR + + declare -a architectures + inArchitectures=false + + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [ "${arg}" == "--architectures" ]; then + inArchitectures=true + elif [[ "${arg}" =~ --* ]]; then + inArchitectures=false + break + elif [ "${inArchitectures}" == "true" ]; then + architectures+=("${arg}") + fi + done + task_run_pod=${HOSTNAME} + name=${task_run_pod%-pod}-job + declare -a success_pids failure_pids + finished_job="" + + function download_images { + pod_name=$(kubectl get pod -l "job-name=${1}-${2}" -o jsonpath='{.items[0].metadata.name}') + # Trigger the image download start event + kubectl exec -c build "${pod_name}" -- bash -c 'echo "done" > /tmp/pipe' + # Download the image + kubectl cp "${pod_name}:/tmp/image-${2}.tar.gz" "/var/oci-archive-storage/image-${2}.tar.gz" + # Trigger the image download complete event + kubectl exec -c build "${pod_name}" -- bash -c 'echo "done" > /tmp/pipe' + } + + for arch in "${architectures[@]}"; do + echo "[INFO] Waiting for the ${arch} build job to complete" + kubectl wait job/"${name}-${arch}" --timeout=-1s --for=condition=Complete & + success_pids+=($!) + kubectl wait job/"${name}-${arch}" --timeout=-1s --for=condition=Failed & + failure_pids+=($!) + download_images "${name}" "${arch}" & + success_pids+=($!) + kubectl wait job/"${name}-${arch}" --timeout=5m --for=jsonpath='{.status.active}'=1 && \ + kubectl wait pod --timeout=10m -l "job-name=${name}-${arch}" --for=condition=ContainersReady && \ + kubectl logs -c build -l "job-name=${name}-${arch}" -f --tail=-1 |& sed -u "s/^/[${arch}] /" || true & + done + + ret=0 + while [ ${ret} -eq 0 ]; do + wait -p finished_job -n "${failure_pids[@]}" "${success_pids[@]}" 2>/dev/null || true + ret=$? + if printf '%s\0' "${failure_pids[@]}" | grep -Fxqz -- "${finished_job}"; then + echo "[ERROR] A failure condition has been met while waiting for the builds jobs to complete" + exit 1 + elif printf '%s\0' "${success_pids[@]}" | grep -Fxqz -- "${finished_job}"; then + success_pids=( ${success_pids[@]/${finished_job}} ) + fi + [ ${#success_pids[@]} -eq 0 ] && break + done + echo "[INFO] All the jobs completed successfully" + ls -lh /var/oci-archive-storage/ + - -- + - --architectures + - $(params.architectures[*]) + - name: package-manifest-list-and-push + image: quay.io/containers/buildah:v1.28.0 + securityContext: + privileged: true + workingDir: /var/oci-archive-storage + resources: + requests: + cpu: 50m + memory: 16Mi + limits: + memory: 256Mi + volumeMounts: + - mountPath: /var/oci-archive-storage + name: oci-archive-storage + command: + - bash + args: + - -c + - | + #!/bin/bash + set -Eueo pipefail + ls -lh + + image="" registriesInsecure="" status="" tlsVerify=true + + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [ "${arg}" == "--image" ]; then + image="$1" + status= + shift + elif [ "${arg}" == "--registries-insecure" ]; then + status="parse_registries_insecure" + elif [[ "${arg}" == --* ]]; then + echo "[ERROR] Invalid usage" + exit 1 + elif [ "${status}" == "parse_registries_insecure" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + else + echo "[ERROR] Invalid usage" + exit 1 + fi + done + + image_name_tag="$(basename ${image})" + echo "[INFO] Creating manifest list" + buildah manifest create "${image_name_tag}" + + for f in image-*.tar.gz; do + echo "[INFO] Adding the $(echo ${f%.tar.gz} | sed 's/^.*-//') manifest to the manifest list" + [[ -e "$f" ]] || { echo "[ERROR] no oci-archive available for the manifest"; exit 1; } # handle case of no files available + buildah manifest add "${image_name_tag}" "oci-archive:$f" + done + + echo "[INFO] Pushing the manifest list ${image_name_tag} to the registry as ${image}" + buildah manifest push --all --digestfile '$(results.shp-image-digest.path)' \ + --tls-verify=${tlsVerify} "${image_name_tag}" "docker://${image}" + echo "[INFO] Manifest list pushed successfully. BuildRun succeeded." + + - -- + - --image + - $(params.shp-output-image) + - --registries-insecure + - $(params.registries-insecure[*]) + parameters: + - name: architectures + description: The list of architectures to build the image for + type: array + defaults: + - amd64 + - name: build-args + description: The values for the args in the Dockerfile. Values must be in the format KEY=VALUE. + type: array + defaults: [ ] + - name: dockerfile + description: The path to the Dockerfile to be used for building the image. + type: string + default: "Dockerfile" + - name: from + type: string + description: Image name used to replace the value in the first FROM instruction in the Dockerfile + default: "" + - name: runtime-stage-from + description: Image name used to replace the value in the last FROM instruction in the Dockerfile + type: string + default: "" + - name: build-contexts + description: >- + Specify an additional build context using its short name and its location. + Additional build contexts can be referenced in the same manner as we access + different stages in COPY instruction. Use values in the form "name=value". + See man buildah-build. + type: array + defaults: [ ] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [ ] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [ ] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: request-cpu + description: The amount of CPU requested for the build pod. + type: string + default: 250m + - name: request-memory + description: The amount of memory requested for the build pod. + type: string + default: 64Mi + - name: limit-cpu + description: The amount of CPU limit for the build pod. + type: string + default: "" + - name: limit-memory + description: The amount of memory limit for the build pod. + type: string + default: 2Gi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1beta1/buildstrategy/multiarch-native-buildah/role_multiarch_native_buildah_cr.yaml b/samples/v1beta1/buildstrategy/multiarch-native-buildah/role_multiarch_native_buildah_cr.yaml new file mode 100644 index 0000000000..ddca2d70e8 --- /dev/null +++ b/samples/v1beta1/buildstrategy/multiarch-native-buildah/role_multiarch_native_buildah_cr.yaml @@ -0,0 +1,28 @@ +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multiarch-native-buildah-pipeline +rules: + - verbs: + - get + - list + - watch + resources: + - pods + apiGroups: + - "" + - verbs: + - create + resources: + - pods/exec + apiGroups: + - "" + - verbs: + - get + - list + - create + - watch + resources: + - jobs + apiGroups: + - batch diff --git a/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_cr.yaml b/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_cr.yaml new file mode 100644 index 0000000000..5d0f47c8e0 --- /dev/null +++ b/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_cr.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiarch-native-buildah-pipeline +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: multiarch-native-buildah-pipeline +subjects: + - kind: ServiceAccount + name: pipeline diff --git a/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_scc_okd_cr.yaml b/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_scc_okd_cr.yaml new file mode 100644 index 0000000000..df65624457 --- /dev/null +++ b/samples/v1beta1/buildstrategy/multiarch-native-buildah/rolebinding_multiarch_native_buildah_scc_okd_cr.yaml @@ -0,0 +1,14 @@ +# NOTE: This is needed secifically in OKD/OpenShift environments. +# The pipeline service account should be allowed running pods that require +# the privileged SecurityContextConstraint. +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multiarch-native-buildah-pipeline-scc-privileged +subjects: + - kind: ServiceAccount + name: pipeline +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: 'system:openshift:scc:privileged' diff --git a/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml b/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml new file mode 100644 index 0000000000..dfcc2fd30b --- /dev/null +++ b/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: multiarch-native-buildah-ex +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: multiarch-native-buildah + kind: ClusterBuildStrategy + paramValues: + - name: architectures + values: + # Setting only to amd64 for the tests to run on amd64 only clusters + - value: "amd64" + - name: build-contexts + values: + - value: "ghcr.io/shipwright-io/shipwright-samples/golang:1.18=docker://ghcr.io/shipwright-io/shipwright-samples/golang:1.18" + # The buildah `--from` replaces the first FROM statement + - name: from + value: "" # Using the build-contexts for this example + # The runtime-stage-from implements the logic to replace the last stage FROM image of a Dockerfile + - name: runtime-stage-from + value: docker://gcr.io/distroless/static:nonroot + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app From 475255a089374a8cb06eb6e25edd75c11c7d038d Mon Sep 17 00:00:00 2001 From: aleskandro Date: Mon, 8 Jul 2024 13:04:07 +0100 Subject: [PATCH 2/3] [Test] Native multi-arch ClusterBuildStrategy --- .../build_multiarch_native_buildah_cr.yaml | 9 ++++++--- .../buildrun_multiarch_native_buildah_cr.yaml | 8 ++++++++ test/e2e/v1beta1/e2e_test.go | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 test/data/v1beta1/buildrun_multiarch_native_buildah_cr.yaml diff --git a/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml b/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml index dfcc2fd30b..b5f4c7f9cd 100644 --- a/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml +++ b/test/data/v1beta1/build_multiarch_native_buildah_cr.yaml @@ -1,11 +1,13 @@ --- -apiVersion: shipwright.io/v1alpha1 +apiVersion: shipwright.io/v1beta1 kind: Build metadata: name: multiarch-native-buildah-ex spec: source: - url: https://github.com/shipwright-io/sample-go + type: Git + git: + url: https://github.com/shipwright-io/sample-go contextDir: docker-build strategy: name: multiarch-native-buildah @@ -24,6 +26,7 @@ spec: # The runtime-stage-from implements the logic to replace the last stage FROM image of a Dockerfile - name: runtime-stage-from value: docker://gcr.io/distroless/static:nonroot - dockerfile: Dockerfile + - name: dockerfile + value: Dockerfile output: image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/buildrun_multiarch_native_buildah_cr.yaml b/test/data/v1beta1/buildrun_multiarch_native_buildah_cr.yaml new file mode 100644 index 0000000000..be8229b98f --- /dev/null +++ b/test/data/v1beta1/buildrun_multiarch_native_buildah_cr.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: multiarch-native-buildah-ex +spec: + build: + name: multiarch-native-buildah-ex diff --git a/test/e2e/v1beta1/e2e_test.go b/test/e2e/v1beta1/e2e_test.go index 0db427e35d..573eca1494 100644 --- a/test/e2e/v1beta1/e2e_test.go +++ b/test/e2e/v1beta1/e2e_test.go @@ -475,6 +475,25 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) }) + Context("when a Multiarch Native Buildah build is defined", func() { + + BeforeEach(func() { + testID = generateTestID("buildah-multi-arch-native") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_multiarch_native_buildah_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_multiarch_native_buildah_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + }) + }) Context("when a s2i build is defined", func() { BeforeEach(func() { From be5660b442ee142b6701ee46b9271e301cdaf9fa Mon Sep 17 00:00:00 2001 From: aleskandro Date: Tue, 23 Jul 2024 18:03:26 -0400 Subject: [PATCH 3/3] Fix Makefile install-strategies target for non-cluster-scoped objects and E2E cases When objects are not cluster-scoped, like rolebindings or local build strategies, if the TEST_NAMESPACE variable is set, the objects should be applied to that given namespace. If not, apply to the current context's namespace. Some test cases were also implementing with an additional creation step for the same buildstrategies defined in the same folder recursively applied by the install-strategies target. This commit deletes those function calls to rely on the Makefile target for creating the non-cluster-scoped build strategies too. --- Makefile | 3 ++- test/e2e/v1alpha1/e2e_test.go | 16 ---------------- test/e2e/v1alpha1/validators_test.go | 13 ------------- test/e2e/v1beta1/e2e_test.go | 17 ----------------- test/e2e/v1beta1/validators_test.go | 13 ------------- 5 files changed, 2 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index 794ea8cdc1..f45876f24d 100644 --- a/Makefile +++ b/Makefile @@ -274,7 +274,8 @@ install-controller-kind: install-apis .PHONY: install-strategies install-strategies: install-apis - kubectl apply -R -f samples/v1beta1/buildstrategy/ + [ -n "${TEST_NAMESPACE}" ] && ADDITIONAL_PARAMS="-n ${TEST_NAMESPACE}"; \ + kubectl apply $$ADDITIONAL_PARAMS -R -f samples/v1beta1/buildstrategy/ .PHONY: local local: install-strategies diff --git a/test/e2e/v1alpha1/e2e_test.go b/test/e2e/v1alpha1/e2e_test.go index f1d165384a..2b325ac075 100644 --- a/test/e2e/v1alpha1/e2e_test.go +++ b/test/e2e/v1alpha1/e2e_test.go @@ -140,17 +140,10 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) Context("when a heroku Buildpacks build is defined using a namespaced strategy", func() { - var buildStrategy *buildv1alpha1.BuildStrategy BeforeEach(func() { testID = generateTestID("buildpacks-v3-heroku-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml") - Expect(err).ToNot(HaveOccurred()) - - err = testBuild.CreateBuildStrategy(buildStrategy) - Expect(err).ToNot(HaveOccurred()) - // create the build definition build = createBuild( testBuild, @@ -169,7 +162,6 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) AfterEach(func() { - err = testBuild.DeleteBuildStrategy(buildStrategy.Name) Expect(err).ToNot(HaveOccurred()) }) }) @@ -198,17 +190,10 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) Context("when a Buildpacks v3 build is defined using a namespaced strategy", func() { - var buildStrategy *buildv1alpha1.BuildStrategy BeforeEach(func() { testID = generateTestID("buildpacks-v3-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml") - Expect(err).ToNot(HaveOccurred()) - - err = testBuild.CreateBuildStrategy(buildStrategy) - Expect(err).ToNot(HaveOccurred()) - // create the build definition build = createBuild( testBuild, @@ -226,7 +211,6 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) AfterEach(func() { - err = testBuild.DeleteBuildStrategy(buildStrategy.Name) Expect(err).ToNot(HaveOccurred()) }) }) diff --git a/test/e2e/v1alpha1/validators_test.go b/test/e2e/v1alpha1/validators_test.go index 4ec185782b..db433ddb14 100644 --- a/test/e2e/v1alpha1/validators_test.go +++ b/test/e2e/v1alpha1/validators_test.go @@ -292,19 +292,6 @@ func readAndDecode(filePath string) (runtime.Object, error) { return obj, err } -// buildStrategyTestData gets the us the BuildStrategy test data set up -func buildStrategyTestData(ns string, buildStrategyCRPath string) (*buildv1alpha1.BuildStrategy, error) { - obj, err := readAndDecode(buildStrategyCRPath) - if err != nil { - return nil, err - } - - buildStrategy := obj.(*buildv1alpha1.BuildStrategy) - buildStrategy.SetNamespace(ns) - - return buildStrategy, err -} - func buildTestData(namespace string, identifier string, filePath string) (*buildv1alpha1.Build, error) { obj, err := readAndDecode(filePath) if err != nil { diff --git a/test/e2e/v1beta1/e2e_test.go b/test/e2e/v1beta1/e2e_test.go index 573eca1494..490df8c961 100644 --- a/test/e2e/v1beta1/e2e_test.go +++ b/test/e2e/v1beta1/e2e_test.go @@ -139,17 +139,9 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) Context("when a heroku Buildpacks build is defined using a namespaced strategy", func() { - var buildStrategy *buildv1beta1.BuildStrategy - BeforeEach(func() { testID = generateTestID("buildpacks-v3-heroku-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml") - Expect(err).ToNot(HaveOccurred()) - - err = testBuild.CreateBuildStrategy(buildStrategy) - Expect(err).ToNot(HaveOccurred()) - // create the build definition build = createBuild( testBuild, @@ -168,7 +160,6 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) AfterEach(func() { - err = testBuild.DeleteBuildStrategy(buildStrategy.Name) Expect(err).ToNot(HaveOccurred()) }) }) @@ -197,17 +188,10 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) Context("when a Buildpacks v3 build is defined using a namespaced strategy", func() { - var buildStrategy *buildv1beta1.BuildStrategy BeforeEach(func() { testID = generateTestID("buildpacks-v3-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml") - Expect(err).ToNot(HaveOccurred()) - - err = testBuild.CreateBuildStrategy(buildStrategy) - Expect(err).ToNot(HaveOccurred()) - // create the build definition build = createBuild( testBuild, @@ -225,7 +209,6 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun }) AfterEach(func() { - err = testBuild.DeleteBuildStrategy(buildStrategy.Name) Expect(err).ToNot(HaveOccurred()) }) }) diff --git a/test/e2e/v1beta1/validators_test.go b/test/e2e/v1beta1/validators_test.go index 3e1c17c737..c80f27a324 100644 --- a/test/e2e/v1beta1/validators_test.go +++ b/test/e2e/v1beta1/validators_test.go @@ -294,19 +294,6 @@ func readAndDecode(filePath string) (runtime.Object, error) { return obj, err } -// buildStrategyTestData gets the us the BuildStrategy test data set up -func buildStrategyTestData(ns string, buildStrategyCRPath string) (*buildv1beta1.BuildStrategy, error) { - obj, err := readAndDecode(buildStrategyCRPath) - if err != nil { - return nil, err - } - - buildStrategy := obj.(*buildv1beta1.BuildStrategy) - buildStrategy.SetNamespace(ns) - - return buildStrategy, err -} - func buildTestData(namespace string, identifier string, filePath string) (*buildv1beta1.Build, error) { obj, err := readAndDecode(filePath) if err != nil {