Files
devops-lib-gcp/vars/homelabPipeline.groovy
T
Mukul SharmaandClaude Opus 5 6d743cbe48 Make the registry hostname configurable and drop the CA mount
buildDocker.groovy hardcoded harbor.35.238.248.203.nip.io as the push
target, so the registry could not move without editing this shared library
and every consumer moving in the same commit. It now reads
config.harbor_registry, whose default lives in homelabPipeline.groovy
beside harbor_project and every other key.

The stage errors rather than defaulting when the value is missing. Carrying
a second copy of the literal would leave two defaults free to disagree, and
an unset value would otherwise build an image named "null/<project>/<repo>"
— which docker accepts as a hostname and then fails to resolve, pointing
nowhere near the cause.

The dind pod no longer mounts the registry CA. That mount existed because
the registry was a nip.io name, which no public CA will issue for, so
cert-manager signed Harbor from a private CA; the node pool was told to
trust it for pulls, but a push comes from dockerd inside the build pod,
which has its own trust store. harbor.infra.deployshed.com carries a Let's
Encrypt certificate that both already trust, so the mount, its volume and
the whole arrangement go away rather than being repointed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEsTefWWifp4ikvhHF5s6N
2026-09-17 09:31:32 +05:30

91 lines
4.9 KiB
Groovy

// New entry point — the homelab equivalent of the real devops-lib's
// buildPipeline.groovy. Same shape: a scripted pipeline global, so a
// service Jenkinsfile needs nothing but `@Library('devops-lib') _` plus
// one call to this — no pipeline{}/agent{}/stages{} block in the
// consuming repo at all, matching gkeCICD.groovy's Podcall precedent
// (podTemplate { node(POD_LABEL) { ... } }) rather than the declarative
// style the earlier version of this Jenkinsfile template used.
//
// Only repo_name is required — everything else defaults sensibly for a
// single-service repo on this one homelab cluster. Override any key by
// passing it explicitly, same as the real buildPipeline's param map, or
// by committing a config.yaml to the repo root (loadConfig merges it in
// after checkout — repo-committed values win over these defaults, same
// as the real system's config.yaml).
//
// dockerBuildVersion (e.g. 'go-1.22', 'node-20', 'python-3.12', 'java-21',
// 'php-8.3') is read by buildDocker.groovy only when the repo has no
// Dockerfile of its own — it picks which resources/com/homelab/<lang>-
// Dockerfile template to render and which base-image version to bake in.
// Repos that already ship a Dockerfile (like demo-go-app) never touch
// this key at all; it has no default because there's no sensible one to
// fall back to.
def call(Map config) {
config.service_name = config.service_name ?: config.repo_name
config.argo_app_name = config.argo_app_name ?: config.repo_name
// The Harbor project images are pushed to. Named apps-registry on this
// cluster, not the homelab's "homelab" — the project has to already
// exist, and Harbor rejects a push to a missing one with
// "unauthorized: project <name> not found", which reads like a
// credentials problem rather than a missing project.
config.harbor_project = config.harbor_project ?: 'apps-registry'
// The registry hostname images are pushed to and pulled from. This is
// the ONLY default for it — buildDocker.groovy deliberately errors
// rather than carrying a second copy, since two defaults for one value
// are free to disagree and the loser only shows up as a push to the
// wrong registry.
//
// It must be spelled identically here, in the dockerconfigjson auths
// key, and in Harbor's own externalURL: docker matches both stored
// credentials and TLS trust by exact hostname, so a mismatch fails as
// "unauthorized" rather than as anything resembling a name problem.
config.harbor_registry = config.harbor_registry ?: 'harbor.infra.deployshed.com'
// Cluster DNS, not the ingress hostname: this clone happens from a build
// pod, so it is pod-to-pod traffic and has no business leaving the
// cluster and coming back in through Contour.
config.helm_repo_url = config.helm_repo_url ?: 'http://gitea-http.gitea.svc.cluster.local:3000/gitadmin/devops-helm-charts-gcp.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()
def loadConfigObj = new com.homelab.stages.loadConfig()
def runHooksObj = new com.homelab.stages.runHooks()
def buildDockerObj = new com.homelab.stages.buildDocker()
def updateHelmTagObj = new com.homelab.stages.updateHelmTag()
def syncArgoAppObj = new com.homelab.stages.syncArgoApp()
def notifyObj = new com.homelab.stages.notify()
try {
checkOutObj.run(config)
loadConfigObj.run(config)
runHooksObj.run(config, 'pre_build')
buildDockerObj.run(config)
runHooksObj.run(config, 'post_build')
updateHelmTagObj.run(config)
syncArgoAppObj.run(config)
}
catch (Exception e) {
currentBuild.result = 'FAILURE'
log.error(e.toString())
}
finally {
notifyObj.run(config)
}
}
}
}