229 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 
 | |
| 	"github.com/micro/go-micro/util/log"
 | |
| )
 | |
| 
 | |
| // Request is used to construct a http request for the k8s API.
 | |
| type Request struct {
 | |
| 	client    *http.Client
 | |
| 	header    http.Header
 | |
| 	params    url.Values
 | |
| 	method    string
 | |
| 	host      string
 | |
| 	namespace string
 | |
| 
 | |
| 	resource     string
 | |
| 	resourceName *string
 | |
| 	body         io.Reader
 | |
| 
 | |
| 	err error
 | |
| }
 | |
| 
 | |
| // Params is the object to pass in to set paramaters
 | |
| // on a request.
 | |
| type Params struct {
 | |
| 	LabelSelector map[string]string
 | |
| 	Annotations   map[string]string
 | |
| }
 | |
| 
 | |
| // verb sets method
 | |
| func (r *Request) verb(method string) *Request {
 | |
| 	r.method = method
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // Get request
 | |
| func (r *Request) Get() *Request {
 | |
| 	return r.verb("GET")
 | |
| }
 | |
| 
 | |
| // Post request
 | |
| func (r *Request) Post() *Request {
 | |
| 	return r.verb("POST")
 | |
| }
 | |
| 
 | |
| // Put request
 | |
| func (r *Request) Put() *Request {
 | |
| 	return r.verb("PUT")
 | |
| }
 | |
| 
 | |
| // Patch request
 | |
| func (r *Request) Patch() *Request {
 | |
| 	return r.verb("PATCH")
 | |
| }
 | |
| 
 | |
| // Delete request
 | |
| func (r *Request) Delete() *Request {
 | |
| 	return r.verb("DELETE")
 | |
| }
 | |
| 
 | |
| // Namespace is to set the namespace to operate on
 | |
| func (r *Request) Namespace(s string) *Request {
 | |
| 	r.namespace = s
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // Resource is the type of resource the operation is
 | |
| // for, such as "services", "endpoints" or "pods"
 | |
| func (r *Request) Resource(s string) *Request {
 | |
| 	r.resource = s
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // Name is for targeting a specific resource by id
 | |
| func (r *Request) Name(s string) *Request {
 | |
| 	r.resourceName = &s
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // Body pass in a body to set, this is for POST, PUT and PATCH requests
 | |
| func (r *Request) Body(in interface{}) *Request {
 | |
| 	b := new(bytes.Buffer)
 | |
| 	// if we're not sending YAML request, we encode to JSON
 | |
| 	if r.header.Get("Content-Type") != "application/yaml" {
 | |
| 		if err := json.NewEncoder(b).Encode(&in); err != nil {
 | |
| 			r.err = err
 | |
| 			return r
 | |
| 		}
 | |
| 		log.Debugf("Request body: %v", b)
 | |
| 		r.body = b
 | |
| 		return r
 | |
| 	}
 | |
| 
 | |
| 	// if application/yaml is set, we assume we get a raw bytes so we just copy over
 | |
| 	body, ok := in.(io.Reader)
 | |
| 	if !ok {
 | |
| 		r.err = errors.New("invalid data")
 | |
| 		return r
 | |
| 	}
 | |
| 	// copy over data to the bytes buffer
 | |
| 	if _, err := io.Copy(b, body); err != nil {
 | |
| 		r.err = err
 | |
| 		return r
 | |
| 	}
 | |
| 
 | |
| 	log.Debugf("Request body: %v", b)
 | |
| 	r.body = b
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // Params isused to set paramters on a request
 | |
| func (r *Request) Params(p *Params) *Request {
 | |
| 	for k, v := range p.LabelSelector {
 | |
| 		// create new key=value pair
 | |
| 		value := fmt.Sprintf("%s=%s", k, v)
 | |
| 		// check if there's an existing value
 | |
| 		if label := r.params.Get("labelSelector"); len(label) > 0 {
 | |
| 			value = fmt.Sprintf("%s,%s", label, value)
 | |
| 		}
 | |
| 		// set and overwrite the value
 | |
| 		r.params.Set("labelSelector", value)
 | |
| 	}
 | |
| 
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // SetHeader sets a header on a request with
 | |
| // a `key` and `value`
 | |
| func (r *Request) SetHeader(key, value string) *Request {
 | |
| 	r.header.Add(key, value)
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // request builds the http.Request from the options
 | |
| func (r *Request) request() (*http.Request, error) {
 | |
| 	var url string
 | |
| 	switch r.resource {
 | |
| 	case "pod", "service", "endpoint":
 | |
| 		// /api/v1/namespaces/{namespace}/pods
 | |
| 		url = fmt.Sprintf("%s/api/v1/namespaces/%s/%ss/", r.host, r.namespace, r.resource)
 | |
| 	case "deployment":
 | |
| 		// /apis/apps/v1/namespaces/{namespace}/deployments/{name}
 | |
| 		url = fmt.Sprintf("%s/apis/apps/v1/namespaces/%s/%ss/", r.host, r.namespace, r.resource)
 | |
| 	}
 | |
| 
 | |
| 	// append resourceName if it is present
 | |
| 	if r.resourceName != nil {
 | |
| 		url += *r.resourceName
 | |
| 	}
 | |
| 
 | |
| 	// append any query params
 | |
| 	if len(r.params) > 0 {
 | |
| 		url += "?" + r.params.Encode()
 | |
| 	}
 | |
| 
 | |
| 	// build request
 | |
| 	req, err := http.NewRequest(r.method, url, r.body)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// set headers on request
 | |
| 	req.Header = r.header
 | |
| 	return req, nil
 | |
| }
 | |
| 
 | |
| // Do builds and triggers the request
 | |
| func (r *Request) Do() *Response {
 | |
| 	if r.err != nil {
 | |
| 		return &Response{
 | |
| 			err: r.err,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	req, err := r.request()
 | |
| 	if err != nil {
 | |
| 		return &Response{
 | |
| 			err: err,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	log.Debugf("kubernetes api request: %v", req)
 | |
| 
 | |
| 	res, err := r.client.Do(req)
 | |
| 	if err != nil {
 | |
| 		return &Response{
 | |
| 			err: err,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	log.Debugf("kubernetes api response: %v", res)
 | |
| 
 | |
| 	// return res, err
 | |
| 	return newResponse(res, err)
 | |
| }
 | |
| 
 | |
| // Options ...
 | |
| type Options struct {
 | |
| 	Host        string
 | |
| 	Namespace   string
 | |
| 	BearerToken *string
 | |
| 	Client      *http.Client
 | |
| }
 | |
| 
 | |
| // NewRequest creates a k8s api request
 | |
| func NewRequest(opts *Options) *Request {
 | |
| 	req := &Request{
 | |
| 		header:    make(http.Header),
 | |
| 		params:    make(url.Values),
 | |
| 		client:    opts.Client,
 | |
| 		namespace: opts.Namespace,
 | |
| 		host:      opts.Host,
 | |
| 	}
 | |
| 
 | |
| 	if opts.BearerToken != nil {
 | |
| 		req.SetHeader("Authorization", "Bearer "+*opts.BearerToken)
 | |
| 	}
 | |
| 
 | |
| 	return req
 | |
| }
 |