国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Kubernetes1.5源碼分析(三) apiServer之go-restful的使用

Doyle / 3361人閱讀

摘要:它包括一組和一個對象,使用進(jìn)行請求派發(fā)。流程基本就是這樣,接著我們直接進(jìn)入接口看實現(xiàn)拼裝然后填充并返回一個對象創(chuàng)建一個這個是關(guān)鍵,會對各種進(jìn)行注冊增加一個的將該加入到前兩個調(diào)用函數(shù)比較簡單,這里不進(jìn)行介紹了。

源碼版本

Kubernetes v1.5.0

go-restful 簡介

go-restful是用于構(gòu)建REST-style web服務(wù)的golang包。
它是出現(xiàn)時因為一個javaer在golang中沒找到順手的REST-based服務(wù)構(gòu)建包,所以就按照他在java里常用的JAX-RS的設(shè)計,在golang中造了一個輪子。

關(guān)鍵組件

1.Route:
路由包含兩種,一種是標(biāo)準(zhǔn)JSR311接口規(guī)范的實現(xiàn)RouterJSR311,一種是快速路由CurlyRouter。
CurlyRouter支持正則表達(dá)式和動態(tài)參數(shù),相比RouterJSR11更加輕量級,apiserver中使用的就是這種路由。
一種Route的設(shè)定包含:請求方法(http Method),請求路徑(URL Path),輸入輸出類型(JSON/YAML)以及對應(yīng)的回掉函數(shù)restful.RouteFunction,響應(yīng)內(nèi)容類型(Accept)等。

2.WebService:
WebService邏輯上是Route的集合,功能上主要是為一組Route統(tǒng)一設(shè)置包括root path,請求響應(yīng)的數(shù)據(jù)類型等一些通用的屬性。
需要注意的是,WebService必須加入到Container中才能生效。

func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
    installer := g.newInstaller()
    ws := installer.NewWebService()
    。。。
    container.Add(ws)
    return utilerrors.NewAggregate(registrationErrors)
}

上面是k8s的REST注冊接口,也調(diào)用了Container.Add(ws),才能讓這個ws生效。

3.Container:
Container邏輯上是WebService的集合,功能上可以實現(xiàn)多終端的效果。
它包括一組restful.WebService和一個http.ServeMux對象,使用RouteSelector進(jìn)行請求派發(fā)。
例如,下面代碼中創(chuàng)建了兩個Container,分別在不同的port上提供服務(wù)。
該代碼是go-restful的example:

package main

import (
    "github.com/emicklei/go-restful"
    "io"
    "log"
    "net/http"
)

func main() {
    ws := new(restful.WebService)
    ws.Route(ws.GET("/hello").To(hello))
    // ws被添加到默認(rèn)的container restful.DefaultContainer中
    restful.Add(ws)
    go func() {
        // restful.DefaultContainer監(jiān)聽在端口8080上
        http.ListenAndServe(":8080", nil)
    }()

    container2 := restful.NewContainer()
    ws2 := new(restful.WebService)
    ws2.Route(ws2.GET("/hello").To(hello2))
    // ws2被添加到container2中
    container2.Add(ws2)
    // container2中監(jiān)聽端口8081
    server := &http.Server{Addr: ":8081", Handler: container2}
    log.Fatal(server.ListenAndServe())
}

func hello(req *restful.Request, resp *restful.Response) {
    io.WriteString(resp, "default world")
}

func hello2(req *restful.Request, resp *restful.Response) {
    io.WriteString(resp, "second world")
}

4.Filter:
Filter用于動態(tài)的攔截請求和響應(yīng),類似于放置在相應(yīng)組件前的鉤子,在相應(yīng)組件功能運行前捕獲請求或者響應(yīng),主要用于記錄log,驗證,重定向等功能。
go-restful中有三種類型的Filter:

Container Filter:
運行在Container中所有的WebService執(zhí)行之前。

// install a (global) filter for the default container (processed before any webservice)
restful.Filter(globalLogging)

