Skip to content

Commit a85023f

Browse files
authored
Cluster env variables should be reflected for StatefulSet update (zalando#2045)
* Cluster env variables should be reflected for StatefulSet update * Add unit test for comparing StatefulSet's
1 parent 78bd4fa commit a85023f

File tree

3 files changed

+84
-60
lines changed

3 files changed

+84
-60
lines changed

pkg/cluster/cluster_test.go

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import (
66
"strings"
77
"testing"
88

9-
"github.com/stretchr/testify/assert"
10-
119
"github.com/sirupsen/logrus"
10+
"github.com/stretchr/testify/assert"
1211
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
1312
fakeacidv1 "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/fake"
1413
"github.com/zalando/postgres-operator/pkg/spec"
@@ -61,7 +60,6 @@ var cl = New(
6160
)
6261

6362
func TestStatefulSetAnnotations(t *testing.T) {
64-
testName := "CheckStatefulsetAnnotations"
6563
spec := acidv1.PostgresSpec{
6664
TeamID: "myapp", NumberOfInstances: 1,
6765
Resources: &acidv1.Resources{
@@ -74,19 +72,59 @@ func TestStatefulSetAnnotations(t *testing.T) {
7472
}
7573
ss, err := cl.generateStatefulSet(&spec)
7674
if err != nil {
77-
t.Errorf("in %s no statefulset created %v", testName, err)
75+
t.Errorf("in %s no statefulset created %v", t.Name(), err)
7876
}
7977
if ss != nil {
8078
annotation := ss.ObjectMeta.GetAnnotations()
8179
if _, ok := annotation["downscaler/downtime_replicas"]; !ok {
82-
t.Errorf("in %s respective annotation not found on sts", testName)
80+
t.Errorf("in %s respective annotation not found on sts", t.Name())
8381
}
8482
}
83+
}
84+
85+
func TestStatefulSetUpdateWithEnv(t *testing.T) {
86+
oldSpec := &acidv1.PostgresSpec{
87+
TeamID: "myapp", NumberOfInstances: 1,
88+
Resources: &acidv1.Resources{
89+
ResourceRequests: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
90+
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
91+
},
92+
Volume: acidv1.Volume{
93+
Size: "1G",
94+
},
95+
}
96+
oldSS, err := cl.generateStatefulSet(oldSpec)
97+
if err != nil {
98+
t.Errorf("in %s no StatefulSet created %v", t.Name(), err)
99+
}
100+
101+
newSpec := oldSpec.DeepCopy()
102+
newSS, err := cl.generateStatefulSet(newSpec)
103+
if err != nil {
104+
t.Errorf("in %s no StatefulSet created %v", t.Name(), err)
105+
}
85106

107+
if !reflect.DeepEqual(oldSS, newSS) {
108+
t.Errorf("in %s StatefulSet's must be equal", t.Name())
109+
}
110+
111+
newSpec.Env = []v1.EnvVar{
112+
{
113+
Name: "CUSTOM_ENV_VARIABLE",
114+
Value: "data",
115+
},
116+
}
117+
newSS, err = cl.generateStatefulSet(newSpec)
118+
if err != nil {
119+
t.Errorf("in %s no StatefulSet created %v", t.Name(), err)
120+
}
121+
122+
if reflect.DeepEqual(oldSS, newSS) {
123+
t.Errorf("in %s StatefulSet's must be not equal", t.Name())
124+
}
86125
}
87126

88127
func TestInitRobotUsers(t *testing.T) {
89-
testName := "TestInitRobotUsers"
90128
tests := []struct {
91129
manifestUsers map[string]acidv1.UserFlags
92130
infraRoles map[string]spec.PgUser
@@ -130,22 +168,20 @@ func TestInitRobotUsers(t *testing.T) {
130168
cl.pgUsers = tt.infraRoles
131169
if err := cl.initRobotUsers(); err != nil {
132170
if tt.err == nil {
133-
t.Errorf("%s got an unexpected error: %v", testName, err)
171+
t.Errorf("%s got an unexpected error: %v", t.Name(), err)
134172
}
135173
if err.Error() != tt.err.Error() {
136-
t.Errorf("%s expected error %v, got %v", testName, tt.err, err)
174+
t.Errorf("%s expected error %v, got %v", t.Name(), tt.err, err)
137175
}
138176
} else {
139177
if !reflect.DeepEqual(cl.pgUsers, tt.result) {
140-
t.Errorf("%s expected: %#v, got %#v", testName, tt.result, cl.pgUsers)
178+
t.Errorf("%s expected: %#v, got %#v", t.Name(), tt.result, cl.pgUsers)
141179
}
142180
}
143181
}
144182
}
145183

146184
func TestInitAdditionalOwnerRoles(t *testing.T) {
147-
testName := "TestInitAdditionalOwnerRoles"
148-
149185
manifestUsers := map[string]acidv1.UserFlags{"foo_owner": {}, "bar_owner": {}, "app_user": {}}
150186
expectedUsers := map[string]spec.PgUser{
151187
"foo_owner": {Origin: spec.RoleOriginManifest, Name: "foo_owner", Namespace: cl.Namespace, Password: "f123", Flags: []string{"LOGIN"}, IsDbOwner: true, MemberOf: []string{"cron_admin", "part_man"}},
@@ -158,7 +194,7 @@ func TestInitAdditionalOwnerRoles(t *testing.T) {
158194

159195
// this should set IsDbOwner field for manifest users
160196
if err := cl.initRobotUsers(); err != nil {
161-
t.Errorf("%s could not init manifest users", testName)
197+
t.Errorf("%s could not init manifest users", t.Name())
162198
}
163199

164200
// now assign additional roles to owners
@@ -169,7 +205,7 @@ func TestInitAdditionalOwnerRoles(t *testing.T) {
169205
expectedPgUser := expectedUsers[username]
170206
if !util.IsEqualIgnoreOrder(expectedPgUser.MemberOf, existingPgUser.MemberOf) {
171207
t.Errorf("%s unexpected membership of user %q: expected member of %#v, got member of %#v",
172-
testName, username, expectedPgUser.MemberOf, existingPgUser.MemberOf)
208+
t.Name(), username, expectedPgUser.MemberOf, existingPgUser.MemberOf)
173209
}
174210
}
175211
}
@@ -195,11 +231,9 @@ func (m *mockTeamsAPIClient) setMembers(members []string) {
195231

196232
// Test adding a member of a product team owning a particular DB cluster
197233
func TestInitHumanUsers(t *testing.T) {
198-
199234
var mockTeamsAPI mockTeamsAPIClient
200235
cl.oauthTokenGetter = &mockOAuthTokenGetter{}
201236
cl.teamsAPIClient = &mockTeamsAPI
202-
testName := "TestInitHumanUsers"
203237

204238
// members of a product team are granted superuser rights for DBs of their team
205239
cl.OpConfig.EnableTeamSuperuser = true
@@ -232,11 +266,11 @@ func TestInitHumanUsers(t *testing.T) {
232266
cl.pgUsers = tt.existingRoles
233267
mockTeamsAPI.setMembers(tt.teamRoles)
234268
if err := cl.initHumanUsers(); err != nil {
235-
t.Errorf("%s got an unexpected error %v", testName, err)
269+
t.Errorf("%s got an unexpected error %v", t.Name(), err)
236270
}
237271

238272
if !reflect.DeepEqual(cl.pgUsers, tt.result) {
239-
t.Errorf("%s expects %#v, got %#v", testName, tt.result, cl.pgUsers)
273+
t.Errorf("%s expects %#v, got %#v", t.Name(), tt.result, cl.pgUsers)
240274
}
241275
}
242276
}
@@ -264,12 +298,10 @@ func (m *mockTeamsAPIClientMultipleTeams) TeamInfo(teamID, token string) (tm *te
264298

265299
// Test adding members of maintenance teams that get superuser rights for all PG databases
266300
func TestInitHumanUsersWithSuperuserTeams(t *testing.T) {
267-
268301
var mockTeamsAPI mockTeamsAPIClientMultipleTeams
269302
cl.oauthTokenGetter = &mockOAuthTokenGetter{}
270303
cl.teamsAPIClient = &mockTeamsAPI
271304
cl.OpConfig.EnableTeamSuperuser = false
272-
testName := "TestInitHumanUsersWithSuperuserTeams"
273305

274306
cl.OpConfig.EnableTeamsAPI = true
275307
cl.OpConfig.PamRoleName = "zalandos"
@@ -371,17 +403,16 @@ func TestInitHumanUsersWithSuperuserTeams(t *testing.T) {
371403
cl.OpConfig.PostgresSuperuserTeams = tt.superuserTeams
372404

373405
if err := cl.initHumanUsers(); err != nil {
374-
t.Errorf("%s got an unexpected error %v", testName, err)
406+
t.Errorf("%s got an unexpected error %v", t.Name(), err)
375407
}
376408

377409
if !reflect.DeepEqual(cl.pgUsers, tt.result) {
378-
t.Errorf("%s expects %#v, got %#v", testName, tt.result, cl.pgUsers)
410+
t.Errorf("%s expects %#v, got %#v", t.Name(), tt.result, cl.pgUsers)
379411
}
380412
}
381413
}
382414

383415
func TestPodAnnotations(t *testing.T) {
384-
testName := "TestPodAnnotations"
385416
tests := []struct {
386417
subTest string
387418
operator map[string]string
@@ -428,13 +459,13 @@ func TestPodAnnotations(t *testing.T) {
428459
for k, v := range annotations {
429460
if observed, expected := v, tt.merged[k]; observed != expected {
430461
t.Errorf("%v expects annotation value %v for key %v, but found %v",
431-
testName+"/"+tt.subTest, expected, observed, k)
462+
t.Name()+"/"+tt.subTest, expected, observed, k)
432463
}
433464
}
434465
for k, v := range tt.merged {
435466
if observed, expected := annotations[k], v; observed != expected {
436467
t.Errorf("%v expects annotation value %v for key %v, but found %v",
437-
testName+"/"+tt.subTest, expected, observed, k)
468+
t.Name()+"/"+tt.subTest, expected, observed, k)
438469
}
439470
}
440471
}
@@ -780,22 +811,20 @@ func TestServiceAnnotations(t *testing.T) {
780811
}
781812

782813
func TestInitSystemUsers(t *testing.T) {
783-
testName := "Test system users initialization"
784-
785814
// default cluster without connection pooler and event streams
786815
cl.initSystemUsers()
787816
if _, exist := cl.systemUsers[constants.ConnectionPoolerUserKeyName]; exist {
788-
t.Errorf("%s, connection pooler user is present", testName)
817+
t.Errorf("%s, connection pooler user is present", t.Name())
789818
}
790819
if _, exist := cl.systemUsers[constants.EventStreamUserKeyName]; exist {
791-
t.Errorf("%s, stream user is present", testName)
820+
t.Errorf("%s, stream user is present", t.Name())
792821
}
793822

794823
// cluster with connection pooler
795824
cl.Spec.EnableConnectionPooler = boolToPointer(true)
796825
cl.initSystemUsers()
797826
if _, exist := cl.systemUsers[constants.ConnectionPoolerUserKeyName]; !exist {
798-
t.Errorf("%s, connection pooler user is not present", testName)
827+
t.Errorf("%s, connection pooler user is not present", t.Name())
799828
}
800829

801830
// superuser is not allowed as connection pool user
@@ -807,7 +836,7 @@ func TestInitSystemUsers(t *testing.T) {
807836

808837
cl.initSystemUsers()
809838
if _, exist := cl.systemUsers["pooler"]; !exist {
810-
t.Errorf("%s, Superuser is not allowed to be a connection pool user", testName)
839+
t.Errorf("%s, Superuser is not allowed to be a connection pool user", t.Name())
811840
}
812841

813842
// neither protected users are
@@ -819,7 +848,7 @@ func TestInitSystemUsers(t *testing.T) {
819848

820849
cl.initSystemUsers()
821850
if _, exist := cl.systemUsers["pooler"]; !exist {
822-
t.Errorf("%s, Protected user are not allowed to be a connection pool user", testName)
851+
t.Errorf("%s, Protected user are not allowed to be a connection pool user", t.Name())
823852
}
824853

825854
delete(cl.systemUsers, "pooler")
@@ -829,15 +858,15 @@ func TestInitSystemUsers(t *testing.T) {
829858

830859
cl.initSystemUsers()
831860
if _, exist := cl.systemUsers["pooler"]; !exist {
832-
t.Errorf("%s, System users are not allowed to be a connection pool user", testName)
861+
t.Errorf("%s, System users are not allowed to be a connection pool user", t.Name())
833862
}
834863

835864
// using stream user in manifest but no streams defined should be treated like normal robot user
836865
streamUser := fmt.Sprintf("%s%s", constants.EventStreamSourceSlotPrefix, constants.UserRoleNameSuffix)
837866
cl.Spec.Users = map[string]acidv1.UserFlags{streamUser: []string{}}
838867
cl.initSystemUsers()
839868
if _, exist := cl.systemUsers[constants.EventStreamUserKeyName]; exist {
840-
t.Errorf("%s, stream user is present", testName)
869+
t.Errorf("%s, stream user is present", t.Name())
841870
}
842871

843872
// cluster with streams
@@ -846,32 +875,30 @@ func TestInitSystemUsers(t *testing.T) {
846875
ApplicationId: "test-app",
847876
Database: "test_db",
848877
Tables: map[string]acidv1.StreamTable{
849-
"data.test_table": acidv1.StreamTable{
878+
"data.test_table": {
850879
EventType: "test_event",
851880
},
852881
},
853882
},
854883
}
855884
cl.initSystemUsers()
856885
if _, exist := cl.systemUsers[constants.EventStreamUserKeyName]; !exist {
857-
t.Errorf("%s, stream user is not present", testName)
886+
t.Errorf("%s, stream user is not present", t.Name())
858887
}
859888
}
860889

861890
func TestPreparedDatabases(t *testing.T) {
862-
testName := "TestDefaultPreparedDatabase"
863-
864891
cl.Spec.PreparedDatabases = map[string]acidv1.PreparedDatabase{}
865892
cl.initPreparedDatabaseRoles()
866893

867894
for _, role := range []string{"acid_test_owner", "acid_test_reader", "acid_test_writer",
868895
"acid_test_data_owner", "acid_test_data_reader", "acid_test_data_writer"} {
869896
if _, exist := cl.pgUsers[role]; !exist {
870-
t.Errorf("%s, default role %q for prepared database not present", testName, role)
897+
t.Errorf("%s, default role %q for prepared database not present", t.Name(), role)
871898
}
872899
}
873900

874-
testName = "TestPreparedDatabaseWithSchema"
901+
testName := "TestPreparedDatabaseWithSchema"
875902

876903
cl.Spec.PreparedDatabases = map[string]acidv1.PreparedDatabase{
877904
"foo": {
@@ -1109,7 +1136,6 @@ func newService(ann map[string]string, svcT v1.ServiceType, lbSr []string) *v1.S
11091136
}
11101137

11111138
func TestCompareServices(t *testing.T) {
1112-
testName := "TestCompareServices"
11131139
cluster := Cluster{
11141140
Config: Config{
11151141
OpConfig: config.Config{
@@ -1410,16 +1436,16 @@ func TestCompareServices(t *testing.T) {
14101436
match, reason := cluster.compareServices(tt.current, tt.new)
14111437
if match && !tt.match {
14121438
t.Logf("match=%v current=%v, old=%v reason=%s", match, tt.current.Annotations, tt.new.Annotations, reason)
1413-
t.Errorf("%s - expected services to do not match: %q and %q", testName, tt.current, tt.new)
1439+
t.Errorf("%s - expected services to do not match: %q and %q", t.Name(), tt.current, tt.new)
14141440
return
14151441
}
14161442
if !match && tt.match {
1417-
t.Errorf("%s - expected services to be the same: %q and %q", testName, tt.current, tt.new)
1443+
t.Errorf("%s - expected services to be the same: %q and %q", t.Name(), tt.current, tt.new)
14181444
return
14191445
}
14201446
if !match && !tt.match {
14211447
if !strings.HasPrefix(reason, tt.reason) {
1422-
t.Errorf("%s - expected reason prefix %s, found %s", testName, tt.reason, reason)
1448+
t.Errorf("%s - expected reason prefix %s, found %s", t.Name(), tt.reason, reason)
14231449
return
14241450
}
14251451
}

pkg/cluster/k8sres.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -797,10 +797,9 @@ func (c *Cluster) generatePodTemplate(
797797

798798
// generatePodEnvVars generates environment variables for the Spilo Pod
799799
func (c *Cluster) generateSpiloPodEnvVars(
800+
spec *acidv1.PostgresSpec,
800801
uid types.UID,
801-
spiloConfiguration string,
802-
cloneDescription *acidv1.CloneDescription,
803-
standbyDescription *acidv1.StandbyDescription) []v1.EnvVar {
802+
spiloConfiguration string) []v1.EnvVar {
804803

805804
// hard-coded set of environment variables we need
806805
// to guarantee core functionality of the operator
@@ -906,17 +905,17 @@ func (c *Cluster) generateSpiloPodEnvVars(
906905
envVars = append(envVars, v1.EnvVar{Name: "KUBERNETES_USE_CONFIGMAPS", Value: "true"})
907906
}
908907

909-
if cloneDescription != nil && cloneDescription.ClusterName != "" {
910-
envVars = append(envVars, c.generateCloneEnvironment(cloneDescription)...)
908+
if spec.Clone != nil && spec.Clone.ClusterName != "" {
909+
envVars = append(envVars, c.generateCloneEnvironment(spec.Clone)...)
911910
}
912911

913-
if standbyDescription != nil {
914-
envVars = append(envVars, c.generateStandbyEnvironment(standbyDescription)...)
912+
if spec.StandbyCluster != nil {
913+
envVars = append(envVars, c.generateStandbyEnvironment(spec.StandbyCluster)...)
915914
}
916915

917916
// fetch cluster-specific variables that will override all subsequent global variables
918-
if len(c.Spec.Env) > 0 {
919-
envVars = appendEnvVars(envVars, c.Spec.Env...)
917+
if len(spec.Env) > 0 {
918+
envVars = appendEnvVars(envVars, spec.Env...)
920919
}
921920

922921
// fetch variables from custom environment Secret
@@ -1186,11 +1185,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
11861185
}
11871186

11881187
// generate environment variables for the spilo container
1189-
spiloEnvVars := c.generateSpiloPodEnvVars(
1190-
c.Postgresql.GetUID(),
1191-
spiloConfiguration,
1192-
spec.Clone,
1193-
spec.StandbyCluster)
1188+
spiloEnvVars := c.generateSpiloPodEnvVars(spec, c.Postgresql.GetUID(), spiloConfiguration)
11941189

11951190
// pickup the docker image for the spilo container
11961191
effectiveDockerImage := util.Coalesce(spec.DockerImage, c.OpConfig.DockerImage)

pkg/cluster/k8sres_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,9 +836,12 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) {
836836

837837
for _, tt := range tests {
838838
c := newMockCluster(tt.opConfig)
839-
c.Postgresql = tt.pgsql
840-
actualEnvs := c.generateSpiloPodEnvVars(
841-
types.UID(dummyUUID), exampleSpiloConfig, tt.cloneDescription, tt.standbyDescription)
839+
pgsql := tt.pgsql
840+
pgsql.Spec.Clone = tt.cloneDescription
841+
pgsql.Spec.StandbyCluster = tt.standbyDescription
842+
c.Postgresql = pgsql
843+
844+
actualEnvs := c.generateSpiloPodEnvVars(&pgsql.Spec, types.UID(dummyUUID), exampleSpiloConfig)
842845

843846
for _, ev := range tt.expectedValues {
844847
env := actualEnvs[ev.envIndex]

0 commit comments

Comments
 (0)