| ... | ... |
@@ -711,7 +711,7 @@ func RunCmdRouter(f *clientcmd.Factory, cmd *cobra.Command, out, errout io.Write |
| 711 | 711 |
objects = append(objects, |
| 712 | 712 |
&kapi.ServiceAccount{ObjectMeta: kapi.ObjectMeta{Name: cfg.ServiceAccount}},
|
| 713 | 713 |
&authapi.ClusterRoleBinding{
|
| 714 |
- ObjectMeta: kapi.ObjectMeta{Name: fmt.Sprintf("router-%s-role", cfg.Name)},
|
|
| 714 |
+ ObjectMeta: kapi.ObjectMeta{Name: generateRoleBindingName(cfg.Name)},
|
|
| 715 | 715 |
Subjects: []kapi.ObjectReference{
|
| 716 | 716 |
{
|
| 717 | 717 |
Kind: "ServiceAccount", |
| ... | ... |
@@ -789,12 +789,49 @@ func RunCmdRouter(f *clientcmd.Factory, cmd *cobra.Command, out, errout io.Write |
| 789 | 789 |
return defaultOutputErr |
| 790 | 790 |
} |
| 791 | 791 |
|
| 792 |
- if errs := cfg.Action.WithMessage(fmt.Sprintf("Creating router %s", cfg.Name), "created").Run(list, namespace); len(errs) > 0 {
|
|
| 792 |
+ levelPrefixFilter := func(e error) string {
|
|
| 793 |
+ // only ignore SA/RB errors if we were creating the service account |
|
| 794 |
+ if createServiceAccount && ignoreError(e, cfg.ServiceAccount, generateRoleBindingName(cfg.Name)) {
|
|
| 795 |
+ return "warning" |
|
| 796 |
+ } |
|
| 797 |
+ return "error" |
|
| 798 |
+ } |
|
| 799 |
+ |
|
| 800 |
+ cfg.Action.Bulk.IgnoreError = func(e error) bool {
|
|
| 801 |
+ return levelPrefixFilter(e) == "warning" |
|
| 802 |
+ } |
|
| 803 |
+ |
|
| 804 |
+ if errs := cfg.Action.WithMessageAndPrefix(fmt.Sprintf("Creating router %s", cfg.Name), "created", levelPrefixFilter).Run(list, namespace); len(errs) > 0 {
|
|
| 793 | 805 |
return cmdutil.ErrExit |
| 794 | 806 |
} |
| 795 | 807 |
return nil |
| 796 | 808 |
} |
| 797 | 809 |
|
| 810 |
+// ignoreError will return true if the error is an already exists status error and |
|
| 811 |
+// 1. it is for a cluster role binding named roleBindingName |
|
| 812 |
+// 2. it is for a serivce account name saName |
|
| 813 |
+func ignoreError(e error, saName string, roleBindingName string) bool {
|
|
| 814 |
+ if !errors.IsAlreadyExists(e) {
|
|
| 815 |
+ return false |
|
| 816 |
+ } |
|
| 817 |
+ statusError, ok := e.(*errors.StatusError) |
|
| 818 |
+ if !ok {
|
|
| 819 |
+ return false |
|
| 820 |
+ } |
|
| 821 |
+ details := statusError.Status().Details |
|
| 822 |
+ if details == nil {
|
|
| 823 |
+ return false |
|
| 824 |
+ } |
|
| 825 |
+ return (details.Kind == "serviceaccounts" && details.Name == saName) || |
|
| 826 |
+ (details.Kind == "clusterrolebinding" && details.Name == roleBindingName) |
|
| 827 |
+} |
|
| 828 |
+ |
|
| 829 |
+// generateRoleBindingName generates a name for the rolebinding object if it is |
|
| 830 |
+// being created. |
|
| 831 |
+func generateRoleBindingName(name string) string {
|
|
| 832 |
+ return fmt.Sprintf("router-%s-role", name)
|
|
| 833 |
+} |
|
| 834 |
+ |
|
| 798 | 835 |
// generateStatsPassword creates a random password. |
| 799 | 836 |
func generateStatsPassword() string {
|
| 800 | 837 |
allowableChars := []rune("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
|
| ... | ... |
@@ -35,13 +35,21 @@ type Mapper interface {
|
| 35 | 35 |
InfoForObject(obj runtime.Object, preferredGVKs []unversioned.GroupVersionKind) (*resource.Info, error) |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
+// IgnoreErrorFunc provides a way to filter errors during the Bulk.Run. If this function returns |
|
| 39 |
+// true the error will NOT be added to the slice of errors returned by Bulk.Run. |
|
| 40 |
+// |
|
| 41 |
+// This may be used in conjunction with |
|
| 42 |
+// BulkAction.WithMessageAndPrefix if you are reporting some errors as warnings. |
|
| 43 |
+type IgnoreErrorFunc func(e error) bool |
|
| 44 |
+ |
|
| 38 | 45 |
// Bulk provides helpers for iterating over a list of items |
| 39 | 46 |
type Bulk struct {
|
| 40 | 47 |
Mapper Mapper |
| 41 | 48 |
|
| 42 |
- Op OpFunc |
|
| 43 |
- After AfterFunc |
|
| 44 |
- Retry RetryFunc |
|
| 49 |
+ Op OpFunc |
|
| 50 |
+ After AfterFunc |
|
| 51 |
+ Retry RetryFunc |
|
| 52 |
+ IgnoreError IgnoreErrorFunc |
|
| 45 | 53 |
} |
| 46 | 54 |
|
| 47 | 55 |
// Create attempts to create each item generically, gathering all errors in the |
| ... | ... |
@@ -52,6 +60,10 @@ func (b *Bulk) Run(list *kapi.List, namespace string) []error {
|
| 52 | 52 |
if after == nil {
|
| 53 | 53 |
after = func(*resource.Info, error) bool { return false }
|
| 54 | 54 |
} |
| 55 |
+ ignoreError := b.IgnoreError |
|
| 56 |
+ if ignoreError == nil {
|
|
| 57 |
+ ignoreError = func(e error) bool { return false }
|
|
| 58 |
+ } |
|
| 55 | 59 |
|
| 56 | 60 |
errs := []error{}
|
| 57 | 61 |
for i, item := range list.Items {
|
| ... | ... |
@@ -70,7 +82,9 @@ func (b *Bulk) Run(list *kapi.List, namespace string) []error {
|
| 70 | 70 |
} |
| 71 | 71 |
} |
| 72 | 72 |
if err != nil {
|
| 73 |
- errs = append(errs, err) |
|
| 73 |
+ if !ignoreError(err) {
|
|
| 74 |
+ errs = append(errs, err) |
|
| 75 |
+ } |
|
| 74 | 76 |
if after(info, err) {
|
| 75 | 77 |
break |
| 76 | 78 |
} |
| ... | ... |
@@ -85,22 +99,22 @@ func (b *Bulk) Run(list *kapi.List, namespace string) []error {
|
| 85 | 85 |
return errs |
| 86 | 86 |
} |
| 87 | 87 |
|
| 88 |
-func NewPrintNameOrErrorAfterIndent(mapper meta.RESTMapper, short bool, operation string, out, errs io.Writer, dryRun bool, indent string) AfterFunc {
|
|
| 88 |
+func NewPrintNameOrErrorAfterIndent(mapper meta.RESTMapper, short bool, operation string, out, errs io.Writer, dryRun bool, indent string, prefixForError PrefixForError) AfterFunc {
|
|
| 89 | 89 |
return func(info *resource.Info, err error) bool {
|
| 90 | 90 |
if err == nil {
|
| 91 | 91 |
fmt.Fprintf(out, indent) |
| 92 | 92 |
cmdutil.PrintSuccess(mapper, short, out, info.Mapping.Resource, info.Name, dryRun, operation) |
| 93 | 93 |
} else {
|
| 94 |
- fmt.Fprintf(errs, "%serror: %v\n", indent, err) |
|
| 94 |
+ fmt.Fprintf(errs, "%s%s: %v\n", indent, prefixForError(err), err) |
|
| 95 | 95 |
} |
| 96 | 96 |
return false |
| 97 | 97 |
} |
| 98 | 98 |
} |
| 99 | 99 |
|
| 100 |
-func NewPrintErrorAfter(mapper meta.RESTMapper, errs io.Writer) func(*resource.Info, error) bool {
|
|
| 100 |
+func NewPrintErrorAfter(mapper meta.RESTMapper, errs io.Writer, prefixForError PrefixForError) func(*resource.Info, error) bool {
|
|
| 101 | 101 |
return func(info *resource.Info, err error) bool {
|
| 102 | 102 |
if err != nil {
|
| 103 |
- fmt.Fprintf(errs, "error: %v\n", err) |
|
| 103 |
+ fmt.Fprintf(errs, "%s: %v\n", prefixForError(err), err) |
|
| 104 | 104 |
} |
| 105 | 105 |
return false |
| 106 | 106 |
} |
| ... | ... |
@@ -186,17 +200,20 @@ func (b *BulkAction) DefaultIndent() string {
|
| 186 | 186 |
return "" |
| 187 | 187 |
} |
| 188 | 188 |
|
| 189 |
-func (b BulkAction) WithMessage(action, individual string) Runner {
|
|
| 189 |
+// PrefixForError allows customization of the prefix that will be printed for any error that occurs in the BulkAction. |
|
| 190 |
+type PrefixForError func(e error) string |
|
| 191 |
+ |
|
| 192 |
+func (b BulkAction) WithMessageAndPrefix(action, individual string, prefixForError PrefixForError) Runner {
|
|
| 190 | 193 |
b.Action = action |
| 191 | 194 |
switch {
|
| 192 | 195 |
// TODO: this should be b printer |
| 193 | 196 |
case b.Output == "": |
| 194 |
- b.Bulk.After = NewPrintNameOrErrorAfterIndent(b.Bulk.Mapper, false, individual, b.Out, b.ErrOut, b.DryRun, b.DefaultIndent()) |
|
| 197 |
+ b.Bulk.After = NewPrintNameOrErrorAfterIndent(b.Bulk.Mapper, false, individual, b.Out, b.ErrOut, b.DryRun, b.DefaultIndent(), prefixForError) |
|
| 195 | 198 |
// TODO: needs to be unified with the name printer (incremental vs exact execution), possibly by creating b synthetic printer? |
| 196 | 199 |
case b.Output == "name": |
| 197 |
- b.Bulk.After = NewPrintNameOrErrorAfterIndent(b.Bulk.Mapper, true, individual, b.Out, b.ErrOut, b.DryRun, b.DefaultIndent()) |
|
| 200 |
+ b.Bulk.After = NewPrintNameOrErrorAfterIndent(b.Bulk.Mapper, true, individual, b.Out, b.ErrOut, b.DryRun, b.DefaultIndent(), prefixForError) |
|
| 198 | 201 |
default: |
| 199 |
- b.Bulk.After = NewPrintErrorAfter(b.Bulk.Mapper, b.ErrOut) |
|
| 202 |
+ b.Bulk.After = NewPrintErrorAfter(b.Bulk.Mapper, b.ErrOut, prefixForError) |
|
| 200 | 203 |
if b.StopOnError {
|
| 201 | 204 |
b.Bulk.After = HaltOnError(b.Bulk.After) |
| 202 | 205 |
} |
| ... | ... |
@@ -204,6 +221,10 @@ func (b BulkAction) WithMessage(action, individual string) Runner {
|
| 204 | 204 |
return &b |
| 205 | 205 |
} |
| 206 | 206 |
|
| 207 |
+func (b BulkAction) WithMessage(action, individual string) Runner {
|
|
| 208 |
+ return b.WithMessageAndPrefix(action, individual, func(e error) string { return "error" })
|
|
| 209 |
+} |
|
| 210 |
+ |
|
| 207 | 211 |
func (b *BulkAction) Run(list *kapi.List, namespace string) []error {
|
| 208 | 212 |
run := b.Bulk |
| 209 | 213 |
|