通过discovery client简化informer使用
2021-12-24 本文已影响0人
wwq2020
背景
有时候我们需要建立多个gvr的informer,需要类似的代码写很多遍
解决方案
可以通过discovery client获取到支持list,watch的gvr批量创建informer,简化使用
package main
import (
"fmt"
"sync"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/dynamic/dynamicinformer"
k8sscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"stash.weimob.com/devops/go_common/app"
)
func main() {
restConfig := &rest.Config{
Host: "yourhost",
BearerToken: "yourtoken",
}
discoverClientSet := discovery.NewDiscoveryClientForConfigOrDie(restConfig)
dynamicClient := dynamic.NewForConfigOrDie(restConfig)
informer := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 0)
preferredResources, err := discoverClientSet.ServerPreferredResources()
if err != nil {
panic(err)
}
gvrs := make(map[schema.GroupVersionResource][]string)
for _, each := range preferredResources {
gv, err := schema.ParseGroupVersion(each.GroupVersion)
if err != nil {
panic(err)
}
for _, resource := range each.APIResources {
gvrs[schema.GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: resource.Name}] = resource.Verbs
}
}
m := make(map[schema.GroupVersionKind]map[string]map[string]runtime.Unstructured)
var lock sync.Mutex
eventHandler := cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
raw := obj.(runtime.Unstructured)
gvk := raw.GetObjectKind().GroupVersionKind()
lock.Lock()
defer lock.Unlock()
metaInfo, err := meta.Accessor(obj)
if err != nil {
panic(err)
}
gvkM, exist := m[gvk]
if !exist {
gvkM = make(map[string]map[string]runtime.Unstructured)
m[gvk] = gvkM
}
namespace := metaInfo.GetNamespace()
namesapceM, exist := gvkM[namespace]
if !exist {
namesapceM = make(map[string]runtime.Unstructured)
gvkM[namespace] = namesapceM
}
name := metaInfo.GetName()
namesapceM[name] = raw
},
UpdateFunc: func(oldObj, newObj interface{}) {
lock.Lock()
defer lock.Unlock()
oldRaw := oldObj.(runtime.Unstructured)
oldGvk := oldRaw.GetObjectKind().GroupVersionKind()
oldMetaInfo, err := meta.Accessor(oldObj)
if err != nil {
panic(err)
}
oldGvkM, exist := m[oldGvk]
if !exist {
oldGvkM = make(map[string]map[string]runtime.Unstructured)
m[oldGvk] = oldGvkM
}
oldNamespace := oldMetaInfo.GetNamespace()
oldNamesapceM, exist := oldGvkM[oldNamespace]
if !exist {
oldNamesapceM = make(map[string]runtime.Unstructured)
oldGvkM[oldNamespace] = oldNamesapceM
}
oldName := oldMetaInfo.GetName()
delete(oldNamesapceM, oldName)
newRaw := newObj.(runtime.Unstructured)
newGvk := newRaw.GetObjectKind().GroupVersionKind()
newMetaInfo, err := meta.Accessor(newObj)
if err != nil {
panic(err)
}
newGvkM, exist := m[newGvk]
if !exist {
newGvkM = make(map[string]map[string]runtime.Unstructured)
m[newGvk] = newGvkM
}
newNamespace := newMetaInfo.GetNamespace()
newNamesapceM, exist := newGvkM[newNamespace]
if !exist {
newNamesapceM = make(map[string]runtime.Unstructured)
newGvkM[newNamespace] = newNamesapceM
}
newName := newMetaInfo.GetName()
newNamesapceM[newName] = newRaw
},
DeleteFunc: func(obj interface{}) {
lock.Lock()
defer lock.Unlock()
oldRaw := obj.(runtime.Unstructured)
oldGvk := oldRaw.GetObjectKind().GroupVersionKind()
oldMetaInfo, err := meta.Accessor(obj)
if err != nil {
panic(err)
}
oldGvkM, exist := m[oldGvk]
if !exist {
oldGvkM = make(map[string]map[string]runtime.Unstructured)
m[oldGvk] = oldGvkM
}
oldNamespace := oldMetaInfo.GetNamespace()
oldNamesapceM, exist := oldGvkM[oldNamespace]
if !exist {
oldNamesapceM = make(map[string]runtime.Unstructured)
oldGvkM[oldNamespace] = oldNamesapceM
}
oldName := oldMetaInfo.GetName()
delete(oldNamesapceM, oldName)
},
}
for gvr, verbs := range gvrs {
if !hasListWatch(verbs) {
continue
}
i := informer.ForResource(gvr).Informer()
i.AddEventHandler(eventHandler)
fmt.Println(verbs, gvr.String())
}
informer.Start(app.Done())
informer.WaitForCacheSync(app.Done())
pod := &corev1.Pod{}
getter := func(namespace, name string, dest runtime.Object) {
kinds, _, err := k8sscheme.Scheme.ObjectKinds(pod)
if err != nil {
panic(err)
}
kind := kinds[0]
obj := m[kind][namespace][name ]
runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(),dest)
}
getter("demonamespace", "demoname", pod)
}
func hasListWatch(verbs []string) bool {
return hasVerb(verbs, "list") && hasVerb(verbs, "watch")
}
func hasVerb(verbs []string, dest string) bool {
for _, each := range verbs {
if each == dest {
return true
}
}
return false
}