mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08:13 +00:00 
			
		
		
		
	Remove the kube-discovery binary from the tree
This commit is contained in:
		| @@ -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. | ||||
|  | ||||
|  | ||||
| []() | ||||
| @@ -25,7 +25,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)) | ||||
| } | ||||
| @@ -13,7 +13,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 | ||||
|   | ||||
| @@ -31,7 +31,6 @@ kube::golang::server_targets() { | ||||
|     cmd/kubelet | ||||
|     cmd/kubeadm | ||||
|     cmd/hyperkube | ||||
|     cmd/kube-discovery | ||||
|     vendor/k8s.io/kube-aggregator | ||||
|     plugin/cmd/kube-scheduler | ||||
|   ) | ||||
| @@ -188,7 +187,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, | ||||
|   | ||||
| 
 | 
		Reference in New Issue
	
	Block a user
	 Lucas Käldström
					Lucas Käldström