-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add exclusion rules to filter unwanted events #259
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -165,6 +165,64 @@ Open your browser to http://localhost:9090. | |
|
||
An example of a useful query is [rate(kubewatch_event_count[5m])](<http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(kubewatch_event_count%5B1m%5D)&g0.tab=0>) | ||
|
||
## Event filtering | ||
|
||
Events can be excluded from Sloop by adding `exclusionRules` to the config file: | ||
|
||
``` | ||
{ | ||
"defaultNamespace": "default", | ||
"defaultKind": "Pod", | ||
"defaultLookback": "1h", | ||
[...] | ||
"exclusionRules": { | ||
"_all": [ | ||
{"==": [ { "var": "metadata.namespace" }, "kube-system" ]} | ||
], | ||
"Pod": [ | ||
{"==": [ { "var": "metadata.name" }, "sloop-0" ]} | ||
], | ||
"Job": [ | ||
{"in": [ { "var": "metadata.name" }, [ "cron1", "cron3" ] ]} | ||
] | ||
} | ||
}` | ||
|
||
``` | ||
|
||
Adding rules can help to reduce resources consumed by Sloop and remove unwanted noise from the UI for events that are of no interest. | ||
|
||
### Limiting rules to specific kinds | ||
|
||
* Rules under the special key `_all` are evaluated against events for objects of any kind | ||
* Rules under any other key are evaluated only against objects whose kind matches the key, e.g. `Pod` only applies to pods, `Job` only applies to jobs etc. | ||
|
||
### Rule format and supported operations | ||
|
||
Rules should follow the [JsonLogic](https://jsonlogic.com) format and are evaluated against the json representation of the Kubernetes API object related to the event (see below). | ||
|
||
Available operators, such as `==` and `in` shown above, are documented [here](https://jsonlogic.com/operations.html). | ||
|
||
### Data available to rule logic | ||
|
||
Kubernetes API conventions for [objects](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#objects) require the following keys to exist in the json data for all resources, all of which can be referenced in rules: | ||
|
||
* `metadata` | ||
* `spec` | ||
* `status` | ||
|
||
Some commonly useful fields under the `metadata` [object](https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#ObjectMeta) are: | ||
|
||
* `name` | ||
* `namespace` | ||
* `labels` | ||
|
||
#### Type specific data | ||
|
||
Some resources contain additional type-specific fields, for example `PersistentVolumeClaimSpec` objects have fields named `selector` and `storageClassName`. | ||
|
||
Type specific fields for each object and their corresponding keys in the object json representation are documented in the [core API](https://pkg.go.dev/k8s.io/[email protected]/core/v1), e.g. for `PersistentVolumeClaimSpec` objects the documentation is [here](https://pkg.go.dev/k8s.io/[email protected]/core/v1#PersistentVolumeClaimSpec). | ||
|
||
## Contributing | ||
|
||
Refer to [CONTRIBUTING.md](CONTRIBUTING.md)<br> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,21 +81,107 @@ func Test_bigPicture(t *testing.T) { | |
masterURL := "url" | ||
kubeContext := "" // empty string makes things work | ||
enableGranularMetrics := true | ||
kw, err := NewKubeWatcherSource(kubeClient, outChan, resync, includeCrds, time.Duration(10*time.Second), masterURL, kubeContext, enableGranularMetrics) | ||
exclusionRules := map[string][]any{} | ||
|
||
kw, err := NewKubeWatcherSource(kubeClient, outChan, resync, includeCrds, time.Duration(10*time.Second), masterURL, kubeContext, enableGranularMetrics, exclusionRules) | ||
assert.NoError(t, err) | ||
|
||
// create namespace | ||
ns := "ns" | ||
_, err = kubeClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.FailNow() | ||
} | ||
|
||
// create first service | ||
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s1"}} | ||
_, err = kubeClient.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating service: %v\n", err) | ||
} | ||
|
||
// create second service | ||
svc = &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s2"}} | ||
_, err = kubeClient.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating service: %v\n", err) | ||
} | ||
|
||
// await events | ||
result1 := <-outChan | ||
result2 := <-outChan | ||
result3 := <-outChan | ||
|
||
assert.Contains(t, result1.Payload, `"name":"ns"`) | ||
assert.Contains(t, result2.Payload, `"name":"s1"`) | ||
assert.Contains(t, result3.Payload, `"name":"s2"`) | ||
|
||
kw.Stop() | ||
} | ||
|
||
// As above but specify non-default exclusion rules to exclude events for service named s2 | ||
func Test_bigPictureWithExclusionRules(t *testing.T) { | ||
newCrdClient = newTestCrdClient(reactionListOfOne) // force startCustomInformers() to use a fake clientset | ||
|
||
kubeClient := kubernetesFake.NewSimpleClientset() | ||
outChan := make(chan typed.KubeWatchResult, 5) | ||
resync := 30 * time.Minute | ||
includeCrds := true | ||
masterURL := "url" | ||
kubeContext := "" // empty string makes things work | ||
enableGranularMetrics := true | ||
exclusionRules := map[string][]any{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we also add a test where exclusionRules are not provided, i.e. uses the default value of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added separate tests for default and non-default exclusion rules |
||
"_all": []any{ | ||
map[string]any{ | ||
"==": []any{ | ||
map[string]any{ | ||
"var": "metadata.name", | ||
}, | ||
"s2", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
kw, err := NewKubeWatcherSource(kubeClient, outChan, resync, includeCrds, time.Duration(10*time.Second), masterURL, kubeContext, enableGranularMetrics, exclusionRules) | ||
assert.NoError(t, err) | ||
|
||
// create service and await corresponding event | ||
// create namespace | ||
ns := "ns" | ||
_, err = kubeClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.FailNow() | ||
} | ||
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s"}} | ||
|
||
// create first service | ||
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s1"}} | ||
_, err = kubeClient.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating service: %v\n", err) | ||
} | ||
|
||
// create second service, corresponding event should be excluded by exclusion rule | ||
svc = &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s2"}} | ||
_, err = kubeClient.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating service: %v\n", err) | ||
} | ||
|
||
// create third service | ||
svc = &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "s3"}} | ||
_, err = kubeClient.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating service: %v\n", err) | ||
} | ||
_ = <-outChan | ||
|
||
// await events | ||
result1 := <-outChan | ||
result2 := <-outChan | ||
result3 := <-outChan | ||
|
||
assert.Contains(t, result1.Payload, `"name":"ns"`) | ||
assert.Contains(t, result2.Payload, `"name":"s1"`) | ||
assert.Contains(t, result3.Payload, `"name":"s3"`) // s2 should've been excluded so expect s3 | ||
|
||
kw.Stop() | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add err check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done