Skip to content

Commit

Permalink
update events configured to watch only specific fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Surbhidongaonkar committed Dec 4, 2019
1 parent d8f10a6 commit e438ef5
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 56 deletions.
7 changes: 6 additions & 1 deletion config.yaml
Expand Up @@ -28,10 +28,15 @@ resources:
-
events:
- create
- update
- delete
- update
- error
updateSetting:
includeDiff: true
fields:
- status
- metadata
- spec
- name: statefulset
namespaces:
include:
Expand Down
22 changes: 19 additions & 3 deletions pkg/config/config.go
Expand Up @@ -29,6 +29,12 @@ const (
ShortNotify NotifType = "short"
// LongNotify for short events notification
LongNotify NotifType = "long"
// SpecUpdate for updates in spec
SpecUpdate FieldType = "spec"
// MetadataUpdate for updates in metadata
MetadataUpdate FieldType = "metadata"
// StatusUpdate for updates in status
StatusUpdate FieldType = "status"
)

// EventType to watch
Expand All @@ -43,6 +49,9 @@ var Notify = true
// NotifType to change notification type
type NotifType string

// FieldType to specify the resource fields for which to get notification
type FieldType string

// Config structure of configuration yaml file
type Config struct {
Resources []Resource
Expand All @@ -53,9 +62,16 @@ type Config struct {

// Resource contains resources to watch
type Resource struct {
Name string
Namespaces Namespaces
Events []EventType
Name string
Namespaces Namespaces
Events []EventType
UpdateSetting UpdateSetting `yaml:"updateSetting"`
}

//UpdateSetting struct defines updateEvent fields specification
type UpdateSetting struct {
Fields []FieldType
IncludeDiff bool `yaml:"includeDiff"`
}

// Namespaces contains namespaces to include and ignore
Expand Down
17 changes: 10 additions & 7 deletions pkg/controller/controller.go
Expand Up @@ -163,13 +163,16 @@ func sendEvent(obj, oldObj interface{}, c *config.Config, notifiers []notify.Not

// check for siginificant Update Events in objects
if eventType == config.UpdateEvent {
updateMsg := utils.Diff(oldObj, obj)
if len(updateMsg) > 0 {
event.Messages = append(event.Messages, updateMsg)
} else {
// skipping least significant update
log.Logger.Debug("skipping least significant Update event")
event.Skip = true
updatesetting, exists := utils.AllowedUpdateEventsMap[utils.KindNS{Resource: kind, Namespace: "all"}]
if exists {
updateMsg := utils.Diff(oldObj, obj, updatesetting)
if len(updateMsg) > 0 {
event.Messages = append(event.Messages, updateMsg)
} else {
// skipping least significant update
log.Logger.Debug("skipping least significant Update event")
event.Skip = true
}
}
}

Expand Down
59 changes: 20 additions & 39 deletions pkg/utils/cmp.go
@@ -1,48 +1,29 @@
package utils

import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"
"github.com/infracloudio/botkube/pkg/config"
)

// SpecDiffReporter is a simple custom reporter that only records differences
// detected in Object Spec during comparison.
type SpecDiffReporter struct {
path cmp.Path
diffs []string
}

// PushStep custom implements Reporter interface
func (r *SpecDiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}

// Report custom implements Reporter interface
func (r *SpecDiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
path := fmt.Sprintf("%#v", r.path)
if ok := strings.Contains(path, ".Spec."); ok {
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
// Diff provides differences between two objects spec
func Diff(x, y interface{}, updatesetting config.UpdateSetting) string {
msg := ""
for _, val := range updatesetting.Fields {
if val == config.SpecUpdate {
var r SpecDiffReporter
cmp.Equal(x, y, cmp.Reporter(&r))
msg = msg + r.String()
}
if val == config.MetadataUpdate {
var r MetadataDiffReporter
cmp.Equal(x, y, cmp.Reporter(&r))
msg = msg + r.String()
}
if val == config.StatusUpdate {
var r StatusDiffReporter
cmp.Equal(x, y, cmp.Reporter(&r))
msg = msg + r.String()
}
}
}

// PopStep custom implements Reporter interface
func (r *SpecDiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}

// String custom implements Reporter interface
func (r *SpecDiffReporter) String() string {
return strings.Join(r.diffs, "\n")
}

// Diff provides differences between two objects spec
func Diff(x, y interface{}) string {
var r SpecDiffReporter
cmp.Equal(x, y, cmp.Reporter(&r))
return r.String()
return msg
}
37 changes: 32 additions & 5 deletions pkg/utils/cmp_test.go
Expand Up @@ -3,12 +3,15 @@ package utils
import (
"fmt"
"testing"

"github.com/infracloudio/botkube/pkg/config"
)

// Object mocks kubernetes objects
type Object struct {
Spec Spec
Other Other
Spec Spec
Status Status
Other Other
}

// Other mocks fileds like MetaData, Status etc in kubernetes objects
Expand All @@ -21,6 +24,11 @@ type Spec struct {
Port int
}

// Status mocks ObjectStatus field in kubernetes object
type Status struct {
Replicas int
}

// ExpectedDiff struct to generate expected diff
type ExpectedDiff struct {
Path string
Expand All @@ -32,27 +40,46 @@ func TestDiff(t *testing.T) {
tests := map[string]struct {
old Object
new Object
update config.UpdateSetting
expected ExpectedDiff
}{
`Spec Diff`: {
old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}},
new: Object{Spec: Spec{Port: 83}, Other: Other{Foo: "bar"}},
update: config.UpdateSetting{Fields: []config.FieldType{config.SpecUpdate}, IncludeDiff: true},
expected: ExpectedDiff{
Path: "{utils.Object}.Spec.Port",
X: "81",
Y: "83",
},
},
`Non Spec Diff`: {
old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}},
new: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "boo"}},
old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}},
new: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "boo"}},
update: config.UpdateSetting{Fields: []config.FieldType{config.MetadataUpdate}, IncludeDiff: true},
expected: ExpectedDiff{},
},
`Status Diff`: {
old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}},
new: Object{Status: Status{Replicas: 2}, Other: Other{Foo: "bar"}},
update: config.UpdateSetting{Fields: []config.FieldType{config.StatusUpdate}, IncludeDiff: true},
expected: ExpectedDiff{
Path: "{utils.Object}.Status.Replicas",
X: "1",
Y: "2",
},
},
`Non Status Diff`: {
old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}},
new: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "boo"}},
update: config.UpdateSetting{Fields: []config.FieldType{config.StatusUpdate}, IncludeDiff: true},
expected: ExpectedDiff{},
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
if actual := Diff(test.old, test.new); actual != test.expected.MockDiff() {
if actual := Diff(test.old, test.new, test.update); actual != test.expected.MockDiff() {
t.Errorf("expected: %+v != actual: %+v\n", test.expected.MockDiff(), actual)
}
})
Expand Down
41 changes: 41 additions & 0 deletions pkg/utils/metadata_reporter.go
@@ -0,0 +1,41 @@
package utils

