From 24f92b22554d8722b25504e9e2b09e6b9ad00ca4 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 31 Aug 2021 14:18:37 +0200 Subject: [PATCH] util: NewK8sClient() should not panic on non-Kubernetes clusters When NewK8sClient() detects and error, it used to call FatalLogMsg() which causes a panic. There are additional features that can be used on Kubernetes clusters, but these are not a requirement for most functionalities of the driver. Instead of causing a panic, returning an error should suffice. This allows using the driver on non-Kubernetes clusters again. Fixes: #2452 Signed-off-by: Niels de Vos (cherry picked from commit 60c2afbccadf008ebcd1293f3c10f0d5596b0e62) --- internal/rbd/rbd_healer.go | 8 +++++++- internal/rbd/rbd_util.go | 6 +++++- internal/util/aws_metadata.go | 7 ++++++- internal/util/k8s.go | 15 ++++++++------- internal/util/kms.go | 7 ++++++- internal/util/secretskms.go | 7 ++++++- internal/util/topology.go | 7 ++++++- internal/util/vault_sa.go | 15 +++++++++++++-- internal/util/vault_tokens.go | 28 ++++++++++++++++++++++------ 9 files changed, 79 insertions(+), 21 deletions(-) diff --git a/internal/rbd/rbd_healer.go b/internal/rbd/rbd_healer.go index bb7b2ae9410..c84b6fee022 100644 --- a/internal/rbd/rbd_healer.go +++ b/internal/rbd/rbd_healer.go @@ -125,7 +125,13 @@ func callNodeStageVolume(ns *NodeServer, c *k8s.Clientset, pv *v1.PersistentVolu // runVolumeHealer heal the volumes attached on a node. func runVolumeHealer(ns *NodeServer, conf *util.Config) error { - c := util.NewK8sClient() + c, err := util.NewK8sClient() + if err != nil { + util.ErrorLogMsg("failed to connect to Kubernetes: %v", err) + + return err + } + val, err := c.StorageV1().VolumeAttachments().List(context.TODO(), metav1.ListOptions{}) if err != nil { util.ErrorLogMsg("list volumeAttachments failed, err: %v", err) diff --git a/internal/rbd/rbd_util.go b/internal/rbd/rbd_util.go index a39276ff5f7..cd658d11f70 100644 --- a/internal/rbd/rbd_util.go +++ b/internal/rbd/rbd_util.go @@ -1060,7 +1060,11 @@ func genVolFromVolID( // be the same in the PV.Spec.CSI.VolumeHandle. Check the PV annotation for // the new volumeHandle. If the new volumeHandle is found, generate the RBD // volume structure from the new volumeHandle. - c := util.NewK8sClient() + c, cErr := util.NewK8sClient() + if cErr != nil { + return vol, cErr + } + listOpt := metav1.ListOptions{ LabelSelector: PVReplicatedLabelKey, } diff --git a/internal/util/aws_metadata.go b/internal/util/aws_metadata.go index 3aadca739ed..d86d9e8d6a2 100644 --- a/internal/util/aws_metadata.go +++ b/internal/util/aws_metadata.go @@ -123,7 +123,12 @@ func initAWSMetadataKMS(args KMSInitializerArgs) (EncryptionKMS, error) { } func (kms *AWSMetadataKMS) getSecrets() (map[string]interface{}, error) { - c := NewK8sClient() + c, err := NewK8sClient() + if err != nil { + return nil, fmt.Errorf("failed to connect to Kubernetes to "+ + "get Secret %s/%s: %w", kms.namespace, kms.secretName, err) + } + secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(), kms.secretName, metav1.GetOptions{}) if err != nil { diff --git a/internal/util/k8s.go b/internal/util/k8s.go index f175e959e88..2b89e44477a 100644 --- a/internal/util/k8s.go +++ b/internal/util/k8s.go @@ -17,33 +17,34 @@ limitations under the License. package util import ( + "fmt" "os" - k8s "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) // NewK8sClient create kubernetes client. -func NewK8sClient() *k8s.Clientset { +func NewK8sClient() (*kubernetes.Clientset, error) { var cfg *rest.Config var err error cPath := os.Getenv("KUBERNETES_CONFIG_PATH") if cPath != "" { cfg, err = clientcmd.BuildConfigFromFlags("", cPath) if err != nil { - FatalLogMsg("Failed to get cluster config with error: %v\n", err) + return nil, fmt.Errorf("failed to get cluster config from %q: %w", cPath, err) } } else { cfg, err = rest.InClusterConfig() if err != nil { - FatalLogMsg("Failed to get cluster config with error: %v\n", err) + return nil, fmt.Errorf("failed to get cluster config: %w", err) } } - client, err := k8s.NewForConfig(cfg) + client, err := kubernetes.NewForConfig(cfg) if err != nil { - FatalLogMsg("Failed to create client with error: %v\n", err) + return nil, fmt.Errorf("failed to create client: %w", err) } - return client + return client, nil } diff --git a/internal/util/kms.go b/internal/util/kms.go index c5b57d5b32e..4bb67cefa41 100644 --- a/internal/util/kms.go +++ b/internal/util/kms.go @@ -146,7 +146,12 @@ func getKMSConfigMap() (map[string]interface{}, error) { } cmName := getKMSConfigMapName() - c := NewK8sClient() + c, err := NewK8sClient() + if err != nil { + return nil, fmt.Errorf("can not get ConfigMap %q, failed to "+ + "connect to Kubernetes: %w", cmName, err) + } + cm, err := c.CoreV1().ConfigMaps(ns).Get(context.Background(), cmName, metav1.GetOptions{}) if err != nil { diff --git a/internal/util/secretskms.go b/internal/util/secretskms.go index 879327983c4..361c370ab8c 100644 --- a/internal/util/secretskms.go +++ b/internal/util/secretskms.go @@ -155,7 +155,12 @@ func (kms SecretsMetadataKMS) fetchEncryptionPassphrase( secretNamespace = defaultNamespace } - c := NewK8sClient() + c, err := NewK8sClient() + if err != nil { + return "", fmt.Errorf("can not get Secret %s/%s, failed to "+ + "connect to Kubernetes: %w", secretNamespace, secretName, err) + } + secret, err := c.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) if err != nil { diff --git a/internal/util/topology.go b/internal/util/topology.go index 5a1fadda6cc..e64c6529f51 100644 --- a/internal/util/topology.go +++ b/internal/util/topology.go @@ -32,7 +32,12 @@ const ( ) func k8sGetNodeLabels(nodeName string) (map[string]string, error) { - client := NewK8sClient() + client, err := NewK8sClient() + if err != nil { + return nil, fmt.Errorf("can not get node %q information, failed "+ + "to connect to Kubernetes: %w", nodeName, err) + } + node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to get node %q information: %w", nodeName, err) diff --git a/internal/util/vault_sa.go b/internal/util/vault_sa.go index c8940ea0310..9aaa14b8706 100644 --- a/internal/util/vault_sa.go +++ b/internal/util/vault_sa.go @@ -260,7 +260,12 @@ func (kms *VaultTenantSA) setServiceAccountName(config map[string]interface{}) e // getServiceAccount returns the Tenants ServiceAccount with the name // configured in the VaultTenantSA. func (kms *VaultTenantSA) getServiceAccount() (*corev1.ServiceAccount, error) { - c := kms.getK8sClient() + c, err := kms.getK8sClient() + if err != nil { + return nil, fmt.Errorf("can not get ServiceAccount %s/%s, "+ + "failed to connect to Kubernetes: %w", kms.Tenant, kms.tenantSAName, err) + } + sa, err := c.CoreV1().ServiceAccounts(kms.Tenant).Get(context.TODO(), kms.tenantSAName, metav1.GetOptions{}) if err != nil { @@ -279,7 +284,13 @@ func (kms *VaultTenantSA) getToken() (string, error) { return "", err } - c := kms.getK8sClient() + c, err := kms.getK8sClient() + if err != nil { + return "", fmt.Errorf("can not get ServiceAccount %s/%s, failed "+ + "to connect to Kubernetes: %w", kms.Tenant, + kms.tenantSAName, err) + } + for _, secretRef := range sa.Secrets { secret, err := c.CoreV1().Secrets(kms.Tenant).Get(context.TODO(), secretRef.Name, metav1.GetOptions{}) if err != nil { diff --git a/internal/util/vault_tokens.go b/internal/util/vault_tokens.go index 6ee4d1e401d..2bdf59cfdda 100644 --- a/internal/util/vault_tokens.go +++ b/internal/util/vault_tokens.go @@ -433,12 +433,16 @@ func (vtc *vaultTenantConnection) initCertificates(config map[string]interface{} return nil } -func (vtc *vaultTenantConnection) getK8sClient() *kubernetes.Clientset { +func (vtc *vaultTenantConnection) getK8sClient() (*kubernetes.Clientset, error) { if vtc.client == nil { - vtc.client = NewK8sClient() + client, err := NewK8sClient() + if err != nil { + return nil, err + } + vtc.client = client } - return vtc.client + return vtc.client, nil } // FetchDEK returns passphrase from Vault. The passphrase is stored in a @@ -488,7 +492,11 @@ func (vtc *vaultTenantConnection) RemoveDEK(key string) error { } func (kms *VaultTokensKMS) getToken() (string, error) { - c := kms.getK8sClient() + c, err := kms.getK8sClient() + if err != nil { + return "", err + } + secret, err := c.CoreV1().Secrets(kms.Tenant).Get(context.TODO(), kms.TokenName, metav1.GetOptions{}) if err != nil { return "", err @@ -503,7 +511,11 @@ func (kms *VaultTokensKMS) getToken() (string, error) { } func (vtc *vaultTenantConnection) getCertificate(tenant, secretName, key string) (string, error) { - c := vtc.getK8sClient() + c, err := vtc.getK8sClient() + if err != nil { + return "", err + } + secret, err := c.CoreV1().Secrets(tenant).Get(context.TODO(), secretName, metav1.GetOptions{}) if err != nil { return "", err @@ -545,7 +557,11 @@ func (vtc *vaultTenantConnection) parseTenantConfig() (map[string]interface{}, e } // fetch the ConfigMap from the tenants namespace - c := vtc.getK8sClient() + c, err := vtc.getK8sClient() + if err != nil { + return nil, err + } + cm, err := c.CoreV1().ConfigMaps(vtc.Tenant).Get(context.TODO(), vtc.ConfigName, metav1.GetOptions{}) if apierrs.IsNotFound(err) {