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 }