github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/api/meta/priority.go (about)

     1  /*
     2  Copyright 2016 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 meta
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    23  )
    24  
    25  const (
    26  	AnyGroup    = "*"
    27  	AnyVersion  = "*"
    28  	AnyResource = "*"
    29  	AnyKind     = "*"
    30  )
    31  
    32  var (
    33  	_ ResettableRESTMapper = PriorityRESTMapper{}
    34  )
    35  
    36  // PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind
    37  // when multiple matches are possible
    38  type PriorityRESTMapper struct {
    39  	// Delegate is the RESTMapper to use to locate all the Kind and Resource matches
    40  	Delegate RESTMapper
    41  
    42  	// ResourcePriority is a list of priority patterns to apply to matching resources.
    43  	// The list of all matching resources is narrowed based on the patterns until only one remains.
    44  	// A pattern with no matches is skipped.  A pattern with more than one match uses its
    45  	// matches as the list to continue matching against.
    46  	ResourcePriority []schema.GroupVersionResource
    47  
    48  	// KindPriority is a list of priority patterns to apply to matching kinds.
    49  	// The list of all matching kinds is narrowed based on the patterns until only one remains.
    50  	// A pattern with no matches is skipped.  A pattern with more than one match uses its
    51  	// matches as the list to continue matching against.
    52  	KindPriority []schema.GroupVersionKind
    53  }
    54  
    55  func (m PriorityRESTMapper) String() string {
    56  	return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate)
    57  }
    58  
    59  // ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit.
    60  func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
    61  	originalGVRs, originalErr := m.Delegate.ResourcesFor(partiallySpecifiedResource)
    62  	if originalErr != nil && len(originalGVRs) == 0 {
    63  		return schema.GroupVersionResource{}, originalErr
    64  	}
    65  	if len(originalGVRs) == 1 {
    66  		return originalGVRs[0], originalErr
    67  	}
    68  
    69  	remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...)
    70  	for _, pattern := range m.ResourcePriority {
    71  		matchedGVRs := []schema.GroupVersionResource{}
    72  		for _, gvr := range remainingGVRs {
    73  			if resourceMatches(pattern, gvr) {
    74  				matchedGVRs = append(matchedGVRs, gvr)
    75  			}
    76  		}
    77  
    78  		switch len(matchedGVRs) {
    79  		case 0:
    80  			// if you have no matches, then nothing matched this pattern just move to the next
    81  			continue
    82  		case 1:
    83  			// one match, return
    84  			return matchedGVRs[0], originalErr
    85  		default:
    86  			// more than one match, use the matched hits as the list moving to the next pattern.
    87  			// this way you can have a series of selection criteria
    88  			remainingGVRs = matchedGVRs
    89  		}
    90  	}
    91  
    92  	return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs}
    93  }
    94  
    95  // KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit.
    96  func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
    97  	originalGVKs, originalErr := m.Delegate.KindsFor(partiallySpecifiedResource)
    98  	if originalErr != nil && len(originalGVKs) == 0 {
    99  		return schema.GroupVersionKind{}, originalErr
   100  	}
   101  	if len(originalGVKs) == 1 {
   102  		return originalGVKs[0], originalErr
   103  	}
   104  
   105  	remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...)
   106  	for _, pattern := range m.KindPriority {
   107  		matchedGVKs := []schema.GroupVersionKind{}
   108  		for _, gvr := range remainingGVKs {
   109  			if kindMatches(pattern, gvr) {
   110  				matchedGVKs = append(matchedGVKs, gvr)
   111  			}
   112  		}
   113  
   114  		switch len(matchedGVKs) {
   115  		case 0:
   116  			// if you have no matches, then nothing matched this pattern just move to the next
   117  			continue
   118  		case 1:
   119  			// one match, return
   120  			return matchedGVKs[0], originalErr
   121  		default:
   122  			// more than one match, use the matched hits as the list moving to the next pattern.
   123  			// this way you can have a series of selection criteria
   124  			remainingGVKs = matchedGVKs
   125  		}
   126  	}
   127  
   128  	return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs}
   129  }
   130  
   131  func resourceMatches(pattern schema.GroupVersionResource, resource schema.GroupVersionResource) bool {
   132  	if pattern.Group != AnyGroup && pattern.Group != resource.Group {
   133  		return false
   134  	}
   135  	if pattern.Version != AnyVersion && pattern.Version != resource.Version {
   136  		return false
   137  	}
   138  	if pattern.Resource != AnyResource && pattern.Resource != resource.Resource {
   139  		return false
   140  	}
   141  
   142  	return true
   143  }
   144  
   145  func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind) bool {
   146  	if pattern.Group != AnyGroup && pattern.Group != kind.Group {
   147  		return false
   148  	}
   149  	if pattern.Version != AnyVersion && pattern.Version != kind.Version {
   150  		return false
   151  	}
   152  	if pattern.Kind != AnyKind && pattern.Kind != kind.Kind {
   153  		return false
   154  	}
   155  
   156  	return true
   157  }
   158  
   159  func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
   160  	mappings, originalErr := m.Delegate.RESTMappings(gk, versions...)
   161  	if originalErr != nil && len(mappings) == 0 {
   162  		return nil, originalErr
   163  	}
   164  
   165  	// any versions the user provides take priority
   166  	priorities := m.KindPriority
   167  	if len(versions) > 0 {
   168  		priorities = make([]schema.GroupVersionKind, 0, len(m.KindPriority)+len(versions))
   169  		for _, version := range versions {
   170  			gv := schema.GroupVersion{
   171  				Version: version,
   172  				Group:   gk.Group,
   173  			}
   174  			priorities = append(priorities, gv.WithKind(AnyKind))
   175  		}
   176  		priorities = append(priorities, m.KindPriority...)
   177  	}
   178  
   179  	remaining := append([]*RESTMapping{}, mappings...)
   180  	for _, pattern := range priorities {
   181  		var matching []*RESTMapping
   182  		for _, m := range remaining {
   183  			if kindMatches(pattern, m.GroupVersionKind) {
   184  				matching = append(matching, m)
   185  			}
   186  		}
   187  
   188  		switch len(matching) {
   189  		case 0:
   190  			// if you have no matches, then nothing matched this pattern just move to the next
   191  			continue
   192  		case 1:
   193  			// one match, return
   194  			return matching[0], originalErr
   195  		default:
   196  			// more than one match, use the matched hits as the list moving to the next pattern.
   197  			// this way you can have a series of selection criteria
   198  			remaining = matching
   199  		}
   200  	}
   201  	if len(remaining) == 1 {
   202  		return remaining[0], originalErr
   203  	}
   204  
   205  	var kinds []schema.GroupVersionKind
   206  	for _, m := range mappings {
   207  		kinds = append(kinds, m.GroupVersionKind)
   208  	}
   209  	return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
   210  }
   211  
   212  func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
   213  	return m.Delegate.RESTMappings(gk, versions...)
   214  }
   215  
   216  func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
   217  	return m.Delegate.ResourceSingularizer(resource)
   218  }
   219  
   220  func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
   221  	return m.Delegate.ResourcesFor(partiallySpecifiedResource)
   222  }
   223  
   224  func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
   225  	return m.Delegate.KindsFor(partiallySpecifiedResource)
   226  }
   227  
   228  func (m PriorityRESTMapper) Reset() {
   229  	MaybeResetRESTMapper(m.Delegate)
   230  }