Commit 7e9ec7f3 authored by Tim Gross's avatar Tim Gross
Browse files

structs: add taskgroup networks and services to plan diffs

Adds a check for differences in `job.Diff` so that task group networks
and services, including new Consul connect stanzas, show up in the job
plan outputs.
parent 35d920fb
Showing with 668 additions and 0 deletions
+668 -0
......@@ -273,6 +273,16 @@ func (tg *TaskGroup) Diff(other *TaskGroup, contextual bool) (*TaskGroupDiff, er
diff.Objects = append(diff.Objects, uDiff)
}
// Network Resources diff
if nDiffs := networkResourceDiffs(tg.Networks, other.Networks, contextual); nDiffs != nil {
diff.Objects = append(diff.Objects, nDiffs...)
}
// Services diff
if sDiffs := serviceDiffs(tg.Services, other.Services, contextual); sDiffs != nil {
diff.Objects = append(diff.Objects, sDiffs...)
}
// Tasks diff
tasks, err := taskDiffs(tg.Tasks, other.Tasks, contextual)
if err != nil {
......@@ -579,6 +589,11 @@ func serviceDiff(old, new *Service, contextual bool) *ObjectDiff {
diff.Objects = append(diff.Objects, cDiffs...)
}
// Consul Connect diffs
if conDiffs := connectDiffs(old.Connect, new.Connect, contextual); conDiffs != nil {
diff.Objects = append(diff.Objects, conDiffs)
}
return diff
}
......@@ -704,6 +719,163 @@ func checkRestartDiff(old, new *CheckRestart, contextual bool) *ObjectDiff {
return diff
}
// connectDiffs returns the diff of two Consul connect objects. If contextual
// diff is enabled, all fields will be returned, even if no diff occurred.
func connectDiffs(old, new *ConsulConnect, contextual bool) *ObjectDiff {
diff := &ObjectDiff{Type: DiffTypeNone, Name: "ConsulConnect"}
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
if reflect.DeepEqual(old, new) {
return nil
} else if old == nil {
old = &ConsulConnect{}
diff.Type = DiffTypeAdded
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
} else if new == nil {
new = &ConsulConnect{}
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)
sidecarSvcDiff := connectSidecarServiceDiff(
old.SidecarService, new.SidecarService, contextual)
if sidecarSvcDiff != nil {
diff.Objects = append(diff.Objects, sidecarSvcDiff)
}
sidecarTaskDiff := sidecarTaskDiff(old.SidecarTask, new.SidecarTask, contextual)
if sidecarTaskDiff != nil {
diff.Objects = append(diff.Objects, sidecarTaskDiff)
}
return diff
}
// connectSidecarServiceDiff returns the diff of two ConsulSidecarService objects.
// If contextual diff is enabled, all fields will be returned, even if no diff occurred.
func connectSidecarServiceDiff(old, new *ConsulSidecarService, contextual bool) *ObjectDiff {
diff := &ObjectDiff{Type: DiffTypeNone, Name: "SidecarService"}
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
if reflect.DeepEqual(old, new) {
return nil
} else if old == nil {
old = &ConsulSidecarService{}
diff.Type = DiffTypeAdded
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
} else if new == nil {
new = &ConsulSidecarService{}
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)
consulProxyDiff := consulProxyDiff(old.Proxy, new.Proxy, contextual)
if consulProxyDiff != nil {
diff.Objects = append(diff.Objects, consulProxyDiff)
}
return diff
}
// sidecarTaskDiff returns the diff of two Task objects.
// If contextual diff is enabled, all fields will be returned, even if no diff occurred.
func sidecarTaskDiff(old, new *SidecarTask, contextual bool) *ObjectDiff {
diff := &ObjectDiff{Type: DiffTypeNone, Name: "SidecarTask"}
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
if reflect.DeepEqual(old, new) {
return nil
} else if old == nil {
old = &SidecarTask{}
diff.Type = DiffTypeAdded
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
} else if new == nil {
new = &SidecarTask{}
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, false)
// Config diff
if cDiff := configDiff(old.Config, new.Config, contextual); cDiff != nil {
diff.Objects = append(diff.Objects, cDiff)
}
// Resources diff
if rDiff := old.Resources.Diff(new.Resources, contextual); rDiff != nil {
diff.Objects = append(diff.Objects, rDiff)
}
// LogConfig diff
lDiff := primitiveObjectDiff(old.LogConfig, new.LogConfig, nil, "LogConfig", contextual)
if lDiff != nil {
diff.Objects = append(diff.Objects, lDiff)
}
return diff
}
// consulProxyDiff returns the diff of two ConsulProxy objects.
// If contextual diff is enabled, all fields will be returned, even if no diff occurred.
func consulProxyDiff(old, new *ConsulProxy, contextual bool) *ObjectDiff {
diff := &ObjectDiff{Type: DiffTypeNone, Name: "ConsulProxy"}
var oldPrimitiveFlat, newPrimitiveFlat map[string]string
if reflect.DeepEqual(old, new) {
return nil
} else if old == nil {
old = &ConsulProxy{}
diff.Type = DiffTypeAdded
newPrimitiveFlat = flatmap.Flatten(new, nil, true)
} else if new == nil {
new = &ConsulProxy{}
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)
consulUpstreamsDiff := primitiveObjectSetDiff(
interfaceSlice(old.Upstreams),
interfaceSlice(new.Upstreams),
nil, "ConsulUpstreams", contextual)
if consulUpstreamsDiff != nil {
diff.Objects = append(diff.Objects, consulUpstreamsDiff...)
}
// Config diff
if cDiff := configDiff(old.Config, new.Config, contextual); cDiff != nil {
diff.Objects = append(diff.Objects, cDiff)
}
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.
......
......@@ -2433,6 +2433,451 @@ func TestTaskGroupDiff(t *testing.T) {
},
},
},
{
// TaskGroup Services edited
Contextual: true,
Old: &TaskGroup{
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,
},
},
Connect: &ConsulConnect{
SidecarTask: &SidecarTask{
Name: "sidecar",
Driver: "docker",
Env: map[string]string{
"FOO": "BAR",
},
Config: map[string]interface{}{
"foo": "baz",
},
},
},
},
},
},
New: &TaskGroup{
Services: []*Service{
{
Name: "foo",
Checks: []*ServiceCheck{
{
Name: "foo",
Type: "tcp",
Command: "bar",
Path: "bar",
Protocol: "tcp",
Interval: 2 * time.Second,
Timeout: 2 * time.Second,
Header: map[string][]string{
"Foo": {"baz"},
},
},
},
Connect: &ConsulConnect{
SidecarService: &ConsulSidecarService{
Port: "http",
Proxy: &ConsulProxy{
Upstreams: []ConsulUpstream{
{
DestinationName: "foo",
LocalBindPort: 8000,
},
},
Config: map[string]interface{}{
"foo": "qux",
},
},
},
},
},
},
},
Expected: &TaskGroupDiff{
Type: DiffTypeEdited,
Objects: []*ObjectDiff{
{
Type: DiffTypeEdited,
Name: "Service",
Fields: []*FieldDiff{
{
Type: DiffTypeNone,
Name: "AddressMode",
Old: "",
New: "",
},
{
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: "AddressMode",
Old: "",
New: "",
},
{
Type: DiffTypeEdited,
Name: "Command",
Old: "foo",
New: "bar",
},
{
Type: DiffTypeNone,
Name: "GRPCService",
Old: "",
New: "",
},
{
Type: DiffTypeNone,
Name: "GRPCUseTLS",
Old: "false",
New: "false",
},
{
Type: DiffTypeNone,
Name: "InitialStatus",
Old: "",
New: "",
},
{
Type: DiffTypeEdited,
Name: "Interval",
Old: "1000000000",
New: "2000000000",
},
{
Type: DiffTypeNone,
Name: "Method",
Old: "",
New: "",
},
{
Type: DiffTypeNone,
Name: "Name",
Old: "foo",
New: "foo",
},
{
Type: DiffTypeEdited,
Name: "Path",
Old: "foo",
New: "bar",
},
{
Type: DiffTypeNone,
Name: "PortLabel",
Old: "",
New: "",
},
{
Type: DiffTypeEdited,
Name: "Protocol",
Old: "http",
New: "tcp",
},
{
Type: DiffTypeNone,
Name: "TLSSkipVerify",
Old: "false",
New: "false",
},
{
Type: DiffTypeNone,
Name: "TaskName",
Old: "",
New: "",
},
{
Type: DiffTypeEdited,
Name: "Timeout",
Old: "1000000000",
New: "2000000000",
},
{
Type: DiffTypeEdited,
Name: "Type",
Old: "http",
New: "tcp",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "Header",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "Foo[0]",
Old: "",
New: "baz",
},
},
},
},
},
{
Type: DiffTypeEdited,
Name: "ConsulConnect",
Fields: []*FieldDiff{
{
Type: DiffTypeNone,
Name: "Native",
Old: "false",
New: "false",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "SidecarService",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "Port",
Old: "",
New: "http",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "ConsulProxy",
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "ConsulUpstreams",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "DestinationName",
Old: "",
New: "foo",
},
{
Type: DiffTypeAdded,
Name: "LocalBindPort",
Old: "",
New: "8000",
},
},
},
{
Type: DiffTypeAdded,
Name: "Config",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "foo",
Old: "",
New: "qux",
},
},
},
},
},
},
},
{
Type: DiffTypeDeleted,
Name: "SidecarTask",
Fields: []*FieldDiff{
{
Type: DiffTypeDeleted,
Name: "Driver",
Old: "docker",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Env[FOO]",
Old: "BAR",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Name",
Old: "sidecar",
New: "",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeDeleted,
Name: "Config",
Fields: []*FieldDiff{
{
Type: DiffTypeDeleted,
Name: "foo",
Old: "baz",
New: "",
},
},
},
},
},
},
},
},
},
},
},
},
{
// TaskGroup Networks edited
Contextual: true,
Old: &TaskGroup{
Networks: Networks{
{
Device: "foo",
CIDR: "foo",
IP: "foo",
MBits: 100,
ReservedPorts: []Port{
{
Label: "foo",
Value: 80,
},
},
},
},
},
New: &TaskGroup{
Networks: Networks{
{
Device: "bar",
CIDR: "bar",
IP: "bar",
MBits: 200,
DynamicPorts: []Port{
{
Label: "bar",
To: 8081,
},
},
},
},
},
Expected: &TaskGroupDiff{
Type: DiffTypeEdited,
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "Network",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "MBits",
Old: "",
New: "200",
},
{
Type: DiffTypeNone,
Name: "Mode",
Old: "",
New: "",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "Dynamic Port",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "Label",
Old: "",
New: "bar",
},
{
Type: DiffTypeAdded,
Name: "To",
Old: "",
New: "8081",
},
},
},
},
},
{
Type: DiffTypeDeleted,
Name: "Network",
Fields: []*FieldDiff{
{
Type: DiffTypeDeleted,
Name: "MBits",
Old: "100",
New: "",
},
{
Type: DiffTypeNone,
Name: "Mode",
Old: "",
New: "",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeDeleted,
Name: "Static Port",
Fields: []*FieldDiff{
{
Type: DiffTypeDeleted,
Name: "Label",
Old: "foo",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "To",
Old: "0",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Value",
Old: "80",
New: "",
},
},
},
},
},
},
},
},
{
// Tasks edited
Old: &TaskGroup{
......@@ -4158,6 +4603,57 @@ func TestTaskDiff(t *testing.T) {
},
},
},
{
Name: "Service with Connect",
Old: &Task{
Services: []*Service{
{
Name: "foo",
},
},
},
New: &Task{
Services: []*Service{
{
Name: "foo",
Connect: &ConsulConnect{
SidecarService: &ConsulSidecarService{},
},
},
},
},
Expected: &TaskDiff{
Type: DiffTypeEdited,
Objects: []*ObjectDiff{
{
Type: DiffTypeEdited,
Name: "Service",
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "ConsulConnect",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "Native",
Old: "",
New: "false",
},
},
Objects: []*ObjectDiff{
{
Type: DiffTypeAdded,
Name: "SidecarService",
},
},
},
},
},
},
},
},
{
Name: "Service Checks edited",
Old: &Task{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment