/
middleware.go
160 lines (128 loc) · 3.85 KB
/
middleware.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package kubeclient
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/errors"
)
type Middleware interface {
Handle(ctx context.Context, rt RoundTrip)
}
var _ Middleware = MiddlewareFunc(nil)
type MiddlewareFunc func(ctx context.Context, rt RoundTrip)
func (f MiddlewareFunc) Handle(ctx context.Context, rt RoundTrip) {
f(ctx, rt)
}
var _ Middleware = Middlewares{}
type Middlewares []Middleware
func (m Middlewares) Handle(ctx context.Context, rt RoundTrip) {
for _, middleware := range m {
middleware := middleware
middleware.Handle(ctx, rt)
}
}
type RoundTrip interface {
Verb() Verb
Namespace() string // this is the only valid way to check namespace, Object.GetNamespace() will almost always be empty
NamespaceScoped() bool
Resource() schema.GroupVersionResource
Subresource() string
MutateRequest(f func(obj Object) error)
MutateResponse(f func(obj Object) error)
}
type Object interface {
runtime.Object // generic access to TypeMeta
metav1.Object // generic access to ObjectMeta
}
var _ RoundTrip = &request{}
type request struct {
verb Verb
namespace string
resource schema.GroupVersionResource
reqFuncs, respFuncs []func(obj Object) error
subresource string
}
func (r *request) Verb() Verb {
return r.verb
}
func (r *request) Namespace() string {
return r.namespace
}
//nolint:gochecknoglobals
var namespaceGVR = corev1.SchemeGroupVersion.WithResource("namespaces")
func (r *request) NamespaceScoped() bool {
if r.Resource() == namespaceGVR {
return false // always consider namespaces to be cluster scoped
}
return len(r.Namespace()) != 0
}
func (r *request) Resource() schema.GroupVersionResource {
return r.resource
}
func (r *request) Subresource() string {
return r.subresource
}
func (r *request) MutateRequest(f func(obj Object) error) {
r.reqFuncs = append(r.reqFuncs, f)
}
func (r *request) MutateResponse(f func(obj Object) error) {
r.respFuncs = append(r.respFuncs, f)
}
type mutationResult struct {
origGVK, newGVK schema.GroupVersionKind
gvkChanged, mutated bool
}
func (r *request) mutateRequest(obj Object) (*mutationResult, error) {
origGVK := obj.GetObjectKind().GroupVersionKind()
if origGVK.Empty() {
return nil, fmt.Errorf("invalid empty orig GVK for %T: %#v", obj, r)
}
origObj, ok := obj.DeepCopyObject().(Object)
if !ok {
return nil, fmt.Errorf("invalid deep copy semantics for %T: %#v", obj, r)
}
var errs []error
for _, reqFunc := range r.reqFuncs {
reqFunc := reqFunc
if err := reqFunc(obj); err != nil {
errs = append(errs, err)
}
}
if err := errors.NewAggregate(errs); err != nil {
return nil, fmt.Errorf("request mutation failed: %w", err)
}
newGVK := obj.GetObjectKind().GroupVersionKind()
if newGVK.Empty() {
return nil, fmt.Errorf("invalid empty new GVK for %T: %#v", obj, r)
}
return &mutationResult{
origGVK: origGVK,
newGVK: newGVK,
gvkChanged: origGVK != newGVK,
mutated: len(r.respFuncs) != 0 || !apiequality.Semantic.DeepEqual(origObj, obj),
}, nil
}
func (r *request) mutateResponse(obj Object) (bool, error) {
origObj, ok := obj.DeepCopyObject().(Object)
if !ok {
return false, fmt.Errorf("invalid deep copy semantics for %T: %#v", obj, r)
}
var errs []error
for _, respFunc := range r.respFuncs {
respFunc := respFunc
if err := respFunc(obj); err != nil {
errs = append(errs, err)
}
}
if err := errors.NewAggregate(errs); err != nil {
return false, fmt.Errorf("response mutation failed: %w", err)
}
mutated := !apiequality.Semantic.DeepEqual(origObj, obj)
return mutated, nil
}