简单总结
kubectl侧根据开启了server print则添加table header信息
apiserver侧如果存在as table header则转换resp为table(以pod为例,格式和信息由printPod构建)
kubectl侧
如果开启了server print则添加table header信息
func NewCmdGet(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
...
构建命令
cmd := &cobra.Command{
...
Run: func(cmd *cobra.Command, args []string) {
...
运行
cmdutil.CheckErr(o.Run(f, args))
},
...
}
...
添加server print column flag
addServerPrintColumnFlags(cmd, o)
...
}
添加server print column flag
func addServerPrintColumnFlags(cmd *cobra.Command, opt *GetOptions) {
cmd.Flags().BoolVar(&opt.ServerPrint, useServerPrintColumns, opt.ServerPrint, "If true, have the server return the appropriate table output. Supports extension APIs and CRDs.")
}
const (
useServerPrintColumns = "server-print"
)
获取get options
func NewGetOptions(parent string, streams genericiooptions.IOStreams) *GetOptions {
return &GetOptions{
...
ServerPrint: true,
}
}
func (o *GetOptions) Run(f cmdutil.Factory, args []string) error {
...
r := f.NewBuilder().
...
TransformRequests(o.transformRequests).
Do()
...
}
转换http request
func (o *GetOptions) transformRequests(req *rest.Request) {
if !o.ServerPrint || !o.IsHumanReadablePrinter {
return
}
如果开启了server print则添加table header信息
req.SetHeader("Accept", strings.Join([]string{
fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1.SchemeGroupVersion.Version, metav1.GroupName),
fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName),
"application/json",
}, ","))
// if sorting, ensure we receive the full object in order to introspect its fields via jsonpath
if len(o.SortBy) > 0 {
req.Param("includeObject", "Object")
}
}
apiserver 侧
如果存在as table header则转换resp为table
staging/src/k8s.io/apiserver/pkg/endpoints/installer.go中
注册resource handler
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, *storageversion.ResourceInfo, error) {
...
注册get handler
switch action.Verb {
case "GET": // Get a resource.
var handler restful.RouteFunction
if isGetterWithOptions {
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource)
} else {
handler = restfulGetResource(getter, reqScope)
}
...
}
rest get resource handler
func restfulGetResource(r rest.Getter, scope handlers.RequestScope) restful.RouteFunction {
return func(req *restful.Request, res *restful.Response) {
handlers.GetResource(r, &scope)(res.ResponseWriter, req.Request)
}
}
staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go中
对外提供 get resource handler
func GetResource(r rest.Getter, scope *RequestScope) http.HandlerFunc {
return getResourceHandler(scope,
func(ctx context.Context, name string, req *http.Request) (runtime.Object, error) {
...
get resource
return r.Get(ctx, name, opts)
})
}
get resource handler
func getResourceHandler(scope *RequestScope, getter getterFunc) http.HandlerFunc {
...
转换resp object为各种格式
transformResponseObject(ctx, scope, req, w, http.StatusOK, outputMediaType, result)
...
}
转换resp object为各种格式
func transformResponseObject(ctx context.Context, scope *RequestScope, req *http.Request, w http.ResponseWriter, statusCode int, mediaType negotiation.MediaTypeOptions, result runtime.Object) {
do := func() {
obj, err = doTransformObject(ctx, result, options, mediaType.Convert, scope)
}
endpointsrequest.TrackTransformResponseObjectLatency(ctx, do)
}
转换resp object为各种格式
func doTransformObject(ctx context.Context, obj runtime.Object, opts interface{}, target *schema.GroupVersionKind, scope *RequestScope) (runtime.Object, error) {
...
case target.Kind == "Table":
...
return asTable(ctx, obj, options, scope, target.GroupVersion())
...
}
转换为table
func asTable(ctx context.Context, result runtime.Object, opts *metav1.TableOptions, scope *RequestScope, groupVersion schema.GroupVersion) (runtime.Object, error) {
...
obj, err := scope.TableConvertor.ConvertToTable(ctx, result, opts)
...
table := (*metav1.Table)(obj)
}
pkg/registry/core/rest/storage_core.go中
构建rest storage
func (p *legacyProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, error) {
...
构建pod rest storage
podStorage, err := podstore.NewStorage(
restOptionsGetter,
nodeStorage.KubeletConnectionInfo,
p.Proxy.Transport,
podDisruptionClient,
)
...
添加rest storage
if resource := "pods"; apiResourceConfigSource.ResourceEnabled(corev1.SchemeGroupVersion.WithResource(resource)) {
添加pod rest storage
storage[resource] = podStorage.Pod
...
}
...
}
构建pod rest storage
func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGetter, proxyTransport http.RoundTripper, podDisruptionBudgetClient policyclient.PodDisruptionBudgetsGetter) (PodStorage, error) {
...
构建rest storage
store := &genericregistry.Store{
...
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
}
...
构建pod rest storage
return PodStorage{
Pod: &REST{store, proxyTransport},
...
}, nil
}
pkg/printers/internalversion/printers.go
printer 处理方法
func AddHandlers(h printers.PrintHandler) {
...
h.TableHandler(podColumnDefinitions, printPod)
...
}
pod printer
func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
...
return []metav1.TableRow{row}, nil
}









网友评论