Skip to content

Commit a0c6ff4

Browse files
authored
Merge branch 'main' into K8SPSMDB-1546
2 parents 5896eaf + 44edc35 commit a0c6ff4

3 files changed

Lines changed: 196 additions & 53 deletions

File tree

pkg/controller/perconaservermongodb/backup.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,10 @@ func (r *ReconcilePerconaServerMongoDB) deleteOldBackupTasks(ctx context.Context
165165
}
166166

167167
for _, todel := range oldjobs {
168+
log.Info("deleting backup exceeding retention", "job", item.Name, "backup", todel.Name)
168169
err = r.client.Delete(ctx, &todel)
169170
if err != nil {
170-
log.Error(err, "failed to delete backup object")
171+
log.Error(err, "failed to delete backup object", "backup", todel.Name)
171172
return true
172173
}
173174
}

pkg/controller/perconaservermongodb/service.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,23 @@ func (r *ReconcilePerconaServerMongoDB) removeOutdatedServices(ctx context.Conte
191191
for i := 0; i < int(replset.Size); i++ {
192192
svcNames[service.Name+"-"+strconv.Itoa(i)] = struct{}{}
193193
}
194-
}
195194

196-
if replset.NonVoting.Enabled {
197-
for i := 0; i < int(replset.NonVoting.Size); i++ {
198-
svcNames[service.Name+"-nv-"+strconv.Itoa(i)] = struct{}{}
195+
if replset.NonVoting.Enabled {
196+
for i := 0; i < int(replset.NonVoting.Size); i++ {
197+
svcNames[service.Name+"-"+naming.ComponentNonVotingShort+"-"+strconv.Itoa(i)] = struct{}{}
198+
}
199199
}
200-
}
201200

202-
if replset.Arbiter.Enabled {
203-
for i := 0; i < int(replset.Arbiter.Size); i++ {
204-
svcNames[service.Name+"-arbiter-"+strconv.Itoa(i)] = struct{}{}
201+
if replset.Hidden.Enabled {
202+
for i := 0; i < int(replset.Hidden.Size); i++ {
203+
svcNames[service.Name+"-"+naming.ComponentHidden+"-"+strconv.Itoa(i)] = struct{}{}
204+
}
205+
}
206+
207+
if replset.Arbiter.Enabled {
208+
for i := 0; i < int(replset.Arbiter.Size); i++ {
209+
svcNames[service.Name+"-"+naming.ComponentArbiter+"-"+strconv.Itoa(i)] = struct{}{}
210+
}
205211
}
206212
}
207213

pkg/controller/perconaservermongodb/service_test.go

Lines changed: 180 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"os"
66
"path/filepath"
7+
"sort"
78
"testing"
89

910
corev1 "k8s.io/api/core/v1"
@@ -12,6 +13,9 @@ import (
1213

1314
api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1"
1415
"github.com/percona/percona-server-mongodb-operator/pkg/naming"
16+
"github.com/percona/percona-server-mongodb-operator/pkg/psmdb"
17+
"github.com/stretchr/testify/assert"
18+
"github.com/stretchr/testify/require"
1519
)
1620

1721
func TestReconcileReplsetServices(t *testing.T) {
@@ -34,9 +38,8 @@ func TestReconcileReplsetServices(t *testing.T) {
3438
t.Helper()
3539

3640
svcList := new(corev1.ServiceList)
37-
if err := cl.List(ctx, svcList, client.InNamespace(cr.Namespace)); err != nil {
38-
t.Fatal(err)
39-
}
41+
err := cl.List(ctx, svcList, client.InNamespace(cr.Namespace))
42+
require.NoError(t, err)
4043

4144
for i := range svcList.Items {
4245
svcList.Items[i].APIVersion = "v1"
@@ -66,76 +69,209 @@ func TestReconcileReplsetServices(t *testing.T) {
6669

6770
t.Run("expose toggle: not sharded cluster", func(t *testing.T) {
6871
cr, err := readDefaultCR(crName, ns)
69-
if err != nil {
70-
t.Fatal(err)
71-
}
72+
require.NoError(t, err)
73+
7274
cr.Spec.Replsets[0].Expose.Enabled = false
7375
cr.Spec.Sharding.Enabled = false
74-
if err := cr.CheckNSetDefaults(ctx, ""); err != nil {
75-
t.Fatal(err)
76-
}
76+
require.NoError(t, cr.CheckNSetDefaults(ctx, ""))
77+
7778
r := buildFakeClient(prepareObjects(t, cr)...)
7879

79-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
80-
t.Fatal(err)
81-
}
80+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
8281
compareSvcList(t, r.client, cr, "svc_list_expose_off.yaml")
8382

8483
cr.Spec.Replsets[0].Expose.Enabled = true
85-
if err := r.client.Update(ctx, cr); err != nil {
86-
t.Fatal(err)
87-
}
88-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
89-
t.Fatal(err)
90-
}
84+
require.NoError(t, r.client.Update(ctx, cr))
85+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
9186
compareSvcList(t, r.client, cr, "svc_list_expose_on.yaml")
9287

9388
cr.Spec.Replsets[0].Expose.Enabled = false
94-
if err := r.client.Update(ctx, cr); err != nil {
95-
t.Fatal(err)
96-
}
97-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
98-
t.Fatal(err)
99-
}
89+
require.NoError(t, r.client.Update(ctx, cr))
90+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
10091
compareSvcList(t, r.client, cr, "svc_list_expose_off.yaml")
10192
})
10293

10394
t.Run("expose toggle: sharded cluster", func(t *testing.T) {
10495
cr, err := readDefaultCR(crName, ns)
105-
if err != nil {
106-
t.Fatal(err)
107-
}
96+
require.NoError(t, err)
97+
10898
cr.Spec.Replsets[0].Expose.Enabled = false
10999
cr.Spec.Sharding.Enabled = true
110-
if err := cr.CheckNSetDefaults(ctx, ""); err != nil {
111-
t.Fatal(err)
112-
}
100+
require.NoError(t, cr.CheckNSetDefaults(ctx, ""))
113101

114102
r := buildFakeClient(prepareObjects(t, cr)...)
115103

116-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
117-
t.Fatal(err)
118-
}
104+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
119105
compareSvcList(t, r.client, cr, "svc_list_sharded_expose_off.yaml")
120106

121107
cr.Spec.Replsets[0].Expose.Enabled = true
122-
if err := r.client.Update(ctx, cr); err != nil {
123-
t.Fatal(err)
124-
}
125-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
126-
t.Fatal(err)
127-
}
108+
require.NoError(t, r.client.Update(ctx, cr))
109+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
128110
compareSvcList(t, r.client, cr, "svc_list_sharded_expose_on.yaml")
129111

130112
cr.Spec.Replsets[0].Expose.Enabled = false
131-
if err := r.client.Update(ctx, cr); err != nil {
132-
t.Fatal(err)
113+
require.NoError(t, r.client.Update(ctx, cr))
114+
require.NoError(t, r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)))
115+
compareSvcList(t, r.client, cr, "svc_list_sharded_expose_off.yaml")
116+
})
117+
}
118+
119+
func TestRemoveOutdatedServices(t *testing.T) {
120+
ctx := t.Context()
121+
const ns = "rs-svc-outdated"
122+
const crName = ns
123+
const rsName = "rs0"
124+
125+
// names of all per-pod external services that may exist for the replset,
126+
// covering every component type. removeOutdatedServices is expected to keep
127+
// the ones backing currently-enabled members and delete the rest.
128+
prefix := crName + "-" + rsName
129+
baseSvcs := []string{prefix + "-0", prefix + "-1", prefix + "-2"}
130+
nonVotingSvcs := []string{
131+
prefix + "-" + naming.ComponentNonVotingShort + "-0",
132+
prefix + "-" + naming.ComponentNonVotingShort + "-1",
133+
prefix + "-" + naming.ComponentNonVotingShort + "-2",
134+
}
135+
hiddenSvcs := []string{
136+
prefix + "-" + naming.ComponentHidden + "-0",
137+
prefix + "-" + naming.ComponentHidden + "-1",
138+
}
139+
arbiterSvcs := []string{prefix + "-" + naming.ComponentArbiter + "-0"}
140+
141+
concat := func(lists ...[]string) []string {
142+
out := []string{}
143+
for _, l := range lists {
144+
out = append(out, l...)
133145
}
134-
if err := r.reconcileReplsetServices(ctx, cr, getReplsets(t, cr)); err != nil {
146+
sort.Strings(out)
147+
return out
148+
}
149+
150+
allSvcs := concat(baseSvcs, nonVotingSvcs, hiddenSvcs, arbiterSvcs)
151+
152+
// seedServices builds external services (with the labels removeOutdatedServices
153+
// selects on) for every name in allSvcs.
154+
seedServices := func(cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec) []client.Object {
155+
objs := make([]client.Object, 0, len(allSvcs))
156+
for _, name := range allSvcs {
157+
objs = append(objs, psmdb.ExternalService(cr, rs, name))
158+
}
159+
return objs
160+
}
161+
162+
remainingServices := func(t *testing.T, cl client.Client) []string {
163+
t.Helper()
164+
165+
svcList := new(corev1.ServiceList)
166+
if err := cl.List(ctx, svcList, client.InNamespace(ns)); err != nil {
135167
t.Fatal(err)
136168
}
137-
compareSvcList(t, r.client, cr, "svc_list_sharded_expose_off.yaml")
138-
})
169+
names := make([]string, 0, len(svcList.Items))
170+
for _, svc := range svcList.Items {
171+
names = append(names, svc.Name)
172+
}
173+
sort.Strings(names)
174+
return names
175+
}
176+
177+
tests := []struct {
178+
name string
179+
configure func(rs *api.ReplsetSpec)
180+
pause bool
181+
want []string
182+
}{
183+
{
184+
name: "exposed replset without special members keeps only base services",
185+
configure: func(rs *api.ReplsetSpec) {
186+
rs.Expose.Enabled = true
187+
},
188+
want: baseSvcs,
189+
},
190+
{
191+
name: "not exposed replset removes all services",
192+
configure: func(rs *api.ReplsetSpec) {
193+
rs.Expose.Enabled = false
194+
rs.NonVoting.Enabled = true
195+
rs.Hidden.Enabled = true
196+
rs.Arbiter.Enabled = true
197+
},
198+
want: nil,
199+
},
200+
{
201+
name: "exposed replset with hidden members keeps base and hidden services",
202+
configure: func(rs *api.ReplsetSpec) {
203+
rs.Expose.Enabled = true
204+
rs.Hidden.Enabled = true
205+
rs.Hidden.Size = 2
206+
},
207+
want: concat(baseSvcs, hiddenSvcs),
208+
},
209+
{
210+
name: "exposed replset with non-voting members keeps base and non-voting services",
211+
configure: func(rs *api.ReplsetSpec) {
212+
rs.Expose.Enabled = true
213+
rs.NonVoting.Enabled = true
214+
rs.NonVoting.Size = 3
215+
},
216+
want: concat(baseSvcs, nonVotingSvcs),
217+
},
218+
{
219+
name: "exposed replset with arbiter keeps base and arbiter services",
220+
configure: func(rs *api.ReplsetSpec) {
221+
rs.Expose.Enabled = true
222+
rs.Arbiter.Enabled = true
223+
rs.Arbiter.Size = 1
224+
},
225+
want: concat(baseSvcs, arbiterSvcs),
226+
},
227+
{
228+
name: "all member types enabled keeps every service",
229+
configure: func(rs *api.ReplsetSpec) {
230+
rs.Expose.Enabled = true
231+
rs.Hidden.Enabled = true
232+
rs.Hidden.Size = 2
233+
rs.NonVoting.Enabled = true
234+
rs.NonVoting.Size = 3
235+
rs.Arbiter.Enabled = true
236+
rs.Arbiter.Size = 1
237+
},
238+
want: allSvcs,
239+
},
240+
{
241+
name: "paused cluster keeps all services untouched",
242+
configure: func(rs *api.ReplsetSpec) {
243+
rs.Expose.Enabled = true
244+
},
245+
pause: true,
246+
want: allSvcs,
247+
},
248+
}
249+
250+
for _, tt := range tests {
251+
t.Run(tt.name, func(t *testing.T) {
252+
cr, err := readDefaultCR(crName, ns)
253+
require.NoError(t, err)
254+
255+
cr.Spec.Sharding.Enabled = false
256+
require.NoError(t, cr.CheckNSetDefaults(ctx, ""))
257+
258+
rs := cr.Spec.Replsets[0]
259+
rs.Size = 3
260+
tt.configure(rs)
261+
cr.Spec.Pause = tt.pause
262+
263+
objs := append([]client.Object{cr}, seedServices(cr, rs)...)
264+
r := buildFakeClient(objs...)
265+
266+
require.NoError(t, r.removeOutdatedServices(ctx, cr, rs))
267+
268+
got := remainingServices(t, r.client)
269+
want := tt.want
270+
sort.Strings(want)
271+
assert.Equal(t, len(want), len(got), "unexpected remaining service count")
272+
assert.ElementsMatch(t, want, got, "unexpected remaining services")
273+
})
274+
}
139275
}
140276

141277
func yamlCompare(t *testing.T, ns string, filename string, compare any) {

0 commit comments

Comments
 (0)