efe1fa89fe
Yes, this is a huge commit.
The middleware allows you to customize the API groups of all of the
*.pinniped.dev API groups.
Some notes about other small things in this commit:
- We removed the internal/client package in favor of pkg/conciergeclient. The
two packages do basically the same thing. I don't think we use the former
anymore.
- We re-enabled cluster-scoped owner assertions in the integration tests.
This code was added in internal/ownerref. See a0546942
for when this
assertion was removed.
- Note: the middlware code is in charge of restoring the GV of a request object,
so we should never need to write mutations that do that.
- We updated the supervisor secret generation to no longer manually set an owner
reference to the deployment since the middleware code now does this. I think we
still need some way to make an initial event for the secret generator
controller, which involves knowing the namespace and the name of the generated
secret, so I still wired the deployment through. We could use a namespace/name
tuple here, but I was lazy.
Signed-off-by: Andrew Keesler <akeesler@vmware.com>
Co-authored-by: Ryan Richard <richardry@vmware.com>
232 lines
6.7 KiB
Go
232 lines
6.7 KiB
Go
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package kubeclient
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
|
|
|
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
|
|
configv1alpha1 "go.pinniped.dev/generated/1.20/apis/supervisor/config/v1alpha1"
|
|
)
|
|
|
|
func Test_updatePathNewGVK(t *testing.T) {
|
|
type args struct {
|
|
reqURL *url.URL
|
|
result *mutationResult
|
|
apiPathPrefix string
|
|
reqInfo *genericapirequest.RequestInfo
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *url.URL
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "no gvk change",
|
|
args: args{
|
|
reqURL: mustParse(t, "https://walrus.tld/api/v1/pods"),
|
|
result: &mutationResult{},
|
|
},
|
|
want: mustParse(t, "https://walrus.tld/api/v1/pods"),
|
|
},
|
|
{
|
|
name: "no original gvk group",
|
|
args: args{
|
|
result: &mutationResult{
|
|
origGVK: schema.GroupVersionKind{
|
|
Group: "",
|
|
},
|
|
gvkChanged: true,
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "cluster-scoped list path",
|
|
args: args{
|
|
reqURL: mustParse(t, "https://walrus.tld/apis/"+loginv1alpha1.SchemeGroupVersion.String()+"/tokencredentialrequests"),
|
|
result: &mutationResult{
|
|
origGVK: loginv1alpha1.SchemeGroupVersion.WithKind("TokenCredentialRequest"),
|
|
newGVK: schema.GroupVersionKind{
|
|
Group: "login.concierge.tuna.io",
|
|
Version: loginv1alpha1.SchemeGroupVersion.Version,
|
|
Kind: "TokenCredentialRequest",
|
|
},
|
|
gvkChanged: true,
|
|
},
|
|
apiPathPrefix: "/apis",
|
|
reqInfo: &genericapirequest.RequestInfo{},
|
|
},
|
|
want: mustParse(t, "https://walrus.tld/apis/login.concierge.tuna.io/v1alpha1/tokencredentialrequests"),
|
|
},
|
|
{
|
|
name: "cluster-scoped get path",
|
|
args: args{
|
|
reqURL: mustParse(t, "https://walrus.tld/apis/"+loginv1alpha1.SchemeGroupVersion.String()+"/tokencredentialrequests/some-name"),
|
|
result: &mutationResult{
|
|
origGVK: loginv1alpha1.SchemeGroupVersion.WithKind("TokenCredentialRequest"),
|
|
newGVK: schema.GroupVersionKind{
|
|
Group: "login.concierge.tuna.io",
|
|
Version: loginv1alpha1.SchemeGroupVersion.Version,
|
|
Kind: "TokenCredentialRequest",
|
|
},
|
|
gvkChanged: true,
|
|
},
|
|
apiPathPrefix: "/apis",
|
|
reqInfo: &genericapirequest.RequestInfo{},
|
|
},
|
|
want: mustParse(t, "https://walrus.tld/apis/login.concierge.tuna.io/v1alpha1/tokencredentialrequests/some-name"),
|
|
},
|
|
{
|
|
name: "namespace-scoped list path",
|
|
args: args{
|
|
reqURL: mustParse(t, "https://walrus.tld/apis/"+configv1alpha1.SchemeGroupVersion.String()+"/namespaces/default/federationdomains"),
|
|
result: &mutationResult{
|
|
origGVK: configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain"),
|
|
newGVK: schema.GroupVersionKind{
|
|
Group: "config.supervisor.tuna.io",
|
|
Version: configv1alpha1.SchemeGroupVersion.Version,
|
|
Kind: "FederationDomain",
|
|
},
|
|
gvkChanged: true,
|
|
},
|
|
apiPathPrefix: "/apis",
|
|
reqInfo: &genericapirequest.RequestInfo{},
|
|
},
|
|
want: mustParse(t, "https://walrus.tld/apis/config.supervisor.tuna.io/v1alpha1/namespaces/default/federationdomains"),
|
|
},
|
|
{
|
|
name: "namespace-scoped get path",
|
|
args: args{
|
|
reqURL: mustParse(t, "https://walrus.tld/apis/"+configv1alpha1.SchemeGroupVersion.String()+"/namespaces/default/federationdomains/some-name"),
|
|
result: &mutationResult{
|
|
origGVK: configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain"),
|
|
newGVK: schema.GroupVersionKind{
|
|
Group: "config.supervisor.tuna.io",
|
|
Version: configv1alpha1.SchemeGroupVersion.Version,
|
|
Kind: "FederationDomain",
|
|
},
|
|
gvkChanged: true,
|
|
},
|
|
apiPathPrefix: "/apis",
|
|
reqInfo: &genericapirequest.RequestInfo{},
|
|
},
|
|
want: mustParse(t, "https://walrus.tld/apis/config.supervisor.tuna.io/v1alpha1/namespaces/default/federationdomains/some-name"),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := updatePathNewGVK(tt.args.reqURL, tt.args.result, tt.args.apiPathPrefix, tt.args.reqInfo)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("updatePathNewGVK() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("updatePathNewGVK() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_reqWithoutPrefix(t *testing.T) {
|
|
body := ioutil.NopCloser(bytes.NewBuffer([]byte("some body")))
|
|
newReq := func(rawurl string) *http.Request {
|
|
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, rawurl, body)
|
|
require.NoError(t, err)
|
|
return req
|
|
}
|
|
|
|
type args struct {
|
|
req *http.Request
|
|
hostURL string
|
|
apiPathPrefix string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *http.Request
|
|
}{
|
|
{
|
|
name: "happy path",
|
|
args: args{
|
|
req: newReq("https://walrus.tld/apis/some/path"),
|
|
hostURL: "https://walrus.tld",
|
|
apiPathPrefix: "/apis",
|
|
},
|
|
want: newReq("https://walrus.tld/some/path"),
|
|
},
|
|
{
|
|
name: "host url already has slash suffix",
|
|
args: args{
|
|
req: newReq("https://walrus.tld/apis/some/path"),
|
|
hostURL: "https://walrus.tld/",
|
|
apiPathPrefix: "/apis",
|
|
},
|
|
want: newReq("https://walrus.tld/some/path"),
|
|
},
|
|
{
|
|
name: "api prefix already has slash prefix",
|
|
args: args{
|
|
req: newReq("https://walrus.tld/apis/some/path"),
|
|
hostURL: "https://walrus.tld",
|
|
apiPathPrefix: "apis",
|
|
},
|
|
want: newReq("https://walrus.tld/some/path"),
|
|
},
|
|
{
|
|
name: "api prefix already has slash suffix",
|
|
args: args{
|
|
req: newReq("https://walrus.tld/apis/some/path"),
|
|
hostURL: "https://walrus.tld",
|
|
apiPathPrefix: "/apis/",
|
|
},
|
|
want: newReq("https://walrus.tld/some/path"),
|
|
},
|
|
{
|
|
name: "no api path prefix",
|
|
args: args{
|
|
req: newReq("https://walrus.tld"),
|
|
},
|
|
want: newReq("https://walrus.tld"),
|
|
},
|
|
{
|
|
name: "hostURL and req URL mismatch",
|
|
args: args{
|
|
req: newReq("https://walrus.tld.some-other-url/some/path"),
|
|
hostURL: "https://walrus.tld",
|
|
apiPathPrefix: "/apis",
|
|
},
|
|
want: newReq("https://walrus.tld.some-other-url/some/path"),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
req := *tt.args.req
|
|
if got := reqWithoutPrefix(&req, tt.args.hostURL, tt.args.apiPathPrefix); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("reqWithoutPrefix() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustParse(t *testing.T, rawurl string) *url.URL {
|
|
t.Helper()
|
|
url, err := url.Parse(rawurl)
|
|
require.NoError(t, err)
|
|
return url
|
|
}
|