@@ -7,11 +7,14 @@ Copyright (C) 2019-2022 EnterpriseDB Corporation.
7
7
package e2e
8
8
9
9
import (
10
+ "fmt"
10
11
"strconv"
11
12
"strings"
12
13
"time"
13
14
15
+ corev1 "k8s.io/api/core/v1"
14
16
"k8s.io/apimachinery/pkg/types"
17
+ "sigs.k8s.io/controller-runtime/pkg/client"
15
18
16
19
apiv1 "github.com/EnterpriseDB/cloud-native-postgresql/api/v1"
17
20
"github.com/EnterpriseDB/cloud-native-postgresql/pkg/specs"
@@ -348,3 +351,173 @@ var _ = Describe("Configuration update", func() {
348
351
})
349
352
})
350
353
})
354
+
355
+ var _ = Describe ("Configuration update with primaryUpdateMethod" , func () {
356
+ const level = tests .High
357
+
358
+ BeforeEach (func () {
359
+ if testLevelEnv .Depth < int (level ) {
360
+ Skip ("Test depth is lower than the amount requested for this test" )
361
+ }
362
+ })
363
+
364
+ Context ("primaryUpdateMethod value set to restart" , Ordered , func () {
365
+ clusterFileWithPrimaryUpdateRestart := fixturesDir +
366
+ "/config_update/primary_update_method/primary-update-restart.yaml"
367
+ var namespace , clusterName string
368
+ var sourceClusterNamespacedName * types.NamespacedName
369
+
370
+ JustAfterEach (func () {
371
+ if CurrentSpecReport ().Failed () {
372
+ env .DumpClusterEnv (namespace , clusterName ,
373
+ "out/" + CurrentSpecReport ().LeafNodeText + ".log" )
374
+ }
375
+ })
376
+
377
+ BeforeAll (func () {
378
+ namespace = "config-change-primary-update-restart"
379
+ // Create a cluster in a namespace we'll delete after the test
380
+ err := env .CreateNamespace (namespace )
381
+ Expect (err ).ToNot (HaveOccurred ())
382
+
383
+ clusterName , err = env .GetResourceNameFromYAML (clusterFileWithPrimaryUpdateRestart )
384
+ Expect (err ).ToNot (HaveOccurred ())
385
+ sourceClusterNamespacedName = & types.NamespacedName {
386
+ Namespace : namespace ,
387
+ Name : clusterName ,
388
+ }
389
+
390
+ By ("setting up cluster with primaryUpdateMethod value set to restart" , func () {
391
+ AssertCreateCluster (namespace , clusterName , clusterFileWithPrimaryUpdateRestart , env )
392
+ })
393
+ })
394
+
395
+ AfterAll (func () {
396
+ err := env .DeleteNamespace (namespace )
397
+ Expect (err ).ToNot (HaveOccurred ())
398
+ })
399
+
400
+ It ("should restart primary in place after increasing config parameter `max_connection` value" , func () {
401
+ const (
402
+ maxConnectionParamKey = "max_connections"
403
+ )
404
+ var oldPrimaryPodName string
405
+ var newMaxConnectionsValue int
406
+ var primaryStartTime time.Time
407
+
408
+ By ("getting old primary info" , func () {
409
+ commandTimeout := time .Second * 2
410
+ primaryPodInfo , err := env .GetClusterPrimary (namespace , clusterName )
411
+ Expect (err ).ToNot (HaveOccurred ())
412
+
413
+ oldPrimaryPodName = primaryPodInfo .GetName ()
414
+ stdout , _ , cmdErr := env .EventuallyExecCommand (env .Ctx , * primaryPodInfo , specs .PostgresContainerName ,
415
+ & commandTimeout , "psql" , "-U" , "postgres" , "-tAc" ,
416
+ "select to_char(pg_postmaster_start_time(), 'YYYY-MM-DD HH24:MI:SS');" )
417
+ Expect (cmdErr ).ToNot (HaveOccurred ())
418
+
419
+ primaryStartTime , err = devUtils .ParseTargetTime (nil , strings .Trim (stdout , "\n " ))
420
+ Expect (err ).NotTo (HaveOccurred ())
421
+
422
+ stdout , _ , cmdErr = env .EventuallyExecCommand (env .Ctx , * primaryPodInfo , specs .PostgresContainerName ,
423
+ & commandTimeout , "psql" , "-U" , "postgres" , "-tAc" , "show max_connections" )
424
+ Expect (cmdErr ).ToNot (HaveOccurred ())
425
+
426
+ v , err := strconv .Atoi (strings .Trim (stdout , "\n " ))
427
+ Expect (err ).NotTo (HaveOccurred ())
428
+
429
+ newMaxConnectionsValue = v + 10
430
+ })
431
+
432
+ By (fmt .Sprintf ("updating max_connection value to %v" , newMaxConnectionsValue ), func () {
433
+ var cluster apiv1.Cluster
434
+ err := env .Client .Get (env .Ctx , * sourceClusterNamespacedName , & cluster )
435
+ Expect (err ).ToNot (HaveOccurred ())
436
+
437
+ updated := cluster .DeepCopy ()
438
+ updated .Spec .PostgresConfiguration .Parameters [maxConnectionParamKey ] = fmt .Sprintf ("%v" ,
439
+ newMaxConnectionsValue )
440
+ err = env .Client .Patch (env .Ctx , updated , client .MergeFrom (& cluster ))
441
+ Expect (err ).ToNot (HaveOccurred ())
442
+ })
443
+
444
+ By ("verifying the new value for max_connections is updated for all instances" , func () {
445
+ podList , err := env .GetClusterPodList (namespace , clusterName )
446
+ Expect (err ).ToNot (HaveOccurred ())
447
+
448
+ commandTimeout := time .Second * 2
449
+ for _ , pod := range podList .Items {
450
+ Eventually (func () (int , error , error ) {
451
+ stdout , _ , err := env .ExecCommand (env .Ctx , pod , specs .PostgresContainerName , & commandTimeout ,
452
+ "psql" , "-U" , "postgres" , "-tAc" , "show max_connections" )
453
+ value , atoiErr := strconv .Atoi (strings .Trim (stdout , "\n " ))
454
+ return value , err , atoiErr
455
+ }, 180 ).Should (BeEquivalentTo (newMaxConnectionsValue ),
456
+ "Pod %v should have updated its configuration" , pod .Name )
457
+ }
458
+ })
459
+
460
+ By ("verifying the old primary is still the primary" , func () {
461
+ cluster := apiv1.Cluster {}
462
+ Eventually (func () (string , error ) {
463
+ err := env .Client .Get (env .Ctx , * sourceClusterNamespacedName , & cluster )
464
+ return cluster .Status .CurrentPrimary , err
465
+ }, 60 ).Should (BeEquivalentTo (oldPrimaryPodName ))
466
+ })
467
+
468
+ By ("verifying that old primary was actually restarted" , func () {
469
+ commandTimeout := time .Second * 2
470
+ pod := corev1.Pod {}
471
+ err := env .Client .Get (env .Ctx , types.NamespacedName {
472
+ Namespace : namespace ,
473
+ Name : oldPrimaryPodName ,
474
+ }, & pod )
475
+ Expect (err ).ToNot (HaveOccurred ())
476
+
477
+ // take pg postmaster start time
478
+ stdout , _ , cmdErr := env .EventuallyExecCommand (env .Ctx , pod , specs .PostgresContainerName , & commandTimeout ,
479
+ "psql" , "-U" , "postgres" , "-tAc" ,
480
+ "select to_char(pg_postmaster_start_time(), 'YYYY-MM-DD HH24:MI:SS');" )
481
+ Expect (cmdErr ).ToNot (HaveOccurred ())
482
+
483
+ newStartTime , err := devUtils .ParseTargetTime (nil , strings .Trim (stdout , "\n " ))
484
+ Expect (err ).NotTo (HaveOccurred ())
485
+
486
+ // verify that pg postmaster start time is greater than currentTimestamp which was taken before restart
487
+ Expect (newStartTime ).Should (BeTemporally (">" , primaryStartTime ))
488
+ })
489
+ })
490
+ It ("work_mem config change should not require a restart" , func () {
491
+ const expectedNewValueForWorkMem = "10MB"
492
+ commandTimeout := time .Second * 2
493
+
494
+ By ("updating work mem " , func () {
495
+ var cluster apiv1.Cluster
496
+ err := env .Client .Get (env .Ctx , * sourceClusterNamespacedName , & cluster )
497
+ Expect (err ).ToNot (HaveOccurred ())
498
+
499
+ updated := cluster .DeepCopy ()
500
+ updated .Spec .PostgresConfiguration .Parameters ["work_mem" ] = expectedNewValueForWorkMem
501
+ err = env .Client .Patch (env .Ctx , updated , client .MergeFrom (& cluster ))
502
+ Expect (err ).ToNot (HaveOccurred ())
503
+ })
504
+
505
+ By ("verify that work_mem result as expected" , func () {
506
+ podList , err := env .GetClusterPodList (namespace , clusterName )
507
+ Expect (err ).ToNot (HaveOccurred ())
508
+
509
+ // Check that the parameter has been modified in every pod
510
+ for _ , pod := range podList .Items {
511
+ pod := pod // pin the variable
512
+ Eventually (func () (int , error , error ) {
513
+ stdout , _ , err := env .ExecCommand (env .Ctx , pod , specs .PostgresContainerName , & commandTimeout ,
514
+ "psql" , "-U" , "postgres" , "-tAc" , "show work_mem" )
515
+ value , atoiErr := strconv .Atoi (strings .Trim (stdout , "MB\n " ))
516
+ return value , err , atoiErr
517
+ }, 160 ).Should (BeEquivalentTo (10 ))
518
+ }
519
+ })
520
+ AssertPostgresNoPendingRestart (namespace , clusterName , commandTimeout , 120 )
521
+ })
522
+ })
523
+ })
0 commit comments