diff --git a/pkg/client/helper.go b/pkg/client/helper.go index 42c6cb35f8e..6c83f2f456b 100644 --- a/pkg/client/helper.go +++ b/pkg/client/helper.go @@ -30,7 +30,12 @@ import ( // initialization. type Config struct { // Host must be a host string, a host:port pair, or a URL to the base of the API. - Host string + Host string + // Prefix is the sub path of the server. If not specified, the client will set + // a default value. Use "/" to indicate the server root should be used + Prefix string + // Version is the API version to talk to. If not specified, the client will use + // the preferred version. Version string // Server requires Basic authentication @@ -61,7 +66,11 @@ type Config struct { // and delete on these objects. An error is returned if the provided configuration // is not valid. func New(c *Config) (*Client, error) { - client, err := RESTClientFor(c) + config := *c + if config.Prefix == "" { + config.Prefix = "/api" + } + client, err := RESTClientFor(&config) if err != nil { return nil, err } @@ -150,7 +159,7 @@ func TransportFor(config *Config) (http.RoundTripper, error) { // DefaultServerURL converts a host, host:port, or URL string to the default base server API path // to use with a Client at a given API version following the standard conventions for a // Kubernetes API. -func DefaultServerURL(host, version string, defaultSecure bool) (*url.URL, error) { +func DefaultServerURL(host, prefix, version string, defaultSecure bool) (*url.URL, error) { if host == "" { return nil, fmt.Errorf("host must be a URL or a host:port pair") } @@ -177,9 +186,12 @@ func DefaultServerURL(host, version string, defaultSecure bool) (*url.URL, error } // If the user specified a URL without a path component (http://server.com), automatically - // append the default API prefix + // append the default prefix if hostURL.Path == "" { - hostURL.Path = "/api" + if prefix == "" { + prefix = "/" + } + hostURL.Path = prefix } // Add the version to the end of the path @@ -211,7 +223,7 @@ func defaultServerUrlFor(config *Config) (*url.URL, error) { if host == "" { host = "localhost" } - return DefaultServerURL(host, version, defaultSecure) + return DefaultServerURL(host, config.Prefix, version, defaultSecure) } // defaultVersionFor is shared between defaultServerUrlFor and RESTClientFor diff --git a/pkg/client/restclient_test.go b/pkg/client/restclient_test.go index b85a888aaee..8c28df74829 100644 --- a/pkg/client/restclient_test.go +++ b/pkg/client/restclient_test.go @@ -37,9 +37,9 @@ func TestChecksCodec(t *testing.T) { Prefix string Codec runtime.Codec }{ - "v1beta1": {false, "/api/v1beta1/", v1beta1.Codec}, - "": {false, "/api/v1beta1/", v1beta1.Codec}, - "v1beta2": {false, "/api/v1beta2/", v1beta2.Codec}, + "v1beta1": {false, "/v1beta1/", v1beta1.Codec}, + "": {false, "/v1beta1/", v1beta1.Codec}, + "v1beta2": {false, "/v1beta2/", v1beta2.Codec}, "v1beta3": {true, "", nil}, } for version, expected := range testCases { @@ -64,31 +64,36 @@ func TestChecksCodec(t *testing.T) { } func TestValidatesHostParameter(t *testing.T) { - testCases := map[string]struct { + testCases := []struct { + Host string + Prefix string + URL string Err bool }{ - "127.0.0.1": {"http://127.0.0.1/api/v1beta1/", false}, - "127.0.0.1:8080": {"http://127.0.0.1:8080/api/v1beta1/", false}, - "foo.bar.com": {"http://foo.bar.com/api/v1beta1/", false}, - "http://host/prefix": {"http://host/prefix/v1beta1/", false}, - "http://host": {"http://host/api/v1beta1/", false}, - "host/server": {"", true}, + {"127.0.0.1", "", "http://127.0.0.1/v1beta1/", false}, + {"127.0.0.1:8080", "", "http://127.0.0.1:8080/v1beta1/", false}, + {"foo.bar.com", "", "http://foo.bar.com/v1beta1/", false}, + {"http://host/prefix", "", "http://host/prefix/v1beta1/", false}, + {"http://host", "", "http://host/v1beta1/", false}, + {"http://host", "/", "http://host/v1beta1/", false}, + {"http://host", "/other", "http://host/other/v1beta1/", false}, + {"host/server", "", "", true}, } - for k, expected := range testCases { - c, err := RESTClientFor(&Config{Host: k, Version: "v1beta1"}) + for i, testCase := range testCases { + c, err := RESTClientFor(&Config{Host: testCase.Host, Prefix: testCase.Prefix, Version: "v1beta1"}) switch { - case err == nil && expected.Err: + case err == nil && testCase.Err: t.Errorf("expected error but was nil") continue - case err != nil && !expected.Err: + case err != nil && !testCase.Err: t.Errorf("unexpected error %v", err) continue case err != nil: continue } - if e, a := expected.URL, c.baseURL.String(); e != a { - t.Errorf("%s: expected host %s, got %s", k, e, a) + if e, a := testCase.URL, c.baseURL.String(); e != a { + t.Errorf("%d: expected host %s, got %s", i, e, a) continue } }