Skip to content

Commit 45b7d16

Browse files
wesleyjellisclaude
andcommitted
Emit account_id and job metadata as Kubernetes pod labels
Rather than weaving the account_id job variable into the pod name (which risks the 63-char limit and OpsLevel-side naming conventions), stamp descriptive labels on the job pod for observability: app.kubernetes.io/name: opslevel-job opslevel.com/account-id: <account_id> (when the job sets it) opslevel.com/job-id: <job id> opslevel.com/mode: <faktory|api> These enable native DataDog filtering via podLabelsAsTags with no pod name parsing. Labels are added after building the PDB label selector so they stay out of the selector, which the instance label already makes unique. Adds a getRunnerJobVariable helper (named explicitly since a similar helper is anticipated for egress proxies). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 28ddc3e commit 45b7d16

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

src/pkg/k8s.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ func NewJobRunner(runnerId string, path string) *JobRunner {
111111
}
112112
}
113113

114+
// getRunnerJobVariable returns the value of the job variable with the given key, if present.
115+
func getRunnerJobVariable(configs []opslevel.RunnerJobVariable, key string) string {
116+
for _, config := range configs {
117+
if config.Key == key {
118+
return config.Value
119+
}
120+
}
121+
return ""
122+
}
123+
114124
// getPodEnv returns the env vars to inject into a container for the given
115125
// scope. Variables with no Scope set are visible to every container; variables
116126
// with a Scope are only visible to containers running in that scope.
@@ -372,6 +382,16 @@ func (s *JobRunner) Run(ctx context.Context, job opslevel.RunnerJob, stdout, std
372382
Outcome: opslevel.RunnerJobOutcomeEnumFailed,
373383
}
374384
}
385+
// Descriptive labels for observability (e.g. DataDog podLabelsAsTags), so
386+
// running pods can be filtered by account/job/mode without parsing the pod
387+
// name. Added after building the selector so they stay out of the PDB
388+
// selector, which the instance label already makes unique.
389+
labels["app.kubernetes.io/name"] = "opslevel-job"
390+
labels["opslevel.com/job-id"] = id
391+
labels["opslevel.com/mode"] = viper.GetString("mode")
392+
if accountId := getRunnerJobVariable(job.Variables, "account_id"); accountId != "" {
393+
labels["opslevel.com/account-id"] = accountId
394+
}
375395
// TODO: manage pods based on image for re-use?
376396
cfgMap, err := s.CreateConfigMap(ctx, s.getConfigMapObject(identifier, job))
377397
if err != nil {

src/pkg/k8s_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,33 @@ func TestGetPodEnv_FiltersByScope(t *testing.T) {
193193
autopilot.Equals(t, []string{"BOTH", "MAIN_ONLY"}, mainKeys)
194194
}
195195

196+
func TestGetRunnerJobVariable_ReturnsMatchingValue(t *testing.T) {
197+
// Arrange
198+
vars := []opslevel.RunnerJobVariable{
199+
{Key: "FOO", Value: "bar"},
200+
{Key: "account_id", Value: "acct-123"},
201+
}
202+
203+
// Act
204+
value := getRunnerJobVariable(vars, "account_id")
205+
206+
// Assert
207+
autopilot.Equals(t, "acct-123", value)
208+
}
209+
210+
func TestGetRunnerJobVariable_ReturnsEmptyWhenMissing(t *testing.T) {
211+
// Arrange
212+
vars := []opslevel.RunnerJobVariable{
213+
{Key: "FOO", Value: "bar"},
214+
}
215+
216+
// Act
217+
value := getRunnerJobVariable(vars, "account_id")
218+
219+
// Assert
220+
autopilot.Equals(t, "", value)
221+
}
222+
196223
func TestGetPodObject_NoInitCommands(t *testing.T) {
197224
// Arrange
198225
runner := &JobRunner{

0 commit comments

Comments
 (0)