Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[installer]: validate the node labels by kind in config #14691

Merged
merged 1 commit into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion install/installer/pkg/cluster/affinity.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}()
40 changes: 3 additions & 37 deletions install/installer/pkg/cluster/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
10 changes: 3 additions & 7 deletions install/installer/pkg/cluster/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
57 changes: 57 additions & 0 deletions install/installer/pkg/config/v1/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package config

import (
"context"
"fmt"
"regexp"

Expand All @@ -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{}{
Expand Down Expand Up @@ -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")))
Expand Down Expand Up @@ -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
}