Skip to content
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 rbac for CRDs #82

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ resourcesToWatch:
ingress: false
coreevent: false
event: true
customresources:
- group: monitoring.coreos.com
version: v1
resource: prometheusrules
slack:
channel: '#YOUR_CHANNEL'
token: 'xoxb-YOUR_TOKEN'
Expand Down Expand Up @@ -129,7 +133,7 @@ Once the Pod is running, you will start seeing Kubernetes events in your configu

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

To modify what notifications you get, update the `kubewatch` ConfigMap and turn on and off (true/false) resources:
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):

```
resource:
Expand All @@ -151,6 +155,10 @@ resource:
ingress: false
coreevent: false
event: true
customresources:
- group: monitoring.coreos.com
version: v1
resource: prometheusrules
```

#### Working with RBAC
Expand Down
10 changes: 9 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ type Resource struct {
CoreEvent bool `json:"coreevent"`
}

// Config struct contains kubewatch configuration
type CRD struct {
Group string `json:"group"`
Version string `json:"version"`
Resource string `json:"resource"`
}

type Config struct {
// Handlers know how to send notifications to specific services.
Handler Handler `json:"handler"`
Expand All @@ -83,6 +88,9 @@ type Config struct {
// Resources to watch.
Resource Resource `json:"resource"`

// CustomResources to Watch
CustomResources []CRD `json:"customresources"`

// For watching specific namespace, leave it empty for watching all.
// this config is ignored when watching namespaces
Namespace string `json:"namespace,omitempty"`
Expand Down
4 changes: 4 additions & 0 deletions examples/conf/kubewatch.conf.crd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
customresources:
- group: monitoring.coreos.com
version: v1
resource: prometheusrules
5 changes: 5 additions & 0 deletions helm/kubewatch/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,9 @@ rules:
- get
- list
- watch
{{- range .Values.rbac.customRules }}
- apiGroups: {{ toYaml .apiGroups | nindent 4 }}
resources: {{ toYaml .resources | nindent 4 }}
verbs: {{ toYaml .verbs | nindent 4 }}
{{- end }}
{{- end -}}
36 changes: 36 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package controller
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"os"
"os/signal"
"reflect"
Expand All @@ -44,6 +46,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
Expand Down Expand Up @@ -89,11 +92,14 @@ func objName(obj interface{}) string {
// Start prepares watchers and run their controllers, then waits for process termination signals
func Start(conf *config.Config, eventHandler handlers.Handler) {
var kubeClient kubernetes.Interface
var dynamicClient dynamic.Interface

if _, err := rest.InClusterConfig(); err != nil {
kubeClient = utils.GetClientOutOfCluster()
dynamicClient = utils.GetDynamicClientOutOfCluster()
} else {
kubeClient = utils.GetClient()
dynamicClient = utils.GetDynamicClient()
}

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

for _, crd := range conf.CustomResources {
informer := cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) {
return dynamicClient.Resource(schema.GroupVersionResource{
Group: crd.Group,
Version: crd.Version,
Resource: crd.Resource,
}).List(context.Background(), options)
},
WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) {
return dynamicClient.Resource(schema.GroupVersionResource{
Group: crd.Group,
Version: crd.Version,
Resource: crd.Resource,
}).Watch(context.Background(), options)
},
},
&unstructured.Unstructured{},
0, //Skip resync
cache.Indexers{},
)

c := newResourceController(kubeClient, eventHandler, informer, crd.Resource, fmt.Sprintf("%s/%s", crd.Group, crd.Version))
stopCh := make(chan struct{})
defer close(stopCh)

go c.Run(stopCh)
}

sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGTERM)
signal.Notify(sigterm, syscall.SIGINT)
Expand Down
32 changes: 31 additions & 1 deletion pkg/utils/k8sutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,27 @@ import (
events_v1 "k8s.io/api/events/v1"
rbac_v1beta1 "k8s.io/api/rbac/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

// GetClient returns a k8s clientset to the request from inside of cluster
// GetDynamicClient returns a k8s dynamic clientset to the request from inside of cluster
func GetDynamicClient() dynamic.Interface {
config, err := rest.InClusterConfig()
if err != nil {
logrus.Fatalf("Can not get kubernetes config: %v", err)
}

clientset, err := dynamic.NewForConfig(config)
if err != nil {
logrus.Fatalf("Can not create dynamic kubernetes client: %v", err)
}

return clientset
}

func GetClient() kubernetes.Interface {
config, err := rest.InClusterConfig()
if err != nil {
Expand Down Expand Up @@ -56,6 +71,21 @@ func GetClientOutOfCluster() kubernetes.Interface {
return clientset
}

// GetDynamicClientOutOfCluster returns a k8s dynamic clientset to the request from outside of cluster
func GetDynamicClientOutOfCluster() dynamic.Interface {
config, err := buildOutOfClusterConfig()
if err != nil {
logrus.Fatalf("Can not get kubernetes config: %v", err)
}

clientset, err := dynamic.NewForConfig(config)
if err != nil {
logrus.Fatalf("Can not get kubernetes config: %v", err)
}

return clientset
}

// GetObjectMetaData returns metadata of a given k8s object
func GetObjectMetaData(obj interface{}) (objectMeta meta_v1.ObjectMeta) {

Expand Down
Loading