mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Merge pull request #25221 from krousey/dynamic_client
Automatic merge from submit-queue Adding patch and cleaning up namespace code cc @kubernetes/sig-api-machinery
This commit is contained in:
commit
c5d85c7822
@ -98,20 +98,11 @@ type ResourceClient struct {
|
||||
ns string
|
||||
}
|
||||
|
||||
// namespace applies a namespace to the request if the configured
|
||||
// resource is a namespaced resource. Otherwise, it just returns the
|
||||
// passed in request.
|
||||
func (rc *ResourceClient) namespace(req *restclient.Request) *restclient.Request {
|
||||
if rc.resource.Namespaced {
|
||||
return req.Namespace(rc.ns)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
// List returns a list of objects for this resource.
|
||||
func (rc *ResourceClient) List(opts runtime.Object) (*runtime.UnstructuredList, error) {
|
||||
result := new(runtime.UnstructuredList)
|
||||
err := rc.namespace(rc.cl.Get()).
|
||||
err := rc.cl.Get().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(opts, parameterEncoder).
|
||||
Do().
|
||||
@ -122,7 +113,8 @@ func (rc *ResourceClient) List(opts runtime.Object) (*runtime.UnstructuredList,
|
||||
// Get gets the resource with the specified name.
|
||||
func (rc *ResourceClient) Get(name string) (*runtime.Unstructured, error) {
|
||||
result := new(runtime.Unstructured)
|
||||
err := rc.namespace(rc.cl.Get()).
|
||||
err := rc.cl.Get().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Do().
|
||||
@ -132,7 +124,8 @@ func (rc *ResourceClient) Get(name string) (*runtime.Unstructured, error) {
|
||||
|
||||
// Delete deletes the resource with the specified name.
|
||||
func (rc *ResourceClient) Delete(name string, opts *v1.DeleteOptions) error {
|
||||
return rc.namespace(rc.cl.Delete()).
|
||||
return rc.cl.Delete().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Body(opts).
|
||||
@ -142,7 +135,8 @@ func (rc *ResourceClient) Delete(name string, opts *v1.DeleteOptions) error {
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (rc *ResourceClient) DeleteCollection(deleteOptions *v1.DeleteOptions, listOptions runtime.Object) error {
|
||||
return rc.namespace(rc.cl.Delete()).
|
||||
return rc.cl.Delete().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(listOptions, parameterEncoder).
|
||||
Body(deleteOptions).
|
||||
@ -153,7 +147,8 @@ func (rc *ResourceClient) DeleteCollection(deleteOptions *v1.DeleteOptions, list
|
||||
// Create creates the provided resource.
|
||||
func (rc *ResourceClient) Create(obj *runtime.Unstructured) (*runtime.Unstructured, error) {
|
||||
result := new(runtime.Unstructured)
|
||||
err := rc.namespace(rc.cl.Post()).
|
||||
err := rc.cl.Post().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Body(obj).
|
||||
Do().
|
||||
@ -167,7 +162,8 @@ func (rc *ResourceClient) Update(obj *runtime.Unstructured) (*runtime.Unstructur
|
||||
if len(obj.GetName()) == 0 {
|
||||
return result, errors.New("object missing name")
|
||||
}
|
||||
err := rc.namespace(rc.cl.Put()).
|
||||
err := rc.cl.Put().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(obj.GetName()).
|
||||
Body(obj).
|
||||
@ -178,12 +174,26 @@ func (rc *ResourceClient) Update(obj *runtime.Unstructured) (*runtime.Unstructur
|
||||
|
||||
// Watch returns a watch.Interface that watches the resource.
|
||||
func (rc *ResourceClient) Watch(opts runtime.Object) (watch.Interface, error) {
|
||||
return rc.namespace(rc.cl.Get().Prefix("watch")).
|
||||
return rc.cl.Get().
|
||||
Prefix("watch").
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(opts, parameterEncoder).
|
||||
Watch()
|
||||
}
|
||||
|
||||
func (rc *ResourceClient) Patch(name string, pt api.PatchType, data []byte) (*runtime.Unstructured, error) {
|
||||
result := new(runtime.Unstructured)
|
||||
err := rc.cl.Patch(pt).
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// dynamicCodec is a codec that wraps the standard unstructured codec
|
||||
// with special handling for Status objects.
|
||||
type dynamicCodec struct{}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
@ -481,3 +482,69 @@ func TestWatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *runtime.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_patch",
|
||||
path: "/api/gtest/vtest/rtest/normal_patch",
|
||||
patch: getJSON("vTest", "rTest", "normal_patch"),
|
||||
want: getObject("vTest", "rTest", "normal_patch"),
|
||||
},
|
||||
{
|
||||
name: "namespaced_patch",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest/namespaced_patch",
|
||||
patch: getJSON("vTest", "rTest", "namespaced_patch"),
|
||||
want: getObject("vTest", "rTest", "namespaced_patch"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &unversioned.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &unversioned.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" {
|
||||
t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Patch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
content := r.Header.Get("Content-Type")
|
||||
if content != string(api.StrategicMergePatchType) {
|
||||
t.Errorf("Patch(%q) got Content-Type %s. wanted %s", tc.name, content, api.StrategicMergePatchType)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Patch(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, api.StrategicMergePatchType, tc.patch)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when patching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Patch(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user