mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-14 05:36:12 +00:00
Make ContinueOnError actually work
In resource.Builder ContinueOnError() should actually do so. Reorganized util.CheckErr() to make it display bulk errors more effectively and be more reusable. Clarified that CheckErr is not specific to kubectl in Godoc. Changed the "Error: " prefix to "error: " to more closely match Unix conventions.
This commit is contained in:
@@ -614,6 +614,9 @@ func (b *Builder) Do() *Result {
|
||||
helpers = append(helpers, RetrieveLazy)
|
||||
}
|
||||
r.visitor = NewDecoratedVisitor(r.visitor, helpers...)
|
||||
if b.continueOnError {
|
||||
r.visitor = ContinueOnErrorVisitor{r.visitor}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ package resource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -606,6 +607,36 @@ func TestMultipleObject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContinueOnErrorVisitor(t *testing.T) {
|
||||
r, _, _ := streamTestData()
|
||||
req := NewBuilder(latest.RESTMapper, api.Scheme, fakeClient()).
|
||||
ContinueOnError().
|
||||
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
||||
Do()
|
||||
count := 0
|
||||
testErr := fmt.Errorf("test error")
|
||||
err := req.Visit(func(_ *Info) error {
|
||||
count++
|
||||
if count > 1 {
|
||||
return testErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if count != 3 {
|
||||
t.Fatalf("did not visit all infos: %d", count)
|
||||
}
|
||||
agg, ok := err.(errors.Aggregate)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(agg.Errors()) != 2 || agg.Errors()[0] != testErr || agg.Errors()[1] != testErr {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSingularObject(t *testing.T) {
|
||||
obj, err := NewBuilder(latest.RESTMapper, api.Scheme, fakeClient()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
|
@@ -350,6 +350,36 @@ func (v DecoratedVisitor) Visit(fn VisitorFunc) error {
|
||||
})
|
||||
}
|
||||
|
||||
// ContinueOnErrorVisitor visits each item and, if an error occurs on
|
||||
// any individual item, returns an aggregate error after all items
|
||||
// are visited.
|
||||
type ContinueOnErrorVisitor struct {
|
||||
Visitor
|
||||
}
|
||||
|
||||
// Visit returns nil if no error occurs during traversal, a regular
|
||||
// error if one occurs, or if multiple errors occur, an aggregate
|
||||
// error. If the provided visitor fails on any individual item it
|
||||
// will not prevent the remaining items from being visited. An error
|
||||
// returned by the visitor directly may still result in some items
|
||||
// not being visited.
|
||||
func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error {
|
||||
errs := []error{}
|
||||
err := v.Visitor.Visit(func(info *Info) error {
|
||||
if err := fn(info); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if len(errs) == 1 {
|
||||
return errs[0]
|
||||
}
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// FlattenListVisitor flattens any objects that runtime.ExtractList recognizes as a list
|
||||
// - has an "Items" public field that is a slice of runtime.Objects or objects satisfying
|
||||
// that interface - into multiple Infos. An error on any sub item (for instance, if a List
|
||||
|
Reference in New Issue
Block a user