Merge pull request #131165 from liggitt/e2e-requesturi

Make Request#RequestURI honor configured context root

Kubernetes-commit: d76b47cc4cd58fcb6544764ea6c1c809ab8fa265
This commit is contained in:
Kubernetes Publisher 2025-05-06 11:49:14 -07:00
commit 2d0ad1ac54
5 changed files with 43 additions and 13 deletions

2
go.mod
View File

@ -26,7 +26,7 @@ require (
google.golang.org/protobuf v1.36.5 google.golang.org/protobuf v1.36.5
gopkg.in/evanphx/json-patch.v4 v4.12.0 gopkg.in/evanphx/json-patch.v4 v4.12.0
k8s.io/api v0.0.0-20250503031400-f7e72be095ee 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/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979

4
go.sum
View File

@ -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= 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 h1:+YExLdNpiASfnQXQfpyLIGIps0RcJPNt7NdiCVH8Bys=
k8s.io/api v0.0.0-20250503031400-f7e72be095ee/go.mod h1:AsuSCzGYZszSLf5GB+qx8FBGGirk0I/TZUkQJFsPRAQ= 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-20250506191157-e07849993d77 h1:bwypcAN4gpWZ8VRVrgr0tYmunGNRCD869R3/h5o2Qa4=
k8s.io/apimachinery v0.0.0-20250503031111-512f488de379/go.mod h1:b+h1nads2hmyfwvvorkgHUriRTTaJ2p2mk0l03sESn8= 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 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=

View File

@ -56,9 +56,13 @@ func (c *client) Paths() (map[string]GroupVersion, error) {
return nil, err 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 // Create GroupVersions for each element of the result
result := map[string]GroupVersion{} result := map[string]GroupVersion{}
for k, v := range discoMap.Paths { 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 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. // 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 // See https://github.com/kubernetes/kubernetes/issues/117463 for details

View File

@ -378,8 +378,9 @@ func (r *Request) NamespaceIfScoped(namespace string, scoped bool) *Request {
return r return r
} }
// AbsPath overwrites an existing path with the segments provided. Trailing slashes are preserved // AbsPath overwrites an existing path with the segments provided.
// when a single segment is passed. // 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 { func (r *Request) AbsPath(segments ...string) *Request {
if r.err != nil { if r.err != nil {
return r return r
@ -392,8 +393,8 @@ func (r *Request) AbsPath(segments ...string) *Request {
return r return r
} }
// RequestURI overwrites existing path and parameters with the value of the provided server relative // RequestURI overwrites existing path and parameters with the value of the provided server relative URI.
// URI. // This is equivalent to clearing params, then calling AbsPath() + Param() for each query parameter.
func (r *Request) RequestURI(uri string) *Request { func (r *Request) RequestURI(uri string) *Request {
if r.err != nil { if r.err != nil {
return r return r
@ -403,14 +404,17 @@ func (r *Request) RequestURI(uri string) *Request {
r.err = err r.err = err
return r 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 len(locator.Query()) > 0 {
if r.params == nil { // clear any existing params
r.params = make(url.Values) r.params = make(url.Values)
}
for k, v := range locator.Query() { for k, v := range locator.Query() {
r.params[k] = v r.params[k] = v
} }
} else {
// clear any existing params
r.params = nil
} }
return r return r
} }

View File

@ -292,14 +292,36 @@ func TestRequestError(t *testing.T) {
} }
func TestRequestURI(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.Prefix("other")
r.RequestURI("/test?foo=b&a=b&c=1&c=2") r.RequestURI("/test?foo=b&a=b&c=1&c=2")
if r.pathPrefix != "/test" { if r.pathPrefix != "/test" {
t.Errorf("path is wrong: %#v", r) t.Errorf("path is wrong: %#v", r)
} }
if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { 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)
} }
} }