mirror of https://github.com/k3s-io/k3s
Merge pull request #42070 from luxas/remove_kube_discovery
Automatic merge from submit-queue Remove the kube-discovery binary from the tree **What this PR does / why we need it**: kube-discovery was a temporary solution to implementing proposal: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bootstrap-discovery.md However, this functionality is now gonna be implemented in the core for v1.6 and will fully replace kube-discovery: - https://github.com/kubernetes/kubernetes/pull/36101 - https://github.com/kubernetes/kubernetes/pull/41281 - https://github.com/kubernetes/kubernetes/pull/41417 So due to that `kube-discovery` isn't used in any v1.6 code, it should be removed. The image `gcr.io/google_containers/kube-discovery-${ARCH}:1.0` should and will continue to exist so kubeadm <= v1.5 continues to work. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # **Special notes for your reviewer**: **Release note**: ```release-note Remove cmd/kube-discovery from the tree since it's not necessary anymore ``` @jbeda @dgoodwin @mikedanese @dmmcquay @lukemarsden @errordeveloper @pirespull/6/head
commit
79883dc48d
|
@ -71,7 +71,6 @@ SERVER_TARGETS = [
|
|||
"//cmd/hyperkube",
|
||||
"//cmd/kube-apiserver",
|
||||
"//cmd/kube-controller-manager",
|
||||
"//cmd/kube-discovery",
|
||||
"//cmd/kubeadm",
|
||||
"//plugin/cmd/kube-scheduler",
|
||||
]
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright 2016 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM BASEIMAGE
|
||||
|
||||
COPY kube-discovery /usr/local/bin
|
||||
ENTRYPOINT "/usr/local/bin/kube-discovery"
|
|
@ -1,57 +0,0 @@
|
|||
# Copyright 2016 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Build the kube-discovery image.
|
||||
#
|
||||
# Requires a pre-built kube-discovery binary:
|
||||
# build/run.sh /bin/bash -c "KUBE_BUILD_PLATFORMS=linux/ARCH make WHAT=cmd/kube-discovery"
|
||||
#
|
||||
# Usage:
|
||||
# [ARCH=amd64] [REGISTRY="gcr.io/google_containers"] make (build|push) VERSION={some_released_version_of_kubernetes}
|
||||
|
||||
REGISTRY?=gcr.io/google_containers
|
||||
ARCH?=amd64
|
||||
TEMP_DIR:=$(shell mktemp -d)
|
||||
VERSION?=1.0
|
||||
|
||||
ifeq ($(ARCH),amd64)
|
||||
BASEIMAGE?=debian:jessie
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
BASEIMAGE?=armhf/debian:jessie
|
||||
endif
|
||||
ifeq ($(ARCH),arm64)
|
||||
BASEIMAGE?=aarch64/debian:jessie
|
||||
endif
|
||||
ifeq ($(ARCH),ppc64le)
|
||||
BASEIMAGE?=ppc64le/debian:jessie
|
||||
endif
|
||||
ifeq ($(ARCH),s390x)
|
||||
BASEIMAGE?=s390x/debian:jessie
|
||||
endif
|
||||
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
cp -r ./* ${TEMP_DIR}
|
||||
cp ../../../_output/dockerized/bin/linux/${ARCH}/kube-discovery ${TEMP_DIR}
|
||||
cd ${TEMP_DIR} && sed -i.back "s|BASEIMAGE|${BASEIMAGE}|g" Dockerfile
|
||||
docker build --pull -t ${REGISTRY}/kube-discovery-${ARCH}:${VERSION} ${TEMP_DIR}
|
||||
rm -rf "${TEMP_DIR}"
|
||||
|
||||
push: build
|
||||
gcloud docker -- push ${REGISTRY}/kube-discovery-${ARCH}:${VERSION}
|
||||
|
||||
.PHONY: all
|
|
@ -1,45 +0,0 @@
|
|||
### kube-discovery
|
||||
|
||||
An initial implementation of a Kubernetes discovery service using JSON Web Signatures.
|
||||
|
||||
This prototype is configured by kubeadm and run within Kubernetes itself.
|
||||
|
||||
## Requirements
|
||||
|
||||
This pod expects the cluster CA, endpoints list, and token map to exist in /tmp/secret. This allows us to pass them in as kubernetes secrets when deployed as a pod.
|
||||
|
||||
```
|
||||
$ cd /tmp/secret
|
||||
$ ls
|
||||
ca.pem endpoint-list.json token-map.json
|
||||
$ cat endpoint-list.json
|
||||
["http://192.168.1.5:8080", "http://192.168.1.6:8080"]
|
||||
$ cat token-map.json
|
||||
{
|
||||
"TOKENID": "ABCDEF1234123456"
|
||||
}
|
||||
```
|
||||
|
||||
## Build And Run From Source
|
||||
|
||||
```
|
||||
$ build/run.sh /bin/bash -c "KUBE_BUILD_PLATFORMS=linux/amd64 make WHAT=cmd/kube-discovery"
|
||||
$ _output/dockerized/bin/linux/amd64/kube-discovery
|
||||
2016/08/23 19:17:28 Listening for requests on port 9898.
|
||||
|
||||
```
|
||||
|
||||
## Running in Docker
|
||||
|
||||
This image is published at: gcr.io/google_containers/kube-discovery
|
||||
|
||||
`docker run -d -p 9898:9898 -v /tmp/secret/ca.pem:/tmp/secret/ca.pem -v /tmp/secret/endpoint-list.json:/tmp/secret/endpoint-list.json -v /tmp/secret/token-map.json:/tmp/secret/token-map.json --name kubediscovery gcr.io/google_containers/kube-discovery`
|
||||
|
||||
## Testing the API
|
||||
|
||||
`curl "http://localhost:9898/cluster-info/v1/?token-id=TOKENID"`
|
||||
|
||||
You should see JSON containing a signed payload. For code to verify and decode that payload see handler_test.go.
|
||||
|
||||
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/cluster/images/kube-discovery/README.md?pixel)]()
|
|
@ -26,7 +26,6 @@ filegroup(
|
|||
"//cmd/hyperkube:all-srcs",
|
||||
"//cmd/kube-apiserver:all-srcs",
|
||||
"//cmd/kube-controller-manager:all-srcs",
|
||||
"//cmd/kube-discovery:all-srcs",
|
||||
"//cmd/kube-proxy:all-srcs",
|
||||
"//cmd/kubeadm:all-srcs",
|
||||
"//cmd/kubectl:all-srcs",
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "kube-discovery",
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kubediscovery.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//cmd/kube-discovery/app:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//cmd/kube-discovery/app:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -1,44 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"handlers.go",
|
||||
"model.go",
|
||||
"routes.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/gorilla/mux",
|
||||
"//vendor:github.com/square/go-jose",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["handlers_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/square/go-jose"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/square/go-jose"
|
||||
)
|
||||
|
||||
const secretPath = "/tmp/secret"
|
||||
|
||||
// CAPath is the expected location of our cluster's CA to be distributed to
|
||||
// clients looking to connect. Because we expect to use kubernetes secrets
|
||||
// for the time being, this file is expected to be a base64 encoded version
|
||||
// of the normal cert PEM.
|
||||
const CAPath = secretPath + "/ca.pem"
|
||||
|
||||
// caLoader is an interface for abstracting how we load the CA certificates
|
||||
// for the cluster.
|
||||
type caLoader interface {
|
||||
LoadPEM() (string, error)
|
||||
}
|
||||
|
||||
// fsCALoader is a caLoader for loading the PEM encoded CA from
|
||||
// /tmp/secret/ca.pem.
|
||||
type fsCALoader struct {
|
||||
certData string
|
||||
}
|
||||
|
||||
func (cl *fsCALoader) LoadPEM() (string, error) {
|
||||
if cl.certData == "" {
|
||||
data, err := ioutil.ReadFile(CAPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cl.certData = string(data)
|
||||
}
|
||||
|
||||
return cl.certData, nil
|
||||
}
|
||||
|
||||
const TokenMapPath = secretPath + "/token-map.json"
|
||||
const EndpointListPath = secretPath + "/endpoint-list.json"
|
||||
|
||||
// tokenLoader is an interface for abstracting how we validate
|
||||
// token IDs and lookup their corresponding token.
|
||||
type tokenLoader interface {
|
||||
// Lookup returns the token for a given token ID, or an error if the token ID
|
||||
// does not exist. Both token and it's ID are expected be strings.
|
||||
LoadAndLookup(tokenID string) (string, error)
|
||||
}
|
||||
|
||||
type jsonFileTokenLoader struct {
|
||||
tokenMap map[string]string
|
||||
}
|
||||
|
||||
func (tl *jsonFileTokenLoader) LoadAndLookup(tokenID string) (string, error) {
|
||||
if len(tl.tokenMap) == 0 {
|
||||
data, err := ioutil.ReadFile(TokenMapPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := json.Unmarshal(data, &tl.tokenMap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if val, ok := tl.tokenMap[tokenID]; ok {
|
||||
return val, nil
|
||||
}
|
||||
return "", errors.New(fmt.Sprintf("invalid token: %s", tokenID))
|
||||
}
|
||||
|
||||
type endpointsLoader interface {
|
||||
LoadList() ([]string, error)
|
||||
}
|
||||
|
||||
type jsonFileEndpointsLoader struct {
|
||||
endpoints []string
|
||||
}
|
||||
|
||||
func (el *jsonFileEndpointsLoader) LoadList() ([]string, error) {
|
||||
if len(el.endpoints) == 0 {
|
||||
data, err := ioutil.ReadFile(EndpointListPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(data, &el.endpoints); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return el.endpoints, nil
|
||||
}
|
||||
|
||||
// ClusterInfoHandler implements the http.ServeHTTP method and allows us to
|
||||
// mock out portions of the request handler in tests.
|
||||
type ClusterInfoHandler struct {
|
||||
tokenLoader tokenLoader
|
||||
caLoader caLoader
|
||||
endpointsLoader endpointsLoader
|
||||
}
|
||||
|
||||
func NewClusterInfoHandler() *ClusterInfoHandler {
|
||||
return &ClusterInfoHandler{
|
||||
tokenLoader: &jsonFileTokenLoader{},
|
||||
caLoader: &fsCALoader{},
|
||||
endpointsLoader: &jsonFileEndpointsLoader{},
|
||||
}
|
||||
}
|
||||
|
||||
func (cih *ClusterInfoHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
||||
tokenID := req.FormValue("token-id")
|
||||
log.Printf("Got token ID: %s", tokenID)
|
||||
token, err := cih.tokenLoader.LoadAndLookup(tokenID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
http.Error(resp, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
log.Printf("Loaded token: %s", token)
|
||||
|
||||
// TODO probably should not leak server-side errors to the client
|
||||
caPEM, err := cih.caLoader.LoadPEM()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error loading root CA certificate data: %s", err)
|
||||
log.Println(err)
|
||||
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Loaded CA: %s", caPEM)
|
||||
|
||||
endpoints, err := cih.endpointsLoader.LoadList()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error loading list of API endpoints: %s", err)
|
||||
log.Println(err)
|
||||
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
clusterInfo := ClusterInfo{
|
||||
CertificateAuthorities: []string{caPEM},
|
||||
Endpoints: endpoints,
|
||||
}
|
||||
|
||||
// Instantiate an signer using HMAC-SHA256.
|
||||
hmacKey := []byte(token)
|
||||
|
||||
log.Printf("Key is %d bytes long", len(hmacKey))
|
||||
signer, err := jose.NewSigner(jose.HS256, hmacKey)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error creating JWS signer: %s", err)
|
||||
log.Println(err)
|
||||
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(clusterInfo)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error serializing clusterInfo to JSON: %s", err)
|
||||
log.Println(err)
|
||||
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Sign a sample payload. Calling the signer returns a protected JWS object,
|
||||
// which can then be serialized for output afterwards. An error would
|
||||
// indicate a problem in an underlying cryptographic primitive.
|
||||
jws, err := signer.Sign(payload)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error signing clusterInfo with JWS: %s", err)
|
||||
log.Println(err)
|
||||
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Serialize the encrypted object using the full serialization format.
|
||||
// Alternatively you can also use the compact format here by calling
|
||||
// object.CompactSerialize() instead.
|
||||
serialized := jws.FullSerialize()
|
||||
|
||||
resp.Write([]byte(serialized))
|
||||
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/square/go-jose"
|
||||
)
|
||||
|
||||
type mockTokenLoader struct {
|
||||
tokenID string
|
||||
token string
|
||||
}
|
||||
|
||||
func (tl *mockTokenLoader) LoadAndLookup(tokenID string) (string, error) {
|
||||
if tokenID == tl.tokenID {
|
||||
return tl.token, nil
|
||||
}
|
||||
return "", errors.New(fmt.Sprintf("invalid token: %s", tokenID))
|
||||
}
|
||||
|
||||
const mockEndpoint1 = "https://192.168.1.5:8080"
|
||||
const mockEndpoint2 = "https://192.168.1.6:8080"
|
||||
|
||||
type mockEndpointsLoader struct {
|
||||
}
|
||||
|
||||
func (el *mockEndpointsLoader) LoadList() ([]string, error) {
|
||||
return []string{mockEndpoint1, mockEndpoint2}, nil
|
||||
}
|
||||
|
||||
const mockCA = "---BEGIN------END---DUMMYDATA"
|
||||
|
||||
type mockCALoader struct {
|
||||
}
|
||||
|
||||
func (cl *mockCALoader) LoadPEM() (string, error) {
|
||||
return mockCA, nil
|
||||
}
|
||||
|
||||
const mockTokenID = "AAAAAA"
|
||||
const mockToken = "9537434E638E4378"
|
||||
|
||||
const mockTokenIDCustom = "SHAREDSECRET"
|
||||
const mockTokenCustom = "VERYSECRETTOKEN"
|
||||
|
||||
func TestClusterInfoIndex(t *testing.T) {
|
||||
longToken := strings.Repeat("a", 1000)
|
||||
tests := map[string]struct {
|
||||
tokenID string // token ID the mock loader will use
|
||||
token string // token the mock loader will use
|
||||
reqTokenID string // token ID the will request with
|
||||
reqToken string // token the caller will validate response with
|
||||
expStatus int
|
||||
expVerifyFailure bool
|
||||
}{
|
||||
"no token": {
|
||||
tokenID: mockTokenID,
|
||||
token: mockToken,
|
||||
reqTokenID: "",
|
||||
reqToken: "",
|
||||
expStatus: http.StatusForbidden,
|
||||
},
|
||||
"valid token ID": {
|
||||
tokenID: mockTokenID,
|
||||
token: mockToken,
|
||||
reqTokenID: mockTokenID,
|
||||
reqToken: mockToken,
|
||||
expStatus: http.StatusOK,
|
||||
},
|
||||
"valid arbitrary string token": {
|
||||
tokenID: mockTokenIDCustom,
|
||||
token: mockTokenCustom,
|
||||
reqTokenID: mockTokenIDCustom,
|
||||
reqToken: mockTokenCustom,
|
||||
expStatus: http.StatusOK,
|
||||
},
|
||||
"valid arbitrary long string token": {
|
||||
tokenID: "LONGTOKENTEST",
|
||||
token: longToken,
|
||||
reqTokenID: "LONGTOKENTEST",
|
||||
reqToken: longToken,
|
||||
expStatus: http.StatusOK,
|
||||
},
|
||||
"invalid token ID": {
|
||||
tokenID: mockTokenID,
|
||||
token: mockToken,
|
||||
reqTokenID: "BADTOKENID",
|
||||
reqToken: mockToken,
|
||||
expStatus: http.StatusForbidden,
|
||||
},
|
||||
"invalid token": {
|
||||
tokenID: mockTokenID,
|
||||
token: mockToken,
|
||||
reqTokenID: mockTokenID,
|
||||
reqToken: "badtoken",
|
||||
expStatus: http.StatusOK,
|
||||
expVerifyFailure: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Logf("Running test: %s", name)
|
||||
tokenLoader := &mockTokenLoader{test.tokenID, test.token}
|
||||
// Create a request to pass to our handler. We don't have any query parameters for now, so we'll
|
||||
// pass 'nil' as the third parameter.
|
||||
url := "/cluster-info/v1/"
|
||||
if test.tokenID != "" {
|
||||
url = fmt.Sprintf("%s?token-id=%s", url, test.reqTokenID)
|
||||
}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := &ClusterInfoHandler{
|
||||
tokenLoader: tokenLoader,
|
||||
caLoader: &mockCALoader{},
|
||||
endpointsLoader: &mockEndpointsLoader{},
|
||||
}
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
if status := rr.Code; status != test.expStatus {
|
||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
||||
status, test.expStatus)
|
||||
continue
|
||||
}
|
||||
|
||||
// If we were expecting valid status validate the body:
|
||||
if test.expStatus == http.StatusOK {
|
||||
var ci ClusterInfo
|
||||
|
||||
body := string(rr.Body.Bytes())
|
||||
|
||||
// Parse the JSON web signature:
|
||||
jws, err := jose.ParseSigned(body)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing JWS from request body: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Now we can verify the signature on the payload. An error here would
|
||||
// indicate the the message failed to verify, e.g. because the signature was
|
||||
// broken or the message was tampered with.
|
||||
var clusterInfoBytes []byte
|
||||
hmacTestKey := []byte(test.reqToken)
|
||||
clusterInfoBytes, err = jws.Verify(hmacTestKey)
|
||||
|
||||
if test.expVerifyFailure {
|
||||
if err == nil {
|
||||
t.Errorf("Signature verification did not fail as expected.")
|
||||
}
|
||||
// We are done the test here either way.
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error verifing signature: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = json.Unmarshal(clusterInfoBytes, &ci)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to unmarshall payload to JSON: error=%s body=%s", err, rr.Body.String())
|
||||
continue
|
||||
}
|
||||
if len(ci.Endpoints) != 2 {
|
||||
t.Errorf("Expected 2 endpoints, got: %d", len(ci.Endpoints))
|
||||
}
|
||||
if mockEndpoint1 != ci.Endpoints[0] {
|
||||
t.Errorf("Unexpected endpoint: %s", ci.Endpoints[0])
|
||||
}
|
||||
if mockEndpoint2 != ci.Endpoints[1] {
|
||||
t.Errorf("Unexpected endpoint: %s", ci.Endpoints[1])
|
||||
}
|
||||
|
||||
if len(ci.CertificateAuthorities) != 1 {
|
||||
t.Errorf("Expected 1 root certificate, got: %d", len(ci.CertificateAuthorities))
|
||||
}
|
||||
if ci.CertificateAuthorities[0] != mockCA {
|
||||
t.Errorf("Expected CA: %s, got: %s", mockCA, ci.CertificateAuthorities[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
type ClusterInfo struct {
|
||||
// TODO Kind, apiVersion
|
||||
// TODO clusterId, fetchedTime, expiredTime
|
||||
CertificateAuthorities []string `json:"certificateAuthorities,omitempty"`
|
||||
Endpoints []string `json:"endpoints,omitempty"`
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Route struct {
|
||||
Name string
|
||||
Method string
|
||||
Pattern string
|
||||
Handler http.Handler
|
||||
}
|
||||
|
||||
type Routes []Route
|
||||
|
||||
var routes = Routes{
|
||||
Route{
|
||||
"ClusterInfoIndex",
|
||||
"GET",
|
||||
"/cluster-info/v1/",
|
||||
NewClusterInfoHandler(),
|
||||
},
|
||||
}
|
||||
|
||||
func NewRouter() *mux.Router {
|
||||
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
for _, route := range routes {
|
||||
router.
|
||||
Methods(route.Method).
|
||||
Path(route.Pattern).
|
||||
Name(route.Name).
|
||||
Handler(route.Handler)
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
kd "k8s.io/kubernetes/cmd/kube-discovery/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure we can load critical files, and be nice to the user by
|
||||
// printing descriptive error message when we fail.
|
||||
for desc, path := range map[string]string{
|
||||
"root CA certificate": kd.CAPath,
|
||||
"token map file": kd.TokenMapPath,
|
||||
"list of API endpoints": kd.EndpointListPath,
|
||||
} {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
log.Fatalf("%s does not exist: %s", desc, path)
|
||||
}
|
||||
// Test read permissions
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to open %s (%q [%s])", desc, path, err)
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
|
||||
router := kd.NewRouter()
|
||||
log.Printf("Listening for requests on port 9898.")
|
||||
log.Fatal(http.ListenAndServe(":9898", router))
|
||||
}
|
|
@ -14,7 +14,6 @@ cmd/kube-apiserver/app
|
|||
cmd/kube-apiserver/app/options
|
||||
cmd/kube-controller-manager
|
||||
cmd/kube-controller-manager/app/options
|
||||
cmd/kube-discovery
|
||||
cmd/kube-proxy
|
||||
cmd/kubeadm
|
||||
cmd/kubeadm/app/apis/kubeadm/install
|
||||
|
|
|
@ -29,7 +29,6 @@ kube::golang::server_targets() {
|
|||
cmd/kubelet
|
||||
cmd/kubeadm
|
||||
cmd/hyperkube
|
||||
cmd/kube-discovery
|
||||
vendor/k8s.io/kube-aggregator
|
||||
plugin/cmd/kube-scheduler
|
||||
)
|
||||
|
@ -190,7 +189,6 @@ readonly KUBE_STATIC_LIBRARIES=(
|
|||
kube-controller-manager
|
||||
kube-scheduler
|
||||
kube-proxy
|
||||
kube-discovery
|
||||
kube-aggregator
|
||||
kubeadm
|
||||
kubectl
|
||||
|
|
|
@ -569,7 +569,6 @@ k8s.io/kubernetes/cmd/genutils,rmmh,1,
|
|||
k8s.io/kubernetes/cmd/hyperkube,jbeda,0,
|
||||
k8s.io/kubernetes/cmd/kube-apiserver/app/options,nikhiljindal,0,
|
||||
k8s.io/kubernetes/cmd/kube-controller-manager/app,dchen1107,1,
|
||||
k8s.io/kubernetes/cmd/kube-discovery/app,pmorie,1,
|
||||
k8s.io/kubernetes/cmd/kube-proxy/app,luxas,1,
|
||||
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/install,ixdy,1,
|
||||
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation,caesarxuchao,1,
|
||||
|
|
|
Loading…
Reference in New Issue