Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
aee9bdd6
Commit
aee9bdd6
authored
Mar 24, 2015
by
Clayton Coleman
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5805 from liggitt/node_proxy
Improve ResourceLocation API, allow proxy to use authenticated transport
parents
9524e71b
a75b5018
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
247 additions
and
72 deletions
+247
-72
integration.go
cmd/integration/integration.go
+4
-0
rest.go
pkg/api/rest/rest.go
+5
-2
apiserver_test.go
pkg/apiserver/apiserver_test.go
+11
-5
proxy.go
pkg/apiserver/proxy.go
+89
-26
proxy_test.go
pkg/apiserver/proxy_test.go
+4
-2
redirect.go
pkg/apiserver/redirect.go
+13
-3
redirect_test.go
pkg/apiserver/redirect_test.go
+2
-2
kubelet.go
pkg/client/kubelet.go
+17
-0
nodecontroller_test.go
pkg/cloudprovider/controller/nodecontroller_test.go
+5
-0
master.go
pkg/master/master.go
+1
-1
rest.go
pkg/registry/minion/rest.go
+28
-8
rest_test.go
pkg/registry/minion/rest_test.go
+12
-4
etcd.go
pkg/registry/pod/etcd/etcd.go
+6
-1
etcd_test.go
pkg/registry/pod/etcd/etcd_test.go
+9
-3
rest.go
pkg/registry/pod/rest.go
+13
-8
rest.go
pkg/registry/service/rest.go
+11
-4
rest_test.go
pkg/registry/service/rest_test.go
+6
-3
httpstream.go
pkg/util/httpstream/httpstream.go
+11
-0
No files found.
cmd/integration/integration.go
View file @
aee9bdd6
...
@@ -106,6 +106,10 @@ func (fakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
...
@@ -106,6 +106,10 @@ func (fakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
return
api
.
NodeInfo
{},
nil
return
api
.
NodeInfo
{},
nil
}
}
func
(
fakeKubeletClient
)
GetConnectionInfo
(
host
string
)
(
string
,
uint
,
http
.
RoundTripper
,
error
)
{
return
""
,
0
,
nil
,
errors
.
New
(
"Not Implemented"
)
}
func
(
fakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
func
(
fakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
return
probe
.
Success
,
nil
return
probe
.
Success
,
nil
}
}
...
...
pkg/api/rest/rest.go
View file @
aee9bdd6
...
@@ -17,6 +17,9 @@ limitations under the License.
...
@@ -17,6 +17,9 @@ limitations under the License.
package
rest
package
rest
import
(
import
(
"net/http"
"net/url"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
...
@@ -142,6 +145,6 @@ type StandardStorage interface {
...
@@ -142,6 +145,6 @@ type StandardStorage interface {
// Redirector know how to return a remote resource's location.
// Redirector know how to return a remote resource's location.
type
Redirector
interface
{
type
Redirector
interface
{
// ResourceLocation should return the remote location of the given resource, or an error.
// ResourceLocation should return the remote location of the given resource,
and an optional transport to use to request it,
or an error.
ResourceLocation
(
ctx
api
.
Context
,
name
string
)
(
remoteLocation
string
,
err
error
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
remoteLocation
*
url
.
URL
,
transport
http
.
RoundTripper
,
err
error
)
}
}
pkg/apiserver/apiserver_test.go
View file @
aee9bdd6
...
@@ -24,6 +24,7 @@ import (
...
@@ -24,6 +24,7 @@ import (
"io/ioutil"
"io/ioutil"
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"net/url"
"reflect"
"reflect"
"strings"
"strings"
"sync"
"sync"
...
@@ -226,7 +227,7 @@ type SimpleRESTStorage struct {
...
@@ -226,7 +227,7 @@ type SimpleRESTStorage struct {
// The id requested, and location to return for ResourceLocation
// The id requested, and location to return for ResourceLocation
requestedResourceLocationID
string
requestedResourceLocationID
string
resourceLocation
string
resourceLocation
*
url
.
URL
expectedResourceNamespace
string
expectedResourceNamespace
string
// If non-nil, called inside the WorkFunc when answering update, delete, create.
// If non-nil, called inside the WorkFunc when answering update, delete, create.
...
@@ -315,18 +316,23 @@ func (storage *SimpleRESTStorage) Watch(ctx api.Context, label labels.Selector,
...
@@ -315,18 +316,23 @@ func (storage *SimpleRESTStorage) Watch(ctx api.Context, label labels.Selector,
}
}
// Implement Redirector.
// Implement Redirector.
func
(
storage
*
SimpleRESTStorage
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
string
,
error
)
{
var
_
=
rest
.
Redirector
(
&
SimpleRESTStorage
{})
// Implement Redirector.
func
(
storage
*
SimpleRESTStorage
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
*
url
.
URL
,
http
.
RoundTripper
,
error
)
{
storage
.
checkContext
(
ctx
)
storage
.
checkContext
(
ctx
)
// validate that the namespace context on the request matches the expected input
// validate that the namespace context on the request matches the expected input
storage
.
requestedResourceNamespace
=
api
.
NamespaceValue
(
ctx
)
storage
.
requestedResourceNamespace
=
api
.
NamespaceValue
(
ctx
)
if
storage
.
expectedResourceNamespace
!=
storage
.
requestedResourceNamespace
{
if
storage
.
expectedResourceNamespace
!=
storage
.
requestedResourceNamespace
{
return
""
,
fmt
.
Errorf
(
"Expected request namespace %s, but got namespace %s"
,
storage
.
expectedResourceNamespace
,
storage
.
requestedResourceNamespace
)
return
nil
,
nil
,
fmt
.
Errorf
(
"Expected request namespace %s, but got namespace %s"
,
storage
.
expectedResourceNamespace
,
storage
.
requestedResourceNamespace
)
}
}
storage
.
requestedResourceLocationID
=
id
storage
.
requestedResourceLocationID
=
id
if
err
:=
storage
.
errors
[
"resourceLocation"
];
err
!=
nil
{
if
err
:=
storage
.
errors
[
"resourceLocation"
];
err
!=
nil
{
return
""
,
err
return
nil
,
nil
,
err
}
}
return
storage
.
resourceLocation
,
nil
// Make a copy so the internal URL never gets mutated
locationCopy
:=
*
storage
.
resourceLocation
return
&
locationCopy
,
nil
,
nil
}
}
type
LegacyRESTStorage
struct
{
type
LegacyRESTStorage
struct
{
...
...
pkg/apiserver/proxy.go
View file @
aee9bdd6
...
@@ -19,6 +19,7 @@ package apiserver
...
@@ -19,6 +19,7 @@ package apiserver
import
(
import
(
"bytes"
"bytes"
"compress/gzip"
"compress/gzip"
"crypto/tls"
"fmt"
"fmt"
"io"
"io"
"io/ioutil"
"io/ioutil"
...
@@ -140,7 +141,7 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -140,7 +141,7 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
return
}
}
location
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
id
)
location
,
transport
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
id
)
if
err
!=
nil
{
if
err
!=
nil
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"Error getting ResourceLocation: %v"
,
err
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"Error getting ResourceLocation: %v"
,
err
)
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
...
@@ -148,22 +149,31 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -148,22 +149,31 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
httpCode
=
status
.
Code
httpCode
=
status
.
Code
return
return
}
}
if
location
==
nil
{
destURL
,
err
:=
url
.
Parse
(
location
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"ResourceLocation for %v returned nil"
,
id
)
if
err
!=
nil
{
notFound
(
w
,
req
)
status
:=
errToAPIStatus
(
err
)
httpCode
=
http
.
StatusNotFound
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
httpCode
=
status
.
Code
return
return
}
}
if
destURL
.
Scheme
==
""
{
// If no scheme was present in location, url.Parse sometimes mistakes
// Default to http
// hosts for paths.
if
location
.
Scheme
==
""
{
destURL
.
Host
=
location
location
.
Scheme
=
"http"
}
}
destURL
.
Path
=
remainder
// Add the subpath
destURL
.
RawQuery
=
req
.
URL
.
RawQuery
if
len
(
remainder
)
>
0
{
newReq
,
err
:=
http
.
NewRequest
(
req
.
Method
,
destURL
.
String
(),
req
.
Body
)
location
.
Path
=
singleJoiningSlash
(
location
.
Path
,
remainder
)
}
// Start with anything returned from the storage, and add the original request's parameters
values
:=
location
.
Query
()
for
k
,
vs
:=
range
req
.
URL
.
Query
()
{
for
_
,
v
:=
range
vs
{
values
.
Add
(
k
,
v
)
}
}
location
.
RawQuery
=
values
.
Encode
()
newReq
,
err
:=
http
.
NewRequest
(
req
.
Method
,
location
.
String
(),
req
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
...
@@ -177,29 +187,34 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -177,29 +187,34 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO convert this entire proxy to an UpgradeAwareProxy similar to
// TODO convert this entire proxy to an UpgradeAwareProxy similar to
// https://github.com/openshift/origin/blob/master/pkg/util/httpproxy/upgradeawareproxy.go.
// https://github.com/openshift/origin/blob/master/pkg/util/httpproxy/upgradeawareproxy.go.
// That proxy needs to be modified to support multiple backends, not just 1.
// That proxy needs to be modified to support multiple backends, not just 1.
if
r
.
tryUpgrade
(
w
,
req
,
newReq
,
destURL
)
{
if
r
.
tryUpgrade
(
w
,
req
,
newReq
,
location
,
transport
)
{
return
return
}
}
proxy
:=
httputil
.
NewSingleHostReverseProxy
(
&
url
.
URL
{
Scheme
:
"http"
,
Host
:
destURL
.
Host
})
proxy
:=
httputil
.
NewSingleHostReverseProxy
(
&
url
.
URL
{
Scheme
:
location
.
Scheme
,
Host
:
location
.
Host
})
proxy
.
Transport
=
&
proxyTransport
{
if
transport
==
nil
{
proxyScheme
:
req
.
URL
.
Scheme
,
prepend
:=
path
.
Join
(
r
.
prefix
,
resource
,
id
)
proxyHost
:
req
.
URL
.
Host
,
if
len
(
namespace
)
>
0
{
proxyPathPrepend
:
requestInfo
.
URLPath
(),
prepend
=
path
.
Join
(
r
.
prefix
,
"namespaces"
,
namespace
,
resource
,
id
)
}
transport
=
&
proxyTransport
{
proxyScheme
:
req
.
URL
.
Scheme
,
proxyHost
:
req
.
URL
.
Host
,
proxyPathPrepend
:
prepend
,
}
}
}
proxy
.
Transport
=
transport
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
proxy
.
ServeHTTP
(
w
,
newReq
)
proxy
.
ServeHTTP
(
w
,
newReq
)
}
}
// tryUpgrade returns true if the request was handled.
// tryUpgrade returns true if the request was handled.
func
(
r
*
ProxyHandler
)
tryUpgrade
(
w
http
.
ResponseWriter
,
req
,
newReq
*
http
.
Request
,
destURL
*
url
.
URL
)
bool
{
func
(
r
*
ProxyHandler
)
tryUpgrade
(
w
http
.
ResponseWriter
,
req
,
newReq
*
http
.
Request
,
location
*
url
.
URL
,
transport
http
.
RoundTripper
)
bool
{
connectionHeader
:=
strings
.
ToLower
(
req
.
Header
.
Get
(
httpstream
.
HeaderConnection
))
if
!
httpstream
.
IsUpgradeRequest
(
req
)
{
if
!
strings
.
Contains
(
connectionHeader
,
strings
.
ToLower
(
httpstream
.
HeaderUpgrade
))
||
len
(
req
.
Header
.
Get
(
httpstream
.
HeaderUpgrade
))
==
0
{
return
false
return
false
}
}
//TODO support TLS? Doesn't look like proxyTransport does anything special ...
dialAddr
:=
netutil
.
CanonicalAddr
(
destURL
)
backendConn
,
err
:=
dialURL
(
location
,
transport
)
backendConn
,
err
:=
net
.
Dial
(
"tcp"
,
dialAddr
)
if
err
!=
nil
{
if
err
!=
nil
{
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
...
@@ -246,6 +261,54 @@ func (r *ProxyHandler) tryUpgrade(w http.ResponseWriter, req, newReq *http.Reque
...
@@ -246,6 +261,54 @@ func (r *ProxyHandler) tryUpgrade(w http.ResponseWriter, req, newReq *http.Reque
return
true
return
true
}
}
func
dialURL
(
url
*
url
.
URL
,
transport
http
.
RoundTripper
)
(
net
.
Conn
,
error
)
{
dialAddr
:=
netutil
.
CanonicalAddr
(
url
)
switch
url
.
Scheme
{
case
"http"
:
return
net
.
Dial
(
"tcp"
,
dialAddr
)
case
"https"
:
// Get the tls config from the transport if we recognize it
var
tlsConfig
*
tls
.
Config
if
transport
!=
nil
{
httpTransport
,
ok
:=
transport
.
(
*
http
.
Transport
)
if
ok
{
tlsConfig
=
httpTransport
.
TLSClientConfig
}
}
// Dial
tlsConn
,
err
:=
tls
.
Dial
(
"tcp"
,
dialAddr
,
tlsConfig
)
if
err
!=
nil
{
return
nil
,
err
}
// Verify
host
,
_
,
_
:=
net
.
SplitHostPort
(
dialAddr
)
if
err
:=
tlsConn
.
VerifyHostname
(
host
);
err
!=
nil
{
tlsConn
.
Close
()
return
nil
,
err
}
return
tlsConn
,
nil
default
:
return
nil
,
fmt
.
Errorf
(
"Unknown scheme: %s"
,
url
.
Scheme
)
}
}
// borrowed from net/http/httputil/reverseproxy.go
func
singleJoiningSlash
(
a
,
b
string
)
string
{
aslash
:=
strings
.
HasSuffix
(
a
,
"/"
)
bslash
:=
strings
.
HasPrefix
(
b
,
"/"
)
switch
{
case
aslash
&&
bslash
:
return
a
+
b
[
1
:
]
case
!
aslash
&&
!
bslash
:
return
a
+
"/"
+
b
}
return
a
+
b
}
type
proxyTransport
struct
{
type
proxyTransport
struct
{
proxyScheme
string
proxyScheme
string
proxyHost
string
proxyHost
string
...
...
pkg/apiserver/proxy_test.go
View file @
aee9bdd6
...
@@ -275,9 +275,10 @@ func TestProxy(t *testing.T) {
...
@@ -275,9 +275,10 @@ func TestProxy(t *testing.T) {
}))
}))
defer
proxyServer
.
Close
()
defer
proxyServer
.
Close
()
serverURL
,
_
:=
url
.
Parse
(
proxyServer
.
URL
)
simpleStorage
:=
&
SimpleRESTStorage
{
simpleStorage
:=
&
SimpleRESTStorage
{
errors
:
map
[
string
]
error
{},
errors
:
map
[
string
]
error
{},
resourceLocation
:
proxyServer
.
URL
,
resourceLocation
:
server
URL
,
expectedResourceNamespace
:
item
.
reqNamespace
,
expectedResourceNamespace
:
item
.
reqNamespace
,
}
}
...
@@ -335,9 +336,10 @@ func TestProxyUpgrade(t *testing.T) {
...
@@ -335,9 +336,10 @@ func TestProxyUpgrade(t *testing.T) {
}))
}))
defer
backendServer
.
Close
()
defer
backendServer
.
Close
()
serverURL
,
_
:=
url
.
Parse
(
backendServer
.
URL
)
simpleStorage
:=
&
SimpleRESTStorage
{
simpleStorage
:=
&
SimpleRESTStorage
{
errors
:
map
[
string
]
error
{},
errors
:
map
[
string
]
error
{},
resourceLocation
:
backendServer
.
URL
,
resourceLocation
:
server
URL
,
expectedResourceNamespace
:
"myns"
,
expectedResourceNamespace
:
"myns"
,
}
}
...
...
pkg/apiserver/redirect.go
View file @
aee9bdd6
...
@@ -17,7 +17,6 @@ limitations under the License.
...
@@ -17,7 +17,6 @@ limitations under the License.
package
apiserver
package
apiserver
import
(
import
(
"fmt"
"net/http"
"net/http"
"time"
"time"
...
@@ -79,15 +78,26 @@ func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -79,15 +78,26 @@ func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
return
}
}
location
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
id
)
location
,
_
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
id
)
if
err
!=
nil
{
if
err
!=
nil
{
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
httpCode
=
status
.
Code
httpCode
=
status
.
Code
return
return
}
}
if
location
==
nil
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"ResourceLocation for %v returned nil"
,
id
)
notFound
(
w
,
req
)
httpCode
=
http
.
StatusNotFound
return
}
// Default to http
if
location
.
Scheme
==
""
{
location
.
Scheme
=
"http"
}
w
.
Header
()
.
Set
(
"Location"
,
fmt
.
Sprintf
(
"http://%s"
,
location
))
w
.
Header
()
.
Set
(
"Location"
,
location
.
String
(
))
w
.
WriteHeader
(
http
.
StatusTemporaryRedirect
)
w
.
WriteHeader
(
http
.
StatusTemporaryRedirect
)
httpCode
=
http
.
StatusTemporaryRedirect
httpCode
=
http
.
StatusTemporaryRedirect
}
}
pkg/apiserver/redirect_test.go
View file @
aee9bdd6
...
@@ -53,7 +53,7 @@ func TestRedirect(t *testing.T) {
...
@@ -53,7 +53,7 @@ func TestRedirect(t *testing.T) {
for
_
,
item
:=
range
table
{
for
_
,
item
:=
range
table
{
simpleStorage
.
errors
[
"resourceLocation"
]
=
item
.
err
simpleStorage
.
errors
[
"resourceLocation"
]
=
item
.
err
simpleStorage
.
resourceLocation
=
item
.
id
simpleStorage
.
resourceLocation
=
&
url
.
URL
{
Host
:
item
.
id
}
resp
,
err
:=
client
.
Get
(
server
.
URL
+
"/api/version/redirect/foo/"
+
item
.
id
)
resp
,
err
:=
client
.
Get
(
server
.
URL
+
"/api/version/redirect/foo/"
+
item
.
id
)
if
resp
==
nil
{
if
resp
==
nil
{
t
.
Fatalf
(
"Unexpected nil resp"
)
t
.
Fatalf
(
"Unexpected nil resp"
)
...
@@ -104,7 +104,7 @@ func TestRedirectWithNamespaces(t *testing.T) {
...
@@ -104,7 +104,7 @@ func TestRedirectWithNamespaces(t *testing.T) {
for
_
,
item
:=
range
table
{
for
_
,
item
:=
range
table
{
simpleStorage
.
errors
[
"resourceLocation"
]
=
item
.
err
simpleStorage
.
errors
[
"resourceLocation"
]
=
item
.
err
simpleStorage
.
resourceLocation
=
item
.
id
simpleStorage
.
resourceLocation
=
&
url
.
URL
{
Host
:
item
.
id
}
resp
,
err
:=
client
.
Get
(
server
.
URL
+
"/api/version/redirect/namespaces/other/foo/"
+
item
.
id
)
resp
,
err
:=
client
.
Get
(
server
.
URL
+
"/api/version/redirect/namespaces/other/foo/"
+
item
.
id
)
if
resp
==
nil
{
if
resp
==
nil
{
t
.
Fatalf
(
"Unexpected nil resp"
)
t
.
Fatalf
(
"Unexpected nil resp"
)
...
...
pkg/client/kubelet.go
View file @
aee9bdd6
...
@@ -40,6 +40,7 @@ type KubeletClient interface {
...
@@ -40,6 +40,7 @@ type KubeletClient interface {
KubeletHealthChecker
KubeletHealthChecker
PodInfoGetter
PodInfoGetter
NodeInfoGetter
NodeInfoGetter
ConnectionInfoGetter
}
}
// KubeletHealthchecker is an interface for healthchecking kubelets
// KubeletHealthchecker is an interface for healthchecking kubelets
...
@@ -59,6 +60,10 @@ type NodeInfoGetter interface {
...
@@ -59,6 +60,10 @@ type NodeInfoGetter interface {
GetNodeInfo
(
host
string
)
(
api
.
NodeInfo
,
error
)
GetNodeInfo
(
host
string
)
(
api
.
NodeInfo
,
error
)
}
}
type
ConnectionInfoGetter
interface
{
GetConnectionInfo
(
host
string
)
(
scheme
string
,
port
uint
,
transport
http
.
RoundTripper
,
error
error
)
}
// HTTPKubeletClient is the default implementation of PodInfoGetter and KubeletHealthchecker, accesses the kubelet over HTTP.
// HTTPKubeletClient is the default implementation of PodInfoGetter and KubeletHealthchecker, accesses the kubelet over HTTP.
type
HTTPKubeletClient
struct
{
type
HTTPKubeletClient
struct
{
Client
*
http
.
Client
Client
*
http
.
Client
...
@@ -92,6 +97,14 @@ func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) {
...
@@ -92,6 +97,14 @@ func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) {
},
nil
},
nil
}
}
func
(
c
*
HTTPKubeletClient
)
GetConnectionInfo
(
host
string
)
(
string
,
uint
,
http
.
RoundTripper
,
error
)
{
scheme
:=
"http"
if
c
.
EnableHttps
{
scheme
=
"https"
}
return
scheme
,
c
.
Port
,
c
.
Client
.
Transport
,
nil
}
func
(
c
*
HTTPKubeletClient
)
url
(
host
,
path
,
query
string
)
string
{
func
(
c
*
HTTPKubeletClient
)
url
(
host
,
path
,
query
string
)
string
{
scheme
:=
"http"
scheme
:=
"http"
if
c
.
EnableHttps
{
if
c
.
EnableHttps
{
...
@@ -168,3 +181,7 @@ func (c FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
...
@@ -168,3 +181,7 @@ func (c FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
func
(
c
FakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
func
(
c
FakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
return
probe
.
Unknown
,
errors
.
New
(
"Not Implemented"
)
return
probe
.
Unknown
,
errors
.
New
(
"Not Implemented"
)
}
}
func
(
c
FakeKubeletClient
)
GetConnectionInfo
(
host
string
)
(
string
,
uint
,
http
.
RoundTripper
,
error
)
{
return
""
,
0
,
nil
,
errors
.
New
(
"Not Implemented"
)
}
pkg/cloudprovider/controller/nodecontroller_test.go
View file @
aee9bdd6
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"net"
"net"
"net/http"
"reflect"
"reflect"
"sort"
"sort"
"testing"
"testing"
...
@@ -135,6 +136,10 @@ func (c *FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
...
@@ -135,6 +136,10 @@ func (c *FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) {
return
api
.
NodeInfo
{},
errors
.
New
(
"Not Implemented"
)
return
api
.
NodeInfo
{},
errors
.
New
(
"Not Implemented"
)
}
}
func
(
c
*
FakeKubeletClient
)
GetConnectionInfo
(
host
string
)
(
string
,
uint
,
http
.
RoundTripper
,
error
)
{
return
""
,
0
,
nil
,
errors
.
New
(
"Not Implemented"
)
}
func
(
c
*
FakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
func
(
c
*
FakeKubeletClient
)
HealthCheck
(
host
string
)
(
probe
.
Result
,
error
)
{
return
c
.
Status
,
c
.
Err
return
c
.
Status
,
c
.
Err
}
}
...
...
pkg/master/master.go
View file @
aee9bdd6
...
@@ -368,7 +368,7 @@ func (m *Master) init(c *Config) {
...
@@ -368,7 +368,7 @@ func (m *Master) init(c *Config) {
m
.
endpointRegistry
=
registry
m
.
endpointRegistry
=
registry
m
.
nodeRegistry
=
registry
m
.
nodeRegistry
=
registry
nodeStorage
:=
minion
.
NewStorage
(
m
.
nodeRegistry
)
nodeStorage
:=
minion
.
NewStorage
(
m
.
nodeRegistry
,
c
.
KubeletClient
)
// TODO: unify the storage -> registry and storage -> client patterns
// TODO: unify the storage -> registry and storage -> client patterns
nodeStorageClient
:=
RESTStorageToNodes
(
nodeStorage
)
nodeStorageClient
:=
RESTStorageToNodes
(
nodeStorage
)
podCache
:=
NewPodCache
(
podCache
:=
NewPodCache
(
...
...
pkg/registry/minion/rest.go
View file @
aee9bdd6
...
@@ -20,28 +20,32 @@ import (
...
@@ -20,28 +20,32 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"net"
"net"
"net/http"
"net/url"
"strconv"
"strconv"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kerrors
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
kerrors
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
)
// REST adapts minion into apiserver's RESTStorage model.
// REST adapts minion into apiserver's RESTStorage model.
type
REST
struct
{
type
REST
struct
{
registry
Registry
registry
Registry
connection
client
.
ConnectionInfoGetter
}
}
// NewStorage returns a new rest.Storage implementation for minion.
// NewStorage returns a new rest.Storage implementation for minion.
func
NewStorage
(
m
Registry
)
*
REST
{
func
NewStorage
(
m
Registry
,
connection
client
.
ConnectionInfoGetter
)
*
REST
{
return
&
REST
{
return
&
REST
{
registry
:
m
,
registry
:
m
,
connection
:
connection
,
}
}
}
}
...
@@ -138,13 +142,29 @@ func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selec
...
@@ -138,13 +142,29 @@ func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selec
return
rs
.
registry
.
WatchMinions
(
ctx
,
label
,
field
,
resourceVersion
)
return
rs
.
registry
.
WatchMinions
(
ctx
,
label
,
field
,
resourceVersion
)
}
}
// Implement Redirector.
var
_
=
rest
.
Redirector
(
&
REST
{})
// ResourceLocation returns a URL to which one can send traffic for the specified minion.
// ResourceLocation returns a URL to which one can send traffic for the specified minion.
func
(
rs
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
string
,
error
)
{
func
(
rs
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
*
url
.
URL
,
http
.
RoundTripper
,
error
)
{
minion
,
err
:=
rs
.
registry
.
GetMinion
(
ctx
,
id
)
minion
,
err
:=
rs
.
registry
.
GetMinion
(
ctx
,
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
nil
,
err
}
}
host
:=
minion
.
Name
host
:=
minion
.
Name
// TODO: Minion webservers should be secure!
return
"http://"
+
net
.
JoinHostPort
(
host
,
strconv
.
Itoa
(
ports
.
KubeletPort
)),
nil
scheme
,
port
,
transport
,
err
:=
rs
.
connection
.
GetConnectionInfo
(
host
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
return
&
url
.
URL
{
Scheme
:
scheme
,
Host
:
net
.
JoinHostPort
(
host
,
strconv
.
FormatUint
(
uint64
(
port
),
10
),
),
},
transport
,
nil
}
}
pkg/registry/minion/rest_test.go
View file @
aee9bdd6
...
@@ -17,6 +17,7 @@ limitations under the License.
...
@@ -17,6 +17,7 @@ limitations under the License.
package
minion
package
minion
import
(
import
(
"net/http"
"testing"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
...
@@ -27,8 +28,15 @@ import (
...
@@ -27,8 +28,15 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
)
)
type
FakeConnectionInfoGetter
struct
{
}
func
(
FakeConnectionInfoGetter
)
GetConnectionInfo
(
host
string
)
(
string
,
uint
,
http
.
RoundTripper
,
error
)
{
return
"http"
,
12345
,
nil
,
nil
}
func
TestMinionRegistryREST
(
t
*
testing
.
T
)
{
func
TestMinionRegistryREST
(
t
*
testing
.
T
)
{
ms
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{}))
ms
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{})
,
FakeConnectionInfoGetter
{}
)
ctx
:=
api
.
NewContext
()
ctx
:=
api
.
NewContext
()
if
obj
,
err
:=
ms
.
Get
(
ctx
,
"foo"
);
err
!=
nil
||
obj
.
(
*
api
.
Node
)
.
Name
!=
"foo"
{
if
obj
,
err
:=
ms
.
Get
(
ctx
,
"foo"
);
err
!=
nil
||
obj
.
(
*
api
.
Node
)
.
Name
!=
"foo"
{
t
.
Errorf
(
"missing expected object"
)
t
.
Errorf
(
"missing expected object"
)
...
@@ -88,7 +96,7 @@ func TestMinionRegistryREST(t *testing.T) {
...
@@ -88,7 +96,7 @@ func TestMinionRegistryREST(t *testing.T) {
}
}
func
TestMinionRegistryValidUpdate
(
t
*
testing
.
T
)
{
func
TestMinionRegistryValidUpdate
(
t
*
testing
.
T
)
{
storage
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{}))
storage
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{})
,
FakeConnectionInfoGetter
{}
)
ctx
:=
api
.
NewContext
()
ctx
:=
api
.
NewContext
()
obj
,
err
:=
storage
.
Get
(
ctx
,
"foo"
)
obj
,
err
:=
storage
.
Get
(
ctx
,
"foo"
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -113,7 +121,7 @@ var (
...
@@ -113,7 +121,7 @@ var (
)
)
func
TestMinionRegistryValidatesCreate
(
t
*
testing
.
T
)
{
func
TestMinionRegistryValidatesCreate
(
t
*
testing
.
T
)
{
storage
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{}))
storage
:=
NewStorage
(
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{})
,
FakeConnectionInfoGetter
{}
)
ctx
:=
api
.
NewContext
()
ctx
:=
api
.
NewContext
()
failureCases
:=
map
[
string
]
api
.
Node
{
failureCases
:=
map
[
string
]
api
.
Node
{
"zero-length Name"
:
{
"zero-length Name"
:
{
...
@@ -156,7 +164,7 @@ func contains(nodes *api.NodeList, nodeID string) bool {
...
@@ -156,7 +164,7 @@ func contains(nodes *api.NodeList, nodeID string) bool {
func
TestCreate
(
t
*
testing
.
T
)
{
func
TestCreate
(
t
*
testing
.
T
)
{
registry
:=
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{})
registry
:=
registrytest
.
NewMinionRegistry
([]
string
{
"foo"
,
"bar"
},
api
.
NodeResources
{})
test
:=
resttest
.
New
(
t
,
NewStorage
(
registry
),
registry
.
SetError
)
.
ClusterScope
()
test
:=
resttest
.
New
(
t
,
NewStorage
(
registry
,
FakeConnectionInfoGetter
{}
),
registry
.
SetError
)
.
ClusterScope
()
test
.
TestCreate
(
test
.
TestCreate
(
// valid
// valid
&
api
.
Node
{
&
api
.
Node
{
...
...
pkg/registry/pod/etcd/etcd.go
View file @
aee9bdd6
...
@@ -18,6 +18,8 @@ package etcd
...
@@ -18,6 +18,8 @@ package etcd
import
(
import
(
"fmt"
"fmt"
"net/http"
"net/url"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
...
@@ -75,8 +77,11 @@ func NewStorage(h tools.EtcdHelper) (*REST, *BindingREST, *StatusREST) {
...
@@ -75,8 +77,11 @@ func NewStorage(h tools.EtcdHelper) (*REST, *BindingREST, *StatusREST) {
return
&
REST
{
*
store
},
&
BindingREST
{
store
:
store
},
&
StatusREST
{
store
:
&
statusStore
}
return
&
REST
{
*
store
},
&
BindingREST
{
store
:
store
},
&
StatusREST
{
store
:
&
statusStore
}
}
}
// Implement Redirector.
var
_
=
rest
.
Redirector
(
&
REST
{})
// ResourceLocation returns a pods location from its HostIP
// ResourceLocation returns a pods location from its HostIP
func
(
r
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
name
string
)
(
string
,
error
)
{
func
(
r
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
name
string
)
(
*
url
.
URL
,
http
.
RoundTripper
,
error
)
{
return
pod
.
ResourceLocation
(
r
,
ctx
,
name
)
return
pod
.
ResourceLocation
(
r
,
ctx
,
name
)
}
}
...
...
pkg/registry/pod/etcd/etcd_test.go
View file @
aee9bdd6
...
@@ -683,13 +683,19 @@ func TestResourceLocation(t *testing.T) {
...
@@ -683,13 +683,19 @@ func TestResourceLocation(t *testing.T) {
storage
=
storage
.
WithPodStatus
(
cache
)
storage
=
storage
.
WithPodStatus
(
cache
)
redirector
:=
rest
.
Redirector
(
storage
)
redirector
:=
rest
.
Redirector
(
storage
)
location
,
err
:=
redirector
.
ResourceLocation
(
api
.
NewDefaultContext
(),
tc
.
query
)
location
,
_
,
err
:=
redirector
.
ResourceLocation
(
api
.
NewDefaultContext
(),
tc
.
query
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
}
}
if
location
==
nil
{
t
.
Errorf
(
"Unexpected nil: %v"
,
location
)
}
if
location
!=
tc
.
location
{
if
location
.
Scheme
!=
""
{
t
.
Errorf
(
"Expected %v, but got %v"
,
tc
.
location
,
location
)
t
.
Errorf
(
"Expected '%v', but got '%v'"
,
""
,
location
.
Scheme
)
}
if
location
.
Host
!=
tc
.
location
{
t
.
Errorf
(
"Expected %v, but got %v"
,
tc
.
location
,
location
.
Host
)
}
}
}
}
}
}
...
...
pkg/registry/pod/rest.go
View file @
aee9bdd6
...
@@ -18,6 +18,9 @@ package pod
...
@@ -18,6 +18,9 @@ package pod
import
(
import
(
"fmt"
"fmt"
"net"
"net/http"
"net/url"
"strings"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
...
@@ -151,12 +154,12 @@ type ResourceGetter interface {
...
@@ -151,12 +154,12 @@ type ResourceGetter interface {
}
}
// ResourceLocation returns a URL to which one can send traffic for the specified pod.
// ResourceLocation returns a URL to which one can send traffic for the specified pod.
func
ResourceLocation
(
getter
ResourceGetter
,
ctx
api
.
Context
,
id
string
)
(
string
,
error
)
{
func
ResourceLocation
(
getter
ResourceGetter
,
ctx
api
.
Context
,
id
string
)
(
*
url
.
URL
,
http
.
RoundTripper
,
error
)
{
// Allow ID as "podname" or "podname:port". If port is not specified,
// Allow ID as "podname" or "podname:port". If port is not specified,
// try to use the first defined port on the pod.
// try to use the first defined port on the pod.
parts
:=
strings
.
Split
(
id
,
":"
)
parts
:=
strings
.
Split
(
id
,
":"
)
if
len
(
parts
)
>
2
{
if
len
(
parts
)
>
2
{
return
""
,
errors
.
NewBadRequest
(
fmt
.
Sprintf
(
"invalid pod request %q"
,
id
))
return
nil
,
nil
,
errors
.
NewBadRequest
(
fmt
.
Sprintf
(
"invalid pod request %q"
,
id
))
}
}
name
:=
parts
[
0
]
name
:=
parts
[
0
]
port
:=
""
port
:=
""
...
@@ -167,11 +170,11 @@ func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (string
...
@@ -167,11 +170,11 @@ func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (string
obj
,
err
:=
getter
.
Get
(
ctx
,
name
)
obj
,
err
:=
getter
.
Get
(
ctx
,
name
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
nil
,
err
}
}
pod
:=
obj
.
(
*
api
.
Pod
)
pod
:=
obj
.
(
*
api
.
Pod
)
if
pod
==
nil
{
if
pod
==
nil
{
return
""
,
nil
return
nil
,
nil
,
nil
}
}
// Try to figure out a port.
// Try to figure out a port.
...
@@ -186,9 +189,11 @@ func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (string
...
@@ -186,9 +189,11 @@ func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (string
// We leave off the scheme ('http://') because we have no idea what sort of server
// We leave off the scheme ('http://') because we have no idea what sort of server
// is listening at this endpoint.
// is listening at this endpoint.
loc
:=
pod
.
Status
.
PodIP
loc
:=
&
url
.
URL
{}
if
port
!=
""
{
if
port
==
""
{
loc
+=
fmt
.
Sprintf
(
":%s"
,
port
)
loc
.
Host
=
pod
.
Status
.
PodIP
}
else
{
loc
.
Host
=
net
.
JoinHostPort
(
pod
.
Status
.
PodIP
,
port
)
}
}
return
loc
,
nil
return
loc
,
nil
,
nil
}
}
pkg/registry/service/rest.go
View file @
aee9bdd6
...
@@ -20,6 +20,8 @@ import (
...
@@ -20,6 +20,8 @@ import (
"fmt"
"fmt"
"math/rand"
"math/rand"
"net"
"net"
"net/http"
"net/url"
"strconv"
"strconv"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
...
@@ -223,19 +225,24 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
...
@@ -223,19 +225,24 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
return
out
,
false
,
err
return
out
,
false
,
err
}
}
// Implement Redirector.
var
_
=
rest
.
Redirector
(
&
REST
{})
// ResourceLocation returns a URL to which one can send traffic for the specified service.
// ResourceLocation returns a URL to which one can send traffic for the specified service.
func
(
rs
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
string
,
error
)
{
func
(
rs
*
REST
)
ResourceLocation
(
ctx
api
.
Context
,
id
string
)
(
*
url
.
URL
,
http
.
RoundTripper
,
error
)
{
eps
,
err
:=
rs
.
registry
.
GetEndpoints
(
ctx
,
id
)
eps
,
err
:=
rs
.
registry
.
GetEndpoints
(
ctx
,
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
nil
,
nil
,
err
}
}
if
len
(
eps
.
Endpoints
)
==
0
{
if
len
(
eps
.
Endpoints
)
==
0
{
return
""
,
fmt
.
Errorf
(
"no endpoints available for %v"
,
id
)
return
nil
,
nil
,
fmt
.
Errorf
(
"no endpoints available for %v"
,
id
)
}
}
// We leave off the scheme ('http://') because we have no idea what sort of server
// We leave off the scheme ('http://') because we have no idea what sort of server
// is listening at this endpoint.
// is listening at this endpoint.
ep
:=
&
eps
.
Endpoints
[
rand
.
Intn
(
len
(
eps
.
Endpoints
))]
ep
:=
&
eps
.
Endpoints
[
rand
.
Intn
(
len
(
eps
.
Endpoints
))]
return
net
.
JoinHostPort
(
ep
.
IP
,
strconv
.
Itoa
(
ep
.
Port
)),
nil
return
&
url
.
URL
{
Host
:
net
.
JoinHostPort
(
ep
.
IP
,
strconv
.
Itoa
(
ep
.
Port
)),
},
nil
,
nil
}
}
func
(
rs
*
REST
)
getLoadbalancerName
(
ctx
api
.
Context
,
service
*
api
.
Service
)
string
{
func
(
rs
*
REST
)
getLoadbalancerName
(
ctx
api
.
Context
,
service
*
api
.
Service
)
string
{
...
...
pkg/registry/service/rest_test.go
View file @
aee9bdd6
...
@@ -385,11 +385,14 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
...
@@ -385,11 +385,14 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
},
},
})
})
redirector
:=
rest
.
Redirector
(
storage
)
redirector
:=
rest
.
Redirector
(
storage
)
location
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
"foo"
)
location
,
_
,
err
:=
redirector
.
ResourceLocation
(
ctx
,
"foo"
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
}
}
if
e
,
a
:=
"foo:80"
,
location
;
e
!=
a
{
if
location
==
nil
{
t
.
Errorf
(
"Unexpected nil: %v"
,
location
)
}
if
e
,
a
:=
"//foo:80"
,
location
.
String
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, but got %v"
,
e
,
a
)
t
.
Errorf
(
"Expected %v, but got %v"
,
e
,
a
)
}
}
if
e
,
a
:=
"foo"
,
registry
.
GottenID
;
e
!=
a
{
if
e
,
a
:=
"foo"
,
registry
.
GottenID
;
e
!=
a
{
...
@@ -398,7 +401,7 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
...
@@ -398,7 +401,7 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
// Test error path
// Test error path
registry
.
Err
=
fmt
.
Errorf
(
"fake error"
)
registry
.
Err
=
fmt
.
Errorf
(
"fake error"
)
if
_
,
err
=
redirector
.
ResourceLocation
(
ctx
,
"foo"
);
err
==
nil
{
if
_
,
_
,
err
=
redirector
.
ResourceLocation
(
ctx
,
"foo"
);
err
==
nil
{
t
.
Errorf
(
"unexpected nil error"
)
t
.
Errorf
(
"unexpected nil error"
)
}
}
}
}
...
...
pkg/util/httpstream/httpstream.go
View file @
aee9bdd6
...
@@ -19,6 +19,7 @@ package httpstream
...
@@ -19,6 +19,7 @@ package httpstream
import
(
import
(
"io"
"io"
"net/http"
"net/http"
"strings"
"time"
"time"
)
)
...
@@ -78,3 +79,13 @@ type Stream interface {
...
@@ -78,3 +79,13 @@ type Stream interface {
// Headers returns the headers used to create the stream.
// Headers returns the headers used to create the stream.
Headers
()
http
.
Header
Headers
()
http
.
Header
}
}
// IsUpgradeRequest returns true if the given request is a connection upgrade request
func
IsUpgradeRequest
(
req
*
http
.
Request
)
bool
{
for
_
,
h
:=
range
req
.
Header
[
http
.
CanonicalHeaderKey
(
HeaderConnection
)]
{
if
strings
.
Contains
(
strings
.
ToLower
(
h
),
strings
.
ToLower
(
HeaderUpgrade
))
{
return
true
}
}
return
false
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment