Switch our client over to use the new TokenCredentialRequest API.
Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
parent
10793ac11f
commit
b3327d7522
@ -75,7 +75,7 @@ func newExchangeCredentialCmd(args []string, stdout, stderr io.Writer) *exchange
|
|||||||
}
|
}
|
||||||
|
|
||||||
type envGetter func(string) (string, bool)
|
type envGetter func(string) (string, bool)
|
||||||
type tokenExchanger func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error)
|
type tokenExchanger func(ctx context.Context, namespace, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error)
|
||||||
|
|
||||||
const ErrMissingEnvVar = constable.Error("failed to get credential: environment variable not set")
|
const ErrMissingEnvVar = constable.Error("failed to get credential: environment variable not set")
|
||||||
|
|
||||||
@ -91,6 +91,11 @@ func exchangeCredential(envGetter envGetter, tokenExchanger tokenExchanger, outp
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
namespace, varExists := envGetter("PINNIPED_NAMESPACE")
|
||||||
|
if !varExists {
|
||||||
|
return envVarNotSetError("PINNIPED_NAMESPACE")
|
||||||
|
}
|
||||||
|
|
||||||
token, varExists := envGetter("PINNIPED_TOKEN")
|
token, varExists := envGetter("PINNIPED_TOKEN")
|
||||||
if !varExists {
|
if !varExists {
|
||||||
return envVarNotSetError("PINNIPED_TOKEN")
|
return envVarNotSetError("PINNIPED_TOKEN")
|
||||||
@ -106,7 +111,7 @@ func exchangeCredential(envGetter envGetter, tokenExchanger tokenExchanger, outp
|
|||||||
return envVarNotSetError("PINNIPED_K8S_API_ENDPOINT")
|
return envVarNotSetError("PINNIPED_K8S_API_ENDPOINT")
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, err := tokenExchanger(ctx, token, caBundle, apiEndpoint)
|
cred, err := tokenExchanger(ctx, namespace, token, caBundle, apiEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get credential: %w", err)
|
return fmt.Errorf("failed to get credential: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,7 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
r = require.New(t)
|
r = require.New(t)
|
||||||
buffer = new(bytes.Buffer)
|
buffer = new(bytes.Buffer)
|
||||||
fakeEnv = map[string]string{
|
fakeEnv = map[string]string{
|
||||||
|
"PINNIPED_NAMESPACE": "namespace from env",
|
||||||
"PINNIPED_TOKEN": "token from env",
|
"PINNIPED_TOKEN": "token from env",
|
||||||
"PINNIPED_CA_BUNDLE": "ca bundle from env",
|
"PINNIPED_CA_BUNDLE": "ca bundle from env",
|
||||||
"PINNIPED_K8S_API_ENDPOINT": "k8s api from env",
|
"PINNIPED_K8S_API_ENDPOINT": "k8s api from env",
|
||||||
@ -142,6 +143,12 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
when("env vars are missing", func() {
|
when("env vars are missing", func() {
|
||||||
|
it("returns an error when PINNIPED_NAMESPACE is missing", func() {
|
||||||
|
delete(fakeEnv, "PINNIPED_NAMESPACE")
|
||||||
|
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||||
|
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_NAMESPACE")
|
||||||
|
})
|
||||||
|
|
||||||
it("returns an error when PINNIPED_TOKEN is missing", func() {
|
it("returns an error when PINNIPED_TOKEN is missing", func() {
|
||||||
delete(fakeEnv, "PINNIPED_TOKEN")
|
delete(fakeEnv, "PINNIPED_TOKEN")
|
||||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||||
@ -163,7 +170,7 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
|
|
||||||
when("the token exchange fails", func() {
|
when("the token exchange fails", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
tokenExchanger = func(ctx context.Context, namespace, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||||
return nil, fmt.Errorf("some error")
|
return nil, fmt.Errorf("some error")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -176,7 +183,7 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
|
|
||||||
when("the JSON encoder fails", func() {
|
when("the JSON encoder fails", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
tokenExchanger = func(ctx context.Context, namespace, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||||
return &clientauthenticationv1beta1.ExecCredential{
|
return &clientauthenticationv1beta1.ExecCredential{
|
||||||
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
||||||
Token: "some token",
|
Token: "some token",
|
||||||
@ -193,7 +200,7 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
|
|
||||||
when("the token exchange times out", func() {
|
when("the token exchange times out", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
tokenExchanger = func(ctx context.Context, namespace, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||||
select {
|
select {
|
||||||
case <-time.After(100 * time.Millisecond):
|
case <-time.After(100 * time.Millisecond):
|
||||||
return &clientauthenticationv1beta1.ExecCredential{
|
return &clientauthenticationv1beta1.ExecCredential{
|
||||||
@ -214,11 +221,11 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
when("the token exchange succeeds", func() {
|
when("the token exchange succeeds", func() {
|
||||||
var actualToken, actualCaBundle, actualAPIEndpoint string
|
var actualNamespace, actualToken, actualCaBundle, actualAPIEndpoint string
|
||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
tokenExchanger = func(ctx context.Context, namespace, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||||
actualToken, actualCaBundle, actualAPIEndpoint = token, caBundle, apiEndpoint
|
actualNamespace, actualToken, actualCaBundle, actualAPIEndpoint = namespace, token, caBundle, apiEndpoint
|
||||||
now := metav1.NewTime(time.Date(2020, 7, 29, 1, 2, 3, 0, time.UTC))
|
now := metav1.NewTime(time.Date(2020, 7, 29, 1, 2, 3, 0, time.UTC))
|
||||||
return &clientauthenticationv1beta1.ExecCredential{
|
return &clientauthenticationv1beta1.ExecCredential{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@ -238,6 +245,7 @@ func TestExchangeCredential(t *testing.T) {
|
|||||||
it("writes the execCredential to the given writer", func() {
|
it("writes the execCredential to the given writer", func() {
|
||||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
r.Equal(fakeEnv["PINNIPED_NAMESPACE"], actualNamespace)
|
||||||
r.Equal(fakeEnv["PINNIPED_TOKEN"], actualToken)
|
r.Equal(fakeEnv["PINNIPED_TOKEN"], actualToken)
|
||||||
r.Equal(fakeEnv["PINNIPED_CA_BUNDLE"], actualCaBundle)
|
r.Equal(fakeEnv["PINNIPED_CA_BUNDLE"], actualCaBundle)
|
||||||
r.Equal(fakeEnv["PINNIPED_K8S_API_ENDPOINT"], actualAPIEndpoint)
|
r.Equal(fakeEnv["PINNIPED_K8S_API_ENDPOINT"], actualAPIEndpoint)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
|
||||||
"github.com/suzerain-io/pinniped/generated/1.19/apis/pinniped/v1alpha1"
|
"github.com/suzerain-io/pinniped/generated/1.19/apis/login/v1alpha1"
|
||||||
"github.com/suzerain-io/pinniped/generated/1.19/client/clientset/versioned"
|
"github.com/suzerain-io/pinniped/generated/1.19/client/clientset/versioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,25 +22,23 @@ import (
|
|||||||
var ErrLoginFailed = errors.New("login failed")
|
var ErrLoginFailed = errors.New("login failed")
|
||||||
|
|
||||||
// ExchangeToken exchanges an opaque token using the Pinniped CredentialRequest API, returning a client-go ExecCredential valid on the target cluster.
|
// ExchangeToken exchanges an opaque token using the Pinniped CredentialRequest API, returning a client-go ExecCredential valid on the target cluster.
|
||||||
func ExchangeToken(ctx context.Context, token string, caBundle string, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
func ExchangeToken(ctx context.Context, namespace string, token string, caBundle string, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||||
client, err := getClient(apiEndpoint, caBundle)
|
client, err := getClient(apiEndpoint, caBundle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get API client: %w", err)
|
return nil, fmt.Errorf("could not get API client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.PinnipedV1alpha1().CredentialRequests().Create(ctx, &v1alpha1.CredentialRequest{
|
resp, err := client.LoginV1alpha1().TokenCredentialRequests(namespace).Create(ctx, &v1alpha1.TokenCredentialRequest{
|
||||||
Spec: v1alpha1.CredentialRequestSpec{
|
Spec: v1alpha1.TokenCredentialRequestSpec{Token: token},
|
||||||
Type: v1alpha1.TokenCredentialType,
|
|
||||||
Token: &v1alpha1.CredentialRequestTokenCredential{
|
|
||||||
Value: token,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, metav1.CreateOptions{})
|
}, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not login: %w", err)
|
return nil, fmt.Errorf("could not login: %w", err)
|
||||||
}
|
}
|
||||||
if resp.Status.Credential == nil || resp.Status.Message != nil {
|
if resp.Status.Credential == nil || resp.Status.Message != nil {
|
||||||
return nil, fmt.Errorf("%w: %s", ErrLoginFailed, *resp.Status.Message)
|
if resp.Status.Message != nil {
|
||||||
|
return nil, fmt.Errorf("%w: %s", ErrLoginFailed, *resp.Status.Message)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%w: unknown", ErrLoginFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &clientauthenticationv1beta1.ExecCredential{
|
return &clientauthenticationv1beta1.ExecCredential{
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||||
|
|
||||||
"github.com/suzerain-io/pinniped/generated/1.19/apis/pinniped/v1alpha1"
|
"github.com/suzerain-io/pinniped/generated/1.19/apis/login/v1alpha1"
|
||||||
"github.com/suzerain-io/pinniped/internal/testutil"
|
"github.com/suzerain-io/pinniped/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("invalid configuration", func(t *testing.T) {
|
t.Run("invalid configuration", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
got, err := ExchangeToken(ctx, "", "", "")
|
got, err := ExchangeToken(ctx, "test-namespace", "", "", "")
|
||||||
require.EqualError(t, err, "could not get API client: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable")
|
require.EqualError(t, err, "could not get API client: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable")
|
||||||
require.Nil(t, got)
|
require.Nil(t, got)
|
||||||
})
|
})
|
||||||
@ -38,8 +38,8 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
_, _ = w.Write([]byte("some server error"))
|
_, _ = w.Write([]byte("some server error"))
|
||||||
})
|
})
|
||||||
|
|
||||||
got, err := ExchangeToken(ctx, "", caBundle, endpoint)
|
got, err := ExchangeToken(ctx, "test-namespace", "", caBundle, endpoint)
|
||||||
require.EqualError(t, err, `could not login: an error on the server ("some server error") has prevented the request from succeeding (post credentialrequests.pinniped.dev)`)
|
require.EqualError(t, err, `could not login: an error on the server ("some server error") has prevented the request from succeeding (post tokencredentialrequests.login.pinniped.dev)`)
|
||||||
require.Nil(t, got)
|
require.Nil(t, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -49,17 +49,32 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
errorMessage := "some login failure"
|
errorMessage := "some login failure"
|
||||||
caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("content-type", "application/json")
|
w.Header().Set("content-type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(&v1alpha1.CredentialRequest{
|
_ = json.NewEncoder(w).Encode(&v1alpha1.TokenCredentialRequest{
|
||||||
TypeMeta: metav1.TypeMeta{APIVersion: "pinniped.dev/v1alpha1", Kind: "CredentialRequest"},
|
TypeMeta: metav1.TypeMeta{APIVersion: "login.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"},
|
||||||
Status: v1alpha1.CredentialRequestStatus{Message: &errorMessage},
|
Status: v1alpha1.TokenCredentialRequestStatus{Message: &errorMessage},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
got, err := ExchangeToken(ctx, "", caBundle, endpoint)
|
got, err := ExchangeToken(ctx, "test-namespace", "", caBundle, endpoint)
|
||||||
require.EqualError(t, err, `login failed: some login failure`)
|
require.EqualError(t, err, `login failed: some login failure`)
|
||||||
require.Nil(t, got)
|
require.Nil(t, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("login failure unknown error", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Start a test server that returns without any error message but also without valid credentials
|
||||||
|
caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("content-type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(&v1alpha1.TokenCredentialRequest{
|
||||||
|
TypeMeta: metav1.TypeMeta{APIVersion: "login.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
got, err := ExchangeToken(ctx, "test-namespace", "", caBundle, endpoint)
|
||||||
|
require.EqualError(t, err, `login failed: unknown`)
|
||||||
|
require.Nil(t, got)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
expires := metav1.NewTime(time.Now().Truncate(time.Second))
|
expires := metav1.NewTime(time.Now().Truncate(time.Second))
|
||||||
@ -67,21 +82,20 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
// Start a test server that returns successfully and asserts various properties of the request.
|
// Start a test server that returns successfully and asserts various properties of the request.
|
||||||
caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
require.Equal(t, http.MethodPost, r.Method)
|
require.Equal(t, http.MethodPost, r.Method)
|
||||||
require.Equal(t, "/apis/pinniped.dev/v1alpha1/credentialrequests", r.URL.Path)
|
require.Equal(t, "/apis/login.pinniped.dev/v1alpha1/namespaces/test-namespace/tokencredentialrequests", r.URL.Path)
|
||||||
require.Equal(t, "application/json", r.Header.Get("content-type"))
|
require.Equal(t, "application/json", r.Header.Get("content-type"))
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.JSONEq(t,
|
require.JSONEq(t,
|
||||||
`{
|
`{
|
||||||
"kind": "CredentialRequest",
|
"kind": "TokenCredentialRequest",
|
||||||
"apiVersion": "pinniped.dev/v1alpha1",
|
"apiVersion": "login.pinniped.dev/v1alpha1",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"creationTimestamp": null
|
"creationTimestamp": null
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"type": "token",
|
"token": "test-token"
|
||||||
"token": {}
|
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
}`,
|
}`,
|
||||||
@ -89,10 +103,10 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
w.Header().Set("content-type", "application/json")
|
w.Header().Set("content-type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(&v1alpha1.CredentialRequest{
|
_ = json.NewEncoder(w).Encode(&v1alpha1.TokenCredentialRequest{
|
||||||
TypeMeta: metav1.TypeMeta{APIVersion: "pinniped.dev/v1alpha1", Kind: "CredentialRequest"},
|
TypeMeta: metav1.TypeMeta{APIVersion: "login.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"},
|
||||||
Status: v1alpha1.CredentialRequestStatus{
|
Status: v1alpha1.TokenCredentialRequestStatus{
|
||||||
Credential: &v1alpha1.CredentialRequestCredential{
|
Credential: &v1alpha1.ClusterCredential{
|
||||||
ExpirationTimestamp: expires,
|
ExpirationTimestamp: expires,
|
||||||
ClientCertificateData: "test-certificate",
|
ClientCertificateData: "test-certificate",
|
||||||
ClientKeyData: "test-key",
|
ClientKeyData: "test-key",
|
||||||
@ -101,7 +115,7 @@ func TestExchangeToken(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
got, err := ExchangeToken(ctx, "", caBundle, endpoint)
|
got, err := ExchangeToken(ctx, "test-namespace", "test-token", caBundle, endpoint)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, &clientauthenticationv1beta1.ExecCredential{
|
require.Equal(t, &clientauthenticationv1beta1.ExecCredential{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
@ -56,6 +56,7 @@ func TestClient(t *testing.T) {
|
|||||||
library.SkipUnlessIntegration(t)
|
library.SkipUnlessIntegration(t)
|
||||||
library.SkipUnlessClusterHasCapability(t, library.ClusterSigningKeyIsAvailable)
|
library.SkipUnlessClusterHasCapability(t, library.ClusterSigningKeyIsAvailable)
|
||||||
token := library.GetEnv(t, "PINNIPED_TEST_USER_TOKEN")
|
token := library.GetEnv(t, "PINNIPED_TEST_USER_TOKEN")
|
||||||
|
namespace := library.GetEnv(t, "PINNIPED_NAMESPACE")
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -67,7 +68,7 @@ func TestClient(t *testing.T) {
|
|||||||
|
|
||||||
// Using the CA bundle and host from the current (admin) kubeconfig, do the token exchange.
|
// Using the CA bundle and host from the current (admin) kubeconfig, do the token exchange.
|
||||||
clientConfig := library.NewClientConfig(t)
|
clientConfig := library.NewClientConfig(t)
|
||||||
resp, err := client.ExchangeToken(ctx, token, string(clientConfig.CAData), clientConfig.Host)
|
resp, err := client.ExchangeToken(ctx, namespace, token, string(clientConfig.CAData), clientConfig.Host)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, resp.Status.ExpirationTimestamp)
|
require.NotNil(t, resp.Status.ExpirationTimestamp)
|
||||||
require.InDelta(t, time.Until(resp.Status.ExpirationTimestamp.Time), 1*time.Hour, float64(3*time.Minute))
|
require.InDelta(t, time.Until(resp.Status.ExpirationTimestamp.Time), 1*time.Hour, float64(3*time.Minute))
|
||||||
|
Loading…
Reference in New Issue
Block a user