forked from RHsyseng/operator-utils
/
reader.go
95 lines (84 loc) · 3.27 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package read
import (
"context"
"github.com/myeung18/operator-utils/pkg/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"reflect"
clientv1 "sigs.k8s.io/controller-runtime/pkg/client"
)
type resourceReader struct {
reader clientv1.Reader
namespace string
ownerObject metav1.Object
}
// New creates a resourceReader object that can be used to load/list kubernetes resources
// the provided reader object will be used for the underlying operations
func New(reader clientv1.Reader) *resourceReader {
return &resourceReader{reader: reader}
}
// WithNamespace filters list operations to the provided namespace
func (this *resourceReader) WithNamespace(namespace string) *resourceReader {
this.namespace = namespace
return this
}
// WithOwnerObject filters list operations to items that have ownerObject as an owner reference
func (this *resourceReader) WithOwnerObject(ownerObject metav1.Object) *resourceReader {
this.ownerObject = ownerObject
return this
}
// List returns a list of Kubernetes resources based on provided List object and configuration
// any error from underlying calls is directly returned as well
func (this *resourceReader) List(listObject runtime.Object) ([]resource.KubernetesResource, error) {
var resources []resource.KubernetesResource
err := this.reader.List(context.TODO(), listObject, &clientv1.ListOptions{Namespace: this.namespace})
if err != nil {
return nil, err
}
itemsValue := reflect.Indirect(reflect.ValueOf(listObject)).FieldByName("Items")
for index := 0; index < itemsValue.Len(); index++ {
item := addr(itemsValue.Index(index)).Interface().(resource.KubernetesResource)
if this.ownerObject == nil || isOwner(this.ownerObject, item) {
resources = append(resources, item)
}
}
return resources, nil
}
func addr(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr {
return v
}
return v.Addr()
}
func isOwner(owner metav1.Object, res resource.KubernetesResource) bool {
for _, ownerRef := range res.GetOwnerReferences() {
if ownerRef.UID == owner.GetUID() {
return true
}
}
return false
}
// ListAll returns a map of Kubernetes resources organized by type, based on provided List objects and configuration
// any error from underlying calls is directly returned as well
func (this *resourceReader) ListAll(listObjects ...runtime.Object) (map[reflect.Type][]resource.KubernetesResource, error) {
objectMap := make(map[reflect.Type][]resource.KubernetesResource)
for _, listObject := range listObjects {
resources, err := this.List(listObject)
if err != nil {
return nil, err
}
if len(resources) > 0 {
itemType := reflect.ValueOf(resources[0]).Elem().Type()
objectMap[itemType] = resources
}
}
return objectMap, nil
}
// Load returns an object of the specified type with the given name, in the previously configured namespace
// any error from the underlying call, including a not-found error, is directly returned as well
func (this *resourceReader) Load(resourceType reflect.Type, name string) (resource.KubernetesResource, error) {
deployed := reflect.New(resourceType).Interface().(resource.KubernetesResource)
err := this.reader.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: this.namespace}, deployed)
return deployed, err
}