Skip to content

Commit 80907c6

Browse files
aantnitisallgoodRobusta Runnerarikalon1
authored
add support for CRDs (#76)
* add support for CRDs * Fixed usage of ListWatch and WatchFunc for conf.CustomResources; removed unused fmt import from config/config.go * Added rbac style permissions for custom resources * Updated yaml files to use customresources; Added to readme Working with CRDs section * update chart version update chart image --------- Co-authored-by: Dima Chievtaiev <[email protected]> Co-authored-by: Robusta Runner <[email protected]> Co-authored-by: arik <[email protected]>
1 parent 01eee55 commit 80907c6

File tree

9 files changed

+165
-8
lines changed

9 files changed

+165
-8
lines changed

README.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# Latest image
1919

2020
```
21-
robustadev/kubewatch:v2.6
21+
robustadev/kubewatch:v2.8.0
2222
```
2323

2424
# Usage
@@ -75,6 +75,10 @@ You may also provide a values file instead:
7575
```yaml
7676
rbac:
7777
create: true
78+
customRoles:
79+
- apiGroups: ["monitoring.coreos.com"]
80+
resources: ["prometheusrules"]
81+
verbs: ["get", "list", "watch"]
7882
resourcesToWatch:
7983
deployment: false
8084
replicationcontroller: false
@@ -94,6 +98,10 @@ resourcesToWatch:
9498
ingress: false
9599
coreevent: false
96100
event: true
101+
customresources:
102+
- group: monitoring.coreos.com
103+
version: v1
104+
resource: prometheusrules
97105
slack:
98106
channel: '#YOUR_CHANNEL'
99107
token: 'xoxb-YOUR_TOKEN'
@@ -129,7 +137,7 @@ Once the Pod is running, you will start seeing Kubernetes events in your configu
129137

130138
![slack](./docs/slack.png)
131139

132-
To modify what notifications you get, update the `kubewatch` ConfigMap and turn on and off (true/false) resources:
140+
To modify what notifications you get, update the `kubewatch` ConfigMap and turn on and off (true/false) resources or configure any resource of your choosing with customresources (CRDs):
133141

134142
```
135143
resource:
@@ -151,6 +159,10 @@ resource:
151159
ingress: false
152160
coreevent: false
153161
event: true
162+
customresources:
163+
- group: monitoring.coreos.com
164+
version: v1
165+
resource: prometheusrules
154166
```
155167

156168
#### Working with RBAC
@@ -179,6 +191,51 @@ Then just create `pod` as usual with:
179191
$ kubectl create -f kubewatch.yaml
180192
```
181193

194+
#### Working with CRDs
195+
`kubewatch` can be configured to monitor Kubernetes Custom Resource Definitions (CRDs), allowing you to receive notifications when changes occur.
196+
To configure kubewatch to watch custom resources, you need to define the `customresources` section either in your values file or by using the `--set` flag with Helm commands.
197+
198+
Include the custom resource configuration in your values file:
199+
200+
```yaml
201+
customresources:
202+
- group: monitoring.coreos.com
203+
version: v1
204+
resource: prometheusrules
205+
```
206+
207+
Then deploy or upgrade `kubwatch` with `helm upgrade` or `helm install`
208+
209+
210+
Alternatively, you can pass this configuration directly using the `--set` flag:
211+
212+
```console
213+
helm install kubewatch robusta/kubewatch --set='rbac.create=true,slack.channel=#YOUR_CHANNEL,slack.token=xoxb-YOUR_TOKEN,resourcesToWatch.pod=true,resourcesToWatch.daemonset=true,customresources[0].group=monitoring.coreos.com,customresources[0].version=v1,customresources[0].resource=prometheusrules'
214+
```
215+
#### Custom RBAC roles
216+
After defining custom resources, make sure that kubewatch has the necessary RBAC permissions to access the custom resources you've configured. Without the appropriate permissions, `kubewatch` will not be able to monitor your custom resources, and you won't receive notifications for changes.
217+
218+
To grant these permissions, you can define custom RBAC roles using `customRoles` within the `rbac` section of your values file or by using the `--set` flag with Helm commands. This allows you to specify exactly which API groups, resources, and actions kubewatch should have access to.
219+
220+
Here’s how you can configure the necessary permissions to monitor your resources:
221+
```yaml
222+
rbac:
223+
create: true
224+
customRoles:
225+
- apiGroups: ["monitoring.coreos.com"]
226+
resources: ["prometheusrules"]
227+
verbs: ["get", "list", "watch"]
228+
```
229+
230+
Then deploy or upgrade `kubwatch` with `helm upgrade` or `helm install`
231+
232+
233+
Alternatively, you can pass this configuration directly using the `--set` flag:
234+
235+
```console
236+
helm install kubewatch robusta/kubewatch --set='rbac.create=true,slack.channel=#YOUR_CHANNEL,slack.token=xoxb-YOUR_TOKEN,customRoles[0].apiGroups={monitoring.coreos.com},customRoles[0].resources={prometheusrules},customRoles[0].verbs={get,list,watch}'
237+
```
238+
182239
### Local Installation
183240
#### Using go package installer:
184241

config/config.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ type Resource struct {
7373
CoreEvent bool `json:"coreevent"`
7474
}
7575

76-
// Config struct contains kubewatch configuration
76+
type CRD struct {
77+
Group string `json:"group"`
78+
Version string `json:"version"`
79+
Resource string `json:"resource"`
80+
}
81+
7782
type Config struct {
7883
// Handlers know how to send notifications to specific services.
7984
Handler Handler `json:"handler"`
@@ -83,6 +88,9 @@ type Config struct {
8388
// Resources to watch.
8489
Resource Resource `json:"resource"`
8590

91+
// CustomResources to Watch
92+
CustomResources []CRD `json:"customresources"`
93+
8694
// For watching specific namespace, leave it empty for watching all.
8795
// this config is ignored when watching namespaces
8896
Namespace string `json:"namespace,omitempty"`
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
customresources:
2+
- group: monitoring.coreos.com
3+
version: v1
4+
resource: prometheusrules

helm/kubewatch/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ maintainers: []
2323
name: kubewatch
2424
sources:
2525
- https://github.com/robusta-dev/kubewatch
26-
version: 3.3.10
26+
version: 3.4.0

helm/kubewatch/templates/clusterrole.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,9 @@ rules:
7676
- get
7777
- list
7878
- watch
79+
{{- range .Values.rbac.customRoles }}
80+
- apiGroups: {{ toYaml .apiGroups | nindent 4 }}
81+
resources: {{ toYaml .resources | nindent 4 }}
82+
verbs: {{ toYaml .verbs | nindent 4 }}
83+
{{- end }}
7984
{{- end -}}

helm/kubewatch/templates/configmap.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,5 @@ data:
4747
lark: {{- toYaml .Values.lark | nindent 8 }}
4848
{{- end }}
4949
resource: {{- toYaml .Values.resourcesToWatch | nindent 6 }}
50+
customresources: {{- toYaml .Values.customresources | nindent 6 }}
5051
namespace: {{ .Values.namespaceToWatch | quote }}

helm/kubewatch/values.yaml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extraDeploy: []
6262
##
6363
image:
6464
repository: robustadev/kubewatch
65-
tag: v2.6
65+
tag: v2.8.0
6666
## Specify a imagePullPolicy
6767
## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
6868
## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images
@@ -214,6 +214,15 @@ resourcesToWatch:
214214
job: false
215215
persistentvolume: false
216216
event: true
217+
218+
## @param customresources Define custom resources to watch for changes
219+
## Example:
220+
## customresources:
221+
## - group: monitoring.coreos.com
222+
## version: v1
223+
## resource: prometheusrules
224+
##
225+
customresources: []
217226
## @param command Override default container command (useful when using custom images)
218227
##
219228
command: []
@@ -439,11 +448,18 @@ initContainers: []
439448
sidecars: []
440449

441450
## @section RBAC parameters
442-
443-
## @param rbac.create Whether to create & use RBAC resources or not
444451
##
445452
rbac:
453+
## @param rbac.create Whether to create & use RBAC resources or not
446454
create: false
455+
## @param rbac.customRoles custom RBAC rules to be applied
456+
## Example:
457+
## customRoles:
458+
## - apiGroups: ["monitoring.coreos.com"]
459+
## resources: ["prometheusrules"]
460+
## verbs: ["get", "list", "watch"]
461+
##
462+
customRoles: []
447463
## Pods Service Account
448464
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
449465
## @param serviceAccount.create Specifies whether a ServiceAccount should be created

pkg/controller/controller.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package controller
1919
import (
2020
"context"
2121
"fmt"
22+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23+
"k8s.io/apimachinery/pkg/runtime/schema"
2224
"os"
2325
"os/signal"
2426
"reflect"
@@ -44,6 +46,7 @@ import (
4446
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
4547
"k8s.io/apimachinery/pkg/util/wait"
4648
"k8s.io/apimachinery/pkg/watch"
49+
"k8s.io/client-go/dynamic"
4750
"k8s.io/client-go/kubernetes"
4851
"k8s.io/client-go/rest"
4952
"k8s.io/client-go/tools/cache"
@@ -89,11 +92,14 @@ func objName(obj interface{}) string {
8992
// Start prepares watchers and run their controllers, then waits for process termination signals
9093
func Start(conf *config.Config, eventHandler handlers.Handler) {
9194
var kubeClient kubernetes.Interface
95+
var dynamicClient dynamic.Interface
9296

9397
if _, err := rest.InClusterConfig(); err != nil {
9498
kubeClient = utils.GetClientOutOfCluster()
99+
dynamicClient = utils.GetDynamicClientOutOfCluster()
95100
} else {
96101
kubeClient = utils.GetClient()
102+
dynamicClient = utils.GetDynamicClient()
97103
}
98104

99105
// User Configured Events
@@ -542,6 +548,36 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
542548
go c.Run(stopCh)
543549
}
544550

551+
for _, crd := range conf.CustomResources {
552+
informer := cache.NewSharedIndexInformer(
553+
&cache.ListWatch{
554+
ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) {
555+
return dynamicClient.Resource(schema.GroupVersionResource{
556+
Group: crd.Group,
557+
Version: crd.Version,
558+
Resource: crd.Resource,
559+
}).List(context.Background(), options)
560+
},
561+
WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) {
562+
return dynamicClient.Resource(schema.GroupVersionResource{
563+
Group: crd.Group,
564+
Version: crd.Version,
565+
Resource: crd.Resource,
566+
}).Watch(context.Background(), options)
567+
},
568+
},
569+
&unstructured.Unstructured{},
570+
0, //Skip resync
571+
cache.Indexers{},
572+
)
573+
574+
c := newResourceController(kubeClient, eventHandler, informer, crd.Resource, fmt.Sprintf("%s/%s", crd.Group, crd.Version))
575+
stopCh := make(chan struct{})
576+
defer close(stopCh)
577+
578+
go c.Run(stopCh)
579+
}
580+
545581
sigterm := make(chan os.Signal, 1)
546582
signal.Notify(sigterm, syscall.SIGTERM)
547583
signal.Notify(sigterm, syscall.SIGINT)

pkg/utils/k8sutil.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,27 @@ import (
1313
events_v1 "k8s.io/api/events/v1"
1414
rbac_v1beta1 "k8s.io/api/rbac/v1beta1"
1515
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"k8s.io/client-go/dynamic"
1617
"k8s.io/client-go/kubernetes"
1718
"k8s.io/client-go/rest"
1819
"k8s.io/client-go/tools/clientcmd"
1920
)
2021

21-
// GetClient returns a k8s clientset to the request from inside of cluster
22+
// GetDynamicClient returns a k8s dynamic clientset to the request from inside of cluster
23+
func GetDynamicClient() dynamic.Interface {
24+
config, err := rest.InClusterConfig()
25+
if err != nil {
26+
logrus.Fatalf("Can not get kubernetes config: %v", err)
27+
}
28+
29+
clientset, err := dynamic.NewForConfig(config)
30+
if err != nil {
31+
logrus.Fatalf("Can not create dynamic kubernetes client: %v", err)
32+
}
33+
34+
return clientset
35+
}
36+
2237
func GetClient() kubernetes.Interface {
2338
config, err := rest.InClusterConfig()
2439
if err != nil {
@@ -56,6 +71,21 @@ func GetClientOutOfCluster() kubernetes.Interface {
5671
return clientset
5772
}
5873

74+
// GetDynamicClientOutOfCluster returns a k8s dynamic clientset to the request from outside of cluster
75+
func GetDynamicClientOutOfCluster() dynamic.Interface {
76+
config, err := buildOutOfClusterConfig()
77+
if err != nil {
78+
logrus.Fatalf("Can not get kubernetes config: %v", err)
79+
}
80+
81+
clientset, err := dynamic.NewForConfig(config)
82+
if err != nil {
83+
logrus.Fatalf("Can not get kubernetes config: %v", err)
84+
}
85+
86+
return clientset
87+
}
88+
5989
// GetObjectMetaData returns metadata of a given k8s object
6090
func GetObjectMetaData(obj interface{}) (objectMeta meta_v1.ObjectMeta) {
6191

0 commit comments

Comments
 (0)