sigs.k8s.io/controller-runtime@v0.18.2/pkg/client/metadata_client.go (about) 1 /* 2 Copyright 2020 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 client 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 24 "k8s.io/apimachinery/pkg/api/meta" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 "k8s.io/client-go/metadata" 28 ) 29 30 // TODO(directxman12): we could rewrite this on top of the low-level REST 31 // client to avoid the extra shallow copy at the end, but I'm not sure it's 32 // worth it -- the metadata client deals with falling back to loading the whole 33 // object on older API servers, etc, and we'd have to reproduce that. 34 35 // metadataClient is a client that reads & writes metadata-only requests to/from the API server. 36 type metadataClient struct { 37 client metadata.Interface 38 restMapper meta.RESTMapper 39 } 40 41 func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) { 42 mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) 43 if err != nil { 44 return nil, err 45 } 46 if mapping.Scope.Name() == meta.RESTScopeNameRoot { 47 return mc.client.Resource(mapping.Resource), nil 48 } 49 return mc.client.Resource(mapping.Resource).Namespace(ns), nil 50 } 51 52 // Delete implements client.Client. 53 func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error { 54 metadata, ok := obj.(*metav1.PartialObjectMetadata) 55 if !ok { 56 return fmt.Errorf("metadata client did not understand object: %T", obj) 57 } 58 59 resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace) 60 if err != nil { 61 return err 62 } 63 64 deleteOpts := DeleteOptions{} 65 deleteOpts.ApplyOptions(opts) 66 67 return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions()) 68 } 69 70 // DeleteAllOf implements client.Client. 71 func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error { 72 metadata, ok := obj.(*metav1.PartialObjectMetadata) 73 if !ok { 74 return fmt.Errorf("metadata client did not understand object: %T", obj) 75 } 76 77 deleteAllOfOpts := DeleteAllOfOptions{} 78 deleteAllOfOpts.ApplyOptions(opts) 79 80 resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace) 81 if err != nil { 82 return err 83 } 84 85 return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions()) 86 } 87 88 // Patch implements client.Client. 89 func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error { 90 metadata, ok := obj.(*metav1.PartialObjectMetadata) 91 if !ok { 92 return fmt.Errorf("metadata client did not understand object: %T", obj) 93 } 94 95 gvk := metadata.GroupVersionKind() 96 resInt, err := mc.getResourceInterface(gvk, metadata.Namespace) 97 if err != nil { 98 return err 99 } 100 101 data, err := patch.Data(obj) 102 if err != nil { 103 return err 104 } 105 106 patchOpts := &PatchOptions{} 107 patchOpts.ApplyOptions(opts) 108 109 res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions()) 110 if err != nil { 111 return err 112 } 113 *metadata = *res 114 metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata 115 return nil 116 } 117 118 // Get implements client.Client. 119 func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { 120 metadata, ok := obj.(*metav1.PartialObjectMetadata) 121 if !ok { 122 return fmt.Errorf("metadata client did not understand object: %T", obj) 123 } 124 125 gvk := metadata.GroupVersionKind() 126 127 getOpts := GetOptions{} 128 getOpts.ApplyOptions(opts) 129 130 resInt, err := mc.getResourceInterface(gvk, key.Namespace) 131 if err != nil { 132 return err 133 } 134 135 res, err := resInt.Get(ctx, key.Name, *getOpts.AsGetOptions()) 136 if err != nil { 137 return err 138 } 139 *metadata = *res 140 metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata 141 return nil 142 } 143 144 // List implements client.Client. 145 func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error { 146 metadata, ok := obj.(*metav1.PartialObjectMetadataList) 147 if !ok { 148 return fmt.Errorf("metadata client did not understand object: %T", obj) 149 } 150 151 gvk := metadata.GroupVersionKind() 152 gvk.Kind = strings.TrimSuffix(gvk.Kind, "List") 153 154 listOpts := ListOptions{} 155 listOpts.ApplyOptions(opts) 156 157 resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace) 158 if err != nil { 159 return err 160 } 161 162 res, err := resInt.List(ctx, *listOpts.AsListOptions()) 163 if err != nil { 164 return err 165 } 166 *metadata = *res 167 metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata 168 return nil 169 } 170 171 func (mc *metadataClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error { 172 metadata, ok := obj.(*metav1.PartialObjectMetadata) 173 if !ok { 174 return fmt.Errorf("metadata client did not understand object: %T", obj) 175 } 176 177 gvk := metadata.GroupVersionKind() 178 resInt, err := mc.getResourceInterface(gvk, metadata.Namespace) 179 if err != nil { 180 return err 181 } 182 183 patchOpts := &SubResourcePatchOptions{} 184 patchOpts.ApplyOptions(opts) 185 186 body := obj 187 if patchOpts.SubResourceBody != nil { 188 body = patchOpts.SubResourceBody 189 } 190 191 data, err := patch.Data(body) 192 if err != nil { 193 return err 194 } 195 196 res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), subResource) 197 if err != nil { 198 return err 199 } 200 201 *metadata = *res 202 metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata 203 return nil 204 }