@@ -2,6 +2,7 @@ package cluster
2
2
3
3
import (
4
4
"bytes"
5
+ "fmt"
5
6
"io/ioutil"
6
7
"net/http"
7
8
"testing"
@@ -480,6 +481,140 @@ func TestCheckAndSetGlobalPostgreSQLConfiguration(t *testing.T) {
480
481
}
481
482
}
482
483
484
+ func TestSyncStandbyClusterConfiguration (t * testing.T ) {
485
+ client , _ := newFakeK8sSyncClient ()
486
+ clusterName := "acid-standby-cluster"
487
+ applicationLabel := "spilo"
488
+ namespace := "default"
489
+
490
+ ctrl := gomock .NewController (t )
491
+ defer ctrl .Finish ()
492
+
493
+ pg := acidv1.Postgresql {
494
+ ObjectMeta : metav1.ObjectMeta {
495
+ Name : clusterName ,
496
+ Namespace : namespace ,
497
+ },
498
+ Spec : acidv1.PostgresSpec {
499
+ NumberOfInstances : int32 (1 ),
500
+ Volume : acidv1.Volume {
501
+ Size : "1Gi" ,
502
+ },
503
+ },
504
+ }
505
+
506
+ var cluster = New (
507
+ Config {
508
+ OpConfig : config.Config {
509
+ PatroniAPICheckInterval : time .Duration (1 ),
510
+ PatroniAPICheckTimeout : time .Duration (5 ),
511
+ PodManagementPolicy : "ordered_ready" ,
512
+ Resources : config.Resources {
513
+ ClusterLabels : map [string ]string {"application" : applicationLabel },
514
+ ClusterNameLabel : "cluster-name" ,
515
+ DefaultCPURequest : "300m" ,
516
+ DefaultCPULimit : "300m" ,
517
+ DefaultMemoryRequest : "300Mi" ,
518
+ DefaultMemoryLimit : "300Mi" ,
519
+ MinInstances : int32 (- 1 ),
520
+ MaxInstances : int32 (- 1 ),
521
+ PodRoleLabel : "spilo-role" ,
522
+ ResourceCheckInterval : time .Duration (3 ),
523
+ ResourceCheckTimeout : time .Duration (10 ),
524
+ },
525
+ },
526
+ }, client , pg , logger , eventRecorder )
527
+
528
+ cluster .Name = clusterName
529
+ cluster .Namespace = namespace
530
+
531
+ // mocking a config after getConfig is called
532
+ mockClient := mocks .NewMockHTTPClient (ctrl )
533
+ configJson := `{"ttl": 20}`
534
+ r := ioutil .NopCloser (bytes .NewReader ([]byte (configJson )))
535
+ response := http.Response {
536
+ StatusCode : 200 ,
537
+ Body : r ,
538
+ }
539
+ mockClient .EXPECT ().Get (gomock .Any ()).Return (& response , nil ).AnyTimes ()
540
+
541
+ // mocking a config after setConfig is called
542
+ standbyJson := `{"standby_cluster":{"create_replica_methods":["bootstrap_standby_with_wale","basebackup_fast_xlog"],"restore_command":"envdir \"/run/etc/wal-e.d/env-standby\" /scripts/restore_command.sh \"%f\" \"%p\""}}`
543
+ r = ioutil .NopCloser (bytes .NewReader ([]byte (standbyJson )))
544
+ response = http.Response {
545
+ StatusCode : 200 ,
546
+ Body : r ,
547
+ }
548
+ mockClient .EXPECT ().Do (gomock .Any ()).Return (& response , nil ).AnyTimes ()
549
+ p := patroni .New (patroniLogger , mockClient )
550
+ cluster .patroni = p
551
+
552
+ mockPod := newMockPod ("192.168.100.1" )
553
+ mockPod .Name = fmt .Sprintf ("%s-0" , clusterName )
554
+ mockPod .Namespace = namespace
555
+ podLabels := map [string ]string {
556
+ "cluster-name" : clusterName ,
557
+ "application" : applicationLabel ,
558
+ "spilo-role" : "master" ,
559
+ }
560
+ mockPod .Labels = podLabels
561
+ client .PodsGetter .Pods (namespace ).Create (context .TODO (), mockPod , metav1.CreateOptions {})
562
+
563
+ // create a statefulset
564
+ sts , err := cluster .createStatefulSet ()
565
+ assert .NoError (t , err )
566
+
567
+ // check that pods do not have a STANDBY_* environment variable
568
+ assert .NotContains (t , sts .Spec .Template .Spec .Containers [0 ].Env , v1.EnvVar {Name : "STANDBY_METHOD" , Value : "STANDBY_WITH_WALE" })
569
+
570
+ // add standby section
571
+ cluster .Spec .StandbyCluster = & acidv1.StandbyDescription {
572
+ S3WalPath : "s3://custom/path/to/bucket/" ,
573
+ }
574
+ cluster .syncStatefulSet ()
575
+ updatedSts := cluster .Statefulset
576
+
577
+ // check that pods do not have a STANDBY_* environment variable
578
+ assert .Contains (t , updatedSts .Spec .Template .Spec .Containers [0 ].Env , v1.EnvVar {Name : "STANDBY_METHOD" , Value : "STANDBY_WITH_WALE" })
579
+
580
+ // this should update the Patroni config
581
+ err = cluster .syncStandbyClusterConfiguration ()
582
+ assert .NoError (t , err )
583
+
584
+ configJson = `{"standby_cluster":{"create_replica_methods":["bootstrap_standby_with_wale","basebackup_fast_xlog"],"restore_command":"envdir \"/run/etc/wal-e.d/env-standby\" /scripts/restore_command.sh \"%f\" \"%p\""}, "ttl": 20}`
585
+ r = ioutil .NopCloser (bytes .NewReader ([]byte (configJson )))
586
+ response = http.Response {
587
+ StatusCode : 200 ,
588
+ Body : r ,
589
+ }
590
+ mockClient .EXPECT ().Get (gomock .Any ()).Return (& response , nil ).AnyTimes ()
591
+
592
+ pods , err := cluster .listPods ()
593
+ assert .NoError (t , err )
594
+
595
+ _ , _ , err = cluster .patroni .GetConfig (& pods [0 ])
596
+ assert .NoError (t , err )
597
+ // ToDo extend GetConfig to return standy_cluster setting to compare
598
+ /*
599
+ defaultStandbyParameters := map[string]interface{}{
600
+ "create_replica_methods": []string{"bootstrap_standby_with_wale", "basebackup_fast_xlog"},
601
+ "restore_command": "envdir \"/run/etc/wal-e.d/env-standby\" /scripts/restore_command.sh \"%f\" \"%p\"",
602
+ }
603
+ assert.True(t, reflect.DeepEqual(defaultStandbyParameters, standbyCluster))
604
+ */
605
+ // remove standby section
606
+ cluster .Spec .StandbyCluster = & acidv1.StandbyDescription {}
607
+ cluster .syncStatefulSet ()
608
+ updatedSts2 := cluster .Statefulset
609
+
610
+ // check that pods do not have a STANDBY_* environment variable
611
+ assert .NotContains (t , updatedSts2 .Spec .Template .Spec .Containers [0 ].Env , v1.EnvVar {Name : "STANDBY_METHOD" , Value : "STANDBY_WITH_WALE" })
612
+
613
+ // this should update the Patroni config again
614
+ err = cluster .syncStandbyClusterConfiguration ()
615
+ assert .NoError (t , err )
616
+ }
617
+
483
618
func TestUpdateSecret (t * testing.T ) {
484
619
testName := "test syncing secrets"
485
620
client , _ := newFakeK8sSyncSecretsClient ()
0 commit comments