mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-14 13:45:06 +00:00
Merge pull request #8237 from smarterclayton/continue_on_error
Make ContinueOnError actually work
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