From 2a33844c686dd966e442abefab28ce077e233bef Mon Sep 17 00:00:00 2001 From: Dario Tranchitella Date: Thu, 8 Sep 2022 15:31:14 +0200 Subject: [PATCH] refactor(utilities): decreasing bloating functions --- .../datastore/datastore_storage_config.go | 3 +- internal/resources/k8s_deployment_resource.go | 37 +++++++++- internal/resources/kubeadm_addons.go | 2 +- internal/resources/kubeadm_upgrade.go | 6 +- internal/resources/kubeadm_utils.go | 4 +- internal/utilities/tenant_client.go | 42 ++++------- internal/utilities/utilities.go | 69 ------------------- 7 files changed, 57 insertions(+), 106 deletions(-) diff --git a/internal/resources/datastore/datastore_storage_config.go b/internal/resources/datastore/datastore_storage_config.go index 4204056..7fed5aa 100644 --- a/internal/resources/datastore/datastore_storage_config.go +++ b/internal/resources/datastore/datastore_storage_config.go @@ -6,6 +6,7 @@ package datastore import ( "context" + "github.com/google/uuid" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ctrl "sigs.k8s.io/controller-runtime" @@ -81,7 +82,7 @@ func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.Te case ok && savedHash == utilities.CalculateConfigMapChecksum(r.resource.StringData): password = r.resource.Data["DB_PASSWORD"] default: - password = []byte(utilities.GenerateUUIDString()) + password = []byte(uuid.New().String()) } r.resource.Data = map[string][]byte{ diff --git a/internal/resources/k8s_deployment_resource.go b/internal/resources/k8s_deployment_resource.go index 2578fc2..1a88d5c 100644 --- a/internal/resources/k8s_deployment_resource.go +++ b/internal/resources/k8s_deployment_resource.go @@ -5,6 +5,11 @@ package resources import ( "context" + "crypto/md5" + "fmt" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sort" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" @@ -115,7 +120,7 @@ func (r *KubernetesDeploymentResource) UpdateTenantControlPlaneStatus(_ context. func (r *KubernetesDeploymentResource) deploymentTemplateLabels(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (labels map[string]string) { hash := func(ctx context.Context, namespace, secretName string) string { - h, _ := utilities.SecretHashValue(ctx, r.Client, namespace, secretName) + h, _ := r.SecretHashValue(ctx, r.Client, namespace, secretName) return h } @@ -160,3 +165,33 @@ func (r *KubernetesDeploymentResource) isProvisioning(tenantControlPlane *kamaji func (r *KubernetesDeploymentResource) isNotReady() bool { return r.resource.Status.ReadyReplicas == 0 } + +// SecretHashValue function returns the md5 value for the secret of the given name and namespace. +func (r *KubernetesDeploymentResource) SecretHashValue(ctx context.Context, client client.Client, namespace, name string) (string, error) { + secret := &corev1.Secret{} + if err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, secret); err != nil { + return "", errors.Wrap(err, "cannot retrieve *corev1.Secret for resource version retrieval") + } + + return r.HashValue(*secret), nil +} + +// HashValue function returns the md5 value for the given secret. +func (r *KubernetesDeploymentResource) HashValue(secret corev1.Secret) string { + // Go access map values in random way, it means we have to sort them. + keys := make([]string, 0, len(secret.Data)) + + for k := range secret.Data { + keys = append(keys, k) + } + + sort.Strings(keys) + // Generating MD5 of Secret values, sorted by key + h := md5.New() + + for _, key := range keys { + h.Write(secret.Data[key]) + } + + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/internal/resources/kubeadm_addons.go b/internal/resources/kubeadm_addons.go index 635f2b0..450a837 100644 --- a/internal/resources/kubeadm_addons.go +++ b/internal/resources/kubeadm_addons.go @@ -69,7 +69,7 @@ func (r *KubeadmAddonResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1. } func (r *KubeadmAddonResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) { - client, err := utilities.GetTenantRESTClient(ctx, r.Client, tenantControlPlane) + client, err := utilities.GetTenantClientSet(ctx, r.Client, tenantControlPlane) if err != nil { return false, err } diff --git a/internal/resources/kubeadm_upgrade.go b/internal/resources/kubeadm_upgrade.go index 41931fb..113303f 100644 --- a/internal/resources/kubeadm_upgrade.go +++ b/internal/resources/kubeadm_upgrade.go @@ -65,14 +65,14 @@ func (k *KubernetesUpgrade) CreateOrUpdate(ctx context.Context, tenantControlPla return controllerutil.OperationResultNone, nil } // Checking if the upgrade is allowed, or not - restClient, err := utilities.GetTenantRESTClient(ctx, k.Client, tenantControlPlane) + clientSet, err := utilities.GetTenantClientSet(ctx, k.Client, tenantControlPlane) if err != nil { return controllerutil.OperationResultNone, errors.Wrap(err, "cannot create REST client required for Kubernetes upgrade plan") } - versionGetter := kamajiupgrade.NewKamajiKubeVersionGetter(restClient) + versionGetter := kamajiupgrade.NewKamajiKubeVersionGetter(clientSet) - if _, err = upgrade.GetAvailableUpgrades(versionGetter, false, false, true, restClient, "", &printers.Discard{}); err != nil { + if _, err = upgrade.GetAvailableUpgrades(versionGetter, false, false, true, clientSet, "", &printers.Discard{}); err != nil { return controllerutil.OperationResultNone, errors.Wrap(err, "cannot retrieve available Upgrades for Kubernetes upgrade plan") } diff --git a/internal/resources/kubeadm_utils.go b/internal/resources/kubeadm_utils.go index 0663841..beae52e 100644 --- a/internal/resources/kubeadm_utils.go +++ b/internal/resources/kubeadm_utils.go @@ -19,7 +19,7 @@ func KubeadmPhaseCreate(ctx context.Context, r KubeadmPhaseResource, tenantContr return controllerutil.OperationResultNone, err } - kubeconfig, err := utilities.GetKubeconfig(ctx, r.GetClient(), tenantControlPlane) + kubeconfig, err := utilities.GetTenantKubeconfig(ctx, r.GetClient(), tenantControlPlane) if err != nil { return controllerutil.OperationResultNone, err } @@ -83,7 +83,7 @@ func KubeadmPhaseCreate(ctx context.Context, r KubeadmPhaseResource, tenantContr return controllerutil.OperationResultNone, nil } - client, err := utilities.GetTenantRESTClient(ctx, r.GetClient(), tenantControlPlane) + client, err := utilities.GetTenantClientSet(ctx, r.GetClient(), tenantControlPlane) if err != nil { return controllerutil.OperationResultNone, err } diff --git a/internal/utilities/tenant_client.go b/internal/utilities/tenant_client.go index cac7c6e..9219214 100644 --- a/internal/utilities/tenant_client.go +++ b/internal/utilities/tenant_client.go @@ -12,16 +12,13 @@ import ( k8stypes "k8s.io/apimachinery/pkg/types" clientset "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "sigs.k8s.io/controller-runtime/pkg/client" kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1" kubeconfigutil "github.com/clastix/kamaji/internal/kubeconfig" ) -const ( - kubeadmConfigSecretKeyName = "admin.conf" -) - func GetTenantClient(ctx context.Context, c client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (client.Client, error) { options := client.Options{} config, err := getRESTClientConfig(ctx, c, tenantControlPlane) @@ -32,7 +29,7 @@ func GetTenantClient(ctx context.Context, c client.Client, tenantControlPlane *k return client.New(config, options) } -func GetTenantRESTClient(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*clientset.Clientset, error) { +func GetTenantClientSet(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*clientset.Clientset, error) { config, err := getRESTClientConfig(ctx, client, tenantControlPlane) if err != nil { return nil, err @@ -41,23 +38,28 @@ func GetTenantRESTClient(ctx context.Context, client client.Client, tenantContro return clientset.NewForConfig(config) } -func GetKubeconfigSecret(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*corev1.Secret, error) { - secret := &corev1.Secret{} - if err := client.Get(ctx, k8stypes.NamespacedName{Namespace: tenantControlPlane.GetNamespace(), Name: tenantControlPlane.Status.KubeConfig.Admin.SecretName}, secret); err != nil { +func GetTenantKubeconfig(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*kubeconfigutil.Kubeconfig, error) { + secretKubeconfig := &corev1.Secret{} + if err := client.Get(ctx, k8stypes.NamespacedName{Namespace: tenantControlPlane.GetNamespace(), Name: tenantControlPlane.Status.KubeConfig.Admin.SecretName}, secretKubeconfig); err != nil { return nil, err } - return secret, nil + bytes, ok := secretKubeconfig.Data[kubeadmconstants.AdminKubeConfigFileName] + if !ok { + return nil, fmt.Errorf("%s is not into kubeconfig secret", kubeadmconstants.AdminKubeConfigFileName) + } + + return kubeconfigutil.GetKubeconfigFromBytes(bytes) } func getRESTClientConfig(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*restclient.Config, error) { - kubeconfig, err := GetKubeconfig(ctx, client, tenantControlPlane) + kubeconfig, err := GetTenantKubeconfig(ctx, client, tenantControlPlane) if err != nil { return nil, err } config := &restclient.Config{ - Host: fmt.Sprintf("https://%s:%d", getTenantControllerInternalFQDN(*tenantControlPlane), tenantControlPlane.Spec.NetworkProfile.Port), + Host: fmt.Sprintf("https://%s.%s.svc.cluster.local:%d", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace(), tenantControlPlane.Spec.NetworkProfile.Port), TLSClientConfig: restclient.TLSClientConfig{ CAData: kubeconfig.Clusters[0].Cluster.CertificateAuthorityData, CertData: kubeconfig.AuthInfos[0].AuthInfo.ClientCertificateData, @@ -68,21 +70,3 @@ func getRESTClientConfig(ctx context.Context, client client.Client, tenantContro return config, nil } - -func GetKubeconfig(ctx context.Context, client client.Client, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*kubeconfigutil.Kubeconfig, error) { - secretKubeconfig, err := GetKubeconfigSecret(ctx, client, tenantControlPlane) - if err != nil { - return nil, err - } - - bytes, ok := secretKubeconfig.Data[kubeadmConfigSecretKeyName] - if !ok { - return nil, fmt.Errorf("%s is not into kubeconfig secret", kubeadmConfigSecretKeyName) - } - - return kubeconfigutil.GetKubeconfigFromBytes(bytes) -} - -func getTenantControllerInternalFQDN(tenantControlPlane kamajiv1alpha1.TenantControlPlane) string { - return fmt.Sprintf("%s.%s.svc.cluster.local", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace()) -} diff --git a/internal/utilities/utilities.go b/internal/utilities/utilities.go index 3090a2a..30b2b03 100644 --- a/internal/utilities/utilities.go +++ b/internal/utilities/utilities.go @@ -5,20 +5,10 @@ package utilities import ( "bytes" - "context" - "crypto/md5" "fmt" - "net" - "regexp" - "sort" - "github.com/google/uuid" - "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer/json" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1" "github.com/clastix/kamaji/internal/constants" @@ -101,62 +91,3 @@ func EncodeToJSON(o runtime.Object) ([]byte, error) { return buf.Bytes(), nil } - -// IsValidIP checks if the given argument is an IP. -func IsValidIP(ip string) bool { - return net.ParseIP(ip) != nil -} - -// IsValidHostname checks if the given argument is a valid hostname. -func IsValidHostname(hostname string) bool { - pattern := "^([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9])(\\.([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9]))*$" - - return validateRegex(pattern, hostname) -} - -func validateRegex(pattern string, value string) bool { - isFound, err := regexp.MatchString(pattern, value) - if err != nil { - return false - } - - return isFound -} - -func GenerateUUID() uuid.UUID { - return uuid.New() -} - -func GenerateUUIDString() string { - return GenerateUUID().String() -} - -// SecretHashValue function returns the md5 value for the secret of the given name and namespace. -func SecretHashValue(ctx context.Context, client client.Client, namespace, name string) (string, error) { - secret := &corev1.Secret{} - if err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, secret); err != nil { - return "", errors.Wrap(err, "cannot retrieve *corev1.Secret for resource version retrieval") - } - - return HashValue(*secret), nil -} - -// HashValue function returns the md5 value for the given secret. -func HashValue(secret corev1.Secret) string { - // Go access map values in random way, it means we have to sort them. - keys := make([]string, 0, len(secret.Data)) - - for k := range secret.Data { - keys = append(keys, k) - } - - sort.Strings(keys) - // Generating MD5 of Secret values, sorted by key - h := md5.New() - - for _, key := range keys { - h.Write(secret.Data[key]) - } - - return fmt.Sprintf("%x", h.Sum(nil)) -}