c6c2c525a6
Also fix some tests that were broken by bumping golang and dependencies in the previous commits. Note that in addition to changes made to satisfy the linter which do not impact the behavior of the code, this commit also adds ReadHeaderTimeout to all usages of http.Server to satisfy the linter (and because it seemed like a good suggestion).
161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
// 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
|
|
}
|