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  }