CLI get-kubeconfig
command reads kubeconfig and CredentialIssuerConfig
This commit is contained in:
parent
872330bee9
commit
4379d2772c
@ -6,20 +6,35 @@ SPDX-License-Identifier: Apache-2.0
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
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"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||||
|
|
||||||
|
"github.com/suzerain-io/pinniped/generated/1.19/apis/crdpinniped/v1alpha1"
|
||||||
|
pinnipedclientset "github.com/suzerain-io/pinniped/generated/1.19/client/clientset/versioned"
|
||||||
|
"github.com/suzerain-io/pinniped/internal/controller/issuerconfig"
|
||||||
"github.com/suzerain-io/pinniped/internal/here"
|
"github.com/suzerain-io/pinniped/internal/here"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
getKubeConfigCmdTokenFlagName = "token"
|
getKubeConfigCmdTokenFlagName = "token"
|
||||||
|
getKubeConfigCmdKubeconfigFlagName = "kubeconfig"
|
||||||
|
getKubeConfigCmdKubeconfigContextFlagName = "kubeconfig-context"
|
||||||
|
getKubeConfigCmdPinnipedNamespaceFlagName = "pinniped-namespace"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint: gochecknoinits
|
//nolint: gochecknoinits
|
||||||
@ -32,8 +47,13 @@ func init() {
|
|||||||
Long: here.Doc(`
|
Long: here.Doc(`
|
||||||
Print a kubeconfig for authenticating into a cluster via Pinniped.
|
Print a kubeconfig for authenticating into a cluster via Pinniped.
|
||||||
|
|
||||||
Assumes that you have admin-like access to the cluster using your
|
Requires admin-like access to the cluster using the current
|
||||||
current kubeconfig context, in order to access Pinniped's metadata.
|
kubeconfig context in order to access Pinniped's metadata.
|
||||||
|
The current kubeconfig is found similar to how kubectl finds it:
|
||||||
|
using the value of the --kubeconfig option, or if that is not
|
||||||
|
specified then from the value of the KUBECONFIG environment
|
||||||
|
variable, or if that is not specified then it defaults to
|
||||||
|
.kube/config in your home directory.
|
||||||
|
|
||||||
Prints a kubeconfig which is suitable to access the cluster using
|
Prints a kubeconfig which is suitable to access the cluster using
|
||||||
Pinniped as the authentication mechanism. This kubeconfig output
|
Pinniped as the authentication mechanism. This kubeconfig output
|
||||||
@ -47,20 +67,54 @@ func init() {
|
|||||||
|
|
||||||
getKubeConfigCmd.Flags().StringP(
|
getKubeConfigCmd.Flags().StringP(
|
||||||
getKubeConfigCmdTokenFlagName,
|
getKubeConfigCmdTokenFlagName,
|
||||||
"t",
|
|
||||||
"",
|
"",
|
||||||
"The credential to include in the resulting kubeconfig output (Required)",
|
"",
|
||||||
|
"Credential to include in the resulting kubeconfig output (Required)",
|
||||||
)
|
)
|
||||||
err := getKubeConfigCmd.MarkFlagRequired(getKubeConfigCmdTokenFlagName)
|
err := getKubeConfigCmd.MarkFlagRequired(getKubeConfigCmdTokenFlagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getKubeConfigCmd.Flags().StringP(
|
||||||
|
getKubeConfigCmdKubeconfigFlagName,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Path to the kubeconfig file",
|
||||||
|
)
|
||||||
|
|
||||||
|
getKubeConfigCmd.Flags().StringP(
|
||||||
|
getKubeConfigCmdKubeconfigContextFlagName,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Kubeconfig context override",
|
||||||
|
)
|
||||||
|
|
||||||
|
getKubeConfigCmd.Flags().StringP(
|
||||||
|
getKubeConfigCmdPinnipedNamespaceFlagName,
|
||||||
|
"",
|
||||||
|
"pinniped",
|
||||||
|
"Namespace in which Pinniped was installed",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGetKubeConfig(cmd *cobra.Command, _ []string) {
|
func runGetKubeConfig(cmd *cobra.Command, _ []string) {
|
||||||
token := cmd.Flag(getKubeConfigCmdTokenFlagName).Value.String()
|
token := cmd.Flag(getKubeConfigCmdTokenFlagName).Value.String()
|
||||||
|
kubeconfigPathOverride := cmd.Flag(getKubeConfigCmdKubeconfigFlagName).Value.String()
|
||||||
|
currentContextOverride := cmd.Flag(getKubeConfigCmdKubeconfigContextFlagName).Value.String()
|
||||||
|
pinnipedInstallationNamespace := cmd.Flag(getKubeConfigCmdPinnipedNamespaceFlagName).Value.String()
|
||||||
|
|
||||||
err := getKubeConfig(os.Stdout, token)
|
err := getKubeConfig(
|
||||||
|
os.Stdout,
|
||||||
|
os.Stderr,
|
||||||
|
token,
|
||||||
|
kubeconfigPathOverride,
|
||||||
|
currentContextOverride,
|
||||||
|
pinnipedInstallationNamespace,
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
return pinnipedclientset.NewForConfig(restConfig)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
|
_, _ = fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
|
||||||
@ -68,45 +122,157 @@ func runGetKubeConfig(cmd *cobra.Command, _ []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKubeConfig(outputWriter io.Writer, token string) error {
|
func getKubeConfig(
|
||||||
clusterName := "pinniped-cluster"
|
outputWriter io.Writer,
|
||||||
userName := "pinniped-user"
|
warningsWriter io.Writer,
|
||||||
|
token string,
|
||||||
|
kubeconfigPathOverride string,
|
||||||
|
currentContextNameOverride string,
|
||||||
|
pinnipedInstallationNamespace string,
|
||||||
|
kubeClientCreator func(restConfig *rest.Config) (pinnipedclientset.Interface, error),
|
||||||
|
) error {
|
||||||
|
if token == "" {
|
||||||
|
return fmt.Errorf("--" + getKubeConfigCmdTokenFlagName + " flag value cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
fullPathToSelf, err := os.Executable()
|
fullPathToSelf, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not find path to self: %w", err)
|
return fmt.Errorf("could not find path to self: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := v1.Config{
|
clientConfig := newClientConfig(kubeconfigPathOverride, currentContextNameOverride)
|
||||||
|
|
||||||
|
currentKubeConfig, err := clientConfig.RawConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialIssuerConfig, err := fetchPinnipedCredentialIssuerConfig(clientConfig, kubeClientCreator, pinnipedInstallationNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v1Cluster, err := copyCurrentClusterFromExistingKubeConfig(err, currentKubeConfig, currentContextNameOverride)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle when credentialIssuerConfig has no Status or no KubeConfigInfo
|
||||||
|
|
||||||
|
err = issueWarningForNonMatchingServerOrCA(v1Cluster, credentialIssuerConfig, warningsWriter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := newPinnipedKubeconfig(v1Cluster, fullPathToSelf, token)
|
||||||
|
|
||||||
|
err = writeConfigAsYAML(outputWriter, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func issueWarningForNonMatchingServerOrCA(v1Cluster v1.Cluster, credentialIssuerConfig *v1alpha1.CredentialIssuerConfig, warningsWriter io.Writer) error {
|
||||||
|
credentialIssuerConfigCA, err := base64.StdEncoding.DecodeString(credentialIssuerConfig.Status.KubeConfigInfo.CertificateAuthorityData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if v1Cluster.Server != credentialIssuerConfig.Status.KubeConfigInfo.Server ||
|
||||||
|
!bytes.Equal(v1Cluster.CertificateAuthorityData, credentialIssuerConfigCA) {
|
||||||
|
_, err := warningsWriter.Write([]byte("WARNING: Server and certificate authority did not match between local kubeconfig and Pinniped's CredentialIssuerConfig on the cluster. Using local kubeconfig values.\n"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("output write error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchPinnipedCredentialIssuerConfig(clientConfig clientcmd.ClientConfig, kubeClientCreator func(restConfig *rest.Config) (pinnipedclientset.Interface, error), pinnipedInstallationNamespace string) (*v1alpha1.CredentialIssuerConfig, error) {
|
||||||
|
restConfig, err := clientConfig.ClientConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientset, err := kubeClientCreator(restConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
||||||
|
defer cancelFunc()
|
||||||
|
|
||||||
|
credentialIssuerConfig, err := clientset.CrdV1alpha1().CredentialIssuerConfigs(pinnipedInstallationNamespace).Get(ctx, issuerconfig.ConfigName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if apierrors.IsNotFound(err) {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
`CredentialIssuerConfig "%s" was not found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
|
||||||
|
issuerconfig.ConfigName,
|
||||||
|
pinnipedInstallationNamespace,
|
||||||
|
pinnipedInstallationNamespace,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentialIssuerConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientConfig(kubeconfigPathOverride string, currentContextName string) clientcmd.ClientConfig {
|
||||||
|
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||||
|
loadingRules.ExplicitPath = kubeconfigPathOverride
|
||||||
|
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{
|
||||||
|
CurrentContext: currentContextName,
|
||||||
|
})
|
||||||
|
return clientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeConfigAsYAML(outputWriter io.Writer, config v1.Config) error {
|
||||||
|
output, err := yaml.Marshal(&config)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("YAML serialization error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = outputWriter.Write(output)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("output write error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyCurrentClusterFromExistingKubeConfig(err error, currentKubeConfig clientcmdapi.Config, currentContextNameOverride string) (v1.Cluster, error) {
|
||||||
|
v1Cluster := v1.Cluster{}
|
||||||
|
|
||||||
|
contextName := currentKubeConfig.CurrentContext
|
||||||
|
if currentContextNameOverride != "" {
|
||||||
|
contextName = currentContextNameOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
err = v1.Convert_api_Cluster_To_v1_Cluster(
|
||||||
|
currentKubeConfig.Clusters[currentKubeConfig.Contexts[contextName].Cluster],
|
||||||
|
&v1Cluster,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return v1.Cluster{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v1Cluster, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPinnipedKubeconfig(v1Cluster v1.Cluster, fullPathToSelf string, token string) v1.Config {
|
||||||
|
clusterName := "pinniped-cluster"
|
||||||
|
userName := "pinniped-user"
|
||||||
|
|
||||||
|
return v1.Config{
|
||||||
Kind: "Config",
|
Kind: "Config",
|
||||||
APIVersion: v1.SchemeGroupVersion.Version,
|
APIVersion: v1.SchemeGroupVersion.Version,
|
||||||
Preferences: v1.Preferences{
|
Preferences: v1.Preferences{},
|
||||||
Colors: false, // TODO what does this setting do?
|
|
||||||
Extensions: nil,
|
|
||||||
},
|
|
||||||
Clusters: []v1.NamedCluster{
|
Clusters: []v1.NamedCluster{
|
||||||
{
|
{
|
||||||
Name: clusterName,
|
Name: clusterName,
|
||||||
Cluster: v1.Cluster{}, // TODO fill in server and cert authority and such
|
Cluster: v1Cluster,
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthInfos: []v1.NamedAuthInfo{
|
|
||||||
{
|
|
||||||
Name: userName,
|
|
||||||
AuthInfo: v1.AuthInfo{
|
|
||||||
Exec: &v1.ExecConfig{
|
|
||||||
Command: fullPathToSelf,
|
|
||||||
Args: []string{"exchange-credential"},
|
|
||||||
Env: []v1.ExecEnvVar{
|
|
||||||
{Name: "PINNIPED_K8S_API_ENDPOINT", Value: ""}, // TODO fill in value
|
|
||||||
{Name: "PINNIPED_CA_BUNDLE", Value: ""}, // TODO fill in value
|
|
||||||
{Name: "PINNIPED_TOKEN", Value: token},
|
|
||||||
},
|
|
||||||
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
|
|
||||||
InstallHint: "The Pinniped CLI is required to authenticate to the current cluster.\n" +
|
|
||||||
"For more information, please visit https://pinniped.dev",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Contexts: []v1.NamedContext{
|
Contexts: []v1.NamedContext{
|
||||||
@ -118,19 +284,25 @@ func getKubeConfig(outputWriter io.Writer, token string) error {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
AuthInfos: []v1.NamedAuthInfo{
|
||||||
|
{
|
||||||
|
Name: userName,
|
||||||
|
AuthInfo: v1.AuthInfo{
|
||||||
|
Exec: &v1.ExecConfig{
|
||||||
|
Command: fullPathToSelf,
|
||||||
|
Args: []string{"exchange-credential"},
|
||||||
|
Env: []v1.ExecEnvVar{
|
||||||
|
{Name: "PINNIPED_K8S_API_ENDPOINT", Value: v1Cluster.Server},
|
||||||
|
{Name: "PINNIPED_CA_BUNDLE", Value: string(v1Cluster.CertificateAuthorityData)},
|
||||||
|
{Name: "PINNIPED_TOKEN", Value: token},
|
||||||
|
},
|
||||||
|
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
|
||||||
|
InstallHint: "The Pinniped CLI is required to authenticate to the current cluster.\n" +
|
||||||
|
"For more information, please visit https://pinniped.dev",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
CurrentContext: clusterName,
|
CurrentContext: clusterName,
|
||||||
Extensions: nil,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := yaml.Marshal(&config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("YAML serialization error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = fmt.Fprint(outputWriter, string(output))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("output write error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -7,40 +7,33 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/sclevine/spec"
|
"github.com/sclevine/spec"
|
||||||
"github.com/sclevine/spec/report"
|
"github.com/sclevine/spec/report"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
|
||||||
|
crdpinnipedv1alpha1 "github.com/suzerain-io/pinniped/generated/1.19/apis/crdpinniped/v1alpha1"
|
||||||
|
pinnipedclientset "github.com/suzerain-io/pinniped/generated/1.19/client/clientset/versioned"
|
||||||
|
pinnipedfake "github.com/suzerain-io/pinniped/generated/1.19/client/clientset/versioned/fake"
|
||||||
"github.com/suzerain-io/pinniped/internal/here"
|
"github.com/suzerain-io/pinniped/internal/here"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetKubeConfig(t *testing.T) {
|
// TODO write a test for the help message and command line flags similar to server_test.go
|
||||||
spec.Run(t, "cmd.getKubeConfig", func(t *testing.T, when spec.G, it spec.S) {
|
|
||||||
var r *require.Assertions
|
|
||||||
var buffer *bytes.Buffer
|
|
||||||
var fullPathToSelf string
|
|
||||||
|
|
||||||
it.Before(func() {
|
func expectedKubeconfigYAML(clusterCAData, clusterServer, command, token, pinnipedEndpoint, pinnipedCABundle string) string {
|
||||||
r = require.New(t)
|
return here.Docf(`
|
||||||
buffer = new(bytes.Buffer)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
fullPathToSelf, err = os.Executable()
|
|
||||||
r.NoError(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("writes the kubeconfig to the given writer", func() {
|
|
||||||
err := getKubeConfig(buffer, "some-token")
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
expectedYAML := here.Docf(`
|
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
clusters:
|
clusters:
|
||||||
- cluster:
|
- cluster:
|
||||||
server: ""
|
certificate-authority-data: %s
|
||||||
|
server: %s
|
||||||
name: pinniped-cluster
|
name: pinniped-cluster
|
||||||
contexts:
|
contexts:
|
||||||
- context:
|
- context:
|
||||||
@ -60,17 +53,376 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
command: %s
|
command: %s
|
||||||
env:
|
env:
|
||||||
- name: PINNIPED_K8S_API_ENDPOINT
|
- name: PINNIPED_K8S_API_ENDPOINT
|
||||||
value: ""
|
value: %s
|
||||||
- name: PINNIPED_CA_BUNDLE
|
- name: PINNIPED_CA_BUNDLE
|
||||||
value: ""
|
value: %s
|
||||||
- name: PINNIPED_TOKEN
|
- name: PINNIPED_TOKEN
|
||||||
value: some-token
|
value: %s
|
||||||
installHint: |-
|
installHint: |-
|
||||||
The Pinniped CLI is required to authenticate to the current cluster.
|
The Pinniped CLI is required to authenticate to the current cluster.
|
||||||
For more information, please visit https://pinniped.dev
|
For more information, please visit https://pinniped.dev
|
||||||
`, fullPathToSelf)
|
`, clusterCAData, clusterServer, command, pinnipedEndpoint, pinnipedCABundle, token)
|
||||||
|
}
|
||||||
|
|
||||||
r.Equal(expectedYAML, buffer.String())
|
func newCredentialIssuerConfig(server, certificateAuthorityData string) *crdpinnipedv1alpha1.CredentialIssuerConfig {
|
||||||
|
return &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "CredentialIssuerConfig",
|
||||||
|
APIVersion: crdpinnipedv1alpha1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pinniped-config",
|
||||||
|
Namespace: "some-namespace",
|
||||||
|
},
|
||||||
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
||||||
|
KubeConfigInfo: &crdpinnipedv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
||||||
|
Server: server,
|
||||||
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(certificateAuthorityData)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetKubeConfig(t *testing.T) {
|
||||||
|
spec.Run(t, "cmd.getKubeConfig", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
|
var r *require.Assertions
|
||||||
|
var outputBuffer *bytes.Buffer
|
||||||
|
var warningsBuffer *bytes.Buffer
|
||||||
|
var fullPathToSelf string
|
||||||
|
var pinnipedClient *pinnipedfake.Clientset
|
||||||
|
|
||||||
|
it.Before(func() {
|
||||||
|
r = require.New(t)
|
||||||
|
|
||||||
|
outputBuffer = new(bytes.Buffer)
|
||||||
|
warningsBuffer = new(bytes.Buffer)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
fullPathToSelf, err = os.Executable()
|
||||||
|
r.NoError(err)
|
||||||
|
|
||||||
|
pinnipedClient = pinnipedfake.NewSimpleClientset()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
when("the CredentialIssuerConfig is found on the cluster with a configuration that matches the existing kubeconfig", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
|
newCredentialIssuerConfig("https://fake-server-url-value", "fake-certificate-authority-data-value"),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("writes the kubeconfig to the given writer", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.NoError(err)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Equal(expectedKubeconfigYAML(
|
||||||
|
base64.StdEncoding.EncodeToString([]byte("fake-certificate-authority-data-value")),
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
fullPathToSelf,
|
||||||
|
"some-token",
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
), outputBuffer.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the currentContextOverride is used to specify a context other than the default context", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
// update the Server and CertificateAuthorityData to make them match the other kubeconfig context
|
||||||
|
r.NoError(pinnipedClient.Tracker().Update(
|
||||||
|
schema.GroupVersionResource{
|
||||||
|
Group: crdpinnipedv1alpha1.GroupName,
|
||||||
|
Version: crdpinnipedv1alpha1.SchemeGroupVersion.Version,
|
||||||
|
Resource: "credentialissuerconfigs",
|
||||||
|
},
|
||||||
|
newCredentialIssuerConfig(
|
||||||
|
"https://some-other-fake-server-url-value",
|
||||||
|
"some-other-fake-certificate-authority-data-value",
|
||||||
|
),
|
||||||
|
"some-namespace",
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
when("that context exists", func() {
|
||||||
|
it("writes the kubeconfig to the given writer using the specified context", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"some-other-context",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://some-other-fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("some-other-fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.NoError(err)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Equal(expectedKubeconfigYAML(
|
||||||
|
base64.StdEncoding.EncodeToString([]byte("some-other-fake-certificate-authority-data-value")),
|
||||||
|
"https://some-other-fake-server-url-value",
|
||||||
|
fullPathToSelf,
|
||||||
|
"some-token",
|
||||||
|
"https://some-other-fake-server-url-value",
|
||||||
|
"some-other-fake-certificate-authority-data-value",
|
||||||
|
), outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("that context does not exist the in the current kubeconfig", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"this-context-name-does-not-exist-in-kubeconfig.yaml",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
|
)
|
||||||
|
r.EqualError(err, `context "this-context-name-does-not-exist-in-kubeconfig.yaml" does not exist`)
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Empty(outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the token passed in is empty", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
|
)
|
||||||
|
r.EqualError(err, "--token flag value cannot be empty")
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Empty(outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the kubeconfig path passed refers to a file that does not exist", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/this-file-does-not-exist.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
|
)
|
||||||
|
r.EqualError(err, "stat ./testdata/this-file-does-not-exist.yaml: no such file or directory")
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Empty(outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the kubeconfig path parameter is empty", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
// Note that this is technically polluting other parallel tests in this file, but other tests
|
||||||
|
// are always specifying the kubeconfigPathOverride parameter, so they're not actually looking
|
||||||
|
// at the value of this environment variable.
|
||||||
|
r.NoError(os.Setenv("KUBECONFIG", "./testdata/kubeconfig.yaml"))
|
||||||
|
})
|
||||||
|
|
||||||
|
it.After(func() {
|
||||||
|
r.NoError(os.Unsetenv("KUBECONFIG"))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("falls back to using the KUBECONFIG env var to find the kubeconfig file", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.NoError(err)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Equal(expectedKubeconfigYAML(
|
||||||
|
base64.StdEncoding.EncodeToString([]byte("fake-certificate-authority-data-value")),
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
fullPathToSelf,
|
||||||
|
"some-token",
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
), outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the wrong pinniped namespace is passed in", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"this-is-the-wrong-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.EqualError(err, `CredentialIssuerConfig "pinniped-config" was not found in namespace "this-is-the-wrong-namespace". Is Pinniped installed on this cluster in namespace "this-is-the-wrong-namespace"?`)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the CredentialIssuerConfig is found on the cluster with a configuration that does not match the existing kubeconfig", func() {
|
||||||
|
when("the Server doesn't match", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
|
newCredentialIssuerConfig("non-matching-pinniped-server-url", "fake-certificate-authority-data-value"),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("writes the kubeconfig to the given writer using the values found in the local kubeconfig and issues a warning", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.NoError(err)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
|
||||||
|
r.Equal(
|
||||||
|
"WARNING: Server and certificate authority did not match between local kubeconfig and Pinniped's CredentialIssuerConfig on the cluster. Using local kubeconfig values.\n",
|
||||||
|
warningsBuffer.String(),
|
||||||
|
)
|
||||||
|
r.Equal(expectedKubeconfigYAML(
|
||||||
|
base64.StdEncoding.EncodeToString([]byte("fake-certificate-authority-data-value")),
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
fullPathToSelf,
|
||||||
|
"some-token",
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
), outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the CA doesn't match", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
|
newCredentialIssuerConfig("https://fake-server-url-value", "non-matching-certificate-authority-data-value"),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("writes the kubeconfig to the given writer using the values found in the local kubeconfig and issues a warning", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.NoError(err)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
|
||||||
|
r.Equal(
|
||||||
|
"WARNING: Server and certificate authority did not match between local kubeconfig and Pinniped's CredentialIssuerConfig on the cluster. Using local kubeconfig values.\n",
|
||||||
|
warningsBuffer.String(),
|
||||||
|
)
|
||||||
|
r.Equal(expectedKubeconfigYAML(
|
||||||
|
base64.StdEncoding.EncodeToString([]byte("fake-certificate-authority-data-value")),
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
fullPathToSelf,
|
||||||
|
"some-token",
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
), outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("the CredentialIssuerConfig does not exist on the cluster", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
r.EqualError(err, `CredentialIssuerConfig "pinniped-config" was not found in namespace "some-namespace". Is Pinniped installed on this cluster in namespace "some-namespace"?`)
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Empty(outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("there is an error while getting the CredentialIssuerConfig from the cluster", func() {
|
||||||
|
it("returns an error", func() {
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
"some-namespace",
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
return nil, fmt.Errorf("some error getting CredentialIssuerConfig")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.EqualError(err, "some error getting CredentialIssuerConfig")
|
||||||
|
r.Empty(warningsBuffer.String())
|
||||||
|
r.Empty(outputBuffer.String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||||
}
|
}
|
||||||
|
31
cmd/pinniped/cmd/testdata/kubeconfig.yaml
vendored
Normal file
31
cmd/pinniped/cmd/testdata/kubeconfig.yaml
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ== # fake-certificate-authority-data-value
|
||||||
|
server: https://fake-server-url-value
|
||||||
|
name: kind-kind
|
||||||
|
- cluster:
|
||||||
|
certificate-authority-data: c29tZS1vdGhlci1mYWtlLWNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhLXZhbHVl # some-other-fake-certificate-authority-data-value
|
||||||
|
server: https://some-other-fake-server-url-value
|
||||||
|
name: some-other-cluster
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: kind-kind
|
||||||
|
user: kind-kind
|
||||||
|
name: kind-kind
|
||||||
|
- context:
|
||||||
|
cluster: some-other-cluster
|
||||||
|
user: some-other-user
|
||||||
|
name: some-other-context
|
||||||
|
current-context: kind-kind
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users:
|
||||||
|
- name: kind-kind
|
||||||
|
user:
|
||||||
|
client-certificate-data: ZmFrZS1jbGllbnQtY2VydGlmaWNhdGUtZGF0YS12YWx1ZQ== # fake-client-certificate-data-value
|
||||||
|
client-key-data: ZmFrZS1jbGllbnQta2V5LWRhdGEtdmFsdWU= # fake-client-key-data-value
|
||||||
|
- name: some-other-user
|
||||||
|
user:
|
||||||
|
client-certificate-data: c29tZS1vdGhlci1mYWtlLWNsaWVudC1jZXJ0aWZpY2F0ZS1kYXRhLXZhbHVl # some-other-fake-client-certificate-data-value
|
||||||
|
client-key-data: c29tZS1vdGhlci1mYWtlLWNsaWVudC1rZXktZGF0YS12YWx1ZQ== # some-other-fake-client-key-data-value
|
@ -28,7 +28,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
|||||||
existingCredentialIssuerConfig, err := pinnipedClient.
|
existingCredentialIssuerConfig, err := pinnipedClient.
|
||||||
CrdV1alpha1().
|
CrdV1alpha1().
|
||||||
CredentialIssuerConfigs(credentialIssuerConfigNamespace).
|
CredentialIssuerConfigs(credentialIssuerConfigNamespace).
|
||||||
Get(ctx, configName, metav1.GetOptions{})
|
Get(ctx, ConfigName, metav1.GetOptions{})
|
||||||
|
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
@ -39,7 +39,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
|||||||
ctx,
|
ctx,
|
||||||
existingCredentialIssuerConfig,
|
existingCredentialIssuerConfig,
|
||||||
notFound,
|
notFound,
|
||||||
configName,
|
ConfigName,
|
||||||
credentialIssuerConfigNamespace,
|
credentialIssuerConfigNamespace,
|
||||||
pinnipedClient,
|
pinnipedClient,
|
||||||
applyUpdatesToCredentialIssuerConfigFunc)
|
applyUpdatesToCredentialIssuerConfigFunc)
|
||||||
|
@ -24,10 +24,10 @@ import (
|
|||||||
const (
|
const (
|
||||||
ClusterInfoNamespace = "kube-public"
|
ClusterInfoNamespace = "kube-public"
|
||||||
|
|
||||||
|
ConfigName = "pinniped-config"
|
||||||
|
|
||||||
clusterInfoName = "cluster-info"
|
clusterInfoName = "cluster-info"
|
||||||
clusterInfoConfigMapKey = "kubeconfig"
|
clusterInfoConfigMapKey = "kubeconfig"
|
||||||
|
|
||||||
configName = "pinniped-config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type publisherController struct {
|
type publisherController struct {
|
||||||
@ -64,7 +64,7 @@ func NewPublisherController(
|
|||||||
),
|
),
|
||||||
withInformer(
|
withInformer(
|
||||||
credentialIssuerConfigInformer,
|
credentialIssuerConfigInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(configName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(ConfigName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -114,7 +114,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
|||||||
existingCredentialIssuerConfigFromInformerCache, err := c.credentialIssuerConfigInformer.
|
existingCredentialIssuerConfigFromInformerCache, err := c.credentialIssuerConfigInformer.
|
||||||
Lister().
|
Lister().
|
||||||
CredentialIssuerConfigs(c.namespace).
|
CredentialIssuerConfigs(c.namespace).
|
||||||
Get(configName)
|
Get(ConfigName)
|
||||||
notFound = k8serrors.IsNotFound(err)
|
notFound = k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("could not get credentialissuerconfig: %w", err)
|
return fmt.Errorf("could not get credentialissuerconfig: %w", err)
|
||||||
@ -131,7 +131,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
|||||||
ctx.Context,
|
ctx.Context,
|
||||||
existingCredentialIssuerConfigFromInformerCache,
|
existingCredentialIssuerConfigFromInformerCache,
|
||||||
notFound,
|
notFound,
|
||||||
configName,
|
ConfigName,
|
||||||
c.namespace,
|
c.namespace,
|
||||||
c.pinnipedClient,
|
c.pinnipedClient,
|
||||||
updateServerAndCAFunc)
|
updateServerAndCAFunc)
|
||||||
|
Loading…
Reference in New Issue
Block a user