WebService Filter:
運行在WebService中所有的Route執(zhí)行之前。

// install a webservice filter (processed before any route)
ws.Filter(webserviceLogging).Filter(measureTime)

Route Filter:
運行在調(diào)用Route綁定的方法之前。

// install 2 chained route filters (processed before calling findUser)
ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser))

示例

拿用官方提供的例子:

package main

import (
    "github.com/emicklei/go-restful"
    "log"
    "net/http"
)

type User struct {
    Id, Name string
}

type UserResource struct {
    // normally one would use DAO (data access object)
    users map[string]User
}

func (u UserResource) Register(container *restful.Container) {
      // 創(chuàng)建新的WebService
    ws := new(restful.WebService)
  
      // 設(shè)定WebService對應(yīng)的路徑("/users")和支持的MIME類型(restful.MIME_XML/ restful.MIME_JSON)
    ws.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well

      // 添加路由: GET /{user-id} --> u.findUser
    ws.Route(ws.GET("/{user-id}").To(u.findUser))
  
      // 添加路由: POST / --> u.updateUser
    ws.Route(ws.POST("").To(u.updateUser))
  
      // 添加路由: PUT /{user-id} --> u.createUser
    ws.Route(ws.PUT("/{user-id}").To(u.createUser))
  
      // 添加路由: DELETE /{user-id} --> u.removeUser
    ws.Route(ws.DELETE("/{user-id}").To(u.removeUser))

      // 將初始化好的WebService添加到Container中
    container.Add(ws)
}

// GET http://localhost:8080/users/1
//
func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
    id := request.PathParameter("user-id")
    usr := u.users[id]
    if len(usr.Id) == 0 {
        response.AddHeader("Content-Type", "text/plain")
        response.WriteErrorString(http.StatusNotFound, "User could not be found.")
    } else {
        response.WriteEntity(usr)
    }
}

// POST http://localhost:8080/users
// 1Melissa Raspberry
//
func (u *UserResource) updateUser(request *restful.Request, response *restful.Response) {
    usr := new(User)
    err := request.ReadEntity(&usr)
    if err == nil {
        u.users[usr.Id] = *usr
        response.WriteEntity(usr)
    } else {
        response.AddHeader("Content-Type", "text/plain")
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
    }
}

// PUT http://localhost:8080/users/1
// 1Melissa
//
func (u *UserResource) createUser(request *restful.Request, response *restful.Response) {
    usr := User{Id: request.PathParameter("user-id")}
    err := request.ReadEntity(&usr)
    if err == nil {
        u.users[usr.Id] = usr
        response.WriteHeader(http.StatusCreated)
        response.WriteEntity(usr)
    } else {
        response.AddHeader("Content-Type", "text/plain")
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
    }
}

// DELETE http://localhost:8080/users/1
//
func (u *UserResource) removeUser(request *restful.Request, response *restful.Response) {
    id := request.PathParameter("user-id")
    delete(u.users, id)
}

func main() {
      // 創(chuàng)建一個空的Container
    wsContainer := restful.NewContainer()
  
    // 設(shè)定路由為CurlyRouter(快速路由)
    wsContainer.Router(restful.CurlyRouter{})
  
      // 創(chuàng)建自定義的Resource Handle(此處為UserResource)
    u := UserResource{map[string]User{}}
  
      // 創(chuàng)建WebService,并將WebService加入到Container中
    u.Register(wsContainer)

    log.Printf("start listening on localhost:8080")
    server := &http.Server{Addr: ":8080", Handler: wsContainer}
      
      // 啟動服務(wù)
    log.Fatal(server.ListenAndServe())
}

上面的示例代碼構(gòu)建RESTful服務(wù),分為幾個步驟,apiServer也是類似:
1.創(chuàng)建Container
2.配置Container屬性:ServeMux/Router type等
3.創(chuàng)建自定義的Resource Handle,實現(xiàn)Resource相關(guān)的處理方式。
4.創(chuàng)建對應(yīng)Resource的WebService,在WebService中添加響應(yīng)Route,并將WebService加入到Container中。
5.啟動監(jiān)聽服務(wù)。

