| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /**
- * Harbor image promote + optional ACK deploy (loaded from Jenkinsfile, not a job entry).
- */
- def DEFAULT_SOURCE_TAG = 'uat-latest'
- def resolveTargetTag(def script, String targetTagParam) {
- def t = (targetTagParam ?: '').trim()
- return t ?: "produ-${script.env.BUILD_NUMBER}"
- }
- /** Empty SOURCE_TAG (incl. old Job cached params) falls back to uat-latest. */
- def requireSourceTag(def script, String sourceTag) {
- def srcTag = (sourceTag ?: '').trim()
- if (!srcTag) {
- script.echo ">>> SOURCE_TAG empty, using default: ${DEFAULT_SOURCE_TAG}"
- return DEFAULT_SOURCE_TAG
- }
- return srcTag
- }
- def promoteHarborImages(def script, List services, Map cfg) {
- def regHost = cfg.harborRegistry.trim()
- def proj = cfg.harborProject.trim()
- def srcTag = requireSourceTag(script, cfg.sourceTag)
- def tgtTag = cfg.targetTag
- def dryRun = cfg.dryRun == true
- def method = (cfg.promoteMethod ?: 'harbor-api').trim()
- def repos = services*.prodDir.join(' ')
- services.each { s ->
- def src = "${regHost}/${proj}/${s.prodDir}:${srcTag}"
- def tgt = "${regHost}/${proj}/${s.prodDir}:${tgtTag}"
- echo ">>> promote ${s.prodDir}: ${src} -> ${tgt} (method=${method})"
- }
- if (dryRun) {
- return
- }
- script.withCredentials([script.usernamePassword(
- credentialsId: cfg.harborCredentialsId,
- usernameVariable: 'HARBOR_USER',
- passwordVariable: 'HARBOR_PASS',
- )]) {
- script.sh """
- set -e
- REG='${regHost}'
- PROJ='${proj}'
- SRC='${srcTag}'
- TGT='${tgtTag}'
- METHOD='${method}'
- if [ "\${METHOD}" != "docker-pull" ] && ! command -v jq >/dev/null 2>&1; then
- echo '>>> jq missing, fallback to docker-pull'
- METHOD=docker-pull
- fi
- if [ "\${METHOD}" = "docker-pull" ]; then
- echo "\${HARBOR_PASS}" | docker login \${REG} -u "\${HARBOR_USER}" --password-stdin
- fi
- promote_repo() {
- local repo="\$1"
- local src_img="\${REG}/\${PROJ}/\${repo}:\${SRC}"
- local tgt_img="\${REG}/\${PROJ}/\${repo}:\${TGT}"
- if [ "\${METHOD}" = "docker-pull" ]; then
- echo ">>> docker promote \${repo}"
- docker pull "\${src_img}"
- docker tag "\${src_img}" "\${tgt_img}"
- docker push "\${tgt_img}"
- docker rmi "\${tgt_img}" "\${src_img}" 2>/dev/null || true
- return 0
- fi
- local enc_repo
- enc_repo=\$(printf '%s' "\${repo}" | jq -sRr @uri)
- echo ">>> Harbor API promote \${repo}: \${SRC} -> \${TGT}"
- if curl -fsS -X POST -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\
- "http://\${REG}/api/v2.0/projects/\${PROJ}/repositories/\${enc_repo}/artifacts/\${SRC}/tags" \\
- -H 'Content-Type: application/json' \\
- -d "{\\"name\\":\\"\${TGT}\\"}"; then
- return 0
- fi
- echo ">>> WARN: Harbor API failed for \${repo}, fallback docker"
- docker pull "\${src_img}"
- docker tag "\${src_img}" "\${tgt_img}"
- docker push "\${tgt_img}"
- docker rmi "\${tgt_img}" "\${src_img}" 2>/dev/null || true
- }
- if [ "\${METHOD}" != "docker-pull" ]; then
- echo "\${HARBOR_PASS}" | docker login \${REG} -u "\${HARBOR_USER}" --password-stdin 2>/dev/null || true
- fi
- for repo in ${repos}; do
- promote_repo "\${repo}"
- done
- """
- }
- }
- def deployServicesToAck(def script, List services, Map cfg) {
- def parallelDeploy = cfg.parallelDeploy != false
- def regHost = cfg.harborRegistry.trim()
- def proj = cfg.harborProject.trim()
- def tgtTag = cfg.targetTag
- def strategy = cfg.deployStrategy ?: 'rolling'
- def ns = cfg.k8sNamespace
- def canaryWeight = (cfg.canaryWeight ?: '10').trim()
- def kubeCreds = cfg.kubeCredentialsId
- def runDeploy = { s ->
- def imageRef = "${regHost}/${proj}/${s.prodDir}:${tgtTag}"
- deployToAck(script, [
- k8sNamespace: ns,
- imageRef: imageRef,
- deployStrategy: strategy == 'canary' ? 'canary' : 'rolling',
- deploymentStable: s.deployName,
- deploymentCanary: "${s.deployName}-canary",
- ingressCanary: "${s.deployName}-canary",
- canaryWeight: canaryWeight,
- kubeCredentialsId: kubeCreds,
- ])
- }
- if (!parallelDeploy || services.size() <= 1) {
- services.each { runDeploy(it) }
- return
- }
- def branches = [:]
- services.each { s ->
- branches[s.prodDir] = { runDeploy(s) }
- }
- script.parallel branches
- }
- def deployToAck(def script, Map cfg) {
- def ns = cfg.k8sNamespace
- def imageRef = cfg.imageRef
- def strategy = cfg.deployStrategy
- def targetDeploy = strategy == 'canary' ? cfg.deploymentCanary : cfg.deploymentStable
- def canaryWeight = cfg.canaryWeight
- def ingressCanary = cfg.ingressCanary
- def kubeCreds = cfg.kubeCredentialsId
- script.withCredentials([script.file(credentialsId: kubeCreds, variable: 'KUBECONFIG')]) {
- script.sh """
- set -e
- kubectl config current-context
- kubectl -n ${ns} set image deployment/${targetDeploy} app=${imageRef} --record
- kubectl -n ${ns} rollout status deployment/${targetDeploy} --timeout=300s
- """
- if (strategy == 'canary') {
- script.sh """
- set -e
- kubectl -n ${ns} annotate ingress ${ingressCanary} \\
- nginx.ingress.kubernetes.io/canary=true \\
- nginx.ingress.kubernetes.io/canary-weight=${canaryWeight} \\
- --overwrite
- """
- }
- }
- }
- /** Single-service promote + ACK. Use script.params / script.env (do not pass params/env as args: CPS breaks method dispatch). */
- def promoteOneServiceToAck(def script, Map svc) {
- def regHost = script.params.HARBOR_REGISTRY.trim()
- def proj = script.params.HARBOR_PROJECT.trim()
- def srcTag = requireSourceTag(script, script.params.SOURCE_TAG)
- def tgtTag = resolveTargetTag(script, script.params.TARGET_TAG)
- def dryRun = script.params.DRY_RUN == true
- def strategy = script.params.DEPLOY_STRATEGY ?: 'rolling'
- script.env.TARGET_TAG_RESOLVED = tgtTag
- script.env.IMAGE_REF = "${regHost}/${proj}/${svc.prodDir}:${tgtTag}"
- promoteHarborImages(script, [svc], [
- harborRegistry: regHost,
- harborProject: proj,
- sourceTag: srcTag,
- targetTag: tgtTag,
- harborCredentialsId: script.env.HARBOR_CREDENTIALS,
- promoteMethod: (script.params.PROMOTE_METHOD ?: 'harbor-api').trim(),
- dryRun: dryRun,
- ])
- if (dryRun || strategy == 'skip') {
- return
- }
- deployToAck(script, [
- k8sNamespace: script.params.K8S_NAMESPACE,
- imageRef: script.env.IMAGE_REF,
- deployStrategy: strategy == 'canary' ? 'canary' : 'rolling',
- deploymentStable: svc.deployName,
- deploymentCanary: "${svc.deployName}-canary",
- ingressCanary: "${svc.deployName}-canary",
- canaryWeight: (script.params.CANARY_WEIGHT ?: '10').trim(),
- kubeCredentialsId: script.env.KUBECONFIG_CREDENTIALS,
- ])
- }
- return this
|