knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/duck/v1/knative_reference.go (about) 1 /* 2 Copyright 2020 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 v1 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 24 "knative.dev/pkg/apis" 25 ) 26 27 // KReference contains enough information to refer to another object. 28 // It's a trimmed down version of corev1.ObjectReference. 29 type KReference struct { 30 // Kind of the referent. 31 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 32 Kind string `json:"kind"` 33 34 // Namespace of the referent. 35 // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ 36 // This is optional field, it gets defaulted to the object holding it if left out. 37 // +optional 38 Namespace string `json:"namespace,omitempty"` 39 40 // Name of the referent. 41 // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 42 Name string `json:"name"` 43 44 // API version of the referent. 45 // +optional 46 APIVersion string `json:"apiVersion,omitempty"` 47 48 // Group of the API, without the version of the group. This can be used as an alternative to the APIVersion, and then resolved using ResolveGroup. 49 // Note: This API is EXPERIMENTAL and might break anytime. For more details: https://github.com/knative/eventing/issues/5086 50 // +optional 51 Group string `json:"group,omitempty"` 52 53 // Address points to a specific Address Name. 54 // +optional 55 Address *string `json:"address,omitempty"` 56 } 57 58 func (kr *KReference) Validate(ctx context.Context) *apis.FieldError { 59 var errs *apis.FieldError 60 if kr == nil { 61 return errs.Also(apis.ErrMissingField("name")). 62 Also(apis.ErrMissingField("apiVersion")). 63 Also(apis.ErrMissingField("kind")) 64 } 65 if kr.Name == "" { 66 errs = errs.Also(apis.ErrMissingField("name")) 67 } 68 if isKReferenceGroupAllowed(ctx) { 69 if kr.APIVersion == "" && kr.Group == "" { 70 errs = errs.Also(apis.ErrMissingField("apiVersion")). 71 Also(apis.ErrMissingField("group")) 72 } 73 if kr.APIVersion != "" && kr.Group != "" && !strings.HasPrefix(kr.APIVersion, kr.Group) { 74 errs = errs.Also(&apis.FieldError{ 75 Message: "both apiVersion and group are specified and they refer to different API groups", 76 Paths: []string{"apiVersion", "group"}, 77 Details: "Only one of them must be specified", 78 }) 79 } 80 } else { 81 if kr.Group != "" { 82 errs = errs.Also(apis.ErrDisallowedFields("group")) 83 } 84 if kr.APIVersion == "" { 85 errs = errs.Also(apis.ErrMissingField("apiVersion")) 86 } 87 } 88 if kr.Kind == "" { 89 errs = errs.Also(apis.ErrMissingField("kind")) 90 } 91 // Only if namespace is empty validate it. This is to deal with legacy 92 // objects in the storage that may now have the namespace filled in. 93 // Because things get defaulted in other cases, moving forward the 94 // kr.Namespace will not be empty. 95 if kr.Namespace != "" { 96 if !apis.IsDifferentNamespaceAllowed(ctx) { 97 parentNS := apis.ParentMeta(ctx).Namespace 98 if parentNS != "" && kr.Namespace != parentNS { 99 errs = errs.Also(&apis.FieldError{ 100 Message: "mismatched namespaces", 101 Paths: []string{"namespace"}, 102 Details: fmt.Sprintf("parent namespace: %q does not match ref: %q", parentNS, kr.Namespace), 103 }) 104 } 105 } 106 } 107 return errs 108 } 109 110 // SetDefaults sets the default values on the KReference. 111 func (kr *KReference) SetDefaults(ctx context.Context) { 112 if kr.Namespace == "" { 113 kr.Namespace = apis.ParentMeta(ctx).Namespace 114 } 115 } 116 117 type isGroupAllowed struct{} 118 119 func isKReferenceGroupAllowed(ctx context.Context) bool { 120 return ctx.Value(isGroupAllowed{}) != nil 121 } 122 123 // KReferenceGroupAllowed notes on the context that further validation 124 // should allow the KReference.Group, which is disabled by default. 125 // Note: This API is EXPERIMENTAL and may disappear once the KReference.Group feature will stabilize. 126 // For more details: https://github.com/knative/eventing/issues/5086 127 func KReferenceGroupAllowed(ctx context.Context) context.Context { 128 return context.WithValue(ctx, isGroupAllowed{}, struct{}{}) 129 } 130 131 func (kr *KReference) String() string { 132 address := "" 133 if kr.Address != nil { 134 address = *kr.Address 135 } 136 return fmt.Sprintf("Kind = %s, Namespace = %s, Name = %s, APIVersion = %s, Group = %s, Address = %s", 137 kr.Kind, kr.Namespace, kr.Name, kr.APIVersion, kr.Group, address) 138 }