mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rebase: update sigs.k8s.io/controller-runtime to current version
There is no release for sigs.k8s.io/controller-runtime that supports Kubernetes v1.27. The main branch has all the required modifications, so we can use that for the time being. Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
2551a0b05f
commit
b1a4590967
16
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
16
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
@ -19,7 +19,6 @@ 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"
|
||||
@ -32,8 +31,11 @@ type Decoder struct {
|
||||
}
|
||||
|
||||
// NewDecoder creates a Decoder given the runtime.Scheme.
|
||||
func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
|
||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
|
||||
func NewDecoder(scheme *runtime.Scheme) *Decoder {
|
||||
if scheme == nil {
|
||||
panic("scheme should never be nil")
|
||||
}
|
||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}
|
||||
}
|
||||
|
||||
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
||||
@ -62,9 +64,13 @@ func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) er
|
||||
if len(rawObj.Raw) == 0 {
|
||||
return fmt.Errorf("there is no content to decode")
|
||||
}
|
||||
if unstructuredInto, isUnstructured := into.(*unstructured.Unstructured); isUnstructured {
|
||||
if unstructuredInto, isUnstructured := into.(runtime.Unstructured); isUnstructured {
|
||||
// unmarshal into unstructured's underlying object to avoid calling the decoder
|
||||
return json.Unmarshal(rawObj.Raw, &unstructuredInto.Object)
|
||||
var object map[string]interface{}
|
||||
if err := json.Unmarshal(rawObj.Raw, &object); err != nil {
|
||||
return err
|
||||
}
|
||||
unstructuredInto.SetUnstructuredContent(object)
|
||||
}
|
||||
|
||||
deserializer := d.codecs.UniversalDeserializer()
|
||||
|
15
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
15
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
@ -33,9 +33,9 @@ type Defaulter interface {
|
||||
}
|
||||
|
||||
// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
|
||||
func DefaultingWebhookFor(defaulter Defaulter) *Webhook {
|
||||
func DefaultingWebhookFor(scheme *runtime.Scheme, defaulter Defaulter) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &mutatingHandler{defaulter: defaulter},
|
||||
Handler: &mutatingHandler{defaulter: defaulter, decoder: NewDecoder(scheme)},
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,16 +44,11 @@ type mutatingHandler struct {
|
||||
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.decoder == nil {
|
||||
panic("decoder should never be nil")
|
||||
}
|
||||
if h.defaulter == nil {
|
||||
panic("defaulter should never be nil")
|
||||
}
|
||||
|
14
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
14
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
@ -34,9 +34,9 @@ type CustomDefaulter interface {
|
||||
}
|
||||
|
||||
// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
|
||||
func WithCustomDefaulter(obj runtime.Object, defaulter CustomDefaulter) *Webhook {
|
||||
func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter CustomDefaulter) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &defaulterForType{object: obj, defaulter: defaulter},
|
||||
Handler: &defaulterForType{object: obj, defaulter: defaulter, decoder: NewDecoder(scheme)},
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,15 +46,11 @@ type defaulterForType struct {
|
||||
decoder *Decoder
|
||||
}
|
||||
|
||||
var _ DecoderInjector = &defaulterForType{}
|
||||
|
||||
func (h *defaulterForType) InjectDecoder(d *Decoder) error {
|
||||
h.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
|
||||
if h.decoder == nil {
|
||||
panic("decoder should never be nil")
|
||||
}
|
||||
if h.defaulter == nil {
|
||||
panic("defaulter should never be nil")
|
||||
}
|
||||
|
6
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
6
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
@ -20,9 +20,3 @@ Package admission provides implementation for admission webhook and methods to i
|
||||
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")
|
||||
|
20
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
@ -52,7 +52,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var reviewResponse Response
|
||||
if r.Body == nil {
|
||||
err = errors.New("request body is empty")
|
||||
wh.log.Error(err, "bad request")
|
||||
wh.getLogger(nil).Error(err, "bad request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
@ -60,7 +60,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer r.Body.Close()
|
||||
if body, err = io.ReadAll(r.Body); err != nil {
|
||||
wh.log.Error(err, "unable to read the body from the incoming request")
|
||||
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
@ -69,7 +69,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// verify the content type is accurate
|
||||
if contentType := r.Header.Get("Content-Type"); 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)
|
||||
wh.getLogger(nil).Error(err, "unable to process a request with unknown content type")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
return
|
||||
@ -88,12 +88,12 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
|
||||
_, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar)
|
||||
if err != nil {
|
||||
wh.log.Error(err, "unable to decode the request")
|
||||
wh.getLogger(nil).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)
|
||||
wh.getLogger(&req).V(4).Info("received request")
|
||||
|
||||
reviewResponse = wh.Handle(ctx, req)
|
||||
wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
|
||||
@ -124,7 +124,7 @@ func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK
|
||||
// writeAdmissionResponse writes ar to w.
|
||||
func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
|
||||
if err := json.NewEncoder(w).Encode(ar); err != nil {
|
||||
wh.log.Error(err, "unable to encode and write the response")
|
||||
wh.getLogger(nil).Error(err, "unable to encode and write the response")
|
||||
// Since the `ar v1.AdmissionReview` is a clear and legal object,
|
||||
// it should not have problem to be marshalled into bytes.
|
||||
// The error here is probably caused by the abnormal HTTP connection,
|
||||
@ -132,15 +132,15 @@ func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
|
||||
// to avoid endless circular calling.
|
||||
serverError := Errored(http.StatusInternalServerError, err)
|
||||
if err = json.NewEncoder(w).Encode(v1.AdmissionReview{Response: &serverError.AdmissionResponse}); err != nil {
|
||||
wh.log.Error(err, "still unable to encode and write the InternalServerError response")
|
||||
wh.getLogger(nil).Error(err, "still unable to encode and write the InternalServerError response")
|
||||
}
|
||||
} else {
|
||||
res := ar.Response
|
||||
if log := wh.log; log.V(1).Enabled() {
|
||||
if log := wh.getLogger(nil); log.V(4).Enabled() {
|
||||
if res.Result != nil {
|
||||
log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason)
|
||||
log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason, "message", res.Result.Message)
|
||||
}
|
||||
log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed)
|
||||
log.V(4).Info("wrote response", "requestID", res.UID, "allowed", res.Allowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
/*
|
||||
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
|
||||
}
|
52
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
52
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
@ -25,8 +25,6 @@ import (
|
||||
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
)
|
||||
|
||||
type multiMutating []Handler
|
||||
@ -62,31 +60,6 @@ func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// InjectDecoder injects the decoder into the handlers.
|
||||
func (hs multiMutating) InjectDecoder(d *Decoder) error {
|
||||
for _, handler := range hs {
|
||||
if _, err := InjectDecoderInto(d, 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
|
||||
@ -120,28 +93,3 @@ func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
|
||||
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
|
||||
}
|
||||
|
||||
// InjectDecoder injects the decoder into the handlers.
|
||||
func (hs multiValidating) InjectDecoder(d *Decoder) error {
|
||||
for _, handler := range hs {
|
||||
if _, err := InjectDecoderInto(d, handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
23
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
23
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
@ -26,21 +26,21 @@ import (
|
||||
|
||||
// Allowed constructs a response indicating that the given operation
|
||||
// is allowed (without any patches).
|
||||
func Allowed(reason string) Response {
|
||||
return ValidationResponse(true, reason)
|
||||
func Allowed(message string) Response {
|
||||
return ValidationResponse(true, message)
|
||||
}
|
||||
|
||||
// Denied constructs a response indicating that the given operation
|
||||
// is not allowed.
|
||||
func Denied(reason string) Response {
|
||||
return ValidationResponse(false, reason)
|
||||
func Denied(message string) Response {
|
||||
return ValidationResponse(false, message)
|
||||
}
|
||||
|
||||
// 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)
|
||||
func Patched(message string, patches ...jsonpatch.JsonPatchOperation) Response {
|
||||
resp := Allowed(message)
|
||||
resp.Patches = patches
|
||||
|
||||
return resp
|
||||
@ -60,21 +60,24 @@ func Errored(code int32, err error) Response {
|
||||
}
|
||||
|
||||
// ValidationResponse returns a response for admitting a request.
|
||||
func ValidationResponse(allowed bool, reason string) Response {
|
||||
func ValidationResponse(allowed bool, message string) Response {
|
||||
code := http.StatusForbidden
|
||||
reason := metav1.StatusReasonForbidden
|
||||
if allowed {
|
||||
code = http.StatusOK
|
||||
reason = ""
|
||||
}
|
||||
resp := Response{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: allowed,
|
||||
Result: &metav1.Status{
|
||||
Code: int32(code),
|
||||
Code: int32(code),
|
||||
Reason: reason,
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(reason) > 0 {
|
||||
resp.Result.Reason = metav1.StatusReason(reason)
|
||||
if len(message) > 0 {
|
||||
resp.Result.Message = message
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
105
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
105
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
@ -18,7 +18,8 @@ package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
goerrors "errors"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
@ -26,18 +27,35 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Warnings represents warning messages.
|
||||
type Warnings []string
|
||||
|
||||
// Validator defines functions for validating an operation.
|
||||
// The custom resource kind which implements this interface can validate itself.
|
||||
// To validate the custom resource with another specific struct, use CustomValidator instead.
|
||||
type Validator interface {
|
||||
runtime.Object
|
||||
ValidateCreate() error
|
||||
ValidateUpdate(old runtime.Object) error
|
||||
ValidateDelete() error
|
||||
|
||||
// ValidateCreate validates the object on creation.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateCreate() (warnings Warnings, err error)
|
||||
|
||||
// ValidateUpdate validates the object on update. The oldObj is the object before the update.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateUpdate(old runtime.Object) (warnings Warnings, err error)
|
||||
|
||||
// ValidateDelete validates the object on deletion.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateDelete() (warnings Warnings, err error)
|
||||
}
|
||||
|
||||
// ValidatingWebhookFor creates a new Webhook for validating the provided type.
|
||||
func ValidatingWebhookFor(validator Validator) *Webhook {
|
||||
func ValidatingWebhookFor(scheme *runtime.Scheme, validator Validator) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &validatingHandler{validator: validator},
|
||||
Handler: &validatingHandler{validator: validator, decoder: NewDecoder(scheme)},
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,42 +64,34 @@ type validatingHandler struct {
|
||||
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.decoder == nil {
|
||||
panic("decoder should never be nil")
|
||||
}
|
||||
if h.validator == nil {
|
||||
panic("validator should never be nil")
|
||||
}
|
||||
|
||||
// Get the object in the request
|
||||
obj := h.validator.DeepCopyObject().(Validator)
|
||||
if req.Operation == v1.Create {
|
||||
err := h.decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
|
||||
var err error
|
||||
var warnings []string
|
||||
|
||||
switch req.Operation {
|
||||
case v1.Connect:
|
||||
// No validation for connect requests.
|
||||
// TODO(vincepri): Should we validate CONNECT requests? In what cases?
|
||||
case v1.Create:
|
||||
if err = h.decoder.Decode(req, obj); err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateCreate()
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if goerrors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status())
|
||||
}
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if req.Operation == v1.Update {
|
||||
warnings, err = obj.ValidateCreate()
|
||||
case v1.Update:
|
||||
oldObj := obj.DeepCopyObject()
|
||||
|
||||
err := h.decoder.DecodeRaw(req.Object, obj)
|
||||
err = h.decoder.DecodeRaw(req.Object, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
@ -90,33 +100,26 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateUpdate(oldObj)
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if goerrors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status())
|
||||
}
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if req.Operation == v1.Delete {
|
||||
warnings, err = obj.ValidateUpdate(oldObj)
|
||||
case v1.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)
|
||||
err = h.decoder.DecodeRaw(req.OldObject, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = obj.ValidateDelete()
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if goerrors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status())
|
||||
}
|
||||
return Denied(err.Error())
|
||||
}
|
||||
warnings, err = obj.ValidateDelete()
|
||||
default:
|
||||
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
|
||||
}
|
||||
|
||||
return Allowed("")
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if errors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
|
||||
}
|
||||
return Denied(err.Error()).WithWarnings(warnings...)
|
||||
}
|
||||
return Allowed("").WithWarnings(warnings...)
|
||||
}
|
||||
|
53
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
53
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
@ -28,16 +28,29 @@ import (
|
||||
)
|
||||
|
||||
// CustomValidator defines functions for validating an operation.
|
||||
// The object to be validated is passed into methods as a parameter.
|
||||
type CustomValidator interface {
|
||||
ValidateCreate(ctx context.Context, obj runtime.Object) error
|
||||
ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error
|
||||
ValidateDelete(ctx context.Context, obj runtime.Object) error
|
||||
|
||||
// ValidateCreate validates the object on creation.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateCreate(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
|
||||
|
||||
// ValidateUpdate validates the object on update.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings Warnings, err error)
|
||||
|
||||
// ValidateDelete validates the object on deletion.
|
||||
// The optional warnings will be added to the response as warning messages.
|
||||
// Return an error if the object is invalid.
|
||||
ValidateDelete(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
|
||||
}
|
||||
|
||||
// WithCustomValidator creates a new Webhook for validating the provided type.
|
||||
func WithCustomValidator(obj runtime.Object, validator CustomValidator) *Webhook {
|
||||
func WithCustomValidator(scheme *runtime.Scheme, obj runtime.Object, validator CustomValidator) *Webhook {
|
||||
return &Webhook{
|
||||
Handler: &validatorForType{object: obj, validator: validator},
|
||||
Handler: &validatorForType{object: obj, validator: validator, decoder: NewDecoder(scheme)},
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,16 +60,11 @@ type validatorForType struct {
|
||||
decoder *Decoder
|
||||
}
|
||||
|
||||
var _ DecoderInjector = &validatorForType{}
|
||||
|
||||
// InjectDecoder injects the decoder into a validatingHandler.
|
||||
func (h *validatorForType) InjectDecoder(d *Decoder) error {
|
||||
h.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
||||
if h.decoder == nil {
|
||||
panic("decoder should never be nil")
|
||||
}
|
||||
if h.validator == nil {
|
||||
panic("validator should never be nil")
|
||||
}
|
||||
@ -70,13 +78,18 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
||||
obj := h.object.DeepCopyObject()
|
||||
|
||||
var err error
|
||||
var warnings []string
|
||||
|
||||
switch req.Operation {
|
||||
case v1.Connect:
|
||||
// No validation for connect requests.
|
||||
// TODO(vincepri): Should we validate CONNECT requests? In what cases?
|
||||
case v1.Create:
|
||||
if err := h.decoder.Decode(req, obj); err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = h.validator.ValidateCreate(ctx, obj)
|
||||
warnings, err = h.validator.ValidateCreate(ctx, obj)
|
||||
case v1.Update:
|
||||
oldObj := obj.DeepCopyObject()
|
||||
if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
|
||||
@ -86,7 +99,7 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = h.validator.ValidateUpdate(ctx, oldObj, obj)
|
||||
warnings, err = h.validator.ValidateUpdate(ctx, oldObj, obj)
|
||||
case v1.Delete:
|
||||
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
||||
// OldObject contains the object being deleted
|
||||
@ -94,20 +107,20 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err = h.validator.ValidateDelete(ctx, obj)
|
||||
warnings, err = h.validator.ValidateDelete(ctx, obj)
|
||||
default:
|
||||
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation request %q", req.Operation))
|
||||
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
|
||||
}
|
||||
|
||||
// Check the error message first.
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if errors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status())
|
||||
return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
|
||||
}
|
||||
return Denied(err.Error())
|
||||
return Denied(err.Error()).WithWarnings(warnings...)
|
||||
}
|
||||
|
||||
// Return allowed if everything succeeded.
|
||||
return Allowed("")
|
||||
return Allowed("").WithWarnings(warnings...)
|
||||
}
|
||||
|
119
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
119
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
@ -21,18 +21,17 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||
)
|
||||
|
||||
@ -131,16 +130,14 @@ type Webhook struct {
|
||||
// headers thus allowing you to read them from within the handler
|
||||
WithContextFunc func(context.Context, *http.Request) context.Context
|
||||
|
||||
// decoder is constructed on receiving a scheme and passed down to then handler
|
||||
decoder *Decoder
|
||||
// LogConstructor is used to construct a logger for logging messages during webhook calls
|
||||
// based on the given base logger (which might carry more values like the webhook's path).
|
||||
// Note: LogConstructor has to be able to handle nil requests as we are also using it
|
||||
// outside the context of requests.
|
||||
LogConstructor func(base logr.Logger, req *Request) logr.Logger
|
||||
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// InjectLogger gets a handle to a logging instance, hopefully with more info about this particular webhook.
|
||||
func (wh *Webhook) InjectLogger(l logr.Logger) error {
|
||||
wh.log = l
|
||||
return nil
|
||||
setupLogOnce sync.Once
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
|
||||
@ -166,79 +163,47 @@ func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response)
|
||||
}()
|
||||
}
|
||||
|
||||
reqLog := wh.getLogger(&req)
|
||||
ctx = logf.IntoContext(ctx, reqLog)
|
||||
|
||||
resp := wh.Handler.Handle(ctx, req)
|
||||
if err := resp.Complete(req); err != nil {
|
||||
wh.log.Error(err, "unable to encode response")
|
||||
reqLog.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 (wh *Webhook) InjectScheme(s *runtime.Scheme) error {
|
||||
// TODO(directxman12): we should have a better way to pass this down
|
||||
|
||||
var err error
|
||||
wh.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 wh.Handler != nil {
|
||||
if _, err := InjectDecoderInto(wh.GetDecoder(), wh.Handler); err != nil {
|
||||
return err
|
||||
// getLogger constructs a logger from the injected log and LogConstructor.
|
||||
func (wh *Webhook) getLogger(req *Request) logr.Logger {
|
||||
wh.setupLogOnce.Do(func() {
|
||||
if wh.log.GetSink() == nil {
|
||||
wh.log = logf.Log.WithName("admission")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
logConstructor := wh.LogConstructor
|
||||
if logConstructor == nil {
|
||||
logConstructor = DefaultLogConstructor
|
||||
}
|
||||
return logConstructor(wh.log, req)
|
||||
}
|
||||
|
||||
// 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 (wh *Webhook) GetDecoder() *Decoder {
|
||||
return wh.decoder
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the webhook.
|
||||
func (wh *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(wh.GetDecoder(), target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
// DefaultLogConstructor adds some commonly interesting fields to the given logger.
|
||||
func DefaultLogConstructor(base logr.Logger, req *Request) logr.Logger {
|
||||
if req != nil {
|
||||
return base.WithValues("object", klog.KRef(req.Namespace, req.Name),
|
||||
"namespace", req.Namespace, "name", req.Name,
|
||||
"resource", req.Resource, "user", req.UserInfo.Username,
|
||||
"requestID", req.UID,
|
||||
)
|
||||
}
|
||||
|
||||
return setFields(wh.Handler)
|
||||
return base
|
||||
}
|
||||
|
||||
// StandaloneOptions let you configure a StandaloneWebhook.
|
||||
type StandaloneOptions struct {
|
||||
// Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources
|
||||
// Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
|
||||
// idea to pass your own scheme in. See the documentation in pkg/scheme for more information.
|
||||
Scheme *runtime.Scheme
|
||||
// Logger to be used by the webhook.
|
||||
// If none is set, it defaults to log.Log global logger.
|
||||
Logger logr.Logger
|
||||
@ -258,19 +223,9 @@ type StandaloneOptions struct {
|
||||
// in your own server/mux. In order to be accessed by a kubernetes cluster,
|
||||
// all webhook servers require TLS.
|
||||
func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) {
|
||||
if opts.Scheme == nil {
|
||||
opts.Scheme = scheme.Scheme
|
||||
if opts.Logger.GetSink() != nil {
|
||||
hook.log = opts.Logger
|
||||
}
|
||||
|
||||
if err := hook.InjectScheme(opts.Scheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.Logger.GetSink() == nil {
|
||||
opts.Logger = logf.RuntimeLog.WithName("webhook")
|
||||
}
|
||||
hook.log = opts.Logger
|
||||
|
||||
if opts.MetricsPath == "" {
|
||||
return hook, nil
|
||||
}
|
||||
|
237
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
237
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
@ -29,12 +29,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
"sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||
)
|
||||
|
||||
@ -49,7 +46,29 @@ var DefaultPort = 9443
|
||||
// at the default locations (tls.crt and tls.key). If you do not
|
||||
// want to configure TLS (i.e for testing purposes) run an
|
||||
// admission.StandaloneWebhook in your own server.
|
||||
type Server struct {
|
||||
type Server interface {
|
||||
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
||||
// the webhook server doesn't need leader election.
|
||||
NeedLeaderElection() bool
|
||||
|
||||
// Register marks the given webhook as being served at the given path.
|
||||
// It panics if two hooks are registered on the same path.
|
||||
Register(path string, hook http.Handler)
|
||||
|
||||
// Start runs the server.
|
||||
// It will install the webhook related resources depend on the server configuration.
|
||||
Start(ctx context.Context) error
|
||||
|
||||
// StartedChecker returns an healthz.Checker which is healthy after the
|
||||
// server has been started.
|
||||
StartedChecker() healthz.Checker
|
||||
|
||||
// WebhookMux returns the servers WebhookMux
|
||||
WebhookMux() *http.ServeMux
|
||||
}
|
||||
|
||||
// Options are all the available options for a webhook.Server
|
||||
type Options struct {
|
||||
// Host is the address that the server will listen on.
|
||||
// Defaults to "" - all addresses.
|
||||
Host string
|
||||
@ -63,9 +82,13 @@ type Server struct {
|
||||
CertDir string
|
||||
|
||||
// CertName is the server certificate name. Defaults to tls.crt.
|
||||
//
|
||||
// Note: This option should only be set when TLSOpts does not override GetCertificate.
|
||||
CertName string
|
||||
|
||||
// KeyName is the server key name. Defaults to tls.key.
|
||||
//
|
||||
// Note: This option should only be set when TLSOpts does not override GetCertificate.
|
||||
KeyName string
|
||||
|
||||
// ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate.
|
||||
@ -82,14 +105,22 @@ type Server struct {
|
||||
|
||||
// WebhookMux is the multiplexer that handles different webhooks.
|
||||
WebhookMux *http.ServeMux
|
||||
}
|
||||
|
||||
// webhooks keep track of all registered webhooks for dependency injection,
|
||||
// and to provide better panic messages on duplicate webhook registration.
|
||||
// NewServer constructs a new Server from the provided options.
|
||||
func NewServer(o Options) Server {
|
||||
return &DefaultServer{
|
||||
Options: o,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultServer is the default implementation used for Server.
|
||||
type DefaultServer struct {
|
||||
Options Options
|
||||
|
||||
// webhooks keep track of all registered webhooks
|
||||
webhooks map[string]http.Handler
|
||||
|
||||
// setFields allows injecting dependencies from an external source
|
||||
setFields inject.Func
|
||||
|
||||
// defaultingOnce ensures that the default fields are only ever set once.
|
||||
defaultingOnce sync.Once
|
||||
|
||||
@ -99,41 +130,49 @@ type Server struct {
|
||||
|
||||
// mu protects access to the webhook map & setFields for Start, Register, etc
|
||||
mu sync.Mutex
|
||||
|
||||
webhookMux *http.ServeMux
|
||||
}
|
||||
|
||||
// setDefaults does defaulting for the Server.
|
||||
func (s *Server) setDefaults() {
|
||||
func (o *Options) setDefaults() {
|
||||
if o.WebhookMux == nil {
|
||||
o.WebhookMux = http.NewServeMux()
|
||||
}
|
||||
|
||||
if o.Port <= 0 {
|
||||
o.Port = DefaultPort
|
||||
}
|
||||
|
||||
if len(o.CertDir) == 0 {
|
||||
o.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs")
|
||||
}
|
||||
|
||||
if len(o.CertName) == 0 {
|
||||
o.CertName = "tls.crt"
|
||||
}
|
||||
|
||||
if len(o.KeyName) == 0 {
|
||||
o.KeyName = "tls.key"
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultServer) setDefaults() {
|
||||
s.webhooks = map[string]http.Handler{}
|
||||
if s.WebhookMux == nil {
|
||||
s.WebhookMux = http.NewServeMux()
|
||||
}
|
||||
s.Options.setDefaults()
|
||||
|
||||
if s.Port <= 0 {
|
||||
s.Port = DefaultPort
|
||||
}
|
||||
|
||||
if len(s.CertDir) == 0 {
|
||||
s.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs")
|
||||
}
|
||||
|
||||
if len(s.CertName) == 0 {
|
||||
s.CertName = "tls.crt"
|
||||
}
|
||||
|
||||
if len(s.KeyName) == 0 {
|
||||
s.KeyName = "tls.key"
|
||||
}
|
||||
s.webhookMux = s.Options.WebhookMux
|
||||
}
|
||||
|
||||
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
||||
// the webhook server doesn't need leader election.
|
||||
func (*Server) NeedLeaderElection() bool {
|
||||
func (*DefaultServer) NeedLeaderElection() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Register marks the given webhook as being served at the given path.
|
||||
// It panics if two hooks are registered on the same path.
|
||||
func (s *Server) Register(path string, hook http.Handler) {
|
||||
func (s *DefaultServer) Register(path string, hook http.Handler) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@ -141,51 +180,11 @@ func (s *Server) Register(path string, hook http.Handler) {
|
||||
if _, found := s.webhooks[path]; found {
|
||||
panic(fmt.Errorf("can't register duplicate path: %v", path))
|
||||
}
|
||||
// TODO(directxman12): call setfields if we've already started the server
|
||||
s.webhooks[path] = hook
|
||||
s.WebhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
|
||||
s.webhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
|
||||
|
||||
regLog := log.WithValues("path", path)
|
||||
regLog.Info("Registering webhook")
|
||||
|
||||
// we've already been "started", inject dependencies here.
|
||||
// Otherwise, InjectFunc will do this for us later.
|
||||
if s.setFields != nil {
|
||||
if err := s.setFields(hook); err != nil {
|
||||
// TODO(directxman12): swallowing this error isn't great, but we'd have to
|
||||
// change the signature to fix that
|
||||
regLog.Error(err, "unable to inject fields into webhook during registration")
|
||||
}
|
||||
|
||||
baseHookLog := log.WithName("webhooks")
|
||||
|
||||
// NB(directxman12): we don't propagate this further by wrapping setFields because it's
|
||||
// unclear if this is how we want to deal with log propagation. In this specific instance,
|
||||
// we want to be able to pass a logger to webhooks because they don't know their own path.
|
||||
if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", path), hook); err != nil {
|
||||
regLog.Error(err, "unable to logger into webhook during registration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StartStandalone runs a webhook server without
|
||||
// a controller manager.
|
||||
func (s *Server) StartStandalone(ctx context.Context, scheme *runtime.Scheme) error {
|
||||
// Use the Kubernetes client-go scheme if none is specified
|
||||
if scheme == nil {
|
||||
scheme = kscheme.Scheme
|
||||
}
|
||||
|
||||
if err := s.InjectFunc(func(i interface{}) error {
|
||||
if _, err := inject.SchemeInto(scheme, i); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Start(ctx)
|
||||
}
|
||||
|
||||
// tlsVersion converts from human-readable TLS version (for example "1.1")
|
||||
@ -210,41 +209,49 @@ func tlsVersion(version string) (uint16, error) {
|
||||
|
||||
// Start runs the server.
|
||||
// It will install the webhook related resources depend on the server configuration.
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
func (s *DefaultServer) Start(ctx context.Context) error {
|
||||
s.defaultingOnce.Do(s.setDefaults)
|
||||
|
||||
baseHookLog := log.WithName("webhooks")
|
||||
baseHookLog.Info("Starting webhook server")
|
||||
|
||||
certPath := filepath.Join(s.CertDir, s.CertName)
|
||||
keyPath := filepath.Join(s.CertDir, s.KeyName)
|
||||
|
||||
certWatcher, err := certwatcher.New(certPath, keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := certWatcher.Start(ctx); err != nil {
|
||||
log.Error(err, "certificate watcher error")
|
||||
}
|
||||
}()
|
||||
|
||||
tlsMinVersion, err := tlsVersion(s.TLSMinVersion)
|
||||
tlsMinVersion, err := tlsVersion(s.Options.TLSMinVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg := &tls.Config{ //nolint:gosec
|
||||
NextProtos: []string{"h2"},
|
||||
GetCertificate: certWatcher.GetCertificate,
|
||||
MinVersion: tlsMinVersion,
|
||||
NextProtos: []string{"h2"},
|
||||
MinVersion: tlsMinVersion,
|
||||
}
|
||||
// fallback TLS config ready, will now mutate if passer wants full control over it
|
||||
for _, op := range s.Options.TLSOpts {
|
||||
op(cfg)
|
||||
}
|
||||
|
||||
// load CA to verify client certificate
|
||||
if s.ClientCAName != "" {
|
||||
if cfg.GetCertificate == nil {
|
||||
certPath := filepath.Join(s.Options.CertDir, s.Options.CertName)
|
||||
keyPath := filepath.Join(s.Options.CertDir, s.Options.KeyName)
|
||||
|
||||
// Create the certificate watcher and
|
||||
// set the config's GetCertificate on the TLSConfig
|
||||
certWatcher, err := certwatcher.New(certPath, keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.GetCertificate = certWatcher.GetCertificate
|
||||
|
||||
go func() {
|
||||
if err := certWatcher.Start(ctx); err != nil {
|
||||
log.Error(err, "certificate watcher error")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Load CA to verify client certificate, if configured.
|
||||
if s.Options.ClientCAName != "" {
|
||||
certPool := x509.NewCertPool()
|
||||
clientCABytes, err := os.ReadFile(filepath.Join(s.CertDir, s.ClientCAName))
|
||||
clientCABytes, err := os.ReadFile(filepath.Join(s.Options.CertDir, s.Options.ClientCAName))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read client CA cert: %w", err)
|
||||
}
|
||||
@ -258,27 +265,23 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
// fallback TLS config ready, will now mutate if passer wants full control over it
|
||||
for _, op := range s.TLSOpts {
|
||||
op(cfg)
|
||||
}
|
||||
|
||||
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
|
||||
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Serving webhook server", "host", s.Host, "port", s.Port)
|
||||
log.Info("Serving webhook server", "host", s.Options.Host, "port", s.Options.Port)
|
||||
|
||||
srv := httpserver.New(s.WebhookMux)
|
||||
srv := httpserver.New(s.webhookMux)
|
||||
|
||||
idleConnsClosed := make(chan struct{})
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.Info("shutting down webhook server")
|
||||
log.Info("Shutting down webhook server with timeout of 1 minute")
|
||||
|
||||
// TODO: use a context with reasonable timeout
|
||||
if err := srv.Shutdown(context.Background()); err != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
// Error from closing listeners, or context timeout
|
||||
log.Error(err, "error shutting down the HTTP server")
|
||||
}
|
||||
@ -298,7 +301,7 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
|
||||
// StartedChecker returns an healthz.Checker which is healthy after the
|
||||
// server has been started.
|
||||
func (s *Server) StartedChecker() healthz.Checker {
|
||||
func (s *DefaultServer) StartedChecker() healthz.Checker {
|
||||
config := &tls.Config{
|
||||
InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
|
||||
}
|
||||
@ -311,7 +314,7 @@ func (s *Server) StartedChecker() healthz.Checker {
|
||||
}
|
||||
|
||||
d := &net.Dialer{Timeout: 10 * time.Second}
|
||||
conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), config)
|
||||
conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("webhook server is not reachable: %w", err)
|
||||
}
|
||||
@ -324,23 +327,7 @@ func (s *Server) StartedChecker() healthz.Checker {
|
||||
}
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the server.
|
||||
func (s *Server) InjectFunc(f inject.Func) error {
|
||||
s.setFields = f
|
||||
|
||||
// inject fields here that weren't injected in Register because we didn't have setFields yet.
|
||||
baseHookLog := log.WithName("webhooks")
|
||||
for hookPath, webhook := range s.webhooks {
|
||||
if err := s.setFields(webhook); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// NB(directxman12): we don't propagate this further by wrapping setFields because it's
|
||||
// unclear if this is how we want to deal with log propagation. In this specific instance,
|
||||
// we want to be able to pass a logger to webhooks because they don't know their own path.
|
||||
if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", hookPath), webhook); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
// WebhookMux returns the servers WebhookMux
|
||||
func (s *DefaultServer) WebhookMux() *http.ServeMux {
|
||||
return s.webhookMux
|
||||
}
|
||||
|
Reference in New Issue
Block a user