From 626d546b8f1d1009418fef6174b1096a7e40f664 Mon Sep 17 00:00:00 2001 From: Simon Emms Date: Tue, 15 Nov 2022 11:23:59 +0000 Subject: [PATCH] [installer]: validate the node labels by kind in config --- install/installer/pkg/cluster/affinity.go | 14 ++++- install/installer/pkg/cluster/checks.go | 40 +------------ install/installer/pkg/cluster/validation.go | 10 +--- install/installer/pkg/config/v1/validation.go | 57 +++++++++++++++++++ 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/install/installer/pkg/cluster/affinity.go b/install/installer/pkg/cluster/affinity.go index ca7c51e45a6584..55fed059ce8be9 100644 --- a/install/installer/pkg/cluster/affinity.go +++ b/install/installer/pkg/cluster/affinity.go @@ -13,10 +13,22 @@ const ( AffinityLabelWorkspacesHeadless = "gitpod.io/workload_workspace_headless" ) -var AffinityList = []string{ +var AffinityListMeta = []string{ AffinityLabelMeta, AffinityLabelIDE, +} + +var AffinityListWorkspace = []string{ AffinityLabelWorkspaceServices, AffinityLabelWorkspacesRegular, AffinityLabelWorkspacesHeadless, } + +var AffinityList = func() []string { + list := []string{} + + list = append(list, AffinityListMeta...) + list = append(list, AffinityListWorkspace...) + + return list +}() diff --git a/install/installer/pkg/cluster/checks.go b/install/installer/pkg/cluster/checks.go index b32603afd121de..641702873c01ba 100644 --- a/install/installer/pkg/cluster/checks.go +++ b/install/installer/pkg/cluster/checks.go @@ -24,40 +24,6 @@ const ( kubernetesVersionConstraint = ">= 1.21.0-0" ) -// checkAffinityLabels validates that the nodes have all the required affinity labels applied -// It assumes all the values are `true` -func checkAffinityLabels(ctx context.Context, config *rest.Config, namespace string) ([]ValidationError, error) { - nodes, err := listNodesFromContext(ctx, config) - if err != nil { - return nil, err - } - - affinityList := map[string]bool{} - for _, affinity := range AffinityList { - affinityList[affinity] = false - } - - var res []ValidationError - for _, node := range nodes { - for k, v := range node.GetLabels() { - if _, found := affinityList[k]; found { - affinityList[k] = v == "true" - } - } - } - - // Check all the values in the map are `true` - for k, v := range affinityList { - if !v { - res = append(res, ValidationError{ - Message: "Affinity label not found in cluster: " + k, - Type: ValidationStatusError, - }) - } - } - return res, nil -} - // checkCertManagerInstalled checks that cert-manager is installed as a cluster dependency func checkCertManagerInstalled(ctx context.Context, config *rest.Config, namespace string) ([]ValidationError, error) { client, err := certmanager.NewForConfig(config) @@ -91,7 +57,7 @@ func checkCertManagerInstalled(ctx context.Context, config *rest.Config, namespa // checkContainerDRuntime checks that the nodes are running with the containerd runtime func checkContainerDRuntime(ctx context.Context, config *rest.Config, namespace string) ([]ValidationError, error) { - nodes, err := listNodesFromContext(ctx, config) + nodes, err := ListNodesFromContext(ctx, config) if err != nil { return nil, err } @@ -139,7 +105,7 @@ func checkKubernetesVersion(ctx context.Context, config *rest.Config, namespace }) } - nodes, err := listNodesFromContext(ctx, config) + nodes, err := ListNodesFromContext(ctx, config) if err != nil { return nil, err } @@ -263,7 +229,7 @@ func checkKernelVersion(ctx context.Context, config *rest.Config, namespace stri return nil, err } - nodes, err := listNodesFromContext(ctx, config) + nodes, err := ListNodesFromContext(ctx, config) if err != nil { return nil, err } diff --git a/install/installer/pkg/cluster/validation.go b/install/installer/pkg/cluster/validation.go index 2b324ef1b22802..702f4f142bf73a 100644 --- a/install/installer/pkg/cluster/validation.go +++ b/install/installer/pkg/cluster/validation.go @@ -8,6 +8,7 @@ import ( "context" "encoding/json" "fmt" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/version" @@ -65,11 +66,6 @@ var ClusterChecks = ValidationChecks{ Description: "all cluster nodes run kubernetes version " + kubernetesVersionConstraint, Check: checkKubernetesVersion, }, - { - Name: "affinity labels", - Check: checkAffinityLabels, - Description: "all required affinity node labels " + fmt.Sprint(AffinityList) + " are present in the cluster", - }, { Name: "cert-manager installed", Check: checkCertManagerInstalled, @@ -100,7 +96,7 @@ func (checks ValidationChecks) Validate(ctx context.Context, config *rest.Config } ctx = context.WithValue(ctx, keyClientset, client) - list, err := listNodesFromContext(ctx, config) + list, err := ListNodesFromContext(ctx, config) if err != nil { return nil, err } @@ -147,7 +143,7 @@ const ( keyClientset = "clientset" ) -func listNodesFromContext(ctx context.Context, config *rest.Config) ([]corev1.Node, error) { +func ListNodesFromContext(ctx context.Context, config *rest.Config) ([]corev1.Node, error) { client, err := clientsetFromContext(ctx, config) if err != nil { return nil, err diff --git a/install/installer/pkg/config/v1/validation.go b/install/installer/pkg/config/v1/validation.go index 0a49bb45d37730..4449997a846592 100644 --- a/install/installer/pkg/config/v1/validation.go +++ b/install/installer/pkg/config/v1/validation.go @@ -5,6 +5,7 @@ package config import ( + "context" "fmt" "regexp" @@ -15,6 +16,7 @@ import ( "github.com/go-playground/validator/v10" corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/rest" ) var InstallationKindList = map[InstallationKind]struct{}{ @@ -121,6 +123,12 @@ func (v version) ClusterValidation(rcfg interface{}) cluster.ValidationChecks { var res cluster.ValidationChecks res = append(res, cluster.CheckSecret(cfg.Certificate.Name, cluster.CheckSecretRequiredData("tls.crt", "tls.key"))) + res = append(res, cluster.ValidationCheck{ + Name: "affinity labels", + Check: checkAffinityLabels(getAffinityListByKind(cfg.Kind)), + Description: "all required affinity node labels " + fmt.Sprint(getAffinityListByKind(cfg.Kind)) + " are present in the cluster", + }) + if cfg.ObjectStorage.CloudStorage != nil { secretName := cfg.ObjectStorage.CloudStorage.ServiceAccount.Name res = append(res, cluster.CheckSecret(secretName, cluster.CheckSecretRequiredData("service-account.json"))) @@ -252,3 +260,52 @@ func (v version) ClusterValidation(rcfg interface{}) cluster.ValidationChecks { return res } + +// checkAffinityLabels validates that the nodes have all the required affinity labels applied +// It assumes all the values are `true` +func checkAffinityLabels(targetAffinityList []string) func(context.Context, *rest.Config, string) ([]cluster.ValidationError, error) { + return func(ctx context.Context, config *rest.Config, namespace string) ([]cluster.ValidationError, error) { + nodes, err := cluster.ListNodesFromContext(ctx, config) + if err != nil { + return nil, err + } + + affinityList := map[string]bool{} + for _, affinity := range targetAffinityList { + affinityList[affinity] = false + } + + var res []cluster.ValidationError + for _, node := range nodes { + for k, v := range node.GetLabels() { + if _, found := affinityList[k]; found { + affinityList[k] = v == "true" + } + } + } + + // Check all the values in the map are `true` + for k, v := range affinityList { + if !v { + res = append(res, cluster.ValidationError{ + Message: "Affinity label not found in cluster: " + k, + Type: cluster.ValidationStatusError, + }) + } + } + return res, nil + } +} + +func getAffinityListByKind(kind InstallationKind) []string { + var affinityList []string + switch kind { + case InstallationMeta: + affinityList = cluster.AffinityListMeta + case InstallationWorkspace: + affinityList = cluster.AffinityListWorkspace + default: + affinityList = cluster.AffinityList + } + return affinityList +}