knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/contexts.go (about)

     1  /*
     2  Copyright 2019 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package apis
    18  
    19  import (
    20  	"context"
    21  	"net/http"
    22  
    23  	authenticationv1 "k8s.io/api/authentication/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  )
    26  
    27  // This is attached to contexts passed to webhook interfaces when
    28  // the receiver being validated is being created.
    29  type inCreateKey struct{}
    30  
    31  // WithinCreate is used to note that the webhook is calling within
    32  // the context of a Create operation.
    33  func WithinCreate(ctx context.Context) context.Context {
    34  	return context.WithValue(ctx, inCreateKey{}, struct{}{})
    35  }
    36  
    37  // IsInCreate checks whether the context is a Create.
    38  func IsInCreate(ctx context.Context) bool {
    39  	return ctx.Value(inCreateKey{}) != nil
    40  }
    41  
    42  // This is attached to contexts passed to webhook interfaces when
    43  // the receiver being validated is being deleted.
    44  type inDeleteKey struct{}
    45  
    46  // WithinDelete is used to note that the webhook is calling within
    47  // the context of a Delete operation.
    48  func WithinDelete(ctx context.Context) context.Context {
    49  	return context.WithValue(ctx, inDeleteKey{}, struct{}{})
    50  }
    51  
    52  // IsInDelete checks whether the context is a Delete.
    53  func IsInDelete(ctx context.Context) bool {
    54  	return ctx.Value(inDeleteKey{}) != nil
    55  }
    56  
    57  // This is attached to contexts passed to webhook interfaces when
    58  // the receiver being validated is being updated.
    59  type inUpdateKey struct{}
    60  
    61  type updatePayload struct {
    62  	base        interface{}
    63  	subresource string
    64  }
    65  
    66  // WithinUpdate is used to note that the webhook is calling within
    67  // the context of a Update operation.
    68  func WithinUpdate(ctx context.Context, base interface{}) context.Context {
    69  	return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
    70  		base: base,
    71  	})
    72  }
    73  
    74  // WithinSubResourceUpdate is used to note that the webhook is calling within
    75  // the context of a Update operation on a subresource.
    76  func WithinSubResourceUpdate(ctx context.Context, base interface{}, sr string) context.Context {
    77  	return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
    78  		base:        base,
    79  		subresource: sr,
    80  	})
    81  }
    82  
    83  // IsInUpdate checks whether the context is an Update.
    84  func IsInUpdate(ctx context.Context) bool {
    85  	return ctx.Value(inUpdateKey{}) != nil
    86  }
    87  
    88  // GetUpdatedSubresource returns the subresource being updated or "" if there
    89  // is no subresource that's being updated. Examples are "status" for Status
    90  // updates, or "scale" for scaling Deployment.
    91  func GetUpdatedSubresource(ctx context.Context) string {
    92  	value := ctx.Value(inUpdateKey{})
    93  	if value == nil {
    94  		return ""
    95  	}
    96  	up := value.(*updatePayload)
    97  	return up.subresource
    98  }
    99  
   100  // IsInStatusUpdate checks whether the context is an Update.
   101  func IsInStatusUpdate(ctx context.Context) bool {
   102  	return GetUpdatedSubresource(ctx) == "status"
   103  }
   104  
   105  // GetBaseline returns the baseline of the update, or nil when we
   106  // are not within an update context.
   107  func GetBaseline(ctx context.Context) interface{} {
   108  	value := ctx.Value(inUpdateKey{})
   109  	if value == nil {
   110  		return nil
   111  	}
   112  	return value.(*updatePayload).base
   113  }
   114  
   115  // This is attached to contexts passed to webhook interfaces when
   116  // the receiver being validated is being created.
   117  type userInfoKey struct{}
   118  
   119  // WithUserInfo is used to note that the webhook is calling within
   120  // the context of a Create operation.
   121  func WithUserInfo(ctx context.Context, ui *authenticationv1.UserInfo) context.Context {
   122  	return context.WithValue(ctx, userInfoKey{}, ui)
   123  }
   124  
   125  // GetUserInfo accesses the UserInfo attached to the webhook context.
   126  func GetUserInfo(ctx context.Context) *authenticationv1.UserInfo {
   127  	if ui, ok := ctx.Value(userInfoKey{}).(*authenticationv1.UserInfo); ok {
   128  		return ui
   129  	}
   130  	return nil
   131  }
   132  
   133  // This is attached to contexts as they are passed down through a resource
   134  // being validated or defaulted to signal the ObjectMeta of the enclosing
   135  // resource.
   136  type parentMetaKey struct{}
   137  
   138  // WithinParent attaches the ObjectMeta of the resource enclosing the
   139  // nested resources we are validating.  This is intended for use with
   140  // interfaces like apis.Defaultable and apis.Validatable.
   141  func WithinParent(ctx context.Context, om metav1.ObjectMeta) context.Context {
   142  	return context.WithValue(ctx, parentMetaKey{}, om)
   143  }
   144  
   145  // IsWithinParent returns true if we're within parent context.
   146  func IsWithinParent(ctx context.Context) bool {
   147  	_, ok := ctx.Value(parentMetaKey{}).(metav1.ObjectMeta)
   148  	return ok
   149  }
   150  
   151  // ParentMeta accesses the ObjectMeta of the enclosing parent resource
   152  // from the context.  See WithinParent for how to attach the parent's
   153  // ObjectMeta to the context.
   154  func ParentMeta(ctx context.Context) metav1.ObjectMeta {
   155  	if om, ok := ctx.Value(parentMetaKey{}).(metav1.ObjectMeta); ok {
   156  		return om
   157  	}
   158  	return metav1.ObjectMeta{}
   159  }
   160  
   161  // This is attached to contexts as they are passed down through a resource
   162  // being validated or defaulted to signal that we are within a Spec.
   163  type inSpec struct{}
   164  
   165  // WithinSpec notes on the context that further validation or defaulting
   166  // is within the context of a Spec.  This is intended for use with
   167  // interfaces like apis.Defaultable and apis.Validatable.
   168  func WithinSpec(ctx context.Context) context.Context {
   169  	return context.WithValue(ctx, inSpec{}, struct{}{})
   170  }
   171  
   172  // IsInSpec returns whether the context of validation or defaulting is
   173  // the Spec of the parent resource.
   174  func IsInSpec(ctx context.Context) bool {
   175  	return ctx.Value(inSpec{}) != nil
   176  }
   177  
   178  // This is attached to contexts as they are passed down through a resource
   179  // being validated or defaulted to signal that we are within a Status.
   180  type inStatus struct{}
   181  
   182  // WithinStatus notes on the context that further validation or defaulting
   183  // is within the context of a Status.  This is intended for use with
   184  // interfaces like apis.Defaultable and apis.Validatable.
   185  func WithinStatus(ctx context.Context) context.Context {
   186  	return context.WithValue(ctx, inStatus{}, struct{}{})
   187  }
   188  
   189  // IsInStatus returns whether the context of validation or defaulting is
   190  // the Status of the parent resource.
   191  func IsInStatus(ctx context.Context) bool {
   192  	return ctx.Value(inStatus{}) != nil
   193  }
   194  
   195  // This is attached to contexts as they are passed down through a resource
   196  // being validated to direct them to disallow deprecated fields.
   197  type disallowDeprecated struct{}
   198  
   199  // DisallowDeprecated notes on the context that further validation
   200  // should disallow the used of deprecated fields. This may be used
   201  // to ensure that new paths through resources to a common type don't
   202  // allow the mistakes of old versions to be introduced.
   203  func DisallowDeprecated(ctx context.Context) context.Context {
   204  	return context.WithValue(ctx, disallowDeprecated{}, struct{}{})
   205  }
   206  
   207  // IsDeprecatedAllowed checks the context to see whether deprecated fields
   208  // are allowed.
   209  func IsDeprecatedAllowed(ctx context.Context) bool {
   210  	return ctx.Value(disallowDeprecated{}) == nil
   211  }
   212  
   213  // This is attached to contexts as they are passed down through a resource
   214  // being validated to direct them to allow namespaces (or missing namespace)
   215  // outside the parent (as indicated by WithinParent.
   216  type allowDifferentNamespace struct{}
   217  
   218  // AllowDifferentNamespace notes on the context that further validation
   219  // should allow different namespaces from the encapsulating object. Mainly
   220  // used by KReference, since it by default requires namespaces to match.
   221  func AllowDifferentNamespace(ctx context.Context) context.Context {
   222  	return context.WithValue(ctx, allowDifferentNamespace{}, struct{}{})
   223  }
   224  
   225  // IsDifferentNamespaceAllowed checks the context to see whether different
   226  // namespace is allowed from the encapsulating object.
   227  func IsDifferentNamespaceAllowed(ctx context.Context) bool {
   228  	return ctx.Value(allowDifferentNamespace{}) != nil
   229  }
   230  
   231  // This is attached to contexts passed to webhook interfaces when the user
   232  // has requested DryRun mode.
   233  type isDryRun struct{}
   234  
   235  // WithDryRun is used to indicate that this call is in DryRun mode.
   236  func WithDryRun(ctx context.Context) context.Context {
   237  	return context.WithValue(ctx, isDryRun{}, struct{}{})
   238  }
   239  
   240  // IsDryRun indicates that this request is in DryRun mode.
   241  func IsDryRun(ctx context.Context) bool {
   242  	return ctx.Value(isDryRun{}) != nil
   243  }
   244  
   245  // This is attached to contexts passed to webhook interfaces with
   246  // additional context from the HTTP request.
   247  type httpReq struct{}
   248  
   249  // WithHTTPRequest associated the HTTP request object the webhook
   250  // received with the context.
   251  func WithHTTPRequest(ctx context.Context, r *http.Request) context.Context {
   252  	return context.WithValue(ctx, httpReq{}, r)
   253  }
   254  
   255  // GetHTTPRequest fetches the raw HTTP request received by the webhook.
   256  func GetHTTPRequest(ctx context.Context) *http.Request {
   257  	v := ctx.Value(httpReq{})
   258  	if v == nil {
   259  		return nil
   260  	}
   261  	return v.(*http.Request)
   262  }