mirror of https://github.com/knative/pkg.git
263 lines
8.9 KiB
Go
263 lines
8.9 KiB
Go
/*
|
|
Copyright 2019 The Knative 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 apis
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
authenticationv1 "k8s.io/api/authentication/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// This is attached to contexts passed to webhook interfaces when
|
|
// the receiver being validated is being created.
|
|
type inCreateKey struct{}
|
|
|
|
// WithinCreate is used to note that the webhook is calling within
|
|
// the context of a Create operation.
|
|
func WithinCreate(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, inCreateKey{}, struct{}{})
|
|
}
|
|
|
|
// IsInCreate checks whether the context is a Create.
|
|
func IsInCreate(ctx context.Context) bool {
|
|
return ctx.Value(inCreateKey{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts passed to webhook interfaces when
|
|
// the receiver being validated is being deleted.
|
|
type inDeleteKey struct{}
|
|
|
|
// WithinDelete is used to note that the webhook is calling within
|
|
// the context of a Delete operation.
|
|
func WithinDelete(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, inDeleteKey{}, struct{}{})
|
|
}
|
|
|
|
// IsInDelete checks whether the context is a Delete.
|
|
func IsInDelete(ctx context.Context) bool {
|
|
return ctx.Value(inDeleteKey{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts passed to webhook interfaces when
|
|
// the receiver being validated is being updated.
|
|
type inUpdateKey struct{}
|
|
|
|
type updatePayload struct {
|
|
base interface{}
|
|
subresource string
|
|
}
|
|
|
|
// WithinUpdate is used to note that the webhook is calling within
|
|
// the context of a Update operation.
|
|
func WithinUpdate(ctx context.Context, base interface{}) context.Context {
|
|
return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
|
|
base: base,
|
|
})
|
|
}
|
|
|
|
// WithinSubResourceUpdate is used to note that the webhook is calling within
|
|
// the context of a Update operation on a subresource.
|
|
func WithinSubResourceUpdate(ctx context.Context, base interface{}, sr string) context.Context {
|
|
return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
|
|
base: base,
|
|
subresource: sr,
|
|
})
|
|
}
|
|
|
|
// IsInUpdate checks whether the context is an Update.
|
|
func IsInUpdate(ctx context.Context) bool {
|
|
return ctx.Value(inUpdateKey{}) != nil
|
|
}
|
|
|
|
// GetUpdatedSubresource returns the subresource being updated or "" if there
|
|
// is no subresource that's being updated. Examples are "status" for Status
|
|
// updates, or "scale" for scaling Deployment.
|
|
func GetUpdatedSubresource(ctx context.Context) string {
|
|
value := ctx.Value(inUpdateKey{})
|
|
if value == nil {
|
|
return ""
|
|
}
|
|
up := value.(*updatePayload)
|
|
return up.subresource
|
|
}
|
|
|
|
// IsInStatusUpdate checks whether the context is an Update.
|
|
func IsInStatusUpdate(ctx context.Context) bool {
|
|
return GetUpdatedSubresource(ctx) == "status"
|
|
}
|
|
|
|
// GetBaseline returns the baseline of the update, or nil when we
|
|
// are not within an update context.
|
|
func GetBaseline(ctx context.Context) interface{} {
|
|
value := ctx.Value(inUpdateKey{})
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
return value.(*updatePayload).base
|
|
}
|
|
|
|
// This is attached to contexts passed to webhook interfaces when
|
|
// the receiver being validated is being created.
|
|
type userInfoKey struct{}
|
|
|
|
// WithUserInfo is used to note that the webhook is calling within
|
|
// the context of a Create operation.
|
|
func WithUserInfo(ctx context.Context, ui *authenticationv1.UserInfo) context.Context {
|
|
return context.WithValue(ctx, userInfoKey{}, ui)
|
|
}
|
|
|
|
// GetUserInfo accesses the UserInfo attached to the webhook context.
|
|
func GetUserInfo(ctx context.Context) *authenticationv1.UserInfo {
|
|
if ui, ok := ctx.Value(userInfoKey{}).(*authenticationv1.UserInfo); ok {
|
|
return ui
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// This is attached to contexts as they are passed down through a resource
|
|
// being validated or defaulted to signal the ObjectMeta of the enclosing
|
|
// resource.
|
|
type parentMetaKey struct{}
|
|
|
|
// WithinParent attaches the ObjectMeta of the resource enclosing the
|
|
// nested resources we are validating. This is intended for use with
|
|
// interfaces like apis.Defaultable and apis.Validatable.
|
|
func WithinParent(ctx context.Context, om metav1.ObjectMeta) context.Context {
|
|
return context.WithValue(ctx, parentMetaKey{}, om)
|
|
}
|
|
|
|
// IsWithinParent returns true if we're within parent context.
|
|
func IsWithinParent(ctx context.Context) bool {
|
|
_, ok := ctx.Value(parentMetaKey{}).(metav1.ObjectMeta)
|
|
return ok
|
|
}
|
|
|
|
// ParentMeta accesses the ObjectMeta of the enclosing parent resource
|
|
// from the context. See WithinParent for how to attach the parent's
|
|
// ObjectMeta to the context.
|
|
func ParentMeta(ctx context.Context) metav1.ObjectMeta {
|
|
if om, ok := ctx.Value(parentMetaKey{}).(metav1.ObjectMeta); ok {
|
|
return om
|
|
}
|
|
return metav1.ObjectMeta{}
|
|
}
|
|
|
|
// This is attached to contexts as they are passed down through a resource
|
|
// being validated or defaulted to signal that we are within a Spec.
|
|
type inSpec struct{}
|
|
|
|
// WithinSpec notes on the context that further validation or defaulting
|
|
// is within the context of a Spec. This is intended for use with
|
|
// interfaces like apis.Defaultable and apis.Validatable.
|
|
func WithinSpec(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, inSpec{}, struct{}{})
|
|
}
|
|
|
|
// IsInSpec returns whether the context of validation or defaulting is
|
|
// the Spec of the parent resource.
|
|
func IsInSpec(ctx context.Context) bool {
|
|
return ctx.Value(inSpec{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts as they are passed down through a resource
|
|
// being validated or defaulted to signal that we are within a Status.
|
|
type inStatus struct{}
|
|
|
|
// WithinStatus notes on the context that further validation or defaulting
|
|
// is within the context of a Status. This is intended for use with
|
|
// interfaces like apis.Defaultable and apis.Validatable.
|
|
func WithinStatus(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, inStatus{}, struct{}{})
|
|
}
|
|
|
|
// IsInStatus returns whether the context of validation or defaulting is
|
|
// the Status of the parent resource.
|
|
func IsInStatus(ctx context.Context) bool {
|
|
return ctx.Value(inStatus{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts as they are passed down through a resource
|
|
// being validated to direct them to disallow deprecated fields.
|
|
type disallowDeprecated struct{}
|
|
|
|
// DisallowDeprecated notes on the context that further validation
|
|
// should disallow the used of deprecated fields. This may be used
|
|
// to ensure that new paths through resources to a common type don't
|
|
// allow the mistakes of old versions to be introduced.
|
|
func DisallowDeprecated(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, disallowDeprecated{}, struct{}{})
|
|
}
|
|
|
|
// IsDeprecatedAllowed checks the context to see whether deprecated fields
|
|
// are allowed.
|
|
func IsDeprecatedAllowed(ctx context.Context) bool {
|
|
return ctx.Value(disallowDeprecated{}) == nil
|
|
}
|
|
|
|
// This is attached to contexts as they are passed down through a resource
|
|
// being validated to direct them to allow namespaces (or missing namespace)
|
|
// outside the parent (as indicated by WithinParent.
|
|
type allowDifferentNamespace struct{}
|
|
|
|
// AllowDifferentNamespace notes on the context that further validation
|
|
// should allow different namespaces from the encapsulating object. Mainly
|
|
// used by KReference, since it by default requires namespaces to match.
|
|
func AllowDifferentNamespace(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, allowDifferentNamespace{}, struct{}{})
|
|
}
|
|
|
|
// IsDifferentNamespaceAllowed checks the context to see whether different
|
|
// namespace is allowed from the encapsulating object.
|
|
func IsDifferentNamespaceAllowed(ctx context.Context) bool {
|
|
return ctx.Value(allowDifferentNamespace{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts passed to webhook interfaces when the user
|
|
// has requested DryRun mode.
|
|
type isDryRun struct{}
|
|
|
|
// WithDryRun is used to indicate that this call is in DryRun mode.
|
|
func WithDryRun(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, isDryRun{}, struct{}{})
|
|
}
|
|
|
|
// IsDryRun indicates that this request is in DryRun mode.
|
|
func IsDryRun(ctx context.Context) bool {
|
|
return ctx.Value(isDryRun{}) != nil
|
|
}
|
|
|
|
// This is attached to contexts passed to webhook interfaces with
|
|
// additional context from the HTTP request.
|
|
type httpReq struct{}
|
|
|
|
// WithHTTPRequest associated the HTTP request object the webhook
|
|
// received with the context.
|
|
func WithHTTPRequest(ctx context.Context, r *http.Request) context.Context {
|
|
return context.WithValue(ctx, httpReq{}, r)
|
|
}
|
|
|
|
// GetHTTPRequest fetches the raw HTTP request received by the webhook.
|
|
func GetHTTPRequest(ctx context.Context) *http.Request {
|
|
v := ctx.Value(httpReq{})
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
return v.(*http.Request)
|
|
}
|