Skip to content

Commit b5caf24

Browse files
committed
Improve bootstrap policy overwrite error handling
Aggregate errors but continue to other objects Avoid unnecessary delete/recreates
1 parent 842a8df commit b5caf24

File tree

1 file changed

+65
-14
lines changed

1 file changed

+65
-14
lines changed

pkg/cmd/server/admin/overwrite_bootstrappolicy.go

+65-14
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import (
99
"github.com/spf13/cobra"
1010

1111
kapi "k8s.io/kubernetes/pkg/api"
12+
kapierrors "k8s.io/kubernetes/pkg/api/errors"
1213
"k8s.io/kubernetes/pkg/api/meta"
1314
"k8s.io/kubernetes/pkg/apimachinery/registered"
1415
"k8s.io/kubernetes/pkg/kubectl"
1516
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
1617
"k8s.io/kubernetes/pkg/kubectl/resource"
1718
"k8s.io/kubernetes/pkg/runtime"
19+
kerrors "k8s.io/kubernetes/pkg/util/errors"
1820

1921
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
2022
policyregistry "github.com/openshift/origin/pkg/authorization/registry/policy"
@@ -173,14 +175,30 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB
173175
}
174176
runtime.DecodeList(template.Objects, kapi.Codecs.UniversalDecoder())
175177

178+
// For each object, we attempt the following to maximize our ability to persist the desired objects, while minimizing etcd write thrashing:
179+
// 1. Create the object (no-ops if the object already exists)
180+
// 2. If the object already exists, attempt to update the object (no-ops if an identical object is already persisted)
181+
// 3. If we encounter any error updating, delete and recreate
182+
errs := []error{}
176183
for _, item := range template.Objects {
177184
switch t := item.(type) {
178185
case *authorizationapi.Role:
179186
ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace)
180187
if change {
181-
roleStorage.Delete(ctx, t.Name, nil)
182-
if _, err := roleStorage.CreateRoleWithEscalation(ctx, t); err != nil {
183-
return err
188+
// Attempt to create
189+
_, err := roleStorage.CreateRoleWithEscalation(ctx, t)
190+
// Unconditional replace if it already exists
191+
if kapierrors.IsAlreadyExists(err) {
192+
_, _, err = roleStorage.UpdateRoleWithEscalation(ctx, t)
193+
}
194+
// Delete and recreate as a last resort
195+
if err != nil {
196+
roleStorage.Delete(ctx, t.Name, nil)
197+
_, err = roleStorage.CreateRoleWithEscalation(ctx, t)
198+
}
199+
// Gather any error
200+
if err != nil {
201+
errs = append(errs, err)
184202
}
185203
} else {
186204
fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name)
@@ -191,9 +209,20 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB
191209
case *authorizationapi.RoleBinding:
192210
ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace)
193211
if change {
194-
roleBindingStorage.Delete(ctx, t.Name, nil)
195-
if _, err := roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t); err != nil {
196-
return err
212+
// Attempt to create
213+
_, err := roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t)
214+
// Unconditional replace if it already exists
215+
if kapierrors.IsAlreadyExists(err) {
216+
_, _, err = roleBindingStorage.UpdateRoleBindingWithEscalation(ctx, t)
217+
}
218+
// Delete and recreate as a last resort
219+
if err != nil {
220+
roleBindingStorage.Delete(ctx, t.Name, nil)
221+
_, err = roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t)
222+
}
223+
// Gather any error
224+
if err != nil {
225+
errs = append(errs, err)
197226
}
198227
} else {
199228
fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name)
@@ -205,9 +234,20 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB
205234
case *authorizationapi.ClusterRole:
206235
ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace)
207236
if change {
208-
clusterRoleStorage.Delete(ctx, t.Name, nil)
209-
if _, err := clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t); err != nil {
210-
return err
237+
// Attempt to create
238+
_, err := clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t)
239+
// Unconditional replace if it already exists
240+
if kapierrors.IsAlreadyExists(err) {
241+
_, _, err = clusterRoleStorage.UpdateClusterRoleWithEscalation(ctx, t)
242+
}
243+
// Delete and recreate as a last resort
244+
if err != nil {
245+
clusterRoleStorage.Delete(ctx, t.Name, nil)
246+
_, err = clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t)
247+
}
248+
// Gather any error
249+
if err != nil {
250+
errs = append(errs, err)
211251
}
212252
} else {
213253
fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name)
@@ -218,9 +258,20 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB
218258
case *authorizationapi.ClusterRoleBinding:
219259
ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace)
220260
if change {
221-
clusterRoleBindingStorage.Delete(ctx, t.Name, nil)
222-
if _, err := clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t); err != nil {
223-
return err
261+
// Attempt to create
262+
_, err := clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t)
263+
// Unconditional replace if it already exists
264+
if kapierrors.IsAlreadyExists(err) {
265+
_, _, err = clusterRoleBindingStorage.UpdateClusterRoleBindingWithEscalation(ctx, t)
266+
}
267+
// Delete and recreate as a last resort
268+
if err != nil {
269+
clusterRoleBindingStorage.Delete(ctx, t.Name, nil)
270+
_, err = clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t)
271+
}
272+
// Gather any error
273+
if err != nil {
274+
errs = append(errs, err)
224275
}
225276
} else {
226277
fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name)
@@ -230,13 +281,13 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB
230281
}
231282

232283
default:
233-
return fmt.Errorf("only roles and rolebindings may be created in this mode, not: %v", reflect.TypeOf(t))
284+
errs = append(errs, fmt.Errorf("only roles and rolebindings may be created in this mode, not: %v", reflect.TypeOf(t)))
234285
}
235286
}
236287
if !change {
237288
fmt.Fprintf(out, "To make the changes described above, pass --force\n")
238289
}
239-
return nil
290+
return kerrors.NewAggregate(errs)
240291
})
241292
}
242293

0 commit comments

Comments
 (0)