mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rebase: add controller runtime dependency
this commits add the controller runtime and its dependency to the vendor. Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
14700b89d1
commit
5af3fe5deb
76
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
Normal file
76
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
)
|
||||
|
||||
// Decoder knows how to decode the contents of an admission
|
||||
// request into a concrete object.
|
||||
type Decoder struct {
|
||||
codecs serializer.CodecFactory
|
||||
}
|
||||
|
||||
// NewDecoder creates a Decoder given the runtime.Scheme
|
||||
func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
|
||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
|
||||
}
|
||||
|
||||
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
||||
// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw.
|
||||
// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes.
|
||||
func (d *Decoder) Decode(req Request, into runtime.Object) error {
|
||||
// we error out if rawObj is an empty object.
|
||||
if len(req.Object.Raw) == 0 {
|
||||
return fmt.Errorf("there is no content to decode")
|
||||
}
|
||||
return d.DecodeRaw(req.Object, into)
|
||||
}
|
||||
|
||||
// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object.
|
||||
// It errors out if rawObj is empty i.e. containing 0 raw bytes.
|
||||
func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error {
|
||||
// NB(directxman12): there's a bug/weird interaction between decoders and
|
||||
// the API server where the API server doesn't send a GVK on the embedded
|
||||
// objects, which means the unstructured decoder refuses to decode. It
|
||||
// also means we can't pass the unstructured directly in, since it'll try
|
||||
// and call unstructured's special Unmarshal implementation, which calls
|
||||
// back into that same decoder :-/
|
||||
// See kubernetes/kubernetes#74373.
|
||||
|
||||
// we error out if rawObj is an empty object.
|
||||
if len(rawObj.Raw) == 0 {
|
||||
return fmt.Errorf("there is no content to decode")
|
||||
}
|
||||
if unstructuredInto, isUnstructured := into.(*unstructured.Unstructured); isUnstructured {
|
||||
// unmarshal into unstructured's underlying object to avoid calling the decoder
|
||||
if err := json.Unmarshal(rawObj.Raw, &unstructuredInto.Object); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
deserializer := d.codecs.UniversalDeserializer()
|
||||
return runtime.DecodeInto(deserializer, rawObj.Raw, into)
|
||||
}
|
75
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
Normal file
75
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Defaulter defines functions for setting defaults on resources
|
||||
type Defaulter interface {
|
||||
runtime.Object
|
||||
Default()
|
||||
}
|
||||
|
||||
// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
|
||||
func DefaultingWebhookFor(defaulter Defaulter) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &mutatingHandler{defaulter: defaulter},
|
||||
}
|
||||
}
|
||||
|
||||
type mutatingHandler struct {
|
||||
defaulter Defaulter
|
||||
decoder *Decoder
|
||||
}
|
||||
|
||||
var _ DecoderInjector = &mutatingHandler{}
|
||||
|
||||
// InjectDecoder injects the decoder into a mutatingHandler.
|
||||
func (h *mutatingHandler) InjectDecoder(d *Decoder) error {
|
||||
h.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
if h.defaulter == nil {
|
||||
panic("defaulter should never be nil")
|
||||
}
|
||||
|
||||
// Get the object in the request
|
||||
obj := h.defaulter.DeepCopyObject().(Defaulter)
|
||||
err := h.decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Default the object
|
||||
obj.Default()
|
||||
marshalled, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
// Create the patch
|
||||
return PatchResponseFromRaw(req.Object.Raw, marshalled)
|
||||
}
|
28
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
Normal file
28
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package admission provides implementation for admission webhook and methods to implement admission webhook handlers.
|
||||
|
||||
See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks.
|
||||
*/
|
||||
package admission
|
||||
|
||||
import (
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
)
|
||||
|
||||
var log = logf.RuntimeLog.WithName("admission")
|
104
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
Normal file
104
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var admissionScheme = runtime.NewScheme()
|
||||
var admissionCodecs = serializer.NewCodecFactory(admissionScheme)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(admissionv1beta1.AddToScheme(admissionScheme))
|
||||
}
|
||||
|
||||
var _ http.Handler = &Webhook{}
|
||||
|
||||
func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var body []byte
|
||||
var err error
|
||||
|
||||
var reviewResponse Response
|
||||
if r.Body != nil {
|
||||
if body, err = ioutil.ReadAll(r.Body); err != nil {
|
||||
wh.log.Error(err, "unable to read the body from the incoming request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = errors.New("request body is empty")
|
||||
wh.log.Error(err, "bad request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
}
|
||||
|
||||
// verify the content type is accurate
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
err = fmt.Errorf("contentType=%s, expected application/json", contentType)
|
||||
wh.log.Error(err, "unable to process a request with an unknown content type", "content type", contentType)
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
}
|
||||
|
||||
req := Request{}
|
||||
ar := v1beta1.AdmissionReview{
|
||||
// avoid an extra copy
|
||||
Request: &req.AdmissionRequest,
|
||||
}
|
||||
if _, _, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar); err != nil {
|
||||
wh.log.Error(err, "unable to decode the request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
}
|
||||
wh.log.V(1).Info("received request", "UID", req.UID, "kind", req.Kind, "resource", req.Resource)
|
||||
|
||||
// TODO: add panic-recovery for Handle
|
||||
reviewResponse = wh.Handle(r.Context(), req)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
}
|
||||
|
||||
func (wh *Webhook) writeResponse(w io.Writer, response Response) {
|
||||
encoder := json.NewEncoder(w)
|
||||
responseAdmissionReview := v1beta1.AdmissionReview{
|
||||
Response: &response.AdmissionResponse,
|
||||
}
|
||||
err := encoder.Encode(responseAdmissionReview)
|
||||
if err != nil {
|
||||
wh.log.Error(err, "unable to encode the response")
|
||||
wh.writeResponse(w, Errored(http.StatusInternalServerError, err))
|
||||
} else {
|
||||
res := responseAdmissionReview.Response
|
||||
wh.log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed, "result", res.Result)
|
||||
}
|
||||
}
|
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
Normal file
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
// DecoderInjector is used by the ControllerManager to inject decoder into webhook handlers.
|
||||
type DecoderInjector interface {
|
||||
InjectDecoder(*Decoder) error
|
||||
}
|
||||
|
||||
// InjectDecoderInto will set decoder on i and return the result if it implements Decoder. Returns
|
||||
// false if i does not implement Decoder.
|
||||
func InjectDecoderInto(decoder *Decoder, i interface{}) (bool, error) {
|
||||
if s, ok := i.(DecoderInjector); ok {
|
||||
return true, s.InjectDecoder(decoder)
|
||||
}
|
||||
return false, nil
|
||||
}
|
126
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
Normal file
126
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
)
|
||||
|
||||
type multiMutating []Handler
|
||||
|
||||
func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
|
||||
patches := []jsonpatch.JsonPatchOperation{}
|
||||
for _, handler := range hs {
|
||||
resp := handler.Handle(ctx, req)
|
||||
if !resp.Allowed {
|
||||
return resp
|
||||
}
|
||||
if resp.PatchType != nil && *resp.PatchType != admissionv1beta1.PatchTypeJSONPatch {
|
||||
return Errored(http.StatusInternalServerError,
|
||||
fmt.Errorf("unexpected patch type returned by the handler: %v, only allow: %v",
|
||||
resp.PatchType, admissionv1beta1.PatchTypeJSONPatch))
|
||||
}
|
||||
patches = append(patches, resp.Patches...)
|
||||
}
|
||||
var err error
|
||||
marshaledPatch, err := json.Marshal(patches)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, fmt.Errorf("error when marshaling the patch: %w", err))
|
||||
}
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
Code: http.StatusOK,
|
||||
},
|
||||
Patch: marshaledPatch,
|
||||
PatchType: func() *admissionv1beta1.PatchType { pt := admissionv1beta1.PatchTypeJSONPatch; return &pt }(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the handlers.
|
||||
func (hs multiMutating) InjectFunc(f inject.Func) error {
|
||||
// inject directly into the handlers. It would be more correct
|
||||
// to do this in a sync.Once in Handle (since we don't have some
|
||||
// other start/finalize-type method), but it's more efficient to
|
||||
// do it here, presumably.
|
||||
for _, handler := range hs {
|
||||
if err := f(handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MultiMutatingHandler combines multiple mutating webhook handlers into a single
|
||||
// mutating webhook handler. Handlers are called in sequential order, and the first
|
||||
// `allowed: false` response may short-circuit the rest. Users must take care to
|
||||
// ensure patches are disjoint.
|
||||
func MultiMutatingHandler(handlers ...Handler) Handler {
|
||||
return multiMutating(handlers)
|
||||
}
|
||||
|
||||
type multiValidating []Handler
|
||||
|
||||
func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
|
||||
for _, handler := range hs {
|
||||
resp := handler.Handle(ctx, req)
|
||||
if !resp.Allowed {
|
||||
return resp
|
||||
}
|
||||
}
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
Code: http.StatusOK,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// MultiValidatingHandler combines multiple validating webhook handlers into a single
|
||||
// validating webhook handler. Handlers are called in sequential order, and the first
|
||||
// `allowed: false` response may short-circuit the rest.
|
||||
func MultiValidatingHandler(handlers ...Handler) Handler {
|
||||
return multiValidating(handlers)
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the handlers.
|
||||
func (hs multiValidating) InjectFunc(f inject.Func) error {
|
||||
// inject directly into the handlers. It would be more correct
|
||||
// to do this in a sync.Once in Handle (since we don't have some
|
||||
// other start/finalize-type method), but it's more efficient to
|
||||
// do it here, presumably.
|
||||
for _, handler := range hs {
|
||||
if err := f(handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
98
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
Normal file
98
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Allowed constructs a response indicating that the given operation
|
||||
// is allowed (without any patches).
|
||||
func Allowed(reason string) Response {
|
||||
return ValidationResponse(true, reason)
|
||||
}
|
||||
|
||||
// Denied constructs a response indicating that the given operation
|
||||
// is not allowed.
|
||||
func Denied(reason string) Response {
|
||||
return ValidationResponse(false, reason)
|
||||
}
|
||||
|
||||
// Patched constructs a response indicating that the given operation is
|
||||
// allowed, and that the target object should be modified by the given
|
||||
// JSONPatch operations.
|
||||
func Patched(reason string, patches ...jsonpatch.JsonPatchOperation) Response {
|
||||
resp := Allowed(reason)
|
||||
resp.Patches = patches
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
// Errored creates a new Response for error-handling a request.
|
||||
func Errored(code int32, err error) Response {
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Code: code,
|
||||
Message: err.Error(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ValidationResponse returns a response for admitting a request.
|
||||
func ValidationResponse(allowed bool, reason string) Response {
|
||||
code := http.StatusForbidden
|
||||
if allowed {
|
||||
code = http.StatusOK
|
||||
}
|
||||
resp := Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: allowed,
|
||||
Result: &metav1.Status{
|
||||
Code: int32(code),
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(reason) > 0 {
|
||||
resp.Result.Reason = metav1.StatusReason(reason)
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// PatchResponseFromRaw takes 2 byte arrays and returns a new response with json patch.
|
||||
// The original object should be passed in as raw bytes to avoid the roundtripping problem
|
||||
// described in https://github.com/kubernetes-sigs/kubebuilder/issues/510.
|
||||
func PatchResponseFromRaw(original, current []byte) Response {
|
||||
patches, err := jsonpatch.CreatePatch(original, current)
|
||||
if err != nil {
|
||||
return Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
return Response{
|
||||
Patches: patches,
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
PatchType: func() *admissionv1beta1.PatchType { pt := admissionv1beta1.PatchTypeJSONPatch; return &pt }(),
|
||||
},
|
||||
}
|
||||
}
|
108
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
Normal file
108
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Validator defines functions for validating an operation
|
||||
type Validator interface {
|
||||
runtime.Object
|
||||
ValidateCreate() error
|
||||
ValidateUpdate(old runtime.Object) error
|
||||
ValidateDelete() error
|
||||
}
|
||||
|
||||
// ValidatingWebhookFor creates a new Webhook for validating the provided type.
|
||||
func ValidatingWebhookFor(validator Validator) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &validatingHandler{validator: validator},
|
||||
}
|
||||
}
|
||||
|
||||
type validatingHandler struct {
|
||||
validator Validator
|
||||
decoder *Decoder
|
||||
}
|
||||
|
||||
var _ DecoderInjector = &validatingHandler{}
|
||||
|
||||
// InjectDecoder injects the decoder into a validatingHandler.
|
||||
func (h *validatingHandler) InjectDecoder(d *Decoder) error {
|
||||
h.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
if h.validator == nil {
|
||||
panic("validator should never be nil")
|
||||
}
|
||||
|
||||
// Get the object in the request
|
||||
obj := h.validator.DeepCopyObject().(Validator)
|
||||
if req.Operation == v1beta1.Create {
|
||||
err := h.decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateCreate()
|
||||
if err != nil {
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if req.Operation == v1beta1.Update {
|
||||
oldObj := obj.DeepCopyObject()
|
||||
|
||||
err := h.decoder.DecodeRaw(req.Object, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
err = h.decoder.DecodeRaw(req.OldObject, oldObj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateUpdate(oldObj)
|
||||
if err != nil {
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if req.Operation == v1beta1.Delete {
|
||||
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
||||
// OldObject contains the object being deleted
|
||||
err := h.decoder.DecodeRaw(req.OldObject, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateDelete()
|
||||
if err != nil {
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return Allowed("")
|
||||
}
|
200
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
Normal file
200
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
)
|
||||
|
||||
var (
|
||||
errUnableToEncodeResponse = errors.New("unable to encode response")
|
||||
)
|
||||
|
||||
// Request defines the input for an admission handler.
|
||||
// It contains information to identify the object in
|
||||
// question (group, version, kind, resource, subresource,
|
||||
// name, namespace), as well as the operation in question
|
||||
// (e.g. Get, Create, etc), and the object itself.
|
||||
type Request struct {
|
||||
admissionv1beta1.AdmissionRequest
|
||||
}
|
||||
|
||||
// Response is the output of an admission handler.
|
||||
// It contains a response indicating if a given
|
||||
// operation is allowed, as well as a set of patches
|
||||
// to mutate the object in the case of a mutating admission handler.
|
||||
type Response struct {
|
||||
// Patches are the JSON patches for mutating webhooks.
|
||||
// Using this instead of setting Response.Patch to minimize
|
||||
// overhead of serialization and deserialization.
|
||||
// Patches set here will override any patches in the response,
|
||||
// so leave this empty if you want to set the patch response directly.
|
||||
Patches []jsonpatch.JsonPatchOperation
|
||||
// AdmissionResponse is the raw admission response.
|
||||
// The Patch field in it will be overwritten by the listed patches.
|
||||
admissionv1beta1.AdmissionResponse
|
||||
}
|
||||
|
||||
// Complete populates any fields that are yet to be set in
|
||||
// the underlying AdmissionResponse, It mutates the response.
|
||||
func (r *Response) Complete(req Request) error {
|
||||
r.UID = req.UID
|
||||
|
||||
// ensure that we have a valid status code
|
||||
if r.Result == nil {
|
||||
r.Result = &metav1.Status{}
|
||||
}
|
||||
if r.Result.Code == 0 {
|
||||
r.Result.Code = http.StatusOK
|
||||
}
|
||||
// TODO(directxman12): do we need to populate this further, and/or
|
||||
// is code actually necessary (the same webhook doesn't use it)
|
||||
|
||||
if len(r.Patches) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
r.Patch, err = json.Marshal(r.Patches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchType := admissionv1beta1.PatchTypeJSONPatch
|
||||
r.PatchType = &patchType
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler can handle an AdmissionRequest.
|
||||
type Handler interface {
|
||||
// Handle yields a response to an AdmissionRequest.
|
||||
//
|
||||
// The supplied context is extracted from the received http.Request, allowing wrapping
|
||||
// http.Handlers to inject values into and control cancelation of downstream request processing.
|
||||
Handle(context.Context, Request) Response
|
||||
}
|
||||
|
||||
// HandlerFunc implements Handler interface using a single function.
|
||||
type HandlerFunc func(context.Context, Request) Response
|
||||
|
||||
var _ Handler = HandlerFunc(nil)
|
||||
|
||||
// Handle process the AdmissionRequest by invoking the underlying function.
|
||||
func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
|
||||
return f(ctx, req)
|
||||
}
|
||||
|
||||
// Webhook represents each individual webhook.
|
||||
type Webhook struct {
|
||||
// Handler actually processes an admission request returning whether it was allowed or denied,
|
||||
// and potentially patches to apply to the handler.
|
||||
Handler Handler
|
||||
|
||||
// decoder is constructed on receiving a scheme and passed down to then handler
|
||||
decoder *Decoder
|
||||
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// InjectLogger gets a handle to a logging instance, hopefully with more info about this particular webhook.
|
||||
func (w *Webhook) InjectLogger(l logr.Logger) error {
|
||||
w.log = l
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle processes AdmissionRequest.
|
||||
// If the webhook is mutating type, it delegates the AdmissionRequest to each handler and merge the patches.
|
||||
// If the webhook is validating type, it delegates the AdmissionRequest to each handler and
|
||||
// deny the request if anyone denies.
|
||||
func (w *Webhook) Handle(ctx context.Context, req Request) Response {
|
||||
resp := w.Handler.Handle(ctx, req)
|
||||
if err := resp.Complete(req); err != nil {
|
||||
w.log.Error(err, "unable to encode response")
|
||||
return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
// InjectScheme injects a scheme into the webhook, in order to construct a Decoder.
|
||||
func (w *Webhook) InjectScheme(s *runtime.Scheme) error {
|
||||
// TODO(directxman12): we should have a better way to pass this down
|
||||
|
||||
var err error
|
||||
w.decoder, err = NewDecoder(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// inject the decoder here too, just in case the order of calling this is not
|
||||
// scheme first, then inject func
|
||||
if w.Handler != nil {
|
||||
if _, err := InjectDecoderInto(w.GetDecoder(), w.Handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDecoder returns a decoder to decode the objects embedded in admission requests.
|
||||
// It may be nil if we haven't received a scheme to use to determine object types yet.
|
||||
func (w *Webhook) GetDecoder() *Decoder {
|
||||
return w.decoder
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the webhook.
|
||||
func (w *Webhook) InjectFunc(f inject.Func) error {
|
||||
// inject directly into the handlers. It would be more correct
|
||||
// to do this in a sync.Once in Handle (since we don't have some
|
||||
// other start/finalize-type method), but it's more efficient to
|
||||
// do it here, presumably.
|
||||
|
||||
// also inject a decoder, and wrap this so that we get a setFields
|
||||
// that injects a decoder (hopefully things don't ignore the duplicate
|
||||
// InjectorInto call).
|
||||
|
||||
var setFields inject.Func
|
||||
setFields = func(target interface{}) error {
|
||||
if err := f(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := inject.InjectorInto(setFields, target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := InjectDecoderInto(w.GetDecoder(), target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return setFields(w.Handler)
|
||||
}
|
Reference in New Issue
Block a user