apiServer go-restful使用 Container初始化

apiServer的Container相關(guān)的結(jié)構(gòu)是APIContainer。
路徑:pkg/genericapiserver/mux/container.go

type APIContainer struct {
    *restful.Container
    NonSwaggerRoutes PathRecorderMux
    SecretRoutes     Mux
}

而該結(jié)構(gòu)是在GenericAPIServer中被使用,分析過apiServer的啟動過程的話,應(yīng)該對該結(jié)構(gòu)比較熟悉。

type GenericAPIServer struct {
    discoveryAddresses DiscoveryAddresses

    LoopbackClientConfig *restclient.Config

    minRequestTimeout time.Duration

    ...

    requestContextMapper api.RequestContextMapper

    // 這里使用到了restful.Container
    HandlerContainer *genericmux.APIContainer

    SecureServingInfo   *SecureServingInfo
    InsecureServingInfo *ServingInfo

    effectiveSecurePort, effectiveInsecurePort int

    ExternalAddress string

    storage map[string]rest.Storage

    Serializer runtime.NegotiatedSerializer

    Handler         http.Handler
    InsecureHandler http.Handler

    apiGroupsForDiscoveryLock sync.RWMutex
    apiGroupsForDiscovery     map[string]unversioned.APIGroup

    ...
}

而該結(jié)構(gòu)的初始化是在master的初始化過程中進(jìn)行的。
調(diào)用過程: main --> App.Run --> master.Complete.New --> c.Config.GenericConfig.SkipComplete().New()
路徑: pkg/genericapiserver/config.go

func (c completedConfig) New() (*GenericAPIServer, error) {
    if c.Serializer == nil {
        return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil")
    }

    s := &GenericAPIServer{
        discoveryAddresses:     c.DiscoveryAddresses,
        LoopbackClientConfig:   c.LoopbackClientConfig,
        legacyAPIGroupPrefixes: c.LegacyAPIGroupPrefixes,
        admissionControl:       c.AdmissionControl,
        requestContextMapper:   c.RequestContextMapper,
        Serializer:             c.Serializer,

        minRequestTimeout:    time.Duration(c.MinRequestTimeout) * time.Second,
        enableSwaggerSupport: c.EnableSwaggerSupport,

        SecureServingInfo:   c.SecureServingInfo,
        InsecureServingInfo: c.InsecureServingInfo,
        ExternalAddress:     c.ExternalAddress,

        apiGroupsForDiscovery: map[string]unversioned.APIGroup{},

        enableOpenAPISupport: c.EnableOpenAPISupport,
        openAPIConfig:        c.OpenAPIConfig,

        postStartHooks: map[string]postStartHookEntry{},
    }
    // 這里進(jìn)行了Contianer的初始化
    s.HandlerContainer = mux.NewAPIContainer(http.NewServeMux(), c.Serializer)
    // 添加了DynamicApisDiscovery的
    s.installAPI(c.Config)

    s.Handler, s.InsecureHandler = c.BuildHandlerChainsFunc(s.HandlerContainer.ServeMux, c.Config)

    return s, nil
}

繼續(xù)調(diào)用mux.NewAPIContainer()接口創(chuàng)建,該接口的兩個參數(shù):新建了一個http的ServeMux; 另一個是實現(xiàn)了編解碼序列化反序列化的對象

func NewAPIContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *APIContainer {
    c := APIContainer{
        // New一個Container
        Container: restful.NewContainer(),
        NonSwaggerRoutes: PathRecorderMux{
            mux: mux,
        },
        SecretRoutes: mux,
    }
    // 配置http.ServeMux
    c.Container.ServeMux = mux
    // 配置該Container的路由方式:CurlyRouter 即快速路由
    c.Container.Router(restful.CurlyRouter{}) // e.g. for proxy/{kind}/{name}/{*}
    // 配置panic產(chǎn)生之后的恢復(fù)處理函數(shù)
    apiserver.InstallRecoverHandler(s, c.Container)
    apiserver.InstallServiceErrorHandler(s, c.Container)

    return &c
}

