subresources.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. "context"
  16. "fmt"
  17. "net/http"
  18. "net/url"
  19. "k8s.io/apimachinery/pkg/runtime"
  20. "k8s.io/apimachinery/pkg/util/net"
  21. "k8s.io/apimachinery/pkg/util/proxy"
  22. genericfeatures "k8s.io/apiserver/pkg/features"
  23. genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
  24. "k8s.io/apiserver/pkg/registry/rest"
  25. utilfeature "k8s.io/apiserver/pkg/util/feature"
  26. api "k8s.io/kubernetes/pkg/apis/core"
  27. "k8s.io/kubernetes/pkg/capabilities"
  28. "k8s.io/kubernetes/pkg/kubelet/client"
  29. "k8s.io/kubernetes/pkg/registry/core/pod"
  30. )
  31. // ProxyREST implements the proxy subresource for a Pod
  32. type ProxyREST struct {
  33. Store *genericregistry.Store
  34. ProxyTransport http.RoundTripper
  35. }
  36. // Implement Connecter
  37. var _ = rest.Connecter(&ProxyREST{})
  38. var proxyMethods = []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}
  39. // New returns an empty podProxyOptions object.
  40. func (r *ProxyREST) New() runtime.Object {
  41. return &api.PodProxyOptions{}
  42. }
  43. // ConnectMethods returns the list of HTTP methods that can be proxied
  44. func (r *ProxyREST) ConnectMethods() []string {
  45. return proxyMethods
  46. }
  47. // NewConnectOptions returns versioned resource that represents proxy parameters
  48. func (r *ProxyREST) NewConnectOptions() (runtime.Object, bool, string) {
  49. return &api.PodProxyOptions{}, true, "path"
  50. }
  51. // Connect returns a handler for the pod proxy
  52. func (r *ProxyREST) Connect(ctx context.Context, id string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
  53. proxyOpts, ok := opts.(*api.PodProxyOptions)
  54. if !ok {
  55. return nil, fmt.Errorf("Invalid options object: %#v", opts)
  56. }
  57. location, transport, err := pod.ResourceLocation(r.Store, r.ProxyTransport, ctx, id)
  58. if err != nil {
  59. return nil, err
  60. }
  61. location.Path = net.JoinPreservingTrailingSlash(location.Path, proxyOpts.Path)
  62. // Return a proxy handler that uses the desired transport, wrapped with additional proxy handling (to get URL rewriting, X-Forwarded-* headers, etc)
  63. return newThrottledUpgradeAwareProxyHandler(location, transport, true, false, false, responder), nil
  64. }
  65. // Support both GET and POST methods. We must support GET for browsers that want to use WebSockets.
  66. var upgradeableMethods = []string{"GET", "POST"}
  67. // AttachREST implements the attach subresource for a Pod
  68. type AttachREST struct {
  69. Store *genericregistry.Store
  70. KubeletConn client.ConnectionInfoGetter
  71. }
  72. // Implement Connecter
  73. var _ = rest.Connecter(&AttachREST{})
  74. // New creates a new podAttachOptions object.
  75. func (r *AttachREST) New() runtime.Object {
  76. return &api.PodAttachOptions{}
  77. }
  78. // Connect returns a handler for the pod exec proxy
  79. func (r *AttachREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
  80. attachOpts, ok := opts.(*api.PodAttachOptions)
  81. if !ok {
  82. return nil, fmt.Errorf("Invalid options object: %#v", opts)
  83. }
  84. location, transport, err := pod.AttachLocation(r.Store, r.KubeletConn, ctx, name, attachOpts)
  85. if err != nil {
  86. return nil, err
  87. }
  88. return newThrottledUpgradeAwareProxyHandler(location, transport, false, true, true, responder), nil
  89. }
  90. // NewConnectOptions returns the versioned object that represents exec parameters
  91. func (r *AttachREST) NewConnectOptions() (runtime.Object, bool, string) {
  92. return &api.PodAttachOptions{}, false, ""
  93. }
  94. // ConnectMethods returns the methods supported by exec
  95. func (r *AttachREST) ConnectMethods() []string {
  96. return upgradeableMethods
  97. }
  98. // ExecREST implements the exec subresource for a Pod
  99. type ExecREST struct {
  100. Store *genericregistry.Store
  101. KubeletConn client.ConnectionInfoGetter
  102. }
  103. // Implement Connecter
  104. var _ = rest.Connecter(&ExecREST{})
  105. // New creates a new podExecOptions object.
  106. func (r *ExecREST) New() runtime.Object {
  107. return &api.PodExecOptions{}
  108. }
  109. // Connect returns a handler for the pod exec proxy
  110. func (r *ExecREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
  111. execOpts, ok := opts.(*api.PodExecOptions)
  112. if !ok {
  113. return nil, fmt.Errorf("invalid options object: %#v", opts)
  114. }
  115. location, transport, err := pod.ExecLocation(r.Store, r.KubeletConn, ctx, name, execOpts)
  116. if err != nil {
  117. return nil, err
  118. }
  119. return newThrottledUpgradeAwareProxyHandler(location, transport, false, true, true, responder), nil
  120. }
  121. // NewConnectOptions returns the versioned object that represents exec parameters
  122. func (r *ExecREST) NewConnectOptions() (runtime.Object, bool, string) {
  123. return &api.PodExecOptions{}, false, ""
  124. }
  125. // ConnectMethods returns the methods supported by exec
  126. func (r *ExecREST) ConnectMethods() []string {
  127. return upgradeableMethods
  128. }
  129. // PortForwardREST implements the portforward subresource for a Pod
  130. type PortForwardREST struct {
  131. Store *genericregistry.Store
  132. KubeletConn client.ConnectionInfoGetter
  133. }
  134. // Implement Connecter
  135. var _ = rest.Connecter(&PortForwardREST{})
  136. // New returns an empty podPortForwardOptions object
  137. func (r *PortForwardREST) New() runtime.Object {
  138. return &api.PodPortForwardOptions{}
  139. }
  140. // NewConnectOptions returns the versioned object that represents the
  141. // portforward parameters
  142. func (r *PortForwardREST) NewConnectOptions() (runtime.Object, bool, string) {
  143. return &api.PodPortForwardOptions{}, false, ""
  144. }
  145. // ConnectMethods returns the methods supported by portforward
  146. func (r *PortForwardREST) ConnectMethods() []string {
  147. return upgradeableMethods
  148. }
  149. // Connect returns a handler for the pod portforward proxy
  150. func (r *PortForwardREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
  151. portForwardOpts, ok := opts.(*api.PodPortForwardOptions)
  152. if !ok {
  153. return nil, fmt.Errorf("invalid options object: %#v", opts)
  154. }
  155. location, transport, err := pod.PortForwardLocation(r.Store, r.KubeletConn, ctx, name, portForwardOpts)
  156. if err != nil {
  157. return nil, err
  158. }
  159. return newThrottledUpgradeAwareProxyHandler(location, transport, false, true, true, responder), nil
  160. }
  161. func newThrottledUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, wrapTransport, upgradeRequired, interceptRedirects bool, responder rest.Responder) *proxy.UpgradeAwareHandler {
  162. handler := proxy.NewUpgradeAwareHandler(location, transport, wrapTransport, upgradeRequired, proxy.NewErrorResponder(responder))
  163. handler.InterceptRedirects = interceptRedirects && utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StreamingProxyRedirects)
  164. handler.RequireSameHostRedirects = utilfeature.DefaultFeatureGate.Enabled(genericfeatures.ValidateProxyRedirects)
  165. handler.MaxBytesPerSec = capabilities.Get().PerConnectionBandwidthLimitBytesPerSec
  166. return handler
  167. }