Add task UUID label to Kubernetes pods (#5544)

This commit is contained in:
Henrik Huitti
2025-09-23 21:30:20 +03:00
committed by GitHub
parent 7707e843f2
commit 0bd69e876f
4 changed files with 58 additions and 38 deletions

View File

@@ -19,6 +19,8 @@ The following metadata labels are supported:
- `woodpecker-ci.org/repo-full-name` - `woodpecker-ci.org/repo-full-name`
- `woodpecker-ci.org/branch` - `woodpecker-ci.org/branch`
- `woodpecker-ci.org/org-id` - `woodpecker-ci.org/org-id`
- `woodpecker-ci.org/task-uuid`
- `woodpecker-ci.org/step`
## Private registries ## Private registries

View File

@@ -274,7 +274,7 @@ func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string)
} }
log.Trace().Str("taskUUID", taskUUID).Msgf("starting step: %s", step.Name) log.Trace().Str("taskUUID", taskUUID).Msgf("starting step: %s", step.Name)
_, err = startPod(ctx, e, step, options) _, err = startPod(ctx, e, step, options, taskUUID)
return err return err
} }

View File

@@ -36,11 +36,12 @@ const (
// This will be removed in the future. // This will be removed in the future.
StepLabelLegacy = "step" StepLabelLegacy = "step"
StepLabel = "woodpecker-ci.org/step" StepLabel = "woodpecker-ci.org/step"
TaskUUIDLabel = "woodpecker-ci.org/task-uuid"
podPrefix = "wp-" podPrefix = "wp-"
defaultFSGroup int64 = 1000 defaultFSGroup int64 = 1000
) )
func mkPod(step *types.Step, config *config, podName, goos string, options BackendOptions) (*v1.Pod, error) { func mkPod(step *types.Step, config *config, podName, goos string, options BackendOptions, taskUUID string) (*v1.Pod, error) {
var err error var err error
nsp := newNativeSecretsProcessor(config, options.Secrets) nsp := newNativeSecretsProcessor(config, options.Secrets)
@@ -49,7 +50,7 @@ func mkPod(step *types.Step, config *config, podName, goos string, options Backe
return nil, err return nil, err
} }
meta, err := podMeta(step, config, options, podName) meta, err := podMeta(step, config, options, podName, taskUUID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -84,7 +85,7 @@ func podName(step *types.Step) (string, error) {
return dnsName(podPrefix + step.UUID) return dnsName(podPrefix + step.UUID)
} }
func podMeta(step *types.Step, config *config, options BackendOptions, podName string) (meta_v1.ObjectMeta, error) { func podMeta(step *types.Step, config *config, options BackendOptions, podName, taskUUID string) (meta_v1.ObjectMeta, error) {
var err error var err error
meta := meta_v1.ObjectMeta{ meta := meta_v1.ObjectMeta{
Name: podName, Name: podName,
@@ -92,7 +93,7 @@ func podMeta(step *types.Step, config *config, options BackendOptions, podName s
Annotations: podAnnotations(config, options), Annotations: podAnnotations(config, options),
} }
meta.Labels, err = podLabels(step, config, options) meta.Labels, err = podLabels(step, config, options, taskUUID)
if err != nil { if err != nil {
return meta, err return meta, err
} }
@@ -100,7 +101,7 @@ func podMeta(step *types.Step, config *config, options BackendOptions, podName s
return meta, nil return meta, nil
} }
func podLabels(step *types.Step, config *config, options BackendOptions) (map[string]string, error) { func podLabels(step *types.Step, config *config, options BackendOptions, taskUUID string) (map[string]string, error) {
var err error var err error
labels := make(map[string]string) labels := make(map[string]string)
@@ -141,6 +142,10 @@ func podLabels(step *types.Step, config *config, options BackendOptions) (map[st
return labels, err return labels, err
} }
if len(taskUUID) > 0 {
labels[TaskUUIDLabel] = taskUUID
}
return labels, nil return labels, nil
} }
@@ -598,13 +603,13 @@ func mapToEnvVars(m map[string]string) []v1.EnvVar {
return ev return ev
} }
func startPod(ctx context.Context, engine *kube, step *types.Step, options BackendOptions) (*v1.Pod, error) { func startPod(ctx context.Context, engine *kube, step *types.Step, options BackendOptions, taskUUID string) (*v1.Pod, error) {
podName, err := stepToPodName(step) podName, err := stepToPodName(step)
if err != nil { if err != nil {
return nil, err return nil, err
} }
engineConfig := engine.getConfig() engineConfig := engine.getConfig()
pod, err := mkPod(step, engineConfig, podName, engine.goos, options) pod, err := mkPod(step, engineConfig, podName, engine.goos, options, taskUUID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -25,6 +25,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
) )
const taskUUID = "11301"
func TestPodName(t *testing.T) { func TestPodName(t *testing.T) {
name, err := podName(&types.Step{UUID: "01he8bebctabr3kgk0qj36d2me-0"}) name, err := podName(&types.Step{UUID: "01he8bebctabr3kgk0qj36d2me-0"})
assert.NoError(t, err) assert.NoError(t, err)
@@ -73,9 +75,10 @@ func TestPodMeta(t *testing.T) {
Environment: map[string]string{"CI": "woodpecker"}, Environment: map[string]string{"CI": "woodpecker"},
}, &config{ }, &config{
Namespace: "woodpecker", Namespace: "woodpecker",
}, BackendOptions{}, "wp-01he8bebctabr3kg-0") }, BackendOptions{}, "wp-01he8bebctabr3kg-0", taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "wp-svc-01he8bebctabr3kg-postgres", meta.Labels[ServiceLabel]) assert.EqualValues(t, "wp-svc-01he8bebctabr3kg-postgres", meta.Labels[ServiceLabel])
assert.EqualValues(t, taskUUID, meta.Labels[TaskUUIDLabel])
// Detached service // Detached service
meta, err = podMeta(&types.Step{ meta, err = podMeta(&types.Step{
@@ -87,7 +90,7 @@ func TestPodMeta(t *testing.T) {
Environment: map[string]string{"CI": "woodpecker"}, Environment: map[string]string{"CI": "woodpecker"},
}, &config{ }, &config{
Namespace: "woodpecker", Namespace: "woodpecker",
}, BackendOptions{}, "wp-01he8bebctabr3kg-0") }, BackendOptions{}, "wp-01he8bebctabr3kg-0", taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "wp-svc-01he8bebctabr3kg-postgres", meta.Labels[ServiceLabel]) assert.EqualValues(t, "wp-svc-01he8bebctabr3kg-postgres", meta.Labels[ServiceLabel])
@@ -101,7 +104,7 @@ func TestPodMeta(t *testing.T) {
Environment: map[string]string{"CI": "woodpecker"}, Environment: map[string]string{"CI": "woodpecker"},
}, &config{ }, &config{
Namespace: "woodpecker", Namespace: "woodpecker",
}, BackendOptions{}, "wp-01he8bebctabr3kg-0") }, BackendOptions{}, "wp-01he8bebctabr3kg-0", taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "", meta.Labels[ServiceLabel]) assert.EqualValues(t, "", meta.Labels[ServiceLabel])
} }
@@ -123,7 +126,8 @@ func TestTinyPod(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "build-via-gradle", "step": "build-via-gradle",
"woodpecker-ci.org/step": "build-via-gradle" "woodpecker-ci.org/step": "build-via-gradle",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -185,7 +189,7 @@ func TestTinyPod(t *testing.T) {
Environment: map[string]string{"CI": "woodpecker"}, Environment: map[string]string{"CI": "woodpecker"},
}, &config{ }, &config{
Namespace: "woodpecker", Namespace: "woodpecker",
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}) }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -205,7 +209,8 @@ func TestFullPod(t *testing.T) {
"app": "test", "app": "test",
"part-of": "woodpecker-ci", "part-of": "woodpecker-ci",
"step": "go-test", "step": "go-test",
"woodpecker-ci.org/step": "go-test" "woodpecker-ci.org/step": "go-test",
"woodpecker-ci.org/task-uuid": "11301"
}, },
"annotations": { "annotations": {
"apps.kubernetes.io/pod-index": "0", "apps.kubernetes.io/pod-index": "0",
@@ -391,7 +396,10 @@ func TestFullPod(t *testing.T) {
PodTolerationsAllowFromStep: true, PodTolerationsAllowFromStep: true,
PodNodeSelector: map[string]string{"topology.kubernetes.io/region": "eu-central-1"}, PodNodeSelector: map[string]string{"topology.kubernetes.io/region": "eu-central-1"},
SecurityContext: SecurityContextConfig{RunAsNonRoot: false}, SecurityContext: SecurityContextConfig{RunAsNonRoot: false},
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{ },
"wp-01he8bebctabr3kgk0qj36d2me-0",
"linux/amd64",
BackendOptions{
Labels: map[string]string{"part-of": "woodpecker-ci"}, Labels: map[string]string{"part-of": "woodpecker-ci"},
Annotations: map[string]string{"kubernetes.io/limit-ranger": "LimitRanger plugin set: cpu, memory request and limit for container"}, Annotations: map[string]string{"kubernetes.io/limit-ranger": "LimitRanger plugin set: cpu, memory request and limit for container"},
NodeSelector: map[string]string{"storage": "ssd"}, NodeSelector: map[string]string{"storage": "ssd"},
@@ -403,7 +411,7 @@ func TestFullPod(t *testing.T) {
Limits: map[string]string{"memory": "256Mi", "cpu": "2"}, Limits: map[string]string{"memory": "256Mi", "cpu": "2"},
}, },
SecurityContext: &secCtx, SecurityContext: &secCtx,
}) }, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -425,7 +433,7 @@ func TestPodPrivilege(t *testing.T) {
SecurityContext: SecurityContextConfig{RunAsNonRoot: globalRunAsRoot}, SecurityContext: SecurityContextConfig{RunAsNonRoot: globalRunAsRoot},
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{ }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{
SecurityContext: &secCtx, SecurityContext: &secCtx,
}) }, "")
} }
// securty context is requesting user and group 101 (non-root) // securty context is requesting user and group 101 (non-root)
@@ -504,7 +512,8 @@ func TestScratchPod(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "curl-google", "step": "curl-google",
"woodpecker-ci.org/step": "curl-google" "woodpecker-ci.org/step": "curl-google",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -532,7 +541,7 @@ func TestScratchPod(t *testing.T) {
Entrypoint: []string{"/usr/bin/curl", "-v", "google.com"}, Entrypoint: []string{"/usr/bin/curl", "-v", "google.com"},
}, &config{ }, &config{
Namespace: "woodpecker", Namespace: "woodpecker",
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}) }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -550,7 +559,8 @@ func TestSecrets(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "test-secrets", "step": "test-secrets",
"woodpecker-ci.org/step": "test-secrets" "woodpecker-ci.org/step": "test-secrets",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -652,7 +662,7 @@ func TestSecrets(t *testing.T) {
Target: SecretTarget{File: "~/.docker/config.json"}, Target: SecretTarget{File: "~/.docker/config.json"},
}, },
}, },
}) }, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -670,7 +680,8 @@ func TestPodTolerations(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "toleration-test", "step": "toleration-test",
"woodpecker-ci.org/step": "toleration-test" "woodpecker-ci.org/step": "toleration-test",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -711,7 +722,7 @@ func TestPodTolerations(t *testing.T) {
Namespace: "woodpecker", Namespace: "woodpecker",
PodTolerations: globalTolerations, PodTolerations: globalTolerations,
PodTolerationsAllowFromStep: false, PodTolerationsAllowFromStep: false,
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}) }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{}, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -729,7 +740,8 @@ func TestPodTolerationsAllowFromStep(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "toleration-test", "step": "toleration-test",
"woodpecker-ci.org/step": "toleration-test" "woodpecker-ci.org/step": "toleration-test",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -751,7 +763,8 @@ func TestPodTolerationsAllowFromStep(t *testing.T) {
"namespace": "woodpecker", "namespace": "woodpecker",
"labels": { "labels": {
"step": "toleration-test", "step": "toleration-test",
"woodpecker-ci.org/step": "toleration-test" "woodpecker-ci.org/step": "toleration-test",
"woodpecker-ci.org/task-uuid": "11301"
} }
}, },
"spec": { "spec": {
@@ -789,7 +802,7 @@ func TestPodTolerationsAllowFromStep(t *testing.T) {
PodTolerationsAllowFromStep: false, PodTolerationsAllowFromStep: false,
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{ }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{
Tolerations: stepTolerations, Tolerations: stepTolerations,
}) }, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err := json.Marshal(pod) podJSON, err := json.Marshal(pod)
@@ -803,7 +816,7 @@ func TestPodTolerationsAllowFromStep(t *testing.T) {
PodTolerationsAllowFromStep: true, PodTolerationsAllowFromStep: true,
}, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{ }, "wp-01he8bebctabr3kgk0qj36d2me-0", "linux/amd64", BackendOptions{
Tolerations: stepTolerations, Tolerations: stepTolerations,
}) }, taskUUID)
assert.NoError(t, err) assert.NoError(t, err)
podJSON, err = json.Marshal(pod) podJSON, err = json.Marshal(pod)