From 70e2fb0415bf6720ca1b0d2a0e6c261d29fa7d44 Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Thu, 1 Dec 2022 09:00:50 -0500 Subject: [PATCH] Add step labels to step containers This adds the following labels: - `io.drone.step.number` - `io.drone.step.name` We use these as labels when we send our logs to Loki Signed-off-by: Julien Duchesne --- engine/compiler/compiler.go | 28 +++++---- engine/compiler/compiler_test.go | 98 ++++++++++++++++++++++++++++++ engine/compiler/testdata/steps.yml | 16 +++++ 3 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 engine/compiler/testdata/steps.yml diff --git a/engine/compiler/compiler.go b/engine/compiler/compiler.go index f62a89d..2eacdd2 100644 --- a/engine/compiler/compiler.go +++ b/engine/compiler/compiler.go @@ -13,6 +13,7 @@ import ( "github.com/drone-runners/drone-runner-docker/engine/resource" "github.com/drone-runners/drone-runner-docker/internal/docker/image" + "github.com/drone/drone-go/drone" "github.com/drone/runner-go/clone" "github.com/drone/runner-go/container" "github.com/drone/runner-go/environ" @@ -147,7 +148,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti } // create system labels - labels := labels.Combine( + stageLabels := labels.Combine( c.Labels, labels.FromRepo(args.Repo), labels.FromBuild(args.Build), @@ -167,7 +168,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti EmptyDir: &engine.VolumeEmptyDir{ ID: random(), Name: mount.Name, - Labels: labels, + Labels: stageLabels, }, } @@ -180,14 +181,14 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti ID: random(), Name: mount.Name, Path: c.Mount, - Labels: labels, + Labels: stageLabels, } } spec := &engine.Spec{ Network: engine.Network{ ID: random(), - Labels: labels, + Labels: stageLabels, Options: c.NetworkOpts, }, Platform: engine.Platform{ @@ -278,7 +279,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti step.ID = random() step.Envs = environ.Combine(envs, step.Envs) step.WorkingDir = full - step.Labels = labels + step.Labels = stageLabels step.Pull = engine.PullIfNotExists step.Volumes = append(step.Volumes, mount) spec.Steps = append(spec.Steps, step) @@ -308,7 +309,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti dst.Detach = true dst.Envs = environ.Combine(envs, dst.Envs) dst.Volumes = append(dst.Volumes, mount) - dst.Labels = labels + dst.Labels = stageLabels setupScript(src, dst, os) setupWorkdir(src, dst, full) spec.Steps = append(spec.Steps, dst) @@ -329,7 +330,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti dst := createStep(pipeline, src) dst.Envs = environ.Combine(envs, dst.Envs) dst.Volumes = append(dst.Volumes, mount) - dst.Labels = labels + dst.Labels = stageLabels setupScript(src, dst, os) setupWorkdir(src, dst, full) spec.Steps = append(spec.Steps, dst) @@ -355,7 +356,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti // to the end user. spec.Internal = append(spec.Internal, &engine.Step{ ID: random(), - Labels: labels, + Labels: stageLabels, Pull: engine.PullIfNotExists, Image: image.Expand(c.Tmate.Image), Entrypoint: []string{"/bin/drone-runner-docker"}, @@ -375,7 +376,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti EmptyDir: &engine.VolumeEmptyDir{ ID: random(), Name: "_addons", - Labels: labels, + Labels: stageLabels, }, }) } @@ -468,8 +469,13 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti } // append global networks to the steps. - for _, step := range spec.Steps { + // append step labels to steps. + for n, step := range spec.Steps { step.Networks = append(step.Networks, c.Networks...) + step.Labels = labels.Combine(step.Labels, labels.FromStep(&drone.Step{ + Number: n + 1, + Name: step.Name, + })) } // append global volumes to the steps. @@ -505,7 +511,7 @@ func (c *Compiler) Compile(ctx context.Context, args runtime.CompilerArgs) runti Name: v.Name, Medium: v.EmptyDir.Medium, SizeLimit: int64(v.EmptyDir.SizeLimit), - Labels: labels, + Labels: stageLabels, } } else if v.HostPath != nil { src.HostPath = &engine.VolumeHostPath{ diff --git a/engine/compiler/compiler_test.go b/engine/compiler/compiler_test.go index 660c23f..c4d4aa7 100644 --- a/engine/compiler/compiler_test.go +++ b/engine/compiler/compiler_test.go @@ -11,6 +11,7 @@ import ( "encoding/json" "io/ioutil" "os" + "strconv" "testing" "github.com/dchest/uniuri" @@ -141,6 +142,103 @@ func TestCompile_Secrets(t *testing.T) { } } +// This test verifies that step labels are generated correctly +func TestCompile_StepLabels(t *testing.T) { + manifest, _ := manifest.ParseFile("testdata/steps.yml") + + compiler := &Compiler{ + Environ: provider.Static(nil), + Registry: registry.Static(nil), + Secret: secret.Static(nil), + Labels: map[string]string{"foo": "bar"}, + } + args := runtime.CompilerArgs{ + Repo: &drone.Repo{ + Name: "repo-name", + Namespace: "repo-namespace", + Slug: "repo-slug", + }, + Build: &drone.Build{ + Number: 42, + }, + Stage: &drone.Stage{ + Name: "default", + Number: 1, + }, + System: &drone.System{ + Host: "drone.example.com", + Proto: "https", + Version: "1.0.0", + }, + Netrc: &drone.Netrc{}, + Manifest: manifest, + Pipeline: manifest.Resources[0].(*resource.Pipeline), + Secret: secret.Static(nil), + } + + ir := compiler.Compile(nocontext, args).(*engine.Spec) + + gotLabels := []map[string]string{} + for _, step := range ir.Steps { + stepLabels := step.Labels + + // Remove timestamps from labels, we can't do a direct comparison + if gotCreated, err := strconv.Atoi(stepLabels["io.drone.created"]); err != nil || gotCreated == 0 { + t.Errorf("Expectec io.drone.created label to be set to a non-zero value. Got %q", stepLabels["io.drone.created"]) + } + delete(stepLabels, "io.drone.created") + + if gotExpires, err := strconv.Atoi(stepLabels["io.drone.expires"]); err != nil || gotExpires == 0 { + t.Errorf("Expectec io.drone.expires label to be set to a non-zero value. Got %q", stepLabels["io.drone.expires"]) + } + delete(stepLabels, "io.drone.expires") + + gotLabels = append(gotLabels, stepLabels) + } + + wantLabels := []map[string]string{ + { + "foo": "bar", + "io.drone": "true", + "io.drone.build.number": "42", + "io.drone.protected": "false", + "io.drone.repo.name": "repo-name", + "io.drone.repo.namespace": "repo-namespace", + "io.drone.repo.slug": "repo-slug", + "io.drone.stage.name": "default", + "io.drone.stage.number": "1", + "io.drone.step.name": "build", + "io.drone.step.number": "1", + "io.drone.system.host": "drone.example.com", + "io.drone.system.proto": "https", + "io.drone.system.version": "1.0.0", + "io.drone.ttl": "0s", + }, + { + "foo": "bar", + "io.drone": "true", + "io.drone.build.number": "42", + "io.drone.protected": "false", + "io.drone.repo.name": "repo-name", + "io.drone.repo.namespace": "repo-namespace", + "io.drone.repo.slug": "repo-slug", + "io.drone.stage.name": "default", + "io.drone.stage.number": "1", + "io.drone.step.name": "test", + "io.drone.step.number": "2", + "io.drone.system.host": "drone.example.com", + "io.drone.system.proto": "https", + "io.drone.system.version": "1.0.0", + "io.drone.ttl": "0s", + }, + } + + if diff := cmp.Diff(gotLabels, wantLabels); len(diff) != 0 { + t.Errorf(diff) + } + +} + // helper function parses and compiles the source file and then // compares to a golden json file. func testCompile(t *testing.T, source, golden string) *engine.Spec { diff --git a/engine/compiler/testdata/steps.yml b/engine/compiler/testdata/steps.yml new file mode 100644 index 0000000..a2cefce --- /dev/null +++ b/engine/compiler/testdata/steps.yml @@ -0,0 +1,16 @@ +kind: pipeline +type: docker +name: default + +clone: + disable: true + +steps: +- name: build + image: golang + commands: + - go build +- name: test + image: golang + commands: + - go test