server

package
v0.0.0-...-2e24269 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 23, 2025 License: Apache-2.0 Imports: 16 Imported by: 1

Documentation

Index

Constants

This section is empty.

Variables

View Source
var New = utilhttp.DeclareServer(
	func(Args) string { return "webhook" },
	defaultHttpPort,
	defaultHttpsPort,
	func(_ Args, fs *flag.FlagSet) Options {
		return Options{
			pathPrefix: fs.String(
				"path-prefix",
				"",
				"Expected path prefix to strip from incoming requests, must start with a slash if set, e.g. `/webhook`",
			),
			dryRun: fs.Bool(
				"dry-run",
				false,
				"never reject any deletions, only update PodProtector and emit rejection metrics",
			),
		}
	},
	func(_ Args, reqs *component.DepRequests) Deps {
		return Deps{
			observer: o11y.Request[observer.Observer](reqs),
			handler:  component.DepPtr(reqs, handler.New(handler.Args{})),
		}
	},
	func(_ Args, options Options, deps Deps, mux *http.ServeMux) (*State, error) {
		mux.HandleFunc(
			fmt.Sprintf("POST %s/{cell}", *options.pathPrefix),
			func(resp http.ResponseWriter, req *http.Request) {
				cellId := req.PathValue("cell")

				ctx, cancelFunc := deps.observer.Get().HttpRequest(
					req.Context(),
					observer.Request{
						Cell:       cellId,
						RemoteAddr: req.RemoteAddr,
					},
				)
				defer cancelFunc()

				postBody, err := io.ReadAll(req.Body)
				if err != nil {
					err = errors.Tag("ReadBody", err)

					deps.observer.Get().HttpError(ctx, observer.HttpError{Err: err})

					resp.WriteHeader(http.StatusBadRequest)
					if _, err := resp.Write([]byte("Cannot read POST body")); err != nil {
						deps.observer.Get().HttpError(
							ctx,
							observer.HttpError{Err: err},
						)
					}

					return
				}

				reviewRequest := new(admissionv1.AdmissionReview)
				if err := json.Unmarshal(postBody, reviewRequest); err != nil {
					err = errors.Tag("UnmarshalBody", err)

					deps.observer.Get().HttpError(ctx, observer.HttpError{Err: err})

					resp.WriteHeader(http.StatusBadRequest)
					if _, err = resp.Write([]byte(fmt.Sprintf("error parsing JSON body: %v", err))); err != nil {
						deps.observer.Get().HttpError(
							ctx,
							observer.HttpError{Err: err},
						)
					}

					return
				}

				auditAnnotations := map[string]string{}
				result := deps.handler.Get().
					Handle(ctx, reviewRequest.Request, cellId, auditAnnotations)
				if result.Err != nil {
					err = errors.Tag("Handle", result.Err)

					deps.observer.Get().HttpError(ctx, observer.HttpError{Err: err})

					if !*options.dryRun {
						resp.WriteHeader(http.StatusInternalServerError)

						if _, err = resp.Write([]byte(fmt.Sprintf("server internal error: %v", err))); err != nil {
							deps.observer.Get().HttpError(
								ctx,
								observer.HttpError{Err: err},
							)
						}

						return
					}
				} else {
					deps.observer.Get().HttpRequestComplete(ctx, observer.RequestComplete{
						Request: reviewRequest.Request,
						Status:  result.Status,
					})

					if !*options.dryRun {
						_ = json.NewEncoder(resp).Encode(&admissionv1.AdmissionReview{
							TypeMeta: metav1.TypeMeta{
								APIVersion: admissionv1.SchemeGroupVersion.String(),
								Kind:       "AdmissionReview",
							},
							Response: &admissionv1.AdmissionResponse{
								UID:     reviewRequest.Request.UID,
								Allowed: !result.Rejection.IsSome(),
								Result: optional.Map(result.Rejection, handler.Rejection.ToStatus).
									GetOrZero(),
								AuditAnnotations: auditAnnotations,
							},
						})

						return
					}
				}

				auditAnnotations[podseidon.AuditAnnotationDryRun] = "1"

				_ = json.NewEncoder(resp).Encode(&admissionv1.AdmissionReview{
					TypeMeta: metav1.TypeMeta{
						APIVersion: admissionv1.SchemeGroupVersion.String(),
						Kind:       "AdmissionReview",
					},
					Response: &admissionv1.AdmissionResponse{
						UID:              reviewRequest.Request.UID,
						Allowed:          true,
						AuditAnnotations: auditAnnotations,
					},
				})
			},
		)

		return &State{}, nil
	},
	component.Lifecycle[Args, Options, Deps, State]{
		Start:        nil,
		Join:         nil,
		HealthChecks: nil,
	},
	func(Args, Options, Deps, *State) util.Empty { return util.Empty{} },
)

Functions

This section is empty.

Types

type Args

type Args struct{}

type Deps

type Deps struct {
	// contains filtered or unexported fields
}

type Options

type Options struct {
	// contains filtered or unexported fields
}

type State

type State struct{}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL