k8s1.11命令⾏——实现源码导读之kubectlget获取资源对象
这⼀讲我们来看kubectl get获取资源对象命令,它的实现在NewCmdGet⽅法中
1. 获取GetOptions中保存的命令⾏输⼊的kubectl get 后⾯跟的参数(如--all-namespace,--chunk-size,--output等)
2. 构建cmd get命令,注册get命令的实现⽅法
3. 给get命令添加相应的参数来控制get命令的操作
func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewGetOptions(parent, streams)
//构建cmd get命令
cmd := &cobra.Command{
Use: "get [(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-t
emplate-file=...|jsonpath=...|jsonpath-file=...] (TYPE[.VER  DisableFlagsInUseLine: true,
Short:  i18n.T("Display one or many resources"),
Long:    getLong + "\n\n" + cmdutil.SuggestApiResources(parent),
Example: getExample,
//代码运⾏部分
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd))
//get请求具体实现⽅法
cmdutil.CheckErr(o.Run(f, cmd, args))
},
SuggestFor: []string{"list", "ps"},
}
o.PrintFlags.AddFlags(cmd)
//参数flag提供修饰符来控制动作命令的操作,即给命令添加参数,这些参数都保存在GetOptions中
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to request from the server.  Uses the transport specified by the kubeconfig file.")
cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no obje  cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")
cmd.Flags().Int64Var(&o.ChunkSize, "chunk-size", o.ChunkSize, "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may  cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.") cmd.Flags().StringVarP(&o.LabelSelector,
"selector", "l", o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=v  cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=val  cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in curr  cmdutil.AddIncludeUninitializedFlag(cmd)
addOpenAPIPrintColumnFlags(cmd, o)
addServerPrintColumnFlags(cmd, o)
cmd.Flags().BoolVar(&o.Export, "export", o.Export, "If true, use 'export' for the resources.  Exported resources are stripped of cluster-specific information.")
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to get from a server.")
return cmd
}
下⾯来看Get命令具体的实现函数Run,Run函数中最关键的⼀步是Build-Visitor机制的实现。什么是Build-Visitor机制:
Builder(建造者模式):建造者模式将部件和其组装过程分开,⼀步⼀步创建⼀个复杂的对象。⽤户只需要指定复杂对象的类型就可以得
到该对象,⽽⽆须知道其内部的具体构造细节。
Visitor(访问者模式):把结构和数据分开,编写⼀个访问者,去访问数据结构中的元素,然后把对各元素的处理全部交给访问者类。这
样,当需要增加新的处理时候,只需要编写新的 访问者类,让数据结构可以接受访问者的访问即可。可以理解成⼀个抽象类,不同⼦类均
继承这⼀抽象类,实现各⾃的访问逻辑(访问者类),然后通过统⼀的接⼝来进⾏对数据结构的访问。
下⾯来看具体的实现代码:
r := f.NewBuilder().
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
LabelSelectorParam(o.LabelSelector).
FieldSelectorParam(o.FieldSelector).
ExportParam(o.Export).
RequestChunksOf(o.ChunkSize).
IncludeUninitialized(o.IncludeUninitialized).
ResourceTypeOrNameArgs(true, ).
ContinueOnError().
Latest().
Flatten().
TransformRequests(func(req *rest.Request) {
// We need full objects if printing with openapi columns
if o.PrintWithOpenAPICols {
return
}
if o.ServerPrint && o.IsHumanReadablePrinter && !o.Sort {
group := metav1beta1.GroupName
version := metav1beta1.SchemeGroupVersion.Version
tableParam := fmt.Sprintf("application/json;as=Table;v=%s;g=%s, application/json", version, group)
req.SetHeader("Accept", tableParam)
}
}).
Do()
可以看到,这是⼀个⼀连串的链式函数,都指向了Builder指针,下⾯逐⼀分析各个函数的功能
免费平台源码资源网NewBuilder返回⼀个Builder对象,该对象有助于从磁盘和服务器加载对象,并实现CLI与通⽤资源交互的通⽤模式。
Unstructured更新构建器,以便它将请求和发送⾮结构化对象。 ⾮结构化对象基于对象的JSON结构以map格式保留服务器发送的所有字段,这意味着当客户端读取然后写⼊对象时不会丢失任何数据。
NamespaceParam,DefaultNamespace,AllNamespaces共同确定了资源对象的命名空间。
FilenameParam将输⼊分为两类:URL和⽂件(⽂件,⽬录,STDIN),分别构建FileVisitor或StreamVisitor,底层均为
StreamVisitor,添加到Builder.path数组中
LabelSelectorParam定义了⼀个应该应⽤于要加载的对象类型的选择器。这不会影响从磁盘或URL加载的⽂件。 如果参数为空,则⽆操作
FieldSelectorParam功能同上
ExportParam接收命令⾏指定的--export
RequestChunksOf接收命令⾏指定的--chunk-size
IncludeUninitialized接受这些资源的include-uninitialized布尔值
ResourceTypeOrNameArgs解析传⼊的资源类型/名称参数
其中调⽤的NormalizeMultipleResourcesArgs将传⼊的多个资源转换为资源元组,a,b,c,d作为转换为a / d  ,b / d , c / d,例如get node node1 node2 变成 node/node1,node/node2
splitResourceTypeName对resource/name进⾏拆分,分别赋值给resource,name,并以resourceTuple{Resource: resource, Name: name}的形式返回,存储到Builder的resourceTuples中
ContinueOnError将尝试加载和访问尽可能多的对象,即使某些访问返回错误或某些对象⽆法加载。
Latest将获取从服务器的URL或⽂件加载的任何对象的最新副本。
Flatten将任何具有名为“Items”的字段的对象转换为单独的条⽬,并为其提供各⾃的项⽬,这些字段是runtime.Object兼容类型的数组。
TransformRequests更改由此Builder发起的客户端进⾏的API调⽤请求。 传递⼀个空列表以清除修饰符。
Do返回⼀个Result对象,其中包含⼀个Visitor,⽤于访问被Builder标识的资源。
这⾥要重点关注⼀下Do函数:
1.构建Visitor
如果b.path不为空(在FilenameParam中创建),则通过path来创建Visitor 如果labelselector或fieldselector不为空,则根据selector来创建Visitor 如果resourceTuples不为空,则根据资源类型和名字来创建Visitor
如果names不为空,则根据name来创建Visitor
2.注册从ApiServer获取资源对象的⽅法
构建helper,通过回调函数VisitorFunc实现了Visitor接⼝
注册从ApiServer获取资源对象的⽅法RetrieveLazy
注册从返回数据中提取资源信息发⽅法NewDecoratedVisitor
3.将结果以result变量返回,result结构体如下:
type Result struct {
err    error
//访问资源对象的Visitor
visitor Visitor
sources            []Visitor
singleItemImplied  bool
targetsSingleItems bool
mapper      *mapper
ignoreErrors []utilerrors.Matcher
// populated by a call to Infos
// info结构体中保存了从ApiServer中获取到的资源对象
info []*Info
}
func (b *Builder) Do() *Result {
r := b.visitorResult()//构建Visitor
r.mapper = b.Mapper()
!= nil {
return r
}
if b.flatten {
r.visitor = NewFlattenListVisitor(r.visitor, b.objectTyper, b.mapper)
}
//helpers实现了Visitor接⼝
helpers := []VisitorFunc{}
//注册获取数据前的动作
if b.defaultNamespace {
helpers = append(helpers, SetNamespace(b.namespace))
}
quireNamespace {
helpers = append(helpers, RequireNamespace(b.namespace))
}
helpers = append(helpers, FilterNamespace)
quireObject {
//注册从Apiserver获取数据的⽅法
//RetrieveLazy最终也是调⽤中的API
helpers = append(helpers, RetrieveLazy)
}
//注册从返回数据中提取信息的⽅法
r.visitor = NewDecoratedVisitor(r.visitor, )
inueOnError {
r.visitor = ContinueOnErrorVisitor{r.visitor}
}
return r
}
最后,将我们获取到的资源对象打印出来即可,打印的具体实现⽅式这⾥不再细讲。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。