import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"
)

// MetadataDiffReporter is a simple custom reporter that only records differences
// detected in Object Spec during comparison.
type MetadataDiffReporter struct {
path cmp.Path
diffs []string
}

// PushStep custom implements Reporter interface
func (r *MetadataDiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}

// Report custom implements Reporter interface
func (r *MetadataDiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
path := fmt.Sprintf("%#v", r.path)
if ok := strings.Contains(path, ".Metadata."); ok {
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
}
}
}

// PopStep custom implements Reporter interface
func (r *MetadataDiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}

// String custom implements Reporter interface
func (r *MetadataDiffReporter) String() string {
return strings.Join(r.diffs, "\n")
}
41 changes: 41 additions & 0 deletions pkg/utils/spec_reporter.go
@@ -0,0 +1,41 @@
package utils

import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"
)

// SpecDiffReporter is a simple custom reporter that only records differences
// detected in Object Spec during comparison.
type SpecDiffReporter struct {
path cmp.Path
diffs []string
}

// PushStep custom implements Reporter interface
func (r *SpecDiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}

// Report custom implements Reporter interface
func (r *SpecDiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
path := fmt.Sprintf("%#v", r.path)
if ok := strings.Contains(path, ".Spec."); ok {
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
}
}
}

// PopStep custom implements Reporter interface
func (r *SpecDiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}

// String custom implements Reporter interface
func (r *SpecDiffReporter) String() string {
return strings.Join(r.diffs, "\n")
}
41 changes: 41 additions & 0 deletions pkg/utils/status_reporter.go
@@ -0,0 +1,41 @@
package utils

import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"
)

// StatusDiffReporter is a simple custom reporter that only records differences
// detected in Object Spec during comparison.
type StatusDiffReporter struct {
path cmp.Path
diffs []string
}

// PushStep custom implements Reporter interface
func (r *StatusDiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}

// Report custom implements Reporter interface
func (r *StatusDiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
path := fmt.Sprintf("%#v", r.path)
if ok := strings.Contains(path, ".Status."); ok {
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
}
}
}

// PopStep custom implements Reporter interface
func (r *StatusDiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}

// String custom implements Reporter interface
func (r *StatusDiffReporter) String() string {
return strings.Join(r.diffs, "\n")
}

0 comments on commit e438ef5

Please sign in to comment.