Skip to content

Commit

Permalink
added ability to monitor custom resources
Browse files Browse the repository at this point in the history
  • Loading branch information
anishrajan25 authored Dec 6, 2023
1 parent 0c20339 commit 87578c5
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 45 deletions.
21 changes: 21 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,27 @@ type Resource struct {
HPA bool `json:"hpa"`
Event bool `json:"event"`
CoreEvent bool `json:"coreevent"`

// Custom Resources to watch
Entity *CustomResource `yaml:"entity,omitempty"`
}

// CustomResource contains custom resource configuration
type CustomResource struct {
// Watch specifies whether to watch the resource or not
Watch bool `json:"watch"`

// ResourceIdentifier of the referenced object.
ResourceIdentifier string `json:"resource_identifier"`

// Compare Fields is list of fields to be compared between old and new objects
CompareFields []*CompareField `json:"compare_fields"`
}

// CompareField contains the name and path of the field to be compared
type CompareField struct {
Name string `json:"name"`
Path []string `json:"path"`
}

// Config struct contains kubewatch configuration
Expand Down
15 changes: 12 additions & 3 deletions examples/conf/kubewatch.conf.webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ handler:
flock:
url: ""
webhook:
url: "https://localhost:443"
tlsskip: false
cert: "/root/tls/ca.crt"
enabled: true
url: "https://webhook.site/c72961f3-da92-4bcc-9c48-07d543b6a2e1"
resource:
deployment: false
replicationcontroller: false
Expand All @@ -28,3 +27,13 @@ resource:
namespace: true
secret: false
ingress: false
entity:
watch: true
resourceidentifier: "entities.v1.entity.sumologic.com" # This needs to be in the format - `resource.group.com` or `resource.version.group.com`
comparefields:
- name: "state"
path: [ "status", "state" ]
- name: "retryAttempts"
path: [ "status", "retryAttempts" ]
- name: "scheduledDay"
path: [ "spec", "scheduleWeekDay" ]
8 changes: 8 additions & 0 deletions helm/kubewatch/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,12 @@ rules:
- get
- list
- watch
- apiGroups:
- entity.sumologic.com
resources:
- entities
verbs:
- get
- list
- watch
{{- end -}}
82 changes: 82 additions & 0 deletions pkg/controller/changes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package controller

import (
"encoding/json"
"reflect"

"github.com/bitnami-labs/kubewatch/config"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

type IChanges interface {
GetInitialValues() map[string]interface{}
GetCurrentValues() map[string]interface{}
String() string
}

type changes struct {
InitialValues map[string]interface{} `json:"initial_values"`
CurrentValues map[string]interface{} `json:"current_values"`
}

func (c *changes) GetInitialValues() map[string]interface{} {
return c.InitialValues
}

func (c *changes) GetCurrentValues() map[string]interface{} {
return c.CurrentValues
}

func (c *changes) String() string {
b, e := json.Marshal(c)
if e != nil {
return e.Error()
}

return string(b)
}

func GetChanges(oldObj, newObj runtime.Object, compareFields []*config.CompareField) IChanges {
oldObject := getUnstructuredObject(oldObj)
newObject := getUnstructuredObject(newObj)

if oldObject == nil || newObject == nil {
logrus.Errorf("Either the new object or old object is not a valid type to evaluate changes.")
return nil
}

return &changes{
InitialValues: getFieldValues(oldObject, compareFields),
CurrentValues: getFieldValues(newObject, compareFields),
}
}

func getUnstructuredObject(obj runtime.Object) *unstructured.Unstructured {
object, ok := obj.(*unstructured.Unstructured)
if !ok {
logrus.Errorf("Invalid object type - %s provided for evaluating changes.", reflect.TypeOf(obj))
return nil
}

return object
}

func getFieldValues(object *unstructured.Unstructured, compareFields []*config.CompareField) map[string]interface{} {
fieldValues := map[string]interface{}{}

for _, field := range compareFields {
fieldValues[field.Name] = getNestedString(object.Object, field.Path...)
}

return fieldValues
}

func getNestedString(obj map[string]interface{}, fields ...string) string {
val, found, err := unstructured.NestedString(obj, fields...)
if !found || err != nil {
return ""
}
return val
}
Loading

0 comments on commit 87578c5

Please sign in to comment.