gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/runtime/kubernetes/client/api/request.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"net/url"
    11  
    12  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/log"
    13  )
    14  
    15  // Request is used to construct a http request for the k8s API.
    16  type Request struct {
    17  	client    *http.Client
    18  	header    http.Header
    19  	params    url.Values
    20  	method    string
    21  	host      string
    22  	namespace string
    23  
    24  	resource     string
    25  	resourceName *string
    26  	body         io.Reader
    27  
    28  	err error
    29  }
    30  
    31  // Params is the object to pass in to set paramaters
    32  // on a request.
    33  type Params struct {
    34  	LabelSelector map[string]string
    35  	Annotations   map[string]string
    36  }
    37  
    38  // verb sets method
    39  func (r *Request) verb(method string) *Request {
    40  	r.method = method
    41  	return r
    42  }
    43  
    44  // Get request
    45  func (r *Request) Get() *Request {
    46  	return r.verb("GET")
    47  }
    48  
    49  // Post request
    50  func (r *Request) Post() *Request {
    51  	return r.verb("POST")
    52  }
    53  
    54  // Put request
    55  func (r *Request) Put() *Request {
    56  	return r.verb("PUT")
    57  }
    58  
    59  // Patch request
    60  func (r *Request) Patch() *Request {
    61  	return r.verb("PATCH")
    62  }
    63  
    64  // Delete request
    65  func (r *Request) Delete() *Request {
    66  	return r.verb("DELETE")
    67  }
    68  
    69  // Namespace is to set the namespace to operate on
    70  func (r *Request) Namespace(s string) *Request {
    71  	r.namespace = s
    72  	return r
    73  }
    74  
    75  // Resource is the type of resource the operation is
    76  // for, such as "services", "endpoints" or "pods"
    77  func (r *Request) Resource(s string) *Request {
    78  	r.resource = s
    79  	return r
    80  }
    81  
    82  // Name is for targeting a specific resource by id
    83  func (r *Request) Name(s string) *Request {
    84  	r.resourceName = &s
    85  	return r
    86  }
    87  
    88  // Body pass in a body to set, this is for POST, PUT and PATCH requests
    89  func (r *Request) Body(in interface{}) *Request {
    90  	b := new(bytes.Buffer)
    91  	// if we're not sending YAML request, we encode to JSON
    92  	if r.header.Get("Content-Type") != "application/yaml" {
    93  		if err := json.NewEncoder(b).Encode(&in); err != nil {
    94  			r.err = err
    95  			return r
    96  		}
    97  		log.Debugf("Request body: %v", b)
    98  		r.body = b
    99  		return r
   100  	}
   101  
   102  	// if application/yaml is set, we assume we get a raw bytes so we just copy over
   103  	body, ok := in.(io.Reader)
   104  	if !ok {
   105  		r.err = errors.New("invalid data")
   106  		return r
   107  	}
   108  	// copy over data to the bytes buffer
   109  	if _, err := io.Copy(b, body); err != nil {
   110  		r.err = err
   111  		return r
   112  	}
   113  
   114  	log.Debugf("Request body: %v", b)
   115  	r.body = b
   116  	return r
   117  }
   118  
   119  // Params isused to set paramters on a request
   120  func (r *Request) Params(p *Params) *Request {
   121  	for k, v := range p.LabelSelector {
   122  		// create new key=value pair
   123  		value := fmt.Sprintf("%s=%s", k, v)
   124  		// check if there's an existing value
   125  		if label := r.params.Get("labelSelector"); len(label) > 0 {
   126  			value = fmt.Sprintf("%s,%s", label, value)
   127  		}
   128  		// set and overwrite the value
   129  		r.params.Set("labelSelector", value)
   130  	}
   131  
   132  	return r
   133  }
   134  
   135  // SetHeader sets a header on a request with
   136  // a `key` and `value`
   137  func (r *Request) SetHeader(key, value string) *Request {
   138  	r.header.Add(key, value)
   139  	return r
   140  }
   141  
   142  // request builds the http.Request from the options
   143  func (r *Request) request() (*http.Request, error) {
   144  	var url string
   145  	switch r.resource {
   146  	case "pod", "service", "endpoint":
   147  		// /api/v1/namespaces/{namespace}/pods
   148  		url = fmt.Sprintf("%s/api/v1/namespaces/%s/%ss/", r.host, r.namespace, r.resource)
   149  	case "deployment":
   150  		// /apis/apps/v1/namespaces/{namespace}/deployments/{name}
   151  		url = fmt.Sprintf("%s/apis/apps/v1/namespaces/%s/%ss/", r.host, r.namespace, r.resource)
   152  	}
   153  
   154  	// append resourceName if it is present
   155  	if r.resourceName != nil {
   156  		url += *r.resourceName
   157  	}
   158  
   159  	// append any query params
   160  	if len(r.params) > 0 {
   161  		url += "?" + r.params.Encode()
   162  	}
   163  
   164  	// build request
   165  	req, err := http.NewRequest(r.method, url, r.body)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	// set headers on request
   171  	req.Header = r.header
   172  	return req, nil
   173  }
   174  
   175  // Do builds and triggers the request
   176  func (r *Request) Do() *Response {
   177  	if r.err != nil {
   178  		return &Response{
   179  			err: r.err,
   180  		}
   181  	}
   182  
   183  	req, err := r.request()
   184  	if err != nil {
   185  		return &Response{
   186  			err: err,
   187  		}
   188  	}
   189  
   190  	log.Debugf("kubernetes api request: %v", req)
   191  
   192  	res, err := r.client.Do(req)
   193  	if err != nil {
   194  		return &Response{
   195  			err: err,
   196  		}
   197  	}
   198  
   199  	log.Debugf("kubernetes api response: %v", res)
   200  
   201  	// return res, err
   202  	return newResponse(res, err)
   203  }
   204  
   205  // Options ...
   206  type Options struct {
   207  	Host        string
   208  	Namespace   string
   209  	BearerToken *string
   210  	Client      *http.Client
   211  }
   212  
   213  // NewRequest creates a k8s api request
   214  func NewRequest(opts *Options) *Request {
   215  	req := &Request{
   216  		header:    make(http.Header),
   217  		params:    make(url.Values),
   218  		client:    opts.Client,
   219  		namespace: opts.Namespace,
   220  		host:      opts.Host,
   221  	}
   222  
   223  	if opts.BearerToken != nil {
   224  		req.SetHeader("Authorization", "Bearer "+*opts.BearerToken)
   225  	}
   226  
   227  	return req
   228  }