什么是Visitor
Visitor定义在/pkg/kubectl/resource/visitor.go中。我们先来看visitor的定义:
1 2 3 4 5
| type Visitor interface { Visit(VisitorFunc) error } type VisitorFunc func(*Info, error) error
|
可以看出,只要实现了Visit(VisitorFunc) error方法的结构体都可以称为Visitor,相当简洁。
其中VisitorFunc的参数为*Info及error,所以可以推断,VisitorFunc()可以对Info及Error进行处理。
Visitor最大的特性就是每个Visitor实现了一个特性,然后可以嵌套使用。Visitor可以分为两类,第一类是生成info,第二类是处理info。我们现在先记着info是用来存储REST请求的返回结果的。
产生info的visitor有:FileVisitor, StreamVisitor, URLVisitor, Selector。
处理info的visitor有:VisitorList, EagerVisitorList, DecoratedVisitor, ContinueOnErrorVisitor, FlattenListVisitor, FlattenListVisitor等。此处需要说明下,有些Visitor只处理了Error,但我们仍把它归为处理info的Visitor。
一般来说,如果info已经生成,那么Visitor嵌套中的Visitor只要info处理Visitor即可;如果没有info,则最里面的Visitor要在fn()调用之前生成info,以供其他Visitor处理。
Visitor嵌套原理
先来看一个Visitor的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| type DecoratedVisitor struct { visitor Visitor decorators []VisitorFunc } func (v DecoratedVisitor) Visit(fn VisitorFunc) error { return v.visitor.Visit(func(info *Info, err error) error { if err != nil { return err } for i := range v.decorators { if err := v.decorators[i](info, nil); err != nil { return err } } return fn(info, nil) }) }
|
一般来说,一个Visitor(父Visitor)结构体中包含另一个Visitor(子Visitor)。父Visitor中的Visit()方法会调用子Visitor的Visit()方法,并传入一个匿名的visitorFunc,这个匿名的visitorFunc在子Visitor看来就是fn。
再来看下Visitor如何嵌套使用,下面代码摘自/pkg/kubectl/resource/builder.go中的Do()函数:
1 2 3 4 5
| if b.continueOnError { r.visitor = ContinueOnErrorVisitor{r.visitor} } return r }
|
嵌套也很简单,就是用一个Visitor去封装另一个Visitor。
所以可以仿照代码写个Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package main import ( "fmt" ) type Visitor interface { Visit(VisitorFunc) error } type VisitorFunc func() error type Visitor1 struct { } func (l Visitor1) Visit(fn VisitorFunc) error { fmt.Println("In Visitor1 before fn") fn() fmt.Println("In Visitor1 after fn") return nil } type Visitor2 struct { visitor Visitor } func (l Visitor2) Visit(fn VisitorFunc) error { return l.visitor.Visit(func() error { fmt.Println("In Visitor2 before fn") fn() fmt.Println("In Visitor2 after fn") return nil }) } type Visitor3 struct { visitor Visitor } func (l Visitor3) Visit(fn VisitorFunc) error { return l.visitor.Visit(func() error { fmt.Println("In Visitor3 before fn") fn() fmt.Println("In Visitor3 after fn") return nil }) } func main() { var visitor Visitor = new(Visitor1) visitor = Visitor2{visitor} visitor = Visitor3{visitor} visitor.Visit(func() error { fmt.Println("In visitFunc") return nil }) }
|
Demo中把Visitor定义的visitFunc代码分为”before fn”和”after fn”。来看执行结果:
1 2 3 4 5 6 7
| In Visitor1 before fn In Visitor2 before fn In Visitor3 before fn In visitFunc In Visitor3 after fn In Visitor2 after fn In Visitor1 after fn
|
所以可以看出,virsitor3{visitor2{visitor1}}顺序下,最先执行的是Visitor1中visitFunc的fn()之前的代码,然后是Visitor2和VIsitor3中fn()之前的代码。接着执行visitor3中的visitFunc。最后又按visitor3,visitor2,visitor1的顺序执行fn()后的代码。通俗地讲,外边的Visitor的visitorFunc会嵌入到里边Visitor的fn处。
在Kubectl中,还有类VisitorList的Visitor。我们再来看个更复杂的Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| package main import ( "fmt" ) type Visitor interface { Visit(VisitorFunc) error } type VisitorFunc func() error type VisitorList []Visitor func (l VisitorList) Visit(fn VisitorFunc) error { for i := range l { if err := l[i].Visit(func() error { fmt.Println("In VisitorList before fn") fn() fmt.Println("In VisitorList after fn") return nil }); err != nil { return err } } return nil } type Visitor1 struct { } func (l Visitor1) Visit(fn VisitorFunc) error { fmt.Println("In Visitor1 before fn") fn() fmt.Println("In Visitor1 after fn") return nil } type Visitor2 struct { visitor Visitor } func (l Visitor2) Visit(fn VisitorFunc) error { fmt.Println("In Visitor2 before Visit") l.visitor.Visit(func() error { fmt.Println("In Visitor2 before fn") fn() fmt.Println("In Visitor2 after fn") return nil }) fmt.Println("In Visitor2 before Visit") return nil } type Visitor3 struct { visitor Visitor } func (l Visitor3) Visit(fn VisitorFunc) error { fmt.Println("In Visitor3 before Visit") l.visitor.Visit(func() error { fmt.Println("In Visitor3 before fn") fn() fmt.Println("In Visitor3 after fn") return nil }) fmt.Println("In Visitor3 after Visit") return nil } func main() { var visitor Visitor = new(Visitor1) var visitors []Visitor visitors = append(visitors, visitor) visitors = append(visitors, visitor) visitor = Visitor2{VisitorList(visitors)} visitor = Visitor3{visitor} visitor.Visit(func() error { fmt.Println("In visitFunc") return nil }) }
|
执行结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| In Visitor3 before Visit In Visitor2 before Visit In Visitor1 before fn In VisitorList before fn In Visitor2 before fn In Visitor3 before fn In visitFunc In Visitor3 after fn In Visitor2 after fn In VisitorList after fn In Visitor1 after fn In Visitor1 before fn In VisitorList before fn In Visitor2 before fn In Visitor3 before fn In visitFunc In Visitor3 after fn In Visitor2 after fn In VisitorList after fn In Visitor1 after fn In Visitor2 before Visit In Visitor3 after Visit
|
添加了visitorList后,由于visitorList包含两个visitor1,相当于visitorList外边的Visitor被嵌入到Visitor1中两次,所以,整个打印过程执行了两次,且visitorList中定义的函数内容会在visitor1和visitor2之间执行。
而visitFunc之前的代码的是先执行最外面的Visitor,再执行里面的Visitor;visitFunc之后的代码是先执行最里面的Visitor,再执行外面的Visitor。
VisitorList
VisitorList包含多个visitor,在迭代包含的visitor时,一遇到错误就返回。
1 2 3 4 5 6 7 8 9 10 11
| type VisitorList []Visitor func (l VisitorList) Visit(fn VisitorFunc) error { for i := range l { if err := l[i].Visit(fn); err != nil { return err } } return nil }
|
EagerVisitorList
EagerVisitorList在迭代包含的visitor时,遇到错误会断续迭代,最后一起返回所有错误。
此处可以体会下匿名函数的魅力,所以匿名函数中的err都会被收集到EagerVisitorList的Visit()方法中的errs中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type EagerVisitorList []Visitor func (l EagerVisitorList) Visit(fn VisitorFunc) error { errs := []error(nil) for i := range l { if err := l[i].Visit(func(info *Info, err error) error { if err != nil { errs = append(errs, err) return nil } if err := fn(info, nil); err != nil { errs = append(errs, err) } return nil }); err != nil { errs = append(errs, err) } } return utilerrors.NewAggregate(errs) }
|
URLVisitor
URLVisitor获取指定URL的内容,并对内容进行格式检查,然后把内容转换为info。URL封装了StreamVisitor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type URLVisitor struct { URL *url.URL *StreamVisitor HttpAttemptCount int } func (v *URLVisitor) Visit(fn VisitorFunc) error { body, err := readHttpWithRetries(httpgetImpl, time.Second, v.URL.String(), v.HttpAttemptCount) if err != nil { return err } defer body.Close() v.StreamVisitor.Reader = body return v.StreamVisitor.Visit(fn) }
|
DecoratedVisitor
DecoratedVisitor会调用decorators对info和err进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| type DecoratedVisitor struct { visitor Visitor decorators []VisitorFunc } func NewDecoratedVisitor(v Visitor, fn ...VisitorFunc) Visitor { if len(fn) == 0 { return v } return DecoratedVisitor{v, fn} } func (v DecoratedVisitor) Visit(fn VisitorFunc) error { return v.visitor.Visit(func(info *Info, err error) error { if err != nil { return err } for i := range v.decorators { if err := v.decorators[i](info, nil); err != nil { return err } } return fn(info, nil) }) }
|
ContinueOnErrorVisitor
ContinueOnErrorVisitor会收集子Visitor产生的错误,并返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| type ContinueOnErrorVisitor struct { Visitor } func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error { errs := []error{} err := v.Visitor.Visit(func(info *Info, err error) error { if err != nil { errs = append(errs, err) return nil } if err := fn(info, nil); err != nil { errs = append(errs, err) } return nil }) if err != nil { errs = append(errs, err) } if len(errs) == 1 { return errs[0] } return utilerrors.NewAggregate(errs) }
|
FlattenListVisitor
FlattenListVisitor可以对列表中的每个元素进行处理。如果有错误发生,则返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| type FlattenListVisitor struct { Visitor *Mapper } func NewFlattenListVisitor(v Visitor, mapper *Mapper) Visitor { return FlattenListVisitor{v, mapper} } func (v FlattenListVisitor) Visit(fn VisitorFunc) error { return v.Visitor.Visit(func(info *Info, err error) error { if err != nil { return err } if info.Object == nil { return fn(info, nil) } items, err := meta.ExtractList(info.Object) if err != nil { return fn(info, nil) } if errs := runtime.DecodeList(items, struct { runtime.ObjectTyper runtime.Decoder }{v.Mapper, v.Mapper.Decoder}); len(errs) > 0 { return utilerrors.NewAggregate(errs) } var preferredGVKs []unversioned.GroupVersionKind if info.Mapping != nil && !info.Mapping.GroupVersionKind.Empty() { preferredGVKs = append(preferredGVKs, info.Mapping.GroupVersionKind) } for i := range items { item, err := v.InfoForObject(items[i], preferredGVKs) if err != nil { return err } if len(info.ResourceVersion) != 0 { item.ResourceVersion = info.ResourceVersion } if err := fn(item, nil); err != nil { return err } } return nil }) }
|
FileVisitor
FileVisitor用来访问文件,并生成Info。FileVisitor是对StreamVisitor的封装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| type FileVisitor struct { Path string *StreamVisitor } func (v *FileVisitor) Visit(fn VisitorFunc) error { var f *os.File if v.Path == constSTDINstr { f = os.Stdin } else { var err error if f, err = os.Open(v.Path); err != nil { return err } } defer f.Close() v.StreamVisitor.Reader = f return v.StreamVisitor.Visit(fn) }
|
StreamVisitor
StreamVisitor 从io.reader中获取数据流,然后转换成json格式,最后进行schema检查,封装成info对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| type StreamVisitor struct { io.Reader *Mapper Source string Schema validation.Schema } func NewStreamVisitor(r io.Reader, mapper *Mapper, source string, schema validation.Schema) *StreamVisitor { return &StreamVisitor{ Reader: r, Mapper: mapper, Source: source, Schema: schema, } } func (v *StreamVisitor) Visit(fn VisitorFunc) error { d := yaml.NewYAMLOrJSONDecoder(v.Reader, 4096) for { ext := runtime.RawExtension{} if err := d.Decode(&ext); err != nil { if err == io.EOF { return nil } return err } ext.Raw = bytes.TrimSpace(ext.Raw) if len(ext.Raw) == 0 || bytes.Equal(ext.Raw, []byte("null")) { continue } if err := ValidateSchema(ext.Raw, v.Schema); err != nil { return fmt.Errorf("error validating %q: %v", v.Source, err) } info, err := v.InfoForData(ext.Raw, v.Source) if err != nil { if fnErr := fn(info, err); fnErr != nil { return fnErr } continue } if err := fn(info, nil); err != nil { return err } } }
|
FilteredVisitor
FilteredVisitor可以检查info是否满足某些条件。如果满足条件,则往下执行,否则返回err。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| type FilteredVisitor struct { visitor Visitor filters []FilterFunc } func NewFilteredVisitor(v Visitor, fn ...FilterFunc) Visitor { if len(fn) == 0 { return v } return FilteredVisitor{v, fn} } func (v FilteredVisitor) Visit(fn VisitorFunc) error { return v.visitor.Visit(func(info *Info, err error) error { if err != nil { return err } for _, filter := range v.filters { ok, err := filter(info, nil) if err != nil { return err } if !ok { return nil } } return fn(info, nil) }) }
|