看下apiserver.InstallRecoverHandler()實現(xiàn):

func InstallRecoverHandler(s runtime.NegotiatedSerializer, container *restful.Container) {
    container.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) {
        logStackOnRecover(s, panicReason, httpWriter)
    })
}

// RecoverHandler changes the default function (logStackOnRecover) to be called
// when a panic is detected. DoNotRecover must be have its default value (=false).
func (c *Container) RecoverHandler(handler RecoverHandleFunction) {
    c.recoverHandleFunc = handler
}

根據(jù)英文注釋可以看明白,該RecoverHandler就是在產(chǎn)生panic后會調(diào)用的恢復(fù)處理函數(shù),默認(rèn)的調(diào)用函數(shù)是logStackOnRecover,調(diào)用Container.RecoverHandler()后會修改該默認(rèn)函數(shù),并且Container.DoNotRecover的bool值必須是false才能生效。
apiserver.InstallServiceErrorHandler()接口就不看了,其實就是修改Service Error產(chǎn)生后的錯誤處理函數(shù),默認(rèn)是調(diào)用writeServiceError()。

到這里Container的初始化基本OK了。

添加WebService

Container已創(chuàng)建并且也進(jìn)行了初始化。該輪到WebService了,這節(jié)會介紹k8s的WebService的創(chuàng)建及添加。
接續(xù)上文的Container初始化入口,繼續(xù)往下看s.installAPI(c.Config):

func (s *GenericAPIServer) installAPI(c *Config) {
    // 這里原本還有很多routes.Install()函數(shù)
    // 這些install()貌似和mux有關(guān)。
    // 而mux就是一個http的多分器,用于派發(fā)某個Request路徑到對應(yīng)的http.Handler進(jìn)行處理
    。。。
    // 往HandlerContainer中的Container里添加WebService
    // 該WebService的創(chuàng)建在s.DynamicApisDiscovery()中進(jìn)行
    // 實際上創(chuàng)建的WebService是用于list 該group下的所有versions
    s.HandlerContainer.Add(s.DynamicApisDiscovery())
}

先看下WebService的創(chuàng)建接口s.DynamicApisDiscovery():
路徑:pkg/genericapiserver/genericapiserver.go

// DynamicApisDiscovery returns a webservice serving api group discovery.
// Note: during the server runtime apiGroupsForDiscovery might change.
func (s *GenericAPIServer) DynamicApisDiscovery() *restful.WebService {
    return apiserver.NewApisWebService(s.Serializer, APIGroupPrefix, func(req *restful.Request) []unversioned.APIGroup {
        // 需要加鎖
        // 接口注釋也有說明。因為k8s可以動態(tài)加載第三方apiGroups
        s.apiGroupsForDiscoveryLock.RLock()
        defer s.apiGroupsForDiscoveryLock.RUnlock()

        // 將apiGroupsForDiscovery中所有的APIGroup按照其名字進(jìn)行升序排序
        sortedGroups := []unversioned.APIGroup{}
        groupNames := make([]string, 0, len(s.apiGroupsForDiscovery))
        for groupName := range s.apiGroupsForDiscovery {
            groupNames = append(groupNames, groupName)
        }
        sort.Strings(groupNames)
        for _, groupName := range groupNames {
            sortedGroups = append(sortedGroups, s.apiGroupsForDiscovery[groupName])
        }
        // 創(chuàng)建切片,并填充各個APIGroup的ServerAddressByClientCIDRs信息
        clientIP := utilnet.GetClientIP(req.Request)
        serverCIDR := s.discoveryAddresses.ServerAddressByClientCIDRs(clientIP)
        groups := make([]unversioned.APIGroup, len(sortedGroups))
        for i := range sortedGroups {
            groups[i] = sortedGroups[i]
            groups[i].ServerAddressByClientCIDRs = serverCIDR
        }
        return groups
    })
}

