From 51d3a0a033999e1ac79e25215e833d6e6c6d6e3b Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Wed, 2 Sep 2026 16:17:56 +0530 Subject: [PATCH] Fix env.FAILURE NPE and buildx read-only-mount failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build #5 got through checkout, loadConfig, and the pre_build hook, then hit two real bugs at the actual docker build step: 1. `docker build` failed with "mkdir /root/.docker/buildx: read-only file system" — dind-pod.yaml mounts the Harbor push-auth secret read-only at /root/.docker, but modern docker defaults to BuildKit/buildx, which wants to write its own state there. Forces the classic builder via DOCKER_BUILDKIT=0 instead. 2. The subsequent error-handling itself then threw a NullPointerException — every stage file (including untouched legacy ones from the real devops-lib) reads env.FAILURE when setting currentBuild.result, but nothing in this repo ever defined it, so it was null. Defined once in homelabPipeline.groovy rather than touching 40+ individual occurrences across every stage file. --- resources/org/homelab/dind-pod.yaml | 10 ++++++++++ vars/homelabPipeline.groovy | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/resources/org/homelab/dind-pod.yaml b/resources/org/homelab/dind-pod.yaml index bc7deca..0704cad 100644 --- a/resources/org/homelab/dind-pod.yaml +++ b/resources/org/homelab/dind-pod.yaml @@ -28,6 +28,16 @@ spec: env: - name: DOCKER_HOST value: tcp://localhost:2375 + # docker-config below mounts the Harbor push-auth secret + # read-only at /root/.docker (needed so `docker push` finds + # config.json without an explicit `docker login` step) — but + # modern `docker build` defaults to BuildKit/buildx, which wants + # to create its own state dir at /root/.docker/buildx and fails + # with "read-only file system" since the whole mount is + # read-only. Forcing the classic builder avoids needing to write + # there at all. + - name: DOCKER_BUILDKIT + value: "0" # For syncArgoApp.groovy — read directly from the ESO-managed # Secret, not a Jenkins-native credential (nothing in this # pipeline uses Jenkins' own credential store; staying consistent diff --git a/vars/homelabPipeline.groovy b/vars/homelabPipeline.groovy index 4e6e04f..b0a5708 100644 --- a/vars/homelabPipeline.groovy +++ b/vars/homelabPipeline.groovy @@ -27,6 +27,19 @@ def call(Map config) { config.helm_repo_url = config.helm_repo_url ?: 'http://gitea.192.168.1.7.nip.io/mukul/devops-helm-charts.git' config.image_tag_yq_path = config.image_tag_yq_path ?: '.deployment.image.tag' + // Every stage file (both the ones adapted for this homelab and the + // untouched legacy ones carried over from the real devops-lib) reads + // `env.FAILURE` when setting currentBuild.result on error — the real + // system must define this as a global Jenkins environment variable + // somewhere upstream of buildPipeline.groovy, since it's referenced + // everywhere but never set anywhere in this repo. Left undefined, + // `env.FAILURE` is null, and `currentBuild.result = null` throws + // `NoSuchMethodError`/`NullPointerException` deep inside Jenkins' + // own result-normalization code — masking whatever the real error + // was. Defining it once here, before any stage runs, is the minimal + // fix rather than touching every individual stage file. + env.FAILURE = 'FAILURE' + podTemplate(yaml: libraryResource('org/homelab/dind-pod.yaml')) { node(POD_LABEL) { def checkOutObj = new com.homelab.stages.checkOut()