From 3a95caa53d47a115eaaa0dffb1f4b919bff834a6 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 29 Dec 2025 16:25:06 +0100 Subject: [PATCH 01/10] Remove zen1 (ES 6.x) discovery support - Delete entire pkg/controller/elasticsearch/version/zen1/ package - Remove zen1 calls from driver layer (upscale, nodes, downscale) - Simplify updateZenSettingsForDownscale to only handle zen2 - Update expectations.go comments to remove zen1 references - Update tests to remove 6.x version fixtures This is part of removing Elasticsearch 6.x support from ECK. --- .../common/expectations/expectations.go | 6 +- .../elasticsearch/driver/downscale.go | 50 +---- .../elasticsearch/driver/downscale_test.go | 102 --------- .../elasticsearch/driver/expectations.go | 2 +- pkg/controller/elasticsearch/driver/nodes.go | 11 +- .../driver/upgrade_pods_deletion.go | 4 - .../elasticsearch/driver/upscale.go | 5 - .../driver/upscale_state_test.go | 6 +- .../elasticsearch/driver/upscale_test.go | 24 --- .../version/zen1/compatibility.go | 64 ------ .../version/zen1/compatibility_test.go | 141 ------------- .../version/zen1/minimum_masters.go | 143 ------------- .../version/zen1/minimum_masters_test.go | 194 ------------------ 13 files changed, 10 insertions(+), 742 deletions(-) delete mode 100644 pkg/controller/elasticsearch/version/zen1/compatibility.go delete mode 100644 pkg/controller/elasticsearch/version/zen1/compatibility_test.go delete mode 100644 pkg/controller/elasticsearch/version/zen1/minimum_masters.go delete mode 100644 pkg/controller/elasticsearch/version/zen1/minimum_masters_test.go diff --git a/pkg/controller/common/expectations/expectations.go b/pkg/controller/common/expectations/expectations.go index 61101e57b38..5da2e67e4a8 100644 --- a/pkg/controller/common/expectations/expectations.go +++ b/pkg/controller/common/expectations/expectations.go @@ -46,8 +46,8 @@ Things that could happen without this mechanism in place: - delete more than one master node at a time - outgrow the changeBudget during upscale and downscales - clear shards allocation excludes for a node that is not removed yet -- update zen1/zen2 minimum_master_nodes/initial_master_nodes based on the wrong number of nodes -- update zen1/zen2 minimum_master_nodes/initial_master_nodes based on the wrong nodes specification (ignoring master->data upgrades) +- update zen2 initial_master_nodes based on the wrong number of nodes +- update zen2 initial_master_nodes based on the wrong nodes specification (ignoring master->data upgrades) - clear voting_config_exclusions while a Pod has not finished its restart yet (or maybe just started) ## What if the operator restarts? @@ -64,7 +64,7 @@ No. In most situations, it's totally fine to rely on Kubernetes optimistic locki * if we delete a resource that does not exist, the operation fails The only cases where we need it are (so far): -- when interacting with external systems own orchestration mechanism (Elasticsearch zen1/zen2) +- when interacting with external systems own orchestration mechanism (Elasticsearch zen2) - when trying to control how many creations/deletions/upgrades happen in parallel ## Where does it come from? diff --git a/pkg/controller/elasticsearch/driver/downscale.go b/pkg/controller/elasticsearch/driver/downscale.go index dd10dc7e12f..b189e4ae48d 100644 --- a/pkg/controller/elasticsearch/driver/downscale.go +++ b/pkg/controller/elasticsearch/driver/downscale.go @@ -23,10 +23,8 @@ import ( esclient "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/nodespec" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/reconcile" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/settings" es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen1" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen2" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/stringsutil" @@ -293,8 +291,6 @@ func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale, actualS downscaleCtx.k8sClient, downscaleCtx.esClient, downscaleCtx.es, - downscaleCtx.reconcileState, - actualStatefulSets, downscale.leavingNodeNames()..., ); err != nil { return err @@ -312,57 +308,15 @@ func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale, actualS return nil } -// updateZenSettingsForDownscale makes sure zen1 and zen2 settings are updated to account for nodes +// updateZenSettingsForDownscale makes sure zen2 settings are updated to account for nodes // that will soon be removed. func updateZenSettingsForDownscale( ctx context.Context, c k8s.Client, esClient esclient.Client, es esv1.Elasticsearch, - reconcileState *reconcile.State, - actualStatefulSets es_sset.StatefulSetList, excludeNodes ...string, ) error { - // Maybe update zen1 minimum_master_nodes. - if err := maybeUpdateZen1ForDownscale(ctx, c, esClient, es, reconcileState, actualStatefulSets); err != nil { - return err - } - - // Maybe update zen2 settings to exclude leaving master nodes from voting. + // Update zen2 settings to exclude leaving master nodes from voting. return zen2.AddToVotingConfigExclusions(ctx, c, esClient, es, excludeNodes) } - -// maybeUpdateZen1ForDownscale updates zen1 minimum master nodes if we are downscaling from 2 to 1 master node. -func maybeUpdateZen1ForDownscale( - ctx context.Context, - c k8s.Client, - esClient esclient.Client, - es esv1.Elasticsearch, - reconcileState *reconcile.State, - actualStatefulSets es_sset.StatefulSetList) error { - // Check if we have at least one Zen1 compatible pod or StatefulSet in flight. - if zen1compatible, err := zen1.AtLeastOneNodeCompatibleWithZen1(ctx, actualStatefulSets, c, es); !zen1compatible || err != nil { - return err - } - - actualMasters, err := es_sset.GetActualMastersForCluster(c, es) - if err != nil { - return err - } - if len(actualMasters) != 2 { - // not in the 2->1 situation - return nil - } - - // We are moving from 2 to 1 master nodes, we need to update minimum_master_nodes before removing - // the 2nd node, otherwise the cluster won't be able to form anymore. - // This is inherently unsafe (can cause split brains), but there's no alternative. - // For other situations (eg. 3 -> 2), it's fine to update minimum_master_nodes after the node is removed - // (will be done at next reconciliation, before nodes removal). - reconcileState.AddEvent( - corev1.EventTypeWarning, events.EventReasonUnhealthy, - "Downscaling from 2 to 1 master nodes: unsafe operation", - ) - minimumMasterNodes := 1 - return zen1.UpdateMinimumMasterNodesTo(ctx, es, esClient, minimumMasterNodes) -} diff --git a/pkg/controller/elasticsearch/driver/downscale_test.go b/pkg/controller/elasticsearch/driver/downscale_test.go index 19075675cca..39102be3d5c 100644 --- a/pkg/controller/elasticsearch/driver/downscale_test.go +++ b/pkg/controller/elasticsearch/driver/downscale_test.go @@ -23,7 +23,6 @@ import ( "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/expectations" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/metadata" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/reconciler" - controllerscheme "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/scheme" sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" esclient "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" @@ -995,107 +994,6 @@ func Test_doDownscale_zen2VotingConfigExclusions(t *testing.T) { // check call to zen2 is the expected one require.Equal(t, tt.wantZen2Called, esClient.AddVotingConfigExclusionsCalled) require.Equal(t, tt.wantZen2CalledWith, esClient.AddVotingConfigExclusionsCalledWith) - // check zen1 was not called - require.False(t, esClient.SetMinimumMasterNodesCalled) - }) - } -} - -func Test_doDownscale_zen1MinimumMasterNodes(t *testing.T) { - controllerscheme.SetupScheme() - es := esv1.Elasticsearch{ObjectMeta: metav1.ObjectMeta{Namespace: ssetMaster3Replicas.Namespace, Name: "es"}} - ssetMasters := sset.TestSset{Name: "masters", Version: "6.8.0", Replicas: 3, Master: true, Data: false}.Build() - masterPods := []corev1.Pod{ - sset.TestPod{ - Namespace: ssetMaster3Replicas.Namespace, - Name: ssetMaster3Replicas.Name + "-0", - ClusterName: es.Name, - StatefulSetName: ssetMaster3Replicas.Name, - Version: "6.8.0", - Master: true, - }.Build(), - sset.TestPod{ - Namespace: ssetMaster3Replicas.Namespace, - Name: ssetMaster3Replicas.Name + "-1", - ClusterName: es.Name, - StatefulSetName: ssetMaster3Replicas.Name, - Version: "6.8.0", - Master: true, - }.Build(), - sset.TestPod{ - Namespace: ssetMaster3Replicas.Namespace, - Name: ssetMaster3Replicas.Name + "-2", - ClusterName: es.Name, - StatefulSetName: ssetMaster3Replicas.Name, - Version: "6.8.0", - Master: true, - }.Build(), - } - ssetData := sset.TestSset{Name: "datas", Version: "6.8.0", Replicas: 3, Master: false, Data: true}.Build() - tests := []struct { - name string - downscale ssetDownscale - statefulSets es_sset.StatefulSetList - apiserverResources []client.Object - wantZen1Called bool - wantZen1CalledWith int - }{ - { - name: "3 -> 2 master nodes", - downscale: ssetDownscale{ - statefulSet: ssetMasters, - initialReplicas: 3, - targetReplicas: 2, - }, - statefulSets: es_sset.StatefulSetList{ssetMasters}, - apiserverResources: []client.Object{&es, &ssetMasters, &masterPods[0], &masterPods[1], &masterPods[2]}, - wantZen1Called: false, - }, - { - name: "3 -> 2 data nodes", - downscale: ssetDownscale{ - statefulSet: ssetData, - initialReplicas: 3, - targetReplicas: 2, - }, - statefulSets: es_sset.StatefulSetList{ssetMasters, ssetData}, - apiserverResources: []client.Object{&es, &ssetMasters, &ssetData, &masterPods[0], &masterPods[1], &masterPods[2]}, - wantZen1Called: false, - }, - { - name: "2 -> 1 master nodes", - downscale: ssetDownscale{ - statefulSet: ssetMasters, - initialReplicas: 2, - targetReplicas: 1, - }, - statefulSets: es_sset.StatefulSetList{ssetMasters}, - // 2 master nodes in the apiserver - apiserverResources: []client.Object{&es, &ssetMasters, &masterPods[0], &masterPods[1]}, - wantZen1Called: true, - wantZen1CalledWith: 1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - k8sClient := k8s.NewFakeClient(tt.apiserverResources...) - esClient := &fakeESClient{} - downscaleCtx := downscaleContext{ - k8sClient: k8sClient, - expectations: expectations.NewExpectations(k8sClient), - reconcileState: reconcile.MustNewState(esv1.Elasticsearch{}), - esClient: esClient, - es: es, - parentCtx: context.Background(), - } - // do the downscale - err := doDownscale(downscaleCtx, tt.downscale, tt.statefulSets) - require.NoError(t, err) - // check call to zen1 is the expected one - require.Equal(t, tt.wantZen1Called, esClient.SetMinimumMasterNodesCalled) - require.Equal(t, tt.wantZen1CalledWith, esClient.SetMinimumMasterNodesCalledWith) - // check zen2 was not called - require.False(t, esClient.AddVotingConfigExclusionsCalled) }) } } diff --git a/pkg/controller/elasticsearch/driver/expectations.go b/pkg/controller/elasticsearch/driver/expectations.go index 6e2dba6ae46..654fd38b5c1 100644 --- a/pkg/controller/elasticsearch/driver/expectations.go +++ b/pkg/controller/elasticsearch/driver/expectations.go @@ -17,7 +17,7 @@ import ( // expectationsSatisfied checks that resources in our local cache match what we expect. // If not, it's safer to not move on with StatefulSets and Pods reconciliation. // Continuing with the reconciliation at this point may lead to: -// - calling ES orchestration settings (zen1/zen2/allocation excludes) with wrong assumptions +// - calling ES orchestration settings (zen2/allocation excludes) with wrong assumptions // (eg. incorrect number of nodes or master-eligible nodes topology) // - create or delete more than one master node at once func (d *defaultDriver) expectationsSatisfied(ctx context.Context) (bool, string, error) { diff --git a/pkg/controller/elasticsearch/driver/nodes.go b/pkg/controller/elasticsearch/driver/nodes.go index d0468327c2d..0ffec659465 100644 --- a/pkg/controller/elasticsearch/driver/nodes.go +++ b/pkg/controller/elasticsearch/driver/nodes.go @@ -26,7 +26,6 @@ import ( "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/pdb" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/reconcile" es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen1" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen2" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" @@ -164,16 +163,8 @@ func (d *defaultDriver) reconcileNodeSpecs( return results.WithReconciliationState(defaultRequeue.WithReason(msg)) } - // Maybe update Zen1 minimum master nodes through the API, corresponding to the current nodes we have. - requeue, err := zen1.UpdateMinimumMasterNodes(ctx, d.Client, d.ES, esClient, actualStatefulSets) - if err != nil { - return results.WithError(err) - } - if requeue { - results.WithReconciliationState(defaultRequeue.WithReason("Not enough available masters to update Zen1 settings")) - } // Remove the zen2 bootstrap annotation if bootstrap is over. - requeue, err = zen2.RemoveZen2BootstrapAnnotation(ctx, d.Client, d.ES, esClient) + requeue, err := zen2.RemoveZen2BootstrapAnnotation(ctx, d.Client, d.ES, esClient) if err != nil { return results.WithError(err) } diff --git a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go index d2f5f04e43c..2b6124ab0c4 100644 --- a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go +++ b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go @@ -187,10 +187,8 @@ func sortCandidates(allPods []corev1.Pod) { // handleMasterScaleChange handles Zen updates when a type change results in the addition or the removal of a master: // In case of a master scale down it shares the same logic that a "traditional" scale down: -// * We proactively set m_m_n to the value of 1 if there are 2 Zen1 masters left // * We exclude the master for Zen2 // In case of a master scale up there's nothing else to do: -// * If there are Zen1 nodes m_m_n is updated prior the update of the StatefulSet in HandleUpscaleAndSpecChanges // * Because of the design of Zen2 there's nothing else to do for it. func (ctx *upgradeCtx) handleMasterScaleChange(pod corev1.Pod) error { masterScaleDown := label.IsMasterNode(pod) && !stringsutil.StringInSlice(pod.Name, ctx.expectedMasters) @@ -200,8 +198,6 @@ func (ctx *upgradeCtx) handleMasterScaleChange(pod corev1.Pod) error { ctx.client, ctx.esClient, ctx.ES, - ctx.reconcileState, - ctx.statefulSets, pod.Name, ); err != nil { return err diff --git a/pkg/controller/elasticsearch/driver/upscale.go b/pkg/controller/elasticsearch/driver/upscale.go index 7a55d7378e3..cb13f883401 100644 --- a/pkg/controller/elasticsearch/driver/upscale.go +++ b/pkg/controller/elasticsearch/driver/upscale.go @@ -24,7 +24,6 @@ import ( "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/reconcile" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/settings" es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen1" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen2" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" @@ -228,10 +227,6 @@ func adjustResources( } func adjustZenConfig(ctx context.Context, k8sClient k8s.Client, es esv1.Elasticsearch, resources nodespec.ResourcesList) error { - // patch configs to consider zen1 minimum master nodes - if err := zen1.SetupMinimumMasterNodesConfig(ctx, k8sClient, es, resources); err != nil { - return err - } // patch configs to consider zen2 initial master nodes return zen2.SetupInitialMasterNodes(ctx, es, k8sClient, resources) } diff --git a/pkg/controller/elasticsearch/driver/upscale_state_test.go b/pkg/controller/elasticsearch/driver/upscale_state_test.go index 542b66c01a0..9b087d6b51e 100644 --- a/pkg/controller/elasticsearch/driver/upscale_state_test.go +++ b/pkg/controller/elasticsearch/driver/upscale_state_test.go @@ -41,9 +41,9 @@ func Test_upscaleState_limitNodesCreation(t *testing.T) { { name: "spec change (same replicas)", state: &upscaleState{}, - actual: sset.TestSset{Name: "sset", Version: "6.8.0", Replicas: 3, Master: true}.Build(), - ssetToApply: sset.TestSset{Name: "sset", Version: "7.2.0", Replicas: 3, Master: true}.Build(), - wantSset: sset.TestSset{Name: "sset", Version: "7.2.0", Replicas: 3, Master: true}.Build(), + actual: sset.TestSset{Name: "sset", Version: "7.17.0", Replicas: 3, Master: true}.Build(), + ssetToApply: sset.TestSset{Name: "sset", Version: "8.0.0", Replicas: 3, Master: true}.Build(), + wantSset: sset.TestSset{Name: "sset", Version: "8.0.0", Replicas: 3, Master: true}.Build(), wantState: &upscaleState{}, }, { diff --git a/pkg/controller/elasticsearch/driver/upscale_test.go b/pkg/controller/elasticsearch/driver/upscale_test.go index 2e986be6f54..68d61d73b91 100644 --- a/pkg/controller/elasticsearch/driver/upscale_test.go +++ b/pkg/controller/elasticsearch/driver/upscale_test.go @@ -432,40 +432,18 @@ func Test_adjustZenConfig(t *testing.T) { es esv1.Elasticsearch statefulSet sset.TestSset pods []client.Object - wantMinimumMasterNodesSet bool wantInitialMasterNodesSet bool }{ - { - name: "adjust zen1 minimum_master_nodes", - es: bootstrappedES, - statefulSet: sset.TestSset{Version: "6.8.0", Replicas: 3, Master: true, Data: true}, - wantMinimumMasterNodesSet: true, - wantInitialMasterNodesSet: false, - }, - { - name: "adjust zen1 minimum_master_nodes if some 6.8.x are still in flight", - es: bootstrappedES, - statefulSet: sset.TestSset{Name: "masters", Version: "7.2.0", Replicas: 3, Master: true, Data: true}, - pods: []client.Object{ - newTestPod("masters-0").withVersion("6.8.0").withRoles(esv1.MasterRole, esv1.DataRole).toPodPtr(), - newTestPod("masters-1").withVersion("6.8.0").withRoles(esv1.MasterRole, esv1.DataRole).toPodPtr(), - newTestPod("masters-2").withVersion("6.8.0").withRoles(esv1.MasterRole, esv1.DataRole).toPodPtr(), - }, - wantMinimumMasterNodesSet: true, - wantInitialMasterNodesSet: false, - }, { name: "adjust zen2 initial master nodes when cluster is not bootstrapped yet", es: notBootstrappedES, statefulSet: sset.TestSset{Version: "7.2.0", Replicas: 3, Master: true, Data: true}, - wantMinimumMasterNodesSet: false, wantInitialMasterNodesSet: true, }, { name: "don't adjust zen2 initial master nodes when cluster is already bootstrapped", es: bootstrappedES, statefulSet: sset.TestSset{Version: "7.2.0", Replicas: 3, Master: true, Data: true}, - wantMinimumMasterNodesSet: false, wantInitialMasterNodesSet: false, }, } @@ -485,8 +463,6 @@ func Test_adjustZenConfig(t *testing.T) { err := adjustZenConfig(context.Background(), client, tt.es, resources) require.NoError(t, err) for _, res := range resources { - hasMinimumMasterNodes := len(res.Config.HasKeys([]string{esv1.DiscoveryZenMinimumMasterNodes})) > 0 - require.Equal(t, tt.wantMinimumMasterNodesSet, hasMinimumMasterNodes) hasInitialMasterNodes := len(res.Config.HasKeys([]string{esv1.ClusterInitialMasterNodes})) > 0 require.Equal(t, tt.wantInitialMasterNodesSet, hasInitialMasterNodes) } diff --git a/pkg/controller/elasticsearch/version/zen1/compatibility.go b/pkg/controller/elasticsearch/version/zen1/compatibility.go deleted file mode 100644 index 1f4afb6644f..00000000000 --- a/pkg/controller/elasticsearch/version/zen1/compatibility.go +++ /dev/null @@ -1,64 +0,0 @@ -// 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 zen1 - -import ( - "context" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" -) - -// versionCompatibleWithZen1 returns true if the given Elasticsearch version is compatible with zen1. -func versionCompatibleWithZen1(v version.Version) bool { - return v.Major < 7 -} - -// IsCompatibleWithZen1 returns true if the given StatefulSet is compatible with zen1. -func IsCompatibleWithZen1(ctx context.Context, statefulSet appsv1.StatefulSet) bool { - return sset.ESVersionMatch(ctx, statefulSet, versionCompatibleWithZen1) -} - -// AtLeastOneNodeCompatibleWithZen1 returns true if at least one of the following conditions is true: -// 1. There is at least one 6.x node in the actual masters. -// 2. The given StatefulSetList contains at least one StatefulSet compatible with zen1. -func AtLeastOneNodeCompatibleWithZen1( - ctx context.Context, - statefulSets sset.StatefulSetList, - c k8s.Client, - es esv1.Elasticsearch, -) (bool, error) { - actualMasters, err := sset.GetActualMastersForCluster(c, es) - if err != nil { - return false, err - } - zen1PodExists, err := atLeasOnePodCompatibleWithZen1(actualMasters) - if err != nil { - return false, err - } - if zen1PodExists { - return true, nil - } - return statefulSets.AtLeastOneESVersionMatch(ctx, versionCompatibleWithZen1), nil -} - -func atLeasOnePodCompatibleWithZen1(pods []corev1.Pod) (bool, error) { - for _, pod := range pods { - version, err := label.ExtractVersion(pod.Labels) - if err != nil { - return false, err - } - if versionCompatibleWithZen1(version) { - return true, nil - } - } - return false, nil -} diff --git a/pkg/controller/elasticsearch/version/zen1/compatibility_test.go b/pkg/controller/elasticsearch/version/zen1/compatibility_test.go deleted file mode 100644 index 7284f63a580..00000000000 --- a/pkg/controller/elasticsearch/version/zen1/compatibility_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// 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 zen1 - -import ( - "context" - "testing" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" -) - -func createStatefulSetWithVersion(version string) appsv1.StatefulSet { - return appsv1.StatefulSet{Spec: appsv1.StatefulSetSpec{Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - label.VersionLabelName: version, - }, - }, - }}} -} - -var testES = esv1.Elasticsearch{ - ObjectMeta: metav1.ObjectMeta{ - Name: "es1", - Namespace: "default", - }, -} - -func createMasterPodsWithVersion(ssetName, version string, replicas int32) []client.Object { - pods := make([]client.Object, replicas) - for i := int32(0); i < replicas; i++ { - pod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: sset.PodName(ssetName, i), - Namespace: "default", - Labels: map[string]string{ - label.VersionLabelName: version, - label.ClusterNameLabelName: "es1", - }, - }, - } - label.NodeTypesMasterLabelName.Set(true, pod.Labels) - pods[i] = pod - } - return pods -} - -func TestIsCompatibleWithZen1(t *testing.T) { - tests := []struct { - name string - sset appsv1.StatefulSet - want bool - }{ - { - name: "version 6.8.0", - sset: createStatefulSetWithVersion("6.8.0"), - want: true, - }, - { - name: "version 7.0.0", - sset: createStatefulSetWithVersion("7.0.0"), - want: false, - }, - { - name: "no version", - sset: createStatefulSetWithVersion(""), - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IsCompatibleWithZen1(context.Background(), tt.sset); got != tt.want { - t.Errorf("IsCompatibleWithZen1() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestAtLeastOneNodeCompatibleWithZen1(t *testing.T) { - tests := []struct { - name string - statefulSets es_sset.StatefulSetList - client k8s.Client - want bool - wantErr bool - }{ - { - name: "no sset", - statefulSets: nil, - client: k8s.NewFakeClient(), - want: false, - }, - { - name: "none compatible", - statefulSets: es_sset.StatefulSetList{createStatefulSetWithVersion("7.0.0"), createStatefulSetWithVersion("7.1.0")}, - client: k8s.NewFakeClient(), - want: false, - }, - { - name: "one compatible", - statefulSets: es_sset.StatefulSetList{createStatefulSetWithVersion("6.8.0"), createStatefulSetWithVersion("7.1.0")}, - client: k8s.NewFakeClient(), - want: true, - }, - { - name: "all compatible", - statefulSets: es_sset.StatefulSetList{createStatefulSetWithVersion("6.8.0"), createStatefulSetWithVersion("6.9.0")}, - client: k8s.NewFakeClient(), - want: true, - }, - { - name: "Version in StatefulSet spec in 7.2.0 but there're still some 6.8.0 in flight", - statefulSets: es_sset.StatefulSetList{createStatefulSetWithVersion("7.2.0")}, - client: k8s.NewFakeClient(createMasterPodsWithVersion("foo", "6.8.0", 5)...), - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := AtLeastOneNodeCompatibleWithZen1(context.Background(), tt.statefulSets, tt.client, testES) - if (err != nil) != tt.wantErr { - t.Errorf("runPredicates error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("AtLeastOneNodeCompatibleWithZen1() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/controller/elasticsearch/version/zen1/minimum_masters.go b/pkg/controller/elasticsearch/version/zen1/minimum_masters.go deleted file mode 100644 index 3d94434bd23..00000000000 --- a/pkg/controller/elasticsearch/version/zen1/minimum_masters.go +++ /dev/null @@ -1,143 +0,0 @@ -// 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 zen1 - -import ( - "context" - "strconv" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - common "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/settings" - sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/nodespec" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/settings" - es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" - ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" -) - -// SetupMinimumMasterNodesConfig modifies the ES config of the given resources to setup -// zen1 minimum master nodes. -// This function should not be called unless all the expectations are met. -func SetupMinimumMasterNodesConfig( - ctx context.Context, - c k8s.Client, - es esv1.Elasticsearch, - nodeSpecResources nodespec.ResourcesList, -) error { - // Check if we have at least one Zen1 compatible pod or StatefulSet in flight. - if zen1compatible, err := AtLeastOneNodeCompatibleWithZen1( - ctx, - nodeSpecResources.StatefulSets(), c, es, - ); !zen1compatible || err != nil { - return err - } - - // There are 2 possible situations here: - // 1. The StatefulSet contains some masters: use the replicas to set m_m_n in the configuration file. - // 2. The StatefulSet does not contain any master but there are some existing Pods: we should NOT rely on the spec - // of the StatefulSet since it might not reflect the situation, the node type "master" might just have been changed - // and a rolling upgrade is maybe in progress. - // In this case some masters are maybe still alive, decreasing m_m_n in the config could lead to a split brain - // situation if the container (not the Pod) restarts. - masters := 0 - for _, resource := range nodeSpecResources { - resource := resource - if label.IsMasterNodeSet(resource.StatefulSet) { - // First situation: just check for the replicas - masters += int(sset.GetReplicas(resource.StatefulSet)) - } else { - // Second situation: not a sset of masters, but we check if there are some of them waiting for a rolling upgrade - actualPods, err := es_sset.GetActualPodsForStatefulSet(c, k8s.ExtractNamespacedName(&resource.StatefulSet)) - if err != nil { - return err - } - actualMasters := len(label.FilterMasterNodePods(actualPods)) - masters += actualMasters - } - } - - quorum := settings.Quorum(masters) - - for i := range nodeSpecResources { - // patch config with the expected minimum master nodes - if err := nodeSpecResources[i].Config.MergeWith( - common.MustNewSingleValue( - esv1.DiscoveryZenMinimumMasterNodes, - strconv.Itoa(quorum), - ), - ); err != nil { - return err - } - } - return nil -} - -// UpdateMinimumMasterNodes calls the ES API to update the minimum_master_nodes setting if required, -// based on nodes currently running in the cluster. -// It returns true if this should be retried later (re-queued). -func UpdateMinimumMasterNodes( - ctx context.Context, - c k8s.Client, - es esv1.Elasticsearch, - esClient client.Client, - actualStatefulSets es_sset.StatefulSetList, -) (bool, error) { - // Check if we have at least one Zen1 compatible pod or StatefulSet in flight. - if zen1compatible, err := AtLeastOneNodeCompatibleWithZen1(ctx, actualStatefulSets, c, es); !zen1compatible || err != nil { - return false, err - } - - actualMasters, err := es_sset.GetActualMastersForCluster(c, es) - if err != nil { - return false, err - } - - // Get current master nodes count - currentMasterCount := len(actualMasters) - currentAvailableMasterCount := 0 - for _, p := range actualMasters { - if k8s.IsPodReady(p) { - currentAvailableMasterCount++ - } - } - // Calculate minimum_master_nodes based on that. - minimumMasterNodes := settings.Quorum(currentMasterCount) - - // Do not attempt to make an API call if there is not enough available masters - if currentAvailableMasterCount < minimumMasterNodes { - // This is expected to happen from time to time - ulog.FromContext(ctx).V(1).Info("Not enough masters to update the API", - "namespace", es.Namespace, - "es_name", es.Name, - "current", currentAvailableMasterCount, - "minimum_master_nodes", minimumMasterNodes) - // We can't update the minimum master nodes right now, it is the case if a new master node is not created yet. - // In that case we need to requeue later. - return true, nil - } - - return false, UpdateMinimumMasterNodesTo(ctx, es, esClient, minimumMasterNodes) -} - -// UpdateMinimumMasterNodesTo calls the ES API to update the value of zen1 minimum_master_nodes -// to the given value, if the cluster is using zen1. -// Should only be called it there are some Zen1 compatible masters -func UpdateMinimumMasterNodesTo( - ctx context.Context, - es esv1.Elasticsearch, - esClient client.Client, - minimumMasterNodes int, -) error { - ulog.FromContext(ctx).Info("Updating minimum master nodes", - "how", "api", - "namespace", es.Namespace, - "es_name", es.Name, - "minimum_master_nodes", minimumMasterNodes, - ) - return esClient.SetMinimumMasterNodes(ctx, minimumMasterNodes) -} diff --git a/pkg/controller/elasticsearch/version/zen1/minimum_masters_test.go b/pkg/controller/elasticsearch/version/zen1/minimum_masters_test.go deleted file mode 100644 index 20ea2674dcf..00000000000 --- a/pkg/controller/elasticsearch/version/zen1/minimum_masters_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// 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 zen1 - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - crclient "sigs.k8s.io/controller-runtime/pkg/client" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - controllerscheme "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/scheme" - settings2 "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/settings" - sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/nodespec" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/settings" - es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" -) - -func TestSetupMinimumMasterNodesConfig(t *testing.T) { - tests := []struct { - name string - nodeSpecResources nodespec.ResourcesList - expected []settings.CanonicalConfig - pods []crclient.Object - }{ - { - name: "no master nodes", - nodeSpecResources: nodespec.ResourcesList{ - {StatefulSet: sset.TestSset{Name: "data", Version: "7.1.0", Replicas: 3, Master: false, Data: true}.Build(), Config: settings.NewCanonicalConfig()}, - }, - expected: []settings.CanonicalConfig{settings.NewCanonicalConfig()}, - pods: createMasterPodsWithVersion("data", "7.1.0", 3), - }, - { - name: "3 masters, 3 master+data, 3 data", - nodeSpecResources: nodespec.ResourcesList{ - {StatefulSet: sset.TestSset{Name: "master", Version: "6.8.0", Replicas: 3, Master: true, Data: false}.Build(), Config: settings.NewCanonicalConfig()}, - {StatefulSet: sset.TestSset{Name: "masterdata", Version: "6.8.0", Replicas: 3, Master: true, Data: true}.Build(), Config: settings.NewCanonicalConfig()}, - {StatefulSet: sset.TestSset{Name: "data", Version: "6.8.0", Replicas: 3, Master: false, Data: true}.Build(), Config: settings.NewCanonicalConfig()}, - }, - expected: []settings.CanonicalConfig{ - {CanonicalConfig: settings2.MustCanonicalConfig(map[string]string{ - esv1.DiscoveryZenMinimumMasterNodes: "4", - })}, - {CanonicalConfig: settings2.MustCanonicalConfig(map[string]string{ - esv1.DiscoveryZenMinimumMasterNodes: "4", - })}, - {CanonicalConfig: settings2.MustCanonicalConfig(map[string]string{ - esv1.DiscoveryZenMinimumMasterNodes: "4", - })}, - }, - pods: []crclient.Object{}, - }, - { - name: "v7 in the spec but still have some 6.x in flight", - nodeSpecResources: nodespec.ResourcesList{ - {StatefulSet: sset.TestSset{Name: "masterv7", Version: "7.1.0", Replicas: 3, Master: true, Data: false}.Build(), Config: settings.NewCanonicalConfig()}, - }, - expected: []settings.CanonicalConfig{ - {CanonicalConfig: settings2.MustCanonicalConfig(map[string]string{ - esv1.DiscoveryZenMinimumMasterNodes: "2", - })}, - settings.NewCanonicalConfig(), - }, - pods: createMasterPodsWithVersion("data", "6.8.0", 3), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - client := k8s.NewFakeClient(tt.pods...) - err := SetupMinimumMasterNodesConfig(context.Background(), client, testES, tt.nodeSpecResources) - require.NoError(t, err) - for i := 0; i < len(tt.nodeSpecResources); i++ { - expected, err := tt.expected[i].Render() - require.NoError(t, err) - actual, err := tt.nodeSpecResources[i].Config.Render() - require.NoError(t, err) - require.Equal(t, expected, actual) - } - }) - } -} - -type fakeESClient struct { - called bool - calledWith int - client.Client -} - -func (f *fakeESClient) SetMinimumMasterNodes(_ context.Context, count int) error { - f.called = true - f.calledWith = count - return nil -} - -func TestUpdateMinimumMasterNodes(t *testing.T) { - controllerscheme.SetupScheme() - esName := "es" - ns := "ns" - nsn := types.NamespacedName{Name: esName, Namespace: ns} - ssetSample := sset.TestSset{Name: "nodes", Namespace: ns, ClusterName: esName, Version: "6.8.0", Replicas: 3, Master: true, Data: true}.Build() - // simulate 3/3 pods ready - labels := map[string]string{ - label.StatefulSetNameLabelName: ssetSample.Name, - label.VersionLabelName: "6.8.0", - label.ClusterNameLabelName: esName, - } - label.NodeTypesMasterLabelName.Set(true, labels) - label.NodeTypesDataLabelName.Set(true, labels) - podsReady3 := make([]corev1.Pod, 0, 3) - for _, podName := range sset.PodNames(ssetSample) { - podsReady3 = append(podsReady3, corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: ssetSample.Namespace, - Name: podName, - Labels: labels, - }, - Status: corev1.PodStatus{ - Conditions: []corev1.PodCondition{ - { - Status: corev1.ConditionTrue, - Type: corev1.ContainersReady, - }, - { - Status: corev1.ConditionTrue, - Type: corev1.PodReady, - }, - }, - }, - }) - } - // simulate 1/3 pods ready - podsReady1 := make([]corev1.Pod, 3) - podsReady1[0] = *podsReady3[0].DeepCopy() - podsReady1[0].Status.Conditions[0].Status = corev1.ConditionFalse - podsReady1[1] = *podsReady3[1].DeepCopy() - podsReady1[1].Status.Conditions[0].Status = corev1.ConditionFalse - podsReady1[2] = *podsReady3[2].DeepCopy() - - tests := []struct { - wantCalled bool - wantRequeue bool - wantCalledWith int - c k8s.Client - es esv1.Elasticsearch - name string - actualStatefulSets es_sset.StatefulSetList - }{ - { - name: "no v6 nodes", - actualStatefulSets: es_sset.StatefulSetList{sset.TestSset{Name: "nodes", Namespace: ns, Version: "7.1.0", Replicas: 3, Master: true, Data: true}.Build()}, - es: esv1.Elasticsearch{ObjectMeta: k8s.ToObjectMeta(nsn)}, - wantCalled: false, - c: k8s.NewFakeClient(createMasterPodsWithVersion("nodes", "7.1.0", 3)...), - }, - { - name: "mmn should be updated", - c: k8s.NewFakeClient(&podsReady3[0], &podsReady3[1], &podsReady3[2]), - actualStatefulSets: es_sset.StatefulSetList{ssetSample}, - es: esv1.Elasticsearch{ObjectMeta: k8s.ToObjectMeta(nsn)}, - wantCalled: true, - wantCalledWith: 2, - }, - { - name: "cannot update since not enough masters available", - c: k8s.NewFakeClient(&podsReady1[0], &podsReady1[1], &podsReady1[2]), - actualStatefulSets: es_sset.StatefulSetList{ssetSample}, - es: esv1.Elasticsearch{ObjectMeta: k8s.ToObjectMeta(nsn)}, - wantCalled: false, - wantRequeue: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require.NoError(t, tt.c.Create(context.Background(), &tt.es)) - esClient := &fakeESClient{} - requeue, err := UpdateMinimumMasterNodes(context.Background(), tt.c, tt.es, esClient, tt.actualStatefulSets) - require.NoError(t, err) - require.Equal(t, tt.wantRequeue, requeue) - require.Equal(t, tt.wantCalled, esClient.called) - require.Equal(t, tt.wantCalledWith, esClient.calledWith) - }) - } -} From 3875f1034da3624b741522de98d17da90567bda6 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 29 Dec 2025 16:40:44 +0100 Subject: [PATCH 02/10] Simplify zen2 package by removing v6 upgrade logic - Remove nonHAZen1MasterUpgrade() function from initial_master_nodes.go - Simplify shouldSetInitialMasterNodes() to only check bootstrap state - Remove unused imports (sset, es_sset, set) - Update tests to remove v6-related test cases - Update compatibility_test.go to use v7/v8 versions This is part of removing Elasticsearch 6.x support from ECK. --- .../version/zen2/compatibility_test.go | 27 ++-- .../version/zen2/initial_master_nodes.go | 72 +---------- .../version/zen2/initial_master_nodes_test.go | 117 +----------------- .../version/zen2/voting_exclusions_test.go | 23 ---- 4 files changed, 16 insertions(+), 223 deletions(-) diff --git a/pkg/controller/elasticsearch/version/zen2/compatibility_test.go b/pkg/controller/elasticsearch/version/zen2/compatibility_test.go index 72017fccef2..7cba8b81b0f 100644 --- a/pkg/controller/elasticsearch/version/zen2/compatibility_test.go +++ b/pkg/controller/elasticsearch/version/zen2/compatibility_test.go @@ -36,16 +36,16 @@ func TestIsCompatibleWithZen2(t *testing.T) { sset appsv1.StatefulSet want bool }{ - { - name: "versionCompatibleWithZen2 6.8.0", - sset: createStatefulSetWithESVersion("6.8.0"), - want: false, - }, { name: "versionCompatibleWithZen2 7.0.0", sset: createStatefulSetWithESVersion("7.0.0"), want: true, }, + { + name: "versionCompatibleWithZen2 8.0.0", + sset: createStatefulSetWithESVersion("8.0.0"), + want: true, + }, { name: "no versionCompatibleWithZen2", sset: createStatefulSetWithESVersion(""), @@ -83,21 +83,12 @@ func TestAllMastersCompatibleWithZen2(t *testing.T) { want: true, }, { - name: "only v6 master nodes (with v7 data nodes)", + name: "mixed v7/v8 masters", pods: []client.Object{ - sset.TestPod{Namespace: es.Namespace, Name: "node0", ClusterName: es.Name, Version: "6.8.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node1", ClusterName: es.Name, Version: "6.8.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node2", ClusterName: es.Name, Version: "7.2.0", Data: true}.BuildPtr(), + sset.TestPod{Namespace: es.Namespace, Name: "node0", ClusterName: es.Name, Version: "8.0.0", Master: true}.BuildPtr(), + sset.TestPod{Namespace: es.Namespace, Name: "node1", ClusterName: es.Name, Version: "7.17.0", Master: true}.BuildPtr(), }, - want: false, - }, - { - name: "mixed v6/v7 masters", - pods: []client.Object{ - sset.TestPod{Namespace: es.Namespace, Name: "node0", ClusterName: es.Name, Version: "7.2.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node1", ClusterName: es.Name, Version: "6.8.0", Master: true}.BuildPtr(), - }, - want: false, + want: true, }, { name: "no pods", diff --git a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go index 3404974bde8..c6dbc78261e 100644 --- a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go +++ b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go @@ -11,16 +11,13 @@ import ( pkgerrors "github.com/pkg/errors" esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/nodespec" - es_sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/set" ) const ( @@ -31,8 +28,7 @@ const ( // SetupInitialMasterNodes sets the `cluster.initial_master_nodes` configuration setting on // zen2-compatible master nodes from nodeSpecResources if necessary. -// This is only necessary when bootstrapping a new zen2 cluster, or when upgrading a single zen1 master. -// Rolling upgrades from eg. v6 to v7 do not need that setting. +// This is only necessary when bootstrapping a new zen2 cluster. // It ensures `cluster.initial_master_nodes` does not vary over time, when this function gets called multiple times. func SetupInitialMasterNodes(ctx context.Context, es esv1.Elasticsearch, k8sClient k8s.Client, nodeSpecResources nodespec.ResourcesList) error { // if the cluster is annotated with `cluster.initial_master_nodes` (zen2 bootstrap in progress), @@ -42,7 +38,7 @@ func SetupInitialMasterNodes(ctx context.Context, es esv1.Elasticsearch, k8sClie } // in most cases, `cluster.initial_master_nodes` should not be set - shouldSetup, err := shouldSetInitialMasterNodes(es, k8sClient, nodeSpecResources) + shouldSetup, err := shouldSetInitialMasterNodes(es) if err != nil { return err } @@ -67,18 +63,13 @@ func SetupInitialMasterNodes(ctx context.Context, es esv1.Elasticsearch, k8sClie return setInitialMasterNodesAnnotation(ctx, k8sClient, es, initialMasterNodes) } -func shouldSetInitialMasterNodes(es esv1.Elasticsearch, k8sClient k8s.Client, nodeSpecResources nodespec.ResourcesList) (bool, error) { +func shouldSetInitialMasterNodes(es esv1.Elasticsearch) (bool, error) { if v, err := version.Parse(es.Spec.Version); err != nil || !versionCompatibleWithZen2(v) { // we only care about zen2-compatible clusters here return false, err } - // we want to set `cluster.initial_master_nodes` if: - // - a new cluster is getting created (not already bootstrapped) - if !bootstrap.AnnotatedForBootstrap(es) { - return true, nil - } - // - we're upgrading (effectively restarting) a non-HA zen1 cluster to zen2 - return nonHAZen1MasterUpgrade(k8sClient, es, nodeSpecResources) + // Set cluster.initial_master_nodes only when a new cluster is getting created (not already bootstrapped) + return !bootstrap.AnnotatedForBootstrap(es), nil } // RemoveZen2BootstrapAnnotation removes the initialMasterNodesAnnotation (if set) once zen2 is bootstrapped @@ -126,59 +117,6 @@ func patchInitialMasterNodesConfig(ctx context.Context, nodeSpecResources nodesp return nil } -// nonHAZen1MasterUpgrade returns true if expected nodes in nodeSpecResources will lead to upgrading -// the one or two zen1-compatible master nodes currently running in the es cluster. -// As we upgrade all nodes at once in one or two node clusters initial master nodes needs to be set as there is no -// existing cluster to join once all v6 nodes have been terminated. -func nonHAZen1MasterUpgrade(c k8s.Client, es esv1.Elasticsearch, nodeSpecResources nodespec.ResourcesList) (bool, error) { - // looking for a non-HA master node setup... - masters, err := es_sset.GetActualMastersForCluster(c, es) - if err != nil { - return false, err - } - if len(masters) > 2 { - return false, nil - } - - currentMasterNames := set.Make() - for _, currentMaster := range masters { - currentMasterNames.Add(currentMaster.Name) - // ...not compatible with zen2... - v, err := label.ExtractVersion(currentMaster.Labels) - if err != nil { - return false, err - } - // at least one master is already on Zen 2 - if versionCompatibleWithZen2(v) { - return false, nil - } - } - - // ...that will be replaced - targetMasters := set.Make() - for _, res := range nodeSpecResources { - if label.IsMasterNodeSet(res.StatefulSet) { - targetMasters.MergeWith(set.Make(sset.PodNames(res.StatefulSet)...)) - } - } - if targetMasters.Count() == 0 { - return false, nil - } - if targetMasters.Count() > 2 { - // Covers the case where the user is upgrading to zen2 + adding more masters simultaneously. - // Additional masters will get created before the existing one gets upgraded/restarted. - return false, nil - } - - if currentMasterNames.Diff(targetMasters).Count() > 0 { - // Covers the case where the existing masters are replaced by other masters in a different NodeSet. - // The new master will be created before the existing one gets removed. - return false, nil - } - // one or two zen1 masters, will be replaced by a one or two zen2 master with the same name - return true, nil -} - // getInitialMasterNodesAnnotation parses the `cluster.initial_master_nodes` value from // annotations on es, or returns nil if not set. func getInitialMasterNodesAnnotation(es esv1.Elasticsearch) []string { diff --git a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes_test.go b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes_test.go index 7be85e3bf9a..3ffc1222ddc 100644 --- a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes_test.go +++ b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - crclient "sigs.k8s.io/controller-runtime/pkg/client" esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" commonsettings "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/settings" @@ -24,12 +23,6 @@ import ( "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ) -func esv6() esv1.Elasticsearch { - return esv1.Elasticsearch{ - ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "es"}, - Spec: esv1.ElasticsearchSpec{Version: "6.8.5"}, - } -} func esv7() esv1.Elasticsearch { return esv1.Elasticsearch{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "es"}, @@ -43,19 +36,6 @@ func withAnnotations(es esv1.Elasticsearch, annotations map[string]string) esv1. } func TestSetupInitialMasterNodes(t *testing.T) { - v6Masters := []crclient.Object{ - // 3 master-only - sset.TestPod{Name: "es-master-0", Master: true, Data: false, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - sset.TestPod{Name: "es-master-1", Master: true, Data: false, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - sset.TestPod{Name: "es-master-2", Master: true, Data: false, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - // 3 master+data - sset.TestPod{Name: "es-masterdata-0", Master: true, Data: true, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - sset.TestPod{Name: "es-masterdata-1", Master: true, Data: true, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - sset.TestPod{Name: "es-masterdata-2", Master: true, Data: true, Version: "6.8.5", ClusterName: "es", Namespace: "ns"}.BuildPtr(), - } - - v7Master := sset.TestPod{Name: "es-master-1", Master: true, Data: false, Version: "7.5.0", ClusterName: "es", Namespace: "ns"}.BuildPtr() - expectedv7resources := func() nodespec.ResourcesList { return nodespec.ResourcesList{ {StatefulSet: sset.TestSset{Name: "es-master", Version: "7.5.0", Replicas: 3, Master: true, Data: false, ClusterName: "es"}.Build(), Config: settings.NewCanonicalConfig()}, @@ -63,11 +43,6 @@ func TestSetupInitialMasterNodes(t *testing.T) { {StatefulSet: sset.TestSset{Name: "es-data", Version: "7.5.0", Replicas: 3, Master: false, Data: true, ClusterName: "es"}.Build(), Config: settings.NewCanonicalConfig()}, } } - expectedv7MasterResources := func(replicas int32, ssetName string) nodespec.ResourcesList { - return nodespec.ResourcesList{ - {StatefulSet: sset.TestSset{Name: ssetName, Version: "7.5.0", Replicas: replicas, Master: true, Data: false, ClusterName: "es"}.Build(), Config: settings.NewCanonicalConfig()}, - } - } tests := []struct { name string nodeSpecResources nodespec.ResourcesList @@ -76,16 +51,6 @@ func TestSetupInitialMasterNodes(t *testing.T) { expectedConfigs []settings.CanonicalConfig expectedAnnotation string }{ - { - name: "v6 cluster: nothing to do", - es: esv6(), - nodeSpecResources: nodespec.ResourcesList{ - {StatefulSet: sset.TestSset{Name: "es-master", Version: "6.8.5", Replicas: 3, Master: true, ClusterName: "es"}.Build(), Config: settings.NewCanonicalConfig()}, - }, - k8sClient: k8s.NewFakeClient(), - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, { name: "v7 cluster initial creation: compute and set cluster.initial_master_nodes", es: esv7(), @@ -130,79 +95,10 @@ func TestSetupInitialMasterNodes(t *testing.T) { { name: "v7 cluster existed before: nothing to do", // set the ClusterUUID annotation to indicate the cluster did form in the past, so - // cluster.Initial_master_nodes should not be set + // cluster.initial_master_nodes should not be set es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), nodeSpecResources: expectedv7resources(), - k8sClient: k8s.NewFakeClient(), // no existing v6 master running - there should be v7 masters in there though, but we don't care in this test - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig(), settings.NewCanonicalConfig(), settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, - { - name: "upgrade single v6 master to single v7 master: should set cluster.initial_master_nodes", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7MasterResources(1, "es-master"), - k8sClient: k8s.NewFakeClient(v6Masters[0]), // one existing v6 master running - expectedConfigs: []settings.CanonicalConfig{ - // master nodes config - {CanonicalConfig: commonsettings.MustCanonicalConfig(map[string][]string{ - esv1.ClusterInitialMasterNodes: {"es-master-0"}, - })}, - }, - expectedAnnotation: "es-master-0", - }, - { - name: "upgrade two v6 master to two v7 masters: should set cluster.initial_master_nodes", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7MasterResources(2, "es-master"), - k8sClient: k8s.NewFakeClient(v6Masters[0], v6Masters[1]), // two existing v6 master running - expectedConfigs: []settings.CanonicalConfig{ - // master nodes config - {CanonicalConfig: commonsettings.MustCanonicalConfig(map[string][]string{ - esv1.ClusterInitialMasterNodes: {"es-master-0", "es-master-1"}, - })}, - }, - expectedAnnotation: "es-master-0,es-master-1", - }, - { - name: "upgrade mixed v6/v7 master to two v7 masters: should not set cluster.initial_master_nodes", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7MasterResources(2, "es-master"), - k8sClient: k8s.NewFakeClient(v6Masters[0], v7Master), // mixed masters running - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, - { - name: "upgrade single v6 master to single v7 master in a different statefulset: should not set " + - "cluster.initial_master_nodes since the new master will be created before the old one is removed", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7MasterResources(1, "es-different-sset"), // v7 master in a different sset - k8sClient: k8s.NewFakeClient(v6Masters[0]), // one existing v6 master running - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, - { - name: "upgrade single v6 master to more v7 masters: should not set cluster.initial_master_nodes" + - "since additional v7 masters will get created before existing v6 master is upgraded", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7resources(), // more than 1 v7 master to create - k8sClient: k8s.NewFakeClient(v6Masters[0]), // single v6 master - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig(), settings.NewCanonicalConfig(), settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, - { - name: "rolling-upgrade multiple v6 masters to multiple v7 masters: should not set cluster.initial_master_nodes", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7resources(), - k8sClient: k8s.NewFakeClient(v6Masters...), // v6 masters getting replaced by v7 masters - expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig(), settings.NewCanonicalConfig(), settings.NewCanonicalConfig()}, - expectedAnnotation: "", - }, - { - name: "upgrade single v6 master to more v7 masters: should not set cluster.initial_master_nodes" + - "since additional v7 masters will get created before existing v6 master is upgraded", - es: withAnnotations(esv7(), map[string]string{bootstrap.ClusterUUIDAnnotationName: "uuid"}), - nodeSpecResources: expectedv7resources(), // more than 1 v7 master to create - k8sClient: k8s.NewFakeClient(v6Masters[0]), // single v6 master + k8sClient: k8s.NewFakeClient(), expectedConfigs: []settings.CanonicalConfig{settings.NewCanonicalConfig(), settings.NewCanonicalConfig(), settings.NewCanonicalConfig()}, expectedAnnotation: "", }, @@ -306,15 +202,6 @@ func TestRemoveZen2BootstrapAnnotation(t *testing.T) { wantRequeue bool wantAnnotation bool }{ - { - name: "v6 cluster: nothing to do", - args: args{ - es: esv6(), - esClient: &mockZen2BootstrapESClient{}, - }, - wantRequeue: false, - wantAnnotation: false, - }, { name: "v7 cluster with no annotation: nothing to do", args: args{ diff --git a/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go b/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go index fe6203c8d58..3c99f892bd2 100644 --- a/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go +++ b/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go @@ -61,16 +61,6 @@ func Test_ClearVotingConfigExclusions(t *testing.T) { wantCall bool wantRequeue bool }{ - { - name: "no v7 nodes", - c: k8s.NewFakeClient(&es), - es: &es, - actualStatefulSets: es_sset.StatefulSetList{ - createStatefulSetWithESVersion("6.8.0"), - }, - wantCall: false, - wantRequeue: false, - }, { name: "3/3 nodes there, should clear", c: k8s.NewFakeClient(&es, &statefulSet3rep, &pods[0], &pods[1], &pods[2]), @@ -127,19 +117,6 @@ func TestAddToVotingConfigExclusions(t *testing.T) { wantAPICalled bool wantAPICalledWith []string }{ - { - name: "some zen1 masters: do nothing", - es: &es, - c: k8s.NewFakeClient(&es, sset.TestPod{ - Namespace: "ns", - Name: "pod-name", - ClusterName: "es", - Version: "6.8.0", - Master: true, - }.BuildPtr()), - excludeNodes: []string{"node1"}, - wantAPICalled: false, - }, { name: "set voting config exclusions", es: &es, From 24329a3a75835831408b88d1ba4594b134e952d0 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 29 Dec 2025 17:02:54 +0100 Subject: [PATCH 03/10] Refactor client hierarchy: delete v6.go, restructure v7 - Delete pkg/controller/elasticsearch/client/v6.go entirely - clientV7 now embeds baseClient directly instead of clientV6 - Remove SetMinimumMasterNodes from Client interface - Remove DiscoveryZen and DiscoveryZenSettings from model.go - Keep security methods in security.go, shard methods in shard.go - Update versioned() in base.go to only create v7/v8 clients - Update all tests to use v7+ versions - Remove SetMinimumMasterNodes from fakeESClient in tests This is part of removing Elasticsearch 6.x support from ECK. --- pkg/controller/elasticsearch/client/base.go | 11 +- pkg/controller/elasticsearch/client/client.go | 2 - .../elasticsearch/client/client_test.go | 123 +++------ .../elasticsearch/client/license_test.go | 18 +- pkg/controller/elasticsearch/client/model.go | 11 - .../elasticsearch/client/security.go | 16 -- pkg/controller/elasticsearch/client/shard.go | 6 +- pkg/controller/elasticsearch/client/v6.go | 256 ------------------ pkg/controller/elasticsearch/client/v7.go | 187 +++++++++++-- .../elasticsearch/driver/esstate_test.go | 9 - .../driver/upgrade_predicates_test.go | 8 +- 11 files changed, 226 insertions(+), 421 deletions(-) delete mode 100644 pkg/controller/elasticsearch/client/v6.go diff --git a/pkg/controller/elasticsearch/client/base.go b/pkg/controller/elasticsearch/client/base.go index 1949c5d8f8e..b947c523558 100644 --- a/pkg/controller/elasticsearch/client/base.go +++ b/pkg/controller/elasticsearch/client/base.go @@ -179,20 +179,17 @@ func (c *baseClient) request( func versioned(b *baseClient, v version.Version) Client { b.version = v - v6 := clientV6{ + v7 := clientV7{ baseClient: *b, } switch v.Major { - case 7: - return &clientV7{ - clientV6: v6, - } case 8, 9: return &clientV8{ - clientV7: clientV7{clientV6: v6}, + clientV7: v7, } default: - return &v6 + // Default to v7 client for version 7.x and any future versions + return &v7 } } diff --git a/pkg/controller/elasticsearch/client/client.go b/pkg/controller/elasticsearch/client/client.go index 6845f087a4e..712bbaafb7c 100644 --- a/pkg/controller/elasticsearch/client/client.go +++ b/pkg/controller/elasticsearch/client/client.go @@ -91,8 +91,6 @@ type Client interface { GetClusterHealthWaitForAllEvents(ctx context.Context) (Health, error) // GetClusterState calls the _cluster/state api. GetClusterState(ctx context.Context) (ClusterState, error) - // SetMinimumMasterNodes sets the transient and persistent setting of the same name in cluster settings. - SetMinimumMasterNodes(ctx context.Context, n int) error // ReloadSecureSettings will decrypt and re-read the entire keystore, on every cluster node, // but only the reloadable secure settings will be applied ReloadSecureSettings(ctx context.Context) error diff --git a/pkg/controller/elasticsearch/client/client_test.go b/pkg/controller/elasticsearch/client/client_test.go index c1ecbfa9781..d4046cd3a0c 100644 --- a/pkg/controller/elasticsearch/client/client_test.go +++ b/pkg/controller/elasticsearch/client/client_test.go @@ -153,15 +153,12 @@ func requestAssertion(test func(req *http.Request)) RoundTripFunc { func TestClientErrorHandling(t *testing.T) { // 303 would lead to a redirect to another error response if we would also set the Location header codes := []int{100, 303, 400, 404, 500} - testClient := NewMockClient(version.MustParse("6.8.0"), errorResponses(codes)) + testClient := NewMockClient(version.MustParse("7.17.0"), errorResponses(codes)) requests := []func() (string, error){ func() (string, error) { _, err := testClient.GetClusterInfo(context.Background()) return "GetClusterInfo", err }, - func() (string, error) { - return "SetMinimumMasterNodes", testClient.SetMinimumMasterNodes(context.Background(), 0) - }, } for range codes { @@ -173,14 +170,12 @@ func TestClientErrorHandling(t *testing.T) { } func TestClientUsesJsonContentType(t *testing.T) { - testClient := NewMockClient(version.MustParse("6.8.0"), requestAssertion(func(req *http.Request) { + testClient := NewMockClient(version.MustParse("7.17.0"), requestAssertion(func(req *http.Request) { assert.Equal(t, []string{"application/json; charset=utf-8"}, req.Header["Content-Type"]) })) _, err := testClient.GetClusterInfo(context.Background()) assert.NoError(t, err) - - assert.NoError(t, testClient.SetMinimumMasterNodes(context.Background(), 0)) } func TestClientSupportsBasicAuth(t *testing.T) { @@ -213,7 +208,7 @@ func TestClientSupportsBasicAuth(t *testing.T) { } for _, tt := range tests { - testClient := NewMockClientWithUser(version.MustParse("6.8.0"), + testClient := NewMockClientWithUser(version.MustParse("7.17.0"), tt.args, requestAssertion(func(req *http.Request) { username, password, ok := req.BasicAuth() @@ -224,7 +219,6 @@ func TestClientSupportsBasicAuth(t *testing.T) { _, err := testClient.GetClusterInfo(context.Background()) assert.NoError(t, err) - assert.NoError(t, testClient.SetMinimumMasterNodes(context.Background(), 0)) } } @@ -308,7 +302,7 @@ func TestAPIError_Error(t *testing.T) { func TestClientGetNodes(t *testing.T) { expectedPath := "/_nodes/_all/no-metrics" - testClient := NewMockClient(version.MustParse("6.8.0"), func(req *http.Request) *http.Response { + testClient := NewMockClient(version.MustParse("7.17.0"), func(req *http.Request) *http.Response { require.Equal(t, expectedPath, req.URL.Path) return &http.Response{ StatusCode: 200, @@ -326,7 +320,7 @@ func TestClientGetNodes(t *testing.T) { func TestClientGetNodesStats(t *testing.T) { expectedPath := "/_nodes/_all/stats/os" - testClient := NewMockClient(version.MustParse("6.8.0"), func(req *http.Request) *http.Response { + testClient := NewMockClient(version.MustParse("7.17.0"), func(req *http.Request) *http.Response { require.Equal(t, expectedPath, req.URL.Path) return &http.Response{ StatusCode: 200, @@ -344,7 +338,7 @@ func TestClientGetNodesStats(t *testing.T) { func TestGetInfo(t *testing.T) { expectedPath := "/" - testClient := NewMockClient(version.MustParse("6.4.1"), func(req *http.Request) *http.Response { + testClient := NewMockClient(version.MustParse("7.17.0"), func(req *http.Request) *http.Response { require.Equal(t, expectedPath, req.URL.Path) return &http.Response{ StatusCode: 200, @@ -357,7 +351,7 @@ func TestGetInfo(t *testing.T) { require.NoError(t, err) require.Equal(t, "af932d24216a4dd69ba47d2fd3214796", info.ClusterName) require.Equal(t, "LGA3VblKTNmzP6Q6SWxfkw", info.ClusterUUID) - require.Equal(t, "6.4.1", info.Version.Number) + require.Equal(t, "6.4.1", info.Version.Number) // This is the version reported by the ES API response in the fixture, not the client version } func TestClient_Equal(t *testing.T) { @@ -373,8 +367,8 @@ func TestClient_Equal(t *testing.T) { return ca.Cert } dummyCACerts := []*x509.Certificate{createCert()} - v6 := version.MustParse("6.8.0") - v7 := version.MustParse("7.0.0") + v7 := version.MustParse("7.17.0") + v8 := version.MustParse("8.0.0") timeout := Timeout(context.Background(), esv1.Elasticsearch{}) x509.NewCertPool() tests := []struct { @@ -385,61 +379,61 @@ func TestClient_Equal(t *testing.T) { }{ { name: "c1 and c2 equals", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), want: true, }, { name: "c2 nil", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), c2: nil, want: false, }, { name: "different endpoint", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, NewStaticURLProvider("another-endpoint"), dummyUser, v6, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, NewStaticURLProvider("another-endpoint"), dummyUser, v7, dummyCACerts, timeout, false), want: false, }, { name: "different user", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, BasicAuth{Name: "user", Password: "another-password"}, v6, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, BasicAuth{Name: "user", Password: "another-password"}, v7, dummyCACerts, timeout, false), want: false, }, { name: "different CA cert", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, []*x509.Certificate{createCert()}, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, []*x509.Certificate{createCert()}, timeout, false), want: false, }, { name: "different CA certs length", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, []*x509.Certificate{createCert(), createCert()}, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, []*x509.Certificate{createCert(), createCert()}, timeout, false), want: false, }, { name: "different dialers are not taken into consideration", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(portforward.NewForwardingDialer(), dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(portforward.NewForwardingDialer(), dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), want: true, }, { name: "different versions", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v6, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v8, dummyCACerts, timeout, false), want: false, }, { name: "same versions", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), - c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v8, dummyCACerts, timeout, false), + c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v8, dummyCACerts, timeout, false), want: true, }, { name: "one has a version", - c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v7, dummyCACerts, timeout, false), + c1: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, v8, dummyCACerts, timeout, false), c2: NewElasticsearchClient(nil, dummyNamespaceName, dummyEndpoint, dummyUser, version.Version{}, dummyCACerts, timeout, false), want: false, }, @@ -458,11 +452,6 @@ func TestClient_AddVotingConfigExclusions(t *testing.T) { version version.Version wantErr bool }{ - { - expectedPath: "", - version: version.MustParse("6.8.0"), - wantErr: true, - }, { expectedPath: "/_cluster/voting_config_exclusions/a,b", version: version.MustParse("7.0.0"), @@ -504,50 +493,14 @@ func TestClient_DeleteVotingConfigExclusions(t *testing.T) { version version.Version wantErr bool }{ - { - expectedPath: "", - version: version.MustParse("6.8.0"), - wantErr: true, - }, { expectedPath: "/_cluster/voting_config_exclusions", version: version.MustParse("7.0.0"), wantErr: false, }, - } - - for _, tt := range tests { - client := NewMockClient(tt.version, func(req *http.Request) *http.Response { - require.Equal(t, tt.expectedPath, req.URL.Path) - return &http.Response{ - StatusCode: 200, - Body: io.NopCloser(strings.NewReader("")), - } - }) - err := client.DeleteVotingConfigExclusions(context.Background(), false) - if (err != nil) != tt.wantErr { - t.Errorf("Client.DeleteVotingConfigExclusions() error = %v, wantErr %v", err, tt.wantErr) - } - } -} - -func TestClient_SetMinimumMasterNodes(t *testing.T) { - tests := []struct { - name string - expectedPath string - version version.Version - wantErr bool - }{ - { - name: "mininum master nodes is essential in v6", - expectedPath: "/_cluster/settings", - version: version.MustParse("6.8.0"), - wantErr: false, - }, { - name: "in v7 it is still supported for bwc but devoid of meaning", - expectedPath: "/_cluster/settings", - version: version.MustParse("7.0.0"), + expectedPath: "/_cluster/voting_config_exclusions", + version: version.MustParse("8.0.0"), wantErr: false, }, } @@ -560,9 +513,9 @@ func TestClient_SetMinimumMasterNodes(t *testing.T) { Body: io.NopCloser(strings.NewReader("")), } }) - err := client.SetMinimumMasterNodes(context.Background(), 1) + err := client.DeleteVotingConfigExclusions(context.Background(), false) if (err != nil) != tt.wantErr { - t.Errorf("Client.SetMinimumMasterNodes() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Client.DeleteVotingConfigExclusions() error = %v, wantErr %v", err, tt.wantErr) } } } @@ -636,18 +589,18 @@ func TestClient_ClusterBootstrappedForZen2(t *testing.T) { bootstrappedForZen2, wantErr bool }{ { - name: "6.x master node", + name: "7.x master node", expectedPath: "/_nodes/_master", - version: "6.8.0", - apiResponse: fixtures.MasterNodeForVersion("6.8.0"), - bootstrappedForZen2: false, + version: "7.5.0", + apiResponse: fixtures.MasterNodeForVersion("7.5.0"), + bootstrappedForZen2: true, wantErr: false, }, { - name: "7.x master node", + name: "8.x master node", expectedPath: "/_nodes/_master", - version: "7.5.0", - apiResponse: fixtures.MasterNodeForVersion("7.5.0"), + version: "8.0.0", + apiResponse: fixtures.MasterNodeForVersion("8.0.0"), bootstrappedForZen2: true, wantErr: false, }, diff --git a/pkg/controller/elasticsearch/client/license_test.go b/pkg/controller/elasticsearch/client/license_test.go index a19c491196d..f3c2a5418cd 100644 --- a/pkg/controller/elasticsearch/client/license_test.go +++ b/pkg/controller/elasticsearch/client/license_test.go @@ -25,12 +25,12 @@ func TestClient_GetLicense(t *testing.T) { version version.Version }{ { - expectedPath: "/_xpack/license", - version: version.MustParse("6.8.0"), + expectedPath: "/_license", + version: version.MustParse("7.0.0"), }, { expectedPath: "/_license", - version: version.MustParse("7.0.0"), + version: version.MustParse("8.0.0"), }, } @@ -64,12 +64,12 @@ func TestClient_UpdateLicense(t *testing.T) { version version.Version }{ { - expectedPath: "/_xpack/license", - version: version.MustParse("6.8.0"), + expectedPath: "/_license", + version: version.MustParse("7.0.0"), }, { expectedPath: "/_license", - version: version.MustParse("7.0.0"), + version: version.MustParse("8.0.0"), }, } for _, tt := range tests { @@ -109,12 +109,12 @@ func TestClient_StartBasic(t *testing.T) { version version.Version }{ { - expectedPath: "/_xpack/license/start_basic", - version: version.MustParse("6.8.0"), + expectedPath: "/_license/start_basic", + version: version.MustParse("7.0.0"), }, { expectedPath: "/_license/start_basic", - version: version.MustParse("7.0.0"), + version: version.MustParse("8.0.0"), }, } diff --git a/pkg/controller/elasticsearch/client/model.go b/pkg/controller/elasticsearch/client/model.go index f894802fadd..2c0027e8131 100644 --- a/pkg/controller/elasticsearch/client/model.go +++ b/pkg/controller/elasticsearch/client/model.go @@ -248,17 +248,6 @@ type ClusterRoutingAllocation struct { Transient AllocationSettings `json:"transient,omitempty"` } -// DiscoveryZen set minimum number of master eligible nodes that must be visible to form a cluster. -type DiscoveryZen struct { - MinimumMasterNodes int `json:"discovery.zen.minimum_master_nodes"` -} - -// DiscoveryZenSettings are cluster settings related to the zen discovery mechanism. -type DiscoveryZenSettings struct { - Transient DiscoveryZen `json:"transient"` - Persistent DiscoveryZen `json:"persistent"` -} - // ErrorResponse is an Elasticsearch error response. type ErrorResponse struct { Status int `json:"status"` diff --git a/pkg/controller/elasticsearch/client/security.go b/pkg/controller/elasticsearch/client/security.go index e8015a52c6d..d33a43c0e80 100644 --- a/pkg/controller/elasticsearch/client/security.go +++ b/pkg/controller/elasticsearch/client/security.go @@ -46,10 +46,6 @@ type SecurityClient interface { InvalidateAPIKeys(ctx context.Context, request APIKeysInvalidateRequest) (APIKeysInvalidateResponse, error) } -func (c *clientV6) GetServiceAccountCredentials(_ context.Context, _ string) (ServiceAccountCredential, error) { - return ServiceAccountCredential{}, errNotSupportedInEs6x -} - func (c *clientV7) GetServiceAccountCredentials(ctx context.Context, namespacedService string) (ServiceAccountCredential, error) { var serviceAccountCredential ServiceAccountCredential path := fmt.Sprintf("/_security/service/%s/credential", namespacedService) @@ -59,10 +55,6 @@ func (c *clientV7) GetServiceAccountCredentials(ctx context.Context, namespacedS return serviceAccountCredential, nil } -func (c *clientV6) GetAPIKeysByName(ctx context.Context, name string) (APIKeyList, error) { - return APIKeyList{}, errNotSupportedInEs6x -} - func (c *clientV7) GetAPIKeysByName(ctx context.Context, name string) (APIKeyList, error) { var apiKeys APIKeyList path := fmt.Sprintf("/_security/api_key?name=%s", name) @@ -81,10 +73,6 @@ func (c *clientV7) GetAPIKeysByName(ctx context.Context, name string) (APIKeyLis return APIKeyList{APIKeys: activeAPIKeys}, nil } -func (c *clientV6) CreateAPIKey(ctx context.Context, request APIKeyCreateRequest) (APIKeyCreateResponse, error) { - return APIKeyCreateResponse{}, errNotSupportedInEs6x -} - func (c *clientV7) CreateAPIKey(ctx context.Context, request APIKeyCreateRequest) (APIKeyCreateResponse, error) { var apiKey APIKeyCreateResponse path := "/_security/api_key" @@ -94,10 +82,6 @@ func (c *clientV7) CreateAPIKey(ctx context.Context, request APIKeyCreateRequest return apiKey, nil } -func (c *clientV6) InvalidateAPIKeys(ctx context.Context, request APIKeysInvalidateRequest) (APIKeysInvalidateResponse, error) { - return APIKeysInvalidateResponse{}, errNotSupportedInEs6x -} - func (c *clientV7) InvalidateAPIKeys(ctx context.Context, request APIKeysInvalidateRequest) (APIKeysInvalidateResponse, error) { path := "/_security/api_key" var response APIKeysInvalidateResponse diff --git a/pkg/controller/elasticsearch/client/shard.go b/pkg/controller/elasticsearch/client/shard.go index 9ddb9d17bf4..43a1670fafd 100644 --- a/pkg/controller/elasticsearch/client/shard.go +++ b/pkg/controller/elasticsearch/client/shard.go @@ -21,7 +21,7 @@ type ShardLister interface { GetShards(ctx context.Context) (Shards, error) } -func (c *clientV6) ExcludeFromShardAllocation(ctx context.Context, nodes string) error { +func (c *clientV7) ExcludeFromShardAllocation(ctx context.Context, nodes string) error { allocationSettings := ClusterRoutingAllocation{ Transient: AllocationSettings{ Cluster: ClusterRoutingSettings{ @@ -38,7 +38,7 @@ func (c *clientV6) ExcludeFromShardAllocation(ctx context.Context, nodes string) return c.put(ctx, "/_cluster/settings", allocationSettings, nil) } -func (c *clientV6) GetShards(ctx context.Context) (Shards, error) { +func (c *clientV7) GetShards(ctx context.Context) (Shards, error) { var shards Shards if err := c.get(ctx, "/_cat/shards?format=json", &shards); err != nil { return shards, err @@ -46,7 +46,7 @@ func (c *clientV6) GetShards(ctx context.Context) (Shards, error) { return shards, nil } -func (c *clientV6) HasShardActivity(ctx context.Context) (bool, error) { +func (c *clientV7) HasShardActivity(ctx context.Context) (bool, error) { health, err := c.GetClusterHealth(ctx) if err != nil { return false, err diff --git a/pkg/controller/elasticsearch/client/v6.go b/pkg/controller/elasticsearch/client/v6.go deleted file mode 100644 index 36fde02c3b8..00000000000 --- a/pkg/controller/elasticsearch/client/v6.go +++ /dev/null @@ -1,256 +0,0 @@ -// 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 client - -import ( - "context" - "net/http" - "net/url" - - "github.com/pkg/errors" - - "github.com/elastic/cloud-on-k8s/v3/pkg/apis/common/v1alpha1" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/stringsutil" -) - -var errNotSupportedInEs6x = errors.New("not supported in Elasticsearch 6.x") - -type clientV6 struct { - baseClient -} - -func (c *clientV6) InvalidateCrossClusterAPIKey(context.Context, string) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) CreateCrossClusterAPIKey(_ context.Context, _ CrossClusterAPIKeyCreateRequest) (CrossClusterAPIKeyCreateResponse, error) { - return CrossClusterAPIKeyCreateResponse{}, errNotSupportedInEs6x -} - -func (c *clientV6) UpdateCrossClusterAPIKey(_ context.Context, _ string, _ CrossClusterAPIKeyUpdateRequest) (CrossClusterAPIKeyUpdateResponse, error) { - return CrossClusterAPIKeyUpdateResponse{}, errNotSupportedInEs6x -} - -func (c *clientV6) GetCrossClusterAPIKeys(_ context.Context, _ string) (CrossClusterAPIKeyList, error) { - return CrossClusterAPIKeyList{}, errNotSupportedInEs6x -} - -func (c *clientV6) Version() version.Version { - return c.version -} - -func (c *clientV6) GetClusterInfo(ctx context.Context) (Info, error) { - var info Info - err := c.get(ctx, "/", &info) - return info, err -} - -func (c *clientV6) GetClusterRoutingAllocation(ctx context.Context) (ClusterRoutingAllocation, error) { - var settings ClusterRoutingAllocation - err := c.get(ctx, "/_cluster/settings", &settings) - return settings, err -} - -func (c *clientV6) updateAllocationEnable(ctx context.Context, value string) error { - allocationSettings := ClusterRoutingAllocation{ - Transient: AllocationSettings{ - Cluster: ClusterRoutingSettings{ - Routing: RoutingSettings{ - Allocation: RoutingAllocationSettings{ - Enable: value, - }, - }, - }, - }, - } - return c.put(ctx, "/_cluster/settings", allocationSettings, nil) -} - -func (c *clientV6) EnableShardAllocation(ctx context.Context) error { - return c.updateAllocationEnable(ctx, "all") -} - -func (c *clientV6) DisableReplicaShardsAllocation(ctx context.Context) error { - return c.updateAllocationEnable(ctx, "primaries") -} - -func (c *clientV6) RemoveTransientAllocationSettings(ctx context.Context) error { - allocationSettings := struct { - Transient struct { - Exclude *string `json:"cluster.routing.allocation.exclude._name"` - Enable *string `json:"cluster.routing.allocation.enable"` - } `json:"transient"` - }{} - return c.put(ctx, "/_cluster/settings", allocationSettings, nil) -} - -func (c *clientV6) SyncedFlush(ctx context.Context) error { - return c.post(ctx, "/_flush/synced", nil, nil) -} - -func (c *clientV6) Flush(ctx context.Context) error { - return c.post(ctx, "/_flush", nil, nil) -} - -func (c *clientV6) GetClusterHealth(ctx context.Context) (Health, error) { - var result Health - err := c.get(ctx, "/_cluster/health", &result) - return result, err -} - -func (c *clientV6) GetClusterHealthWaitForAllEvents(ctx context.Context) (Health, error) { - var result Health - // wait for all events means wait for all events down to `languid` events which is the lowest event priority - pathWithQuery := "/_cluster/health?wait_for_events=languid&timeout=0s" - // ignore timeout errors as they are communicated in the returned payload and a timeout is to be expected - // given the query parameters. 408 for other reasons than the clients timeout parameter should not happen - // as they are expected only on idle connections https://go-review.googlesource.com/c/go/+/179457/4/src/net/http/transport.go#1931 - err := c.request(ctx, http.MethodGet, pathWithQuery, nil, &result, IsTimeout) - return result, err -} - -func (c *clientV6) SetMinimumMasterNodes(ctx context.Context, n int) error { - zenSettings := DiscoveryZenSettings{ - Transient: DiscoveryZen{MinimumMasterNodes: n}, - Persistent: DiscoveryZen{MinimumMasterNodes: n}, - } - return c.put(ctx, "/_cluster/settings", &zenSettings, nil) -} - -func (c *clientV6) ReloadSecureSettings(ctx context.Context) error { - return c.post(ctx, "/_nodes/reload_secure_settings", nil, nil) -} - -func (c *clientV6) GetNodes(ctx context.Context) (Nodes, error) { - var nodes Nodes - // restrict call to minimal node information with a non-existent metric filter - err := c.get(ctx, "/_nodes/_all/no-metrics", &nodes) - return nodes, err -} - -func (c *clientV6) GetNodesStats(ctx context.Context) (NodesStats, error) { - var nodesStats NodesStats - // restrict call to basic node info only - err := c.get(ctx, "/_nodes/_all/stats/os", &nodesStats) - return nodesStats, err -} - -func (c *clientV6) UpdateRemoteClusterSettings(ctx context.Context, settings RemoteClustersSettings) error { - return c.put(ctx, "/_cluster/settings", &settings, nil) -} - -func (c *clientV6) GetRemoteClusterSettings(ctx context.Context) (RemoteClustersSettings, error) { - remoteClustersSettings := RemoteClustersSettings{} - err := c.get(ctx, "/_cluster/settings", &remoteClustersSettings) - return remoteClustersSettings, err -} - -func (c *clientV6) GetLicense(ctx context.Context) (License, error) { - var license LicenseResponse - err := c.get(ctx, "/_xpack/license", &license) - return license.License, err -} - -func (c *clientV6) UpdateLicense(ctx context.Context, licenses LicenseUpdateRequest) (LicenseUpdateResponse, error) { - var response LicenseUpdateResponse - err := c.post(ctx, "/_xpack/license?acknowledge=true", licenses, &response) - return response, err -} - -func (c *clientV6) StartTrial(ctx context.Context) (StartTrialResponse, error) { - var response StartTrialResponse - err := c.post(ctx, "/_xpack/license/start_trial?acknowledge=true", nil, &response) - return response, err -} - -func (c *clientV6) StartBasic(ctx context.Context) (StartBasicResponse, error) { - var response StartBasicResponse - err := c.post(ctx, "/_xpack/license/start_basic?acknowledge=true", nil, &response) - return response, err -} - -func (c *clientV6) AddVotingConfigExclusions(_ context.Context, _ []string) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) DeleteVotingConfigExclusions(_ context.Context, _ bool) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) DeleteAutoscalingPolicies(_ context.Context) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) CreateAutoscalingPolicy(_ context.Context, _ string, _ v1alpha1.AutoscalingPolicy) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) GetAutoscalingCapacity(_ context.Context) (AutoscalingCapacityResult, error) { - return AutoscalingCapacityResult{}, errNotSupportedInEs6x -} - -func (c *clientV6) UpdateMLNodesSettings(_ context.Context, _ int32, _ string) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) GetShutdown(context.Context, *string) (ShutdownResponse, error) { - return ShutdownResponse{}, errNotSupportedInEs6x -} - -func (c *clientV6) PutShutdown(context.Context, string, ShutdownType, string) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) DeleteShutdown(context.Context, string) error { - return errNotSupportedInEs6x -} - -func (c *clientV6) ClusterBootstrappedForZen2(ctx context.Context) (bool, error) { - // Look at the current master node of the cluster: if it's running version 7.x.x or above, - // the cluster has been bootstrapped. - // Even though c is a clientV6, it may be targeting a mixed v6/v7 having a v7 master. - var response Nodes - if err := c.get(ctx, "/_nodes/_master", &response); err != nil { - return false, err - } - if len(response.Nodes) == 0 { - // no known master node (yet), consider the cluster is not bootstrapped - return false, nil - } - for _, master := range response.Nodes { - return master.isV7OrAbove() - } - // should never happen since we ensured a single entry in the above map - return false, errors.New("no master found in ClusterBootstrappedForZen2") -} - -func (c *clientV6) GetClusterState(_ context.Context) (ClusterState, error) { - return ClusterState{}, errors.New("cluster state is not supported in Elasticsearch 6.x") -} - -func (c *clientV6) Request(ctx context.Context, r *http.Request) (*http.Response, error) { - baseURL, err := c.URLProvider.URL() - if err != nil { - return nil, err - } - newURL, err := url.Parse(stringsutil.Concat(baseURL, r.URL.String())) - if err != nil { - return nil, err - } - r.URL = newURL - return c.doRequest(ctx, r) -} - -// Equal returns true if c2 can be considered the same as c -func (c *clientV6) Equal(c2 Client) bool { - other, ok := c2.(*clientV6) - if !ok { - return false - } - return c.baseClient.equal(&other.baseClient) -} - -var _ Client = &clientV6{} diff --git a/pkg/controller/elasticsearch/client/v7.go b/pkg/controller/elasticsearch/client/v7.go index 2e086b650d8..cf8fce24d95 100644 --- a/pkg/controller/elasticsearch/client/v7.go +++ b/pkg/controller/elasticsearch/client/v7.go @@ -7,16 +7,123 @@ package client import ( "context" "fmt" + "net/http" + "net/url" "strconv" "strings" "github.com/pkg/errors" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" + "github.com/elastic/cloud-on-k8s/v3/pkg/utils/stringsutil" ) +var errNotSupportedInEs7x = errors.New("not supported in Elasticsearch 7.x") + type clientV7 struct { - clientV6 + baseClient +} + +func (c *clientV7) Version() version.Version { + return c.version +} + +func (c *clientV7) GetClusterInfo(ctx context.Context) (Info, error) { + var info Info + err := c.get(ctx, "/", &info) + return info, err +} + +func (c *clientV7) GetClusterRoutingAllocation(ctx context.Context) (ClusterRoutingAllocation, error) { + var settings ClusterRoutingAllocation + err := c.get(ctx, "/_cluster/settings", &settings) + return settings, err +} + +func (c *clientV7) updateAllocationEnable(ctx context.Context, value string) error { + allocationSettings := ClusterRoutingAllocation{ + Transient: AllocationSettings{ + Cluster: ClusterRoutingSettings{ + Routing: RoutingSettings{ + Allocation: RoutingAllocationSettings{ + Enable: value, + }, + }, + }, + }, + } + return c.put(ctx, "/_cluster/settings", allocationSettings, nil) +} + +func (c *clientV7) EnableShardAllocation(ctx context.Context) error { + return c.updateAllocationEnable(ctx, "all") +} + +func (c *clientV7) DisableReplicaShardsAllocation(ctx context.Context) error { + return c.updateAllocationEnable(ctx, "primaries") +} + +func (c *clientV7) RemoveTransientAllocationSettings(ctx context.Context) error { + allocationSettings := struct { + Transient struct { + Exclude *string `json:"cluster.routing.allocation.exclude._name"` + Enable *string `json:"cluster.routing.allocation.enable"` + } `json:"transient"` + }{} + return c.put(ctx, "/_cluster/settings", allocationSettings, nil) +} + +func (c *clientV7) SyncedFlush(ctx context.Context) error { + return c.post(ctx, "/_flush/synced", nil, nil) +} + +func (c *clientV7) Flush(ctx context.Context) error { + return c.post(ctx, "/_flush", nil, nil) +} + +func (c *clientV7) GetClusterHealth(ctx context.Context) (Health, error) { + var result Health + err := c.get(ctx, "/_cluster/health", &result) + return result, err +} + +func (c *clientV7) GetClusterHealthWaitForAllEvents(ctx context.Context) (Health, error) { + var result Health + // wait for all events means wait for all events down to `languid` events which is the lowest event priority + pathWithQuery := "/_cluster/health?wait_for_events=languid&timeout=0s" + // ignore timeout errors as they are communicated in the returned payload and a timeout is to be expected + // given the query parameters. 408 for other reasons than the clients timeout parameter should not happen + // as they are expected only on idle connections https://go-review.googlesource.com/c/go/+/179457/4/src/net/http/transport.go#1931 + err := c.request(ctx, http.MethodGet, pathWithQuery, nil, &result, IsTimeout) + return result, err +} + +func (c *clientV7) ReloadSecureSettings(ctx context.Context) error { + return c.post(ctx, "/_nodes/reload_secure_settings", nil, nil) +} + +func (c *clientV7) GetNodes(ctx context.Context) (Nodes, error) { + var nodes Nodes + // restrict call to minimal node information with a non-existent metric filter + err := c.get(ctx, "/_nodes/_all/no-metrics", &nodes) + return nodes, err +} + +func (c *clientV7) GetNodesStats(ctx context.Context) (NodesStats, error) { + var nodesStats NodesStats + // restrict call to basic node info only + err := c.get(ctx, "/_nodes/_all/stats/os", &nodesStats) + return nodesStats, err +} + +func (c *clientV7) UpdateRemoteClusterSettings(ctx context.Context, settings RemoteClustersSettings) error { + return c.put(ctx, "/_cluster/settings", &settings, nil) +} + +func (c *clientV7) GetRemoteClusterSettings(ctx context.Context) (RemoteClustersSettings, error) { + remoteClustersSettings := RemoteClustersSettings{} + err := c.get(ctx, "/_cluster/settings", &remoteClustersSettings) + return remoteClustersSettings, err } func (c *clientV7) GetLicense(ctx context.Context) (License, error) { @@ -31,18 +138,18 @@ func (c *clientV7) UpdateLicense(ctx context.Context, licenses LicenseUpdateRequ return response, err } -func (c *clientV7) StartBasic(ctx context.Context) (StartBasicResponse, error) { - var response StartBasicResponse - err := c.post(ctx, "/_license/start_basic?acknowledge=true", nil, &response) - return response, err -} - func (c *clientV7) StartTrial(ctx context.Context) (StartTrialResponse, error) { var response StartTrialResponse err := c.post(ctx, "/_license/start_trial?acknowledge=true", nil, &response) return response, err } +func (c *clientV7) StartBasic(ctx context.Context) (StartBasicResponse, error) { + var response StartBasicResponse + err := c.post(ctx, "/_license/start_basic?acknowledge=true", nil, &response) + return response, err +} + func (c *clientV7) AddVotingConfigExclusions(ctx context.Context, nodeNames []string) error { var path string if c.version.GTE(version.From(7, 8, 0)) { @@ -58,6 +165,18 @@ func (c *clientV7) AddVotingConfigExclusions(ctx context.Context, nodeNames []st return nil } +func (c *clientV7) DeleteVotingConfigExclusions(ctx context.Context, waitForRemoval bool) error { + path := fmt.Sprintf( + "/_cluster/voting_config_exclusions?wait_for_removal=%s", + strconv.FormatBool(waitForRemoval), + ) + + if err := c.delete(ctx, path); err != nil { + return errors.Wrap(err, "unable to delete /_cluster/voting_config_exclusions") + } + return nil +} + func (c *clientV7) GetShutdown(ctx context.Context, nodeID *string) (ShutdownResponse, error) { var r ShutdownResponse path := "/_nodes/shutdown" @@ -80,22 +199,58 @@ func (c *clientV7) DeleteShutdown(ctx context.Context, nodeID string) error { return c.delete(ctx, fmt.Sprintf("/_nodes/%s/shutdown", nodeID)) } -func (c *clientV7) DeleteVotingConfigExclusions(ctx context.Context, waitForRemoval bool) error { - path := fmt.Sprintf( - "/_cluster/voting_config_exclusions?wait_for_removal=%s", - strconv.FormatBool(waitForRemoval), - ) - - if err := c.delete(ctx, path); err != nil { - return errors.Wrap(err, "unable to delete /_cluster/voting_config_exclusions") +func (c *clientV7) ClusterBootstrappedForZen2(ctx context.Context) (bool, error) { + // Look at the current master node of the cluster: if it's running version 7.x.x or above, + // the cluster has been bootstrapped. + var response Nodes + if err := c.get(ctx, "/_nodes/_master", &response); err != nil { + return false, err } - return nil + if len(response.Nodes) == 0 { + // no known master node (yet), consider the cluster is not bootstrapped + return false, nil + } + for _, master := range response.Nodes { + return master.isV7OrAbove() + } + // should never happen since we ensured a single entry in the above map + return false, errors.New("no master found in ClusterBootstrappedForZen2") } func (c *clientV7) GetClusterState(_ context.Context) (ClusterState, error) { return ClusterState{}, errors.New("cluster state is not supported in Elasticsearch 7.x") } +func (c *clientV7) InvalidateCrossClusterAPIKey(context.Context, string) error { + return errNotSupportedInEs7x +} + +func (c *clientV7) CreateCrossClusterAPIKey(_ context.Context, _ CrossClusterAPIKeyCreateRequest) (CrossClusterAPIKeyCreateResponse, error) { + return CrossClusterAPIKeyCreateResponse{}, errNotSupportedInEs7x +} + +func (c *clientV7) UpdateCrossClusterAPIKey(_ context.Context, _ string, _ CrossClusterAPIKeyUpdateRequest) (CrossClusterAPIKeyUpdateResponse, error) { + return CrossClusterAPIKeyUpdateResponse{}, errNotSupportedInEs7x +} + +func (c *clientV7) GetCrossClusterAPIKeys(_ context.Context, _ string) (CrossClusterAPIKeyList, error) { + return CrossClusterAPIKeyList{}, errNotSupportedInEs7x +} + +func (c *clientV7) Request(ctx context.Context, r *http.Request) (*http.Response, error) { + baseURL, err := c.URLProvider.URL() + if err != nil { + return nil, err + } + newURL, err := url.Parse(stringsutil.Concat(baseURL, r.URL.String())) + if err != nil { + return nil, err + } + r.URL = newURL + return c.doRequest(ctx, r) +} + +// Equal returns true if c2 can be considered the same as c func (c *clientV7) Equal(c2 Client) bool { other, ok := c2.(*clientV7) if !ok { diff --git a/pkg/controller/elasticsearch/driver/esstate_test.go b/pkg/controller/elasticsearch/driver/esstate_test.go index e8bcd438a16..23aa981739d 100644 --- a/pkg/controller/elasticsearch/driver/esstate_test.go +++ b/pkg/controller/elasticsearch/driver/esstate_test.go @@ -22,9 +22,6 @@ import ( type fakeESClient struct { //nolint:maligned esclient.Client - SetMinimumMasterNodesCalled bool - SetMinimumMasterNodesCalledWith int - AddVotingConfigExclusionsCalled bool AddVotingConfigExclusionsCalledWith []string @@ -52,12 +49,6 @@ type fakeESClient struct { //nolint:maligned version version.Version } -func (f *fakeESClient) SetMinimumMasterNodes(_ context.Context, n int) error { - f.SetMinimumMasterNodesCalled = true - f.SetMinimumMasterNodesCalledWith = n - return nil -} - func (f *fakeESClient) AddVotingConfigExclusions(_ context.Context, nodeNames []string) error { f.AddVotingConfigExclusionsCalled = true f.AddVotingConfigExclusionsCalledWith = append(f.AddVotingConfigExclusionsCalledWith, nodeNames...) diff --git a/pkg/controller/elasticsearch/driver/upgrade_predicates_test.go b/pkg/controller/elasticsearch/driver/upgrade_predicates_test.go index e021f6b5634..a0d7e6cd5b9 100644 --- a/pkg/controller/elasticsearch/driver/upgrade_predicates_test.go +++ b/pkg/controller/elasticsearch/driver/upgrade_predicates_test.go @@ -141,11 +141,8 @@ func TestUpgradePodsDeletion_WithNodeTypeMutations(t *testing.T) { deleted []string wantErr bool wantShardsAllocationDisabled bool - /* Zen1 checks */ - minimumMasterNodesCalled bool - minimumMasterNodesCalledWith int recordedEvents int - /* Zend2 checks */ + /* Zen2 checks */ votingExclusionCalledWith []string }{ { @@ -252,9 +249,6 @@ func TestUpgradePodsDeletion_WithNodeTypeMutations(t *testing.T) { assert.Equal(t, tt.wantShardsAllocationDisabled, esClient.DisableReplicaShardsAllocationCalled, tt.name) /* Zen2 checks */ assert.ElementsMatch(t, tt.votingExclusionCalledWith, esClient.AddVotingConfigExclusionsCalledWith, tt.name) - /* Zen1 checks */ - assert.Equal(t, tt.minimumMasterNodesCalled, esClient.SetMinimumMasterNodesCalled, tt.name) - assert.Equal(t, tt.minimumMasterNodesCalledWith, esClient.SetMinimumMasterNodesCalledWith, tt.name) assert.Equal(t, tt.recordedEvents, len(ctx.reconcileState.Events()), tt.name) } } From b287a9016f592e8a496b4e85fd46604cd07f87c9 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 29 Dec 2025 17:31:23 +0100 Subject: [PATCH 04/10] Remove 6.x config conditionals and field constants - Remove DiscoveryZenMinimumMasterNodes and DiscoveryZenHostsProvider constants - Remove 6.x realm syntax constants (XPackSecurityAuthcRealmsFile1*, etc.) - Remove ver.Major < 7 conditionals in merged_config.go - Update 7.x minimum supported version from 6.8.0 to 7.0.0 - Update test fixtures to use 7.x versions This is part of removing Elasticsearch 6.x support from ECK. --- pkg/apis/elasticsearch/v1/fields.go | 17 ++++-------- pkg/apis/elasticsearch/v1beta1/fields.go | 15 +++-------- .../elasticsearch/v1beta1/validations_test.go | 6 ++--- .../elasticsearch/settings/merged_config.go | 27 +++++-------------- .../settings/merged_config_test.go | 3 +-- .../version/supported_versions.go | 5 ++-- .../version/supported_versions_test.go | 8 +++--- 7 files changed, 25 insertions(+), 56 deletions(-) diff --git a/pkg/apis/elasticsearch/v1/fields.go b/pkg/apis/elasticsearch/v1/fields.go index 307e8dc11c4..0295f8ece5b 100644 --- a/pkg/apis/elasticsearch/v1/fields.go +++ b/pkg/apis/elasticsearch/v1/fields.go @@ -13,12 +13,10 @@ var MinReadinessPortVersion = version.MinFor(8, 2, 0) const ( ClusterName = "cluster.name" - DiscoveryZenMinimumMasterNodes = "discovery.zen.minimum_master_nodes" - ClusterInitialMasterNodes = "cluster.initial_master_nodes" + ClusterInitialMasterNodes = "cluster.initial_master_nodes" - DiscoveryZenHostsProvider = "discovery.zen.hosts_provider" // ES < 7.X - DiscoverySeedProviders = "discovery.seed_providers" // ES >= 7.X - DiscoverySeedHosts = "discovery.seed_hosts" // ES >= 7.X + DiscoverySeedProviders = "discovery.seed_providers" + DiscoverySeedHosts = "discovery.seed_hosts" ReadinessPort = "readiness.port" // ES >= 8.2.0 @@ -38,12 +36,8 @@ const ( ShardAwarenessAttributes = "cluster.routing.allocation.awareness.attributes" NodeAttr = "node.attr" - XPackSecurityAuthcRealmsFileFile1Order = "xpack.security.authc.realms.file.file1.order" // 7.x realm syntax - XPackSecurityAuthcRealmsFile1Order = "xpack.security.authc.realms.file1.order" // 6.x realm syntax - XPackSecurityAuthcRealmsFile1Type = "xpack.security.authc.realms.file1.type" // 6.x realm syntax - XPackSecurityAuthcRealmsNativeNative1Order = "xpack.security.authc.realms.native.native1.order" // 7.x realm syntax - XPackSecurityAuthcRealmsNative1Order = "xpack.security.authc.realms.native1.order" // 6.x realm syntax - XPackSecurityAuthcRealmsNative1Type = "xpack.security.authc.realms.native1.type" // 6.x realm syntax + XPackSecurityAuthcRealmsFileFile1Order = "xpack.security.authc.realms.file.file1.order" + XPackSecurityAuthcRealmsNativeNative1Order = "xpack.security.authc.realms.native.native1.order" XPackSecurityAuthcReservedRealmEnabled = "xpack.security.authc.reserved_realm.enabled" XPackSecurityEnabled = "xpack.security.enabled" @@ -72,7 +66,6 @@ var UnsupportedSettings = []string{ ClusterName, DiscoverySeedHosts, DiscoverySeedProviders, - DiscoveryZenMinimumMasterNodes, ClusterInitialMasterNodes, NetworkHost, NetworkPublishHost, diff --git a/pkg/apis/elasticsearch/v1beta1/fields.go b/pkg/apis/elasticsearch/v1beta1/fields.go index 9d01777bb42..819789d0c56 100644 --- a/pkg/apis/elasticsearch/v1beta1/fields.go +++ b/pkg/apis/elasticsearch/v1beta1/fields.go @@ -7,11 +7,9 @@ package v1beta1 const ( ClusterName = "cluster.name" - DiscoveryZenMinimumMasterNodes = "discovery.zen.minimum_master_nodes" - ClusterInitialMasterNodes = "cluster.initial_master_nodes" + ClusterInitialMasterNodes = "cluster.initial_master_nodes" - DiscoveryZenHostsProvider = "discovery.zen.hosts_provider" // ES < 7.X - DiscoverySeedProviders = "discovery.seed_providers" // ES >= 7.X + DiscoverySeedProviders = "discovery.seed_providers" NetworkHost = "network.host" NetworkPublishHost = "network.publish_host" @@ -21,12 +19,8 @@ const ( PathData = "path.data" PathLogs = "path.logs" - XPackSecurityAuthcRealmsFileFile1Order = "xpack.security.authc.realms.file.file1.order" // 7.x realm syntax - XPackSecurityAuthcRealmsFile1Order = "xpack.security.authc.realms.file1.order" // 6.x realm syntax - XPackSecurityAuthcRealmsFile1Type = "xpack.security.authc.realms.file1.type" // 6.x realm syntax - XPackSecurityAuthcRealmsNativeNative1Order = "xpack.security.authc.realms.native.native1.order" // 7.x realm syntax - XPackSecurityAuthcRealmsNative1Order = "xpack.security.authc.realms.native1.order" // 6.x realm syntax - XPackSecurityAuthcRealmsNative1Type = "xpack.security.authc.realms.native1.type" // 6.x realm syntax + XPackSecurityAuthcRealmsFileFile1Order = "xpack.security.authc.realms.file.file1.order" + XPackSecurityAuthcRealmsNativeNative1Order = "xpack.security.authc.realms.native.native1.order" XPackSecurityAuthcReservedRealmEnabled = "xpack.security.authc.reserved_realm.enabled" XPackSecurityEnabled = "xpack.security.enabled" @@ -43,7 +37,6 @@ const ( var UnsupportedSettings = []string{ ClusterName, - DiscoveryZenMinimumMasterNodes, ClusterInitialMasterNodes, NetworkHost, NetworkPublishHost, diff --git a/pkg/apis/elasticsearch/v1beta1/validations_test.go b/pkg/apis/elasticsearch/v1beta1/validations_test.go index f0d894406aa..878f5e200f5 100644 --- a/pkg/apis/elasticsearch/v1beta1/validations_test.go +++ b/pkg/apis/elasticsearch/v1beta1/validations_test.go @@ -88,7 +88,7 @@ func Test_hasMaster(t *testing.T) { }{ { name: "no topology", - es: es("6.8.0"), + es: es("7.17.0"), expectErrors: true, }, { @@ -543,7 +543,7 @@ func TestValidation_noDowngrades(t *testing.T) { { name: "no validation on create", current: nil, - proposed: es("6.8.0"), + proposed: es("7.17.0"), expectErrors: false, }, { @@ -604,7 +604,7 @@ func Test_validUpgradePath(t *testing.T) { }, { name: "in range accepted", - current: es("6.8.0"), + current: es("7.0.0"), proposed: es("7.17.0"), expectErrors: false, }, diff --git a/pkg/controller/elasticsearch/settings/merged_config.go b/pkg/controller/elasticsearch/settings/merged_config.go index 0aa33631905..59f01f67d67 100644 --- a/pkg/controller/elasticsearch/settings/merged_config.go +++ b/pkg/controller/elasticsearch/settings/merged_config.go @@ -79,16 +79,10 @@ func baseConfig(clusterName string, ver version.Version, ipFamily corev1.IPFamil cfg[esv1.RemoteClusterHost] = "0" } - // seed hosts setting name changed starting ES 7.X - fileProvider := "file" - if ver.Major < 7 { - cfg[esv1.DiscoveryZenHostsProvider] = fileProvider - } else { - cfg[esv1.DiscoverySeedProviders] = fileProvider - // to avoid misleading error messages about the inability to connect to localhost for discovery despite us using - // file based discovery - cfg[esv1.DiscoverySeedHosts] = []string{} - } + cfg[esv1.DiscoverySeedProviders] = "file" + // to avoid misleading error messages about the inability to connect to localhost for discovery despite us using + // file based discovery + cfg[esv1.DiscoverySeedHosts] = []string{} if ver.GTE(esv1.MinReadinessPortVersion) { cfg[esv1.ReadinessPort] = "8080" @@ -153,17 +147,8 @@ func xpackConfig(ver version.Version, httpCfg commonv1.HTTPConfig, remoteCluster } // always enable the built-in file and native internal realms for user auth, ordered as first - if ver.Major < 7 { - // 6.x syntax - cfg[esv1.XPackSecurityAuthcRealmsFile1Type] = "file" - cfg[esv1.XPackSecurityAuthcRealmsFile1Order] = -100 - cfg[esv1.XPackSecurityAuthcRealmsNative1Type] = "native" - cfg[esv1.XPackSecurityAuthcRealmsNative1Order] = -99 - } else { - // 7.x syntax - cfg[esv1.XPackSecurityAuthcRealmsFileFile1Order] = -100 - cfg[esv1.XPackSecurityAuthcRealmsNativeNative1Order] = -99 - } + cfg[esv1.XPackSecurityAuthcRealmsFileFile1Order] = -100 + cfg[esv1.XPackSecurityAuthcRealmsNativeNative1Order] = -99 if ver.GTE(version.MustParse("7.8.1")) { cfg[esv1.XPackLicenseUploadTypes] = []string{ diff --git a/pkg/controller/elasticsearch/settings/merged_config_test.go b/pkg/controller/elasticsearch/settings/merged_config_test.go index 2f508834397..ceca0778513 100644 --- a/pkg/controller/elasticsearch/settings/merged_config_test.go +++ b/pkg/controller/elasticsearch/settings/merged_config_test.go @@ -142,12 +142,11 @@ func TestNewMergedESConfig(t *testing.T) { }, }, { - name: "starting 7.x, seed hosts settings should be discovery.seed_providers", + name: "seed hosts settings should be discovery.seed_providers", version: "7.0.0", ipFamily: corev1.IPv4Protocol, cfgData: map[string]interface{}{}, assert: func(cfg CanonicalConfig) { - require.Equal(t, 0, len(cfg.HasKeys([]string{esv1.DiscoveryZenHostsProvider}))) require.Equal(t, 1, len(cfg.HasKeys([]string{esv1.DiscoverySeedProviders}))) }, }, diff --git a/pkg/controller/elasticsearch/version/supported_versions.go b/pkg/controller/elasticsearch/version/supported_versions.go index 8a4d8b8a381..0079b3103c7 100644 --- a/pkg/controller/elasticsearch/version/supported_versions.go +++ b/pkg/controller/elasticsearch/version/supported_versions.go @@ -22,9 +22,8 @@ func technicallySupportedVersions(v version.Version) *version.MinMaxVersion { switch v.Major { case 7: return &version.MinMaxVersion{ - // 6.8.0 is the lowest wire compatibility version for 7.x - Min: version.MustParse("6.8.0"), - // higher may be possible, but not proven yet, lower may also be a requirement... + // 7.0.0 is the minimum supported version for 7.x + Min: version.MustParse("7.0.0"), Max: version.MustParse("7.99.99"), } case 8: diff --git a/pkg/controller/elasticsearch/version/supported_versions_test.go b/pkg/controller/elasticsearch/version/supported_versions_test.go index 64ae21ea123..6a33a5d08fb 100644 --- a/pkg/controller/elasticsearch/version/supported_versions_test.go +++ b/pkg/controller/elasticsearch/version/supported_versions_test.go @@ -29,12 +29,12 @@ func TestSupportedVersions(t *testing.T) { v: version.MustParse("7.1.0"), }, supported: []version.Version{ - version.MustParse("6.8.0"), // wire compat + version.MustParse("7.0.0"), version.MustParse("7.2.0"), version.MustParse("7.99.99"), }, unsupported: []version.Version{ - version.MustParse("6.6.0"), + version.MustParse("6.8.0"), version.MustParse("8.0.0"), }, }, @@ -82,7 +82,7 @@ func Test_supportedVersionsWithMinimum(t *testing.T) { min: version.Version{}, }, want: &version.MinMaxVersion{ - Min: version.MustParse("6.8.0"), + Min: version.MustParse("7.0.0"), Max: version.MustParse("7.99.99"), }, }, @@ -93,7 +93,7 @@ func Test_supportedVersionsWithMinimum(t *testing.T) { min: version.MustParse("7.10.0"), }, want: &version.MinMaxVersion{ - Min: version.MustParse("6.8.0"), + Min: version.MustParse("7.0.0"), Max: version.MustParse("7.99.99"), }, }, From 71024cc6531e51979453abeb66a5a0689d0a2c8c Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 29 Dec 2025 17:39:53 +0100 Subject: [PATCH 05/10] Remove ApmUserRoleV6 and update APM associations - Remove ApmUserRoleV6 constant and role definition from roles.go - Update getAPMElasticsearchRoles() to use v7 role as fallback - Remove 6.8.x test cases from apm_es_test.go - Update expected role count from 58 to 57 in reconcile_test.go - Update validation test to use 7.0.0 instead of 6.8.0 This is part of removing Elasticsearch 6.x support from ECK. --- pkg/controller/association/controller/apm_es.go | 14 +++----------- .../association/controller/apm_es_test.go | 15 +++------------ .../elasticsearch/user/reconcile_test.go | 2 +- pkg/controller/elasticsearch/user/roles.go | 11 ----------- .../elasticsearch/validation/validations_test.go | 2 +- 5 files changed, 8 insertions(+), 36 deletions(-) diff --git a/pkg/controller/association/controller/apm_es.go b/pkg/controller/association/controller/apm_es.go index a1fc51adb3d..960aed83c6f 100644 --- a/pkg/controller/association/controller/apm_es.go +++ b/pkg/controller/association/controller/apm_es.go @@ -125,18 +125,10 @@ func getAPMElasticsearchRoles(associated commonv1.Associated) (string, error) { }, ","), nil } - // 7.1.x to 7.4.x - if v.GTE(version.From(7, 1, 0)) { - return strings.Join([]string{ - user.ApmUserRoleV7, // Retrieve cluster details (e.g. version) and manage apm-* indices - "ingest_admin", // Set up index templates - "apm_system", // To collect metrics about APM Server - }, ","), nil - } - - // 6.8 + // 7.1.x to 7.4.x (and fallback for any older 7.x versions) return strings.Join([]string{ - user.ApmUserRoleV6, // Retrieve cluster details (e.g. version) and manage apm-* indices + user.ApmUserRoleV7, // Retrieve cluster details (e.g. version) and manage apm-* indices + "ingest_admin", // Set up index templates "apm_system", // To collect metrics about APM Server }, ","), nil } diff --git a/pkg/controller/association/controller/apm_es_test.go b/pkg/controller/association/controller/apm_es_test.go index f71d13a23b7..2b92b52a92e 100644 --- a/pkg/controller/association/controller/apm_es_test.go +++ b/pkg/controller/association/controller/apm_es_test.go @@ -22,22 +22,13 @@ func Test_getAPMElasticsearchRoles(t *testing.T) { wantErr bool }{ { - name: "Test roles for APM Server v6.8.0", + name: "Test roles for APM Server v7.0.0", args: args{ associated: &apmv1.ApmServer{ - Spec: apmv1.ApmServerSpec{Version: "6.8.0"}, + Spec: apmv1.ApmServerSpec{Version: "7.0.0"}, }, }, - want: "eck_apm_user_role_v6,apm_system", - }, - { - name: "Test roles for APM Server v6.8.99", - args: args{ - associated: &apmv1.ApmServer{ - Spec: apmv1.ApmServerSpec{Version: "6.8.99"}, - }, - }, - want: "eck_apm_user_role_v6,apm_system", + want: "eck_apm_user_role_v7,ingest_admin,apm_system", }, { name: "Test roles for APM Server v7.1.0", diff --git a/pkg/controller/elasticsearch/user/reconcile_test.go b/pkg/controller/elasticsearch/user/reconcile_test.go index 547c38ccd75..daac766b992 100644 --- a/pkg/controller/elasticsearch/user/reconcile_test.go +++ b/pkg/controller/elasticsearch/user/reconcile_test.go @@ -131,6 +131,6 @@ func Test_aggregateRoles(t *testing.T) { c := k8s.NewFakeClient(sampleUserProvidedRolesSecret...) roles, err := aggregateRoles(context.Background(), c, sampleEsWithAuth, initDynamicWatches(), record.NewFakeRecorder(10)) require.NoError(t, err) - require.Len(t, roles, 58) + require.Len(t, roles, 57) require.Contains(t, roles, ProbeUserRole, ClusterManageRole, "role1", "role2") } diff --git a/pkg/controller/elasticsearch/user/roles.go b/pkg/controller/elasticsearch/user/roles.go index a18fabc4a4e..3b1df195fd4 100644 --- a/pkg/controller/elasticsearch/user/roles.go +++ b/pkg/controller/elasticsearch/user/roles.go @@ -32,8 +32,6 @@ const ( // DiagnosticsUserRoleV85 is the name of the built-in role for ECK diagnostics use from version 8.5. DiagnosticsUserRoleV85 = "elastic_internal_diagnostics_v85" - // ApmUserRoleV6 is the name of the role used by 6.8.x APMServer instances to connect to Elasticsearch. - ApmUserRoleV6 = "eck_apm_user_role_v6" // ApmUserRoleV7 is the name of the role used by APMServer instances to connect to Elasticsearch from version 7.1 to 7.4 included. ApmUserRoleV7 = "eck_apm_user_role_v7" // ApmUserRoleV75 is the name of the role used by APMServer instances to connect to Elasticsearch from version 7.5 @@ -137,15 +135,6 @@ var ( Indices: diagnosticsRoleIndices, Applications: diagnosticsAppsKibanaPrivileges, }, - ApmUserRoleV6: esclient.Role{ - Cluster: []string{"monitor", "manage_index_templates"}, - Indices: []esclient.IndexRole{ - { - Names: []string{"apm-*"}, - Privileges: []string{"write", "create_index"}, - }, - }, - }, ApmUserRoleV7: esclient.Role{ Cluster: []string{"monitor", "manage_ilm", "manage_index_templates"}, Indices: []esclient.IndexRole{ diff --git a/pkg/controller/elasticsearch/validation/validations_test.go b/pkg/controller/elasticsearch/validation/validations_test.go index 582ed096828..14a9f6ca84d 100644 --- a/pkg/controller/elasticsearch/validation/validations_test.go +++ b/pkg/controller/elasticsearch/validation/validations_test.go @@ -475,7 +475,7 @@ func Test_validUpgradePath(t *testing.T) { }, { name: "in range accepted", - current: es("6.8.0"), + current: es("7.0.0"), proposed: es("7.17.0"), expectErrors: false, }, From 3374b5c950998e012843a14077690a750ad976ad Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Tue, 30 Dec 2025 11:03:02 +0100 Subject: [PATCH 06/10] Update test fixtures and cleanup remaining 6.x references - Remove ES 6.x reference from bootstrap.go comment - Update sset/list_test.go to use 7.x/8.x instead of 6.x/7.x - Remove 6.x test case from kibana/config_reconcile_test.go - Update 'no topology' test to use 7.0.0 in validations_test.go - Update test fixtures (info.go, nodes.go) to use 7.17.0 - Update client_test.go assertion for new fixture version This is the final commit for removing Elasticsearch 6.x support from ECK. --- .../elasticsearch/bootstrap/bootstrap.go | 3 +-- pkg/controller/elasticsearch/client/client_test.go | 2 +- .../elasticsearch/client/test_fixtures/info.go | 12 ++++++------ .../elasticsearch/client/test_fixtures/nodes.go | 6 +++--- pkg/controller/elasticsearch/sset/list_test.go | 14 +++++++------- .../elasticsearch/validation/validations_test.go | 2 +- pkg/controller/kibana/config_reconcile_test.go | 5 ----- 7 files changed, 19 insertions(+), 25 deletions(-) diff --git a/pkg/controller/elasticsearch/bootstrap/bootstrap.go b/pkg/controller/elasticsearch/bootstrap/bootstrap.go index 60df9ba9914..f3334d8434a 100644 --- a/pkg/controller/elasticsearch/bootstrap/bootstrap.go +++ b/pkg/controller/elasticsearch/bootstrap/bootstrap.go @@ -45,8 +45,7 @@ func ReconcileClusterUUID(ctx context.Context, k8sClient k8s.Client, cluster *es clusterUUID, err := getClusterUUID(ctx, esClient) if err != nil { // There was an error while retrieving the UUID of the Elasticsearch cluster. - // For example, it could be the case with ES 6.x if the cluster does not have a master yet, in this case an - // API call to get the cluster UUID returns a 503 error. + // For example, if the cluster does not have a master yet, an API call to get the cluster UUID returns a 503 error. // However we don't want to stop the reconciliation loop here because it could prevent the user to apply // an update to the cluster spec to fix a problem. // Therefore we just log the error and notify the driver that the reconciliation should be eventually re-queued. diff --git a/pkg/controller/elasticsearch/client/client_test.go b/pkg/controller/elasticsearch/client/client_test.go index d4046cd3a0c..f55254862eb 100644 --- a/pkg/controller/elasticsearch/client/client_test.go +++ b/pkg/controller/elasticsearch/client/client_test.go @@ -351,7 +351,7 @@ func TestGetInfo(t *testing.T) { require.NoError(t, err) require.Equal(t, "af932d24216a4dd69ba47d2fd3214796", info.ClusterName) require.Equal(t, "LGA3VblKTNmzP6Q6SWxfkw", info.ClusterUUID) - require.Equal(t, "6.4.1", info.Version.Number) // This is the version reported by the ES API response in the fixture, not the client version + require.Equal(t, "7.17.0", info.Version.Number) // This is the version reported by the ES API response in the fixture, not the client version } func TestClient_Equal(t *testing.T) { diff --git a/pkg/controller/elasticsearch/client/test_fixtures/info.go b/pkg/controller/elasticsearch/client/test_fixtures/info.go index 3111431c518..77f048de5cb 100644 --- a/pkg/controller/elasticsearch/client/test_fixtures/info.go +++ b/pkg/controller/elasticsearch/client/test_fixtures/info.go @@ -9,12 +9,12 @@ const ( "cluster_name": "af932d24216a4dd69ba47d2fd3214796", "cluster_uuid": "LGA3VblKTNmzP6Q6SWxfkw", "version": { - "build_date": "2018-09-13T22:18:07.696808Z", - "minimum_wire_compatibility_version": "6.5.0", - "build_hash": "e36acdb", - "number": "6.4.1", - "lucene_version": "7.4.0", - "minimum_index_compatibility_version": "5.0.0", + "build_date": "2021-01-13T00:42:12.435326Z", + "minimum_wire_compatibility_version": "6.8.0", + "build_hash": "78722783c38caa25a70982b5b042074cde5d3b3a", + "number": "7.17.0", + "lucene_version": "8.11.1", + "minimum_index_compatibility_version": "6.0.0-beta1", "build_flavor": "default", "build_snapshot": false, "build_type": "tar" diff --git a/pkg/controller/elasticsearch/client/test_fixtures/nodes.go b/pkg/controller/elasticsearch/client/test_fixtures/nodes.go index 2a122f673a1..00ba4128d1a 100644 --- a/pkg/controller/elasticsearch/client/test_fixtures/nodes.go +++ b/pkg/controller/elasticsearch/client/test_fixtures/nodes.go @@ -168,7 +168,7 @@ const ( }, "ip": "172.25.98.100", "host": "172.25.98.100", - "version": "6.4.1", + "version": "7.17.0", "jvm": { "vm_name": "Java HotSpot(TM) 64-Bit Server VM", "vm_version": "25.144-b01", @@ -402,7 +402,7 @@ const ( }, "ip": "172.25.137.90", "host": "172.25.137.90", - "version": "6.4.1", + "version": "7.17.0", "jvm": { "vm_name": "Java HotSpot(TM) 64-Bit Server VM", "vm_version": "25.144-b01", @@ -639,7 +639,7 @@ const ( }, "ip": "172.25.133.112", "host": "172.25.133.112", - "version": "6.4.1", + "version": "7.17.0", "jvm": { "vm_name": "Java HotSpot(TM) 64-Bit Server VM", "vm_version": "25.144-b01", diff --git a/pkg/controller/elasticsearch/sset/list_test.go b/pkg/controller/elasticsearch/sset/list_test.go index a5b20589867..2d7ae44a04e 100644 --- a/pkg/controller/elasticsearch/sset/list_test.go +++ b/pkg/controller/elasticsearch/sset/list_test.go @@ -83,23 +83,23 @@ func TestESVersionMatch(t *testing.T) { ) require.Equal(t, false, ESVersionMatch(context.Background(), ssetv7, func(v version.Version) bool { - return v.Major == 6 + return v.Major == 8 }), ) } func TestAtLeastOneESVersionMatch(t *testing.T) { - ssetv6 := *ssetv7.DeepCopy() - ssetv6.Spec.Template.Labels[label.VersionLabelName] = "6.8.0" + ssetv8 := *ssetv7.DeepCopy() + ssetv8.Spec.Template.Labels[label.VersionLabelName] = "8.0.0" require.Equal(t, true, - StatefulSetList{ssetv6, ssetv7}.AtLeastOneESVersionMatch(context.Background(), func(v version.Version) bool { - return v.Major == 7 + StatefulSetList{ssetv7, ssetv8}.AtLeastOneESVersionMatch(context.Background(), func(v version.Version) bool { + return v.Major == 8 }), ) require.Equal(t, false, - StatefulSetList{ssetv6, ssetv6}.AtLeastOneESVersionMatch(context.Background(), func(v version.Version) bool { - return v.Major == 7 + StatefulSetList{ssetv7, ssetv7}.AtLeastOneESVersionMatch(context.Background(), func(v version.Version) bool { + return v.Major == 8 }), ) } diff --git a/pkg/controller/elasticsearch/validation/validations_test.go b/pkg/controller/elasticsearch/validation/validations_test.go index 14a9f6ca84d..eca1fab761e 100644 --- a/pkg/controller/elasticsearch/validation/validations_test.go +++ b/pkg/controller/elasticsearch/validation/validations_test.go @@ -111,7 +111,7 @@ func Test_hasCorrectNodeRoles(t *testing.T) { }{ { name: "no topology", - es: esWithRoles("6.8.0", 1), + es: esWithRoles("7.0.0", 1), expectErrors: true, }, { diff --git a/pkg/controller/kibana/config_reconcile_test.go b/pkg/controller/kibana/config_reconcile_test.go index a0aad83a66f..332ea73f1d6 100644 --- a/pkg/controller/kibana/config_reconcile_test.go +++ b/pkg/controller/kibana/config_reconcile_test.go @@ -127,11 +127,6 @@ func TestVersionDefaults(t *testing.T) { version string want *settings.CanonicalConfig }{ - { - name: "6.x", - version: "6.8.5", - want: settings.NewCanonicalConfig(), - }, { name: "7.x", version: "7.1.0", From febb0361487b2435a4dd49bf40986312e571ae2c Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Tue, 30 Dec 2025 12:37:04 +0100 Subject: [PATCH 07/10] Clean up e2e tests and remove dead code E2E test cleanup: - Remove 6.x upgrade path test cases from version_test.go - Update TLS handshake comment in checks_transport.go - Use 7.x as default in APM index naming instead of 6.x - Simplify comments in reversal_test.go and remote_cluster_test.go Dead code removal: - Remove unused ZenDiscoveryStatus struct from v1beta1 API - Remove unused statefulSets parameter from downscale functions - Remove unused toPodPtr() helper from fixtures.go This completes the removal of Elasticsearch 6.x support from ECK. --- docs/reference/api-reference/main.md | 2 -- .../elasticsearch/v1beta1/elasticsearch_types.go | 4 ---- .../v1beta1/zz_generated.deepcopy.go | 15 --------------- pkg/controller/elasticsearch/driver/downscale.go | 7 +++---- .../elasticsearch/driver/downscale_test.go | 6 +++--- pkg/controller/elasticsearch/driver/fixtures.go | 5 ----- test/e2e/es/remote_cluster_test.go | 2 +- test/e2e/es/reversal_test.go | 6 ++---- test/e2e/test/apmserver/checks_apm.go | 10 ++++------ test/e2e/test/elasticsearch/checks_transport.go | 2 +- test/e2e/test/version_test.go | 5 ++--- 11 files changed, 16 insertions(+), 48 deletions(-) diff --git a/docs/reference/api-reference/main.md b/docs/reference/api-reference/main.md index 1712bc79d46..86eec84bc8d 100644 --- a/docs/reference/api-reference/main.md +++ b/docs/reference/api-reference/main.md @@ -1649,8 +1649,6 @@ UpdateStrategy specifies how updates to the cluster should be performed. - - % TODO add function to crd-ref-docs return anchor used in links docs-v3 does not seem to produce valid markdown anchors ## enterprisesearch.k8s.elastic.co/v1 [#enterprisesearchk8selasticcov1] diff --git a/pkg/apis/elasticsearch/v1beta1/elasticsearch_types.go b/pkg/apis/elasticsearch/v1beta1/elasticsearch_types.go index a17cac4ae47..b0df730cc36 100644 --- a/pkg/apis/elasticsearch/v1beta1/elasticsearch_types.go +++ b/pkg/apis/elasticsearch/v1beta1/elasticsearch_types.go @@ -193,10 +193,6 @@ type ElasticsearchStatus struct { Phase ElasticsearchOrchestrationPhase `json:"phase,omitempty"` } -type ZenDiscoveryStatus struct { - MinimumMasterNodes int `json:"minimumMasterNodes,omitempty"` -} - // IsDegraded returns true if the current status is worse than the previous. func (es ElasticsearchStatus) IsDegraded(prev ElasticsearchStatus) bool { return es.Health.Less(prev.Health) diff --git a/pkg/apis/elasticsearch/v1beta1/zz_generated.deepcopy.go b/pkg/apis/elasticsearch/v1beta1/zz_generated.deepcopy.go index 438eb256ed0..68ea2323f44 100644 --- a/pkg/apis/elasticsearch/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/elasticsearch/v1beta1/zz_generated.deepcopy.go @@ -244,18 +244,3 @@ func (in *UpdateStrategy) DeepCopy() *UpdateStrategy { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZenDiscoveryStatus) DeepCopyInto(out *ZenDiscoveryStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZenDiscoveryStatus. -func (in *ZenDiscoveryStatus) DeepCopy() *ZenDiscoveryStatus { - if in == nil { - return nil - } - out := new(ZenDiscoveryStatus) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/controller/elasticsearch/driver/downscale.go b/pkg/controller/elasticsearch/driver/downscale.go index b189e4ae48d..f5ece902f97 100644 --- a/pkg/controller/elasticsearch/driver/downscale.go +++ b/pkg/controller/elasticsearch/driver/downscale.go @@ -73,7 +73,7 @@ func HandleDownscale( for _, downscale := range downscales { // attempt the StatefulSet downscale (may or may not remove nodes) - requeue, err := attemptDownscale(downscaleCtx, downscale, actualStatefulSets) + requeue, err := attemptDownscale(downscaleCtx, downscale) if err != nil { return results.WithError(err) } @@ -180,7 +180,6 @@ func downscaleBudgetFilter(ctx context.Context, state *downscaleState, actualSse func attemptDownscale( ctx downscaleContext, downscale ssetDownscale, - statefulSets es_sset.StatefulSetList, ) (bool, error) { // adjust the theoretical downscale to one we can safely perform performable, err := calculatePerformableDownscale(ctx, downscale) @@ -193,7 +192,7 @@ func attemptDownscale( } // do performable downscale, and requeue if needed shouldRequeue := performable.targetReplicas != downscale.finalReplicas - return shouldRequeue, doDownscale(ctx, performable, statefulSets) + return shouldRequeue, doDownscale(ctx, performable) } // deleteStatefulSetResources deletes the given StatefulSet along with the corresponding @@ -278,7 +277,7 @@ func calculatePerformableDownscale( } // doDownscale schedules nodes removal for the given downscale, and updates zen settings accordingly. -func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale, actualStatefulSets es_sset.StatefulSetList) error { +func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale) error { ssetLogger(downscaleCtx.parentCtx, downscale.statefulSet).Info( "Scaling replicas down", "from", downscale.initialReplicas, diff --git a/pkg/controller/elasticsearch/driver/downscale_test.go b/pkg/controller/elasticsearch/driver/downscale_test.go index 39102be3d5c..355710cc134 100644 --- a/pkg/controller/elasticsearch/driver/downscale_test.go +++ b/pkg/controller/elasticsearch/driver/downscale_test.go @@ -855,7 +855,7 @@ func Test_attemptDownscale(t *testing.T) { parentCtx: context.Background(), } // do the downscale - _, err := attemptDownscale(downscaleCtx, tt.downscale, tt.statefulSets) + _, err := attemptDownscale(downscaleCtx, tt.downscale) require.NoError(t, err) // retrieve statefulsets var ssets appsv1.StatefulSetList @@ -901,7 +901,7 @@ func Test_doDownscale_updateReplicasAndExpectations(t *testing.T) { require.Len(t, downscaleCtx.expectations.GetGenerations(), 0) // do the downscale - err := doDownscale(downscaleCtx, downscale, es_sset.StatefulSetList{sset1, sset2}) + err := doDownscale(downscaleCtx, downscale) require.NoError(t, err) // sset resource should be updated @@ -989,7 +989,7 @@ func Test_doDownscale_zen2VotingConfigExclusions(t *testing.T) { parentCtx: context.Background(), } // do the downscale - err := doDownscale(downscaleCtx, tt.downscale, es_sset.StatefulSetList{ssetMasters, ssetData}) + err := doDownscale(downscaleCtx, tt.downscale) require.NoError(t, err) // check call to zen2 is the expected one require.Equal(t, tt.wantZen2Called, esClient.AddVotingConfigExclusionsCalled) diff --git a/pkg/controller/elasticsearch/driver/fixtures.go b/pkg/controller/elasticsearch/driver/fixtures.go index cac5825d0a6..84ff22eaa66 100644 --- a/pkg/controller/elasticsearch/driver/fixtures.go +++ b/pkg/controller/elasticsearch/driver/fixtures.go @@ -334,11 +334,6 @@ func (t testPod) toPod() corev1.Pod { return pod } -func (t testPod) toPodPtr() *corev1.Pod { - pod := t.toPod() - return &pod -} - type testESState struct { inCluster []string health client.Health diff --git a/test/e2e/es/remote_cluster_test.go b/test/e2e/es/remote_cluster_test.go index ac8b7d1dac2..b3e06f404e9 100644 --- a/test/e2e/es/remote_cluster_test.go +++ b/test/e2e/es/remote_cluster_test.go @@ -84,7 +84,7 @@ func TestRemoteCluster(t *testing.T) { test.Step{ Name: "Add some data to the first cluster", Test: func(t *testing.T) { - // Always enable soft deletes on test index. This is required to create follower indices but disabled by default on 6.x + // Always enable soft deletes on test index. This is required to create follower indices. require.NoError(t, elasticsearch.NewDataIntegrityCheck(k, es1Builder).WithSoftDeletesEnabled(true).Init()) }, }, diff --git a/test/e2e/es/reversal_test.go b/test/e2e/es/reversal_test.go index 8cba4c8ecfe..9cc2b13ed0b 100644 --- a/test/e2e/es/reversal_test.go +++ b/test/e2e/es/reversal_test.go @@ -37,10 +37,8 @@ func TestReversalRiskyMasterDownscale(t *testing.T) { b := elasticsearch.NewBuilder("test-non-ha-downscale-reversal"). WithESMasterDataNodes(2, elasticsearch.DefaultResources) - // we then scale it down to 1 node, which for 6.x cluster in particular is a risky operation - // after reversing we expect a cluster to re-form. There is some potential for data loss - // in case the cluster indeed goes into split-brain. - // TODO it might be necessary to accept some data loss for 6.x here + // we then scale it down to 1 node. + // after reversing we expect a cluster to re-form. down := b.WithNoESTopology().WithESMasterDataNodes(1, elasticsearch.DefaultResources) RunESMutationReversal(t, b, down) diff --git a/test/e2e/test/apmserver/checks_apm.go b/test/e2e/test/apmserver/checks_apm.go index fb4686c5d96..c7b7b767465 100644 --- a/test/e2e/test/apmserver/checks_apm.go +++ b/test/e2e/test/apmserver/checks_apm.go @@ -300,17 +300,15 @@ func getIndexNames(apm apmv1.ApmServer) (string, string, error) { } // Check that the metric and error have been stored - // default to indices names from 6.x - metricIndex = fmt.Sprintf("apm-%s-2017.05.30", apm.EffectiveVersion()) - errorIndex = fmt.Sprintf("apm-%s-2018.08.09", apm.EffectiveVersion()) switch v.Major { - case 7: - metricIndex = fmt.Sprintf("apm-%s-metric-2017.05.30", apm.EffectiveVersion()) - errorIndex = fmt.Sprintf("apm-%s-error-2018.08.09", apm.EffectiveVersion()) case 8, 9: // these are datastreams and not indices, but can be searched/counted in the same way metricIndex = "metrics-apm.app.1234_service_12a3-default" errorIndex = "logs-apm.error-default" + default: + // 7.x index naming + metricIndex = fmt.Sprintf("apm-%s-metric-2017.05.30", apm.EffectiveVersion()) + errorIndex = fmt.Sprintf("apm-%s-error-2018.08.09", apm.EffectiveVersion()) } return metricIndex, errorIndex, nil diff --git a/test/e2e/test/elasticsearch/checks_transport.go b/test/e2e/test/elasticsearch/checks_transport.go index 7f05bf37488..940d0129a09 100644 --- a/test/e2e/test/elasticsearch/checks_transport.go +++ b/test/e2e/test/elasticsearch/checks_transport.go @@ -62,7 +62,7 @@ func CheckTransportCACertificate(es esv1.Elasticsearch, ca *x509.Certificate) er return err } client := tls.Client(conn, &config) - // handshake can fail on 6.x versions of Elasticsearch because the test client is not presenting the right certificates + // handshake can fail if the test client is not presenting the right certificates // but we are only interested in the peer certificates err = client.Handshake() if correctCertsPresented { diff --git a/test/e2e/test/version_test.go b/test/e2e/test/version_test.go index 144733520bd..3050a381690 100644 --- a/test/e2e/test/version_test.go +++ b/test/e2e/test/version_test.go @@ -17,17 +17,16 @@ func TestIsValidUpgrade(t *testing.T) { isValid bool }{ // valid upgrade paths - {from: "6.8.5", to: "6.8.6", isValid: true}, - {from: "6.8.5", to: "7.1.1", isValid: true}, {from: "7.1.1", to: "7.6.0", isValid: true}, {from: "7.17.0", to: "8.0.0", isValid: true}, + {from: "8.0.0", to: "8.15.0", isValid: true}, // invalid upgrade paths {from: "7.16.0", to: "8.0.0", isValid: false}, {from: "7.6.0", to: "8.0.0-SNAPSHOT", isValid: false}, {from: "7.6.0", to: "7.6.0", isValid: false}, {from: "7.6.0", to: "7.5.0", isValid: false}, {from: "7.6.1", to: "7.6.0", isValid: false}, - {from: "7.6.0", to: "6.8.5", isValid: false}, + {from: "8.0.0", to: "7.17.0", isValid: false}, {from: "7.6.0", to: "9.0.0", isValid: false}, {from: "7.6.0-SNAPSHOT", to: "7.7.0", isValid: false}, } From 90eae571e5cf9b783b3fb65d4ccfcb8885452b72 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 5 Jan 2026 11:42:57 +0100 Subject: [PATCH 08/10] Input from code review: * update e2e test comment * inline call to zen2.AddToVotingConfigExclusions --- .../elasticsearch/driver/downscale.go | 18 +++--------------- .../driver/upgrade_pods_deletion.go | 6 ++++-- test/e2e/es/mutation_test.go | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/pkg/controller/elasticsearch/driver/downscale.go b/pkg/controller/elasticsearch/driver/downscale.go index f5ece902f97..3ceacbe37a7 100644 --- a/pkg/controller/elasticsearch/driver/downscale.go +++ b/pkg/controller/elasticsearch/driver/downscale.go @@ -285,12 +285,13 @@ func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale) error { ) if label.IsMasterNodeSet(downscale.statefulSet) { - if err := updateZenSettingsForDownscale( + // Update zen2 settings to exclude leaving master nodes from voting. + if err := zen2.AddToVotingConfigExclusions( downscaleCtx.parentCtx, downscaleCtx.k8sClient, downscaleCtx.esClient, downscaleCtx.es, - downscale.leavingNodeNames()..., + downscale.leavingNodeNames(), ); err != nil { return err } @@ -306,16 +307,3 @@ func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale) error { return nil } - -// updateZenSettingsForDownscale makes sure zen2 settings are updated to account for nodes -// that will soon be removed. -func updateZenSettingsForDownscale( - ctx context.Context, - c k8s.Client, - esClient esclient.Client, - es esv1.Elasticsearch, - excludeNodes ...string, -) error { - // Update zen2 settings to exclude leaving master nodes from voting. - return zen2.AddToVotingConfigExclusions(ctx, c, esClient, es, excludeNodes) -} diff --git a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go index 2b6124ab0c4..7f890049ae9 100644 --- a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go +++ b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go @@ -16,6 +16,7 @@ import ( "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/reconcile" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" + "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/version/zen2" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/stringsutil" @@ -193,12 +194,13 @@ func sortCandidates(allPods []corev1.Pod) { func (ctx *upgradeCtx) handleMasterScaleChange(pod corev1.Pod) error { masterScaleDown := label.IsMasterNode(pod) && !stringsutil.StringInSlice(pod.Name, ctx.expectedMasters) if masterScaleDown { - if err := updateZenSettingsForDownscale( + // Update zen2 settings to exclude leaving master nodes from voting. + if err := zen2.AddToVotingConfigExclusions( ctx.parentCtx, ctx.client, ctx.esClient, ctx.ES, - pod.Name, + []string{pod.Name}, ); err != nil { return err } diff --git a/test/e2e/es/mutation_test.go b/test/e2e/es/mutation_test.go index 1a62e5f9a63..b9e3f6fba09 100644 --- a/test/e2e/es/mutation_test.go +++ b/test/e2e/es/mutation_test.go @@ -76,7 +76,7 @@ func TestMutationMoreNodes(t *testing.T) { // TestMutationLessNodes creates a 3 node cluster, // then mutates it to a 1 node cluster. -// Covers the special case of going from 2 to 1 master node with zen1. +// Covers the special case of going from 3 (HA) to 1 (non-HA) on a mixed node role cluster. func TestMutationLessNodes(t *testing.T) { // create an ES cluster with 3 node b := elasticsearch.NewBuilder("test-mutation-less-nodes"). From 3b21f597c5386a3381145414ce0f8779d067bf2e Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 5 Jan 2026 12:17:53 +0100 Subject: [PATCH 09/10] Remove zen2 compatibility checks after ES 6.x support removal With Elasticsearch 6.x support removed, all supported versions are now 7.0+ and use zen2 for cluster coordination. This removes the obsolete compatibility checks that were only needed during 6.x to 7.x upgrades. Changes: - Remove AllMastersCompatibleWithZen2, IsCompatibleWithZen2, and versionCompatibleWithZen2 functions - Delete compatibility.go and compatibility_test.go - Simplify AddToVotingConfigExclusions by removing k8s.Client parameter (was only needed for compatibility check) - Remove compatibility checks from ClearVotingConfigExclusions - Simplify shouldSetInitialMasterNodes and RemoveZen2BootstrapAnnotation by removing version checks - Remove version check from patchInitialMasterNodesConfig - Fix test setup to properly initialize CanonicalConfig --- .../elasticsearch/driver/downscale.go | 1 - .../driver/upgrade_pods_deletion.go | 1 - .../elasticsearch/driver/upscale_test.go | 8 +- .../version/zen2/compatibility.go | 50 -------- .../version/zen2/compatibility_test.go | 108 ------------------ .../version/zen2/initial_master_nodes.go | 35 +++--- .../version/zen2/voting_exclusions.go | 18 +-- .../version/zen2/voting_exclusions_test.go | 14 +-- 8 files changed, 19 insertions(+), 216 deletions(-) delete mode 100644 pkg/controller/elasticsearch/version/zen2/compatibility.go delete mode 100644 pkg/controller/elasticsearch/version/zen2/compatibility_test.go diff --git a/pkg/controller/elasticsearch/driver/downscale.go b/pkg/controller/elasticsearch/driver/downscale.go index 3ceacbe37a7..220721f7cc0 100644 --- a/pkg/controller/elasticsearch/driver/downscale.go +++ b/pkg/controller/elasticsearch/driver/downscale.go @@ -288,7 +288,6 @@ func doDownscale(downscaleCtx downscaleContext, downscale ssetDownscale) error { // Update zen2 settings to exclude leaving master nodes from voting. if err := zen2.AddToVotingConfigExclusions( downscaleCtx.parentCtx, - downscaleCtx.k8sClient, downscaleCtx.esClient, downscaleCtx.es, downscale.leavingNodeNames(), diff --git a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go index 7f890049ae9..54851fdb2d3 100644 --- a/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go +++ b/pkg/controller/elasticsearch/driver/upgrade_pods_deletion.go @@ -197,7 +197,6 @@ func (ctx *upgradeCtx) handleMasterScaleChange(pod corev1.Pod) error { // Update zen2 settings to exclude leaving master nodes from voting. if err := zen2.AddToVotingConfigExclusions( ctx.parentCtx, - ctx.client, ctx.esClient, ctx.ES, []string{pod.Name}, diff --git a/pkg/controller/elasticsearch/driver/upscale_test.go b/pkg/controller/elasticsearch/driver/upscale_test.go index 68d61d73b91..a3a5860c569 100644 --- a/pkg/controller/elasticsearch/driver/upscale_test.go +++ b/pkg/controller/elasticsearch/driver/upscale_test.go @@ -139,7 +139,7 @@ func TestHandleUpscaleAndSpecChanges(t *testing.T) { Name: "sset1", }, }, - Config: settings.CanonicalConfig{}, + Config: settings.NewCanonicalConfig(), }, { StatefulSet: appsv1.StatefulSet{ @@ -157,7 +157,7 @@ func TestHandleUpscaleAndSpecChanges(t *testing.T) { Name: "sset2", }, }, - Config: settings.CanonicalConfig{}, + Config: settings.NewCanonicalConfig(), }, } @@ -293,7 +293,7 @@ func TestHandleUpscaleAndSpecChanges_PVCResize(t *testing.T) { Name: "sset1", }, }, - Config: settings.CanonicalConfig{}, + Config: settings.NewCanonicalConfig(), }, { StatefulSet: dataResized, @@ -303,7 +303,7 @@ func TestHandleUpscaleAndSpecChanges_PVCResize(t *testing.T) { Name: "sset2", }, }, - Config: settings.CanonicalConfig{}, + Config: settings.NewCanonicalConfig(), }, } diff --git a/pkg/controller/elasticsearch/version/zen2/compatibility.go b/pkg/controller/elasticsearch/version/zen2/compatibility.go deleted file mode 100644 index 43dd76222a9..00000000000 --- a/pkg/controller/elasticsearch/version/zen2/compatibility.go +++ /dev/null @@ -1,50 +0,0 @@ -// 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 zen2 - -import ( - "context" - - appsv1 "k8s.io/api/apps/v1" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/sset" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" -) - -// zen2VersionMatch returns true if the given Elasticsearch versionCompatibleWithZen2 is compatible with zen2. -func versionCompatibleWithZen2(v version.Version) bool { - return v.Major >= 7 -} - -// IsCompatibleWithZen2 returns true if the given StatefulSet is compatible with zen2. -func IsCompatibleWithZen2(ctx context.Context, statefulSet appsv1.StatefulSet) bool { - return sset.ESVersionMatch(ctx, statefulSet, versionCompatibleWithZen2) -} - -// AllMastersCompatibleWithZen2 returns true if all master nodes in the given cluster can use zen2 APIs. -// During a v6 -> v7 rolling upgrade, we can only call zen2 APIs once the current master is using v7, -// which would happen only if there is no more v6 master-eligible nodes in the cluster. -func AllMastersCompatibleWithZen2(c k8s.Client, es esv1.Elasticsearch) (bool, error) { - masters, err := sset.GetActualMastersForCluster(c, es) - if err != nil { - return false, err - } - if len(masters) == 0 { - return false, nil - } - for _, pod := range masters { - v, err := label.ExtractVersion(pod.Labels) - if err != nil { - return false, err - } - if !versionCompatibleWithZen2(v) { - return false, nil - } - } - return true, nil -} diff --git a/pkg/controller/elasticsearch/version/zen2/compatibility_test.go b/pkg/controller/elasticsearch/version/zen2/compatibility_test.go deleted file mode 100644 index 7cba8b81b0f..00000000000 --- a/pkg/controller/elasticsearch/version/zen2/compatibility_test.go +++ /dev/null @@ -1,108 +0,0 @@ -// 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 zen2 - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - sset "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/statefulset" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" - "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" -) - -func createStatefulSetWithESVersion(version string) appsv1.StatefulSet { - return appsv1.StatefulSet{Spec: appsv1.StatefulSetSpec{Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - label.VersionLabelName: version, - }, - }, - }}} -} - -func TestIsCompatibleWithZen2(t *testing.T) { - tests := []struct { - name string - sset appsv1.StatefulSet - want bool - }{ - { - name: "versionCompatibleWithZen2 7.0.0", - sset: createStatefulSetWithESVersion("7.0.0"), - want: true, - }, - { - name: "versionCompatibleWithZen2 8.0.0", - sset: createStatefulSetWithESVersion("8.0.0"), - want: true, - }, - { - name: "no versionCompatibleWithZen2", - sset: createStatefulSetWithESVersion(""), - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IsCompatibleWithZen2(context.Background(), tt.sset); got != tt.want { - t.Errorf("IsCompatibleWithZen2() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestAllMastersCompatibleWithZen2(t *testing.T) { - es := esv1.Elasticsearch{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns", - Name: "cluster", - }, - } - tests := []struct { - name string - pods []client.Object - want bool - }{ - { - name: "only v7 master nodes", - pods: []client.Object{ - sset.TestPod{Namespace: es.Namespace, Name: "node0", ClusterName: es.Name, Version: "7.2.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node1", ClusterName: es.Name, Version: "7.2.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node2", ClusterName: es.Name, Version: "7.2.0", Data: true}.BuildPtr(), - }, - want: true, - }, - { - name: "mixed v7/v8 masters", - pods: []client.Object{ - sset.TestPod{Namespace: es.Namespace, Name: "node0", ClusterName: es.Name, Version: "8.0.0", Master: true}.BuildPtr(), - sset.TestPod{Namespace: es.Namespace, Name: "node1", ClusterName: es.Name, Version: "7.17.0", Master: true}.BuildPtr(), - }, - want: true, - }, - { - name: "no pods", - pods: []client.Object{}, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := AllMastersCompatibleWithZen2(k8s.NewFakeClient(tt.pods...), es) - require.NoError(t, err) - if got != tt.want { - t.Errorf("AllMastersCompatibleWithZen2() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go index c6dbc78261e..3446c0d59f8 100644 --- a/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go +++ b/pkg/controller/elasticsearch/version/zen2/initial_master_nodes.go @@ -11,11 +11,11 @@ import ( pkgerrors "github.com/pkg/errors" esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1" - "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/bootstrap" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/label" "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/nodespec" + "github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/settings" "github.com/elastic/cloud-on-k8s/v3/pkg/utils/k8s" ulog "github.com/elastic/cloud-on-k8s/v3/pkg/utils/log" ) @@ -34,15 +34,11 @@ func SetupInitialMasterNodes(ctx context.Context, es esv1.Elasticsearch, k8sClie // if the cluster is annotated with `cluster.initial_master_nodes` (zen2 bootstrap in progress), // make sure we reuse that value since it is not supposed to vary over time if initialMasterNodes := getInitialMasterNodesAnnotation(es); initialMasterNodes != nil { - return patchInitialMasterNodesConfig(ctx, nodeSpecResources, initialMasterNodes) + return patchInitialMasterNodesConfig(nodeSpecResources, initialMasterNodes) } // in most cases, `cluster.initial_master_nodes` should not be set - shouldSetup, err := shouldSetInitialMasterNodes(es) - if err != nil { - return err - } - if !shouldSetup { + if !shouldSetInitialMasterNodes(es) { return nil } @@ -56,29 +52,21 @@ func SetupInitialMasterNodes(ctx context.Context, es esv1.Elasticsearch, k8sClie "es_name", es.Name, "cluster.initial_master_nodes", strings.Join(initialMasterNodes, ","), ) - if err := patchInitialMasterNodesConfig(ctx, nodeSpecResources, initialMasterNodes); err != nil { + if err := patchInitialMasterNodesConfig(nodeSpecResources, initialMasterNodes); err != nil { return err } // keep the computed value in an annotation for reuse in subsequent reconciliations return setInitialMasterNodesAnnotation(ctx, k8sClient, es, initialMasterNodes) } -func shouldSetInitialMasterNodes(es esv1.Elasticsearch) (bool, error) { - if v, err := version.Parse(es.Spec.Version); err != nil || !versionCompatibleWithZen2(v) { - // we only care about zen2-compatible clusters here - return false, err - } +func shouldSetInitialMasterNodes(es esv1.Elasticsearch) bool { // Set cluster.initial_master_nodes only when a new cluster is getting created (not already bootstrapped) - return !bootstrap.AnnotatedForBootstrap(es), nil + return !bootstrap.AnnotatedForBootstrap(es) } // RemoveZen2BootstrapAnnotation removes the initialMasterNodesAnnotation (if set) once zen2 is bootstrapped // on the corresponding cluster. func RemoveZen2BootstrapAnnotation(ctx context.Context, k8sClient k8s.Client, es esv1.Elasticsearch, esClient client.Client) (bool, error) { - if v, err := version.Parse(es.Spec.Version); err != nil || !versionCompatibleWithZen2(v) { - // we only care about zen2-compatible clusters here - return false, err - } if getInitialMasterNodesAnnotation(es) == nil { // most common case: no annotation set, nothing to do return false, nil @@ -102,14 +90,17 @@ func RemoveZen2BootstrapAnnotation(ctx context.Context, k8sClient k8s.Client, es return false, k8sClient.Update(ctx, &es) } -// patchInitialMasterNodesConfig mutates the configuration of zen2-compatible master nodes +// patchInitialMasterNodesConfig mutates the configuration of master nodes // to have the given `cluster.initial_master_nodes` setting. -func patchInitialMasterNodesConfig(ctx context.Context, nodeSpecResources nodespec.ResourcesList, initialMasterNodes []string) error { +func patchInitialMasterNodesConfig(nodeSpecResources nodespec.ResourcesList, initialMasterNodes []string) error { for i, res := range nodeSpecResources { - if !label.IsMasterNodeSet(res.StatefulSet) || !IsCompatibleWithZen2(ctx, res.StatefulSet) { - // we only care about updating zen2 masters config here + if !label.IsMasterNodeSet(res.StatefulSet) { continue } + // Defensively initialize config if nil (should never be the case except for tests) + if nodeSpecResources[i].Config.CanonicalConfig == nil { + nodeSpecResources[i].Config = settings.NewCanonicalConfig() + } if err := nodeSpecResources[i].Config.SetStrings(esv1.ClusterInitialMasterNodes, initialMasterNodes...); err != nil { return err } diff --git a/pkg/controller/elasticsearch/version/zen2/voting_exclusions.go b/pkg/controller/elasticsearch/version/zen2/voting_exclusions.go index 55ee18ef3ac..d2b777713f7 100644 --- a/pkg/controller/elasticsearch/version/zen2/voting_exclusions.go +++ b/pkg/controller/elasticsearch/version/zen2/voting_exclusions.go @@ -15,15 +15,7 @@ import ( ) // AddToVotingConfigExclusions adds the given node names to exclude from voting config exclusions. -func AddToVotingConfigExclusions(ctx context.Context, c k8s.Client, esClient client.Client, es esv1.Elasticsearch, excludeNodes []string) error { - compatible, err := AllMastersCompatibleWithZen2(c, es) - if err != nil { - return err - } - if !compatible { - return nil - } - +func AddToVotingConfigExclusions(ctx context.Context, esClient client.Client, es esv1.Elasticsearch, excludeNodes []string) error { ulog.FromContext(ctx).Info("Setting voting config exclusions", "namespace", es.Namespace, "nodes", excludeNodes) return esClient.AddVotingConfigExclusions(ctx, excludeNodes) } @@ -47,14 +39,6 @@ func canClearVotingConfigExclusions(ctx context.Context, c k8s.Client, actualSta // It returns true if this should be retried later (re-queued). func ClearVotingConfigExclusions(ctx context.Context, es esv1.Elasticsearch, c k8s.Client, esClient client.Client, actualStatefulSets sset.StatefulSetList) (bool, error) { log := ulog.FromContext(ctx) - compatible, err := AllMastersCompatibleWithZen2(c, es) - if err != nil { - return false, err - } - if !compatible { - // nothing to do - return false, nil - } canClear, err := canClearVotingConfigExclusions(ctx, c, actualStatefulSets) if err != nil { diff --git a/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go b/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go index 3c99f892bd2..02872e7f210 100644 --- a/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go +++ b/pkg/controller/elasticsearch/version/zen2/voting_exclusions_test.go @@ -102,17 +102,9 @@ func Test_ClearVotingConfigExclusions(t *testing.T) { func TestAddToVotingConfigExclusions(t *testing.T) { es := esv1.Elasticsearch{ObjectMeta: metav1.ObjectMeta{Name: "es", Namespace: "ns"}} - masterPod := sset.TestPod{ - Namespace: "ns", - Name: "pod-name", - ClusterName: "es", - Version: "7.2.0", - Master: true, - }.BuildPtr() tests := []struct { name string es *esv1.Elasticsearch - c k8s.Client excludeNodes []string wantAPICalled bool wantAPICalledWith []string @@ -120,7 +112,6 @@ func TestAddToVotingConfigExclusions(t *testing.T) { { name: "set voting config exclusions", es: &es, - c: k8s.NewFakeClient(&es, masterPod), excludeNodes: []string{"node1", "node2"}, wantAPICalled: true, wantAPICalledWith: []string{"node1", "node2"}, @@ -129,13 +120,10 @@ func TestAddToVotingConfigExclusions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { clientMock := &fakeVotingConfigExclusionsESClient{} - err := AddToVotingConfigExclusions(context.Background(), tt.c, clientMock, *tt.es, tt.excludeNodes) + err := AddToVotingConfigExclusions(context.Background(), clientMock, *tt.es, tt.excludeNodes) require.NoError(t, err) require.Equal(t, tt.wantAPICalled, clientMock.called) require.Equal(t, tt.wantAPICalledWith, clientMock.excludedNodes) - var retrievedES esv1.Elasticsearch - err = tt.c.Get(context.Background(), k8s.ExtractNamespacedName(tt.es), &retrievedES) - require.NoError(t, err) }) } } From 53bf4ea5a332e60ac65d9232b77fb2029f893d90 Mon Sep 17 00:00:00 2001 From: Peter Brachwitz Date: Mon, 5 Jan 2026 12:29:39 +0100 Subject: [PATCH 10/10] Happy new year --- NOTICE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE.txt b/NOTICE.txt index 767f4105f12..14f8b6bdedb 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,4 +1,4 @@ -Copyright 2018-2025 Elasticsearch BV +Copyright 2018-2026 Elasticsearch BV This product includes software developed by The Apache Software Foundation (http://www.apache.org/).