diff --git a/.changelog/11400.txt b/.changelog/11400.txt new file mode 100644 index 000000000000..15557ab411e7 --- /dev/null +++ b/.changelog/11400.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: Improve `nomad job plan` output for `artifact` and `template` changes +``` diff --git a/nomad/structs/diff.go b/nomad/structs/diff.go index 845c37c5a520..d0f9e5bb2272 100644 --- a/nomad/structs/diff.go +++ b/nomad/structs/diff.go @@ -10,6 +10,14 @@ import ( "github.com/mitchellh/hashstructure" ) +// DiffableWithID defines an object that has a unique and stable value that can +// be used as an identifier when generating a diff. +type DiffableWithID interface { + // DiffID returns the value to use to match entities between the old and + // the new input. + DiffID() string +} + // DiffType denotes the type of a diff object. type DiffType string @@ -2419,11 +2427,20 @@ func primitiveObjectSetDiff(old, new []interface{}, filter []string, name string makeSet := func(objects []interface{}) map[string]interface{} { objMap := make(map[string]interface{}, len(objects)) for _, obj := range objects { - hash, err := hashstructure.Hash(obj, nil) - if err != nil { - panic(err) + var key string + + if diffable, ok := obj.(DiffableWithID); ok { + key = diffable.DiffID() } - objMap[fmt.Sprintf("%d", hash)] = obj + + if key == "" { + hash, err := hashstructure.Hash(obj, nil) + if err != nil { + panic(err) + } + key = fmt.Sprintf("%d", hash) + } + objMap[key] = obj } return objMap @@ -2433,10 +2450,11 @@ func primitiveObjectSetDiff(old, new []interface{}, filter []string, name string newSet := makeSet(new) var diffs []*ObjectDiff - for k, v := range oldSet { - // Deleted - if _, ok := newSet[k]; !ok { - diffs = append(diffs, primitiveObjectDiff(v, nil, filter, name, contextual)) + for k, oldObj := range oldSet { + newObj := newSet[k] + diff := primitiveObjectDiff(oldObj, newObj, filter, name, contextual) + if diff != nil { + diffs = append(diffs, diff) } } for k, v := range newSet { diff --git a/nomad/structs/diff_test.go b/nomad/structs/diff_test.go index 6410ce4af1dc..bfb2f960b22f 100644 --- a/nomad/structs/diff_test.go +++ b/nomad/structs/diff_test.go @@ -4459,7 +4459,7 @@ func TestTaskDiff(t *testing.T) { New: &Task{ Artifacts: []*TaskArtifact{ { - GetterSource: "foo", + GetterSource: "foo/bar", GetterOptions: map[string]string{ "foo": "bar", }, @@ -4482,6 +4482,18 @@ func TestTaskDiff(t *testing.T) { Expected: &TaskDiff{ Type: DiffTypeEdited, Objects: []*ObjectDiff{ + { + Type: DiffTypeEdited, + Name: "Artifact", + Fields: []*FieldDiff{ + { + Type: DiffTypeEdited, + Name: "GetterSource", + Old: "foo", + New: "foo/bar", + }, + }, + }, { Type: DiffTypeAdded, Name: "Artifact", @@ -6914,7 +6926,7 @@ func TestTaskDiff(t *testing.T) { { SourcePath: "foo", DestPath: "bar", - EmbeddedTmpl: "baz", + EmbeddedTmpl: "baz new", ChangeMode: "bam", ChangeSignal: "SIGHUP", Splay: 1, @@ -6934,6 +6946,18 @@ func TestTaskDiff(t *testing.T) { Expected: &TaskDiff{ Type: DiffTypeEdited, Objects: []*ObjectDiff{ + { + Type: DiffTypeEdited, + Name: "Template", + Fields: []*FieldDiff{ + { + Type: DiffTypeEdited, + Name: "EmbeddedTmpl", + Old: "baz", + New: "baz new", + }, + }, + }, { Type: DiffTypeAdded, Name: "Template", diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index a773ba1071c4..94b31e1eec9e 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -7479,6 +7479,11 @@ func (t *Template) Warnings() error { return mErr.ErrorOrNil() } +// DiffID fulfills the DiffableWithID interface. +func (t *Template) DiffID() string { + return t.DestPath +} + // AllocState records a single event that changes the state of the whole allocation type AllocStateField uint8 @@ -8120,6 +8125,11 @@ func (ta *TaskArtifact) GoString() string { return fmt.Sprintf("%+v", ta) } +// DiffID fulfills the DiffableWithID interface. +func (ta *TaskArtifact) DiffID() string { + return ta.RelativeDest +} + // hashStringMap appends a deterministic hash of m onto h. func hashStringMap(h hash.Hash, m map[string]string) { keys := make([]string, 0, len(m))