...
1
16
17 package resource
18
19 import (
20 "fmt"
21 "reflect"
22
23 "k8s.io/api/core/v1"
24 "k8s.io/apimachinery/pkg/api/meta"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apimachinery/pkg/runtime/schema"
28 utilerrors "k8s.io/apimachinery/pkg/util/errors"
29 "k8s.io/apimachinery/pkg/util/sets"
30 "k8s.io/apimachinery/pkg/watch"
31 )
32
33
34 type ErrMatchFunc func(error) bool
35
36
37 type Result struct {
38 err error
39 visitor Visitor
40
41 sources []Visitor
42 singleItemImplied bool
43 targetsSingleItems bool
44
45 mapper *mapper
46 ignoreErrors []utilerrors.Matcher
47
48
49 info []*Info
50 }
51
52
53 func (r *Result) withError(err error) *Result {
54 r.err = err
55 return r
56 }
57
58
59
60
61 func (r *Result) TargetsSingleItems() bool {
62 return r.targetsSingleItems
63 }
64
65
66
67
68
69
70
71
72 func (r *Result) IgnoreErrors(fns ...ErrMatchFunc) *Result {
73 for _, fn := range fns {
74 r.ignoreErrors = append(r.ignoreErrors, utilerrors.Matcher(fn))
75 }
76 return r
77 }
78
79
80 func (r *Result) Mapper() *mapper {
81 return r.mapper
82 }
83
84
85
86
87 func (r *Result) Err() error {
88 return r.err
89 }
90
91
92
93
94
95 func (r *Result) Visit(fn VisitorFunc) error {
96 if r.err != nil {
97 return r.err
98 }
99 err := r.visitor.Visit(fn)
100 return utilerrors.FilterOut(err, r.ignoreErrors...)
101 }
102
103
104
105 func (r *Result) IntoSingleItemImplied(b *bool) *Result {
106 *b = r.singleItemImplied
107 return r
108 }
109
110
111
112
113 func (r *Result) Infos() ([]*Info, error) {
114 if r.err != nil {
115 return nil, r.err
116 }
117 if r.info != nil {
118 return r.info, nil
119 }
120
121 infos := []*Info{}
122 err := r.visitor.Visit(func(info *Info, err error) error {
123 if err != nil {
124 return err
125 }
126 infos = append(infos, info)
127 return nil
128 })
129 err = utilerrors.FilterOut(err, r.ignoreErrors...)
130
131 r.info, r.err = infos, err
132 return infos, err
133 }
134
135
136
137
138
139
140
141 func (r *Result) Object() (runtime.Object, error) {
142 infos, err := r.Infos()
143 if err != nil {
144 return nil, err
145 }
146
147 versions := sets.String{}
148 objects := []runtime.Object{}
149 for _, info := range infos {
150 if info.Object != nil {
151 objects = append(objects, info.Object)
152 versions.Insert(info.ResourceVersion)
153 }
154 }
155
156 if len(objects) == 1 {
157 if r.singleItemImplied {
158 return objects[0], nil
159 }
160
161 if meta.IsListType(objects[0]) {
162 return objects[0], nil
163 }
164 }
165
166 version := ""
167 if len(versions) == 1 {
168 version = versions.List()[0]
169 }
170
171 return toV1List(objects, version), err
172 }
173
174
175 var _ metav1.ListInterface = &v1.List{}
176 var _ metav1.ListMetaAccessor = &v1.List{}
177
178
179
180 func toV1List(objects []runtime.Object, version string) runtime.Object {
181 raw := []runtime.RawExtension{}
182 for _, o := range objects {
183 raw = append(raw, runtime.RawExtension{Object: o})
184 }
185 return &v1.List{
186 ListMeta: metav1.ListMeta{
187 ResourceVersion: version,
188 },
189 Items: raw,
190 }
191 }
192
193
194
195
196 func (r *Result) ResourceMapping() (*meta.RESTMapping, error) {
197 if r.err != nil {
198 return nil, r.err
199 }
200 mappings := map[schema.GroupVersionResource]*meta.RESTMapping{}
201 for i := range r.sources {
202 m, ok := r.sources[i].(ResourceMapping)
203 if !ok {
204 return nil, fmt.Errorf("a resource mapping could not be loaded from %v", reflect.TypeOf(r.sources[i]))
205 }
206 mapping := m.ResourceMapping()
207 mappings[mapping.Resource] = mapping
208 }
209 if len(mappings) != 1 {
210 return nil, fmt.Errorf("expected only a single resource type")
211 }
212 for _, mapping := range mappings {
213 return mapping, nil
214 }
215 return nil, nil
216 }
217
218
219
220
221
222
223 func (r *Result) Watch(resourceVersion string) (watch.Interface, error) {
224 if r.err != nil {
225 return nil, r.err
226 }
227 if len(r.sources) != 1 {
228 return nil, fmt.Errorf("you may only watch a single resource or type of resource at a time")
229 }
230 w, ok := r.sources[0].(Watchable)
231 if !ok {
232 info, err := r.Infos()
233 if err != nil {
234 return nil, err
235 }
236 if len(info) != 1 {
237 return nil, fmt.Errorf("watch is only supported on individual resources and resource collections - %d resources were found", len(info))
238 }
239 return info[0].Watch(resourceVersion)
240 }
241 return w.Watch(resourceVersion)
242 }
243
View as plain text