繼續(xù)深入看apiserver.NewApisWebService(),該接口傳入了編解碼對象,APIGroup的Prefix,還有一個function。

func NewApisWebService(s runtime.NegotiatedSerializer, apiPrefix string, f func(req *restful.Request) []unversioned.APIGroup) *restful.WebService {
    // 用于向后兼容v1.1版本,返回一個空的APIGroup
    ss := StripVersionNegotiatedSerializer{s}
    // 獲取支持的媒體類型,比如:application/json,application/yaml
    mediaTypes, _ := mediaTypesForSerializer(s)
    // 構(gòu)建go-restful的Route處理方法
    rootAPIHandler := RootAPIHandler(ss, f)
    // 創(chuàng)建WebService
    ws := new(restful.WebService)
    // 添加Path
    ws.Path(apiPrefix)
    // API 說明
    ws.Doc("get available API versions")
    // 配置GET("/") 轉(zhuǎn)到rootAPIHandler()接口
    ws.Route(ws.GET("/").To(rootAPIHandler).
        Doc("get available API versions").
        Operation("getAPIVersions").
        Produces(mediaTypes...).
        Consumes(mediaTypes...).
        Writes(unversioned.APIGroupList{}))
    return ws
}

到這里list某個Group下所有的versions的API已經(jīng)注冊完成了。
這些都不是關(guān)鍵的RESTful API的注冊,關(guān)鍵的注冊都會在pkg/apiserver/apiserver.go中的InstallREST()接口中進(jìn)行。
琢磨過apiServer啟動流程的同學(xué),應(yīng)該會知道/api和/apis的注冊接口最后都會調(diào)用到該接口。
/api的注冊接口是pkg/genericapiserver/genericapiserver.go中的InstallLegacyAPIGroup()接口
/apis的注冊接口是InstallAPIGroup()。
這兩個接口都會調(diào)用s.installAPIResources(),最后再調(diào)用apiGroupVersion.InstallREST()進(jìn)行API注冊。
流程基本就是這樣,接著我們直接進(jìn)入InstallREST()接口看實現(xiàn):

func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
    // 拼裝path: "Prefix/Group/Version"    
    // 然后填充并返回一個APIInstaller對象
    installer := g.newInstaller()
    // 創(chuàng)建一個WebService
    ws := installer.NewWebService()
    // 這個是關(guān)鍵,會對各種URL進(jìn)行注冊
    apiResources, registrationErrors := installer.Install(ws)
    lister := g.ResourceLister
    if lister == nil {
        lister = staticLister{apiResources}
    }
    // 增加一個list的API
    AddSupportedResourcesWebService(g.Serializer, ws, g.GroupVersion, lister)
    // 將該WebService加入到Container
    container.Add(ws)
    return utilerrors.NewAggregate(registrationErrors)
}

前兩個調(diào)用函數(shù)比較簡單,這里不進(jìn)行介紹了。直接進(jìn)入關(guān)鍵函數(shù)installer.Install(ws):

func (a *APIInstaller) Install(ws *restful.WebService) (apiResources []unversioned.APIResource, errors []error) {
    errors = make([]error, 0)

    proxyHandler := (&ProxyHandler{
        prefix:     a.prefix + "/proxy/",
        storage:    a.group.Storage,
        serializer: a.group.Serializer,
        mapper:     a.group.Context,
    })

    // 將所有的path合成一個切片,并按照升序重新排序
    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 {
        // 注冊各個URL,關(guān)鍵接口
        // 傳入的參數(shù):path,rest.Storage,WebService,Handler
        apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws, proxyHandler)
        if err != nil {
            errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))
        }
        // 將所有注冊成功的Resource合成一個切片
        // 將該切片作為返回值,便于之后的接口注冊list Resources的API
        if apiResource != nil {
            apiResources = append(apiResources, *apiResource)
        }
    }
    return apiResources, errors
}

