github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 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 "strings" 22 23 "k8s.io/kubernetes/pkg/api/unversioned" 24 utilerrors "k8s.io/kubernetes/pkg/util/errors" 25 "k8s.io/kubernetes/pkg/util/sets" 26 ) 27 28 // MultiRESTMapper is a wrapper for multiple RESTMappers. 29 type MultiRESTMapper []RESTMapper 30 31 func (m MultiRESTMapper) String() string { 32 nested := []string{} 33 for _, t := range m { 34 currString := fmt.Sprintf("%v", t) 35 splitStrings := strings.Split(currString, "\n") 36 nested = append(nested, strings.Join(splitStrings, "\n\t")) 37 } 38 39 return fmt.Sprintf("MultiRESTMapper{\n\t%s\n}", strings.Join(nested, "\n\t")) 40 } 41 42 // ResourceSingularizer converts a REST resource name from plural to singular (e.g., from pods to pod) 43 // This implementation supports multiple REST schemas and return the first match. 44 func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { 45 for _, t := range m { 46 singular, err = t.ResourceSingularizer(resource) 47 if err == nil { 48 return 49 } 50 } 51 return 52 } 53 54 func (m MultiRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) { 55 allGVRs := []unversioned.GroupVersionResource{} 56 for _, t := range m { 57 gvrs, err := t.ResourcesFor(resource) 58 // ignore "no match" errors, but any other error percolates back up 59 if IsNoResourceMatchError(err) { 60 continue 61 } 62 if err != nil { 63 return nil, err 64 } 65 66 // walk the existing values to de-dup 67 for _, curr := range gvrs { 68 found := false 69 for _, existing := range allGVRs { 70 if curr == existing { 71 found = true 72 break 73 } 74 } 75 76 if !found { 77 allGVRs = append(allGVRs, curr) 78 } 79 } 80 } 81 82 if len(allGVRs) == 0 { 83 return nil, &NoResourceMatchError{PartialResource: resource} 84 } 85 86 return allGVRs, nil 87 } 88 89 func (m MultiRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) { 90 allGVKs := []unversioned.GroupVersionKind{} 91 for _, t := range m { 92 gvks, err := t.KindsFor(resource) 93 // ignore "no match" errors, but any other error percolates back up 94 if IsNoResourceMatchError(err) { 95 continue 96 } 97 if err != nil { 98 return nil, err 99 } 100 101 // walk the existing values to de-dup 102 for _, curr := range gvks { 103 found := false 104 for _, existing := range allGVKs { 105 if curr == existing { 106 found = true 107 break 108 } 109 } 110 111 if !found { 112 allGVKs = append(allGVKs, curr) 113 } 114 } 115 } 116 117 if len(allGVKs) == 0 { 118 return nil, &NoResourceMatchError{PartialResource: resource} 119 } 120 121 return allGVKs, nil 122 } 123 124 func (m MultiRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) { 125 resources, err := m.ResourcesFor(resource) 126 if err != nil { 127 return unversioned.GroupVersionResource{}, err 128 } 129 if len(resources) == 1 { 130 return resources[0], nil 131 } 132 133 return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources} 134 } 135 136 func (m MultiRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { 137 kinds, err := m.KindsFor(resource) 138 if err != nil { 139 return unversioned.GroupVersionKind{}, err 140 } 141 if len(kinds) == 1 { 142 return kinds[0], nil 143 } 144 145 return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds} 146 } 147 148 // RESTMapping provides the REST mapping for the resource based on the 149 // kind and version. This implementation supports multiple REST schemas and 150 // return the first match. 151 func (m MultiRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) { 152 allMappings := []*RESTMapping{} 153 errors := []error{} 154 155 for _, t := range m { 156 currMapping, err := t.RESTMapping(gk, versions...) 157 // ignore "no match" errors, but any other error percolates back up 158 if IsNoResourceMatchError(err) { 159 continue 160 } 161 if err != nil { 162 errors = append(errors, err) 163 continue 164 } 165 166 allMappings = append(allMappings, currMapping) 167 } 168 169 // if we got exactly one mapping, then use it even if other requested failed 170 if len(allMappings) == 1 { 171 return allMappings[0], nil 172 } 173 if len(allMappings) > 1 { 174 return nil, fmt.Errorf("multiple matches found for %v in %v", gk, versions) 175 } 176 if len(errors) > 0 { 177 return nil, utilerrors.NewAggregate(errors) 178 } 179 return nil, fmt.Errorf("no match found for %v in %v", gk, versions) 180 } 181 182 // AliasesForResource finds the first alias response for the provided mappers. 183 func (m MultiRESTMapper) AliasesForResource(alias string) ([]string, bool) { 184 seenAliases := sets.NewString() 185 allAliases := []string{} 186 handled := false 187 188 for _, t := range m { 189 if currAliases, currOk := t.AliasesForResource(alias); currOk { 190 for _, currAlias := range currAliases { 191 if !seenAliases.Has(currAlias) { 192 allAliases = append(allAliases, currAlias) 193 seenAliases.Insert(currAlias) 194 } 195 } 196 handled = true 197 } 198 } 199 return allAliases, handled 200 }