Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag and Untag job versions #23863

Open
wants to merge 16 commits into
base: epic/23794-golden-versions
Choose a base branch
from

Conversation

philrenaud
Copy link
Contributor

@philrenaud philrenaud commented Aug 25, 2024

via curl:

Adds a tag to Version 3:

curl -X PUT localhost:4646/v1/job/difftester/versions/testabc/tag -H "Content-Type: application/json" -d '{"Version": "3", "Tag": {"Name": "Foo", "Description": "Bar"}}'

Removes the tag:

curl -X DELETE localhost:4646/v1/job/difftester/versions/testabc/tag -H "Content-Type: application/json"

via Nomad CLI:

Adds a tag to Version 0:

nomad job tag apply \
  -version=0 \
  -name="Foo" \
  -description="Bar baz" \
fails_every_10

Adds a tag to the latest/current version:

nomad job tag apply -name=foo -description=bar difftester

Removes a tag:

nomad job tag unset -name=foo fails_every_10

Copy link

github-actions bot commented Aug 25, 2024

Ember Test Audit comparison

epic/23794-golden-versions 482fe55 change
passes 1578 1578 0
failures 0 0 0
flaky 0 0 0
duration 12m 05s 720ms 11m 56s 768ms -08s 952ms

Copy link
Member

@gulducat gulducat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks pretty good! few comments for ye

api/jobs.go Outdated Show resolved Hide resolved
s.parseWriteRequest(req, &rpcArgs.WriteRequest)

var out structs.JobTagResponse
if err := s.agent.RPC("Job.TagVersion", &rpcArgs, &out); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two httpserver methods are almost identical except for the RPC that they call, so you could save a decent little bit of duplicate code by moving the logic into the main jobTagVersion method instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up splitting these up a bit more — the differences started compounding (unset doesn't get version passed in now that we go by tag name; they both get their own structs for req/resp, etc.)

Not opposed to having a single method to handle these but they look to me like they should be separated currently

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This did in fact end up being a fence I straddled and continue to straddle — see "request for reviewers" code comment)

command/agent/job_endpoint.go Outdated Show resolved Hide resolved
command/agent/job_endpoint.go Outdated Show resolved Hide resolved
command/job_tag.go Outdated Show resolved Hide resolved
command/job_tag.go Outdated Show resolved Hide resolved
nomad/structs/structs.go Outdated Show resolved Hide resolved
website/content/docs/operations/metrics-reference.mdx Outdated Show resolved Hide resolved
nomad/structs/structs.go Outdated Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
api/jobs.go Outdated Show resolved Hide resolved
command/agent/job_endpoint.go Show resolved Hide resolved
nomad/job_endpoint.go Outdated Show resolved Hide resolved
nomad/job_endpoint.go Show resolved Hide resolved
command/agent/job_endpoint.go Outdated Show resolved Hide resolved
command/agent/job_endpoint.go Outdated Show resolved Hide resolved
command/job_tag.go Outdated Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
Copy link
Member

@tgross tgross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great @philrenaud!

nomad/state/state_store.go Outdated Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
command/job_tag.go Outdated Show resolved Hide resolved
api/jobs.go Outdated Show resolved Hide resolved
Copy link
Member

@tgross tgross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

I've left a couple last items but once you've resolved those this is good-to-merge.

nomad/state/state_store.go Show resolved Hide resolved
nomad/state/state_store.go Outdated Show resolved Hide resolved
Copy link
Member

@gulducat gulducat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mostly easy stuff, couple of concerns for your consideration!


// parseVersion parses the version flag and returns the index, whether it
// was set and potentially an error during parsing.
func parseVersion(input string) (uint64, bool, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't appear to be used; I suspect it was orphaned here when the version str->int logic was moved to command

Comment on lines +117 to +129
jobID, namespace, err := c.JobIDByPrefix(client, jobIDPrefix, nil)
if err != nil {
c.Ui.Error(err.Error())
return 1
}

// If the version is not provided, get the "active" version of the job
var versionInt uint64
if versionStr == "" {
q := &api.QueryOptions{
Namespace: namespace,
}
latestVersion, _, err := client.Jobs().Info(job, q)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't this be a single call? or is it two so that users can provide just a prefix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because versions can be 0, we need to query in order to have a TagVersion API that's both ergonomic and unambiguous.

Comment on lines +45 to +46
// err := state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, v0)
// must.NoError(t, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vestigial

func (c *JobTagUnsetCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
// "-version": complete.PredictNothing,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vestigial

return j, nil
}
}
return nil, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my nil pointer sense is tingling! to me nil, nil return for (*pointer, error) is a capital offense.

shouldn't it be an error if they asked for a tag by name, but no such tag exists?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the single-object state store methods return nil, nil on non-existing objects, rather than some kind of NotFound error.

Comment on lines +4972 to +4980
latestJob, err := s.JobByID(nil, namespace, jobID)
if err != nil {
return err
}
if versionCopy.Version == latestJob.Version {
if err := txn.Insert("jobs", versionCopy); err != nil {
return err
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sure hope that versionCopy and latestJob are otherwise totally identical, since this replaces the latter with the former in the "jobs" table.

Copy link
Member

@tgross tgross Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

job and latestJob are pointers to the exact same struct, so versionCopy is a copy of job that for safe upsert that needs to be done to any table where we have that pointer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants