Skip to content

Commit 3707210

Browse files
committed
all configmap should be updated when not in manual mode
Signed-off-by: haorenfsa <shaoyue.chen@zilliz.com>
1 parent 149985a commit 3707210

File tree

3 files changed

+109
-40
lines changed

3 files changed

+109
-40
lines changed

apis/milvus.io/v1beta1/components_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ type MilvusComponents struct {
200200
// note: the active configmap won't switch automatically
201201
// because we may want to change configmap for existing pods
202202
// so it's hard to determine when to switch. you need to switch it manually.
203+
// if EnableManualMode is set to false, changes will be applied to all configmaps
203204
ActiveConfigMap string `json:"activeConfigMap,omitempty"`
204205

205206
// RunAsNonRoot whether to run milvus as non-root user

pkg/controllers/configmaps.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import (
66
corev1 "k8s.io/api/core/v1"
77
kerrors "k8s.io/apimachinery/pkg/api/errors"
88
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/labels"
910
"k8s.io/apimachinery/pkg/types"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
1012
"sigs.k8s.io/yaml"
1113

1214
"github.com/milvus-io/milvus-operator/apis/milvus.io/v1beta1"
1315
"github.com/milvus-io/milvus-operator/pkg/config"
1416
"github.com/milvus-io/milvus-operator/pkg/util"
17+
"github.com/pkg/errors"
1518
)
1619

1720
func (r *MilvusReconciler) getMinioAccessInfo(ctx context.Context, mc v1beta1.Milvus) (string, string) {
@@ -116,7 +119,40 @@ func (r *MilvusReconciler) updateConfigMap(ctx context.Context, mc v1beta1.Milvu
116119
}
117120

118121
func (r *MilvusReconciler) ReconcileConfigMaps(ctx context.Context, mc v1beta1.Milvus) error {
119-
namespacedName := NamespacedName(mc.Namespace, mc.GetActiveConfigMap())
122+
if mc.Spec.Com.EnableManualMode {
123+
namespacedName := NamespacedName(mc.Namespace, mc.GetActiveConfigMap())
124+
return reconcileOneConfigMap(r, ctx, mc, namespacedName)
125+
}
126+
// reconcile all configmaps
127+
cmLabels := NewAppLabels(mc.Name)
128+
cmList := &corev1.ConfigMapList{}
129+
err := r.List(ctx, cmList, &client.ListOptions{
130+
Namespace: mc.Namespace,
131+
LabelSelector: labels.SelectorFromSet(cmLabels),
132+
})
133+
if err != nil {
134+
return errors.Wrap(err, "list configmaps")
135+
}
136+
if len(cmList.Items) == 0 {
137+
// when no configmap found, create one
138+
cmList.Items = append(cmList.Items, corev1.ConfigMap{
139+
ObjectMeta: metav1.ObjectMeta{
140+
Name: mc.GetActiveConfigMap(),
141+
Namespace: mc.Namespace,
142+
},
143+
})
144+
}
145+
146+
for _, cm := range cmList.Items {
147+
err = reconcileOneConfigMap(r, ctx, mc, client.ObjectKeyFromObject(&cm))
148+
if err != nil {
149+
return errors.Wrapf(err, "reconcile configmap[%s]", &cm.ObjectMeta)
150+
}
151+
}
152+
return nil
153+
}
154+
155+
var reconcileOneConfigMap = func(r *MilvusReconciler, ctx context.Context, mc v1beta1.Milvus, namespacedName types.NamespacedName) error {
120156
old := &corev1.ConfigMap{}
121157
err := r.Get(ctx, namespacedName, old)
122158
if kerrors.IsNotFound(err) {

pkg/controllers/configmaps_test.go

Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package controllers
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"testing"
87

98
"github.com/milvus-io/milvus-operator/apis/milvus.io/v1beta1"
@@ -12,18 +11,75 @@ import (
1211
corev1 "k8s.io/api/core/v1"
1312
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
1413
"k8s.io/apimachinery/pkg/runtime/schema"
14+
"k8s.io/apimachinery/pkg/types"
1515
"sigs.k8s.io/controller-runtime/pkg/client"
16-
"sigs.k8s.io/yaml"
1716
)
1817

19-
func TestReconcileConfigMaps_CreateIfNotfound(t *testing.T) {
18+
func TestReconcileConfigMaps(t *testing.T) {
2019
env := newTestEnv(t)
2120
defer env.checkMocks()
22-
r := env.Reconciler
2321
mockClient := env.MockClient
22+
r := env.Reconciler
2423
ctx := env.ctx
2524
mc := env.Inst
2625

26+
// mock reconcileOneConfigMap
27+
bak := reconcileOneConfigMap
28+
defer func() {
29+
reconcileOneConfigMap = bak
30+
}()
31+
var reconcileCMCount int
32+
reconcileOneConfigMap = func(r *MilvusReconciler, ctx context.Context, mc v1beta1.Milvus, namespacedName types.NamespacedName) error {
33+
reconcileCMCount++
34+
return nil
35+
}
36+
t.Run("reconcile only active cm when manual mode enabled", func(t *testing.T) {
37+
reconcileCMCount = 0
38+
mc.Spec.Com.EnableManualMode = true
39+
err := r.ReconcileConfigMaps(ctx, mc)
40+
assert.NoError(t, err)
41+
assert.Equal(t, 1, reconcileCMCount)
42+
})
43+
44+
t.Run("create if none", func(t *testing.T) {
45+
reconcileCMCount = 0
46+
mc.Spec.Com.EnableManualMode = false
47+
mockClient.EXPECT().
48+
List(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
49+
err := r.ReconcileConfigMaps(ctx, mc)
50+
assert.NoError(t, err)
51+
assert.Equal(t, 1, reconcileCMCount)
52+
})
53+
54+
t.Run("reconcile all cm when manual mode disabled", func(t *testing.T) {
55+
reconcileCMCount = 0
56+
mc.Spec.Com.EnableManualMode = false
57+
mockClient.EXPECT().
58+
List(gomock.Any(), gomock.Any(), gomock.Any()).
59+
DoAndReturn(func(ctx, obj any, opts ...any) error {
60+
list := obj.(*corev1.ConfigMapList)
61+
list.Items = []corev1.ConfigMap{
62+
{}, {}, {},
63+
}
64+
return nil
65+
})
66+
err := r.ReconcileConfigMaps(ctx, mc)
67+
assert.NoError(t, err)
68+
assert.Equal(t, 3, reconcileCMCount)
69+
})
70+
}
71+
72+
func TestReconcileOneConfigMap_CreateIfNotfound(t *testing.T) {
73+
env := newTestEnv(t)
74+
defer env.checkMocks()
75+
r := env.Reconciler
76+
mockClient := env.MockClient
77+
ctx := env.ctx
78+
mc := env.Inst
79+
nn := types.NamespacedName{
80+
Namespace: mc.Namespace,
81+
Name: mc.GetActiveConfigMap(),
82+
}
2783
// all ok
2884
gomock.InOrder(
2985
mockClient.EXPECT().
@@ -36,32 +92,35 @@ func TestReconcileConfigMaps_CreateIfNotfound(t *testing.T) {
3692
mockClient.EXPECT().
3793
Create(gomock.Any(), gomock.Any()).Return(nil),
3894
)
39-
err := r.ReconcileConfigMaps(ctx, mc)
95+
err := reconcileOneConfigMap(r, ctx, mc, nn)
4096
assert.NoError(t, err)
4197

4298
// get failed
4399
mockClient.EXPECT().
44100
Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&corev1.ConfigMap{})).
45101
Return(errors.New("some network issue"))
46-
err = r.ReconcileConfigMaps(ctx, mc)
102+
err = reconcileOneConfigMap(r, ctx, mc, nn)
47103
assert.Error(t, err)
48104

49105
// get failed
50106
mockClient.EXPECT().
51107
Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&corev1.ConfigMap{})).
52108
Return(errors.New("some network issue"))
53-
err = r.ReconcileConfigMaps(ctx, mc)
109+
err = reconcileOneConfigMap(r, ctx, mc, nn)
54110
assert.Error(t, err)
55111
}
56112

57-
func TestReconcileConfigMaps_Existed(t *testing.T) {
113+
func TestReconcileOneConfigMap_Existed(t *testing.T) {
58114
env := newTestEnv(t)
59115
defer env.checkMocks()
60116
r := env.Reconciler
61117
mockClient := env.MockClient
62118
ctx := env.ctx
63119
mc := env.Inst
64-
120+
nn := types.NamespacedName{
121+
Namespace: mc.Namespace,
122+
Name: mc.GetActiveConfigMap(),
123+
}
65124
t.Run("call client.Update if changed configmap", func(t *testing.T) {
66125
mc.Spec.HookConf.Data = map[string]interface{}{
67126
"x": "y",
@@ -83,35 +142,8 @@ func TestReconcileConfigMaps_Existed(t *testing.T) {
83142
Update(gomock.Any(), gomock.Any()).Return(nil),
84143
)
85144

86-
err := r.ReconcileConfigMaps(ctx, mc)
145+
err := reconcileOneConfigMap(r, ctx, mc, nn)
87146
assert.NoError(t, err)
88-
mockClient.EXPECT().
89-
Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&corev1.ConfigMap{})).
90-
DoAndReturn(func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...any) error {
91-
cm := obj.(*corev1.ConfigMap)
92-
cm.Name = "cm1"
93-
cm.Namespace = "ns"
94-
err := mockClient.Get(ctx, client.ObjectKeyFromObject(cm), cm)
95-
if err != nil {
96-
return err
97-
}
98-
if len(cm.Data) == 0 {
99-
return errors.New("expect data in configmap")
100-
}
101-
if _, ok := cm.Data["hook.yaml"]; !ok {
102-
return errors.New("expect hook.yaml as key in data")
103-
}
104-
expected, err := yaml.Marshal(map[string]string{
105-
"x": "y",
106-
})
107-
if err != nil {
108-
return err
109-
}
110-
if cm.Data["hook.yaml"] != string(expected) {
111-
return fmt.Errorf("content not match, expected: %s, got: %s", cm.Data["hook.yaml"], string(expected))
112-
}
113-
return nil
114-
})
115147
})
116148

117149
t.Run("not call client.Update if configmap not changed", func(t *testing.T) {
@@ -130,7 +162,7 @@ func TestReconcileConfigMaps_Existed(t *testing.T) {
130162
Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&corev1.Secret{})).
131163
Return(k8sErrors.NewNotFound(schema.GroupResource{}, "mockErr")).Times(2),
132164
)
133-
err := r.ReconcileConfigMaps(ctx, mc)
165+
err := reconcileOneConfigMap(r, ctx, mc, nn)
134166
assert.NoError(t, err)
135167
})
136168

@@ -150,7 +182,7 @@ func TestReconcileConfigMaps_Existed(t *testing.T) {
150182
Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&corev1.Secret{})).
151183
Return(k8sErrors.NewNotFound(schema.GroupResource{}, "mockErr")).Times(2),
152184
)
153-
err := r.ReconcileConfigMaps(ctx, mc)
185+
err := reconcileOneConfigMap(r, ctx, mc, nn)
154186
assert.NoError(t, err)
155187
})
156188

0 commit comments

Comments
 (0)