@@ -336,6 +336,227 @@ func TestStackConfigPolicy(t *testing.T) {
336336 test .Sequence (nil , steps , esWithlicense ).RunSequential (t )
337337}
338338
339+ // TestStackConfigPolicyMultipleWeights tests multiple StackConfigPolicies with different weights.
340+ func TestStackConfigPolicyMultipleWeights (t * testing.T ) {
341+ // only execute this test if we have a test license to work with
342+ if test .Ctx ().TestLicense == "" {
343+ t .SkipNow ()
344+ }
345+
346+ // StackConfigPolicy is supported for ES versions with file-based settings feature
347+ stackVersion := version .MustParse (test .Ctx ().ElasticStackVersion )
348+ if ! stackVersion .GTE (filesettings .FileBasedSettingsMinPreVersion ) {
349+ t .SkipNow ()
350+ }
351+
352+ es := elasticsearch .NewBuilder ("test-es-scp-multi" ).
353+ WithESMasterDataNodes (1 , elasticsearch .DefaultResources ).
354+ WithLabel ("app" , "elasticsearch" )
355+
356+ namespace := test .Ctx ().ManagedNamespace (0 )
357+
358+ // Policy with weight 20 (lower priority) - sets cluster.name
359+ lowPriorityPolicy := policyv1alpha1.StackConfigPolicy {
360+ ObjectMeta : metav1.ObjectMeta {
361+ Namespace : namespace ,
362+ Name : fmt .Sprintf ("low-priority-scp-%s" , rand .String (4 )),
363+ },
364+ Spec : policyv1alpha1.StackConfigPolicySpec {
365+ Weight : 20 ,
366+ ResourceSelector : metav1.LabelSelector {
367+ MatchLabels : map [string ]string {"app" : "elasticsearch" },
368+ },
369+ Elasticsearch : policyv1alpha1.ElasticsearchConfigPolicySpec {
370+ Config : & commonv1.Config {
371+ Data : map [string ]interface {}{
372+ "cluster.name" : "low-priority-cluster" ,
373+ },
374+ },
375+ ClusterSettings : & commonv1.Config {
376+ Data : map [string ]interface {}{
377+ "indices" : map [string ]interface {}{
378+ "recovery.max_bytes_per_sec" : "50mb" ,
379+ },
380+ },
381+ },
382+ },
383+ },
384+ }
385+
386+ // Policy with weight 10 (higher priority) - should override cluster.name and settings
387+ highPriorityPolicy := policyv1alpha1.StackConfigPolicy {
388+ ObjectMeta : metav1.ObjectMeta {
389+ Namespace : namespace ,
390+ Name : fmt .Sprintf ("high-priority-scp-%s" , rand .String (4 )),
391+ },
392+ Spec : policyv1alpha1.StackConfigPolicySpec {
393+ Weight : 10 ,
394+ ResourceSelector : metav1.LabelSelector {
395+ MatchLabels : map [string ]string {"app" : "elasticsearch" },
396+ },
397+ Elasticsearch : policyv1alpha1.ElasticsearchConfigPolicySpec {
398+ Config : & commonv1.Config {
399+ Data : map [string ]interface {}{
400+ "cluster" : map [string ]interface {}{
401+ "name" : "high-priority-cluster" ,
402+ },
403+ },
404+ },
405+ ClusterSettings : & commonv1.Config {
406+ Data : map [string ]interface {}{
407+ "indices" : map [string ]interface {}{
408+ "recovery" : map [string ]interface {}{
409+ "max_bytes_per_sec" : "200mb" ,
410+ },
411+ },
412+ },
413+ },
414+ },
415+ },
416+ }
417+
418+ // Policy with same weight 20 but different selector (should not conflict)
419+ nonConflictingPolicy := policyv1alpha1.StackConfigPolicy {
420+ ObjectMeta : metav1.ObjectMeta {
421+ Namespace : namespace ,
422+ Name : fmt .Sprintf ("non-conflicting-scp-%s" , rand .String (4 )),
423+ },
424+ Spec : policyv1alpha1.StackConfigPolicySpec {
425+ Weight : 20 ,
426+ ResourceSelector : metav1.LabelSelector {
427+ MatchLabels : map [string ]string {"app" : "kibana" }, // Different selector
428+ },
429+ Elasticsearch : policyv1alpha1.ElasticsearchConfigPolicySpec {
430+ Config : & commonv1.Config {
431+ Data : map [string ]interface {}{
432+ "cluster.name" : "should-not-apply" ,
433+ },
434+ },
435+ },
436+ },
437+ }
438+
439+ esWithlicense := test .LicenseTestBuilder (es )
440+
441+ steps := func (k * test.K8sClient ) test.StepList {
442+ return test.StepList {
443+ test.Step {
444+ Name : "Create low priority StackConfigPolicy" ,
445+ Test : test .Eventually (func () error {
446+ return k .CreateOrUpdate (& lowPriorityPolicy )
447+ }),
448+ },
449+ test.Step {
450+ Name : "Create high priority StackConfigPolicy" ,
451+ Test : test .Eventually (func () error {
452+ return k .CreateOrUpdate (& highPriorityPolicy )
453+ }),
454+ },
455+ test.Step {
456+ Name : "Create non-conflicting StackConfigPolicy" ,
457+ Test : test .Eventually (func () error {
458+ return k .CreateOrUpdate (& nonConflictingPolicy )
459+ }),
460+ },
461+ test.Step {
462+ Name : "High priority cluster name should be applied" ,
463+ Test : test .Eventually (func () error {
464+ esClient , err := elasticsearch .NewElasticsearchClient (es .Elasticsearch , k )
465+ if err != nil {
466+ return err
467+ }
468+
469+ var apiResponse ClusterInfoResponse
470+ if _ , _ , err = request (esClient , http .MethodGet , "/" , nil , & apiResponse ); err != nil {
471+ return err
472+ }
473+
474+ if apiResponse .ClusterName != "high-priority-cluster" {
475+ return fmt .Errorf ("expected cluster name 'high-priority-cluster', got '%s'" , apiResponse .ClusterName )
476+ }
477+ return nil
478+ }),
479+ },
480+ test.Step {
481+ Name : "High priority cluster settings should be applied" ,
482+ Test : test .Eventually (func () error {
483+ esClient , err := elasticsearch .NewElasticsearchClient (es .Elasticsearch , k )
484+ if err != nil {
485+ return err
486+ }
487+
488+ var settings ClusterSettings
489+ _ , _ , err = request (esClient , http .MethodGet , "/_cluster/settings" , nil , & settings )
490+ if err != nil {
491+ return err
492+ }
493+
494+ if settings .Persistent .Indices .Recovery .MaxBytesPerSec != "200mb" {
495+ return fmt .Errorf ("expected max_bytes_per_sec '200mb', got '%s'" , settings .Persistent .Indices .Recovery .MaxBytesPerSec )
496+ }
497+ return nil
498+ }),
499+ },
500+ test.Step {
501+ Name : "Delete high priority policy - low priority should take effect" ,
502+ Test : test .Eventually (func () error {
503+ return k .Client .Delete (context .Background (), & highPriorityPolicy )
504+ }),
505+ },
506+ test.Step {
507+ Name : "Low priority cluster name should now be applied" ,
508+ Test : test .Eventually (func () error {
509+ esClient , err := elasticsearch .NewElasticsearchClient (es .Elasticsearch , k )
510+ if err != nil {
511+ return err
512+ }
513+
514+ var apiResponse ClusterInfoResponse
515+ if _ , _ , err = request (esClient , http .MethodGet , "/" , nil , & apiResponse ); err != nil {
516+ return err
517+ }
518+
519+ if apiResponse .ClusterName != "low-priority-cluster" {
520+ return fmt .Errorf ("expected cluster name 'low-priority-cluster', got '%s'" , apiResponse .ClusterName )
521+ }
522+ return nil
523+ }),
524+ },
525+ test.Step {
526+ Name : "Low priority cluster settings should now be applied" ,
527+ Test : test .Eventually (func () error {
528+ esClient , err := elasticsearch .NewElasticsearchClient (es .Elasticsearch , k )
529+ if err != nil {
530+ return err
531+ }
532+
533+ var settings ClusterSettings
534+ _ , _ , err = request (esClient , http .MethodGet , "/_cluster/settings" , nil , & settings )
535+ if err != nil {
536+ return err
537+ }
538+
539+ if settings .Persistent .Indices .Recovery .MaxBytesPerSec != "50mb" {
540+ return fmt .Errorf ("expected max_bytes_per_sec '50mb', got '%s'" , settings .Persistent .Indices .Recovery .MaxBytesPerSec )
541+ }
542+ return nil
543+ }),
544+ },
545+ test.Step {
546+ Name : "Clean up remaining policies" ,
547+ Test : test .Eventually (func () error {
548+ if err := k .Client .Delete (context .Background (), & lowPriorityPolicy ); err != nil {
549+ return err
550+ }
551+ return k .Client .Delete (context .Background (), & nonConflictingPolicy )
552+ }),
553+ },
554+ }
555+ }
556+
557+ test .Sequence (nil , steps , esWithlicense ).RunSequential (t )
558+ }
559+
339560func checkAPIStatusCode (esClient client.Client , url string , expectedStatusCode int ) error {
340561 var items map [string ]interface {}
341562 _ , actualStatusCode , _ := request (esClient , http .MethodGet , url , nil , & items )
0 commit comments