k8s APIServer源码: api注册详细细节
k8s APIServer源码: api注册详细细节
基于版本 1.6.7
前面介绍了, api注册过程
问题: go-restful github的route
中, handler
和path
是如何绑定在一起的? handler
在哪里定义的?
以/api
为例
前面介绍到/api
和/apis
分别注册加入到Container
, 而最终, 二者调用installer.Install(ws)
. 这一步, 我们需要进一步了解细节.
webservice.add(route)
问题: 构建Route加入到WebService在哪里处理的?
- vendor/k8s.io/apiserver/pkg/endpoints/installer.go
func (a *APIInstaller) Install(ws *restful.WebService) (apiResources []metav1.APIResource, errors []error) {
// Register the paths in a deterministic (sorted) order to get a deterministic swagger spec.
paths := make([]string, len(a.group.Storage))
var i int = 0
for path := range a.group.Storage {
paths[i] = path
i++
}
sort.Strings(paths)
for _, path := range paths {
apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler)
}
}
- apiserver/pkg/endpoints/installer.go
仅摘录部分核心代码, 这里, 获取handler
之后, 构建route
, 然后加入到webservice
中
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) (*metav1.APIResource, error) {
...
creater, isCreater := storage.(rest.Creater)
....
actions = appendIf(actions, action{"POST", resourcePath, resourceParams, namer, false}, isCreater)
case "POST":
// 获取handler
handler = handlers.CreateResource(creater, reqScope, a.group.Typer, admit) // => next
// 构建route, action.Path -> handler
route := ws.POST(action.Path).To(handler).
Doc(doc).
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
Operation("create"+namespaced+kind+strings.Title(subresource)+operationSuffix).
Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...).
Returns(http.StatusOK, "OK", versionedObject).
Reads(versionedObject).
Writes(versionedObject)
addParams(route, action.Params)
// 添加route到webservice
ws.Route(route)
}
create handler
- vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest.go
// CreateResource returns a function that will handle a resource creation.
func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) restful.RouteFunction {
return createHandler(&namedCreaterAdapter{r}, scope, typer, admit, false)
}
func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface, includeName bool) restful.RouteFunction {
return func(req *restful.Request, res *restful.Response) {
original := r.New() // => here
responsewriters.WriteObject(http.StatusCreated, scope.Kind.GroupVersion(), scope.Serializer, result, w, req.Request)
}
}
即, 最终handler
执行时, 调用的是rest.Creater.New()
这里的 Creater
是一个interface
# vendor/k8s.io/apiserver/pkg/registry/rest/rest.go
// Creater is an object that can create an instance of a RESTful object.
type Creater interface {
// New returns an empty object that can be used with Create after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
// Create creates a new version of a resource.
Create(ctx genericapirequest.Context, obj runtime.Object) (runtime.Object, error)
}
回到最初的问题
最终, handler
调用的是rest.Creater.New()
而creater
声明的位置
- apiserver/pkg/endpoints/installer.go
creater, isCreater := storage.(rest.Creater)
这里, 想要知道handler
最终调用的是哪里定义的方法, 我们需要分析storage
的来源
第一步: 链路分析
调用链
// pkg/master/master.go
// => got: apiGroupInfo 初始化
func (m *Master) InstallLegacyAPI(c *Config, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo)
}
// vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
s.installAPIResources(apiPrefix, apiGroupInfo)
}
// vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
// NOTE => apigroup TO apigroupversion
// => got: apigroupversion
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
apiGroupVersion := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
apiGroupVersion.InstallREST(s.HandlerContainer.Container); }
}
// vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
// => got: APIGroupVersion.Storage = make(map[string]rest.Storage
// APIGroupVersion.Storage[path] = apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version][path]
func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion schema.GroupVersion, apiPrefix string) *genericapi.APIGroupVersion {
storage := make(map[string]rest.Storage)
for k, v := range apiGroupInfo.VersionedResourcesStorageMap[