simple.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. Copyright 2018 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 dynamic
  14. import (
  15. "io"
  16. "k8s.io/apimachinery/pkg/api/meta"
  17. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  18. "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  19. "k8s.io/apimachinery/pkg/runtime"
  20. "k8s.io/apimachinery/pkg/runtime/schema"
  21. "k8s.io/apimachinery/pkg/runtime/serializer/streaming"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/apimachinery/pkg/watch"
  24. "k8s.io/client-go/rest"
  25. )
  26. type dynamicClient struct {
  27. client *rest.RESTClient
  28. }
  29. var _ Interface = &dynamicClient{}
  30. func NewForConfig(inConfig *rest.Config) (Interface, error) {
  31. config := rest.CopyConfig(inConfig)
  32. // for serializing the options
  33. config.GroupVersion = &schema.GroupVersion{}
  34. config.APIPath = "/if-you-see-this-search-for-the-break"
  35. config.AcceptContentTypes = "application/json"
  36. config.ContentType = "application/json"
  37. config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
  38. if config.UserAgent == "" {
  39. config.UserAgent = rest.DefaultKubernetesUserAgent()
  40. }
  41. restClient, err := rest.RESTClientFor(config)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return &dynamicClient{client: restClient}, nil
  46. }
  47. type dynamicResourceClient struct {
  48. client *dynamicClient
  49. namespace string
  50. resource schema.GroupVersionResource
  51. }
  52. func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
  53. return &dynamicResourceClient{client: c, resource: resource}
  54. }
  55. func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
  56. ret := *c
  57. ret.namespace = ns
  58. return &ret
  59. }
  60. func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
  61. outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
  62. if err != nil {
  63. return nil, err
  64. }
  65. name := ""
  66. if len(subresources) > 0 {
  67. accessor, err := meta.Accessor(obj)
  68. if err != nil {
  69. return nil, err
  70. }
  71. name = accessor.GetName()
  72. }
  73. result := c.client.client.Post().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(outBytes).Do()
  74. if err := result.Error(); err != nil {
  75. return nil, err
  76. }
  77. retBytes, err := result.Raw()
  78. if err != nil {
  79. return nil, err
  80. }
  81. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return uncastObj.(*unstructured.Unstructured), nil
  86. }
  87. func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
  88. accessor, err := meta.Accessor(obj)
  89. if err != nil {
  90. return nil, err
  91. }
  92. outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
  93. if err != nil {
  94. return nil, err
  95. }
  96. result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).Body(outBytes).Do()
  97. if err := result.Error(); err != nil {
  98. return nil, err
  99. }
  100. retBytes, err := result.Raw()
  101. if err != nil {
  102. return nil, err
  103. }
  104. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  105. if err != nil {
  106. return nil, err
  107. }
  108. return uncastObj.(*unstructured.Unstructured), nil
  109. }
  110. func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
  111. accessor, err := meta.Accessor(obj)
  112. if err != nil {
  113. return nil, err
  114. }
  115. outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
  116. if err != nil {
  117. return nil, err
  118. }
  119. result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).Body(outBytes).Do()
  120. if err := result.Error(); err != nil {
  121. return nil, err
  122. }
  123. retBytes, err := result.Raw()
  124. if err != nil {
  125. return nil, err
  126. }
  127. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  128. if err != nil {
  129. return nil, err
  130. }
  131. return uncastObj.(*unstructured.Unstructured), nil
  132. }
  133. func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
  134. if opts == nil {
  135. opts = &metav1.DeleteOptions{}
  136. }
  137. deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
  138. if err != nil {
  139. return err
  140. }
  141. result := c.client.client.Delete().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(deleteOptionsByte).Do()
  142. return result.Error()
  143. }
  144. func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
  145. if opts == nil {
  146. opts = &metav1.DeleteOptions{}
  147. }
  148. deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
  149. if err != nil {
  150. return err
  151. }
  152. result := c.client.client.Delete().AbsPath(c.makeURLSegments("")...).Body(deleteOptionsByte).SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).Do()
  153. return result.Error()
  154. }
  155. func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
  156. result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
  157. if err := result.Error(); err != nil {
  158. return nil, err
  159. }
  160. retBytes, err := result.Raw()
  161. if err != nil {
  162. return nil, err
  163. }
  164. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  165. if err != nil {
  166. return nil, err
  167. }
  168. return uncastObj.(*unstructured.Unstructured), nil
  169. }
  170. func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
  171. result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
  172. if err := result.Error(); err != nil {
  173. return nil, err
  174. }
  175. retBytes, err := result.Raw()
  176. if err != nil {
  177. return nil, err
  178. }
  179. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  180. if err != nil {
  181. return nil, err
  182. }
  183. if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
  184. return list, nil
  185. }
  186. list, err := uncastObj.(*unstructured.Unstructured).ToList()
  187. if err != nil {
  188. return nil, err
  189. }
  190. return list, nil
  191. }
  192. func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
  193. internalGV := schema.GroupVersions{
  194. {Group: c.resource.Group, Version: runtime.APIVersionInternal},
  195. // always include the legacy group as a decoding target to handle non-error `Status` return types
  196. {Group: "", Version: runtime.APIVersionInternal},
  197. }
  198. s := &rest.Serializers{
  199. Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
  200. Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),
  201. RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
  202. return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
  203. },
  204. StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
  205. Framer: watchJsonSerializerInfo.StreamSerializer.Framer,
  206. }
  207. wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
  208. framer := s.Framer.NewFrameReader(body)
  209. return streaming.NewDecoder(framer, s.StreamingSerializer)
  210. }
  211. opts.Watch = true
  212. return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
  213. SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
  214. WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
  215. }
  216. func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error) {
  217. result := c.client.client.Patch(pt).AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(data).Do()
  218. if err := result.Error(); err != nil {
  219. return nil, err
  220. }
  221. retBytes, err := result.Raw()
  222. if err != nil {
  223. return nil, err
  224. }
  225. uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return uncastObj.(*unstructured.Unstructured), nil
  230. }
  231. func (c *dynamicResourceClient) makeURLSegments(name string) []string {
  232. url := []string{}
  233. if len(c.resource.Group) == 0 {
  234. url = append(url, "api")
  235. } else {
  236. url = append(url, "apis", c.resource.Group)
  237. }
  238. url = append(url, c.resource.Version)
  239. if len(c.namespace) > 0 {
  240. url = append(url, "namespaces", c.namespace)
  241. }
  242. url = append(url, c.resource.Resource)
  243. if len(name) > 0 {
  244. url = append(url, name)
  245. }
  246. return url
  247. }