657488fe90
Previously, our controllers would automatically create a CredentialIssuer with a singleton name. The helpers we had for this also used "raw" client access and did not take advantage of the informer cache pattern. With this change, the CredentialIssuer is always created at install time in the ytt YAML. The controllers now only update the existing CredentialIssuer status, and they do so using the informer cache as much as possible. This change is targeted at only the kubecertagent controller to start. The impersonatorconfig controller will be updated in a following PR along with other changes. Signed-off-by: Matt Moyer <moyerm@vmware.com>
108 lines
4.6 KiB
Go
108 lines
4.6 KiB
Go
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
|
|
|
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
|
"go.pinniped.dev/test/library"
|
|
)
|
|
|
|
func TestCredentialIssuer(t *testing.T) {
|
|
env := library.IntegrationEnv(t)
|
|
config := library.NewClientConfig(t)
|
|
client := library.NewConciergeClientset(t)
|
|
aggregatedClientset := library.NewAggregatedClientset(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
defer cancel()
|
|
|
|
t.Run("test successful CredentialIssuer", func(t *testing.T) {
|
|
actualConfigList, err := client.
|
|
ConfigV1alpha1().
|
|
CredentialIssuers().
|
|
List(ctx, metav1.ListOptions{})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, actualConfigList.Items, 1)
|
|
|
|
actualConfig := actualConfigList.Items[0]
|
|
actualStatusKubeConfigInfo := actualConfigList.Items[0].Status.KubeConfigInfo
|
|
|
|
for k, v := range env.ConciergeCustomLabels {
|
|
require.Equalf(t, v, actualConfig.Labels[k], "expected ci to have label `%s: %s`", k, v)
|
|
}
|
|
require.Equal(t, env.ConciergeAppName, actualConfig.Labels["app"])
|
|
|
|
apiService, err := aggregatedClientset.ApiregistrationV1().APIServices().Get(ctx, "v1alpha1.login.concierge."+env.APIGroupSuffix, metav1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
// work around stupid behavior of WithoutVersionDecoder.Decode
|
|
apiService.APIVersion, apiService.Kind = apiregistrationv1.SchemeGroupVersion.WithKind("APIService").ToAPIVersionAndKind()
|
|
|
|
// Verify the cluster strategy status based on what's expected of the test cluster's ability to share signing keys.
|
|
actualStatusStrategies := actualConfigList.Items[0].Status.Strategies
|
|
|
|
// There should be two. One of type KubeClusterSigningCertificate and one of type ImpersonationProxy.
|
|
require.Len(t, actualStatusStrategies, 2)
|
|
|
|
// The details of the ImpersonationProxy type is tested by a different integration test for the impersonator.
|
|
// Grab the KubeClusterSigningCertificate result so we can check it in detail below.
|
|
var actualStatusStrategy configv1alpha1.CredentialIssuerStrategy
|
|
for _, s := range actualStatusStrategies {
|
|
if s.Type == configv1alpha1.KubeClusterSigningCertificateStrategyType {
|
|
actualStatusStrategy = s
|
|
break
|
|
}
|
|
}
|
|
require.NotNil(t, actualStatusStrategy)
|
|
|
|
if env.HasCapability(library.ClusterSigningKeyIsAvailable) {
|
|
require.Equal(t, configv1alpha1.SuccessStrategyStatus, actualStatusStrategy.Status)
|
|
require.Equal(t, configv1alpha1.FetchedKeyStrategyReason, actualStatusStrategy.Reason)
|
|
require.Equal(t, "key was fetched successfully", actualStatusStrategy.Message)
|
|
require.NotNil(t, actualStatusStrategy.Frontend)
|
|
require.Equal(t, configv1alpha1.TokenCredentialRequestAPIFrontendType, actualStatusStrategy.Frontend.Type)
|
|
expectedTokenRequestAPIInfo := configv1alpha1.TokenCredentialRequestAPIInfo{
|
|
Server: config.Host,
|
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString(config.TLSClientConfig.CAData),
|
|
}
|
|
require.Equal(t, &expectedTokenRequestAPIInfo, actualStatusStrategy.Frontend.TokenCredentialRequestAPIInfo)
|
|
|
|
// Verify the published kube config info.
|
|
require.Equal(
|
|
t,
|
|
&configv1alpha1.CredentialIssuerKubeConfigInfo{
|
|
Server: expectedTokenRequestAPIInfo.Server,
|
|
CertificateAuthorityData: expectedTokenRequestAPIInfo.CertificateAuthorityData,
|
|
},
|
|
actualStatusKubeConfigInfo,
|
|
)
|
|
|
|
// Only validate LastUpdateTime when cluster signing key is available. The last update time
|
|
// will be set every time our controllers resync, but only when there exists controller
|
|
// manager pods (all other pods will be filtered out), hence why this assertion is in this
|
|
// if branch.
|
|
//
|
|
// This behavior is up for debate. We should eventually discuss the contract for this
|
|
// LastUpdateTime field and ensure that the implementation is the same for when the cluster
|
|
// signing key is available and not available.
|
|
require.WithinDuration(t, time.Now(), actualStatusStrategy.LastUpdateTime.Local(), 10*time.Minute)
|
|
} else {
|
|
require.Equal(t, configv1alpha1.ErrorStrategyStatus, actualStatusStrategy.Status)
|
|
require.Equal(t, configv1alpha1.CouldNotFetchKeyStrategyReason, actualStatusStrategy.Reason)
|
|
require.Contains(t, actualStatusStrategy.Message, "could not find a healthy kube-controller-manager pod (0 candidates)")
|
|
require.Nil(t, actualStatusKubeConfigInfo)
|
|
}
|
|
})
|
|
}
|