Info

什么是Info

之前我们说过,Visitor可以生成Info或处理Info。那么到底什么是Info呢?Info定义在/pkg/kubectl/resource/visitor.go中,与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
26
// Info contains temporary info to execute a REST call, or show the results
// of an already completed REST call.
//***Info用来存储REST的返回结果***//
type Info struct {
Client RESTClient
Mapping *meta.RESTMapping
Namespace string
Name string
// Optional, Source is the filename or URL to template file (.json or .yaml),
// or stdin to use to handle the resource
Source string
// Optional, this is the provided object in a versioned type before defaulting
// and conversions into its corresponding internal type. This is useful for
// reflecting on user intent which may be lost after defaulting and conversions.
VersionedObject interface{}
// Optional, this is the most recent value returned by the server if available
runtime.Object
// Optional, this is the most recent resource version the server knows about for
// this type of resource. It may not match the resource version of the object,
// but if set it should be equal to or newer than the resource version of the
// object (however the server defines resource version).
ResourceVersion string
// Optional, should this resource be exported, stripped of cluster-specific and instance specific fields
Export bool
}

可以看出,Info包含了REST请求需要的信息及REST的返回结果runtime.Object。

Visit()

由于Info也实现了Visit(),所以Info也可以称得上是一个Visitor。Info的Visit()方法比较简单,仅仅调用VisitorFunc,参数为自身及nil。

1
2
3
func (i *Info) Visit(fn VisitorFunc) error {
return fn(i, nil)
}

Get()

Get()调用Helper依据Info中的信息获取obj,并更新到Info的Object字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Get retrieves the object from the Namespace and Name fields
func (i *Info) Get() (err error) {
//***NewHelper的用法***//
obj, err := NewHelper(i.Client, i.Mapping).Get(i.Namespace, i.Name, i.Export)
if err != nil {
if errors.IsNotFound(err) && len(i.Namespace) > 0 && i.Namespace != api.NamespaceDefault && i.Namespace != api.NamespaceAll {
err2 := i.Client.Get().AbsPath("api", "v1", "namespaces", i.Namespace).Do().Error()
if err2 != nil && errors.IsNotFound(err2) {
return err2
}
}
return err
}
//***更新i.Object和i.ResourceVersion***//
i.Object = obj
i.ResourceVersion, _ = i.Mapping.MetadataAccessor.ResourceVersion(obj)
return nil
}

Refresh()

Refresh()把已经存在的obj更新到Info的Object。

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
//***把一个object更新到info中***//
func (i *Info) Refresh(obj runtime.Object, ignoreError bool) error {
name, err := i.Mapping.MetadataAccessor.Name(obj)
if err != nil {
if !ignoreError {
return err
}
} else {
i.Name = name
}
namespace, err := i.Mapping.MetadataAccessor.Namespace(obj)
if err != nil {
if !ignoreError {
return err
}
} else {
i.Namespace = namespace
}
version, err := i.Mapping.MetadataAccessor.ResourceVersion(obj)
if err != nil {
if !ignoreError {
return err
}
} else {
i.ResourceVersion = version
}
i.Object = obj
return nil
}

Result

什么是Result

之前我们提过,Builder的Do()可以返回Result。现在让我们来看看Result的定义,Result定义在/pkg/kubectl/resource/result.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Result contains helper methods for dealing with the outcome of a Builder.
type Result struct {
err error
visitor Visitor
sources []Visitor
singular bool
ignoreErrors []utilerrors.Matcher
// populated by a call to Infos
info []*Info
}

可以看到,Result也包含一个visitor,及一个info表示[]*Info,所以Result提供了Infos()方法来获取Visitor的结果Info数组及Object()方法来获取Visitor的结果Obj(可能为List)。

Infos()

Info()调用层层封装的visitor,然后收集所有info并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func (r *Result) Infos() ([]*Info, error) {
if r.err != nil {
return nil, r.err
}
if r.info != nil {
return r.info, nil
}
infos := []*Info{}
//***此处可以领略匿名函数的魅力***//
err := r.visitor.Visit(func(info *Info, err error) error {
if err != nil {
return err
}
infos = append(infos, info)
return nil
})
err = utilerrors.FilterOut(err, r.ignoreErrors...)
r.info, r.err = infos, err
return infos, err
}

Object()

Object()先调用Infos()来获取infos,然后从每个info中提取出Object组成ObjectList返回。

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
func (r *Result) Object() (runtime.Object, error) {
infos, err := r.Infos()
if err != nil {
return nil, err
}
versions := sets.String{}
objects := []runtime.Object{}
for _, info := range infos {
if info.Object != nil {
objects = append(objects, info.Object)
versions.Insert(info.ResourceVersion)
}
}
if len(objects) == 1 {
if r.singular {
return objects[0], nil
}
// if the item is a list already, don't create another list
if meta.IsListType(objects[0]) {
return objects[0], nil
}
}
version := ""
if len(versions) == 1 {
version = versions.List()[0]
}
return &api.List{
ListMeta: unversioned.ListMeta{
ResourceVersion: version,
},
Items: objects,
}, err
}

Helper

什么是Helper

在Kubernetes中,Helper一般都提供类似驱动的功能。Kubectl的helper就是用来访问Client的驱动。一般来说,某个visitFunc函数中会调用Helper的相关成员函数来完成具体请求。

Helper定义在/pkg/kubectl/resource/helper.go中:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Helper provides methods for retrieving or mutating a RESTful
// resource.
type Helper struct {
// The name of this resource as the server would recognize it
Resource string
// A RESTClient capable of mutating this resource.
RESTClient RESTClient
// An interface for reading or writing the resource version of this
// type.
Versioner runtime.ResourceVersioner
// True if the resource type is scoped to namespaces
NamespaceScoped bool
}

Helper实现了Get(), List(), Watch(), WatchSingle(), Delete(), Create(), Patch(), Replace()等方法,这些方法是对RESTClient的封装,所以待以后分析了RESTClient之后,这些方法的实现就很容易明白,这里就不展开了。