K8s源码分析(20)-client go组件之request和result

2022-10-30 13:22:08 浏览数 (1)

上一篇文章里,我们主要介绍了 kubernetes 世界中 client go 这个基础组件,它的主要职责是负责与 API server 进行通讯交互。其中负责资源调度的 kube-scheduler 组件,负责资源管理的 controller manager 组件,以及负责 pod 生命周期的 kublet 组件,负责网络管理的 kube-proxy 组件都会依赖于这个组件。而该组件在通讯的时候又依赖于 request 对象,并且得到相应的 result 对象,在本篇文章里我们主要来介绍 request 和 result 对象。

Request 结构体

该结构体主要封装了上一篇文章中介绍的 RESTClient 对象,用以完成和 API server 之间的通讯,其图解和相关源码如下:

代码语言:javascript复制
type Request struct {
  c *RESTClient  
  warningHandler WarningHandler
  rateLimiter flowcontrol.RateLimiter
  backoff     BackoffManager
  timeout     time.Duration
  maxRetries  int

  verb       string
  pathPrefix string
  subpath    string
  params     url.Values
  headers    http.Header

  namespace    string
  namespaceSet bool
  resource     string
  resourceName string
  subresource  string

  err  error
  body io.Reader
}

func (r *Request) Do(ctx context.Context) Result {
  var result Result
  err := r.request(ctx, func(req *http.Request, resp *http.Response) {
    result = r.transformResponse(resp, req)
  })
  if err != nil {
    return Result{err: err}
  }
  return result
}

func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result {
                ............
  var decoder runtime.Decoder
  contentType := resp.Header.Get("Content-Type")
  if len(contentType) == 0 {
    contentType = r.c.content.ContentType
  }
                ............
  decoder, err = r.c.content.Negotiator.Decoder(mediaType, params)
  ............
  return Result{
    body:        body,
    contentType: contentType,
    statusCode:  resp.StatusCode,
    decoder:     decoder,
    warnings:    handleWarnings(resp.Header, r.warningHandler),
  }
}
  • 在该结构体的源码定义中, 封装了上一篇文章中介绍的 RESTClient 对象。同时也封装对应的 http 请求方法 verb,路径的前缀 pathPrefix ,以及请求参数和请求头等有关必要信息。
  • 在该结构体中还封装了资源的信息,例如是本次操作的资源是否为基于 namespace 的资源,具体资源是属于哪个命名空间的,资源的种类,资源的名字,还有子资源的种类等等。
  • 该结构体中封装了 Do() 方法用以发送请求和处理响应。
  • 封装了 transformResponse() 方法用完成对 API 响应的封装操作,其核心是调用上一篇文章中介绍的 ClientNegotiator 定义的 Decoder 方法来得到相应的 decoder,然后封装到一个 Result 对象中。

Result 结构体

该结构体主要封装了请求对象和 API server 交互的结果,并提供反序列化得到相应资源对象的功能,其图解和相关源码如下:

代码语言:javascript复制
type Result struct {
  body        []byte
  warnings    []net.WarningHeader
  contentType string
  err         error
  statusCode  int

  decoder runtime.Decoder
}

func (r Result) Into(obj runtime.Object) error {
  if r.err != nil {
    // Check whether the result has a Status object in the body and prefer that.
    return r.Error()
  }
  if r.decoder == nil {
    return fmt.Errorf("serializer for %s doesn't exist", r.contentType)
  }
  if len(r.body) == 0 {
    return fmt.Errorf("0-length response with status code: %d and content type: %s",
      r.statusCode, r.contentType)
  }

  out, _, err := r.decoder.Decode(r.body, nil, obj)
  if err != nil || out == obj {
    return err
  }
  // if a different object is returned, see if it is Status and avoid double decoding
  // the object.
  switch t := out.(type) {
  case *metav1.Status:
    // any status besides StatusSuccess is considered an error.
    if t.Status != metav1.StatusSuccess {
      return errors.FromObject(t)
    }
  }
  return nil
}
  • 在该结构体的源码定义中, 封装了响应返回的二进制结果 body,同时也封装了对应的 decoder 对象用来反序列化。
  • 该接结构体中封装了 Into() 方法用完成对结果的反序列化操作,其核心就是调用内部的 decoder 对象来把结果转化为对应的资源对象。

目前先我们写到这里,在下一篇文章中我们继续来介绍对于不同 group/version 的资源是如何通过发送请求来操作的。

0 人点赞