From 17e3bafd36e6801c71a25c9e239b552a1842efa4 Mon Sep 17 00:00:00 2001 From: Phil Renaud Date: Sun, 25 Aug 2024 23:48:55 -0400 Subject: [PATCH] TaggedVersion information in structs, rather than job_endpoint (#23841) * TaggedVersion information in structs, rather than job_endpoint * Test for taggedVersion description length * Some API plumbing --- api/jobs.go | 19 ++++++++++++++++++ command/agent/job_endpoint.go | 13 ++++++++++++ command/agent/job_endpoint_test.go | 32 ++++++++++++++++++++++++++++++ nomad/structs/structs.go | 27 +++++++++++++++++++++++++ nomad/structs/structs_test.go | 12 +++++++++++ 5 files changed, 103 insertions(+) diff --git a/api/jobs.go b/api/jobs.go index a0788f5176d9..a39fadd053b6 100644 --- a/api/jobs.go +++ b/api/jobs.go @@ -990,6 +990,24 @@ func (j *JobUILink) Copy() *JobUILink { } } +type JobTaggedVersion struct { + Name string + Description string + TaggedTime int64 +} + +func (j *JobTaggedVersion) Copy() *JobTaggedVersion { + if j == nil { + return nil + } + + return &JobTaggedVersion{ + Name: j.Name, + Description: j.Description, + TaggedTime: j.TaggedTime, + } +} + func (js *JobSubmission) Canonicalize() { if js == nil { return @@ -1068,6 +1086,7 @@ type Job struct { CreateIndex *uint64 ModifyIndex *uint64 JobModifyIndex *uint64 + TaggedVersion *JobTaggedVersion } // IsPeriodic returns whether a job is periodic. diff --git a/command/agent/job_endpoint.go b/command/agent/job_endpoint.go index 2f7b9f2c2e7f..7dec748e34b0 100644 --- a/command/agent/job_endpoint.go +++ b/command/agent/job_endpoint.go @@ -1043,6 +1043,7 @@ func ApiJobToStructJob(job *api.Job) *structs.Job { Constraints: ApiConstraintsToStructs(job.Constraints), Affinities: ApiAffinitiesToStructs(job.Affinities), UI: ApiJobUIConfigToStructs(job.UI), + TaggedVersion: ApiJobTaggedVersionToStructs(job.TaggedVersion), } // Update has been pushed into the task groups. stagger and max_parallel are @@ -2145,6 +2146,18 @@ func ApiJobUIConfigToStructs(jobUI *api.JobUIConfig) *structs.JobUIConfig { } } +func ApiJobTaggedVersionToStructs(jobTaggedVersion *api.JobTaggedVersion) *structs.JobTaggedVersion { + if jobTaggedVersion == nil { + return nil + } + + return &structs.JobTaggedVersion{ + Name: jobTaggedVersion.Name, + Description: jobTaggedVersion.Description, + TaggedTime: jobTaggedVersion.TaggedTime, + } +} + func ApiAffinityToStructs(a1 *api.Affinity) *structs.Affinity { return &structs.Affinity{ LTarget: a1.LTarget, diff --git a/command/agent/job_endpoint_test.go b/command/agent/job_endpoint_test.go index f06c5767e307..c5d2c1b9e331 100644 --- a/command/agent/job_endpoint_test.go +++ b/command/agent/job_endpoint_test.go @@ -4448,3 +4448,35 @@ func TestConversion_ApiJobUIConfigToStructs(t *testing.T) { must.Eq(t, expected, result) }) } + +func TestConversion_ApiJobTaggedVersionToStructs(t *testing.T) { + t.Run("nil tagged version", func(t *testing.T) { + must.Nil(t, ApiJobTaggedVersionToStructs(nil)) + }) + + t.Run("empty tagged version", func(t *testing.T) { + taggedVersion := &api.JobTaggedVersion{} + expected := &structs.JobTaggedVersion{ + Name: "", + Description: "", + TaggedTime: 0, + } + result := ApiJobTaggedVersionToStructs(taggedVersion) + must.Eq(t, expected, result) + }) + + t.Run("tagged version with tag and version", func(t *testing.T) { + taggedVersion := &api.JobTaggedVersion{ + Name: "low-latency", + Description: "Low latency version", + TaggedTime: 1234567890, + } + expected := &structs.JobTaggedVersion{ + Name: "low-latency", + Description: "Low latency version", + TaggedTime: 1234567890, + } + result := ApiJobTaggedVersionToStructs(taggedVersion) + must.Eq(t, expected, result) + }) +} diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 18a5de39c4f3..51744f012674 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -4516,6 +4516,26 @@ type Job struct { // Links and Description fields for the Web UI UI *JobUIConfig + + // Metadata related to a tagged Job Version (which itself is really a Job) + TaggedVersion *JobTaggedVersion +} + +type JobTaggedVersion struct { + Name string + Description string + TaggedTime int64 +} + +func (tv *JobTaggedVersion) Copy() *JobTaggedVersion { + if tv == nil { + return nil + } + return &JobTaggedVersion{ + Name: tv.Name, + Description: tv.Description, + TaggedTime: tv.TaggedTime, + } } type JobUIConfig struct { @@ -4663,6 +4683,7 @@ func (j *Job) Copy() *Job { nj.Affinities = CopySliceAffinities(j.Affinities) nj.Multiregion = j.Multiregion.Copy() nj.UI = j.UI.Copy() + nj.TaggedVersion = j.TaggedVersion.Copy() if j.TaskGroups != nil { tgs := make([]*TaskGroup, len(j.TaskGroups)) @@ -4760,6 +4781,12 @@ func (j *Job) Validate() error { } } + if j.TaggedVersion != nil { + if len(j.TaggedVersion.Description) > MaxDescriptionCharacters { + mErr.Errors = append(mErr.Errors, fmt.Errorf("Tagged version description must be under 1000 characters, currently %d", len(j.TaggedVersion.Description))) + } + } + // Check for duplicate task groups taskGroups := make(map[string]int) for idx, tg := range j.TaskGroups { diff --git a/nomad/structs/structs_test.go b/nomad/structs/structs_test.go index 3f8a90f469b3..00d1f426f80d 100644 --- a/nomad/structs/structs_test.go +++ b/nomad/structs/structs_test.go @@ -397,6 +397,18 @@ func TestJob_Validate(t *testing.T) { "Task Group web should have an ephemeral disk object", }, }, + { + name: "TaggedVersion Description length", + job: &Job{ + Type: JobTypeService, + TaggedVersion: &JobTaggedVersion{ + Description: strings.Repeat("a", 1001), + }, + }, + expErr: []string{ + "Tagged version description must be under 1000 characters", + }, + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) {