mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rebase: update controller-runtime package to v0.9.2
This commit updates controller-runtime to v0.9.2 and makes changes in persistentvolume.go to add context to various functions and function calls made here instead of context.TODO(). Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
8
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
8
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
@ -31,7 +31,7 @@ type Decoder struct {
|
||||
codecs serializer.CodecFactory
|
||||
}
|
||||
|
||||
// NewDecoder creates a Decoder given the runtime.Scheme
|
||||
// NewDecoder creates a Decoder given the runtime.Scheme.
|
||||
func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
|
||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
|
||||
}
|
||||
@ -64,11 +64,7 @@ func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) er
|
||||
}
|
||||
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
|
||||
return json.Unmarshal(rawObj.Raw, &unstructuredInto.Object)
|
||||
}
|
||||
|
||||
deserializer := d.codecs.UniversalDeserializer()
|
||||
|
5
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
5
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
@ -24,7 +24,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Defaulter defines functions for setting defaults on resources
|
||||
// Defaulter defines functions for setting defaults on resources.
|
||||
type Defaulter interface {
|
||||
runtime.Object
|
||||
Default()
|
||||
@ -58,8 +58,7 @@ func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
|
||||
// Get the object in the request
|
||||
obj := h.defaulter.DeepCopyObject().(Defaulter)
|
||||
err := h.decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
if err := h.decoder.Decode(req, obj); err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
|
94
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
94
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
@ -24,9 +24,10 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
@ -35,7 +36,8 @@ var admissionScheme = runtime.NewScheme()
|
||||
var admissionCodecs = serializer.NewCodecFactory(admissionScheme)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(admissionv1beta1.AddToScheme(admissionScheme))
|
||||
utilruntime.Must(v1.AddToScheme(admissionScheme))
|
||||
utilruntime.Must(v1beta1.AddToScheme(admissionScheme))
|
||||
}
|
||||
|
||||
var _ http.Handler = &Webhook{}
|
||||
@ -43,16 +45,13 @@ var _ http.Handler = &Webhook{}
|
||||
func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var body []byte
|
||||
var err error
|
||||
ctx := r.Context()
|
||||
if wh.WithContextFunc != nil {
|
||||
ctx = wh.WithContextFunc(ctx, r)
|
||||
}
|
||||
|
||||
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 {
|
||||
if r.Body == nil {
|
||||
err = errors.New("request body is empty")
|
||||
wh.log.Error(err, "bad request")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
@ -60,9 +59,16 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
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
|
||||
}
|
||||
|
||||
// verify the content type is accurate
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
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)
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
@ -70,12 +76,19 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Both v1 and v1beta1 AdmissionReview types are exactly the same, so the v1beta1 type can
|
||||
// be decoded into the v1 type. However the runtime codec's decoder guesses which type to
|
||||
// decode into by type name if an Object's TypeMeta isn't set. By setting TypeMeta of an
|
||||
// unregistered type to the v1 GVK, the decoder will coerce a v1beta1 AdmissionReview to v1.
|
||||
// The actual AdmissionReview GVK will be used to write a typed response in case the
|
||||
// webhook config permits multiple versions, otherwise this response will fail.
|
||||
req := Request{}
|
||||
ar := v1beta1.AdmissionReview{
|
||||
// avoid an extra copy
|
||||
Request: &req.AdmissionRequest,
|
||||
}
|
||||
if _, _, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar); err != nil {
|
||||
ar := unversionedAdmissionReview{}
|
||||
// avoid an extra copy
|
||||
ar.Request = &req.AdmissionRequest
|
||||
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")
|
||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||
wh.writeResponse(w, reviewResponse)
|
||||
@ -83,22 +96,51 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
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)
|
||||
reviewResponse = wh.Handle(ctx, req)
|
||||
wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
|
||||
}
|
||||
|
||||
// writeResponse writes response to w generically, i.e. without encoding GVK information.
|
||||
func (wh *Webhook) writeResponse(w io.Writer, response Response) {
|
||||
encoder := json.NewEncoder(w)
|
||||
responseAdmissionReview := v1beta1.AdmissionReview{
|
||||
wh.writeAdmissionResponse(w, v1.AdmissionReview{Response: &response.AdmissionResponse})
|
||||
}
|
||||
|
||||
// writeResponseTyped writes response to w with GVK set to admRevGVK, which is necessary
|
||||
// if multiple AdmissionReview versions are permitted by the webhook.
|
||||
func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK *schema.GroupVersionKind) {
|
||||
ar := v1.AdmissionReview{
|
||||
Response: &response.AdmissionResponse,
|
||||
}
|
||||
err := encoder.Encode(responseAdmissionReview)
|
||||
if err != nil {
|
||||
// Default to a v1 AdmissionReview, otherwise the API server may not recognize the request
|
||||
// if multiple AdmissionReview versions are permitted by the webhook config.
|
||||
// TODO(estroz): this should be configurable since older API servers won't know about v1.
|
||||
if admRevGVK == nil || *admRevGVK == (schema.GroupVersionKind{}) {
|
||||
ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
|
||||
} else {
|
||||
ar.SetGroupVersionKind(*admRevGVK)
|
||||
}
|
||||
wh.writeAdmissionResponse(w, ar)
|
||||
}
|
||||
|
||||
// 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 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)
|
||||
res := ar.Response
|
||||
if log := wh.log; log.V(1).Enabled() {
|
||||
if res.Result != nil {
|
||||
log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason)
|
||||
}
|
||||
log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unversionedAdmissionReview is used to decode both v1 and v1beta1 AdmissionReview types.
|
||||
type unversionedAdmissionReview struct {
|
||||
v1.AdmissionReview
|
||||
}
|
||||
|
||||
var _ runtime.Object = &unversionedAdmissionReview{}
|
||||
|
35
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
35
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
@ -22,9 +22,10 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
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"
|
||||
)
|
||||
|
||||
@ -37,10 +38,10 @@ func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
|
||||
if !resp.Allowed {
|
||||
return resp
|
||||
}
|
||||
if resp.PatchType != nil && *resp.PatchType != admissionv1beta1.PatchTypeJSONPatch {
|
||||
if resp.PatchType != nil && *resp.PatchType != admissionv1.PatchTypeJSONPatch {
|
||||
return Errored(http.StatusInternalServerError,
|
||||
fmt.Errorf("unexpected patch type returned by the handler: %v, only allow: %v",
|
||||
resp.PatchType, admissionv1beta1.PatchTypeJSONPatch))
|
||||
resp.PatchType, admissionv1.PatchTypeJSONPatch))
|
||||
}
|
||||
patches = append(patches, resp.Patches...)
|
||||
}
|
||||
@ -50,13 +51,13 @@ func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
|
||||
return Errored(http.StatusBadRequest, fmt.Errorf("error when marshaling the patch: %w", err))
|
||||
}
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
Code: http.StatusOK,
|
||||
},
|
||||
Patch: marshaledPatch,
|
||||
PatchType: func() *admissionv1beta1.PatchType { pt := admissionv1beta1.PatchTypeJSONPatch; return &pt }(),
|
||||
PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -76,6 +77,16 @@ func (hs multiMutating) InjectFunc(f inject.Func) error {
|
||||
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
|
||||
@ -94,7 +105,7 @@ func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
|
||||
}
|
||||
}
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
Code: http.StatusOK,
|
||||
@ -124,3 +135,13 @@ func (hs multiValidating) InjectFunc(f inject.Func) error {
|
||||
|
||||
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
|
||||
}
|
||||
|
39
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
39
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
@ -19,9 +19,8 @@ package admission
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@ -50,7 +49,7 @@ func Patched(reason string, patches ...jsonpatch.JsonPatchOperation) Response {
|
||||
// Errored creates a new Response for error-handling a request.
|
||||
func Errored(code int32, err error) Response {
|
||||
return Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Code: code,
|
||||
@ -67,7 +66,7 @@ func ValidationResponse(allowed bool, reason string) Response {
|
||||
code = http.StatusOK
|
||||
}
|
||||
resp := Response{
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: allowed,
|
||||
Result: &metav1.Status{
|
||||
Code: int32(code),
|
||||
@ -90,9 +89,33 @@ func PatchResponseFromRaw(original, current []byte) Response {
|
||||
}
|
||||
return Response{
|
||||
Patches: patches,
|
||||
AdmissionResponse: admissionv1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
PatchType: func() *admissionv1beta1.PatchType { pt := admissionv1beta1.PatchTypeJSONPatch; return &pt }(),
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
PatchType: func() *admissionv1.PatchType {
|
||||
if len(patches) == 0 {
|
||||
return nil
|
||||
}
|
||||
pt := admissionv1.PatchTypeJSONPatch
|
||||
return &pt
|
||||
}(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// validationResponseFromStatus returns a response for admitting a request with provided Status object.
|
||||
func validationResponseFromStatus(allowed bool, status metav1.Status) Response {
|
||||
resp := Response{
|
||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||
Allowed: allowed,
|
||||
Result: &status,
|
||||
},
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// WithWarnings adds the given warnings to the Response.
|
||||
// If any warnings were already given, they will not be overwritten.
|
||||
func (r Response) WithWarnings(warnings ...string) Response {
|
||||
r.AdmissionResponse.Warnings = append(r.AdmissionResponse.Warnings, warnings...)
|
||||
return r
|
||||
}
|
||||
|
24
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
24
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
@ -18,13 +18,15 @@ package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
goerrors "errors"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Validator defines functions for validating an operation
|
||||
// Validator defines functions for validating an operation.
|
||||
type Validator interface {
|
||||
runtime.Object
|
||||
ValidateCreate() error
|
||||
@ -60,7 +62,7 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
|
||||
// Get the object in the request
|
||||
obj := h.validator.DeepCopyObject().(Validator)
|
||||
if req.Operation == v1beta1.Create {
|
||||
if req.Operation == v1.Create {
|
||||
err := h.decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
return Errored(http.StatusBadRequest, err)
|
||||
@ -68,11 +70,15 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
|
||||
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 == v1beta1.Update {
|
||||
if req.Operation == v1.Update {
|
||||
oldObj := obj.DeepCopyObject()
|
||||
|
||||
err := h.decoder.DecodeRaw(req.Object, obj)
|
||||
@ -86,11 +92,15 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
|
||||
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 == v1beta1.Delete {
|
||||
if req.Operation == 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)
|
||||
@ -100,6 +110,10 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||
|
||||
err = obj.ValidateDelete()
|
||||
if err != nil {
|
||||
var apiStatus apierrors.APIStatus
|
||||
if goerrors.As(err, &apiStatus) {
|
||||
return validationResponseFromStatus(false, apiStatus.Status())
|
||||
}
|
||||
return Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
93
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
93
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
@ -22,13 +22,16 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
jsonpatch "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"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -41,7 +44,7 @@ var (
|
||||
// name, namespace), as well as the operation in question
|
||||
// (e.g. Get, Create, etc), and the object itself.
|
||||
type Request struct {
|
||||
admissionv1beta1.AdmissionRequest
|
||||
admissionv1.AdmissionRequest
|
||||
}
|
||||
|
||||
// Response is the output of an admission handler.
|
||||
@ -57,7 +60,7 @@ type Response struct {
|
||||
Patches []jsonpatch.JsonPatchOperation
|
||||
// AdmissionResponse is the raw admission response.
|
||||
// The Patch field in it will be overwritten by the listed patches.
|
||||
admissionv1beta1.AdmissionResponse
|
||||
admissionv1.AdmissionResponse
|
||||
}
|
||||
|
||||
// Complete populates any fields that are yet to be set in
|
||||
@ -84,7 +87,7 @@ func (r *Response) Complete(req Request) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchType := admissionv1beta1.PatchTypeJSONPatch
|
||||
patchType := admissionv1.PatchTypeJSONPatch
|
||||
r.PatchType = &patchType
|
||||
|
||||
return nil
|
||||
@ -110,11 +113,19 @@ func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
|
||||
}
|
||||
|
||||
// Webhook represents each individual webhook.
|
||||
//
|
||||
// It must be registered with a webhook.Server or
|
||||
// populated by StandaloneWebhook to be ran on an arbitrary HTTP server.
|
||||
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
|
||||
|
||||
// WithContextFunc will allow you to take the http.Request.Context() and
|
||||
// add any additional information such as passing the request path or
|
||||
// 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
|
||||
|
||||
@ -122,8 +133,8 @@ type Webhook struct {
|
||||
}
|
||||
|
||||
// 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
|
||||
func (wh *Webhook) InjectLogger(l logr.Logger) error {
|
||||
wh.log = l
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -131,10 +142,10 @@ func (w *Webhook) InjectLogger(l logr.Logger) error {
|
||||
// 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)
|
||||
func (wh *Webhook) Handle(ctx context.Context, req Request) Response {
|
||||
resp := wh.Handler.Handle(ctx, req)
|
||||
if err := resp.Complete(req); err != nil {
|
||||
w.log.Error(err, "unable to encode response")
|
||||
wh.log.Error(err, "unable to encode response")
|
||||
return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
||||
}
|
||||
|
||||
@ -142,19 +153,19 @@ func (w *Webhook) Handle(ctx context.Context, req Request) Response {
|
||||
}
|
||||
|
||||
// InjectScheme injects a scheme into the webhook, in order to construct a Decoder.
|
||||
func (w *Webhook) InjectScheme(s *runtime.Scheme) error {
|
||||
func (wh *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)
|
||||
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 w.Handler != nil {
|
||||
if _, err := InjectDecoderInto(w.GetDecoder(), w.Handler); err != nil {
|
||||
if wh.Handler != nil {
|
||||
if _, err := InjectDecoderInto(wh.GetDecoder(), wh.Handler); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -164,12 +175,12 @@ func (w *Webhook) InjectScheme(s *runtime.Scheme) error {
|
||||
|
||||
// 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
|
||||
func (wh *Webhook) GetDecoder() *Decoder {
|
||||
return wh.decoder
|
||||
}
|
||||
|
||||
// InjectFunc injects the field setter into the webhook.
|
||||
func (w *Webhook) InjectFunc(f inject.Func) error {
|
||||
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
|
||||
@ -189,12 +200,56 @@ func (w *Webhook) InjectFunc(f inject.Func) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := InjectDecoderInto(w.GetDecoder(), target); err != nil {
|
||||
if _, err := InjectDecoderInto(wh.GetDecoder(), target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return setFields(w.Handler)
|
||||
return setFields(wh.Handler)
|
||||
}
|
||||
|
||||
// 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
|
||||
// MetricsPath is used for labelling prometheus metrics
|
||||
// by the path is served on.
|
||||
// If none is set, prometheus metrics will not be generated.
|
||||
MetricsPath string
|
||||
}
|
||||
|
||||
// StandaloneWebhook prepares a webhook for use without a webhook.Server,
|
||||
// passing in the information normally populated by webhook.Server
|
||||
// and instrumenting the webhook with metrics.
|
||||
//
|
||||
// Use this to attach your webhook to an arbitrary HTTP server or mux.
|
||||
//
|
||||
// Note that you are responsible for terminating TLS if you use StandaloneWebhook
|
||||
// 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 err := hook.InjectScheme(opts.Scheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.Logger == nil {
|
||||
opts.Logger = logf.RuntimeLog.WithName("webhook")
|
||||
}
|
||||
hook.log = opts.Logger
|
||||
|
||||
if opts.MetricsPath == "" {
|
||||
return hook, nil
|
||||
}
|
||||
return metrics.InstrumentedHook(opts.MetricsPath, hook), nil
|
||||
}
|
||||
|
4
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
generated
vendored
4
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
generated
vendored
@ -23,10 +23,10 @@ import (
|
||||
|
||||
// define some aliases for common bits of the webhook functionality
|
||||
|
||||
// Defaulter defines functions for setting defaults on resources
|
||||
// Defaulter defines functions for setting defaults on resources.
|
||||
type Defaulter = admission.Defaulter
|
||||
|
||||
// Validator defines functions for validating an operation
|
||||
// Validator defines functions for validating an operation.
|
||||
type Validator = admission.Validator
|
||||
|
||||
// AdmissionRequest defines the input for an admission handler.
|
||||
|
162
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/certwatcher/certwatcher.go
generated
vendored
162
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/certwatcher/certwatcher.go
generated
vendored
@ -1,162 +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 certwatcher
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/fsnotify.v1"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
)
|
||||
|
||||
var log = logf.RuntimeLog.WithName("certwatcher")
|
||||
|
||||
// CertWatcher watches certificate and key files for changes. When either file
|
||||
// changes, it reads and parses both and calls an optional callback with the new
|
||||
// certificate.
|
||||
type CertWatcher struct {
|
||||
sync.Mutex
|
||||
|
||||
currentCert *tls.Certificate
|
||||
watcher *fsnotify.Watcher
|
||||
|
||||
certPath string
|
||||
keyPath string
|
||||
}
|
||||
|
||||
// New returns a new CertWatcher watching the given certificate and key.
|
||||
func New(certPath, keyPath string) (*CertWatcher, error) {
|
||||
var err error
|
||||
|
||||
cw := &CertWatcher{
|
||||
certPath: certPath,
|
||||
keyPath: keyPath,
|
||||
}
|
||||
|
||||
// Initial read of certificate and key.
|
||||
if err := cw.ReadCertificate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cw.watcher, err = fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cw, nil
|
||||
}
|
||||
|
||||
// GetCertificate fetches the currently loaded certificate, which may be nil.
|
||||
func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
cw.Lock()
|
||||
defer cw.Unlock()
|
||||
return cw.currentCert, nil
|
||||
}
|
||||
|
||||
// Start starts the watch on the certificate and key files.
|
||||
func (cw *CertWatcher) Start(stopCh <-chan struct{}) error {
|
||||
files := []string{cw.certPath, cw.keyPath}
|
||||
|
||||
for _, f := range files {
|
||||
if err := cw.watcher.Add(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
go cw.Watch()
|
||||
|
||||
log.Info("Starting certificate watcher")
|
||||
|
||||
// Block until the stop channel is closed.
|
||||
<-stopCh
|
||||
|
||||
return cw.watcher.Close()
|
||||
}
|
||||
|
||||
// Watch reads events from the watcher's channel and reacts to changes.
|
||||
func (cw *CertWatcher) Watch() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-cw.watcher.Events:
|
||||
// Channel is closed.
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
cw.handleEvent(event)
|
||||
|
||||
case err, ok := <-cw.watcher.Errors:
|
||||
// Channel is closed.
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
log.Error(err, "certificate watch error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadCertificate reads the certificate and key files from disk, parses them,
|
||||
// and updates the current certificate on the watcher. If a callback is set, it
|
||||
// is invoked with the new certificate.
|
||||
func (cw *CertWatcher) ReadCertificate() error {
|
||||
cert, err := tls.LoadX509KeyPair(cw.certPath, cw.keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cw.Lock()
|
||||
cw.currentCert = &cert
|
||||
cw.Unlock()
|
||||
|
||||
log.Info("Updated current TLS certificate")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
|
||||
// Only care about events which may modify the contents of the file.
|
||||
if !(isWrite(event) || isRemove(event) || isCreate(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
log.V(1).Info("certificate event", "event", event)
|
||||
|
||||
// If the file was removed, re-add the watch.
|
||||
if isRemove(event) {
|
||||
if err := cw.watcher.Add(event.Name); err != nil {
|
||||
log.Error(err, "error re-watching file")
|
||||
}
|
||||
}
|
||||
|
||||
if err := cw.ReadCertificate(); err != nil {
|
||||
log.Error(err, "error re-reading certificate")
|
||||
}
|
||||
}
|
||||
|
||||
func isWrite(event fsnotify.Event) bool {
|
||||
return event.Op&fsnotify.Write == fsnotify.Write
|
||||
}
|
||||
|
||||
func isCreate(event fsnotify.Event) bool {
|
||||
return event.Op&fsnotify.Create == fsnotify.Create
|
||||
}
|
||||
|
||||
func isRemove(event fsnotify.Event) bool {
|
||||
return event.Op&fsnotify.Remove == fsnotify.Remove
|
||||
}
|
49
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
generated
vendored
49
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
generated
vendored
@ -17,7 +17,10 @@ limitations under the License.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
)
|
||||
@ -32,9 +35,51 @@ var (
|
||||
},
|
||||
[]string{"webhook"},
|
||||
)
|
||||
|
||||
// RequestTotal is a prometheus metric which is a counter of the total processed admission requests.
|
||||
RequestTotal = func() *prometheus.CounterVec {
|
||||
return prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "controller_runtime_webhook_requests_total",
|
||||
Help: "Total number of admission requests by HTTP status code.",
|
||||
},
|
||||
[]string{"webhook", "code"},
|
||||
)
|
||||
}()
|
||||
|
||||
// RequestInFlight is a prometheus metric which is a gauge of the in-flight admission requests.
|
||||
RequestInFlight = func() *prometheus.GaugeVec {
|
||||
return prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "controller_runtime_webhook_requests_in_flight",
|
||||
Help: "Current number of admission requests being served.",
|
||||
},
|
||||
[]string{"webhook"},
|
||||
)
|
||||
}()
|
||||
)
|
||||
|
||||
func init() {
|
||||
metrics.Registry.MustRegister(
|
||||
RequestLatency)
|
||||
metrics.Registry.MustRegister(RequestLatency, RequestTotal, RequestInFlight)
|
||||
}
|
||||
|
||||
// InstrumentedHook adds some instrumentation on top of the given webhook.
|
||||
func InstrumentedHook(path string, hookRaw http.Handler) http.Handler {
|
||||
lbl := prometheus.Labels{"webhook": path}
|
||||
|
||||
lat := RequestLatency.MustCurryWith(lbl)
|
||||
cnt := RequestTotal.MustCurryWith(lbl)
|
||||
gge := RequestInFlight.With(lbl)
|
||||
|
||||
// Initialize the most likely HTTP status codes.
|
||||
cnt.WithLabelValues("200")
|
||||
cnt.WithLabelValues("500")
|
||||
|
||||
return promhttp.InstrumentHandlerDuration(
|
||||
lat,
|
||||
promhttp.InstrumentHandlerCounter(
|
||||
cnt,
|
||||
promhttp.InstrumentHandlerInFlight(gge, hookRaw),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
151
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
151
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
@ -28,25 +28,32 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"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/runtime/inject"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/certwatcher"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||
)
|
||||
|
||||
// DefaultPort is the default port that the webhook server serves.
|
||||
var DefaultPort = 443
|
||||
var DefaultPort = 9443
|
||||
|
||||
// Server is an admission webhook server that can serve traffic and
|
||||
// generates related k8s resources for deploying.
|
||||
//
|
||||
// TLS is required for a webhook to be accessed by kubernetes, so
|
||||
// you must provide a CertName and KeyName or have valid cert/key
|
||||
// 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 {
|
||||
// Host is the address that the server will listen on.
|
||||
// Defaults to "" - all addresses.
|
||||
Host string
|
||||
|
||||
// Port is the port number that the server will serve.
|
||||
// It will be defaulted to 443 if unspecified.
|
||||
// It will be defaulted to 9443 if unspecified.
|
||||
Port int
|
||||
|
||||
// CertDir is the directory that contains the server key and certificate. The
|
||||
@ -63,6 +70,10 @@ type Server struct {
|
||||
// Defaults to "", which means server does not verify client's certificate.
|
||||
ClientCAName string
|
||||
|
||||
// TLSVersion is the minimum version of TLS supported. Accepts
|
||||
// "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility)
|
||||
TLSMinVersion string
|
||||
|
||||
// WebhookMux is the multiplexer that handles different webhooks.
|
||||
WebhookMux *http.ServeMux
|
||||
|
||||
@ -75,6 +86,9 @@ type Server struct {
|
||||
|
||||
// defaultingOnce ensures that the default fields are only ever set once.
|
||||
defaultingOnce sync.Once
|
||||
|
||||
// mu protects access to the webhook map & setFields for Start, Register, etc
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// setDefaults does defaulting for the Server.
|
||||
@ -110,50 +124,87 @@ func (*Server) 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.
|
||||
func (s *Server) Register(path string, hook http.Handler) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.defaultingOnce.Do(s.setDefaults)
|
||||
_, found := s.webhooks[path]
|
||||
if found {
|
||||
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, instrumentedHook(path, hook))
|
||||
log.Info("registering webhook", "path", path)
|
||||
}
|
||||
s.WebhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
|
||||
|
||||
// instrumentedHook adds some instrumentation on top of the given webhook.
|
||||
func instrumentedHook(path string, hookRaw http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
startTS := time.Now()
|
||||
defer func() { metrics.RequestLatency.WithLabelValues(path).Observe(time.Since(startTS).Seconds()) }()
|
||||
hookRaw.ServeHTTP(resp, req)
|
||||
regLog := log.WithValues("path", path)
|
||||
regLog.Info("registering webhook")
|
||||
|
||||
// TODO(directxman12): add back in metric about total requests broken down by result?
|
||||
})
|
||||
}
|
||||
|
||||
// Start runs the server.
|
||||
// It will install the webhook related resources depend on the server configuration.
|
||||
func (s *Server) Start(stop <-chan struct{}) error {
|
||||
s.defaultingOnce.Do(s.setDefaults)
|
||||
|
||||
baseHookLog := log.WithName("webhooks")
|
||||
baseHookLog.Info("starting webhook server")
|
||||
|
||||
// inject fields here as opposed to in Register so that we're certain to have our setFields
|
||||
// function available.
|
||||
for hookPath, webhook := range s.webhooks {
|
||||
if err := s.setFields(webhook); err != nil {
|
||||
return err
|
||||
// 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", hookPath), webhook); err != nil {
|
||||
return err
|
||||
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")
|
||||
// to the values accepted by tls.Config (for example 0x301).
|
||||
func tlsVersion(version string) (uint16, error) {
|
||||
switch version {
|
||||
// default is previous behaviour
|
||||
case "":
|
||||
return tls.VersionTLS10, nil
|
||||
case "1.0":
|
||||
return tls.VersionTLS10, nil
|
||||
case "1.1":
|
||||
return tls.VersionTLS11, nil
|
||||
case "1.2":
|
||||
return tls.VersionTLS12, nil
|
||||
case "1.3":
|
||||
return tls.VersionTLS13, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid TLSMinVersion %v: expects 1.0, 1.1, 1.2, 1.3 or empty", version)
|
||||
}
|
||||
}
|
||||
|
||||
// Start runs the server.
|
||||
// It will install the webhook related resources depend on the server configuration.
|
||||
func (s *Server) 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)
|
||||
@ -164,14 +215,20 @@ func (s *Server) Start(stop <-chan struct{}) error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := certWatcher.Start(stop); err != nil {
|
||||
if err := certWatcher.Start(ctx); err != nil {
|
||||
log.Error(err, "certificate watcher error")
|
||||
}
|
||||
}()
|
||||
|
||||
cfg := &tls.Config{
|
||||
tlsMinVersion, err := tlsVersion(s.TLSMinVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg := &tls.Config{ //nolint:gosec
|
||||
NextProtos: []string{"h2"},
|
||||
GetCertificate: certWatcher.GetCertificate,
|
||||
MinVersion: tlsMinVersion,
|
||||
}
|
||||
|
||||
// load CA to verify client certificate
|
||||
@ -191,7 +248,7 @@ func (s *Server) Start(stop <-chan struct{}) error {
|
||||
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(int(s.Port))), cfg)
|
||||
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -204,7 +261,7 @@ func (s *Server) Start(stop <-chan struct{}) error {
|
||||
|
||||
idleConnsClosed := make(chan struct{})
|
||||
go func() {
|
||||
<-stop
|
||||
<-ctx.Done()
|
||||
log.Info("shutting down webhook server")
|
||||
|
||||
// TODO: use a context with reasonable timeout
|
||||
@ -215,8 +272,7 @@ func (s *Server) Start(stop <-chan struct{}) error {
|
||||
close(idleConnsClosed)
|
||||
}()
|
||||
|
||||
err = srv.Serve(listener)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -227,5 +283,20 @@ func (s *Server) Start(stop <-chan struct{}) error {
|
||||
// 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
|
||||
}
|
||||
|
Reference in New Issue
Block a user