Add service diff
This commit is contained in:
parent
967011e25c
commit
59e244d18e
|
@ -388,6 +388,11 @@ func (t *Task) Diff(other *Task, contextual bool) (*TaskDiff, error) {
|
|||
diff.Objects = append(diff.Objects, diffs...)
|
||||
}
|
||||
|
||||
// Services diff
|
||||
if sDiffs := serviceDiffs(t.Services, other.Services, contextual); sDiffs != nil {
|
||||
diff.Objects = append(diff.Objects, sDiffs...)
|
||||
}
|
||||
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
|
@ -454,6 +459,133 @@ func (t TaskDiffs) Len() int { return len(t) }
|
|||
func (t TaskDiffs) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t TaskDiffs) Less(i, j int) bool { return t[i].Name < t[j].Name }
|
||||
|
||||
// serviceDiff returns the diff of two service objects. If contextual diff is
|
||||
// enabled, all fields will be returned, even if no diff occured.
|
||||
func serviceDiff(old, new *Service, contextual bool) *ObjectDiff {
|
||||
diff := &ObjectDiff{Type: DiffTypeNone, Name: "Service"}
|
||||
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
|
||||
|
||||
if reflect.DeepEqual(old, new) {
|
||||
return nil
|
||||
} else if old == nil {
|
||||
old = &Service{}
|
||||
diff.Type = DiffTypeAdded
|
||||
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
|
||||
} else if new == nil {
|
||||
new = &Service{}
|
||||
diff.Type = DiffTypeDeleted
|
||||
oldPrimitiveFlat = flatmap.Flatten(old, nil, true)
|
||||
} else {
|
||||
diff.Type = DiffTypeEdited
|
||||
oldPrimitiveFlat = flatmap.Flatten(old, nil, true)
|
||||
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
|
||||
}
|
||||
|
||||
// Diff the primitive fields.
|
||||
diff.Fields = fieldDiffs(oldPrimitiveFlat, newPrimitiveFlat, contextual)
|
||||
|
||||
// Checks diffs
|
||||
if cDiffs := serviceCheckDiffs(old.Checks, new.Checks, contextual); cDiffs != nil {
|
||||
diff.Objects = append(diff.Objects, cDiffs...)
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
// serviceDiffs diffs a set of services. If contextual diff is enabled, unchanged
|
||||
// fields within objects nested in the tasks will be returned.
|
||||
func serviceDiffs(old, new []*Service, contextual bool) []*ObjectDiff {
|
||||
oldMap := make(map[string]*Service, len(old))
|
||||
newMap := make(map[string]*Service, len(new))
|
||||
for _, o := range old {
|
||||
oldMap[o.Name] = o
|
||||
}
|
||||
for _, n := range new {
|
||||
newMap[n.Name] = n
|
||||
}
|
||||
|
||||
var diffs []*ObjectDiff
|
||||
for name, oldService := range oldMap {
|
||||
// Diff the same, deleted and edited
|
||||
if diff := serviceDiff(oldService, newMap[name], contextual); diff != nil {
|
||||
diffs = append(diffs, diff)
|
||||
}
|
||||
}
|
||||
|
||||
for name, newService := range newMap {
|
||||
// Diff the added
|
||||
if old, ok := oldMap[name]; !ok {
|
||||
if diff := serviceDiff(old, newService, contextual); diff != nil {
|
||||
diffs = append(diffs, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(ObjectDiffs(diffs))
|
||||
return diffs
|
||||
}
|
||||
|
||||
// serviceCheckDiff returns the diff of two service check objects. If contextual
|
||||
// diff is enabled, all fields will be returned, even if no diff occured.
|
||||
func serviceCheckDiff(old, new *ServiceCheck, contextual bool) *ObjectDiff {
|
||||
diff := &ObjectDiff{Type: DiffTypeNone, Name: "Check"}
|
||||
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
|
||||
|
||||
if reflect.DeepEqual(old, new) {
|
||||
return nil
|
||||
} else if old == nil {
|
||||
old = &ServiceCheck{}
|
||||
diff.Type = DiffTypeAdded
|
||||
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
|
||||
} else if new == nil {
|
||||
new = &ServiceCheck{}
|
||||
diff.Type = DiffTypeDeleted
|
||||
oldPrimitiveFlat = flatmap.Flatten(old, nil, true)
|
||||
} else {
|
||||
diff.Type = DiffTypeEdited
|
||||
oldPrimitiveFlat = flatmap.Flatten(old, nil, true)
|
||||
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
|
||||
}
|
||||
|
||||
// Diff the primitive fields.
|
||||
diff.Fields = fieldDiffs(oldPrimitiveFlat, newPrimitiveFlat, contextual)
|
||||
return diff
|
||||
}
|
||||
|
||||
// serviceCheckDiffs diffs a set of service checks. If contextual diff is
|
||||
// enabled, unchanged fields within objects nested in the tasks will be
|
||||
// returned.
|
||||
func serviceCheckDiffs(old, new []*ServiceCheck, contextual bool) []*ObjectDiff {
|
||||
oldMap := make(map[string]*ServiceCheck, len(old))
|
||||
newMap := make(map[string]*ServiceCheck, len(new))
|
||||
for _, o := range old {
|
||||
oldMap[o.Name] = o
|
||||
}
|
||||
for _, n := range new {
|
||||
newMap[n.Name] = n
|
||||
}
|
||||
|
||||
var diffs []*ObjectDiff
|
||||
for name, oldService := range oldMap {
|
||||
// Diff the same, deleted and edited
|
||||
if diff := serviceCheckDiff(oldService, newMap[name], contextual); diff != nil {
|
||||
diffs = append(diffs, diff)
|
||||
}
|
||||
}
|
||||
|
||||
for name, newService := range newMap {
|
||||
// Diff the added
|
||||
if old, ok := oldMap[name]; !ok {
|
||||
if diff := serviceCheckDiff(old, newService, contextual); diff != nil {
|
||||
diffs = append(diffs, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(ObjectDiffs(diffs))
|
||||
return diffs
|
||||
}
|
||||
|
||||
// Diff returns a diff of two resource objects. If contextual diff is enabled,
|
||||
// non-changed fields will still be returned.
|
||||
func (r *Resources) Diff(other *Resources, contextual bool) *ObjectDiff {
|
||||
|
|
|
@ -2263,6 +2263,452 @@ func TestTaskDiff(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Services edited (no checks)
|
||||
Old: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
PortLabel: "foo",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
PortLabel: "bar",
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
PortLabel: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
New: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "bar",
|
||||
PortLabel: "bar",
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
PortLabel: "baz2",
|
||||
},
|
||||
{
|
||||
Name: "bam",
|
||||
PortLabel: "bam",
|
||||
},
|
||||
},
|
||||
},
|
||||
Expected: &TaskDiff{
|
||||
Type: DiffTypeEdited,
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Service",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "PortLabel",
|
||||
Old: "baz",
|
||||
New: "baz2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Service",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Name",
|
||||
Old: "",
|
||||
New: "bam",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "PortLabel",
|
||||
Old: "",
|
||||
New: "bam",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Service",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Name",
|
||||
Old: "foo",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "PortLabel",
|
||||
Old: "foo",
|
||||
New: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Services edited (no checks) with context
|
||||
Contextual: true,
|
||||
Old: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
PortLabel: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
New: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
PortLabel: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
Expected: &TaskDiff{
|
||||
Type: DiffTypeEdited,
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Service",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Name",
|
||||
Old: "foo",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "PortLabel",
|
||||
Old: "foo",
|
||||
New: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Service Checks edited
|
||||
Old: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Checks: []*ServiceCheck{
|
||||
{
|
||||
Name: "foo",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
New: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Checks: []*ServiceCheck{
|
||||
{
|
||||
Name: "bar",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
Type: "tcp",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "bam",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Expected: &TaskDiff{
|
||||
Type: DiffTypeEdited,
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Service",
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Check",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Type",
|
||||
Old: "http",
|
||||
New: "tcp",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Check",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Command",
|
||||
Old: "",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Interval",
|
||||
Old: "",
|
||||
New: "1000000000",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Name",
|
||||
Old: "",
|
||||
New: "bam",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Path",
|
||||
Old: "",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Protocol",
|
||||
Old: "",
|
||||
New: "http",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Timeout",
|
||||
Old: "",
|
||||
New: "1000000000",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Type",
|
||||
Old: "",
|
||||
New: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Check",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Command",
|
||||
Old: "foo",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Interval",
|
||||
Old: "1000000000",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Name",
|
||||
Old: "foo",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Path",
|
||||
Old: "foo",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Protocol",
|
||||
Old: "http",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Timeout",
|
||||
Old: "1000000000",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Type",
|
||||
Old: "http",
|
||||
New: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Service Checks edited with context
|
||||
Contextual: true,
|
||||
Old: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Checks: []*ServiceCheck{
|
||||
{
|
||||
Name: "foo",
|
||||
Type: "http",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
New: &Task{
|
||||
Services: []*Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Checks: []*ServiceCheck{
|
||||
{
|
||||
Name: "foo",
|
||||
Type: "tcp",
|
||||
Command: "foo",
|
||||
Args: []string{"foo"},
|
||||
Path: "foo",
|
||||
Protocol: "http",
|
||||
Interval: 1 * time.Second,
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Expected: &TaskDiff{
|
||||
Type: DiffTypeEdited,
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Service",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Name",
|
||||
Old: "foo",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "PortLabel",
|
||||
Old: "",
|
||||
New: "",
|
||||
},
|
||||
},
|
||||
Objects: []*ObjectDiff{
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Check",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Command",
|
||||
Old: "foo",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Interval",
|
||||
Old: "1000000000",
|
||||
New: "1000000000",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Name",
|
||||
Old: "foo",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Path",
|
||||
Old: "foo",
|
||||
New: "foo",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Protocol",
|
||||
Old: "http",
|
||||
New: "http",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeNone,
|
||||
Name: "Timeout",
|
||||
Old: "1000000000",
|
||||
New: "1000000000",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeEdited,
|
||||
Name: "Type",
|
||||
Old: "http",
|
||||
New: "tcp",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
|
|
Loading…
Reference in New Issue