該接口先是遍歷所有的path,并升序重新排列,然后循環(huán)調(diào)用接口注冊各個URL的API,并將這些注冊成功的APIResource加入到同一個切片中。
我們繼續(xù)看a.registerResourceHandlers()接口:

func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) (*unversioned.APIResource, error) {
    ...

    // 構(gòu)建creater、lister、deleter、updater、watcher等,其實就是storage
    creater, isCreater := storage.(rest.Creater)
    namedCreater, isNamedCreater := storage.(rest.NamedCreater)
    lister, isLister := storage.(rest.Lister)
    getter, isGetter := storage.(rest.Getter)
    getterWithOptions, isGetterWithOptions := storage.(rest.GetterWithOptions)
    deleter, isDeleter := storage.(rest.Deleter)
    gracefulDeleter, isGracefulDeleter := storage.(rest.GracefulDeleter)
    collectionDeleter, isCollectionDeleter := storage.(rest.CollectionDeleter)
    updater, isUpdater := storage.(rest.Updater)
    patcher, isPatcher := storage.(rest.Patcher)
    watcher, isWatcher := storage.(rest.Watcher)
    _, isRedirector := storage.(rest.Redirector)
    connecter, isConnecter := storage.(rest.Connecter)
    storageMeta, isMetadata := storage.(rest.StorageMetadata)
    ...
    var apiResource unversioned.APIResource
    // k8s資源分為兩類:無namespace的RESTScopeNameRoot; 有namespace的RESTScopeNameNamespace
    // 在對應(yīng)的path上添加各類actions,并指定對應(yīng)的handler。
    switch scope.Name() {
    case meta.RESTScopeNameRoot:
        // Handle non-namespace scoped resources like nodes.
        resourcePath := resource
        resourceParams := params
        itemPath := resourcePath + "/{name}"
        nameParams := append(params, nameParam)
        proxyParams := append(nameParams, pathParam)
        suffix := ""
        if hasSubresource {
            suffix = "/" + subresource
            itemPath = itemPath + suffix
            resourcePath = itemPath
            resourceParams = nameParams
        }
        apiResource.Name = path
        apiResource.Namespaced = false
        apiResource.Kind = resourceKind
        namer := rootScopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, resourcePath, "/"), suffix}

        // Handler for standard REST verbs (GET, PUT, POST and DELETE).
        // Add actions at the resource path: /api/apiVersion/resource
        actions = appendIf(actions, action{"LIST", resourcePath, resourceParams, namer, false}, isLister)
        actions = appendIf(actions, action{"POST", resourcePath, resourceParams, namer, false}, isCreater)
        actions = appendIf(actions, action{"DELETECOLLECTION", resourcePath, resourceParams, namer, false}, isCollectionDeleter)
        // DEPRECATED
        actions = appendIf(actions, action{"WATCHLIST", "watch/" + resourcePath, resourceParams, namer, false}, allowWatchList)

        // Add actions at the item path: /api/apiVersion/resource/{name}
        actions = appendIf(actions, action{"GET", itemPath, nameParams, namer, false}, isGetter)
        if getSubpath {
            actions = appendIf(actions, action{"GET", itemPath + "/{path:*}", proxyParams, namer, false}, isGetter)
        }
        actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer, false}, isUpdater)
        actions = appendIf(actions, action{"PATCH", itemPath, nameParams, namer, false}, isPatcher)
        actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer, false}, isDeleter)
        actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher)
        // We add "proxy" subresource to remove the need for the generic top level prefix proxy.
        // The generic top level prefix proxy is deprecated in v1.2, and will be removed in 1.3, or 1.4 at the latest.
        // TODO: DEPRECATED in v1.2.
        actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath + "/{path:*}", proxyParams, namer, false}, isRedirector)
        // TODO: DEPRECATED in v1.2.
        actions = appendIf(actions, action{"PROXY", "proxy/" + itemPath, nameParams, namer, false}, isRedirector)
        actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter)
        actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath)
        break
    case meta.RESTScopeNameNamespace:
        ...
        break
    default:
        return nil, fmt.Errorf("unsupported restscope: %s", scope.Name())
    }

    ...
    // 根據(jù)之前生成的actions,進(jìn)行遍歷
    // 然后在WebService中添加指定的route
    for _, action := range actions {
        versionedObject := storageMeta.ProducesObject(action.Verb)
        if versionedObject == nil {
            versionedObject = defaultVersionedObject
        }
        reqScope.Namer = action.Namer
        namespaced := ""
        if apiResource.Namespaced {
            namespaced = "Namespaced"
        }
        operationSuffix := ""
        if strings.HasSuffix(action.Path, "/{path:*}") {
            operationSuffix = operationSuffix + "WithPath"
        }
        if action.AllNamespaces {
            operationSuffix = operationSuffix + "ForAllNamespaces"
            namespaced = ""
        }
        // 判斷action的動作類型
        // 生成響應(yīng)的handler,創(chuàng)建route添加到WebService中
        switch action.Verb {
        case "GET": // Get a resource.
            var handler restful.RouteFunction
            // 判斷是否有參數(shù)
            if isGetterWithOptions {
                handler = GetResourceWithOptions(getterWithOptions, reqScope)
            } else {
                handler = GetResource(getter, exporter, reqScope)
            }
            // 生成處理函數(shù)
            handler = metrics.InstrumentRouteFunc(action.Verb, resource, handler)
            doc := "read the specified " + kind
            if hasSubresource {
                doc = "read " + subresource + " of the specified " + kind
            }
            route := ws.GET(action.Path).To(handler).
                Doc(doc).
                Param(ws.QueryParameter("pretty", "If "true", then the output is pretty printed.")).
                Operation("read"+namespaced+kind+strings.Title(subresource)+operationSuffix).
                Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...).
                Returns(http.StatusOK, "OK", versionedObject).
                Writes(versionedObject)
            if isGetterWithOptions {
                if err := addObjectParams(ws, route, versionedGetOptions); err != nil {
                    return nil, err
                }
            }
            if isExporter {
                if err := addObjectParams(ws, route, versionedExportOptions); err != nil {
                    return nil, err
                }
            }
            addParams(route, action.Params)
            ws.Route(route)
        case "LIST": // List all resources of a kind.
            ...
        case "PUT": // Update a resource.
            ...
        case "PATCH": // Partially update a resource
            ...
        case "POST": // Create a resource.
            ...
        case "DELETE": // Delete a resource.
            ...
        case "DELETECOLLECTION":
            ...
        case "WATCH": // Watch a resource.
            ...
        case "WATCHLIST": // Watch all resources of a kind.
            ...
        case "PROXY": // Proxy requests to a resource.
            ...
        case "CONNECT":
            ...
            }
        default:
            return nil, fmt.Errorf("unrecognized action verb: %s", action.Verb)
        }
        // Note: update GetAttribs() when adding a custom handler.
    }
    return &apiResource, nil
}

