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 }