<freeStyleBuild _class='hudson.model.FreeStyleBuild'><action _class='hudson.model.CauseAction'><cause _class='com.cloudbees.jenkins.GitHubPushCause'><shortDescription>Started by GitHub push by ti-chi-bot[bot]</shortDescription></cause><cause _class='com.cloudbees.jenkins.GitHubPushCause'><shortDescription>Started by GitHub push by ti-chi-bot[bot]</shortDescription></cause></action><action></action><action _class='jenkins.metrics.impl.TimeInQueueAction'><blockedDurationMillis>0</blockedDurationMillis><blockedTimeMillis>0</blockedTimeMillis><buildableDurationMillis>25363</buildableDurationMillis><buildableTimeMillis>25363</buildableTimeMillis><buildingDurationMillis>43925</buildingDurationMillis><executingTimeMillis>43925</executingTimeMillis><executorUtilization>1.0</executorUtilization><subTaskCount>0</subTaskCount><waitingDurationMillis>9576</waitingDurationMillis><waitingTimeMillis>9576</waitingTimeMillis></action><action _class='hudson.plugins.git.util.BuildData'><buildsByBranchName><originmain _class='hudson.plugins.git.util.Build'><buildNumber>1628</buildNumber><marked><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><branch><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><name>origin/main</name></branch></marked><revision><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><branch><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><name>origin/main</name></branch></revision></originmain></buildsByBranchName><lastBuiltRevision><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><branch><SHA1>5a6b44c85a4a37a83027975092ab283a389d6fe2</SHA1><name>origin/main</name></branch></lastBuiltRevision><remoteUrl>https://github.com/PingCAP-QE/ci.git</remoteUrl><scmName></scmName></action><action></action><action></action><action></action><action></action><action></action><action></action><action _class='org.jenkinsci.plugins.displayurlapi.actions.RunDisplayAction'></action><building>false</building><displayName>#1628</displayName><duration>43925</duration><estimatedDuration>43022</estimatedDuration><fullDisplayName>seed #1628</fullDisplayName><id>1628</id><inProgress>false</inProgress><keepLog>false</keepLog><number>1628</number><queueId>3669346</queueId><result>SUCCESS</result><timestamp>1776312717379</timestamp><url>https://do.pingcap.net/jenkins/job/seed/1628/</url><builtOn>default-v5n4g</builtOn><changeSet _class='hudson.plugins.git.GitChangeSetList'><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>prow-jobs/pingcap-qe/ci/presubmits.yaml</affectedPath><affectedPath>.ci/verify-k8s-pod-yaml.sh</affectedPath><affectedPath>docs/guides/CI.md</affectedPath><affectedPath>pipelines/ti-community-infra/test-prod/pod-prow_debug.yaml</affectedPath><commitId>5a6b44c85a4a37a83027975092ab283a389d6fe2</commitId><timestamp>1776312678000</timestamp><author><absoluteUrl>https://do.pingcap.net/jenkins/user/noreply</absoluteUrl><fullName>noreply</fullName></author><authorEmail>noreply@github.com</authorEmail><comment>ci: verify pipeline pod YAML volumes blocks (#4526)

## Summary
- keep the non-Python `sh + yq` structural validation for pipeline Pod
YAML files
- add supplemental `kubectl --dry-run=client` and `kubectl
--dry-run=server` validation paths when the presubmit runs with
in-cluster Kubernetes API access
- inject a synthetic test `metadata.name` before calling `kubectl`,
because Jenkins pod templates usually omit pod names
- fix one real invalid Pod manifest already present on `main`:
`pipelines/ti-community-infra/test-prod/pod-prow_debug.yaml`

## What is checked
- YAML must parse successfully
- `apiVersion` must be `v1`
- `kind` must be `Pod`
- `spec` must be a map
- `spec.containers` must be a non-empty sequence
- explicit null nodes are rejected anywhere in the Pod manifest
- when in-cluster API access is available, `kubectl` also validates the
rendered manifest after injecting a test pod name and namespace:
  - `kubectl apply --dry-run=client --validate=strict`
  - `kubectl apply --dry-run=server --validate=strict`

## Why this shape
- plain schema validation alone is not enough for the repo-specific
null-node cases we found
- `kubectl` validation is useful as extra Kubernetes-side verification,
but Jenkins pod templates need a synthetic test name before it can run
cleanly
- so the PR keeps the deterministic structural guardrail, and adds
`kubectl` validation opportunistically when the presubmit environment
supports it

## Findings from this follow-up
- `pipelines/pingcap/tidb/latest/pod-ghpr_mysql_test.yaml` is already
clean on current `main`
- current `main` did still contain another real invalid case:
`pipelines/ti-community-infra/test-prod/pod-prow_debug.yaml` with
`spec.containers: null`
- this PR fixes that file and adds a dedicated presubmit guardrail

## Validation
- `sh .ci/verify-k8s-pod-yaml.sh`
- stubbed `kubectl` validation locally to verify the script injects
`metadata.name=ci-pod-yaml-validate`, injects the test namespace, and
calls both client/server dry-run paths
- `sh .ci/verify-k8s-pod-yaml.sh /tmp/invalid-null-volumes.yaml` -&gt;
fails as expected
- `sh .ci/verify-k8s-pod-yaml.sh /tmp/invalid-null-containers.yaml` -&gt;
fails as expected
- YAML parse for `prow-jobs/pingcap-qe/ci/presubmits.yaml` and
`pipelines/ti-community-infra/test-prod/pod-prow_debug.yaml` -&gt;
`yaml-ok`
- `.ci/update-prow-job-kustomization.sh`
</comment><date>2026-04-16 04:11:18 +0000</date><id>5a6b44c85a4a37a83027975092ab283a389d6fe2</id><msg>ci: verify pipeline pod YAML volumes blocks (#4526)</msg><path><editType>add</editType><file>.ci/verify-k8s-pod-yaml.sh</file></path><path><editType>edit</editType><file>prow-jobs/pingcap-qe/ci/presubmits.yaml</file></path><path><editType>edit</editType><file>docs/guides/CI.md</file></path><path><editType>edit</editType><file>pipelines/ti-community-infra/test-prod/pod-prow_debug.yaml</file></path></item><kind>git</kind></changeSet><culprit><absoluteUrl>https://do.pingcap.net/jenkins/user/noreply</absoluteUrl><fullName>noreply</fullName></culprit></freeStyleBuild>