pkg/controller/elasticsearch/label/label.go (140 lines of code) (raw):

// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one // or more contributor license agreements. Licensed under the Elastic License 2.0; // you may not use this file except in compliance with the Elastic License 2.0. package label import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" commonv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/common/v1" esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/labels" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" ) const ( // ClusterNameLabelName used to represent a cluster in k8s resources ClusterNameLabelName = "elasticsearch.k8s.elastic.co/cluster-name" // ClusterNamespaceLabelName used to represent a cluster in k8s resources ClusterNamespaceLabelName = "elasticsearch.k8s.elastic.co/cluster-namespace" // VersionLabelName used to store the Elasticsearch version of the resource VersionLabelName = "elasticsearch.k8s.elastic.co/version" // PodNameLabelName used to store the name of the pod on other objects PodNameLabelName = "elasticsearch.k8s.elastic.co/pod-name" // StatefulSetNameLabelName used to store the name of the statefulset. StatefulSetNameLabelName = "elasticsearch.k8s.elastic.co/statefulset-name" // NodeTypesMasterLabelName is a label set to true on nodes with the master role NodeTypesMasterLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-master" // NodeTypesDataLabelName is a label set to true on nodes with the data role NodeTypesDataLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data" // NodeTypesIngestLabelName is a label set to true on nodes with the ingest role NodeTypesIngestLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-ingest" // NodeTypesMLLabelName is a label set to true on nodes with the ml role NodeTypesMLLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-ml" // NodeTypesTransformLabelName is a label set to true on nodes with the transform role NodeTypesTransformLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-transform" // NodeTypesRemoteClusterClientLabelName is a label set to true on nodes with the remote_cluster_client role NodeTypesRemoteClusterClientLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-remote_cluster_client" // NodeTypesVotingOnlyLabelName is a label set to true on voting-only master-eligible nodes NodeTypesVotingOnlyLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-voting_only" // NodeTypesDataColdLabelName is a label set to true on nodes with the data_cold role. NodeTypesDataColdLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data_cold" // NodeTypesDataContentLabelName is a label set to true on nodes with the data_content role. NodeTypesDataContentLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data_content" // NodeTypesDataHotLabelName is a label set to true on nodes with the data_hot role. NodeTypesDataHotLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data_hot" // NodeTypesDataWarmLabelName is a label set to true on nodes with the data_warm role. NodeTypesDataWarmLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data_warm" // NodeTypesDataFrozenLabelName is a label set to true on nodes with the data_frozen role. NodeTypesDataFrozenLabelName labels.TrueFalseLabel = "elasticsearch.k8s.elastic.co/node-data_frozen" HTTPSchemeLabelName = "elasticsearch.k8s.elastic.co/http-scheme" // Type represents the Elasticsearch type Type = "elasticsearch" ) // NonMasterRoles are all Elasticsearch node roles except master or voting-only. var NonMasterRoles = []labels.TrueFalseLabel{ NodeTypesDataLabelName, NodeTypesDataHotLabelName, NodeTypesDataColdLabelName, NodeTypesDataFrozenLabelName, NodeTypesDataContentLabelName, NodeTypesDataWarmLabelName, NodeTypesIngestLabelName, NodeTypesMLLabelName, NodeTypesRemoteClusterClientLabelName, NodeTypesTransformLabelName, } // IsMasterNode returns true if the pod has the master node label func IsMasterNode(pod corev1.Pod) bool { return NodeTypesMasterLabelName.HasValue(true, pod.Labels) } // IsMasterNodeSet returns true if the given StatefulSet specifies master nodes. func IsMasterNodeSet(statefulSet appsv1.StatefulSet) bool { return NodeTypesMasterLabelName.HasValue(true, statefulSet.Spec.Template.Labels) } // IsDataNodeSet returns true if the given StatefulSet specifies data nodes. func IsDataNodeSet(statefulSet appsv1.StatefulSet) bool { return NodeTypesDataLabelName.HasValue(true, statefulSet.Spec.Template.Labels) } // IsIngestNodeSet returns true if the given StatefulSet specifies ingest nodes. func IsIngestNodeSet(statefulSet appsv1.StatefulSet) bool { return NodeTypesIngestLabelName.HasValue(true, statefulSet.Spec.Template.Labels) } func FilterMasterNodePods(pods []corev1.Pod) []corev1.Pod { masters := []corev1.Pod{} for _, pod := range pods { if IsMasterNode(pod) { masters = append(masters, pod) } } return masters } // IsDataNode returns true if the pod has the data node label func IsDataNode(pod corev1.Pod) bool { return NodeTypesDataLabelName.HasValue(true, pod.Labels) } // ExtractVersion extracts the Elasticsearch version from the given labels. func ExtractVersion(labels map[string]string) (version.Version, error) { return version.FromLabels(labels, VersionLabelName) } // NewLabels constructs a new set of labels from an Elasticsearch definition. func NewLabels(es types.NamespacedName) map[string]string { return map[string]string{ ClusterNameLabelName: es.Name, commonv1.TypeLabelName: Type, } } // NewPodLabels returns labels to apply for a new Elasticsearch pod. func NewPodLabels( es types.NamespacedName, ssetName string, ver version.Version, nodeRoles *esv1.Node, scheme string, ) map[string]string { // cluster name based labels labels := NewLabels(es) // version label labels[VersionLabelName] = ver.String() // node types labels NodeTypesMasterLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.MasterRole), labels) NodeTypesDataLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataRole), labels) NodeTypesIngestLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.IngestRole), labels) NodeTypesMLLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.MLRole), labels) // transform and remote_cluster_client roles were only added in 7.7.0 so we should not annotate previous versions with them if ver.GTE(version.From(7, 7, 0)) { NodeTypesTransformLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.TransformRole), labels) NodeTypesRemoteClusterClientLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.RemoteClusterClientRole), labels) } // voting_only master eligible nodes were added only in 7.3.0 so we don't want to label prior versions with it if ver.GTE(version.From(7, 3, 0)) { NodeTypesVotingOnlyLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.VotingOnlyRole), labels) } // data tiers were added in 7.10.0 if ver.GTE(version.From(7, 10, 0)) { NodeTypesDataContentLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataContentRole), labels) NodeTypesDataColdLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataColdRole), labels) NodeTypesDataHotLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataHotRole), labels) NodeTypesDataWarmLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataWarmRole), labels) } // frozen tier has been introduced in 7.12.0 if ver.GTE(version.From(7, 12, 0)) { NodeTypesDataFrozenLabelName.Set(nodeRoles.IsConfiguredWithRole(esv1.DataFrozenRole), labels) } labels[HTTPSchemeLabelName] = scheme // apply stateful set label selector for k, v := range NewStatefulSetLabels(es, ssetName) { labels[k] = v } return labels } // NewConfigLabels returns labels to apply for an Elasticsearch Config secret. func NewConfigLabels(es types.NamespacedName, ssetName string) map[string]string { return NewStatefulSetLabels(es, ssetName) } func NewStatefulSetLabels(es types.NamespacedName, ssetName string) map[string]string { lbls := NewLabels(es) lbls[StatefulSetNameLabelName] = ssetName return lbls } // NewLabelSelectorForElasticsearch returns a labels.Selector that matches the labels as constructed by NewLabels func NewLabelSelectorForElasticsearch(es esv1.Elasticsearch) client.MatchingLabels { return NewLabelSelectorForElasticsearchClusterName(es.Name) } // NewLabelSelectorForElasticsearchClusterName returns a labels.Selector that matches the labels as constructed by // NewLabels for the provided cluster name. func NewLabelSelectorForElasticsearchClusterName(clusterName string) client.MatchingLabels { return client.MatchingLabels(map[string]string{ClusterNameLabelName: clusterName}) } // NewLabelSelectorForStatefulSetName returns a labels.Selector that matches the labels set on resources managed for // a given StatefulSet in a cluster. func NewLabelSelectorForStatefulSetName(clusterName, ssetName string) client.MatchingLabels { return client.MatchingLabels(map[string]string{ ClusterNameLabelName: clusterName, StatefulSetNameLabelName: ssetName, }) } // ClusterFromResourceLabels returns the NamespacedName of the Elasticsearch associated // to the given resource, by retrieving its name from the resource labels. // It does implicitly consider the cluster and the resource to be in the same namespace. func ClusterFromResourceLabels(metaObject metav1.Object) (types.NamespacedName, bool) { resourceName, exists := metaObject.GetLabels()[ClusterNameLabelName] return types.NamespacedName{ Namespace: metaObject.GetNamespace(), Name: resourceName, }, exists }