github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/schema/group_version.go (about) 1 /* 2 Copyright 2015 The Kubernetes 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 schema 18 19 import ( 20 "fmt" 21 "strings" 22 ) 23 24 // ParseResourceArg takes the common style of string which may be either `resource.group.com` or `resource.version.group.com` 25 // and parses it out into both possibilities. This code takes no responsibility for knowing which representation was intended 26 // but with a knowledge of all GroupVersions, calling code can take a very good guess. If there are only two segments, then 27 // `*GroupVersionResource` is nil. 28 // `resource.group.com` -> `group=com, version=group, resource=resource` and `group=group.com, resource=resource` 29 func ParseResourceArg(arg string) (*GroupVersionResource, GroupResource) { 30 var gvr *GroupVersionResource 31 if strings.Count(arg, ".") >= 2 { 32 s := strings.SplitN(arg, ".", 3) 33 gvr = &GroupVersionResource{Group: s[2], Version: s[1], Resource: s[0]} 34 } 35 36 return gvr, ParseGroupResource(arg) 37 } 38 39 // ParseKindArg takes the common style of string which may be either `Kind.group.com` or `Kind.version.group.com` 40 // and parses it out into both possibilities. This code takes no responsibility for knowing which representation was intended 41 // but with a knowledge of all GroupKinds, calling code can take a very good guess. If there are only two segments, then 42 // `*GroupVersionResource` is nil. 43 // `Kind.group.com` -> `group=com, version=group, kind=Kind` and `group=group.com, kind=Kind` 44 func ParseKindArg(arg string) (*GroupVersionKind, GroupKind) { 45 var gvk *GroupVersionKind 46 if strings.Count(arg, ".") >= 2 { 47 s := strings.SplitN(arg, ".", 3) 48 gvk = &GroupVersionKind{Group: s[2], Version: s[1], Kind: s[0]} 49 } 50 51 return gvk, ParseGroupKind(arg) 52 } 53 54 // GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying 55 // concepts during lookup stages without having partially valid types 56 type GroupResource struct { 57 Group string 58 Resource string 59 } 60 61 func (gr GroupResource) WithVersion(version string) GroupVersionResource { 62 return GroupVersionResource{Group: gr.Group, Version: version, Resource: gr.Resource} 63 } 64 65 func (gr GroupResource) Empty() bool { 66 return len(gr.Group) == 0 && len(gr.Resource) == 0 67 } 68 69 func (gr GroupResource) String() string { 70 if len(gr.Group) == 0 { 71 return gr.Resource 72 } 73 return gr.Resource + "." + gr.Group 74 } 75 76 func ParseGroupKind(gk string) GroupKind { 77 i := strings.Index(gk, ".") 78 if i == -1 { 79 return GroupKind{Kind: gk} 80 } 81 82 return GroupKind{Group: gk[i+1:], Kind: gk[:i]} 83 } 84 85 // ParseGroupResource turns "resource.group" string into a GroupResource struct. Empty strings are allowed 86 // for each field. 87 func ParseGroupResource(gr string) GroupResource { 88 if i := strings.Index(gr, "."); i >= 0 { 89 return GroupResource{Group: gr[i+1:], Resource: gr[:i]} 90 } 91 return GroupResource{Resource: gr} 92 } 93 94 // GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion 95 // to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling 96 type GroupVersionResource struct { 97 Group string 98 Version string 99 Resource string 100 } 101 102 func (gvr GroupVersionResource) Empty() bool { 103 return len(gvr.Group) == 0 && len(gvr.Version) == 0 && len(gvr.Resource) == 0 104 } 105 106 func (gvr GroupVersionResource) GroupResource() GroupResource { 107 return GroupResource{Group: gvr.Group, Resource: gvr.Resource} 108 } 109 110 func (gvr GroupVersionResource) GroupVersion() GroupVersion { 111 return GroupVersion{Group: gvr.Group, Version: gvr.Version} 112 } 113 114 func (gvr GroupVersionResource) String() string { 115 return strings.Join([]string{gvr.Group, "/", gvr.Version, ", Resource=", gvr.Resource}, "") 116 } 117 118 // GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying 119 // concepts during lookup stages without having partially valid types 120 type GroupKind struct { 121 Group string 122 Kind string 123 } 124 125 func (gk GroupKind) Empty() bool { 126 return len(gk.Group) == 0 && len(gk.Kind) == 0 127 } 128 129 func (gk GroupKind) WithVersion(version string) GroupVersionKind { 130 return GroupVersionKind{Group: gk.Group, Version: version, Kind: gk.Kind} 131 } 132 133 func (gk GroupKind) String() string { 134 if len(gk.Group) == 0 { 135 return gk.Kind 136 } 137 return gk.Kind + "." + gk.Group 138 } 139 140 // GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion 141 // to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling 142 type GroupVersionKind struct { 143 Group string 144 Version string 145 Kind string 146 } 147 148 // Empty returns true if group, version, and kind are empty 149 func (gvk GroupVersionKind) Empty() bool { 150 return len(gvk.Group) == 0 && len(gvk.Version) == 0 && len(gvk.Kind) == 0 151 } 152 153 func (gvk GroupVersionKind) GroupKind() GroupKind { 154 return GroupKind{Group: gvk.Group, Kind: gvk.Kind} 155 } 156 157 func (gvk GroupVersionKind) GroupVersion() GroupVersion { 158 return GroupVersion{Group: gvk.Group, Version: gvk.Version} 159 } 160 161 func (gvk GroupVersionKind) String() string { 162 return gvk.Group + "/" + gvk.Version + ", Kind=" + gvk.Kind 163 } 164 165 // GroupVersion contains the "group" and the "version", which uniquely identifies the API. 166 type GroupVersion struct { 167 Group string 168 Version string 169 } 170 171 // Empty returns true if group and version are empty 172 func (gv GroupVersion) Empty() bool { 173 return len(gv.Group) == 0 && len(gv.Version) == 0 174 } 175 176 // String puts "group" and "version" into a single "group/version" string. For the legacy v1 177 // it returns "v1". 178 func (gv GroupVersion) String() string { 179 if len(gv.Group) > 0 { 180 return gv.Group + "/" + gv.Version 181 } 182 return gv.Version 183 } 184 185 // Identifier implements runtime.GroupVersioner interface. 186 func (gv GroupVersion) Identifier() string { 187 return gv.String() 188 } 189 190 // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false 191 // if none of the options match the group. It prefers a match to group and version over just group. 192 // TODO: Move GroupVersion to a package under pkg/runtime, since it's used by scheme. 193 // TODO: Introduce an adapter type between GroupVersion and runtime.GroupVersioner, and use LegacyCodec(GroupVersion) 194 // 195 // in fewer places. 196 func (gv GroupVersion) KindForGroupVersionKinds(kinds []GroupVersionKind) (target GroupVersionKind, ok bool) { 197 for _, gvk := range kinds { 198 if gvk.Group == gv.Group && gvk.Version == gv.Version { 199 return gvk, true 200 } 201 } 202 for _, gvk := range kinds { 203 if gvk.Group == gv.Group { 204 return gv.WithKind(gvk.Kind), true 205 } 206 } 207 return GroupVersionKind{}, false 208 } 209 210 // ParseGroupVersion turns "group/version" string into a GroupVersion struct. It reports error 211 // if it cannot parse the string. 212 func ParseGroupVersion(gv string) (GroupVersion, error) { 213 // this can be the internal version for the legacy kube types 214 // TODO once we've cleared the last uses as strings, this special case should be removed. 215 if (len(gv) == 0) || (gv == "/") { 216 return GroupVersion{}, nil 217 } 218 219 switch strings.Count(gv, "/") { 220 case 0: 221 return GroupVersion{"", gv}, nil 222 case 1: 223 i := strings.Index(gv, "/") 224 return GroupVersion{gv[:i], gv[i+1:]}, nil 225 default: 226 return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv) 227 } 228 } 229 230 // WithKind creates a GroupVersionKind based on the method receiver's GroupVersion and the passed Kind. 231 func (gv GroupVersion) WithKind(kind string) GroupVersionKind { 232 return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind} 233 } 234 235 // WithResource creates a GroupVersionResource based on the method receiver's GroupVersion and the passed Resource. 236 func (gv GroupVersion) WithResource(resource string) GroupVersionResource { 237 return GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: resource} 238 } 239 240 // GroupVersions can be used to represent a set of desired group versions. 241 // TODO: Move GroupVersions to a package under pkg/runtime, since it's used by scheme. 242 // TODO: Introduce an adapter type between GroupVersions and runtime.GroupVersioner, and use LegacyCodec(GroupVersion) 243 // 244 // in fewer places. 245 type GroupVersions []GroupVersion 246 247 // Identifier implements runtime.GroupVersioner interface. 248 func (gvs GroupVersions) Identifier() string { 249 groupVersions := make([]string, 0, len(gvs)) 250 for i := range gvs { 251 groupVersions = append(groupVersions, gvs[i].String()) 252 } 253 return fmt.Sprintf("[%s]", strings.Join(groupVersions, ",")) 254 } 255 256 // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false 257 // if none of the options match the group. 258 func (gvs GroupVersions) KindForGroupVersionKinds(kinds []GroupVersionKind) (GroupVersionKind, bool) { 259 var targets []GroupVersionKind 260 for _, gv := range gvs { 261 target, ok := gv.KindForGroupVersionKinds(kinds) 262 if !ok { 263 continue 264 } 265 targets = append(targets, target) 266 } 267 if len(targets) == 1 { 268 return targets[0], true 269 } 270 if len(targets) > 1 { 271 return bestMatch(kinds, targets), true 272 } 273 return GroupVersionKind{}, false 274 } 275 276 // bestMatch tries to pick best matching GroupVersionKind and falls back to the first 277 // found if no exact match exists. 278 func bestMatch(kinds []GroupVersionKind, targets []GroupVersionKind) GroupVersionKind { 279 for _, gvk := range targets { 280 for _, k := range kinds { 281 if k == gvk { 282 return k 283 } 284 } 285 } 286 return targets[0] 287 } 288 289 // ToAPIVersionAndKind is a convenience method for satisfying runtime.Object on types that 290 // do not use TypeMeta. 291 func (gvk GroupVersionKind) ToAPIVersionAndKind() (string, string) { 292 if gvk.Empty() { 293 return "", "" 294 } 295 return gvk.GroupVersion().String(), gvk.Kind 296 } 297 298 // FromAPIVersionAndKind returns a GVK representing the provided fields for types that 299 // do not use TypeMeta. This method exists to support test types and legacy serializations 300 // that have a distinct group and kind. 301 // TODO: further reduce usage of this method. 302 func FromAPIVersionAndKind(apiVersion, kind string) GroupVersionKind { 303 if gv, err := ParseGroupVersion(apiVersion); err == nil { 304 return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind} 305 } 306 return GroupVersionKind{Kind: kind} 307 }