首先構(gòu)建creater、lister、getter、deleter、updater、patcher、watcher,其實他們都是storage,只是對應(yīng)著對etcd的不同操作。
然后針對所有的action,構(gòu)建響應(yīng)的handler。創(chuàng)建對應(yīng)的route,最后把route添加到service里面。這樣就完成了api的注冊。

關(guān)鍵的REST API注冊基本就這樣結(jié)束了,除此之外還會有很多別的API的注冊:
比如APIGroupVersion.InstallREST()接口中的AddSupportedResourcesWebService(g.Serializer, ws, g.GroupVersion, lister);
GenericAPIServer.InstallLegacyAPIGroup()接口中的apiserver.AddApiWebService()的調(diào)用;
等等。。
其實上面也注冊了各種REST API,比如像PodList,ServiceList,ReplicationControllerList等。這些就不深入了,都是大同小異。

參考資料

1.go-restful example: http://ernestmicklei.com/2012...
2.go-restful api desgin: http://ernestmicklei.com/2012...
3.go-restful github code: https://github.com/emicklei/g...
4.go-restful GoDoc: https://godoc.org/github.com/...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/32555.html

相關(guān)文章

  • Kubernetes1.5源碼分析(二) apiServer資源注冊

    摘要:我們先將上面的接口解析放放,先看下是如何初始化的路徑定義了,再看路徑定義空的創(chuàng)建,用于不同版本對象轉(zhuǎn)換增加一些轉(zhuǎn)換函數(shù)上面就創(chuàng)建了一個空的。其實就是向添加了轉(zhuǎn)換函數(shù),比如將轉(zhuǎn)換為,將轉(zhuǎn)換為。 源碼版本 Kubernetes v1.5.0 簡介 k8s里面有各種資源,如Pod、Service、RC、namespaces等資源,用戶操作的其實也就是這一大堆資源。但這些資源并不是雜亂無章的,...

    imccl 評論0 收藏0
  • Kubernetes1.5源碼分析(一) apiServer啟動分析

    摘要:源碼版本簡介是最重要的組成部分,不論是命令操作還是通過進(jìn)行控制,實際都需要經(jīng)過。僅用于長時間執(zhí)行的請求最小請求處理超時時間,默認(rèn)僅用于該文件內(nèi)設(shè)置鑒權(quán)機(jī)構(gòu)一組用于運行時的配置信息。在最后會啟動服務(wù)。 源碼版本 Kubernetes v1.5.0 簡介 apiserver是K8S最重要的組成部分,不論是命令操作還是通過remote API進(jìn)行控制,實際都需要經(jīng)過apiserver。api...

    stormgens 評論0 收藏0
  • Kubernetes1.5源碼分析(四) apiServer資源etcd接口實現(xiàn)

    摘要:為所有對外提供服務(wù)的資源實現(xiàn)了一套通用的符合要求的操作接口,每個服務(wù)接口負(fù)責(zé)處理一類資源對象。該接口最終返回了的和清除操作資源的接口。 源碼版本 Kubernetes v1.5.0 簡介 k8s的各個組件與apiServer交互操作各種資源對象,最終都會落入到etcd中。k8s為所有對外提供服務(wù)的Restful資源實現(xiàn)了一套通用的符合Restful要求的etcd操作接口,每個服務(wù)接口負(fù)...

    K_B_Z 評論0 收藏0
  • Kubernetes監(jiān)控Heapster源碼分析

    摘要:源碼版本簡介是下的一個監(jiān)控項目,用于進(jìn)行容器集群的監(jiān)控和性能分析。基本的功能及概念介紹可以回顧我之前的一篇文章監(jiān)控之介紹。在源碼分析之前我們先介紹的實現(xiàn)流程,由上圖可以看出會從各個上獲取相關(guān)的監(jiān)控信息,然后進(jìn)行匯總發(fā)送給后臺數(shù)據(jù)庫。 源碼版本 heapster version: release-1.2 簡介 Heapster是Kubernetes下的一個監(jiān)控項目,用于進(jìn)行容器集群的監(jiān)控...

    gclove 評論0 收藏0
  • kubeadm源碼分析(kubernetes離線安裝包,步安裝)

    摘要:離線安裝包三步安裝,簡單到難以置信源碼分析說句實在話,的代碼寫的真心一般,質(zhì)量不是很高。然后給該租戶綁定角色。 k8s離線安裝包 三步安裝,簡單到難以置信 kubeadm源碼分析 說句實在話,kubeadm的代碼寫的真心一般,質(zhì)量不是很高。 幾個關(guān)鍵點來先說一下kubeadm干的幾個核心的事: kubeadm 生成證書在/etc/kubernetes/pki目錄下 kubeadm 生...

    Eirunye 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<