Skip to content

Commit 6b5907a

Browse files
wadlejitendraphiscosxd
authored
test: E2E for primaryUpdateMethod
Co-authored-by: Philippe Scorsolini <philippe.scorsolini@enterprisedb.com> Co-authored-by: Jonathan Gonzalez V <jonathan.gonzalez@enterprisedb.com>
1 parent 2cdc977 commit 6b5907a

File tree

6 files changed

+274
-1
lines changed

6 files changed

+274
-1
lines changed

tests/e2e/configuration_update_test.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ Copyright (C) 2019-2022 EnterpriseDB Corporation.
77
package e2e
88

99
import (
10+
"fmt"
1011
"strconv"
1112
"strings"
1213
"time"
1314

15+
corev1 "k8s.io/api/core/v1"
1416
"k8s.io/apimachinery/pkg/types"
17+
"sigs.k8s.io/controller-runtime/pkg/client"
1518

1619
apiv1 "github.com/EnterpriseDB/cloud-native-postgresql/api/v1"
1720
"github.com/EnterpriseDB/cloud-native-postgresql/pkg/specs"
@@ -348,3 +351,173 @@ var _ = Describe("Configuration update", func() {
348351
})
349352
})
350353
})
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+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
primary-update-restart.yaml
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Cluster
3+
metadata:
4+
name: primary-update-restart
5+
spec:
6+
instances: 3
7+
8+
postgresql:
9+
parameters:
10+
work_mem: "8MB"
11+
max_connections: "105"
12+
log_checkpoints: "on"
13+
log_lock_waits: "on"
14+
log_min_duration_statement: '1000'
15+
log_statement: 'ddl'
16+
log_temp_files: '1024'
17+
log_autovacuum_min_duration: '1s'
18+
log_replication_commands: 'on'
19+
20+
# Example of rolling update strategy:
21+
# - unsupervised: automated update of the primary once all
22+
# replicas have been upgraded (default)
23+
# - supervised: requires manual supervision to perform
24+
# the switchover of the primary
25+
primaryUpdateStrategy: unsupervised
26+
primaryUpdateMethod: restart
27+
28+
bootstrap:
29+
initdb:
30+
database: app
31+
owner: app
32+
33+
# Persistent storage configuration
34+
storage:
35+
storageClass: ${E2E_DEFAULT_STORAGE_CLASS}
36+
size: 1Gi
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
cluster-three-instances.yaml
2-
cluster-single-instance.yaml
2+
cluster-single-instance.yaml
3+
cluster-using-primary-update-method.yaml
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Cluster
3+
metadata:
4+
name: postgresql-three-instances
5+
spec:
6+
imageName: ${E2E_PRE_ROLLING_UPDATE_IMG}
7+
instances: 3
8+
9+
postgresql:
10+
parameters:
11+
log_checkpoints: "on"
12+
log_lock_waits: "on"
13+
log_min_duration_statement: '1000'
14+
log_statement: 'ddl'
15+
log_temp_files: '1024'
16+
log_autovacuum_min_duration: '1s'
17+
log_replication_commands: 'on'
18+
19+
# Example of rolling update strategy:
20+
# - unsupervised: automated update of the primary once all
21+
# replicas have been upgraded (default)
22+
# - supervised: requires manual supervision to perform
23+
# the switchover of the primary
24+
primaryUpdateStrategy: unsupervised
25+
primaryUpdateMethod: restart
26+
27+
bootstrap:
28+
initdb:
29+
database: app
30+
owner: app
31+
32+
# Persistent storage configuration
33+
storage:
34+
storageClass: ${E2E_DEFAULT_STORAGE_CLASS}
35+
size: 1Gi

tests/e2e/rolling_update_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,31 @@ var _ = Describe("Rolling updates", func() {
332332
AssertRollingUpdate(namespace, clusterName, sampleFile, 1)
333333
})
334334
})
335+
336+
Context("primaryUpdateMethod set to restart", func() {
337+
const sampleFile = fixturesDir + "/rolling_updates/cluster-using-primary-update-method.yaml"
338+
var namespace, clusterName string
339+
340+
JustAfterEach(func() {
341+
if CurrentSpecReport().Failed() {
342+
env.DumpClusterEnv(namespace, clusterName,
343+
"out/"+CurrentSpecReport().LeafNodeText+".log")
344+
}
345+
})
346+
347+
AfterEach(func() {
348+
err := env.DeleteNamespace(namespace)
349+
Expect(err).ToNot(HaveOccurred())
350+
})
351+
352+
It("can do rolling update", func() {
353+
namespace = "cluster-rolling-with-primary-update-method"
354+
err := env.CreateNamespace(namespace)
355+
Expect(err).ToNot(HaveOccurred())
356+
357+
clusterName, err = env.GetResourceNameFromYAML(sampleFile)
358+
Expect(err).ToNot(HaveOccurred())
359+
AssertRollingUpdate(namespace, clusterName, sampleFile, 2)
360+
})
361+
})
335362
})

0 commit comments

Comments
 (0)