fixture.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package testing
  14. import (
  15. "fmt"
  16. "reflect"
  17. "sort"
  18. "strings"
  19. "sync"
  20. "sigs.k8s.io/yaml"
  21. jsonpatch "gopkg.in/evanphx/json-patch.v4"
  22. apierrors "k8s.io/apimachinery/pkg/api/errors"
  23. "k8s.io/apimachinery/pkg/api/meta"
  24. "k8s.io/apimachinery/pkg/api/meta/testrestmapper"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  27. "k8s.io/apimachinery/pkg/runtime"
  28. "k8s.io/apimachinery/pkg/runtime/schema"
  29. "k8s.io/apimachinery/pkg/types"
  30. "k8s.io/apimachinery/pkg/util/json"
  31. "k8s.io/apimachinery/pkg/util/managedfields"
  32. "k8s.io/apimachinery/pkg/util/strategicpatch"
  33. "k8s.io/apimachinery/pkg/watch"
  34. restclient "k8s.io/client-go/rest"
  35. )
  36. // ObjectTracker keeps track of objects. It is intended to be used to
  37. // fake calls to a server by returning objects based on their kind,
  38. // namespace and name.
  39. type ObjectTracker interface {
  40. // Add adds an object to the tracker. If object being added
  41. // is a list, its items are added separately.
  42. Add(obj runtime.Object) error
  43. // Get retrieves the object by its kind, namespace and name.
  44. Get(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.GetOptions) (runtime.Object, error)
  45. // Create adds an object to the tracker in the specified namespace.
  46. Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.CreateOptions) error
  47. // Update updates an existing object in the tracker in the specified namespace.
  48. Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.UpdateOptions) error
  49. // Patch patches an existing object in the tracker in the specified namespace.
  50. Patch(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.PatchOptions) error
  51. // Apply applies an object in the tracker in the specified namespace.
  52. Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, opts ...metav1.PatchOptions) error
  53. // List retrieves all objects of a given kind in the given
  54. // namespace. Only non-List kinds are accepted.
  55. List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string, opts ...metav1.ListOptions) (runtime.Object, error)
  56. // Delete deletes an existing object from the tracker. If object
  57. // didn't exist in the tracker prior to deletion, Delete returns
  58. // no error.
  59. Delete(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.DeleteOptions) error
  60. // Watch watches objects from the tracker. Watch returns a channel
  61. // which will push added / modified / deleted object.
  62. Watch(gvr schema.GroupVersionResource, ns string, opts ...metav1.ListOptions) (watch.Interface, error)
  63. }
  64. // ObjectScheme abstracts the implementation of common operations on objects.
  65. type ObjectScheme interface {
  66. runtime.ObjectCreater
  67. runtime.ObjectTyper
  68. }
  69. // ObjectReaction returns a ReactionFunc that applies core.Action to
  70. // the given tracker.
  71. //
  72. // If tracker also implements ManagedFieldObjectTracker, then managed fields
  73. // will be handled by the tracker and apply patch actions will be evaluated
  74. // using the field manager and will take field ownership into consideration.
  75. // Without a ManagedFieldObjectTracker, apply patch actions do not consider
  76. // field ownership.
  77. //
  78. // WARNING: There is no server side defaulting, validation, or conversion handled
  79. // by the fake client and subresources are not handled accurately (fields in the
  80. // root resource are not automatically updated when a scale resource is updated, for example).
  81. func ObjectReaction(tracker ObjectTracker) ReactionFunc {
  82. reactor := objectTrackerReact{tracker: tracker}
  83. return func(action Action) (bool, runtime.Object, error) {
  84. // Here and below we need to switch on implementation types,
  85. // not on interfaces, as some interfaces are identical
  86. // (e.g. UpdateAction and CreateAction), so if we use them,
  87. // updates and creates end up matching the same case branch.
  88. switch action := action.(type) {
  89. case ListActionImpl:
  90. obj, err := reactor.List(action)
  91. return true, obj, err
  92. case GetActionImpl:
  93. obj, err := reactor.Get(action)
  94. return true, obj, err
  95. case CreateActionImpl:
  96. obj, err := reactor.Create(action)
  97. return true, obj, err
  98. case UpdateActionImpl:
  99. obj, err := reactor.Update(action)
  100. return true, obj, err
  101. case DeleteActionImpl:
  102. obj, err := reactor.Delete(action)
  103. return true, obj, err
  104. case PatchActionImpl:
  105. if action.GetPatchType() == types.ApplyPatchType {
  106. obj, err := reactor.Apply(action)
  107. return true, obj, err
  108. }
  109. obj, err := reactor.Patch(action)
  110. return true, obj, err
  111. default:
  112. return false, nil, fmt.Errorf("no reaction implemented for %s", action)
  113. }
  114. }
  115. }
  116. type objectTrackerReact struct {
  117. tracker ObjectTracker
  118. }
  119. func (o objectTrackerReact) List(action ListActionImpl) (runtime.Object, error) {
  120. return o.tracker.List(action.GetResource(), action.GetKind(), action.GetNamespace(), action.ListOptions)
  121. }
  122. func (o objectTrackerReact) Get(action GetActionImpl) (runtime.Object, error) {
  123. return o.tracker.Get(action.GetResource(), action.GetNamespace(), action.GetName(), action.GetOptions)
  124. }
  125. func (o objectTrackerReact) Create(action CreateActionImpl) (runtime.Object, error) {
  126. ns := action.GetNamespace()
  127. gvr := action.GetResource()
  128. objMeta, err := meta.Accessor(action.GetObject())
  129. if err != nil {
  130. return nil, err
  131. }
  132. if action.GetSubresource() == "" {
  133. err = o.tracker.Create(gvr, action.GetObject(), ns, action.CreateOptions)
  134. if err != nil {
  135. return nil, err
  136. }
  137. } else {
  138. oldObj, getOldObjErr := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  139. if getOldObjErr != nil {
  140. return nil, getOldObjErr
  141. }
  142. // Check whether the existing historical object type is the same as the current operation object type that needs to be updated, and if it is the same, perform the update operation.
  143. if reflect.TypeOf(oldObj) == reflect.TypeOf(action.GetObject()) {
  144. // TODO: Currently we're handling subresource creation as an update
  145. // on the enclosing resource. This works for some subresources but
  146. // might not be generic enough.
  147. err = o.tracker.Update(gvr, action.GetObject(), ns, metav1.UpdateOptions{
  148. DryRun: action.CreateOptions.DryRun,
  149. FieldManager: action.CreateOptions.FieldManager,
  150. FieldValidation: action.CreateOptions.FieldValidation,
  151. })
  152. } else {
  153. // If the historical object type is different from the current object type, need to make sure we return the object submitted,don't persist the submitted object in the tracker.
  154. return action.GetObject(), nil
  155. }
  156. }
  157. if err != nil {
  158. return nil, err
  159. }
  160. obj, err := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  161. return obj, err
  162. }
  163. func (o objectTrackerReact) Update(action UpdateActionImpl) (runtime.Object, error) {
  164. ns := action.GetNamespace()
  165. gvr := action.GetResource()
  166. objMeta, err := meta.Accessor(action.GetObject())
  167. if err != nil {
  168. return nil, err
  169. }
  170. err = o.tracker.Update(gvr, action.GetObject(), ns, action.UpdateOptions)
  171. if err != nil {
  172. return nil, err
  173. }
  174. obj, err := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  175. return obj, err
  176. }
  177. func (o objectTrackerReact) Delete(action DeleteActionImpl) (runtime.Object, error) {
  178. err := o.tracker.Delete(action.GetResource(), action.GetNamespace(), action.GetName(), action.DeleteOptions)
  179. return nil, err
  180. }
  181. func (o objectTrackerReact) Apply(action PatchActionImpl) (runtime.Object, error) {
  182. ns := action.GetNamespace()
  183. gvr := action.GetResource()
  184. patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
  185. if err := yaml.Unmarshal(action.GetPatch(), &patchObj.Object); err != nil {
  186. return nil, err
  187. }
  188. patchObj.SetName(action.GetName())
  189. err := o.tracker.Apply(gvr, patchObj, ns, action.PatchOptions)
  190. if err != nil {
  191. return nil, err
  192. }
  193. obj, err := o.tracker.Get(gvr, ns, action.GetName(), metav1.GetOptions{})
  194. return obj, err
  195. }
  196. func (o objectTrackerReact) Patch(action PatchActionImpl) (runtime.Object, error) {
  197. ns := action.GetNamespace()
  198. gvr := action.GetResource()
  199. obj, err := o.tracker.Get(gvr, ns, action.GetName(), metav1.GetOptions{})
  200. if err != nil {
  201. return nil, err
  202. }
  203. old, err := json.Marshal(obj)
  204. if err != nil {
  205. return nil, err
  206. }
  207. // reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields
  208. // in obj that are removed by patch are cleared
  209. value := reflect.ValueOf(obj)
  210. value.Elem().Set(reflect.New(value.Type().Elem()).Elem())
  211. switch action.GetPatchType() {
  212. case types.JSONPatchType:
  213. patch, err := jsonpatch.DecodePatch(action.GetPatch())
  214. if err != nil {
  215. return nil, err
  216. }
  217. modified, err := patch.Apply(old)
  218. if err != nil {
  219. return nil, err
  220. }
  221. if err = json.Unmarshal(modified, obj); err != nil {
  222. return nil, err
  223. }
  224. case types.MergePatchType:
  225. modified, err := jsonpatch.MergePatch(old, action.GetPatch())
  226. if err != nil {
  227. return nil, err
  228. }
  229. if err := json.Unmarshal(modified, obj); err != nil {
  230. return nil, err
  231. }
  232. case types.StrategicMergePatchType:
  233. mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj)
  234. if err != nil {
  235. return nil, err
  236. }
  237. if err = json.Unmarshal(mergedByte, obj); err != nil {
  238. return nil, err
  239. }
  240. default:
  241. return nil, fmt.Errorf("PatchType %s is not supported", action.GetPatchType())
  242. }
  243. if err = o.tracker.Patch(gvr, obj, ns, action.PatchOptions); err != nil {
  244. return nil, err
  245. }
  246. return obj, nil
  247. }
  248. type tracker struct {
  249. scheme ObjectScheme
  250. decoder runtime.Decoder
  251. lock sync.RWMutex
  252. objects map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object
  253. // The value type of watchers is a map of which the key is either a namespace or
  254. // all/non namespace aka "" and its value is list of fake watchers.
  255. // Manipulations on resources will broadcast the notification events into the
  256. // watchers' channel. Note that too many unhandled events (currently 100,
  257. // see apimachinery/pkg/watch.DefaultChanSize) will cause a panic.
  258. watchers map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher
  259. }
  260. var _ ObjectTracker = &tracker{}
  261. // NewObjectTracker returns an ObjectTracker that can be used to keep track
  262. // of objects for the fake clientset. Mostly useful for unit tests.
  263. func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker {
  264. return &tracker{
  265. scheme: scheme,
  266. decoder: decoder,
  267. objects: make(map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object),
  268. watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher),
  269. }
  270. }
  271. func (t *tracker) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string, opts ...metav1.ListOptions) (runtime.Object, error) {
  272. _, err := assertOptionalSingleArgument(opts)
  273. if err != nil {
  274. return nil, err
  275. }
  276. // Heuristic for list kind: original kind + List suffix. Might
  277. // not always be true but this tracker has a pretty limited
  278. // understanding of the actual API model.
  279. listGVK := gvk
  280. listGVK.Kind = listGVK.Kind + "List"
  281. // GVK does have the concept of "internal version". The scheme recognizes
  282. // the runtime.APIVersionInternal, but not the empty string.
  283. if listGVK.Version == "" {
  284. listGVK.Version = runtime.APIVersionInternal
  285. }
  286. list, err := t.scheme.New(listGVK)
  287. if err != nil {
  288. return nil, err
  289. }
  290. if !meta.IsListType(list) {
  291. return nil, fmt.Errorf("%q is not a list type", listGVK.Kind)
  292. }
  293. t.lock.RLock()
  294. defer t.lock.RUnlock()
  295. objs, ok := t.objects[gvr]
  296. if !ok {
  297. return list, nil
  298. }
  299. matchingObjs, err := filterByNamespace(objs, ns)
  300. if err != nil {
  301. return nil, err
  302. }
  303. if err := meta.SetList(list, matchingObjs); err != nil {
  304. return nil, err
  305. }
  306. return list.DeepCopyObject(), nil
  307. }
  308. func (t *tracker) Watch(gvr schema.GroupVersionResource, ns string, opts ...metav1.ListOptions) (watch.Interface, error) {
  309. _, err := assertOptionalSingleArgument(opts)
  310. if err != nil {
  311. return nil, err
  312. }
  313. t.lock.Lock()
  314. defer t.lock.Unlock()
  315. fakewatcher := watch.NewRaceFreeFake()
  316. if _, exists := t.watchers[gvr]; !exists {
  317. t.watchers[gvr] = make(map[string][]*watch.RaceFreeFakeWatcher)
  318. }
  319. t.watchers[gvr][ns] = append(t.watchers[gvr][ns], fakewatcher)
  320. return fakewatcher, nil
  321. }
  322. func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.GetOptions) (runtime.Object, error) {
  323. _, err := assertOptionalSingleArgument(opts)
  324. if err != nil {
  325. return nil, err
  326. }
  327. errNotFound := apierrors.NewNotFound(gvr.GroupResource(), name)
  328. t.lock.RLock()
  329. defer t.lock.RUnlock()
  330. objs, ok := t.objects[gvr]
  331. if !ok {
  332. return nil, errNotFound
  333. }
  334. matchingObj, ok := objs[types.NamespacedName{Namespace: ns, Name: name}]
  335. if !ok {
  336. return nil, errNotFound
  337. }
  338. // Only one object should match in the tracker if it works
  339. // correctly, as Add/Update methods enforce kind/namespace/name
  340. // uniqueness.
  341. obj := matchingObj.DeepCopyObject()
  342. if status, ok := obj.(*metav1.Status); ok {
  343. if status.Status != metav1.StatusSuccess {
  344. return nil, &apierrors.StatusError{ErrStatus: *status}
  345. }
  346. }
  347. return obj, nil
  348. }
  349. func (t *tracker) Add(obj runtime.Object) error {
  350. if meta.IsListType(obj) {
  351. return t.addList(obj, false)
  352. }
  353. objMeta, err := meta.Accessor(obj)
  354. if err != nil {
  355. return err
  356. }
  357. gvks, _, err := t.scheme.ObjectKinds(obj)
  358. if err != nil {
  359. return err
  360. }
  361. if partial, ok := obj.(*metav1.PartialObjectMetadata); ok && len(partial.TypeMeta.APIVersion) > 0 {
  362. gvks = []schema.GroupVersionKind{partial.TypeMeta.GroupVersionKind()}
  363. }
  364. if len(gvks) == 0 {
  365. return fmt.Errorf("no registered kinds for %v", obj)
  366. }
  367. for _, gvk := range gvks {
  368. // NOTE: UnsafeGuessKindToResource is a heuristic and default match. The
  369. // actual registration in apiserver can specify arbitrary route for a
  370. // gvk. If a test uses such objects, it cannot preset the tracker with
  371. // objects via Add(). Instead, it should trigger the Create() function
  372. // of the tracker, where an arbitrary gvr can be specified.
  373. gvr, _ := meta.UnsafeGuessKindToResource(gvk)
  374. // Resource doesn't have the concept of "__internal" version, just set it to "".
  375. if gvr.Version == runtime.APIVersionInternal {
  376. gvr.Version = ""
  377. }
  378. err := t.add(gvr, obj, objMeta.GetNamespace(), false)
  379. if err != nil {
  380. return err
  381. }
  382. }
  383. return nil
  384. }
  385. func (t *tracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.CreateOptions) error {
  386. _, err := assertOptionalSingleArgument(opts)
  387. if err != nil {
  388. return err
  389. }
  390. return t.add(gvr, obj, ns, false)
  391. }
  392. func (t *tracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.UpdateOptions) error {
  393. _, err := assertOptionalSingleArgument(opts)
  394. if err != nil {
  395. return err
  396. }
  397. return t.add(gvr, obj, ns, true)
  398. }
  399. func (t *tracker) Patch(gvr schema.GroupVersionResource, patchedObject runtime.Object, ns string, opts ...metav1.PatchOptions) error {
  400. _, err := assertOptionalSingleArgument(opts)
  401. if err != nil {
  402. return err
  403. }
  404. return t.add(gvr, patchedObject, ns, true)
  405. }
  406. func (t *tracker) Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, opts ...metav1.PatchOptions) error {
  407. _, err := assertOptionalSingleArgument(opts)
  408. if err != nil {
  409. return err
  410. }
  411. applyConfigurationMeta, err := meta.Accessor(applyConfiguration)
  412. if err != nil {
  413. return err
  414. }
  415. obj, err := t.Get(gvr, ns, applyConfigurationMeta.GetName(), metav1.GetOptions{})
  416. if err != nil {
  417. return err
  418. }
  419. old, err := json.Marshal(obj)
  420. if err != nil {
  421. return err
  422. }
  423. // reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields
  424. // in obj that are removed by patch are cleared
  425. value := reflect.ValueOf(obj)
  426. value.Elem().Set(reflect.New(value.Type().Elem()).Elem())
  427. // For backward compatibility with behavior 1.30 and earlier, continue to handle apply
  428. // via strategic merge patch (clients may use fake.NewClientset and ManagedFieldObjectTracker
  429. // for full field manager support).
  430. patch, err := json.Marshal(applyConfiguration)
  431. if err != nil {
  432. return err
  433. }
  434. mergedByte, err := strategicpatch.StrategicMergePatch(old, patch, obj)
  435. if err != nil {
  436. return err
  437. }
  438. if err = json.Unmarshal(mergedByte, obj); err != nil {
  439. return err
  440. }
  441. return t.add(gvr, obj, ns, true)
  442. }
  443. // IsWatchListSemanticsUnSupported informs the reflector that this client
  444. // doesn't support WatchList semantics.
  445. //
  446. // This is a synthetic method whose sole purpose is to satisfy the optional
  447. // interface check performed by the reflector.
  448. // Returning true signals that WatchList can NOT be used.
  449. // No additional logic is implemented here.
  450. func (t *tracker) IsWatchListSemanticsUnSupported() bool {
  451. return true
  452. }
  453. func (t *tracker) getWatches(gvr schema.GroupVersionResource, ns string) []*watch.RaceFreeFakeWatcher {
  454. watches := []*watch.RaceFreeFakeWatcher{}
  455. if t.watchers[gvr] != nil {
  456. if w := t.watchers[gvr][ns]; w != nil {
  457. watches = append(watches, w...)
  458. }
  459. if ns != metav1.NamespaceAll {
  460. if w := t.watchers[gvr][metav1.NamespaceAll]; w != nil {
  461. watches = append(watches, w...)
  462. }
  463. }
  464. }
  465. return watches
  466. }
  467. func (t *tracker) add(gvr schema.GroupVersionResource, obj runtime.Object, ns string, replaceExisting bool) error {
  468. t.lock.Lock()
  469. defer t.lock.Unlock()
  470. gr := gvr.GroupResource()
  471. // To avoid the object from being accidentally modified by caller
  472. // after it's been added to the tracker, we always store the deep
  473. // copy.
  474. obj = obj.DeepCopyObject()
  475. newMeta, err := meta.Accessor(obj)
  476. if err != nil {
  477. return err
  478. }
  479. // Propagate namespace to the new object if hasn't already been set.
  480. if len(newMeta.GetNamespace()) == 0 {
  481. newMeta.SetNamespace(ns)
  482. }
  483. if ns != newMeta.GetNamespace() {
  484. msg := fmt.Sprintf("request namespace does not match object namespace, request: %q object: %q", ns, newMeta.GetNamespace())
  485. return apierrors.NewBadRequest(msg)
  486. }
  487. _, ok := t.objects[gvr]
  488. if !ok {
  489. t.objects[gvr] = make(map[types.NamespacedName]runtime.Object)
  490. }
  491. namespacedName := types.NamespacedName{Namespace: newMeta.GetNamespace(), Name: newMeta.GetName()}
  492. if _, ok = t.objects[gvr][namespacedName]; ok {
  493. if replaceExisting {
  494. for _, w := range t.getWatches(gvr, ns) {
  495. // To avoid the object from being accidentally modified by watcher
  496. w.Modify(obj.DeepCopyObject())
  497. }
  498. t.objects[gvr][namespacedName] = obj
  499. return nil
  500. }
  501. return apierrors.NewAlreadyExists(gr, newMeta.GetName())
  502. }
  503. if replaceExisting {
  504. // Tried to update but no matching object was found.
  505. return apierrors.NewNotFound(gr, newMeta.GetName())
  506. }
  507. t.objects[gvr][namespacedName] = obj
  508. for _, w := range t.getWatches(gvr, ns) {
  509. // To avoid the object from being accidentally modified by watcher
  510. w.Add(obj.DeepCopyObject())
  511. }
  512. return nil
  513. }
  514. func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error {
  515. list, err := meta.ExtractList(obj)
  516. if err != nil {
  517. return err
  518. }
  519. errs := runtime.DecodeList(list, t.decoder)
  520. if len(errs) > 0 {
  521. return errs[0]
  522. }
  523. for _, obj := range list {
  524. if err := t.Add(obj); err != nil {
  525. return err
  526. }
  527. }
  528. return nil
  529. }
  530. func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.DeleteOptions) error {
  531. _, err := assertOptionalSingleArgument(opts)
  532. if err != nil {
  533. return err
  534. }
  535. t.lock.Lock()
  536. defer t.lock.Unlock()
  537. objs, ok := t.objects[gvr]
  538. if !ok {
  539. return apierrors.NewNotFound(gvr.GroupResource(), name)
  540. }
  541. namespacedName := types.NamespacedName{Namespace: ns, Name: name}
  542. obj, ok := objs[namespacedName]
  543. if !ok {
  544. return apierrors.NewNotFound(gvr.GroupResource(), name)
  545. }
  546. delete(objs, namespacedName)
  547. for _, w := range t.getWatches(gvr, ns) {
  548. w.Delete(obj.DeepCopyObject())
  549. }
  550. return nil
  551. }
  552. type managedFieldObjectTracker struct {
  553. ObjectTracker
  554. scheme ObjectScheme
  555. objectConverter runtime.ObjectConvertor
  556. mapper func() meta.RESTMapper
  557. typeConverter managedfields.TypeConverter
  558. }
  559. var _ ObjectTracker = &managedFieldObjectTracker{}
  560. // NewFieldManagedObjectTracker returns an ObjectTracker that can be used to keep track
  561. // of objects and managed fields for the fake clientset. Mostly useful for unit tests.
  562. func NewFieldManagedObjectTracker(scheme *runtime.Scheme, decoder runtime.Decoder, typeConverter managedfields.TypeConverter) ObjectTracker {
  563. return &managedFieldObjectTracker{
  564. ObjectTracker: NewObjectTracker(scheme, decoder),
  565. scheme: scheme,
  566. objectConverter: scheme,
  567. mapper: func() meta.RESTMapper {
  568. return testrestmapper.TestOnlyStaticRESTMapper(scheme)
  569. },
  570. typeConverter: typeConverter,
  571. }
  572. }
  573. func (t *managedFieldObjectTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, vopts ...metav1.CreateOptions) error {
  574. opts, err := assertOptionalSingleArgument(vopts)
  575. if err != nil {
  576. return err
  577. }
  578. gvk, err := t.mapper().KindFor(gvr)
  579. if err != nil {
  580. return err
  581. }
  582. mgr, err := t.fieldManagerFor(gvk)
  583. if err != nil {
  584. return err
  585. }
  586. objType, err := meta.TypeAccessor(obj)
  587. if err != nil {
  588. return err
  589. }
  590. // Stamp GVK
  591. apiVersion, kind := gvk.ToAPIVersionAndKind()
  592. objType.SetAPIVersion(apiVersion)
  593. objType.SetKind(kind)
  594. objMeta, err := meta.Accessor(obj)
  595. if err != nil {
  596. return err
  597. }
  598. liveObject, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  599. if apierrors.IsNotFound(err) {
  600. liveObject, err = t.scheme.New(gvk)
  601. if err != nil {
  602. return err
  603. }
  604. liveObject.GetObjectKind().SetGroupVersionKind(gvk)
  605. } else if err != nil {
  606. return err
  607. }
  608. objWithManagedFields, err := mgr.Update(liveObject, obj, opts.FieldManager)
  609. if err != nil {
  610. return err
  611. }
  612. return t.ObjectTracker.Create(gvr, objWithManagedFields, ns, opts)
  613. }
  614. func (t *managedFieldObjectTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, vopts ...metav1.UpdateOptions) error {
  615. opts, err := assertOptionalSingleArgument(vopts)
  616. if err != nil {
  617. return err
  618. }
  619. gvk, err := t.mapper().KindFor(gvr)
  620. if err != nil {
  621. return err
  622. }
  623. mgr, err := t.fieldManagerFor(gvk)
  624. if err != nil {
  625. return err
  626. }
  627. objMeta, err := meta.Accessor(obj)
  628. if err != nil {
  629. return err
  630. }
  631. oldObj, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  632. if err != nil {
  633. return err
  634. }
  635. objWithManagedFields, err := mgr.Update(oldObj, obj, opts.FieldManager)
  636. if err != nil {
  637. return err
  638. }
  639. return t.ObjectTracker.Update(gvr, objWithManagedFields, ns, opts)
  640. }
  641. func (t *managedFieldObjectTracker) Patch(gvr schema.GroupVersionResource, patchedObject runtime.Object, ns string, vopts ...metav1.PatchOptions) error {
  642. opts, err := assertOptionalSingleArgument(vopts)
  643. if err != nil {
  644. return err
  645. }
  646. gvk, err := t.mapper().KindFor(gvr)
  647. if err != nil {
  648. return err
  649. }
  650. mgr, err := t.fieldManagerFor(gvk)
  651. if err != nil {
  652. return err
  653. }
  654. objMeta, err := meta.Accessor(patchedObject)
  655. if err != nil {
  656. return err
  657. }
  658. oldObj, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
  659. if err != nil {
  660. return err
  661. }
  662. objWithManagedFields, err := mgr.Update(oldObj, patchedObject, opts.FieldManager)
  663. if err != nil {
  664. return err
  665. }
  666. return t.ObjectTracker.Patch(gvr, objWithManagedFields, ns, vopts...)
  667. }
  668. func (t *managedFieldObjectTracker) Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, vopts ...metav1.PatchOptions) error {
  669. opts, err := assertOptionalSingleArgument(vopts)
  670. if err != nil {
  671. return err
  672. }
  673. gvk, err := t.mapper().KindFor(gvr)
  674. if err != nil {
  675. return err
  676. }
  677. applyConfigurationMeta, err := meta.Accessor(applyConfiguration)
  678. if err != nil {
  679. return err
  680. }
  681. exists := true
  682. liveObject, err := t.ObjectTracker.Get(gvr, ns, applyConfigurationMeta.GetName(), metav1.GetOptions{})
  683. if apierrors.IsNotFound(err) {
  684. exists = false
  685. liveObject, err = t.scheme.New(gvk)
  686. if err != nil {
  687. return err
  688. }
  689. liveObject.GetObjectKind().SetGroupVersionKind(gvk)
  690. } else if err != nil {
  691. return err
  692. }
  693. mgr, err := t.fieldManagerFor(gvk)
  694. if err != nil {
  695. return err
  696. }
  697. force := false
  698. if opts.Force != nil {
  699. force = *opts.Force
  700. }
  701. objWithManagedFields, err := mgr.Apply(liveObject, applyConfiguration, opts.FieldManager, force)
  702. if err != nil {
  703. return err
  704. }
  705. if !exists {
  706. return t.ObjectTracker.Create(gvr, objWithManagedFields, ns, metav1.CreateOptions{
  707. DryRun: opts.DryRun,
  708. FieldManager: opts.FieldManager,
  709. FieldValidation: opts.FieldValidation,
  710. })
  711. } else {
  712. return t.ObjectTracker.Update(gvr, objWithManagedFields, ns, metav1.UpdateOptions{
  713. DryRun: opts.DryRun,
  714. FieldManager: opts.FieldManager,
  715. FieldValidation: opts.FieldValidation,
  716. })
  717. }
  718. }
  719. func (t *managedFieldObjectTracker) fieldManagerFor(gvk schema.GroupVersionKind) (*managedfields.FieldManager, error) {
  720. return managedfields.NewDefaultFieldManager(
  721. t.typeConverter,
  722. t.objectConverter,
  723. &objectDefaulter{},
  724. t.scheme,
  725. gvk,
  726. gvk.GroupVersion(),
  727. "",
  728. nil)
  729. }
  730. // objectDefaulter implements runtime.Defaulter, but it actually
  731. // does nothing.
  732. type objectDefaulter struct{}
  733. func (d *objectDefaulter) Default(_ runtime.Object) {}
  734. // filterByNamespace returns all objects in the collection that
  735. // match provided namespace. Empty namespace matches
  736. // non-namespaced objects.
  737. func filterByNamespace(objs map[types.NamespacedName]runtime.Object, ns string) ([]runtime.Object, error) {
  738. var res []runtime.Object
  739. for _, obj := range objs {
  740. acc, err := meta.Accessor(obj)
  741. if err != nil {
  742. return nil, err
  743. }
  744. if ns != "" && acc.GetNamespace() != ns {
  745. continue
  746. }
  747. res = append(res, obj)
  748. }
  749. // Sort res to get deterministic order.
  750. sort.Slice(res, func(i, j int) bool {
  751. acc1, _ := meta.Accessor(res[i])
  752. acc2, _ := meta.Accessor(res[j])
  753. if acc1.GetNamespace() != acc2.GetNamespace() {
  754. return acc1.GetNamespace() < acc2.GetNamespace()
  755. }
  756. return acc1.GetName() < acc2.GetName()
  757. })
  758. return res, nil
  759. }
  760. func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc {
  761. return func(action Action) (bool, watch.Interface, error) {
  762. return true, watchInterface, err
  763. }
  764. }
  765. // SimpleReactor is a Reactor. Each reaction function is attached to a given verb,resource tuple. "*" in either field matches everything for that value.
  766. // For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions
  767. type SimpleReactor struct {
  768. Verb string
  769. Resource string
  770. Reaction ReactionFunc
  771. }
  772. func (r *SimpleReactor) Handles(action Action) bool {
  773. verbCovers := r.Verb == "*" || r.Verb == action.GetVerb()
  774. if !verbCovers {
  775. return false
  776. }
  777. return resourceCovers(r.Resource, action)
  778. }
  779. func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) {
  780. return r.Reaction(action)
  781. }
  782. // SimpleWatchReactor is a WatchReactor. Each reaction function is attached to a given resource. "*" matches everything for that value.
  783. // For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions
  784. type SimpleWatchReactor struct {
  785. Resource string
  786. Reaction WatchReactionFunc
  787. }
  788. func (r *SimpleWatchReactor) Handles(action Action) bool {
  789. return resourceCovers(r.Resource, action)
  790. }
  791. func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) {
  792. return r.Reaction(action)
  793. }
  794. // SimpleProxyReactor is a ProxyReactor. Each reaction function is attached to a given resource. "*" matches everything for that value.
  795. // For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions.
  796. type SimpleProxyReactor struct {
  797. Resource string
  798. Reaction ProxyReactionFunc
  799. }
  800. func (r *SimpleProxyReactor) Handles(action Action) bool {
  801. return resourceCovers(r.Resource, action)
  802. }
  803. func (r *SimpleProxyReactor) React(action Action) (bool, restclient.ResponseWrapper, error) {
  804. return r.Reaction(action)
  805. }
  806. func resourceCovers(resource string, action Action) bool {
  807. if resource == "*" {
  808. return true
  809. }
  810. if resource == action.GetResource().Resource {
  811. return true
  812. }
  813. if index := strings.Index(resource, "/"); index != -1 &&
  814. resource[:index] == action.GetResource().Resource &&
  815. resource[index+1:] == action.GetSubresource() {
  816. return true
  817. }
  818. return false
  819. }
  820. // assertOptionalSingleArgument returns an error if there is more than one variadic argument.
  821. // Otherwise, it returns the first variadic argument, or zero value if there are no arguments.
  822. func assertOptionalSingleArgument[T any](arguments []T) (T, error) {
  823. var a T
  824. switch len(arguments) {
  825. case 0:
  826. return a, nil
  827. case 1:
  828. return arguments[0], nil
  829. default:
  830. return a, fmt.Errorf("expected only one option argument but got %d", len(arguments))
  831. }
  832. }