package framework import ( "encoding/json" "fmt" "strings" corev1 "k8s.io/api/core/v1" "github.com/aws/eks-anywhere/pkg/api/v1alpha1" "github.com/aws/eks-anywhere/pkg/constants" "github.com/aws/eks-anywhere/pkg/logger" ) const LabelPrefix = "eksa.e2e" func ValidateControlPlaneLabels(controlPlane v1alpha1.ControlPlaneConfiguration, node corev1.Node) error { logger.V(4).Info("Validating control plane labels") return validateLabels(controlPlane.Labels, node) } // ValidateControlPlaneFailureDomainLabels validate if Cloudstack provider replaces ds.meta_data.failuredomain with proper failuredomain name // in control plane node label 'cluster.x-k8s.io/failure-domain'. func ValidateControlPlaneFailureDomainLabels(controlPlane v1alpha1.ControlPlaneConfiguration, node corev1.Node) error { if controlPlane.MachineGroupRef.Kind == "CloudStackMachineConfig" { logger.V(4).Info("Validating control plane node failuredomain label") return validateFailureDomainLabel(controlPlane.Labels, node) } return fmt.Errorf("ds.meta_data.failuredomain placeholder in node label is currently only supported in CloudStack provider") } func ValidateWorkerNodeLabels(w v1alpha1.WorkerNodeGroupConfiguration, node corev1.Node) error { logger.V(4).Info("Validating worker node labels", "worker node group", w.Name) return validateLabels(w.Labels, node) } // ValidateWorkerNodeFailureDomainLabels validate if Cloudstack provider replaces ds.meta_data.failuredomain with proper failuredomain name // in worker group node label 'cluster.x-k8s.io/failure-domain'. func ValidateWorkerNodeFailureDomainLabels(w v1alpha1.WorkerNodeGroupConfiguration, node corev1.Node) error { if w.MachineGroupRef.Kind == v1alpha1.CloudStackMachineConfigKind { logger.V(4).Info("Validating worker node failuredomain label", "worker node group", w.Name) return validateFailureDomainLabel(w.Labels, node) } return fmt.Errorf("ds.meta_data.failuredomain placeholder in node label is currently only supported in CloudStack provider") } func validateLabels(expectedLabels map[string]string, node corev1.Node) error { actualLabels := retrieveTestNodeLabels(node.Labels) expectedBytes, _ := json.Marshal(expectedLabels) actualBytes, _ := json.Marshal(actualLabels) if !v1alpha1.MapEqual(expectedLabels, actualLabels) { return fmt.Errorf("labels on node %v and corresponding configuration do not match; configured labels: %v; node labels: %v", node.Name, string(expectedBytes), string(actualBytes)) } logger.V(4).Info("expected labels from cluster spec configuration are present on the corresponding node", "node", node.Name, "node labels", string(actualBytes), "configuration labels", string(expectedBytes)) return nil } func retrieveTestNodeLabels(nodeLabels map[string]string) map[string]string { labels := map[string]string{} for key, val := range nodeLabels { if strings.HasPrefix(key, LabelPrefix) { labels[key] = val } } return labels } func validateFailureDomainLabel(expectedLabels map[string]string, node corev1.Node) error { if failuredomainSpecified, ok := expectedLabels[constants.FailureDomainLabelName]; ok { if failuredomain, exist := node.Labels[constants.FailureDomainLabelName]; exist { logger.V(4).Info("node label: ", constants.FailureDomainLabelName, failuredomain) if failuredomainSpecified == constants.CloudstackFailureDomainPlaceholder && failuredomain == failuredomainSpecified { return fmt.Errorf("value %s of label %s on node %s is not replaced with a failurdomain name by CloudStack provider", constants.CloudstackFailureDomainPlaceholder, constants.FailureDomainLabelName, node.Name) } } else { return fmt.Errorf("expected labels %s not found on node %s", constants.FailureDomainLabelName, node.Name) } } return nil }