Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / sigs.k8s.io / controller-runtime / pkg / client / fake / client.go
1 /*
2 Copyright 2018 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 fake
18
19 import (
20         "context"
21         "encoding/json"
22         "fmt"
23         "os"
24         "strings"
25
26         "k8s.io/apimachinery/pkg/api/meta"
27         "k8s.io/apimachinery/pkg/labels"
28         "k8s.io/apimachinery/pkg/runtime"
29         "k8s.io/apimachinery/pkg/runtime/schema"
30         "k8s.io/client-go/kubernetes/scheme"
31         "k8s.io/client-go/testing"
32
33         "sigs.k8s.io/controller-runtime/pkg/client"
34         "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
35         "sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
36         logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
37 )
38
39 var (
40         log = logf.KBLog.WithName("fake-client")
41 )
42
43 type fakeClient struct {
44         tracker testing.ObjectTracker
45         scheme  *runtime.Scheme
46 }
47
48 var _ client.Client = &fakeClient{}
49
50 // NewFakeClient creates a new fake client for testing.
51 // You can choose to initialize it with a slice of runtime.Object.
52 func NewFakeClient(initObjs ...runtime.Object) client.Client {
53         return NewFakeClientWithScheme(scheme.Scheme, initObjs...)
54 }
55
56 // NewFakeClientWithScheme creates a new fake client with the given scheme
57 // for testing.
58 // You can choose to initialize it with a slice of runtime.Object.
59 func NewFakeClientWithScheme(clientScheme *runtime.Scheme, initObjs ...runtime.Object) client.Client {
60         tracker := testing.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder())
61         for _, obj := range initObjs {
62                 err := tracker.Add(obj)
63                 if err != nil {
64                         log.Error(err, "failed to add object to fake client", "object", obj)
65                         os.Exit(1)
66                         return nil
67                 }
68         }
69         return &fakeClient{
70                 tracker: tracker,
71                 scheme:  clientScheme,
72         }
73 }
74
75 func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error {
76         gvr, err := getGVRFromObject(obj, c.scheme)
77         if err != nil {
78                 return err
79         }
80         o, err := c.tracker.Get(gvr, key.Namespace, key.Name)
81         if err != nil {
82                 return err
83         }
84         j, err := json.Marshal(o)
85         if err != nil {
86                 return err
87         }
88         decoder := scheme.Codecs.UniversalDecoder()
89         _, _, err = decoder.Decode(j, nil, obj)
90         return err
91 }
92
93 func (c *fakeClient) List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error {
94         gvk, err := getGVKFromList(list, c.scheme)
95         if err != nil {
96                 // The old fake client required GVK info in Raw.TypeMeta, so check there
97                 // before giving up
98                 if opts.Raw == nil || opts.Raw.TypeMeta.APIVersion == "" || opts.Raw.TypeMeta.Kind == "" {
99                         return err
100                 }
101                 gvk = opts.Raw.TypeMeta.GroupVersionKind()
102         }
103
104         gvr, _ := meta.UnsafeGuessKindToResource(gvk)
105         o, err := c.tracker.List(gvr, gvk, opts.Namespace)
106         if err != nil {
107                 return err
108         }
109         j, err := json.Marshal(o)
110         if err != nil {
111                 return err
112         }
113         decoder := scheme.Codecs.UniversalDecoder()
114         _, _, err = decoder.Decode(j, nil, list)
115         if err != nil {
116                 return err
117         }
118
119         if opts.LabelSelector != nil {
120                 return filterListItems(list, opts.LabelSelector)
121         }
122         return nil
123 }
124
125 func filterListItems(list runtime.Object, labSel labels.Selector) error {
126         objs, err := meta.ExtractList(list)
127         if err != nil {
128                 return err
129         }
130         filteredObjs, err := objectutil.FilterWithLabels(objs, labSel)
131         if err != nil {
132                 return err
133         }
134         err = meta.SetList(list, filteredObjs)
135         if err != nil {
136                 return err
137         }
138         return nil
139 }
140
141 func (c *fakeClient) Create(ctx context.Context, obj runtime.Object) error {
142         gvr, err := getGVRFromObject(obj, c.scheme)
143         if err != nil {
144                 return err
145         }
146         accessor, err := meta.Accessor(obj)
147         if err != nil {
148                 return err
149         }
150         return c.tracker.Create(gvr, obj, accessor.GetNamespace())
151 }
152
153 func (c *fakeClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOptionFunc) error {
154         gvr, err := getGVRFromObject(obj, c.scheme)
155         if err != nil {
156                 return err
157         }
158         accessor, err := meta.Accessor(obj)
159         if err != nil {
160                 return err
161         }
162         //TODO: implement propagation
163         return c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
164 }
165
166 func (c *fakeClient) Update(ctx context.Context, obj runtime.Object) error {
167         gvr, err := getGVRFromObject(obj, c.scheme)
168         if err != nil {
169                 return err
170         }
171         accessor, err := meta.Accessor(obj)
172         if err != nil {
173                 return err
174         }
175         return c.tracker.Update(gvr, obj, accessor.GetNamespace())
176 }
177
178 func (c *fakeClient) Status() client.StatusWriter {
179         return &fakeStatusWriter{client: c}
180 }
181
182 func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionResource, error) {
183         gvk, err := apiutil.GVKForObject(obj, scheme)
184         if err != nil {
185                 return schema.GroupVersionResource{}, err
186         }
187         gvr, _ := meta.UnsafeGuessKindToResource(gvk)
188         return gvr, nil
189 }
190
191 func getGVKFromList(list runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
192         gvk, err := apiutil.GVKForObject(list, scheme)
193         if err != nil {
194                 return schema.GroupVersionKind{}, err
195         }
196
197         if gvk.Kind == "List" {
198                 return schema.GroupVersionKind{}, fmt.Errorf("cannot derive GVK for generic List type %T (kind %q)", list, gvk)
199         }
200
201         if !strings.HasSuffix(gvk.Kind, "List") {
202                 return schema.GroupVersionKind{}, fmt.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
203         }
204         // we need the non-list GVK, so chop off the "List" from the end of the kind
205         gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
206         return gvk, nil
207 }
208
209 type fakeStatusWriter struct {
210         client *fakeClient
211 }
212
213 func (sw *fakeStatusWriter) Update(ctx context.Context, obj runtime.Object) error {
214         // TODO(droot): This results in full update of the obj (spec + status). Need
215         // a way to update status field only.
216         return sw.client.Update(ctx, obj)
217 }