request.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package rest
  14. import (
  15. "bytes"
  16. "context"
  17. "encoding/hex"
  18. "fmt"
  19. "io"
  20. "io/ioutil"
  21. "mime"
  22. "net/http"
  23. "net/url"
  24. "path"
  25. "reflect"
  26. "strconv"
  27. "strings"
  28. "time"
  29. "github.com/golang/glog"
  30. "golang.org/x/net/http2"
  31. "k8s.io/apimachinery/pkg/api/errors"
  32. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  33. "k8s.io/apimachinery/pkg/runtime"
  34. "k8s.io/apimachinery/pkg/runtime/schema"
  35. "k8s.io/apimachinery/pkg/runtime/serializer/streaming"
  36. "k8s.io/apimachinery/pkg/util/net"
  37. "k8s.io/apimachinery/pkg/watch"
  38. restclientwatch "k8s.io/client-go/rest/watch"
  39. "k8s.io/client-go/tools/metrics"
  40. "k8s.io/client-go/util/flowcontrol"
  41. )
  42. var (
  43. // longThrottleLatency defines threshold for logging requests. All requests being
  44. // throttle for more than longThrottleLatency will be logged.
  45. longThrottleLatency = 50 * time.Millisecond
  46. )
  47. // HTTPClient is an interface for testing a request object.
  48. type HTTPClient interface {
  49. Do(req *http.Request) (*http.Response, error)
  50. }
  51. // ResponseWrapper is an interface for getting a response.
  52. // The response may be either accessed as a raw data (the whole output is put into memory) or as a stream.
  53. type ResponseWrapper interface {
  54. DoRaw() ([]byte, error)
  55. Stream() (io.ReadCloser, error)
  56. }
  57. // RequestConstructionError is returned when there's an error assembling a request.
  58. type RequestConstructionError struct {
  59. Err error
  60. }
  61. // Error returns a textual description of 'r'.
  62. func (r *RequestConstructionError) Error() string {
  63. return fmt.Sprintf("request construction error: '%v'", r.Err)
  64. }
  65. // Request allows for building up a request to a server in a chained fashion.
  66. // Any errors are stored until the end of your call, so you only have to
  67. // check once.
  68. type Request struct {
  69. // required
  70. client HTTPClient
  71. verb string
  72. baseURL *url.URL
  73. content ContentConfig
  74. serializers Serializers
  75. // generic components accessible via method setters
  76. pathPrefix string
  77. subpath string
  78. params url.Values
  79. headers http.Header
  80. // structural elements of the request that are part of the Kubernetes API conventions
  81. namespace string
  82. namespaceSet bool
  83. resource string
  84. resourceName string
  85. subresource string
  86. timeout time.Duration
  87. // output
  88. err error
  89. body io.Reader
  90. // This is only used for per-request timeouts, deadlines, and cancellations.
  91. ctx context.Context
  92. backoffMgr BackoffManager
  93. throttle flowcontrol.RateLimiter
  94. }
  95. // NewRequest creates a new request helper object for accessing runtime.Objects on a server.
  96. func NewRequest(client HTTPClient, verb string, baseURL *url.URL, versionedAPIPath string, content ContentConfig, serializers Serializers, backoff BackoffManager, throttle flowcontrol.RateLimiter, timeout time.Duration) *Request {
  97. if backoff == nil {
  98. glog.V(2).Infof("Not implementing request backoff strategy.")
  99. backoff = &NoBackoff{}
  100. }
  101. pathPrefix := "/"
  102. if baseURL != nil {
  103. pathPrefix = path.Join(pathPrefix, baseURL.Path)
  104. }
  105. r := &Request{
  106. client: client,
  107. verb: verb,
  108. baseURL: baseURL,
  109. pathPrefix: path.Join(pathPrefix, versionedAPIPath),
  110. content: content,
  111. serializers: serializers,
  112. backoffMgr: backoff,
  113. throttle: throttle,
  114. timeout: timeout,
  115. }
  116. switch {
  117. case len(content.AcceptContentTypes) > 0:
  118. r.SetHeader("Accept", content.AcceptContentTypes)
  119. case len(content.ContentType) > 0:
  120. r.SetHeader("Accept", content.ContentType+", */*")
  121. }
  122. return r
  123. }
  124. // Prefix adds segments to the relative beginning to the request path. These
  125. // items will be placed before the optional Namespace, Resource, or Name sections.
  126. // Setting AbsPath will clear any previously set Prefix segments
  127. func (r *Request) Prefix(segments ...string) *Request {
  128. if r.err != nil {
  129. return r
  130. }
  131. r.pathPrefix = path.Join(r.pathPrefix, path.Join(segments...))
  132. return r
  133. }
  134. // Suffix appends segments to the end of the path. These items will be placed after the prefix and optional
  135. // Namespace, Resource, or Name sections.
  136. func (r *Request) Suffix(segments ...string) *Request {
  137. if r.err != nil {
  138. return r
  139. }
  140. r.subpath = path.Join(r.subpath, path.Join(segments...))
  141. return r
  142. }
  143. // Resource sets the resource to access (<resource>/[ns/<namespace>/]<name>)
  144. func (r *Request) Resource(resource string) *Request {
  145. if r.err != nil {
  146. return r
  147. }
  148. if len(r.resource) != 0 {
  149. r.err = fmt.Errorf("resource already set to %q, cannot change to %q", r.resource, resource)
  150. return r
  151. }
  152. if msgs := IsValidPathSegmentName(resource); len(msgs) != 0 {
  153. r.err = fmt.Errorf("invalid resource %q: %v", resource, msgs)
  154. return r
  155. }
  156. r.resource = resource
  157. return r
  158. }
  159. // BackOff sets the request's backoff manager to the one specified,
  160. // or defaults to the stub implementation if nil is provided
  161. func (r *Request) BackOff(manager BackoffManager) *Request {
  162. if manager == nil {
  163. r.backoffMgr = &NoBackoff{}
  164. return r
  165. }
  166. r.backoffMgr = manager
  167. return r
  168. }
  169. // Throttle receives a rate-limiter and sets or replaces an existing request limiter
  170. func (r *Request) Throttle(limiter flowcontrol.RateLimiter) *Request {
  171. r.throttle = limiter
  172. return r
  173. }
  174. // SubResource sets a sub-resource path which can be multiple segments segment after the resource
  175. // name but before the suffix.
  176. func (r *Request) SubResource(subresources ...string) *Request {
  177. if r.err != nil {
  178. return r
  179. }
  180. subresource := path.Join(subresources...)
  181. if len(r.subresource) != 0 {
  182. r.err = fmt.Errorf("subresource already set to %q, cannot change to %q", r.resource, subresource)
  183. return r
  184. }
  185. for _, s := range subresources {
  186. if msgs := IsValidPathSegmentName(s); len(msgs) != 0 {
  187. r.err = fmt.Errorf("invalid subresource %q: %v", s, msgs)
  188. return r
  189. }
  190. }
  191. r.subresource = subresource
  192. return r
  193. }
  194. // Name sets the name of a resource to access (<resource>/[ns/<namespace>/]<name>)
  195. func (r *Request) Name(resourceName string) *Request {
  196. if r.err != nil {
  197. return r
  198. }
  199. if len(resourceName) == 0 {
  200. r.err = fmt.Errorf("resource name may not be empty")
  201. return r
  202. }
  203. if len(r.resourceName) != 0 {
  204. r.err = fmt.Errorf("resource name already set to %q, cannot change to %q", r.resourceName, resourceName)
  205. return r
  206. }
  207. if msgs := IsValidPathSegmentName(resourceName); len(msgs) != 0 {
  208. r.err = fmt.Errorf("invalid resource name %q: %v", resourceName, msgs)
  209. return r
  210. }
  211. r.resourceName = resourceName
  212. return r
  213. }
  214. // Namespace applies the namespace scope to a request (<resource>/[ns/<namespace>/]<name>)
  215. func (r *Request) Namespace(namespace string) *Request {
  216. if r.err != nil {
  217. return r
  218. }
  219. if r.namespaceSet {
  220. r.err = fmt.Errorf("namespace already set to %q, cannot change to %q", r.namespace, namespace)
  221. return r
  222. }
  223. if msgs := IsValidPathSegmentName(namespace); len(msgs) != 0 {
  224. r.err = fmt.Errorf("invalid namespace %q: %v", namespace, msgs)
  225. return r
  226. }
  227. r.namespaceSet = true
  228. r.namespace = namespace
  229. return r
  230. }
  231. // NamespaceIfScoped is a convenience function to set a namespace if scoped is true
  232. func (r *Request) NamespaceIfScoped(namespace string, scoped bool) *Request {
  233. if scoped {
  234. return r.Namespace(namespace)
  235. }
  236. return r
  237. }
  238. // AbsPath overwrites an existing path with the segments provided. Trailing slashes are preserved
  239. // when a single segment is passed.
  240. func (r *Request) AbsPath(segments ...string) *Request {
  241. if r.err != nil {
  242. return r
  243. }
  244. r.pathPrefix = path.Join(r.baseURL.Path, path.Join(segments...))
  245. if len(segments) == 1 && (len(r.baseURL.Path) > 1 || len(segments[0]) > 1) && strings.HasSuffix(segments[0], "/") {
  246. // preserve any trailing slashes for legacy behavior
  247. r.pathPrefix += "/"
  248. }
  249. return r
  250. }
  251. // RequestURI overwrites existing path and parameters with the value of the provided server relative
  252. // URI.
  253. func (r *Request) RequestURI(uri string) *Request {
  254. if r.err != nil {
  255. return r
  256. }
  257. locator, err := url.Parse(uri)
  258. if err != nil {
  259. r.err = err
  260. return r
  261. }
  262. r.pathPrefix = locator.Path
  263. if len(locator.Query()) > 0 {
  264. if r.params == nil {
  265. r.params = make(url.Values)
  266. }
  267. for k, v := range locator.Query() {
  268. r.params[k] = v
  269. }
  270. }
  271. return r
  272. }
  273. // Param creates a query parameter with the given string value.
  274. func (r *Request) Param(paramName, s string) *Request {
  275. if r.err != nil {
  276. return r
  277. }
  278. return r.setParam(paramName, s)
  279. }
  280. // VersionedParams will take the provided object, serialize it to a map[string][]string using the
  281. // implicit RESTClient API version and the default parameter codec, and then add those as parameters
  282. // to the request. Use this to provide versioned query parameters from client libraries.
  283. // VersionedParams will not write query parameters that have omitempty set and are empty. If a
  284. // parameter has already been set it is appended to (Params and VersionedParams are additive).
  285. func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request {
  286. return r.SpecificallyVersionedParams(obj, codec, *r.content.GroupVersion)
  287. }
  288. func (r *Request) SpecificallyVersionedParams(obj runtime.Object, codec runtime.ParameterCodec, version schema.GroupVersion) *Request {
  289. if r.err != nil {
  290. return r
  291. }
  292. params, err := codec.EncodeParameters(obj, version)
  293. if err != nil {
  294. r.err = err
  295. return r
  296. }
  297. for k, v := range params {
  298. if r.params == nil {
  299. r.params = make(url.Values)
  300. }
  301. r.params[k] = append(r.params[k], v...)
  302. }
  303. return r
  304. }
  305. func (r *Request) setParam(paramName, value string) *Request {
  306. if r.params == nil {
  307. r.params = make(url.Values)
  308. }
  309. r.params[paramName] = append(r.params[paramName], value)
  310. return r
  311. }
  312. func (r *Request) SetHeader(key string, values ...string) *Request {
  313. if r.headers == nil {
  314. r.headers = http.Header{}
  315. }
  316. r.headers.Del(key)
  317. for _, value := range values {
  318. r.headers.Add(key, value)
  319. }
  320. return r
  321. }
  322. // Timeout makes the request use the given duration as an overall timeout for the
  323. // request. Additionally, if set passes the value as "timeout" parameter in URL.
  324. func (r *Request) Timeout(d time.Duration) *Request {
  325. if r.err != nil {
  326. return r
  327. }
  328. r.timeout = d
  329. return r
  330. }
  331. // Body makes the request use obj as the body. Optional.
  332. // If obj is a string, try to read a file of that name.
  333. // If obj is a []byte, send it directly.
  334. // If obj is an io.Reader, use it directly.
  335. // If obj is a runtime.Object, marshal it correctly, and set Content-Type header.
  336. // If obj is a runtime.Object and nil, do nothing.
  337. // Otherwise, set an error.
  338. func (r *Request) Body(obj interface{}) *Request {
  339. if r.err != nil {
  340. return r
  341. }
  342. switch t := obj.(type) {
  343. case string:
  344. data, err := ioutil.ReadFile(t)
  345. if err != nil {
  346. r.err = err
  347. return r
  348. }
  349. glogBody("Request Body", data)
  350. r.body = bytes.NewReader(data)
  351. case []byte:
  352. glogBody("Request Body", t)
  353. r.body = bytes.NewReader(t)
  354. case io.Reader:
  355. r.body = t
  356. case runtime.Object:
  357. // callers may pass typed interface pointers, therefore we must check nil with reflection
  358. if reflect.ValueOf(t).IsNil() {
  359. return r
  360. }
  361. data, err := runtime.Encode(r.serializers.Encoder, t)
  362. if err != nil {
  363. r.err = err
  364. return r
  365. }
  366. glogBody("Request Body", data)
  367. r.body = bytes.NewReader(data)
  368. r.SetHeader("Content-Type", r.content.ContentType)
  369. default:
  370. r.err = fmt.Errorf("unknown type used for body: %+v", obj)
  371. }
  372. return r
  373. }
  374. // Context adds a context to the request. Contexts are only used for
  375. // timeouts, deadlines, and cancellations.
  376. func (r *Request) Context(ctx context.Context) *Request {
  377. r.ctx = ctx
  378. return r
  379. }
  380. // URL returns the current working URL.
  381. func (r *Request) URL() *url.URL {
  382. p := r.pathPrefix
  383. if r.namespaceSet && len(r.namespace) > 0 {
  384. p = path.Join(p, "namespaces", r.namespace)
  385. }
  386. if len(r.resource) != 0 {
  387. p = path.Join(p, strings.ToLower(r.resource))
  388. }
  389. // Join trims trailing slashes, so preserve r.pathPrefix's trailing slash for backwards compatibility if nothing was changed
  390. if len(r.resourceName) != 0 || len(r.subpath) != 0 || len(r.subresource) != 0 {
  391. p = path.Join(p, r.resourceName, r.subresource, r.subpath)
  392. }
  393. finalURL := &url.URL{}
  394. if r.baseURL != nil {
  395. *finalURL = *r.baseURL
  396. }
  397. finalURL.Path = p
  398. query := url.Values{}
  399. for key, values := range r.params {
  400. for _, value := range values {
  401. query.Add(key, value)
  402. }
  403. }
  404. // timeout is handled specially here.
  405. if r.timeout != 0 {
  406. query.Set("timeout", r.timeout.String())
  407. }
  408. finalURL.RawQuery = query.Encode()
  409. return finalURL
  410. }
  411. // finalURLTemplate is similar to URL(), but will make all specific parameter values equal
  412. // - instead of name or namespace, "{name}" and "{namespace}" will be used, and all query
  413. // parameters will be reset. This creates a copy of the request so as not to change the
  414. // underlying object. This means some useful request info (like the types of field
  415. // selectors in use) will be lost.
  416. // TODO: preserve field selector keys
  417. func (r Request) finalURLTemplate() url.URL {
  418. if len(r.resourceName) != 0 {
  419. r.resourceName = "{name}"
  420. }
  421. if r.namespaceSet && len(r.namespace) != 0 {
  422. r.namespace = "{namespace}"
  423. }
  424. newParams := url.Values{}
  425. v := []string{"{value}"}
  426. for k := range r.params {
  427. newParams[k] = v
  428. }
  429. r.params = newParams
  430. url := r.URL()
  431. return *url
  432. }
  433. func (r *Request) tryThrottle() {
  434. now := time.Now()
  435. if r.throttle != nil {
  436. r.throttle.Accept()
  437. }
  438. if latency := time.Since(now); latency > longThrottleLatency {
  439. glog.V(4).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
  440. }
  441. }
  442. // Watch attempts to begin watching the requested location.
  443. // Returns a watch.Interface, or an error.
  444. func (r *Request) Watch() (watch.Interface, error) {
  445. return r.WatchWithSpecificDecoders(
  446. func(body io.ReadCloser) streaming.Decoder {
  447. framer := r.serializers.Framer.NewFrameReader(body)
  448. return streaming.NewDecoder(framer, r.serializers.StreamingSerializer)
  449. },
  450. r.serializers.Decoder,
  451. )
  452. }
  453. // WatchWithSpecificDecoders attempts to begin watching the requested location with a *different* decoder.
  454. // Turns out that you want one "standard" decoder for the watch event and one "personal" decoder for the content
  455. // Returns a watch.Interface, or an error.
  456. func (r *Request) WatchWithSpecificDecoders(wrapperDecoderFn func(io.ReadCloser) streaming.Decoder, embeddedDecoder runtime.Decoder) (watch.Interface, error) {
  457. // We specifically don't want to rate limit watches, so we
  458. // don't use r.throttle here.
  459. if r.err != nil {
  460. return nil, r.err
  461. }
  462. if r.serializers.Framer == nil {
  463. return nil, fmt.Errorf("watching resources is not possible with this client (content-type: %s)", r.content.ContentType)
  464. }
  465. url := r.URL().String()
  466. req, err := http.NewRequest(r.verb, url, r.body)
  467. if err != nil {
  468. return nil, err
  469. }
  470. if r.ctx != nil {
  471. req = req.WithContext(r.ctx)
  472. }
  473. req.Header = r.headers
  474. client := r.client
  475. if client == nil {
  476. client = http.DefaultClient
  477. }
  478. r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
  479. resp, err := client.Do(req)
  480. updateURLMetrics(r, resp, err)
  481. if r.baseURL != nil {
  482. if err != nil {
  483. r.backoffMgr.UpdateBackoff(r.baseURL, err, 0)
  484. } else {
  485. r.backoffMgr.UpdateBackoff(r.baseURL, err, resp.StatusCode)
  486. }
  487. }
  488. if err != nil {
  489. // The watch stream mechanism handles many common partial data errors, so closed
  490. // connections can be retried in many cases.
  491. if net.IsProbableEOF(err) {
  492. return watch.NewEmptyWatch(), nil
  493. }
  494. return nil, err
  495. }
  496. if resp.StatusCode != http.StatusOK {
  497. defer resp.Body.Close()
  498. if result := r.transformResponse(resp, req); result.err != nil {
  499. return nil, result.err
  500. }
  501. return nil, fmt.Errorf("for request '%+v', got status: %v", url, resp.StatusCode)
  502. }
  503. wrapperDecoder := wrapperDecoderFn(resp.Body)
  504. return watch.NewStreamWatcher(restclientwatch.NewDecoder(wrapperDecoder, embeddedDecoder)), nil
  505. }
  506. // updateURLMetrics is a convenience function for pushing metrics.
  507. // It also handles corner cases for incomplete/invalid request data.
  508. func updateURLMetrics(req *Request, resp *http.Response, err error) {
  509. url := "none"
  510. if req.baseURL != nil {
  511. url = req.baseURL.Host
  512. }
  513. // Errors can be arbitrary strings. Unbound label cardinality is not suitable for a metric
  514. // system so we just report them as `<error>`.
  515. if err != nil {
  516. metrics.RequestResult.Increment("<error>", req.verb, url)
  517. } else {
  518. //Metrics for failure codes
  519. metrics.RequestResult.Increment(strconv.Itoa(resp.StatusCode), req.verb, url)
  520. }
  521. }
  522. // Stream formats and executes the request, and offers streaming of the response.
  523. // Returns io.ReadCloser which could be used for streaming of the response, or an error
  524. // Any non-2xx http status code causes an error. If we get a non-2xx code, we try to convert the body into an APIStatus object.
  525. // If we can, we return that as an error. Otherwise, we create an error that lists the http status and the content of the response.
  526. func (r *Request) Stream() (io.ReadCloser, error) {
  527. if r.err != nil {
  528. return nil, r.err
  529. }
  530. r.tryThrottle()
  531. url := r.URL().String()
  532. req, err := http.NewRequest(r.verb, url, nil)
  533. if err != nil {
  534. return nil, err
  535. }
  536. if r.ctx != nil {
  537. req = req.WithContext(r.ctx)
  538. }
  539. req.Header = r.headers
  540. client := r.client
  541. if client == nil {
  542. client = http.DefaultClient
  543. }
  544. r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
  545. resp, err := client.Do(req)
  546. updateURLMetrics(r, resp, err)
  547. if r.baseURL != nil {
  548. if err != nil {
  549. r.backoffMgr.UpdateBackoff(r.URL(), err, 0)
  550. } else {
  551. r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode)
  552. }
  553. }
  554. if err != nil {
  555. return nil, err
  556. }
  557. switch {
  558. case (resp.StatusCode >= 200) && (resp.StatusCode < 300):
  559. return resp.Body, nil
  560. default:
  561. // ensure we close the body before returning the error
  562. defer resp.Body.Close()
  563. result := r.transformResponse(resp, req)
  564. err := result.Error()
  565. if err == nil {
  566. err = fmt.Errorf("%d while accessing %v: %s", result.statusCode, url, string(result.body))
  567. }
  568. return nil, err
  569. }
  570. }
  571. // request connects to the server and invokes the provided function when a server response is
  572. // received. It handles retry behavior and up front validation of requests. It will invoke
  573. // fn at most once. It will return an error if a problem occurred prior to connecting to the
  574. // server - the provided function is responsible for handling server errors.
  575. func (r *Request) request(fn func(*http.Request, *http.Response)) error {
  576. //Metrics for total request latency
  577. start := time.Now()
  578. defer func() {
  579. metrics.RequestLatency.Observe(r.verb, r.finalURLTemplate(), time.Since(start))
  580. }()
  581. if r.err != nil {
  582. glog.V(4).Infof("Error in request: %v", r.err)
  583. return r.err
  584. }
  585. // TODO: added to catch programmer errors (invoking operations with an object with an empty namespace)
  586. if (r.verb == "GET" || r.verb == "PUT" || r.verb == "DELETE") && r.namespaceSet && len(r.resourceName) > 0 && len(r.namespace) == 0 {
  587. return fmt.Errorf("an empty namespace may not be set when a resource name is provided")
  588. }
  589. if (r.verb == "POST") && r.namespaceSet && len(r.namespace) == 0 {
  590. return fmt.Errorf("an empty namespace may not be set during creation")
  591. }
  592. client := r.client
  593. if client == nil {
  594. client = http.DefaultClient
  595. }
  596. // Right now we make about ten retry attempts if we get a Retry-After response.
  597. maxRetries := 10
  598. retries := 0
  599. for {
  600. url := r.URL().String()
  601. req, err := http.NewRequest(r.verb, url, r.body)
  602. if err != nil {
  603. return err
  604. }
  605. if r.timeout > 0 {
  606. if r.ctx == nil {
  607. r.ctx = context.Background()
  608. }
  609. var cancelFn context.CancelFunc
  610. r.ctx, cancelFn = context.WithTimeout(r.ctx, r.timeout)
  611. defer cancelFn()
  612. }
  613. if r.ctx != nil {
  614. req = req.WithContext(r.ctx)
  615. }
  616. req.Header = r.headers
  617. r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
  618. if retries > 0 {
  619. // We are retrying the request that we already send to apiserver
  620. // at least once before.
  621. // This request should also be throttled with the client-internal throttler.
  622. r.tryThrottle()
  623. }
  624. resp, err := client.Do(req)
  625. updateURLMetrics(r, resp, err)
  626. if err != nil {
  627. r.backoffMgr.UpdateBackoff(r.URL(), err, 0)
  628. } else {
  629. r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode)
  630. }
  631. if err != nil {
  632. // "Connection reset by peer" is usually a transient error.
  633. // Thus in case of "GET" operations, we simply retry it.
  634. // We are not automatically retrying "write" operations, as
  635. // they are not idempotent.
  636. if !net.IsConnectionReset(err) || r.verb != "GET" {
  637. return err
  638. }
  639. // For the purpose of retry, we set the artificial "retry-after" response.
  640. // TODO: Should we clean the original response if it exists?
  641. resp = &http.Response{
  642. StatusCode: http.StatusInternalServerError,
  643. Header: http.Header{"Retry-After": []string{"1"}},
  644. Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
  645. }
  646. }
  647. done := func() bool {
  648. // Ensure the response body is fully read and closed
  649. // before we reconnect, so that we reuse the same TCP
  650. // connection.
  651. defer func() {
  652. const maxBodySlurpSize = 2 << 10
  653. if resp.ContentLength <= maxBodySlurpSize {
  654. io.Copy(ioutil.Discard, &io.LimitedReader{R: resp.Body, N: maxBodySlurpSize})
  655. }
  656. resp.Body.Close()
  657. }()
  658. retries++
  659. if seconds, wait := checkWait(resp); wait && retries < maxRetries {
  660. if seeker, ok := r.body.(io.Seeker); ok && r.body != nil {
  661. _, err := seeker.Seek(0, 0)
  662. if err != nil {
  663. glog.V(4).Infof("Could not retry request, can't Seek() back to beginning of body for %T", r.body)
  664. fn(req, resp)
  665. return true
  666. }
  667. }
  668. glog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", seconds, retries, url)
  669. r.backoffMgr.Sleep(time.Duration(seconds) * time.Second)
  670. return false
  671. }
  672. fn(req, resp)
  673. return true
  674. }()
  675. if done {
  676. return nil
  677. }
  678. }
  679. }
  680. // Do formats and executes the request. Returns a Result object for easy response
  681. // processing.
  682. //
  683. // Error type:
  684. // * If the request can't be constructed, or an error happened earlier while building its
  685. // arguments: *RequestConstructionError
  686. // * If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError
  687. // * http.Client.Do errors are returned directly.
  688. func (r *Request) Do() Result {
  689. r.tryThrottle()
  690. var result Result
  691. err := r.request(func(req *http.Request, resp *http.Response) {
  692. result = r.transformResponse(resp, req)
  693. })
  694. if err != nil {
  695. return Result{err: err}
  696. }
  697. return result
  698. }
  699. // DoRaw executes the request but does not process the response body.
  700. func (r *Request) DoRaw() ([]byte, error) {
  701. r.tryThrottle()
  702. var result Result
  703. err := r.request(func(req *http.Request, resp *http.Response) {
  704. result.body, result.err = ioutil.ReadAll(resp.Body)
  705. glogBody("Response Body", result.body)
  706. if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent {
  707. result.err = r.transformUnstructuredResponseError(resp, req, result.body)
  708. }
  709. })
  710. if err != nil {
  711. return nil, err
  712. }
  713. return result.body, result.err
  714. }
  715. // transformResponse converts an API response into a structured API object
  716. func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result {
  717. var body []byte
  718. if resp.Body != nil {
  719. data, err := ioutil.ReadAll(resp.Body)
  720. switch err.(type) {
  721. case nil:
  722. body = data
  723. case http2.StreamError:
  724. // This is trying to catch the scenario that the server may close the connection when sending the
  725. // response body. This can be caused by server timeout due to a slow network connection.
  726. // TODO: Add test for this. Steps may be:
  727. // 1. client-go (or kubectl) sends a GET request.
  728. // 2. Apiserver sends back the headers and then part of the body
  729. // 3. Apiserver closes connection.
  730. // 4. client-go should catch this and return an error.
  731. glog.V(2).Infof("Stream error %#v when reading response body, may be caused by closed connection.", err)
  732. streamErr := fmt.Errorf("Stream error %#v when reading response body, may be caused by closed connection. Please retry.", err)
  733. return Result{
  734. err: streamErr,
  735. }
  736. default:
  737. glog.Errorf("Unexpected error when reading response body: %#v", err)
  738. unexpectedErr := fmt.Errorf("Unexpected error %#v when reading response body. Please retry.", err)
  739. return Result{
  740. err: unexpectedErr,
  741. }
  742. }
  743. }
  744. glogBody("Response Body", body)
  745. // verify the content type is accurate
  746. contentType := resp.Header.Get("Content-Type")
  747. decoder := r.serializers.Decoder
  748. if len(contentType) > 0 && (decoder == nil || (len(r.content.ContentType) > 0 && contentType != r.content.ContentType)) {
  749. mediaType, params, err := mime.ParseMediaType(contentType)
  750. if err != nil {
  751. return Result{err: errors.NewInternalError(err)}
  752. }
  753. decoder, err = r.serializers.RenegotiatedDecoder(mediaType, params)
  754. if err != nil {
  755. // if we fail to negotiate a decoder, treat this as an unstructured error
  756. switch {
  757. case resp.StatusCode == http.StatusSwitchingProtocols:
  758. // no-op, we've been upgraded
  759. case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent:
  760. return Result{err: r.transformUnstructuredResponseError(resp, req, body)}
  761. }
  762. return Result{
  763. body: body,
  764. contentType: contentType,
  765. statusCode: resp.StatusCode,
  766. }
  767. }
  768. }
  769. switch {
  770. case resp.StatusCode == http.StatusSwitchingProtocols:
  771. // no-op, we've been upgraded
  772. case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent:
  773. // calculate an unstructured error from the response which the Result object may use if the caller
  774. // did not return a structured error.
  775. retryAfter, _ := retryAfterSeconds(resp)
  776. err := r.newUnstructuredResponseError(body, isTextResponse(resp), resp.StatusCode, req.Method, retryAfter)
  777. return Result{
  778. body: body,
  779. contentType: contentType,
  780. statusCode: resp.StatusCode,
  781. decoder: decoder,
  782. err: err,
  783. }
  784. }
  785. return Result{
  786. body: body,
  787. contentType: contentType,
  788. statusCode: resp.StatusCode,
  789. decoder: decoder,
  790. }
  791. }
  792. // truncateBody decides if the body should be truncated, based on the glog Verbosity.
  793. func truncateBody(body string) string {
  794. max := 0
  795. switch {
  796. case bool(glog.V(10)):
  797. return body
  798. case bool(glog.V(9)):
  799. max = 10240
  800. case bool(glog.V(8)):
  801. max = 1024
  802. }
  803. if len(body) <= max {
  804. return body
  805. }
  806. return body[:max] + fmt.Sprintf(" [truncated %d chars]", len(body)-max)
  807. }
  808. // glogBody logs a body output that could be either JSON or protobuf. It explicitly guards against
  809. // allocating a new string for the body output unless necessary. Uses a simple heuristic to determine
  810. // whether the body is printable.
  811. func glogBody(prefix string, body []byte) {
  812. if glog.V(8) {
  813. if bytes.IndexFunc(body, func(r rune) bool {
  814. return r < 0x0a
  815. }) != -1 {
  816. glog.Infof("%s:\n%s", prefix, truncateBody(hex.Dump(body)))
  817. } else {
  818. glog.Infof("%s: %s", prefix, truncateBody(string(body)))
  819. }
  820. }
  821. }
  822. // maxUnstructuredResponseTextBytes is an upper bound on how much output to include in the unstructured error.
  823. const maxUnstructuredResponseTextBytes = 2048
  824. // transformUnstructuredResponseError handles an error from the server that is not in a structured form.
  825. // It is expected to transform any response that is not recognizable as a clear server sent error from the
  826. // K8S API using the information provided with the request. In practice, HTTP proxies and client libraries
  827. // introduce a level of uncertainty to the responses returned by servers that in common use result in
  828. // unexpected responses. The rough structure is:
  829. //
  830. // 1. Assume the server sends you something sane - JSON + well defined error objects + proper codes
  831. // - this is the happy path
  832. // - when you get this output, trust what the server sends
  833. // 2. Guard against empty fields / bodies in received JSON and attempt to cull sufficient info from them to
  834. // generate a reasonable facsimile of the original failure.
  835. // - Be sure to use a distinct error type or flag that allows a client to distinguish between this and error 1 above
  836. // 3. Handle true disconnect failures / completely malformed data by moving up to a more generic client error
  837. // 4. Distinguish between various connection failures like SSL certificates, timeouts, proxy errors, unexpected
  838. // initial contact, the presence of mismatched body contents from posted content types
  839. // - Give these a separate distinct error type and capture as much as possible of the original message
  840. //
  841. // TODO: introduce transformation of generic http.Client.Do() errors that separates 4.
  842. func (r *Request) transformUnstructuredResponseError(resp *http.Response, req *http.Request, body []byte) error {
  843. if body == nil && resp.Body != nil {
  844. if data, err := ioutil.ReadAll(&io.LimitedReader{R: resp.Body, N: maxUnstructuredResponseTextBytes}); err == nil {
  845. body = data
  846. }
  847. }
  848. retryAfter, _ := retryAfterSeconds(resp)
  849. return r.newUnstructuredResponseError(body, isTextResponse(resp), resp.StatusCode, req.Method, retryAfter)
  850. }
  851. // newUnstructuredResponseError instantiates the appropriate generic error for the provided input. It also logs the body.
  852. func (r *Request) newUnstructuredResponseError(body []byte, isTextResponse bool, statusCode int, method string, retryAfter int) error {
  853. // cap the amount of output we create
  854. if len(body) > maxUnstructuredResponseTextBytes {
  855. body = body[:maxUnstructuredResponseTextBytes]
  856. }
  857. message := "unknown"
  858. if isTextResponse {
  859. message = strings.TrimSpace(string(body))
  860. }
  861. var groupResource schema.GroupResource
  862. if len(r.resource) > 0 {
  863. groupResource.Group = r.content.GroupVersion.Group
  864. groupResource.Resource = r.resource
  865. }
  866. return errors.NewGenericServerResponse(
  867. statusCode,
  868. method,
  869. groupResource,
  870. r.resourceName,
  871. message,
  872. retryAfter,
  873. true,
  874. )
  875. }
  876. // isTextResponse returns true if the response appears to be a textual media type.
  877. func isTextResponse(resp *http.Response) bool {
  878. contentType := resp.Header.Get("Content-Type")
  879. if len(contentType) == 0 {
  880. return true
  881. }
  882. media, _, err := mime.ParseMediaType(contentType)
  883. if err != nil {
  884. return false
  885. }
  886. return strings.HasPrefix(media, "text/")
  887. }
  888. // checkWait returns true along with a number of seconds if the server instructed us to wait
  889. // before retrying.
  890. func checkWait(resp *http.Response) (int, bool) {
  891. switch r := resp.StatusCode; {
  892. // any 500 error code and 429 can trigger a wait
  893. case r == http.StatusTooManyRequests, r >= 500:
  894. default:
  895. return 0, false
  896. }
  897. i, ok := retryAfterSeconds(resp)
  898. return i, ok
  899. }
  900. // retryAfterSeconds returns the value of the Retry-After header and true, or 0 and false if
  901. // the header was missing or not a valid number.
  902. func retryAfterSeconds(resp *http.Response) (int, bool) {
  903. if h := resp.Header.Get("Retry-After"); len(h) > 0 {
  904. if i, err := strconv.Atoi(h); err == nil {
  905. return i, true
  906. }
  907. }
  908. return 0, false
  909. }
  910. // Result contains the result of calling Request.Do().
  911. type Result struct {
  912. body []byte
  913. contentType string
  914. err error
  915. statusCode int
  916. decoder runtime.Decoder
  917. }
  918. // Raw returns the raw result.
  919. func (r Result) Raw() ([]byte, error) {
  920. return r.body, r.err
  921. }
  922. // Get returns the result as an object, which means it passes through the decoder.
  923. // If the returned object is of type Status and has .Status != StatusSuccess, the
  924. // additional information in Status will be used to enrich the error.
  925. func (r Result) Get() (runtime.Object, error) {
  926. if r.err != nil {
  927. // Check whether the result has a Status object in the body and prefer that.
  928. return nil, r.Error()
  929. }
  930. if r.decoder == nil {
  931. return nil, fmt.Errorf("serializer for %s doesn't exist", r.contentType)
  932. }
  933. // decode, but if the result is Status return that as an error instead.
  934. out, _, err := r.decoder.Decode(r.body, nil, nil)
  935. if err != nil {
  936. return nil, err
  937. }
  938. switch t := out.(type) {
  939. case *metav1.Status:
  940. // any status besides StatusSuccess is considered an error.
  941. if t.Status != metav1.StatusSuccess {
  942. return nil, errors.FromObject(t)
  943. }
  944. }
  945. return out, nil
  946. }
  947. // StatusCode returns the HTTP status code of the request. (Only valid if no
  948. // error was returned.)
  949. func (r Result) StatusCode(statusCode *int) Result {
  950. *statusCode = r.statusCode
  951. return r
  952. }
  953. // Into stores the result into obj, if possible. If obj is nil it is ignored.
  954. // If the returned object is of type Status and has .Status != StatusSuccess, the
  955. // additional information in Status will be used to enrich the error.
  956. func (r Result) Into(obj runtime.Object) error {
  957. if r.err != nil {
  958. // Check whether the result has a Status object in the body and prefer that.
  959. return r.Error()
  960. }
  961. if r.decoder == nil {
  962. return fmt.Errorf("serializer for %s doesn't exist", r.contentType)
  963. }
  964. if len(r.body) == 0 {
  965. return fmt.Errorf("0-length response")
  966. }
  967. out, _, err := r.decoder.Decode(r.body, nil, obj)
  968. if err != nil || out == obj {
  969. return err
  970. }
  971. // if a different object is returned, see if it is Status and avoid double decoding
  972. // the object.
  973. switch t := out.(type) {
  974. case *metav1.Status:
  975. // any status besides StatusSuccess is considered an error.
  976. if t.Status != metav1.StatusSuccess {
  977. return errors.FromObject(t)
  978. }
  979. }
  980. return nil
  981. }
  982. // WasCreated updates the provided bool pointer to whether the server returned
  983. // 201 created or a different response.
  984. func (r Result) WasCreated(wasCreated *bool) Result {
  985. *wasCreated = r.statusCode == http.StatusCreated
  986. return r
  987. }
  988. // Error returns the error executing the request, nil if no error occurred.
  989. // If the returned object is of type Status and has Status != StatusSuccess, the
  990. // additional information in Status will be used to enrich the error.
  991. // See the Request.Do() comment for what errors you might get.
  992. func (r Result) Error() error {
  993. // if we have received an unexpected server error, and we have a body and decoder, we can try to extract
  994. // a Status object.
  995. if r.err == nil || !errors.IsUnexpectedServerError(r.err) || len(r.body) == 0 || r.decoder == nil {
  996. return r.err
  997. }
  998. // attempt to convert the body into a Status object
  999. // to be backwards compatible with old servers that do not return a version, default to "v1"
  1000. out, _, err := r.decoder.Decode(r.body, &schema.GroupVersionKind{Version: "v1"}, nil)
  1001. if err != nil {
  1002. glog.V(5).Infof("body was not decodable (unable to check for Status): %v", err)
  1003. return r.err
  1004. }
  1005. switch t := out.(type) {
  1006. case *metav1.Status:
  1007. // because we default the kind, we *must* check for StatusFailure
  1008. if t.Status == metav1.StatusFailure {
  1009. return errors.FromObject(t)
  1010. }
  1011. }
  1012. return r.err
  1013. }
  1014. // NameMayNotBe specifies strings that cannot be used as names specified as path segments (like the REST API or etcd store)
  1015. var NameMayNotBe = []string{".", ".."}
  1016. // NameMayNotContain specifies substrings that cannot be used in names specified as path segments (like the REST API or etcd store)
  1017. var NameMayNotContain = []string{"/", "%"}
  1018. // IsValidPathSegmentName validates the name can be safely encoded as a path segment
  1019. func IsValidPathSegmentName(name string) []string {
  1020. for _, illegalName := range NameMayNotBe {
  1021. if name == illegalName {
  1022. return []string{fmt.Sprintf(`may not be '%s'`, illegalName)}
  1023. }
  1024. }
  1025. var errors []string
  1026. for _, illegalContent := range NameMayNotContain {
  1027. if strings.Contains(name, illegalContent) {
  1028. errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
  1029. }
  1030. }
  1031. return errors
  1032. }
  1033. // IsValidPathSegmentPrefix validates the name can be used as a prefix for a name which will be encoded as a path segment
  1034. // It does not check for exact matches with disallowed names, since an arbitrary suffix might make the name valid
  1035. func IsValidPathSegmentPrefix(name string) []string {
  1036. var errors []string
  1037. for _, illegalContent := range NameMayNotContain {
  1038. if strings.Contains(name, illegalContent) {
  1039. errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
  1040. }
  1041. }
  1042. return errors
  1043. }
  1044. // ValidatePathSegmentName validates the name can be safely encoded as a path segment
  1045. func ValidatePathSegmentName(name string, prefix bool) []string {
  1046. if prefix {
  1047. return IsValidPathSegmentPrefix(name)
  1048. } else {
  1049. return IsValidPathSegmentName(name)
  1050. }
  1051. }