Skip to content

Commit 0d533d5

Browse files
committed
fix: preserve valid config on failed reload
1 parent ff04631 commit 0d533d5

2 files changed

Lines changed: 85 additions & 12 deletions

File tree

pkg/identity/keystone/keystone.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,16 @@ func (k *Auth) processNextItem() bool {
171171
return true
172172
}
173173

174-
func (k *Auth) updatePolicies(cm *apiv1.ConfigMap, key string) {
174+
func (k *Auth) updatePolicies(cm *apiv1.ConfigMap, key string) error {
175175
klog.Info("ConfigMap created or updated, will update the authorization policy.")
176176

177177
var policy policyList
178178
if err := json.Unmarshal([]byte(cm.Data["policies"]), &policy); err != nil {
179-
runtimeutil.HandleError(fmt.Errorf("failed to parse policies defined in the configmap %s: %v", key, err))
179+
return fmt.Errorf("failed to parse policies defined in the configmap %s: %w", key, err)
180180
}
181181
if len(policy) > 0 {
182182
if _, err := json.MarshalIndent(policy, "", " "); err != nil {
183-
runtimeutil.HandleError(fmt.Errorf("failed to parse policies defined in the configmap %s: %v", key, err))
183+
return fmt.Errorf("failed to parse policies defined in the configmap %s: %w", key, err)
184184
}
185185
}
186186

@@ -189,23 +189,26 @@ func (k *Auth) updatePolicies(cm *apiv1.ConfigMap, key string) {
189189
k.authz.mu.Unlock()
190190

191191
klog.Infof("Authorization policy updated.")
192+
return nil
192193
}
193194

194-
func (k *Auth) updateSyncConfig(cm *apiv1.ConfigMap, key string) {
195+
func (k *Auth) updateSyncConfig(cm *apiv1.ConfigMap, key string) error {
195196
klog.Info("ConfigMap created or updated, will update the sync configuration.")
196197

197-
var sc *syncConfig
198-
newConfig := newSyncConfig()
199-
sc = &newConfig
200-
if err := yaml.Unmarshal([]byte(cm.Data["syncConfig"]), sc); err != nil {
201-
runtimeutil.HandleError(fmt.Errorf("failed to parse sync config defined in the configmap %s: %v", key, err))
198+
sc := newSyncConfig()
199+
if err := yaml.Unmarshal([]byte(cm.Data["syncConfig"]), &sc); err != nil {
200+
return fmt.Errorf("failed to parse sync config defined in the configmap %s: %w", key, err)
201+
}
202+
if err := sc.validate(); err != nil {
203+
return fmt.Errorf("sync config defined in the configmap %s is invalid: %w", key, err)
202204
}
203205

204206
k.syncer.mu.Lock()
205-
k.syncer.syncConfig = sc
207+
k.syncer.syncConfig = &sc
206208
k.syncer.mu.Unlock()
207209

208210
klog.Infof("Sync configuration updated.")
211+
return nil
209212
}
210213

211214
func (k *Auth) processItem(key string) error {
@@ -234,10 +237,14 @@ func (k *Auth) processItem(key string) error {
234237
return fmt.Errorf("error fetching object with key %s: %v", key, err)
235238
default:
236239
if name == k.config.PolicyConfigMapName {
237-
k.updatePolicies(cm, key)
240+
if err := k.updatePolicies(cm, key); err != nil {
241+
return err
242+
}
238243
}
239244
if name == k.config.SyncConfigMapName {
240-
k.updateSyncConfig(cm, key)
245+
if err := k.updateSyncConfig(cm, key); err != nil {
246+
return err
247+
}
241248
}
242249
}
243250

pkg/identity/keystone/keystone_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"testing"
2828

2929
"github.com/spf13/pflag"
30+
apiv1 "k8s.io/api/core/v1"
3031
)
3132

3233
func TestUserAgentFlag(t *testing.T) {
@@ -152,3 +153,68 @@ func TestWebhookRouting(t *testing.T) {
152153
})
153154
}
154155
}
156+
157+
func TestUpdatePolicies(t *testing.T) {
158+
existingPolicy := &policy{}
159+
auth := &Auth{authz: &Authorizer{pl: policyList{existingPolicy}}}
160+
161+
err := auth.updatePolicies(&apiv1.ConfigMap{Data: map[string]string{"policies": "{"}}, "kube-system/policy")
162+
if err == nil {
163+
t.Fatal("expected an invalid policy update to fail")
164+
}
165+
if len(auth.authz.pl) != 1 || auth.authz.pl[0] != existingPolicy {
166+
t.Fatal("invalid policy update replaced the existing policy")
167+
}
168+
169+
err = auth.updatePolicies(&apiv1.ConfigMap{Data: map[string]string{"policies": "[{}]"}}, "kube-system/policy")
170+
if err != nil {
171+
t.Fatalf("expected a valid policy update to succeed: %v", err)
172+
}
173+
if len(auth.authz.pl) != 1 || auth.authz.pl[0] == existingPolicy {
174+
t.Fatal("valid policy update did not replace the existing policy")
175+
}
176+
}
177+
178+
func TestUpdateSyncConfig(t *testing.T) {
179+
tests := []struct {
180+
name string
181+
syncConfig string
182+
}{
183+
{
184+
name: "malformed config",
185+
syncConfig: "data-types-to-sync: [projects",
186+
},
187+
{
188+
name: "invalid config",
189+
syncConfig: "data-types-to-sync: [unsupported]",
190+
},
191+
}
192+
193+
for _, tt := range tests {
194+
t.Run(tt.name, func(t *testing.T) {
195+
existingConfig := &syncConfig{DataTypesToSync: []string{Projects}, NamespaceFormat: "%i"}
196+
auth := &Auth{syncer: &Syncer{syncConfig: existingConfig}}
197+
198+
err := auth.updateSyncConfig(&apiv1.ConfigMap{Data: map[string]string{"syncConfig": tt.syncConfig}}, "kube-system/sync")
199+
if err == nil {
200+
t.Fatal("expected an invalid sync config update to fail")
201+
}
202+
if auth.syncer.syncConfig != existingConfig {
203+
t.Fatal("invalid sync config update replaced the existing config")
204+
}
205+
})
206+
}
207+
208+
auth := &Auth{syncer: &Syncer{syncConfig: &syncConfig{}}}
209+
err := auth.updateSyncConfig(&apiv1.ConfigMap{Data: map[string]string{
210+
"syncConfig": "data-types-to-sync: [projects]\nnamespace-format: prefix-%i"},
211+
}, "kube-system/sync")
212+
if err != nil {
213+
t.Fatalf("expected a valid sync config update to succeed: %v", err)
214+
}
215+
if auth.syncer.syncConfig.NamespaceFormat != "prefix-%i" ||
216+
len(auth.syncer.syncConfig.DataTypesToSync) != 1 ||
217+
auth.syncer.syncConfig.DataTypesToSync[0] != Projects {
218+
t.Fatalf("valid sync config update was not applied: %#v", auth.syncer.syncConfig)
219+
}
220+
}

0 commit comments

Comments
 (0)