diff --git a/go.mod b/go.mod index 28416d78..61ae569d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( google.golang.org/protobuf v1.36.5 gopkg.in/evanphx/json-patch.v4 v4.12.0 k8s.io/api v0.0.0-20250503031400-f7e72be095ee - k8s.io/apimachinery v0.0.0-20250503031111-512f488de379 + k8s.io/apimachinery v0.0.0-20250506191157-e07849993d77 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 diff --git a/go.sum b/go.sum index d6eb70aa..0e553f91 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.0.0-20250503031400-f7e72be095ee h1:+YExLdNpiASfnQXQfpyLIGIps0RcJPNt7NdiCVH8Bys= k8s.io/api v0.0.0-20250503031400-f7e72be095ee/go.mod h1:AsuSCzGYZszSLf5GB+qx8FBGGirk0I/TZUkQJFsPRAQ= -k8s.io/apimachinery v0.0.0-20250503031111-512f488de379 h1:SRKtgNyQVTGF7yOs8CXK9AhZMd/1g5h4YlHAkYVXq5Y= -k8s.io/apimachinery v0.0.0-20250503031111-512f488de379/go.mod h1:b+h1nads2hmyfwvvorkgHUriRTTaJ2p2mk0l03sESn8= +k8s.io/apimachinery v0.0.0-20250506191157-e07849993d77 h1:bwypcAN4gpWZ8VRVrgr0tYmunGNRCD869R3/h5o2Qa4= +k8s.io/apimachinery v0.0.0-20250506191157-e07849993d77/go.mod h1:b+h1nads2hmyfwvvorkgHUriRTTaJ2p2mk0l03sESn8= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= diff --git a/openapi/client.go b/openapi/client.go index 6a430571..d32895a2 100644 --- a/openapi/client.go +++ b/openapi/client.go @@ -56,9 +56,13 @@ func (c *client) Paths() (map[string]GroupVersion, error) { return nil, err } + // Calculate the client-side prefix for a "root" request + rootPrefix := strings.TrimSuffix(c.restClient.Get().AbsPath("/").URL().Path, "/") // Create GroupVersions for each element of the result result := map[string]GroupVersion{} for k, v := range discoMap.Paths { + // Trim off the prefix that will always be added in client-side + v.ServerRelativeURL = strings.TrimPrefix(v.ServerRelativeURL, rootPrefix) // If the server returned a URL rooted at /openapi/v3, preserve any additional client-side prefix. // If the server returned a URL not rooted at /openapi/v3, treat it as an actual server-relative URL. // See https://github.com/kubernetes/kubernetes/issues/117463 for details diff --git a/rest/request.go b/rest/request.go index 1eb2f9b4..9696d1cb 100644 --- a/rest/request.go +++ b/rest/request.go @@ -378,8 +378,9 @@ func (r *Request) NamespaceIfScoped(namespace string, scoped bool) *Request { return r } -// AbsPath overwrites an existing path with the segments provided. Trailing slashes are preserved -// when a single segment is passed. +// AbsPath overwrites an existing path with the segments provided. +// Trailing slashes are preserved when a single segment is passed. +// Any path in the request's REST client's base URL is preserved as a prefix. func (r *Request) AbsPath(segments ...string) *Request { if r.err != nil { return r @@ -392,8 +393,8 @@ func (r *Request) AbsPath(segments ...string) *Request { return r } -// RequestURI overwrites existing path and parameters with the value of the provided server relative -// URI. +// RequestURI overwrites existing path and parameters with the value of the provided server relative URI. +// This is equivalent to clearing params, then calling AbsPath() + Param() for each query parameter. func (r *Request) RequestURI(uri string) *Request { if r.err != nil { return r @@ -403,14 +404,17 @@ func (r *Request) RequestURI(uri string) *Request { r.err = err return r } - r.pathPrefix = locator.Path + // AbsPath handles prepending r.c.base.Path, if set + r.AbsPath(locator.Path) if len(locator.Query()) > 0 { - if r.params == nil { - r.params = make(url.Values) - } + // clear any existing params + r.params = make(url.Values) for k, v := range locator.Query() { r.params[k] = v } + } else { + // clear any existing params + r.params = nil } return r } diff --git a/rest/request_test.go b/rest/request_test.go index fd64dcb0..ad106169 100644 --- a/rest/request_test.go +++ b/rest/request_test.go @@ -292,14 +292,36 @@ func TestRequestError(t *testing.T) { } func TestRequestURI(t *testing.T) { - r := (&Request{}).Param("foo", "a") + r := (&Request{c: &RESTClient{base: &url.URL{Path: "/"}}}).Param("foo", "a").Param("bar", "b") r.Prefix("other") r.RequestURI("/test?foo=b&a=b&c=1&c=2") if r.pathPrefix != "/test" { t.Errorf("path is wrong: %#v", r) } if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { - t.Errorf("should have set a param: %#v", r) + t.Errorf("should have set a param, got: %#v", r.params) + } +} + +func TestRequestURIContext(t *testing.T) { + r := (&Request{c: &RESTClient{base: &url.URL{Path: "/context"}}}).Param("foo", "a").Param("bar", "b") + r.Prefix("other") + r.RequestURI("/test?foo=b&a=b&c=1&c=2") + if r.pathPrefix != "/context/test" { + t.Errorf("path is wrong: %#v", r) + } + if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { + t.Errorf("should have set a param, got: %#v", r.params) + } + + r = (&Request{c: &RESTClient{base: &url.URL{Path: "/context"}}}).Param("foo", "a").Param("bar", "b") + r.Prefix("other") + r.RequestURI("../test?foo=b&a=b&c=1&c=2") + if r.pathPrefix != "/test" { + t.Errorf("path is wrong: %#v", r) + } + if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { + t.Errorf("should have set a param, got: %#v", r.params) } }