Update dependencies
This commit is contained in:
parent
bf5616c65b
commit
d6d374b28d
13962 changed files with 48226 additions and 3618880 deletions
65
vendor/k8s.io/apiserver/pkg/server/filters/BUILD
generated
vendored
65
vendor/k8s.io/apiserver/pkg/server/filters/BUILD
generated
vendored
|
|
@ -1,65 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"compression_test.go",
|
||||
"cors_test.go",
|
||||
"maxinflight_test.go",
|
||||
"timeout_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/filters:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"compression.go",
|
||||
"cors.go",
|
||||
"doc.go",
|
||||
"longrunning.go",
|
||||
"maxinflight.go",
|
||||
"timeout.go",
|
||||
"wrap.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/metrics:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/httplog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
3
vendor/k8s.io/apiserver/pkg/server/filters/OWNERS
generated
vendored
3
vendor/k8s.io/apiserver/pkg/server/filters/OWNERS
generated
vendored
|
|
@ -1,3 +0,0 @@
|
|||
reviewers:
|
||||
- sttts
|
||||
- dims
|
||||
183
vendor/k8s.io/apiserver/pkg/server/filters/compression.go
generated
vendored
183
vendor/k8s.io/apiserver/pkg/server/filters/compression.go
generated
vendored
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 filters
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"compress/zlib"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
// Compressor is an interface to compression writers
|
||||
type Compressor interface {
|
||||
io.WriteCloser
|
||||
Flush() error
|
||||
}
|
||||
|
||||
const (
|
||||
headerAcceptEncoding = "Accept-Encoding"
|
||||
headerContentEncoding = "Content-Encoding"
|
||||
|
||||
encodingGzip = "gzip"
|
||||
encodingDeflate = "deflate"
|
||||
)
|
||||
|
||||
// WithCompression wraps an http.Handler with the Compression Handler
|
||||
func WithCompression(handler http.Handler, ctxMapper request.RequestContextMapper) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
wantsCompression, encoding := wantsCompressedResponse(req, ctxMapper)
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
if wantsCompression {
|
||||
compressionWriter, err := NewCompressionResponseWriter(w, encoding)
|
||||
if err != nil {
|
||||
handleError(w, req, err)
|
||||
runtime.HandleError(fmt.Errorf("failed to compress HTTP response: %v", err))
|
||||
return
|
||||
}
|
||||
compressionWriter.Header().Set("Content-Encoding", encoding)
|
||||
handler.ServeHTTP(compressionWriter, req)
|
||||
compressionWriter.(*compressionResponseWriter).Close()
|
||||
} else {
|
||||
handler.ServeHTTP(w, req)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// wantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested.
|
||||
func wantsCompressedResponse(req *http.Request, ctxMapper request.RequestContextMapper) (bool, string) {
|
||||
// don't compress watches
|
||||
ctx, ok := ctxMapper.Get(req)
|
||||
if !ok {
|
||||
return false, ""
|
||||
}
|
||||
info, ok := request.RequestInfoFrom(ctx)
|
||||
if !ok {
|
||||
return false, ""
|
||||
}
|
||||
if !info.IsResourceRequest {
|
||||
return false, ""
|
||||
}
|
||||
if info.Verb == "watch" {
|
||||
return false, ""
|
||||
}
|
||||
header := req.Header.Get(headerAcceptEncoding)
|
||||
gi := strings.Index(header, encodingGzip)
|
||||
zi := strings.Index(header, encodingDeflate)
|
||||
// use in order of appearance
|
||||
switch {
|
||||
case gi == -1:
|
||||
return zi != -1, encodingDeflate
|
||||
case zi == -1:
|
||||
return gi != -1, encodingGzip
|
||||
case gi < zi:
|
||||
return true, encodingGzip
|
||||
default:
|
||||
return true, encodingDeflate
|
||||
}
|
||||
}
|
||||
|
||||
type compressionResponseWriter struct {
|
||||
writer http.ResponseWriter
|
||||
compressor Compressor
|
||||
encoding string
|
||||
}
|
||||
|
||||
// NewCompressionResponseWriter returns wraps w with a compression ResponseWriter, using the given encoding
|
||||
func NewCompressionResponseWriter(w http.ResponseWriter, encoding string) (http.ResponseWriter, error) {
|
||||
var compressor Compressor
|
||||
switch encoding {
|
||||
case encodingGzip:
|
||||
compressor = gzip.NewWriter(w)
|
||||
case encodingDeflate:
|
||||
compressor = zlib.NewWriter(w)
|
||||
default:
|
||||
return nil, fmt.Errorf("%s is not a supported encoding type", encoding)
|
||||
}
|
||||
return &compressionResponseWriter{
|
||||
writer: w,
|
||||
compressor: compressor,
|
||||
encoding: encoding,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// compressionResponseWriter implements http.Responsewriter Interface
|
||||
var _ http.ResponseWriter = &compressionResponseWriter{}
|
||||
|
||||
func (c *compressionResponseWriter) Header() http.Header {
|
||||
return c.writer.Header()
|
||||
}
|
||||
|
||||
// compress data according to compression method
|
||||
func (c *compressionResponseWriter) Write(p []byte) (int, error) {
|
||||
if c.compressorClosed() {
|
||||
return -1, errors.New("compressing error: tried to write data using closed compressor")
|
||||
}
|
||||
c.Header().Set(headerContentEncoding, c.encoding)
|
||||
return c.compressor.Write(p)
|
||||
}
|
||||
|
||||
func (c *compressionResponseWriter) WriteHeader(status int) {
|
||||
c.writer.WriteHeader(status)
|
||||
}
|
||||
|
||||
// CloseNotify is part of http.CloseNotifier interface
|
||||
func (c *compressionResponseWriter) CloseNotify() <-chan bool {
|
||||
return c.writer.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
// Close the underlying compressor
|
||||
func (c *compressionResponseWriter) Close() error {
|
||||
if c.compressorClosed() {
|
||||
return errors.New("Compressing error: tried to close already closed compressor")
|
||||
}
|
||||
|
||||
c.compressor.Close()
|
||||
c.compressor = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *compressionResponseWriter) Flush() {
|
||||
if c.compressorClosed() {
|
||||
return
|
||||
}
|
||||
c.compressor.Flush()
|
||||
}
|
||||
|
||||
func (c *compressionResponseWriter) compressorClosed() bool {
|
||||
return nil == c.compressor
|
||||
}
|
||||
|
||||
// RestfulWithCompression wraps WithCompression to be compatible with go-restful
|
||||
func RestfulWithCompression(function restful.RouteFunction, ctxMapper request.RequestContextMapper) restful.RouteFunction {
|
||||
return restful.RouteFunction(func(request *restful.Request, response *restful.Response) {
|
||||
handler := WithCompression(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
response.ResponseWriter = w
|
||||
request.Request = req
|
||||
function(request, response)
|
||||
}), ctxMapper)
|
||||
handler.ServeHTTP(response.ResponseWriter, request.Request)
|
||||
})
|
||||
}
|
||||
110
vendor/k8s.io/apiserver/pkg/server/filters/compression_test.go
generated
vendored
110
vendor/k8s.io/apiserver/pkg/server/filters/compression_test.go
generated
vendored
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 filters
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/endpoints/filters"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
func TestCompression(t *testing.T) {
|
||||
tests := []struct {
|
||||
encoding string
|
||||
watch bool
|
||||
}{
|
||||
{"", false},
|
||||
{"gzip", true},
|
||||
{"gzip", false},
|
||||
}
|
||||
|
||||
responseData := []byte("1234")
|
||||
|
||||
requestContextMapper := request.NewRequestContextMapper()
|
||||
|
||||
for _, test := range tests {
|
||||
handler := WithCompression(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write(responseData)
|
||||
}),
|
||||
requestContextMapper,
|
||||
)
|
||||
handler = filters.WithRequestInfo(handler, newTestRequestInfoResolver(), requestContextMapper)
|
||||
handler = request.WithRequestContext(handler, requestContextMapper)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
DisableCompression: true,
|
||||
},
|
||||
}
|
||||
|
||||
url := server.URL + "/api/v1/pods"
|
||||
if test.watch {
|
||||
url = url + "?watch=1"
|
||||
}
|
||||
request, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
request.Header.Set("Accept-Encoding", test.encoding)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
var reader io.Reader
|
||||
if test.encoding == "gzip" && !test.watch {
|
||||
if response.Header.Get("Content-Encoding") != "gzip" {
|
||||
t.Fatal("expected response header Content-Encoding to be set to \"gzip\"")
|
||||
}
|
||||
if response.Header.Get("Vary") != "Accept-Encoding" {
|
||||
t.Fatal("expected response header Vary to be set to \"Accept-Encoding\"")
|
||||
}
|
||||
reader, err = gzip.NewReader(response.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if response.Header.Get("Content-Encoding") == "gzip" {
|
||||
t.Fatal("expected response header Content-Encoding not to be set")
|
||||
}
|
||||
reader = response.Body
|
||||
}
|
||||
body, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(body, responseData) {
|
||||
t.Fatalf("Expected response body %s to equal %s", body, responseData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newTestRequestInfoResolver() *request.RequestInfoFactory {
|
||||
return &request.RequestInfoFactory{
|
||||
APIPrefixes: sets.NewString("api", "apis"),
|
||||
GrouplessAPIPrefixes: sets.NewString("api"),
|
||||
}
|
||||
}
|
||||
98
vendor/k8s.io/apiserver/pkg/server/filters/cors.go
generated
vendored
98
vendor/k8s.io/apiserver/pkg/server/filters/cors.go
generated
vendored
|
|
@ -1,98 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// TODO: use restful.CrossOriginResourceSharing
|
||||
// See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and
|
||||
// github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go
|
||||
// Or, for a more detailed implementation use https://github.com/martini-contrib/cors
|
||||
// or implement CORS at your proxy layer.
|
||||
|
||||
// WithCORS is a simple CORS implementation that wraps an http Handler.
|
||||
// Pass nil for allowedMethods and allowedHeaders to use the defaults. If allowedOriginPatterns
|
||||
// is empty or nil, no CORS support is installed.
|
||||
func WithCORS(handler http.Handler, allowedOriginPatterns []string, allowedMethods []string, allowedHeaders []string, exposedHeaders []string, allowCredentials string) http.Handler {
|
||||
if len(allowedOriginPatterns) == 0 {
|
||||
return handler
|
||||
}
|
||||
allowedOriginPatternsREs := allowedOriginRegexps(allowedOriginPatterns)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
origin := req.Header.Get("Origin")
|
||||
if origin != "" {
|
||||
allowed := false
|
||||
for _, re := range allowedOriginPatternsREs {
|
||||
if allowed = re.MatchString(origin); allowed {
|
||||
break
|
||||
}
|
||||
}
|
||||
if allowed {
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
// Set defaults for methods and headers if nothing was passed
|
||||
if allowedMethods == nil {
|
||||
allowedMethods = []string{"POST", "GET", "OPTIONS", "PUT", "DELETE", "PATCH"}
|
||||
}
|
||||
if allowedHeaders == nil {
|
||||
allowedHeaders = []string{"Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "X-Requested-With", "If-Modified-Since"}
|
||||
}
|
||||
if exposedHeaders == nil {
|
||||
exposedHeaders = []string{"Date"}
|
||||
}
|
||||
w.Header().Set("Access-Control-Allow-Methods", strings.Join(allowedMethods, ", "))
|
||||
w.Header().Set("Access-Control-Allow-Headers", strings.Join(allowedHeaders, ", "))
|
||||
w.Header().Set("Access-Control-Expose-Headers", strings.Join(exposedHeaders, ", "))
|
||||
w.Header().Set("Access-Control-Allow-Credentials", allowCredentials)
|
||||
|
||||
// Stop here if its a preflight OPTIONS request
|
||||
if req.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dispatch to the next handler
|
||||
handler.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
func allowedOriginRegexps(allowedOrigins []string) []*regexp.Regexp {
|
||||
res, err := compileRegexps(allowedOrigins)
|
||||
if err != nil {
|
||||
glog.Fatalf("Invalid CORS allowed origin, --cors-allowed-origins flag was set to %v - %v", strings.Join(allowedOrigins, ","), err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Takes a list of strings and compiles them into a list of regular expressions
|
||||
func compileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) {
|
||||
regexps := []*regexp.Regexp{}
|
||||
for _, regexpStr := range regexpStrings {
|
||||
r, err := regexp.Compile(regexpStr)
|
||||
if err != nil {
|
||||
return []*regexp.Regexp{}, err
|
||||
}
|
||||
regexps = append(regexps, r)
|
||||
}
|
||||
return regexps, nil
|
||||
}
|
||||
183
vendor/k8s.io/apiserver/pkg/server/filters/cors_test.go
generated
vendored
183
vendor/k8s.io/apiserver/pkg/server/filters/cors_test.go
generated
vendored
|
|
@ -1,183 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCORSAllowedOrigins(t *testing.T) {
|
||||
table := []struct {
|
||||
allowedOrigins []string
|
||||
origin string
|
||||
allowed bool
|
||||
}{
|
||||
{[]string{}, "example.com", false},
|
||||
{[]string{"example.com"}, "example.com", true},
|
||||
{[]string{"example.com"}, "not-allowed.com", false},
|
||||
{[]string{"not-matching.com", "example.com"}, "example.com", true},
|
||||
{[]string{".*"}, "example.com", true},
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
handler := WithCORS(
|
||||
http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}),
|
||||
item.allowedOrigins, nil, nil, nil, "true",
|
||||
)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
client := http.Client{}
|
||||
|
||||
request, err := http.NewRequest("GET", server.URL+"/version", nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
request.Header.Set("Origin", item.origin)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if item.allowed {
|
||||
if !reflect.DeepEqual(item.origin, response.Header.Get("Access-Control-Allow-Origin")) {
|
||||
t.Errorf("Expected %#v, Got %#v", item.origin, response.Header.Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Credentials") == "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Credentials header to be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Headers") == "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Headers header to be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Methods") == "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Methods header to be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Expose-Headers") != "Date" {
|
||||
t.Errorf("Expected Date in Access-Control-Expose-Headers header")
|
||||
}
|
||||
} else {
|
||||
if response.Header.Get("Access-Control-Allow-Origin") != "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Origin header to not be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Credentials") != "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Credentials header to not be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Headers") != "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Headers header to not be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Allow-Methods") != "" {
|
||||
t.Errorf("Expected Access-Control-Allow-Methods header to not be set")
|
||||
}
|
||||
|
||||
if response.Header.Get("Access-Control-Expose-Headers") == "Date" {
|
||||
t.Errorf("Expected Date in Access-Control-Expose-Headers header")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSAllowedMethods(t *testing.T) {
|
||||
tests := []struct {
|
||||
allowedMethods []string
|
||||
method string
|
||||
allowed bool
|
||||
}{
|
||||
{nil, "POST", true},
|
||||
{nil, "GET", true},
|
||||
{nil, "OPTIONS", true},
|
||||
{nil, "PUT", true},
|
||||
{nil, "DELETE", true},
|
||||
{nil, "PATCH", true},
|
||||
{[]string{"GET", "POST"}, "PATCH", false},
|
||||
}
|
||||
|
||||
allowsMethod := func(res *http.Response, method string) bool {
|
||||
allowedMethods := strings.Split(res.Header.Get("Access-Control-Allow-Methods"), ",")
|
||||
for _, allowedMethod := range allowedMethods {
|
||||
if strings.TrimSpace(allowedMethod) == method {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
handler := WithCORS(
|
||||
http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}),
|
||||
[]string{".*"}, test.allowedMethods, nil, nil, "true",
|
||||
)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
client := http.Client{}
|
||||
|
||||
request, err := http.NewRequest(test.method, server.URL+"/version", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
request.Header.Set("Origin", "allowed.com")
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
methodAllowed := allowsMethod(response, test.method)
|
||||
switch {
|
||||
case test.allowed && !methodAllowed:
|
||||
t.Errorf("Expected %v to be allowed, Got only %#v", test.method, response.Header.Get("Access-Control-Allow-Methods"))
|
||||
case !test.allowed && methodAllowed:
|
||||
t.Errorf("Unexpected allowed method %v, Expected only %#v", test.method, response.Header.Get("Access-Control-Allow-Methods"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCompileRegex(t *testing.T) {
|
||||
uncompiledRegexes := []string{"endsWithMe$", "^startingWithMe"}
|
||||
regexes, err := compileRegexps(uncompiledRegexes)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Failed to compile legal regexes: '%v': %v", uncompiledRegexes, err)
|
||||
}
|
||||
if len(regexes) != len(uncompiledRegexes) {
|
||||
t.Errorf("Wrong number of regexes returned: '%v': %v", uncompiledRegexes, regexes)
|
||||
}
|
||||
|
||||
if !regexes[0].MatchString("Something that endsWithMe") {
|
||||
t.Errorf("Wrong regex returned: '%v': %v", uncompiledRegexes[0], regexes[0])
|
||||
}
|
||||
if regexes[0].MatchString("Something that doesn't endsWithMe.") {
|
||||
t.Errorf("Wrong regex returned: '%v': %v", uncompiledRegexes[0], regexes[0])
|
||||
}
|
||||
if !regexes[1].MatchString("startingWithMe is very important") {
|
||||
t.Errorf("Wrong regex returned: '%v': %v", uncompiledRegexes[1], regexes[1])
|
||||
}
|
||||
if regexes[1].MatchString("not startingWithMe should fail") {
|
||||
t.Errorf("Wrong regex returned: '%v': %v", uncompiledRegexes[1], regexes[1])
|
||||
}
|
||||
}
|
||||
19
vendor/k8s.io/apiserver/pkg/server/filters/doc.go
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/filters/doc.go
generated
vendored
|
|
@ -1,19 +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.
|
||||
*/
|
||||
|
||||
// Package filters contains all the http handler chain filters which
|
||||
// are not api related.
|
||||
package filters // import "k8s.io/apiserver/pkg/server/filters"
|
||||
37
vendor/k8s.io/apiserver/pkg/server/filters/longrunning.go
generated
vendored
37
vendor/k8s.io/apiserver/pkg/server/filters/longrunning.go
generated
vendored
|
|
@ -1,37 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
// BasicLongRunningRequestCheck returns true if the given request has one of the specified verbs or one of the specified subresources
|
||||
func BasicLongRunningRequestCheck(longRunningVerbs, longRunningSubresources sets.String) apirequest.LongRunningRequestCheck {
|
||||
return func(r *http.Request, requestInfo *apirequest.RequestInfo) bool {
|
||||
if longRunningVerbs.Has(requestInfo.Verb) {
|
||||
return true
|
||||
}
|
||||
if requestInfo.IsResourceRequest && longRunningSubresources.Has(requestInfo.Subresource) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
133
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
133
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
|
|
@ -1,133 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Constant for the retry-after interval on rate limiting.
|
||||
// TODO: maybe make this dynamic? or user-adjustable?
|
||||
const retryAfter = "1"
|
||||
|
||||
var nonMutatingRequestVerbs = sets.NewString("get", "list", "watch")
|
||||
|
||||
func handleError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Internal Server Error: %#v", r.RequestURI)
|
||||
glog.Errorf(err.Error())
|
||||
}
|
||||
|
||||
// WithMaxInFlightLimit limits the number of in-flight requests to buffer size of the passed in channel.
|
||||
func WithMaxInFlightLimit(
|
||||
handler http.Handler,
|
||||
nonMutatingLimit int,
|
||||
mutatingLimit int,
|
||||
requestContextMapper genericapirequest.RequestContextMapper,
|
||||
longRunningRequestCheck apirequest.LongRunningRequestCheck,
|
||||
) http.Handler {
|
||||
if nonMutatingLimit == 0 && mutatingLimit == 0 {
|
||||
return handler
|
||||
}
|
||||
var nonMutatingChan chan bool
|
||||
var mutatingChan chan bool
|
||||
if nonMutatingLimit != 0 {
|
||||
nonMutatingChan = make(chan bool, nonMutatingLimit)
|
||||
}
|
||||
if mutatingLimit != 0 {
|
||||
mutatingChan = make(chan bool, mutatingLimit)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, ok := requestContextMapper.Get(r)
|
||||
if !ok {
|
||||
handleError(w, r, fmt.Errorf("no context found for request, handler chain must be wrong"))
|
||||
return
|
||||
}
|
||||
requestInfo, ok := apirequest.RequestInfoFrom(ctx)
|
||||
if !ok {
|
||||
handleError(w, r, fmt.Errorf("no RequestInfo found in context, handler chain must be wrong"))
|
||||
return
|
||||
}
|
||||
|
||||
// Skip tracking long running events.
|
||||
if longRunningRequestCheck != nil && longRunningRequestCheck(r, requestInfo) {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
var c chan bool
|
||||
if !nonMutatingRequestVerbs.Has(requestInfo.Verb) {
|
||||
c = mutatingChan
|
||||
} else {
|
||||
c = nonMutatingChan
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
handler.ServeHTTP(w, r)
|
||||
} else {
|
||||
|
||||
select {
|
||||
case c <- true:
|
||||
defer func() { <-c }()
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
default:
|
||||
// at this point we're about to return a 429, BUT not all actors should be rate limited. A system:master is so powerful
|
||||
// that he should always get an answer. It's a super-admin or a loopback connection.
|
||||
if currUser, ok := apirequest.UserFrom(ctx); ok {
|
||||
for _, group := range currUser.GetGroups() {
|
||||
if group == user.SystemPrivilegedGroup {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
scope := "cluster"
|
||||
if requestInfo.Namespace != "" {
|
||||
scope = "namespace"
|
||||
}
|
||||
if requestInfo.Name != "" {
|
||||
scope = "resource"
|
||||
}
|
||||
if requestInfo.IsResourceRequest {
|
||||
metrics.MonitorRequest(r, strings.ToUpper(requestInfo.Verb), requestInfo.Resource, requestInfo.Subresource, "", scope, http.StatusTooManyRequests, 0, time.Now())
|
||||
} else {
|
||||
metrics.MonitorRequest(r, strings.ToUpper(requestInfo.Verb), "", requestInfo.Path, "", scope, http.StatusTooManyRequests, 0, time.Now())
|
||||
}
|
||||
tooManyRequests(r, w)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func tooManyRequests(req *http.Request, w http.ResponseWriter) {
|
||||
// Return a 429 status indicating "Too Many Requests"
|
||||
w.Header().Set("Retry-After", retryAfter)
|
||||
http.Error(w, "Too many requests, please try again later.", http.StatusTooManyRequests)
|
||||
}
|
||||
316
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight_test.go
generated
vendored
316
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight_test.go
generated
vendored
|
|
@ -1,316 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
apifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
func createMaxInflightServer(callsWg, blockWg *sync.WaitGroup, disableCallsWg *bool, disableCallsWgMutex *sync.Mutex, nonMutating, mutating int) *httptest.Server {
|
||||
longRunningRequestCheck := BasicLongRunningRequestCheck(sets.NewString("watch"), sets.NewString("proxy"))
|
||||
|
||||
requestContextMapper := apirequest.NewRequestContextMapper()
|
||||
requestInfoFactory := &apirequest.RequestInfoFactory{APIPrefixes: sets.NewString("apis", "api"), GrouplessAPIPrefixes: sets.NewString("api")}
|
||||
handler := WithMaxInFlightLimit(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// A short, accounted request that does not wait for block WaitGroup.
|
||||
if strings.Contains(r.URL.Path, "dontwait") {
|
||||
return
|
||||
}
|
||||
disableCallsWgMutex.Lock()
|
||||
waitForCalls := *disableCallsWg
|
||||
disableCallsWgMutex.Unlock()
|
||||
if waitForCalls {
|
||||
callsWg.Done()
|
||||
}
|
||||
blockWg.Wait()
|
||||
}),
|
||||
nonMutating,
|
||||
mutating,
|
||||
requestContextMapper,
|
||||
longRunningRequestCheck,
|
||||
)
|
||||
handler = withFakeUser(handler, requestContextMapper)
|
||||
handler = apifilters.WithRequestInfo(handler, requestInfoFactory, requestContextMapper)
|
||||
handler = apirequest.WithRequestContext(handler, requestContextMapper)
|
||||
|
||||
return httptest.NewServer(handler)
|
||||
}
|
||||
|
||||
func withFakeUser(handler http.Handler, requestContextMapper apirequest.RequestContextMapper) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, ok := requestContextMapper.Get(r)
|
||||
if !ok {
|
||||
handleError(w, r, fmt.Errorf("no context found for request, handler chain must be wrong"))
|
||||
return
|
||||
}
|
||||
|
||||
if len(r.Header["Groups"]) > 0 {
|
||||
requestContextMapper.Update(r, apirequest.WithUser(ctx, &user.DefaultInfo{
|
||||
Groups: r.Header["Groups"],
|
||||
}))
|
||||
}
|
||||
handler.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Tests that MaxInFlightLimit works, i.e.
|
||||
// - "long" requests such as proxy or watch, identified by regexp are not accounted despite
|
||||
// hanging for the long time,
|
||||
// - "short" requests are correctly accounted, i.e. there can be only size of channel passed to the
|
||||
// constructor in flight at any given moment,
|
||||
// - subsequent "short" requests are rejected instantly with appropriate error,
|
||||
// - subsequent "long" requests are handled normally,
|
||||
// - we correctly recover after some "short" requests finish, i.e. we can process new ones.
|
||||
func TestMaxInFlightNonMutating(t *testing.T) {
|
||||
const AllowedNonMutatingInflightRequestsNo = 3
|
||||
|
||||
// Calls is used to wait until all server calls are received. We are sending
|
||||
// AllowedNonMutatingInflightRequestsNo of 'long' not-accounted requests and the same number of
|
||||
// 'short' accounted ones.
|
||||
calls := &sync.WaitGroup{}
|
||||
calls.Add(AllowedNonMutatingInflightRequestsNo * 2)
|
||||
|
||||
// Responses is used to wait until all responses are
|
||||
// received. This prevents some async requests getting EOF
|
||||
// errors from prematurely closing the server
|
||||
responses := &sync.WaitGroup{}
|
||||
responses.Add(AllowedNonMutatingInflightRequestsNo * 2)
|
||||
|
||||
// Block is used to keep requests in flight for as long as we need to. All requests will
|
||||
// be unblocked at the same time.
|
||||
block := &sync.WaitGroup{}
|
||||
block.Add(1)
|
||||
|
||||
waitForCalls := true
|
||||
waitForCallsMutex := sync.Mutex{}
|
||||
|
||||
server := createMaxInflightServer(calls, block, &waitForCalls, &waitForCallsMutex, AllowedNonMutatingInflightRequestsNo, 1)
|
||||
defer server.Close()
|
||||
|
||||
// These should hang, but not affect accounting. use a query param match
|
||||
for i := 0; i < AllowedNonMutatingInflightRequestsNo; i++ {
|
||||
// These should hang waiting on block...
|
||||
go func() {
|
||||
if err := expectHTTPGet(server.URL+"/api/v1/namespaces/default/wait?watch=true", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
responses.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Check that sever is not saturated by not-accounted calls
|
||||
if err := expectHTTPGet(server.URL+"/dontwait", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// These should hang and be accounted, i.e. saturate the server
|
||||
for i := 0; i < AllowedNonMutatingInflightRequestsNo; i++ {
|
||||
// These should hang waiting on block...
|
||||
go func() {
|
||||
if err := expectHTTPGet(server.URL, http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
responses.Done()
|
||||
}()
|
||||
}
|
||||
// We wait for all calls to be received by the server
|
||||
calls.Wait()
|
||||
// Disable calls notifications in the server
|
||||
waitForCallsMutex.Lock()
|
||||
waitForCalls = false
|
||||
waitForCallsMutex.Unlock()
|
||||
|
||||
// Do this multiple times to show that rate limit rejected requests don't block.
|
||||
for i := 0; i < 2; i++ {
|
||||
if err := expectHTTPGet(server.URL, http.StatusTooManyRequests); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// Validate that non-accounted URLs still work. use a path regex match
|
||||
if err := expectHTTPGet(server.URL+"/api/v1/watch/namespaces/default/dontwait", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// We should allow a single mutating request.
|
||||
if err := expectHTTPPost(server.URL+"/dontwait", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Let all hanging requests finish
|
||||
block.Done()
|
||||
|
||||
// Show that we recover from being blocked up.
|
||||
// Too avoid flakyness we need to wait until at least one of the requests really finishes.
|
||||
responses.Wait()
|
||||
if err := expectHTTPGet(server.URL, http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxInFlightMutating(t *testing.T) {
|
||||
const AllowedMutatingInflightRequestsNo = 3
|
||||
|
||||
calls := &sync.WaitGroup{}
|
||||
calls.Add(AllowedMutatingInflightRequestsNo)
|
||||
|
||||
responses := &sync.WaitGroup{}
|
||||
responses.Add(AllowedMutatingInflightRequestsNo)
|
||||
|
||||
// Block is used to keep requests in flight for as long as we need to. All requests will
|
||||
// be unblocked at the same time.
|
||||
block := &sync.WaitGroup{}
|
||||
block.Add(1)
|
||||
|
||||
waitForCalls := true
|
||||
waitForCallsMutex := sync.Mutex{}
|
||||
|
||||
server := createMaxInflightServer(calls, block, &waitForCalls, &waitForCallsMutex, 1, AllowedMutatingInflightRequestsNo)
|
||||
defer server.Close()
|
||||
|
||||
// These should hang and be accounted, i.e. saturate the server
|
||||
for i := 0; i < AllowedMutatingInflightRequestsNo; i++ {
|
||||
// These should hang waiting on block...
|
||||
go func() {
|
||||
if err := expectHTTPPost(server.URL+"/foo/bar", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
responses.Done()
|
||||
}()
|
||||
}
|
||||
// We wait for all calls to be received by the server
|
||||
calls.Wait()
|
||||
// Disable calls notifications in the server
|
||||
// Disable calls notifications in the server
|
||||
waitForCallsMutex.Lock()
|
||||
waitForCalls = false
|
||||
waitForCallsMutex.Unlock()
|
||||
|
||||
// Do this multiple times to show that rate limit rejected requests don't block.
|
||||
for i := 0; i < 2; i++ {
|
||||
if err := expectHTTPPost(server.URL+"/foo/bar/", http.StatusTooManyRequests); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// Validate that non-mutating URLs still work. use a path regex match
|
||||
if err := expectHTTPGet(server.URL+"/dontwait", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Let all hanging requests finish
|
||||
block.Done()
|
||||
|
||||
// Show that we recover from being blocked up.
|
||||
// Too avoid flakyness we need to wait until at least one of the requests really finishes.
|
||||
responses.Wait()
|
||||
if err := expectHTTPPost(server.URL+"/foo/bar", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// We use GET as a sample non-mutating request.
|
||||
func expectHTTPGet(url string, code int) error {
|
||||
r, err := http.Get(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if r.StatusCode != code {
|
||||
return fmt.Errorf("unexpected response: %v", r.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// We use POST as a sample mutating request.
|
||||
func expectHTTPPost(url string, code int, groups ...string) error {
|
||||
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader("foo bar"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, group := range groups {
|
||||
req.Header.Add("Groups", group)
|
||||
}
|
||||
|
||||
r, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if r.StatusCode != code {
|
||||
return fmt.Errorf("unexpected response: %v", r.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMaxInFlightSkipsMasters(t *testing.T) {
|
||||
const AllowedMutatingInflightRequestsNo = 3
|
||||
|
||||
calls := &sync.WaitGroup{}
|
||||
calls.Add(AllowedMutatingInflightRequestsNo)
|
||||
|
||||
responses := &sync.WaitGroup{}
|
||||
responses.Add(AllowedMutatingInflightRequestsNo)
|
||||
|
||||
// Block is used to keep requests in flight for as long as we need to. All requests will
|
||||
// be unblocked at the same time.
|
||||
block := &sync.WaitGroup{}
|
||||
block.Add(1)
|
||||
|
||||
waitForCalls := true
|
||||
waitForCallsMutex := sync.Mutex{}
|
||||
|
||||
server := createMaxInflightServer(calls, block, &waitForCalls, &waitForCallsMutex, 1, AllowedMutatingInflightRequestsNo)
|
||||
defer server.Close()
|
||||
|
||||
// These should hang and be accounted, i.e. saturate the server
|
||||
for i := 0; i < AllowedMutatingInflightRequestsNo; i++ {
|
||||
// These should hang waiting on block...
|
||||
go func() {
|
||||
if err := expectHTTPPost(server.URL+"/foo/bar", http.StatusOK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
responses.Done()
|
||||
}()
|
||||
}
|
||||
// We wait for all calls to be received by the server
|
||||
calls.Wait()
|
||||
// Disable calls notifications in the server
|
||||
// Disable calls notifications in the server
|
||||
waitForCallsMutex.Lock()
|
||||
waitForCalls = false
|
||||
waitForCallsMutex.Unlock()
|
||||
|
||||
// Do this multiple times to show that rate limit rejected requests don't block.
|
||||
for i := 0; i < 2; i++ {
|
||||
if err := expectHTTPPost(server.URL+"/dontwait", http.StatusOK, user.SystemPrivilegedGroup); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Let all hanging requests finish
|
||||
block.Done()
|
||||
|
||||
responses.Wait()
|
||||
}
|
||||
287
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
287
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
|
|
@ -1,287 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
var errConnKilled = fmt.Errorf("kill connection/stream")
|
||||
|
||||
// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by timeout.
|
||||
func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, longRunning apirequest.LongRunningRequestCheck, timeout time.Duration) http.Handler {
|
||||
if longRunning == nil {
|
||||
return handler
|
||||
}
|
||||
timeoutFunc := func(req *http.Request) (<-chan time.Time, func(), *apierrors.StatusError) {
|
||||
// TODO unify this with apiserver.MaxInFlightLimit
|
||||
ctx, ok := requestContextMapper.Get(req)
|
||||
if !ok {
|
||||
// if this happens, the handler chain isn't setup correctly because there is no context mapper
|
||||
return time.After(timeout), func() {}, apierrors.NewInternalError(fmt.Errorf("no context found for request during timeout"))
|
||||
}
|
||||
|
||||
requestInfo, ok := apirequest.RequestInfoFrom(ctx)
|
||||
if !ok {
|
||||
// if this happens, the handler chain isn't setup correctly because there is no request info
|
||||
return time.After(timeout), func() {}, apierrors.NewInternalError(fmt.Errorf("no request info found for request during timeout"))
|
||||
}
|
||||
|
||||
if longRunning(req, requestInfo) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
now := time.Now()
|
||||
metricFn := func() {
|
||||
scope := "cluster"
|
||||
if requestInfo.Namespace != "" {
|
||||
scope = "namespace"
|
||||
}
|
||||
if requestInfo.Name != "" {
|
||||
scope = "resource"
|
||||
}
|
||||
if requestInfo.IsResourceRequest {
|
||||
metrics.MonitorRequest(req, strings.ToUpper(requestInfo.Verb), requestInfo.Resource, requestInfo.Subresource, "", scope, http.StatusGatewayTimeout, 0, now)
|
||||
} else {
|
||||
metrics.MonitorRequest(req, strings.ToUpper(requestInfo.Verb), "", requestInfo.Path, "", scope, http.StatusGatewayTimeout, 0, now)
|
||||
}
|
||||
}
|
||||
return time.After(timeout), metricFn, apierrors.NewTimeoutError(fmt.Sprintf("request did not complete within %s", timeout), 0)
|
||||
}
|
||||
return WithTimeout(handler, timeoutFunc)
|
||||
}
|
||||
|
||||
// WithTimeout returns an http.Handler that runs h with a timeout
|
||||
// determined by timeoutFunc. The new http.Handler calls h.ServeHTTP to handle
|
||||
// each request, but if a call runs for longer than its time limit, the
|
||||
// handler responds with a 504 Gateway Timeout error and the message
|
||||
// provided. (If msg is empty, a suitable default message will be sent.) After
|
||||
// the handler times out, writes by h to its http.ResponseWriter will return
|
||||
// http.ErrHandlerTimeout. If timeoutFunc returns a nil timeout channel, no
|
||||
// timeout will be enforced. recordFn is a function that will be invoked whenever
|
||||
// a timeout happens.
|
||||
func WithTimeout(h http.Handler, timeoutFunc func(*http.Request) (timeout <-chan time.Time, recordFn func(), err *apierrors.StatusError)) http.Handler {
|
||||
return &timeoutHandler{h, timeoutFunc}
|
||||
}
|
||||
|
||||
type timeoutHandler struct {
|
||||
handler http.Handler
|
||||
timeout func(*http.Request) (<-chan time.Time, func(), *apierrors.StatusError)
|
||||
}
|
||||
|
||||
func (t *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
after, recordFn, err := t.timeout(r)
|
||||
if after == nil {
|
||||
t.handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
tw := newTimeoutWriter(w)
|
||||
go func() {
|
||||
t.handler.ServeHTTP(tw, r)
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-after:
|
||||
recordFn()
|
||||
tw.timeout(err)
|
||||
}
|
||||
}
|
||||
|
||||
type timeoutWriter interface {
|
||||
http.ResponseWriter
|
||||
timeout(*apierrors.StatusError)
|
||||
}
|
||||
|
||||
func newTimeoutWriter(w http.ResponseWriter) timeoutWriter {
|
||||
base := &baseTimeoutWriter{w: w}
|
||||
|
||||
_, notifiable := w.(http.CloseNotifier)
|
||||
_, hijackable := w.(http.Hijacker)
|
||||
|
||||
switch {
|
||||
case notifiable && hijackable:
|
||||
return &closeHijackTimeoutWriter{base}
|
||||
case notifiable:
|
||||
return &closeTimeoutWriter{base}
|
||||
case hijackable:
|
||||
return &hijackTimeoutWriter{base}
|
||||
default:
|
||||
return base
|
||||
}
|
||||
}
|
||||
|
||||
type baseTimeoutWriter struct {
|
||||
w http.ResponseWriter
|
||||
|
||||
mu sync.Mutex
|
||||
// if the timeout handler has timedout
|
||||
timedOut bool
|
||||
// if this timeout writer has wrote header
|
||||
wroteHeader bool
|
||||
// if this timeout writer has been hijacked
|
||||
hijacked bool
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) Header() http.Header {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut {
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
return tw.w.Header()
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) Write(p []byte) (int, error) {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut {
|
||||
return 0, http.ErrHandlerTimeout
|
||||
}
|
||||
if tw.hijacked {
|
||||
return 0, http.ErrHijacked
|
||||
}
|
||||
|
||||
tw.wroteHeader = true
|
||||
return tw.w.Write(p)
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) Flush() {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut {
|
||||
return
|
||||
}
|
||||
|
||||
if flusher, ok := tw.w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) WriteHeader(code int) {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut || tw.wroteHeader || tw.hijacked {
|
||||
return
|
||||
}
|
||||
|
||||
tw.wroteHeader = true
|
||||
tw.w.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) timeout(err *apierrors.StatusError) {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
tw.timedOut = true
|
||||
|
||||
// The timeout writer has not been used by the inner handler.
|
||||
// We can safely timeout the HTTP request by sending by a timeout
|
||||
// handler
|
||||
if !tw.wroteHeader && !tw.hijacked {
|
||||
tw.w.WriteHeader(http.StatusGatewayTimeout)
|
||||
enc := json.NewEncoder(tw.w)
|
||||
enc.Encode(&err.ErrStatus)
|
||||
} else {
|
||||
// The timeout writer has been used by the inner handler. There is
|
||||
// no way to timeout the HTTP request at the point. We have to shutdown
|
||||
// the connection for HTTP1 or reset stream for HTTP2.
|
||||
//
|
||||
// Note from: Brad Fitzpatrick
|
||||
// if the ServeHTTP goroutine panics, that will do the best possible thing for both
|
||||
// HTTP/1 and HTTP/2. In HTTP/1, assuming you're replying with at least HTTP/1.1 and
|
||||
// you've already flushed the headers so it's using HTTP chunking, it'll kill the TCP
|
||||
// connection immediately without a proper 0-byte EOF chunk, so the peer will recognize
|
||||
// the response as bogus. In HTTP/2 the server will just RST_STREAM the stream, leaving
|
||||
// the TCP connection open, but resetting the stream to the peer so it'll have an error,
|
||||
// like the HTTP/1 case.
|
||||
panic(errConnKilled)
|
||||
}
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) closeNotify() <-chan bool {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut {
|
||||
done := make(chan bool)
|
||||
close(done)
|
||||
return done
|
||||
}
|
||||
|
||||
return tw.w.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (tw *baseTimeoutWriter) hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
tw.mu.Lock()
|
||||
defer tw.mu.Unlock()
|
||||
|
||||
if tw.timedOut {
|
||||
return nil, nil, http.ErrHandlerTimeout
|
||||
}
|
||||
conn, rw, err := tw.w.(http.Hijacker).Hijack()
|
||||
if err == nil {
|
||||
tw.hijacked = true
|
||||
}
|
||||
return conn, rw, err
|
||||
}
|
||||
|
||||
type closeTimeoutWriter struct {
|
||||
*baseTimeoutWriter
|
||||
}
|
||||
|
||||
func (tw *closeTimeoutWriter) CloseNotify() <-chan bool {
|
||||
return tw.closeNotify()
|
||||
}
|
||||
|
||||
type hijackTimeoutWriter struct {
|
||||
*baseTimeoutWriter
|
||||
}
|
||||
|
||||
func (tw *hijackTimeoutWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return tw.hijack()
|
||||
}
|
||||
|
||||
type closeHijackTimeoutWriter struct {
|
||||
*baseTimeoutWriter
|
||||
}
|
||||
|
||||
func (tw *closeHijackTimeoutWriter) CloseNotify() <-chan bool {
|
||||
return tw.closeNotify()
|
||||
}
|
||||
|
||||
func (tw *closeHijackTimeoutWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return tw.hijack()
|
||||
}
|
||||
117
vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go
generated
vendored
117
vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go
generated
vendored
|
|
@ -1,117 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
type recorder struct {
|
||||
lock sync.Mutex
|
||||
count int
|
||||
}
|
||||
|
||||
func (r *recorder) Record() {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
r.count++
|
||||
}
|
||||
|
||||
func (r *recorder) Count() int {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
return r.count
|
||||
}
|
||||
|
||||
func TestTimeout(t *testing.T) {
|
||||
sendResponse := make(chan struct{}, 1)
|
||||
writeErrors := make(chan error, 1)
|
||||
timeout := make(chan time.Time, 1)
|
||||
resp := "test response"
|
||||
timeoutErr := apierrors.NewServerTimeout(schema.GroupResource{Group: "foo", Resource: "bar"}, "get", 0)
|
||||
record := &recorder{}
|
||||
|
||||
ts := httptest.NewServer(WithTimeout(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
<-sendResponse
|
||||
_, err := w.Write([]byte(resp))
|
||||
writeErrors <- err
|
||||
}),
|
||||
func(*http.Request) (<-chan time.Time, func(), *apierrors.StatusError) {
|
||||
return timeout, record.Record, timeoutErr
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
// No timeouts
|
||||
sendResponse <- struct{}{}
|
||||
res, err := http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Errorf("got res.StatusCode %d; expected %d", res.StatusCode, http.StatusOK)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
if string(body) != resp {
|
||||
t.Errorf("got body %q; expected %q", string(body), resp)
|
||||
}
|
||||
if err := <-writeErrors; err != nil {
|
||||
t.Errorf("got unexpected Write error on first request: %v", err)
|
||||
}
|
||||
if record.Count() != 0 {
|
||||
t.Errorf("invoked record method: %#v", record)
|
||||
}
|
||||
|
||||
// Times out
|
||||
timeout <- time.Time{}
|
||||
res, err = http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != http.StatusGatewayTimeout {
|
||||
t.Errorf("got res.StatusCode %d; expected %d", res.StatusCode, http.StatusServiceUnavailable)
|
||||
}
|
||||
body, _ = ioutil.ReadAll(res.Body)
|
||||
status := &metav1.Status{}
|
||||
if err := json.Unmarshal(body, status); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(status, &timeoutErr.ErrStatus) {
|
||||
t.Errorf("unexpected object: %s", diff.ObjectReflectDiff(&timeoutErr.ErrStatus, status))
|
||||
}
|
||||
if record.Count() != 1 {
|
||||
t.Errorf("did not invoke record method: %#v", record)
|
||||
}
|
||||
|
||||
// Now try to send a response
|
||||
sendResponse <- struct{}{}
|
||||
if err := <-writeErrors; err != http.ErrHandlerTimeout {
|
||||
t.Errorf("got Write error of %v; expected %v", err, http.ErrHandlerTimeout)
|
||||
}
|
||||
}
|
||||
43
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
43
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
|
|
@ -1,43 +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.
|
||||
*/
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
)
|
||||
|
||||
// WithPanicRecovery wraps an http Handler to recover and log panics.
|
||||
func WithPanicRecovery(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
defer runtime.HandleCrash(func(err interface{}) {
|
||||
http.Error(w, "This request caused apisever to panic. Look in log for details.", http.StatusInternalServerError)
|
||||
glog.Errorf("APIServer panic'd on %v %v: %v\n%s\n", req.Method, req.RequestURI, err, debug.Stack())
|
||||
})
|
||||
|
||||
logger := httplog.NewLogged(req, &w)
|
||||
defer logger.Log()
|
||||
|
||||
// Dispatch to the internal handler
|
||||
handler.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
35
vendor/k8s.io/apiserver/pkg/server/httplog/BUILD
generated
vendored
35
vendor/k8s.io/apiserver/pkg/server/httplog/BUILD
generated
vendored
|
|
@ -1,35 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["httplog_test.go"],
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"httplog.go",
|
||||
],
|
||||
deps = ["//vendor/github.com/golang/glog:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
19
vendor/k8s.io/apiserver/pkg/server/httplog/doc.go
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/httplog/doc.go
generated
vendored
|
|
@ -1,19 +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 httplog contains a helper object and functions to maintain a log
|
||||
// along with an http response.
|
||||
package httplog // import "k8s.io/apiserver/pkg/server/httplog"
|
||||
213
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
213
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
|
|
@ -1,213 +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 httplog
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// StacktracePred returns true if a stacktrace should be logged for this status.
|
||||
type StacktracePred func(httpStatus int) (logStacktrace bool)
|
||||
|
||||
type logger interface {
|
||||
Addf(format string, data ...interface{})
|
||||
}
|
||||
|
||||
// Add a layer on top of ResponseWriter, so we can track latency and error
|
||||
// message sources.
|
||||
//
|
||||
// TODO now that we're using go-restful, we shouldn't need to be wrapping
|
||||
// the http.ResponseWriter. We can recover panics from go-restful, and
|
||||
// the logging value is questionable.
|
||||
type respLogger struct {
|
||||
hijacked bool
|
||||
statusRecorded bool
|
||||
status int
|
||||
statusStack string
|
||||
addedInfo string
|
||||
startTime time.Time
|
||||
|
||||
captureErrorOutput bool
|
||||
|
||||
req *http.Request
|
||||
w http.ResponseWriter
|
||||
|
||||
logStacktracePred StacktracePred
|
||||
}
|
||||
|
||||
// Simple logger that logs immediately when Addf is called
|
||||
type passthroughLogger struct{}
|
||||
|
||||
// Addf logs info immediately.
|
||||
func (passthroughLogger) Addf(format string, data ...interface{}) {
|
||||
glog.V(2).Info(fmt.Sprintf(format, data...))
|
||||
}
|
||||
|
||||
// DefaultStacktracePred is the default implementation of StacktracePred.
|
||||
func DefaultStacktracePred(status int) bool {
|
||||
return (status < http.StatusOK || status >= http.StatusInternalServerError) && status != http.StatusSwitchingProtocols
|
||||
}
|
||||
|
||||
// NewLogged turns a normal response writer into a logged response writer.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// defer NewLogged(req, &w).StacktraceWhen(StatusIsNot(200, 202)).Log()
|
||||
//
|
||||
// (Only the call to Log() is deferred, so you can set everything up in one line!)
|
||||
//
|
||||
// Note that this *changes* your writer, to route response writing actions
|
||||
// through the logger.
|
||||
//
|
||||
// Use LogOf(w).Addf(...) to log something along with the response result.
|
||||
func NewLogged(req *http.Request, w *http.ResponseWriter) *respLogger {
|
||||
if _, ok := (*w).(*respLogger); ok {
|
||||
// Don't double-wrap!
|
||||
panic("multiple NewLogged calls!")
|
||||
}
|
||||
rl := &respLogger{
|
||||
startTime: time.Now(),
|
||||
req: req,
|
||||
w: *w,
|
||||
logStacktracePred: DefaultStacktracePred,
|
||||
}
|
||||
*w = rl // hijack caller's writer!
|
||||
return rl
|
||||
}
|
||||
|
||||
// LogOf returns the logger hiding in w. If there is not an existing logger
|
||||
// then a passthroughLogger will be created which will log to stdout immediately
|
||||
// when Addf is called.
|
||||
func LogOf(req *http.Request, w http.ResponseWriter) logger {
|
||||
if _, exists := w.(*respLogger); !exists {
|
||||
pl := &passthroughLogger{}
|
||||
return pl
|
||||
}
|
||||
if rl, ok := w.(*respLogger); ok {
|
||||
return rl
|
||||
}
|
||||
panic("Unable to find or create the logger!")
|
||||
}
|
||||
|
||||
// Unlogged returns the original ResponseWriter, or w if it is not our inserted logger.
|
||||
func Unlogged(w http.ResponseWriter) http.ResponseWriter {
|
||||
if rl, ok := w.(*respLogger); ok {
|
||||
return rl.w
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// StacktraceWhen sets the stacktrace logging predicate, which decides when to log a stacktrace.
|
||||
// There's a default, so you don't need to call this unless you don't like the default.
|
||||
func (rl *respLogger) StacktraceWhen(pred StacktracePred) *respLogger {
|
||||
rl.logStacktracePred = pred
|
||||
return rl
|
||||
}
|
||||
|
||||
// StatusIsNot returns a StacktracePred which will cause stacktraces to be logged
|
||||
// for any status *not* in the given list.
|
||||
func StatusIsNot(statuses ...int) StacktracePred {
|
||||
return func(status int) bool {
|
||||
for _, s := range statuses {
|
||||
if status == s {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Addf adds additional data to be logged with this request.
|
||||
func (rl *respLogger) Addf(format string, data ...interface{}) {
|
||||
rl.addedInfo += "\n" + fmt.Sprintf(format, data...)
|
||||
}
|
||||
|
||||
// Log is intended to be called once at the end of your request handler, via defer
|
||||
func (rl *respLogger) Log() {
|
||||
latency := time.Since(rl.startTime)
|
||||
if glog.V(2) {
|
||||
if !rl.hijacked {
|
||||
glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) %v%v%v [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.status, rl.statusStack, rl.addedInfo, rl.req.Header["User-Agent"], rl.req.RemoteAddr))
|
||||
} else {
|
||||
glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) hijacked [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.req.Header["User-Agent"], rl.req.RemoteAddr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Header implements http.ResponseWriter.
|
||||
func (rl *respLogger) Header() http.Header {
|
||||
return rl.w.Header()
|
||||
}
|
||||
|
||||
// Write implements http.ResponseWriter.
|
||||
func (rl *respLogger) Write(b []byte) (int, error) {
|
||||
if !rl.statusRecorded {
|
||||
rl.recordStatus(http.StatusOK) // Default if WriteHeader hasn't been called
|
||||
}
|
||||
if rl.captureErrorOutput {
|
||||
rl.Addf("logging error output: %q\n", string(b))
|
||||
}
|
||||
return rl.w.Write(b)
|
||||
}
|
||||
|
||||
// Flush implements http.Flusher even if the underlying http.Writer doesn't implement it.
|
||||
// Flush is used for streaming purposes and allows to flush buffered data to the client.
|
||||
func (rl *respLogger) Flush() {
|
||||
if flusher, ok := rl.w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
} else if glog.V(2) {
|
||||
glog.InfoDepth(1, fmt.Sprintf("Unable to convert %+v into http.Flusher", rl.w))
|
||||
}
|
||||
}
|
||||
|
||||
// WriteHeader implements http.ResponseWriter.
|
||||
func (rl *respLogger) WriteHeader(status int) {
|
||||
rl.recordStatus(status)
|
||||
rl.w.WriteHeader(status)
|
||||
}
|
||||
|
||||
// Hijack implements http.Hijacker.
|
||||
func (rl *respLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
rl.hijacked = true
|
||||
return rl.w.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
// CloseNotify implements http.CloseNotifier
|
||||
func (rl *respLogger) CloseNotify() <-chan bool {
|
||||
return rl.w.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (rl *respLogger) recordStatus(status int) {
|
||||
rl.status = status
|
||||
rl.statusRecorded = true
|
||||
if rl.logStacktracePred(status) {
|
||||
// Only log stacks for errors
|
||||
stack := make([]byte, 50*1024)
|
||||
stack = stack[:runtime.Stack(stack, false)]
|
||||
rl.statusStack = "\n" + string(stack)
|
||||
rl.captureErrorOutput = true
|
||||
} else {
|
||||
rl.statusStack = ""
|
||||
}
|
||||
}
|
||||
152
vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go
generated
vendored
152
vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go
generated
vendored
|
|
@ -1,152 +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 httplog
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultStacktracePred(t *testing.T) {
|
||||
for _, x := range []int{101, 200, 204, 302, 400, 404} {
|
||||
if DefaultStacktracePred(x) {
|
||||
t.Fatalf("should not log on %v by default", x)
|
||||
}
|
||||
}
|
||||
|
||||
for _, x := range []int{500, 100} {
|
||||
if !DefaultStacktracePred(x) {
|
||||
t.Fatalf("should log on %v by default", x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusIsNot(t *testing.T) {
|
||||
statusTestTable := []struct {
|
||||
status int
|
||||
statuses []int
|
||||
want bool
|
||||
}{
|
||||
{http.StatusOK, []int{}, true},
|
||||
{http.StatusOK, []int{http.StatusOK}, false},
|
||||
{http.StatusCreated, []int{http.StatusOK, http.StatusAccepted}, true},
|
||||
}
|
||||
for _, tt := range statusTestTable {
|
||||
sp := StatusIsNot(tt.statuses...)
|
||||
got := sp(tt.status)
|
||||
if got != tt.want {
|
||||
t.Errorf("Expected %v, got %v", tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLogged(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||
NewLogged(req, &w)
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("Expected NewLogged to panic")
|
||||
}
|
||||
}()
|
||||
NewLogged(req, &w)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
}
|
||||
|
||||
func TestLogOf(t *testing.T) {
|
||||
logOfTests := []bool{true, false}
|
||||
for _, makeLogger := range logOfTests {
|
||||
req, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||
var want string
|
||||
if makeLogger {
|
||||
NewLogged(req, &w)
|
||||
want = "*httplog.respLogger"
|
||||
} else {
|
||||
want = "*httplog.passthroughLogger"
|
||||
}
|
||||
got := reflect.TypeOf(LogOf(r, w)).String()
|
||||
if want != got {
|
||||
t.Errorf("Expected %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnlogged(t *testing.T) {
|
||||
unloggedTests := []bool{true, false}
|
||||
for _, makeLogger := range unloggedTests {
|
||||
req, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||
want := w
|
||||
if makeLogger {
|
||||
NewLogged(req, &w)
|
||||
}
|
||||
got := Unlogged(w)
|
||||
if want != got {
|
||||
t.Errorf("Expected %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
type testResponseWriter struct{}
|
||||
|
||||
func (*testResponseWriter) Header() http.Header { return nil }
|
||||
func (*testResponseWriter) Write([]byte) (int, error) { return 0, nil }
|
||||
func (*testResponseWriter) WriteHeader(int) {}
|
||||
|
||||
func TestLoggedStatus(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
var tw http.ResponseWriter = new(testResponseWriter)
|
||||
logger := NewLogged(req, &tw)
|
||||
logger.Write(nil)
|
||||
|
||||
if logger.status != http.StatusOK {
|
||||
t.Errorf("expected status after write to be %v, got %v", http.StatusOK, logger.status)
|
||||
}
|
||||
|
||||
tw = new(testResponseWriter)
|
||||
logger = NewLogged(req, &tw)
|
||||
logger.WriteHeader(http.StatusForbidden)
|
||||
logger.Write(nil)
|
||||
|
||||
if logger.status != http.StatusForbidden {
|
||||
t.Errorf("expected status after write to remain %v, got %v", http.StatusForbidden, logger.status)
|
||||
}
|
||||
}
|
||||
40
vendor/k8s.io/apiserver/pkg/server/mux/BUILD
generated
vendored
40
vendor/k8s.io/apiserver/pkg/server/mux/BUILD
generated
vendored
|
|
@ -1,40 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["pathrecorder_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = ["//vendor/github.com/stretchr/testify/assert:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"pathrecorder.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
2
vendor/k8s.io/apiserver/pkg/server/mux/OWNERS
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/mux/OWNERS
generated
vendored
|
|
@ -1,2 +0,0 @@
|
|||
reviewers:
|
||||
- sttts
|
||||
18
vendor/k8s.io/apiserver/pkg/server/mux/doc.go
generated
vendored
18
vendor/k8s.io/apiserver/pkg/server/mux/doc.go
generated
vendored
|
|
@ -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.
|
||||
*/
|
||||
|
||||
// Package mux contains abstractions for http multiplexing of APIs.
|
||||
package mux
|
||||
278
vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go
generated
vendored
278
vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go
generated
vendored
|
|
@ -1,278 +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.
|
||||
*/
|
||||
|
||||
package mux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// PathRecorderMux wraps a mux object and records the registered exposedPaths.
|
||||
type PathRecorderMux struct {
|
||||
// name is used for logging so you can trace requests through
|
||||
name string
|
||||
|
||||
lock sync.Mutex
|
||||
notFoundHandler http.Handler
|
||||
pathToHandler map[string]http.Handler
|
||||
prefixToHandler map[string]http.Handler
|
||||
|
||||
// mux stores a pathHandler and is used to handle the actual serving.
|
||||
// Turns out, we want to accept trailing slashes, BUT we don't care about handling
|
||||
// everything under them. This does exactly matches only unless its explicitly requested to
|
||||
// do something different
|
||||
mux atomic.Value
|
||||
|
||||
// exposedPaths is the list of paths that should be shown at /
|
||||
exposedPaths []string
|
||||
|
||||
// pathStacks holds the stacks of all registered paths. This allows us to show a more helpful message
|
||||
// before the "http: multiple registrations for %s" panic.
|
||||
pathStacks map[string]string
|
||||
}
|
||||
|
||||
// pathHandler is an http.Handler that will satify requests first by exact match, then by prefix,
|
||||
// then by notFoundHandler
|
||||
type pathHandler struct {
|
||||
// muxName is used for logging so you can trace requests through
|
||||
muxName string
|
||||
|
||||
// pathToHandler is a map of exactly matching request to its handler
|
||||
pathToHandler map[string]http.Handler
|
||||
|
||||
// this has to be sorted by most slashes then by length
|
||||
prefixHandlers []prefixHandler
|
||||
|
||||
// notFoundHandler is the handler to use for satisfying requests with no other match
|
||||
notFoundHandler http.Handler
|
||||
}
|
||||
|
||||
// prefixHandler holds the prefix it should match and the handler to use
|
||||
type prefixHandler struct {
|
||||
// prefix is the prefix to test for a request match
|
||||
prefix string
|
||||
// handler is used to satisfy matching requests
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
// NewPathRecorderMux creates a new PathRecorderMux
|
||||
func NewPathRecorderMux(name string) *PathRecorderMux {
|
||||
ret := &PathRecorderMux{
|
||||
name: name,
|
||||
pathToHandler: map[string]http.Handler{},
|
||||
prefixToHandler: map[string]http.Handler{},
|
||||
mux: atomic.Value{},
|
||||
exposedPaths: []string{},
|
||||
pathStacks: map[string]string{},
|
||||
}
|
||||
|
||||
ret.mux.Store(&pathHandler{notFoundHandler: http.NotFoundHandler()})
|
||||
return ret
|
||||
}
|
||||
|
||||
// ListedPaths returns the registered handler exposedPaths.
|
||||
func (m *PathRecorderMux) ListedPaths() []string {
|
||||
handledPaths := append([]string{}, m.exposedPaths...)
|
||||
sort.Strings(handledPaths)
|
||||
|
||||
return handledPaths
|
||||
}
|
||||
|
||||
func (m *PathRecorderMux) trackCallers(path string) {
|
||||
if existingStack, ok := m.pathStacks[path]; ok {
|
||||
utilruntime.HandleError(fmt.Errorf("registered %q from %v", path, existingStack))
|
||||
}
|
||||
m.pathStacks[path] = string(debug.Stack())
|
||||
}
|
||||
|
||||
// refreshMuxLocked creates a new mux and must be called while locked. Otherwise the view of handlers may
|
||||
// not be consistent
|
||||
func (m *PathRecorderMux) refreshMuxLocked() {
|
||||
newMux := &pathHandler{
|
||||
muxName: m.name,
|
||||
pathToHandler: map[string]http.Handler{},
|
||||
prefixHandlers: []prefixHandler{},
|
||||
notFoundHandler: http.NotFoundHandler(),
|
||||
}
|
||||
if m.notFoundHandler != nil {
|
||||
newMux.notFoundHandler = m.notFoundHandler
|
||||
}
|
||||
for path, handler := range m.pathToHandler {
|
||||
newMux.pathToHandler[path] = handler
|
||||
}
|
||||
|
||||
keys := sets.StringKeySet(m.prefixToHandler).List()
|
||||
sort.Sort(sort.Reverse(byPrefixPriority(keys)))
|
||||
for _, prefix := range keys {
|
||||
newMux.prefixHandlers = append(newMux.prefixHandlers, prefixHandler{
|
||||
prefix: prefix,
|
||||
handler: m.prefixToHandler[prefix],
|
||||
})
|
||||
}
|
||||
|
||||
m.mux.Store(newMux)
|
||||
}
|
||||
|
||||
// NotFoundHandler sets the handler to use if there's no match for a give path
|
||||
func (m *PathRecorderMux) NotFoundHandler(notFoundHandler http.Handler) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
m.notFoundHandler = notFoundHandler
|
||||
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// Unregister removes a path from the mux.
|
||||
func (m *PathRecorderMux) Unregister(path string) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
delete(m.pathToHandler, path)
|
||||
delete(m.prefixToHandler, path)
|
||||
delete(m.pathStacks, path)
|
||||
for i := range m.exposedPaths {
|
||||
if m.exposedPaths[i] == path {
|
||||
m.exposedPaths = append(m.exposedPaths[:i], m.exposedPaths[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// Handle registers the handler for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
func (m *PathRecorderMux) Handle(path string, handler http.Handler) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.trackCallers(path)
|
||||
|
||||
m.exposedPaths = append(m.exposedPaths, path)
|
||||
m.pathToHandler[path] = handler
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// HandleFunc registers the handler function for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
func (m *PathRecorderMux) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
m.Handle(path, http.HandlerFunc(handler))
|
||||
}
|
||||
|
||||
// UnlistedHandle registers the handler for the given pattern, but doesn't list it.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
func (m *PathRecorderMux) UnlistedHandle(path string, handler http.Handler) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.trackCallers(path)
|
||||
|
||||
m.pathToHandler[path] = handler
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// UnlistedHandleFunc registers the handler function for the given pattern, but doesn't list it.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
func (m *PathRecorderMux) UnlistedHandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
m.UnlistedHandle(path, http.HandlerFunc(handler))
|
||||
}
|
||||
|
||||
// HandlePrefix is like Handle, but matches for anything under the path. Like a standard golang trailing slash.
|
||||
func (m *PathRecorderMux) HandlePrefix(path string, handler http.Handler) {
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
panic(fmt.Sprintf("%q must end in a trailing slash", path))
|
||||
}
|
||||
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.trackCallers(path)
|
||||
|
||||
m.exposedPaths = append(m.exposedPaths, path)
|
||||
m.prefixToHandler[path] = handler
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// UnlistedHandlePrefix is like UnlistedHandle, but matches for anything under the path. Like a standard golang trailing slash.
|
||||
func (m *PathRecorderMux) UnlistedHandlePrefix(path string, handler http.Handler) {
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
panic(fmt.Sprintf("%q must end in a trailing slash", path))
|
||||
}
|
||||
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.trackCallers(path)
|
||||
|
||||
m.prefixToHandler[path] = handler
|
||||
m.refreshMuxLocked()
|
||||
}
|
||||
|
||||
// ServeHTTP makes it an http.Handler
|
||||
func (m *PathRecorderMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m.mux.Load().(*pathHandler).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// ServeHTTP makes it an http.Handler
|
||||
func (h *pathHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if exactHandler, ok := h.pathToHandler[r.URL.Path]; ok {
|
||||
glog.V(5).Infof("%v: %q satisfied by exact match", h.muxName, r.URL.Path)
|
||||
exactHandler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
for _, prefixHandler := range h.prefixHandlers {
|
||||
if strings.HasPrefix(r.URL.Path, prefixHandler.prefix) {
|
||||
glog.V(5).Infof("%v: %q satisfied by prefix %v", h.muxName, r.URL.Path, prefixHandler.prefix)
|
||||
prefixHandler.handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(5).Infof("%v: %q satisfied by NotFoundHandler", h.muxName, r.URL.Path)
|
||||
h.notFoundHandler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// byPrefixPriority sorts url prefixes by the order in which they should be tested by the mux
|
||||
// this has to be sorted by most slashes then by length so that we can iterate straight
|
||||
// through to match the "best" one first.
|
||||
type byPrefixPriority []string
|
||||
|
||||
func (s byPrefixPriority) Len() int { return len(s) }
|
||||
func (s byPrefixPriority) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byPrefixPriority) Less(i, j int) bool {
|
||||
lhsNumParts := strings.Count(s[i], "/")
|
||||
rhsNumParts := strings.Count(s[j], "/")
|
||||
if lhsNumParts != rhsNumParts {
|
||||
return lhsNumParts < rhsNumParts
|
||||
}
|
||||
|
||||
lhsLen := len(s[i])
|
||||
rhsLen := len(s[j])
|
||||
if lhsLen != rhsLen {
|
||||
return lhsLen < rhsLen
|
||||
}
|
||||
|
||||
return strings.Compare(s[i], s[j]) < 0
|
||||
}
|
||||
135
vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go
generated
vendored
135
vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder_test.go
generated
vendored
|
|
@ -1,135 +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.
|
||||
*/
|
||||
|
||||
package mux
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSecretHandlers(t *testing.T) {
|
||||
c := NewPathRecorderMux("test")
|
||||
c.UnlistedHandleFunc("/secret", func(http.ResponseWriter, *http.Request) {})
|
||||
c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {})
|
||||
assert.NotContains(t, c.ListedPaths(), "/secret")
|
||||
assert.Contains(t, c.ListedPaths(), "/nonswagger")
|
||||
}
|
||||
|
||||
func TestUnregisterHandlers(t *testing.T) {
|
||||
first := 0
|
||||
second := 0
|
||||
|
||||
c := NewPathRecorderMux("test")
|
||||
s := httptest.NewServer(c)
|
||||
defer s.Close()
|
||||
|
||||
c.UnlistedHandleFunc("/secret", func(http.ResponseWriter, *http.Request) {})
|
||||
c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {
|
||||
first = first + 1
|
||||
})
|
||||
assert.NotContains(t, c.ListedPaths(), "/secret")
|
||||
assert.Contains(t, c.ListedPaths(), "/nonswagger")
|
||||
|
||||
resp, _ := http.Get(s.URL + "/nonswagger")
|
||||
assert.Equal(t, first, 1)
|
||||
assert.Equal(t, resp.StatusCode, http.StatusOK)
|
||||
|
||||
c.Unregister("/nonswagger")
|
||||
assert.NotContains(t, c.ListedPaths(), "/nonswagger")
|
||||
|
||||
resp, _ = http.Get(s.URL + "/nonswagger")
|
||||
assert.Equal(t, first, 1)
|
||||
assert.Equal(t, resp.StatusCode, http.StatusNotFound)
|
||||
|
||||
c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {
|
||||
second = second + 1
|
||||
})
|
||||
assert.Contains(t, c.ListedPaths(), "/nonswagger")
|
||||
resp, _ = http.Get(s.URL + "/nonswagger")
|
||||
assert.Equal(t, first, 1)
|
||||
assert.Equal(t, second, 1)
|
||||
assert.Equal(t, resp.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestPrefixHandlers(t *testing.T) {
|
||||
c := NewPathRecorderMux("test")
|
||||
s := httptest.NewServer(c)
|
||||
defer s.Close()
|
||||
|
||||
secretPrefixCount := 0
|
||||
c.UnlistedHandlePrefix("/secretPrefix/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
secretPrefixCount = secretPrefixCount + 1
|
||||
}))
|
||||
publicPrefixCount := 0
|
||||
c.HandlePrefix("/publicPrefix/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
publicPrefixCount = publicPrefixCount + 1
|
||||
}))
|
||||
precisePrefixCount := 0
|
||||
c.HandlePrefix("/publicPrefix/but-more-precise/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
precisePrefixCount = precisePrefixCount + 1
|
||||
}))
|
||||
exactMatchCount := 0
|
||||
c.Handle("/publicPrefix/exactmatch", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
exactMatchCount = exactMatchCount + 1
|
||||
}))
|
||||
slashMatchCount := 0
|
||||
c.Handle("/otherPublic/exactmatchslash/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
slashMatchCount = slashMatchCount + 1
|
||||
}))
|
||||
fallThroughCount := 0
|
||||
c.NotFoundHandler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
fallThroughCount = fallThroughCount + 1
|
||||
}))
|
||||
|
||||
assert.NotContains(t, c.ListedPaths(), "/secretPrefix/")
|
||||
assert.Contains(t, c.ListedPaths(), "/publicPrefix/")
|
||||
|
||||
resp, _ := http.Get(s.URL + "/fallthrough")
|
||||
assert.Equal(t, 1, fallThroughCount)
|
||||
assert.Equal(t, resp.StatusCode, http.StatusOK)
|
||||
resp, _ = http.Get(s.URL + "/publicPrefix")
|
||||
assert.Equal(t, 2, fallThroughCount)
|
||||
assert.Equal(t, resp.StatusCode, http.StatusOK)
|
||||
|
||||
http.Get(s.URL + "/publicPrefix/")
|
||||
assert.Equal(t, 1, publicPrefixCount)
|
||||
http.Get(s.URL + "/publicPrefix/something")
|
||||
assert.Equal(t, 2, publicPrefixCount)
|
||||
http.Get(s.URL + "/publicPrefix/but-more-precise")
|
||||
assert.Equal(t, 3, publicPrefixCount)
|
||||
http.Get(s.URL + "/publicPrefix/but-more-precise/")
|
||||
assert.Equal(t, 1, precisePrefixCount)
|
||||
http.Get(s.URL + "/publicPrefix/but-more-precise/more-stuff")
|
||||
assert.Equal(t, 2, precisePrefixCount)
|
||||
|
||||
http.Get(s.URL + "/publicPrefix/exactmatch")
|
||||
assert.Equal(t, 1, exactMatchCount)
|
||||
http.Get(s.URL + "/publicPrefix/exactmatch/")
|
||||
assert.Equal(t, 4, publicPrefixCount)
|
||||
http.Get(s.URL + "/otherPublic/exactmatchslash")
|
||||
assert.Equal(t, 3, fallThroughCount)
|
||||
http.Get(s.URL + "/otherPublic/exactmatchslash/")
|
||||
assert.Equal(t, 1, slashMatchCount)
|
||||
|
||||
http.Get(s.URL + "/secretPrefix/")
|
||||
assert.Equal(t, 1, secretPrefixCount)
|
||||
http.Get(s.URL + "/secretPrefix/something")
|
||||
assert.Equal(t, 2, secretPrefixCount)
|
||||
}
|
||||
102
vendor/k8s.io/apiserver/pkg/server/options/BUILD
generated
vendored
102
vendor/k8s.io/apiserver/pkg/server/options/BUILD
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["serving_test.go"],
|
||||
data = glob(["testdata/**"]),
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"admission.go",
|
||||
"audit.go",
|
||||
"authentication.go",
|
||||
"authorization.go",
|
||||
"coreapi.go",
|
||||
"doc.go",
|
||||
"etcd.go",
|
||||
"feature.go",
|
||||
"recommended.go",
|
||||
"server_run_options.go",
|
||||
"serving.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/pborman/uuid:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/gopkg.in/natefinch/lumberjack.v2:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/etcd3/preflight:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/plugin/pkg/audit/log:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/plugin/pkg/audit/webhook:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "testdata",
|
||||
srcs = glob(["testdata/*"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
15
vendor/k8s.io/apiserver/pkg/server/options/OWNERS
generated
vendored
15
vendor/k8s.io/apiserver/pkg/server/options/OWNERS
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
reviewers:
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- sttts
|
||||
- jlowdermilk
|
||||
- soltysh
|
||||
- dims
|
||||
- cjcullen
|
||||
- ericchiang
|
||||
- ping035627
|
||||
- xiangpengzhao
|
||||
- enj
|
||||
97
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
97
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/admission/initializer"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// AdmissionOptions holds the admission options
|
||||
type AdmissionOptions struct {
|
||||
PluginNames []string
|
||||
ConfigFile string
|
||||
Plugins *admission.Plugins
|
||||
}
|
||||
|
||||
// NewAdmissionOptions creates a new instance of AdmissionOptions
|
||||
// Note:
|
||||
// In addition it calls RegisterAllAdmissionPlugins to register
|
||||
// all generic admission plugins.
|
||||
func NewAdmissionOptions() *AdmissionOptions {
|
||||
options := &AdmissionOptions{
|
||||
Plugins: &admission.Plugins{},
|
||||
PluginNames: []string{},
|
||||
}
|
||||
server.RegisterAllAdmissionPlugins(options.Plugins)
|
||||
return options
|
||||
}
|
||||
|
||||
// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
|
||||
func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringSliceVar(&a.PluginNames, "admission-control", a.PluginNames, ""+
|
||||
"Ordered list of plug-ins to do admission control of resources into cluster. "+
|
||||
"Comma-delimited list of: "+strings.Join(a.Plugins.Registered(), ", ")+".")
|
||||
|
||||
fs.StringVar(&a.ConfigFile, "admission-control-config-file", a.ConfigFile,
|
||||
"File with admission control configuration.")
|
||||
}
|
||||
|
||||
// ApplyTo adds the admission chain to the server configuration
|
||||
// the method lazily initializes a generic plugin that is appended to the list of pluginInitializers
|
||||
// note this method uses:
|
||||
// genericconfig.LoopbackClientConfig
|
||||
// genericconfig.SharedInformerFactory
|
||||
// genericconfig.Authorizer
|
||||
func (a *AdmissionOptions) ApplyTo(c *server.Config, informers informers.SharedInformerFactory, pluginInitializers ...admission.PluginInitializer) error {
|
||||
pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(a.PluginNames, a.ConfigFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read plugin config: %v", err)
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(c.LoopbackClientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genericInitializer, err := initializer.New(clientset, informers, c.Authorizer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initializersChain := admission.PluginInitializers{}
|
||||
pluginInitializers = append(pluginInitializers, genericInitializer)
|
||||
initializersChain = append(initializersChain, pluginInitializers...)
|
||||
|
||||
admissionChain, err := a.Plugins.NewFromPlugins(a.PluginNames, pluginsConfigProvider, initializersChain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.AdmissionControl = admissionChain
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AdmissionOptions) Validate() []error {
|
||||
errs := []error{}
|
||||
return errs
|
||||
}
|
||||
265
vendor/k8s.io/apiserver/pkg/server/options/audit.go
generated
vendored
265
vendor/k8s.io/apiserver/pkg/server/options/audit.go
generated
vendored
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
pluginlog "k8s.io/apiserver/plugin/pkg/audit/log"
|
||||
pluginwebhook "k8s.io/apiserver/plugin/pkg/audit/webhook"
|
||||
)
|
||||
|
||||
func appendBackend(existing, newBackend audit.Backend) audit.Backend {
|
||||
if existing == nil {
|
||||
return newBackend
|
||||
}
|
||||
return audit.Union(existing, newBackend)
|
||||
}
|
||||
|
||||
func advancedAuditingEnabled() bool {
|
||||
return utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing)
|
||||
}
|
||||
|
||||
type AuditOptions struct {
|
||||
// Policy configuration file for filtering audit events that are captured.
|
||||
// If unspecified, a default is provided.
|
||||
PolicyFile string
|
||||
|
||||
// Plugin options
|
||||
|
||||
LogOptions AuditLogOptions
|
||||
WebhookOptions AuditWebhookOptions
|
||||
}
|
||||
|
||||
// AuditLogOptions determines the output of the structured audit log by default.
|
||||
// If the AdvancedAuditing feature is set to false, AuditLogOptions holds the legacy
|
||||
// audit log writer.
|
||||
type AuditLogOptions struct {
|
||||
Path string
|
||||
MaxAge int
|
||||
MaxBackups int
|
||||
MaxSize int
|
||||
Format string
|
||||
}
|
||||
|
||||
// AuditWebhookOptions control the webhook configuration for audit events.
|
||||
type AuditWebhookOptions struct {
|
||||
ConfigFile string
|
||||
// Should the webhook asynchronous batch events to the webhook backend or
|
||||
// should the webhook block responses?
|
||||
//
|
||||
// Defaults to asynchronous batch events.
|
||||
Mode string
|
||||
}
|
||||
|
||||
func NewAuditOptions() *AuditOptions {
|
||||
return &AuditOptions{
|
||||
WebhookOptions: AuditWebhookOptions{Mode: pluginwebhook.ModeBatch},
|
||||
LogOptions: AuditLogOptions{Format: pluginlog.FormatJson},
|
||||
}
|
||||
}
|
||||
|
||||
// Validate checks invalid config combination
|
||||
func (o *AuditOptions) Validate() []error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
allErrors := []error{}
|
||||
|
||||
if !advancedAuditingEnabled() {
|
||||
if len(o.PolicyFile) > 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-policy-file", features.AdvancedAuditing))
|
||||
}
|
||||
if len(o.WebhookOptions.ConfigFile) > 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-webhook-config-file", features.AdvancedAuditing))
|
||||
}
|
||||
} else {
|
||||
// check webhook mode
|
||||
validMode := false
|
||||
for _, m := range pluginwebhook.AllowedModes {
|
||||
if m == o.WebhookOptions.Mode {
|
||||
validMode = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validMode {
|
||||
allErrors = append(allErrors, fmt.Errorf("invalid audit webhook mode %s, allowed modes are %q", o.WebhookOptions.Mode, strings.Join(pluginwebhook.AllowedModes, ",")))
|
||||
}
|
||||
|
||||
// check log format
|
||||
validFormat := false
|
||||
for _, f := range pluginlog.AllowedFormats {
|
||||
if f == o.LogOptions.Format {
|
||||
validFormat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validFormat {
|
||||
allErrors = append(allErrors, fmt.Errorf("invalid audit log format %s, allowed formats are %q", o.LogOptions.Format, strings.Join(pluginlog.AllowedFormats, ",")))
|
||||
}
|
||||
}
|
||||
|
||||
// Check validities of MaxAge, MaxBackups and MaxSize of log options
|
||||
if o.LogOptions.MaxAge < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("--audit-log-maxage %v can't be a negative number", o.LogOptions.MaxAge))
|
||||
}
|
||||
if o.LogOptions.MaxBackups < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("--audit-log-maxbackup %v can't be a negative number", o.LogOptions.MaxBackups))
|
||||
}
|
||||
if o.LogOptions.MaxSize < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("--audit-log-maxsize %v can't be a negative number", o.LogOptions.MaxSize))
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func (o *AuditOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringVar(&o.PolicyFile, "audit-policy-file", o.PolicyFile,
|
||||
"Path to the file that defines the audit policy configuration. Requires the 'AdvancedAuditing' feature gate."+
|
||||
" With AdvancedAuditing, a profile is required to enable auditing.")
|
||||
|
||||
o.LogOptions.AddFlags(fs)
|
||||
o.WebhookOptions.AddFlags(fs)
|
||||
}
|
||||
|
||||
func (o *AuditOptions) ApplyTo(c *server.Config) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply legacy audit options if advanced audit is not enabled.
|
||||
if !advancedAuditingEnabled() {
|
||||
return o.LogOptions.legacyApplyTo(c)
|
||||
}
|
||||
|
||||
// Apply advanced options if advanced audit is enabled.
|
||||
// 1. Apply generic options.
|
||||
if err := o.applyTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. Apply plugin options.
|
||||
if err := o.LogOptions.advancedApplyTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.WebhookOptions.applyTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.AuditBackend != nil && c.AuditPolicyChecker == nil {
|
||||
glog.V(2).Info("No audit policy file provided for AdvancedAuditing, no events will be recorded.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AuditOptions) applyTo(c *server.Config) error {
|
||||
if o.PolicyFile == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
p, err := policy.LoadPolicyFromFile(o.PolicyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading audit policy file: %v", err)
|
||||
}
|
||||
c.AuditPolicyChecker = policy.NewChecker(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&o.Path, "audit-log-path", o.Path,
|
||||
"If set, all requests coming to the apiserver will be logged to this file. '-' means standard out.")
|
||||
fs.IntVar(&o.MaxAge, "audit-log-maxage", o.MaxBackups,
|
||||
"The maximum number of days to retain old audit log files based on the timestamp encoded in their filename.")
|
||||
fs.IntVar(&o.MaxBackups, "audit-log-maxbackup", o.MaxBackups,
|
||||
"The maximum number of old audit log files to retain.")
|
||||
fs.IntVar(&o.MaxSize, "audit-log-maxsize", o.MaxSize,
|
||||
"The maximum size in megabytes of the audit log file before it gets rotated.")
|
||||
fs.StringVar(&o.Format, "audit-log-format", o.Format,
|
||||
"Format of saved audits. \"legacy\" indicates 1-line text format for each event."+
|
||||
" \"json\" indicates structured json format. Requires the 'AdvancedAuditing' feature"+
|
||||
" gate. Known formats are "+strings.Join(pluginlog.AllowedFormats, ",")+".")
|
||||
}
|
||||
|
||||
func (o *AuditLogOptions) getWriter() io.Writer {
|
||||
if o.Path == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var w io.Writer = os.Stdout
|
||||
if o.Path != "-" {
|
||||
w = &lumberjack.Logger{
|
||||
Filename: o.Path,
|
||||
MaxAge: o.MaxAge,
|
||||
MaxBackups: o.MaxBackups,
|
||||
MaxSize: o.MaxSize,
|
||||
}
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func (o *AuditLogOptions) advancedApplyTo(c *server.Config) error {
|
||||
if w := o.getWriter(); w != nil {
|
||||
c.AuditBackend = appendBackend(c.AuditBackend, pluginlog.NewBackend(w, o.Format, auditv1beta1.SchemeGroupVersion))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AuditLogOptions) legacyApplyTo(c *server.Config) error {
|
||||
c.LegacyAuditWriter = o.getWriter()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AuditWebhookOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&o.ConfigFile, "audit-webhook-config-file", o.ConfigFile,
|
||||
"Path to a kubeconfig formatted file that defines the audit webhook configuration."+
|
||||
" Requires the 'AdvancedAuditing' feature gate.")
|
||||
fs.StringVar(&o.Mode, "audit-webhook-mode", o.Mode,
|
||||
"Strategy for sending audit events. Blocking indicates sending events should block"+
|
||||
" server responses. Batch causes the webhook to buffer and send events"+
|
||||
" asynchronously. Known modes are "+strings.Join(pluginwebhook.AllowedModes, ",")+".")
|
||||
}
|
||||
|
||||
func (o *AuditWebhookOptions) applyTo(c *server.Config) error {
|
||||
if o.ConfigFile == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, o.Mode, auditv1beta1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing audit webhook: %v", err)
|
||||
}
|
||||
c.AuditBackend = appendBackend(c.AuditBackend, webhook)
|
||||
return nil
|
||||
}
|
||||
388
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
388
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
|
|
@ -1,388 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
|
||||
coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
type RequestHeaderAuthenticationOptions struct {
|
||||
UsernameHeaders []string
|
||||
GroupHeaders []string
|
||||
ExtraHeaderPrefixes []string
|
||||
ClientCAFile string
|
||||
AllowedNames []string
|
||||
}
|
||||
|
||||
func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringSliceVar(&s.UsernameHeaders, "requestheader-username-headers", s.UsernameHeaders, ""+
|
||||
"List of request headers to inspect for usernames. X-Remote-User is common.")
|
||||
|
||||
fs.StringSliceVar(&s.GroupHeaders, "requestheader-group-headers", s.GroupHeaders, ""+
|
||||
"List of request headers to inspect for groups. X-Remote-Group is suggested.")
|
||||
|
||||
fs.StringSliceVar(&s.ExtraHeaderPrefixes, "requestheader-extra-headers-prefix", s.ExtraHeaderPrefixes, ""+
|
||||
"List of request header prefixes to inspect. X-Remote-Extra- is suggested.")
|
||||
|
||||
fs.StringVar(&s.ClientCAFile, "requestheader-client-ca-file", s.ClientCAFile, ""+
|
||||
"Root certificate bundle to use to verify client certificates on incoming requests "+
|
||||
"before trusting usernames in headers specified by --requestheader-username-headers")
|
||||
|
||||
fs.StringSliceVar(&s.AllowedNames, "requestheader-allowed-names", s.AllowedNames, ""+
|
||||
"List of client certificate common names to allow to provide usernames in headers "+
|
||||
"specified by --requestheader-username-headers. If empty, any client certificate validated "+
|
||||
"by the authorities in --requestheader-client-ca-file is allowed.")
|
||||
}
|
||||
|
||||
// ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options
|
||||
// if necessary, nil otherwise.
|
||||
func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig {
|
||||
if len(s.ClientCAFile) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &authenticatorfactory.RequestHeaderConfig{
|
||||
UsernameHeaders: s.UsernameHeaders,
|
||||
GroupHeaders: s.GroupHeaders,
|
||||
ExtraHeaderPrefixes: s.ExtraHeaderPrefixes,
|
||||
ClientCA: s.ClientCAFile,
|
||||
AllowedClientNames: s.AllowedNames,
|
||||
}
|
||||
}
|
||||
|
||||
type ClientCertAuthenticationOptions struct {
|
||||
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
||||
ClientCA string
|
||||
}
|
||||
|
||||
func (s *ClientCertAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.ClientCA, "client-ca-file", s.ClientCA, ""+
|
||||
"If set, any request presenting a client certificate signed by one of "+
|
||||
"the authorities in the client-ca-file is authenticated with an identity "+
|
||||
"corresponding to the CommonName of the client certificate.")
|
||||
}
|
||||
|
||||
// DelegatingAuthenticationOptions provides an easy way for composing API servers to delegate their authentication to
|
||||
// the root kube API server. The API federator will act as
|
||||
// a front proxy and direction connections will be able to delegate to the core kube API server
|
||||
type DelegatingAuthenticationOptions struct {
|
||||
// RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
|
||||
// TokenAccessReview.authentication.k8s.io endpoint for checking tokens.
|
||||
RemoteKubeConfigFile string
|
||||
|
||||
// CacheTTL is the length of time that a token authentication answer will be cached.
|
||||
CacheTTL time.Duration
|
||||
|
||||
ClientCert ClientCertAuthenticationOptions
|
||||
RequestHeader RequestHeaderAuthenticationOptions
|
||||
|
||||
SkipInClusterLookup bool
|
||||
}
|
||||
|
||||
func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
|
||||
return &DelegatingAuthenticationOptions{
|
||||
// very low for responsiveness, but high enough to handle storms
|
||||
CacheTTL: 10 * time.Second,
|
||||
ClientCert: ClientCertAuthenticationOptions{},
|
||||
RequestHeader: RequestHeaderAuthenticationOptions{
|
||||
UsernameHeaders: []string{"x-remote-user"},
|
||||
GroupHeaders: []string{"x-remote-group"},
|
||||
ExtraHeaderPrefixes: []string{"x-remote-extra-"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) Validate() []error {
|
||||
allErrors := []error{}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+
|
||||
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
|
||||
"tokenaccessreviews.authentication.k8s.io.")
|
||||
|
||||
fs.DurationVar(&s.CacheTTL, "authentication-token-webhook-cache-ttl", s.CacheTTL,
|
||||
"The duration to cache responses from the webhook token authenticator.")
|
||||
|
||||
s.ClientCert.AddFlags(fs)
|
||||
s.RequestHeader.AddFlags(fs)
|
||||
|
||||
fs.BoolVar(&s.SkipInClusterLookup, "authentication-skip-lookup", s.SkipInClusterLookup, ""+
|
||||
"If false, the authentication-kubeconfig will be used to lookup missing authentication "+
|
||||
"configuration from the cluster.")
|
||||
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) ApplyTo(c *server.Config) error {
|
||||
if s == nil {
|
||||
c.Authenticator = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
clientCA, err := s.getClientCA()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err = c.ApplyClientCert(clientCA.ClientCA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load client CA file: %v", err)
|
||||
}
|
||||
|
||||
requestHeader, err := s.getRequestHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err = c.ApplyClientCert(requestHeader.ClientCAFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load client CA file: %v", err)
|
||||
}
|
||||
|
||||
cfg, err := s.ToAuthenticationConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authenticator, securityDefinitions, err := cfg.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Authenticator = authenticator
|
||||
if c.OpenAPIConfig != nil {
|
||||
c.OpenAPIConfig.SecurityDefinitions = securityDefinitions
|
||||
}
|
||||
c.SupportsBasicAuth = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig() (authenticatorfactory.DelegatingAuthenticatorConfig, error) {
|
||||
tokenClient, err := s.newTokenAccessReview()
|
||||
if err != nil {
|
||||
return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
|
||||
}
|
||||
|
||||
clientCA, err := s.getClientCA()
|
||||
if err != nil {
|
||||
return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
|
||||
}
|
||||
requestHeader, err := s.getRequestHeader()
|
||||
if err != nil {
|
||||
return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
|
||||
}
|
||||
|
||||
ret := authenticatorfactory.DelegatingAuthenticatorConfig{
|
||||
Anonymous: true,
|
||||
TokenAccessReviewClient: tokenClient,
|
||||
CacheTTL: s.CacheTTL,
|
||||
ClientCAFile: clientCA.ClientCA,
|
||||
RequestHeaderConfig: requestHeader.ToAuthenticationRequestHeaderConfig(),
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
const (
|
||||
authenticationConfigMapNamespace = metav1.NamespaceSystem
|
||||
authenticationConfigMapName = "extension-apiserver-authentication"
|
||||
authenticationRoleName = "extension-apiserver-authentication-reader"
|
||||
)
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) getClientCA() (*ClientCertAuthenticationOptions, error) {
|
||||
if len(s.ClientCert.ClientCA) > 0 || s.SkipInClusterLookup {
|
||||
return &s.ClientCert, nil
|
||||
}
|
||||
|
||||
incluster, err := s.lookupInClusterClientCA()
|
||||
if err != nil {
|
||||
glog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
|
||||
"'kubectl create rolebinding -n %s ROLE_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
|
||||
authenticationConfigMapName, authenticationConfigMapNamespace, authenticationConfigMapNamespace, authenticationRoleName)
|
||||
return nil, err
|
||||
}
|
||||
if incluster == nil {
|
||||
return nil, fmt.Errorf("cluster doesn't provide client-ca-file")
|
||||
}
|
||||
return incluster, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) getRequestHeader() (*RequestHeaderAuthenticationOptions, error) {
|
||||
if len(s.RequestHeader.ClientCAFile) > 0 || s.SkipInClusterLookup {
|
||||
return &s.RequestHeader, nil
|
||||
}
|
||||
|
||||
incluster, err := s.lookupInClusterRequestHeader()
|
||||
if err != nil {
|
||||
glog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
|
||||
"'kubectl create rolebinding -n %s ROLE_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
|
||||
authenticationConfigMapName, authenticationConfigMapNamespace, authenticationConfigMapNamespace, authenticationRoleName)
|
||||
return nil, err
|
||||
}
|
||||
if incluster == nil {
|
||||
return nil, fmt.Errorf("cluster doesn't provide requestheader-client-ca-file")
|
||||
}
|
||||
return incluster, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) lookupInClusterClientCA() (*ClientCertAuthenticationOptions, error) {
|
||||
clientConfig, err := s.getClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := coreclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authConfigMap, err := client.ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientCA, ok := authConfigMap.Data["client-ca-file"]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile("", "client-ca-file")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(clientCA), 0600); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ClientCertAuthenticationOptions{ClientCA: f.Name()}, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) lookupInClusterRequestHeader() (*RequestHeaderAuthenticationOptions, error) {
|
||||
clientConfig, err := s.getClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := coreclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authConfigMap, err := client.ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestHeaderCA, ok := authConfigMap.Data["requestheader-client-ca-file"]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile("", "requestheader-client-ca-file")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(requestHeaderCA), 0600); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usernameHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-username-headers"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-group-headers"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extraHeaderPrefixes, err := deserializeStrings(authConfigMap.Data["requestheader-extra-headers-prefix"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allowedNames, err := deserializeStrings(authConfigMap.Data["requestheader-allowed-names"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &RequestHeaderAuthenticationOptions{
|
||||
UsernameHeaders: usernameHeaders,
|
||||
GroupHeaders: groupHeaders,
|
||||
ExtraHeaderPrefixes: extraHeaderPrefixes,
|
||||
ClientCAFile: f.Name(),
|
||||
AllowedNames: allowedNames,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func deserializeStrings(in string) ([]string, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var ret []string
|
||||
if err := json.Unmarshal([]byte(in), &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) getClientConfig() (*rest.Config, error) {
|
||||
var clientConfig *rest.Config
|
||||
var err error
|
||||
if len(s.RemoteKubeConfigFile) > 0 {
|
||||
loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
|
||||
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||
|
||||
clientConfig, err = loader.ClientConfig()
|
||||
|
||||
} else {
|
||||
// without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
|
||||
// use this path
|
||||
clientConfig, err = rest.InClusterConfig()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set high qps/burst limits since this will effectively limit API server responsiveness
|
||||
clientConfig.QPS = 200
|
||||
clientConfig.Burst = 400
|
||||
|
||||
return clientConfig, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authenticationclient.TokenReviewInterface, error) {
|
||||
clientConfig, err := s.getClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := authenticationclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client.TokenReviews(), nil
|
||||
}
|
||||
138
vendor/k8s.io/apiserver/pkg/server/options/authorization.go
generated
vendored
138
vendor/k8s.io/apiserver/pkg/server/options/authorization.go
generated
vendored
|
|
@ -1,138 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// DelegatingAuthorizationOptions provides an easy way for composing API servers to delegate their authorization to
|
||||
// the root kube API server
|
||||
type DelegatingAuthorizationOptions struct {
|
||||
// RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
|
||||
// SubjectAccessReview.authorization.k8s.io endpoint for checking tokens.
|
||||
RemoteKubeConfigFile string
|
||||
|
||||
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
||||
AllowCacheTTL time.Duration
|
||||
|
||||
// DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
|
||||
// You generally want more responsive, "deny, try again" flows.
|
||||
DenyCacheTTL time.Duration
|
||||
}
|
||||
|
||||
func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions {
|
||||
return &DelegatingAuthorizationOptions{
|
||||
// very low for responsiveness, but high enough to handle storms
|
||||
AllowCacheTTL: 10 * time.Second,
|
||||
DenyCacheTTL: 10 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) Validate() []error {
|
||||
allErrors := []error{}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringVar(&s.RemoteKubeConfigFile, "authorization-kubeconfig", s.RemoteKubeConfigFile, ""+
|
||||
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
|
||||
" subjectaccessreviews.authorization.k8s.io.")
|
||||
|
||||
fs.DurationVar(&s.AllowCacheTTL, "authorization-webhook-cache-authorized-ttl",
|
||||
s.AllowCacheTTL,
|
||||
"The duration to cache 'authorized' responses from the webhook authorizer.")
|
||||
|
||||
fs.DurationVar(&s.DenyCacheTTL,
|
||||
"authorization-webhook-cache-unauthorized-ttl", s.DenyCacheTTL,
|
||||
"The duration to cache 'unauthorized' responses from the webhook authorizer.")
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) ApplyTo(c *server.Config) error {
|
||||
if s == nil {
|
||||
c.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg, err := s.ToAuthorizationConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorizer, err := cfg.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Authorizer = authorizer
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizerfactory.DelegatingAuthorizerConfig, error) {
|
||||
sarClient, err := s.newSubjectAccessReview()
|
||||
if err != nil {
|
||||
return authorizerfactory.DelegatingAuthorizerConfig{}, err
|
||||
}
|
||||
|
||||
ret := authorizerfactory.DelegatingAuthorizerConfig{
|
||||
SubjectAccessReviewClient: sarClient,
|
||||
AllowCacheTTL: s.AllowCacheTTL,
|
||||
DenyCacheTTL: s.DenyCacheTTL,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) newSubjectAccessReview() (authorizationclient.SubjectAccessReviewInterface, error) {
|
||||
var clientConfig *rest.Config
|
||||
var err error
|
||||
if len(s.RemoteKubeConfigFile) > 0 {
|
||||
loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
|
||||
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||
|
||||
clientConfig, err = loader.ClientConfig()
|
||||
|
||||
} else {
|
||||
// without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
|
||||
// use this path
|
||||
clientConfig, err = rest.InClusterConfig()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set high qps/burst limits since this will effectively limit API server responsiveness
|
||||
clientConfig.QPS = 200
|
||||
clientConfig.Burst = 400
|
||||
|
||||
client, err := authorizationclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client.SubjectAccessReviews(), nil
|
||||
}
|
||||
83
vendor/k8s.io/apiserver/pkg/server/options/coreapi.go
generated
vendored
83
vendor/k8s.io/apiserver/pkg/server/options/coreapi.go
generated
vendored
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
clientgoinformers "k8s.io/client-go/informers"
|
||||
clientgoclientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// CoreAPIOptions contains options to configure the connection to a core API Kubernetes apiserver.
|
||||
type CoreAPIOptions struct {
|
||||
// CoreAPIKubeconfigPath is a filename for a kubeconfig file to contact the core API server with.
|
||||
// If it is not set, the in cluster config is used.
|
||||
CoreAPIKubeconfigPath string
|
||||
}
|
||||
|
||||
func NewCoreAPIOptions() *CoreAPIOptions {
|
||||
return &CoreAPIOptions{}
|
||||
}
|
||||
|
||||
func (o *CoreAPIOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringVar(&o.CoreAPIKubeconfigPath, "kubeconfig", o.CoreAPIKubeconfigPath,
|
||||
"kubeconfig file pointing at the 'core' kubernetes server.")
|
||||
}
|
||||
|
||||
func (o *CoreAPIOptions) ApplyTo(config *server.RecommendedConfig) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create shared informer for Kubernetes APIs
|
||||
var kubeconfig *rest.Config
|
||||
var err error
|
||||
if len(o.CoreAPIKubeconfigPath) > 0 {
|
||||
loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: o.CoreAPIKubeconfigPath}
|
||||
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||
kubeconfig, err = loader.ClientConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load kubeconfig at %q: %v", o.CoreAPIKubeconfigPath, err)
|
||||
}
|
||||
} else {
|
||||
kubeconfig, err = rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeconfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create Kubernetes clientset: %v", err)
|
||||
}
|
||||
config.SharedInformerFactory = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CoreAPIOptions) Validate() []error {
|
||||
return nil
|
||||
}
|
||||
21
vendor/k8s.io/apiserver/pkg/server/options/doc.go
generated
vendored
21
vendor/k8s.io/apiserver/pkg/server/options/doc.go
generated
vendored
|
|
@ -1,21 +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.
|
||||
*/
|
||||
|
||||
// package options is the public flags and options used by a generic api
|
||||
// server. It takes a minimal set of dependencies and does not reference
|
||||
// implementations, in order to ensure it may be reused by multiple components
|
||||
// (such as CLI commands that wish to generate or validate config).
|
||||
package options // import "k8s.io/apiserver/pkg/server/options"
|
||||
50
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD
generated
vendored
50
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD
generated
vendored
|
|
@ -1,50 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"config.go",
|
||||
"plugins.go",
|
||||
"types.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/aes:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/identity:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/secretbox:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["encryptionconfig_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
295
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
295
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 encryptionconfig
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
yaml "github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
|
||||
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
|
||||
"k8s.io/apiserver/pkg/storage/value/encrypt/identity"
|
||||
"k8s.io/apiserver/pkg/storage/value/encrypt/secretbox"
|
||||
)
|
||||
|
||||
const (
|
||||
aesCBCTransformerPrefixV1 = "k8s:enc:aescbc:v1:"
|
||||
aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:"
|
||||
secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:"
|
||||
kmsTransformerPrefixV1 = "k8s:enc:kms:v1:"
|
||||
)
|
||||
|
||||
// GetTransformerOverrides returns the transformer overrides by reading and parsing the encryption provider configuration file
|
||||
func GetTransformerOverrides(filepath string) (map[schema.GroupResource]value.Transformer, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening encryption provider configuration file %q: %v", filepath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
result, err := ParseEncryptionConfiguration(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing encryption provider configuration file %q: %v", filepath, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ParseEncryptionConfiguration parses configuration data and returns the transformer overrides
|
||||
func ParseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.Transformer, error) {
|
||||
configFileContents, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read contents: %v", err)
|
||||
}
|
||||
|
||||
var config EncryptionConfig
|
||||
err = yaml.Unmarshal(configFileContents, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing file: %v", err)
|
||||
}
|
||||
|
||||
if config.Kind == "" {
|
||||
return nil, fmt.Errorf("invalid configuration file, missing Kind")
|
||||
}
|
||||
if config.Kind != "EncryptionConfig" {
|
||||
return nil, fmt.Errorf("invalid configuration kind %q provided", config.Kind)
|
||||
}
|
||||
// TODO config.APIVersion is unchecked
|
||||
|
||||
resourceToPrefixTransformer := map[schema.GroupResource][]value.PrefixTransformer{}
|
||||
|
||||
// For each entry in the configuration
|
||||
for _, resourceConfig := range config.Resources {
|
||||
transformers, err := GetPrefixTransformers(&resourceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// For each resource, create a list of providers to use
|
||||
for _, resource := range resourceConfig.Resources {
|
||||
gr := schema.ParseGroupResource(resource)
|
||||
resourceToPrefixTransformer[gr] = append(
|
||||
resourceToPrefixTransformer[gr], transformers...)
|
||||
}
|
||||
}
|
||||
|
||||
result := map[schema.GroupResource]value.Transformer{}
|
||||
for gr, transList := range resourceToPrefixTransformer {
|
||||
result[gr] = value.NewMutableTransformer(value.NewPrefixTransformers(fmt.Errorf("no matching prefix found"), transList...))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPrefixTransformers constructs and returns the appropriate prefix transformers for the passed resource using its configuration
|
||||
func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, error) {
|
||||
var result []value.PrefixTransformer
|
||||
for _, provider := range config.Providers {
|
||||
found := false
|
||||
|
||||
var transformer value.PrefixTransformer
|
||||
var err error
|
||||
|
||||
if provider.AESGCM != nil {
|
||||
transformer, err = GetAESPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.AESCBC != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
transformer, err = GetAESPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1)
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.Secretbox != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
transformer, err = GetSecretboxPrefixTransformer(provider.Secretbox)
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.Identity != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
transformer = value.PrefixTransformer{
|
||||
Transformer: identity.NewEncryptCheckTransformer(),
|
||||
Prefix: []byte{},
|
||||
}
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.KMS != nil {
|
||||
if found == true {
|
||||
return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
f, err := os.Open(provider.KMS.ConfigFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening KMS provider configuration file %q: %v", provider.KMS.ConfigFile, err)
|
||||
}
|
||||
defer f.Close()
|
||||
envelopeService, pluginFound, err := KMSPluginRegistry.getPlugin(provider.KMS.Name, f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMS plugin %q, %v", provider.KMS.Name, err)
|
||||
}
|
||||
if pluginFound == false {
|
||||
return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name)
|
||||
}
|
||||
transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1)
|
||||
found = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = append(result, transformer)
|
||||
|
||||
if found == false {
|
||||
return result, fmt.Errorf("invalid provider configuration: at least one provider must be specified")
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BlockTransformerFunc takes an AES cipher block and returns a value transformer.
|
||||
type BlockTransformerFunc func(cipher.Block) value.Transformer
|
||||
|
||||
// GetAESPrefixTransformer returns a prefix transformer from the provided configuration.
|
||||
// Returns an AES transformer based on the provided prefix and block transformer.
|
||||
func GetAESPrefixTransformer(config *AESConfig, fn BlockTransformerFunc, prefix string) (value.PrefixTransformer, error) {
|
||||
var result value.PrefixTransformer
|
||||
|
||||
if len(config.Keys) == 0 {
|
||||
return result, fmt.Errorf("aes provider has no valid keys")
|
||||
}
|
||||
for _, key := range config.Keys {
|
||||
if key.Name == "" {
|
||||
return result, fmt.Errorf("key with invalid name provided")
|
||||
}
|
||||
if key.Secret == "" {
|
||||
return result, fmt.Errorf("key %v has no provided secret", key.Name)
|
||||
}
|
||||
}
|
||||
|
||||
keyTransformers := []value.PrefixTransformer{}
|
||||
|
||||
for _, keyData := range config.Keys {
|
||||
key, err := base64.StdEncoding.DecodeString(keyData.Secret)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("could not obtain secret for named key %s: %s", keyData.Name, err)
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("error while creating cipher for named key %s: %s", keyData.Name, err)
|
||||
}
|
||||
|
||||
// Create a new PrefixTransformer for this key
|
||||
keyTransformers = append(keyTransformers,
|
||||
value.PrefixTransformer{
|
||||
Transformer: fn(block),
|
||||
Prefix: []byte(keyData.Name + ":"),
|
||||
})
|
||||
}
|
||||
|
||||
// Create a prefixTransformer which can choose between these keys
|
||||
keyTransformer := value.NewPrefixTransformers(
|
||||
fmt.Errorf("no matching key was found for the provided AES transformer"), keyTransformers...)
|
||||
|
||||
// Create a PrefixTransformer which shall later be put in a list with other providers
|
||||
result = value.PrefixTransformer{
|
||||
Transformer: keyTransformer,
|
||||
Prefix: []byte(prefix),
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetSecretboxPrefixTransformer returns a prefix transformer from the provided configuration
|
||||
func GetSecretboxPrefixTransformer(config *SecretboxConfig) (value.PrefixTransformer, error) {
|
||||
var result value.PrefixTransformer
|
||||
|
||||
if len(config.Keys) == 0 {
|
||||
return result, fmt.Errorf("secretbox provider has no valid keys")
|
||||
}
|
||||
for _, key := range config.Keys {
|
||||
if key.Name == "" {
|
||||
return result, fmt.Errorf("key with invalid name provided")
|
||||
}
|
||||
if key.Secret == "" {
|
||||
return result, fmt.Errorf("key %v has no provided secret", key.Name)
|
||||
}
|
||||
}
|
||||
|
||||
keyTransformers := []value.PrefixTransformer{}
|
||||
|
||||
for _, keyData := range config.Keys {
|
||||
key, err := base64.StdEncoding.DecodeString(keyData.Secret)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("could not obtain secret for named key %s: %s", keyData.Name, err)
|
||||
}
|
||||
|
||||
if len(key) != 32 {
|
||||
return result, fmt.Errorf("expected key size 32 for secretbox provider, got %v", len(key))
|
||||
}
|
||||
|
||||
keyArray := [32]byte{}
|
||||
copy(keyArray[:], key)
|
||||
|
||||
// Create a new PrefixTransformer for this key
|
||||
keyTransformers = append(keyTransformers,
|
||||
value.PrefixTransformer{
|
||||
Transformer: secretbox.NewSecretboxTransformer(keyArray),
|
||||
Prefix: []byte(keyData.Name + ":"),
|
||||
})
|
||||
}
|
||||
|
||||
// Create a prefixTransformer which can choose between these keys
|
||||
keyTransformer := value.NewPrefixTransformers(
|
||||
fmt.Errorf("no matching key was found for the provided Secretbox transformer"), keyTransformers...)
|
||||
|
||||
// Create a PrefixTransformer which shall later be put in a list with other providers
|
||||
result = value.PrefixTransformer{
|
||||
Transformer: keyTransformer,
|
||||
Prefix: []byte(secretboxTransformerPrefixV1),
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// getEnvelopePrefixTransformer returns a prefix transformer from the provided config.
|
||||
// envelopeService is used as the root of trust.
|
||||
func getEnvelopePrefixTransformer(config *KMSConfig, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) {
|
||||
envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, config.CacheSize, aestransformer.NewCBCTransformer)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, err
|
||||
}
|
||||
return value.PrefixTransformer{
|
||||
Transformer: envelopeTransformer,
|
||||
Prefix: []byte(prefix + config.Name + ":"),
|
||||
}, nil
|
||||
}
|
||||
339
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go
generated
vendored
339
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go
generated
vendored
|
|
@ -1,339 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 encryptionconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
|
||||
)
|
||||
|
||||
const (
|
||||
sampleText = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
sampleContextText = "0123456789"
|
||||
|
||||
// Modify these in all configurations if changed
|
||||
testEnvelopeServiceConfigPath = "testproviderconfig"
|
||||
testEnvelopeServiceProviderName = "testprovider"
|
||||
|
||||
correctConfigWithIdentityFirst = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
- namespaces
|
||||
providers:
|
||||
- identity: {}
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- kms:
|
||||
name: testprovider
|
||||
configfile: testproviderconfig
|
||||
cachesize: 10
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- secretbox:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
|
||||
`
|
||||
|
||||
correctConfigWithAesGcmFirst = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- secretbox:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
|
||||
- kms:
|
||||
name: testprovider
|
||||
configfile: testproviderconfig
|
||||
cachesize: 10
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- identity: {}
|
||||
`
|
||||
|
||||
correctConfigWithAesCbcFirst = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- kms:
|
||||
name: testprovider
|
||||
configfile: testproviderconfig
|
||||
cachesize: 10
|
||||
- identity: {}
|
||||
- secretbox:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
`
|
||||
|
||||
correctConfigWithSecretboxFirst = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- secretbox:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- kms:
|
||||
name: testprovider
|
||||
configfile: testproviderconfig
|
||||
cachesize: 10
|
||||
- identity: {}
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
`
|
||||
|
||||
correctConfigWithKMSFirst = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- kms:
|
||||
name: testprovider
|
||||
configfile: testproviderconfig
|
||||
cachesize: 10
|
||||
- secretbox:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
- identity: {}
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: dGhpcyBpcyBwYXNzd29yZA==
|
||||
`
|
||||
|
||||
incorrectConfigNoSecretForKey = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
providers:
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
`
|
||||
|
||||
incorrectConfigInvalidKey = `
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
providers:
|
||||
- aesgcm:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZQ==
|
||||
- name: key2
|
||||
secret: YSBzZWNyZXQgYSBzZWNyZXQ=
|
||||
`
|
||||
)
|
||||
|
||||
// testEnvelopeService is a mock envelope service which can be used to simulate remote Envelope services
|
||||
// for testing of the envelope transformer with other transformers.
|
||||
type testEnvelopeService struct {
|
||||
disabled bool
|
||||
}
|
||||
|
||||
func (t *testEnvelopeService) Decrypt(data string) ([]byte, error) {
|
||||
if t.disabled {
|
||||
return nil, fmt.Errorf("Envelope service was disabled")
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(data)
|
||||
}
|
||||
|
||||
func (t *testEnvelopeService) Encrypt(data []byte) (string, error) {
|
||||
if t.disabled {
|
||||
return "", fmt.Errorf("Envelope service was disabled")
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func (t *testEnvelopeService) SetDisabledStatus(status bool) {
|
||||
t.disabled = status
|
||||
}
|
||||
|
||||
var _ envelope.Service = &testEnvelopeService{}
|
||||
|
||||
func TestEncryptionProviderConfigCorrect(t *testing.T) {
|
||||
os.OpenFile(testEnvelopeServiceConfigPath, os.O_CREATE, 0666)
|
||||
defer os.Remove(testEnvelopeServiceConfigPath)
|
||||
KMSPluginRegistry.Register(testEnvelopeServiceProviderName, func(_ io.Reader) (envelope.Service, error) {
|
||||
return &testEnvelopeService{}, nil
|
||||
})
|
||||
|
||||
// Creates compound/prefix transformers with different ordering of available transformers.
|
||||
// Transforms data using one of them, and tries to untransform using the others.
|
||||
// Repeats this for all possible combinations.
|
||||
identityFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithIdentityFirst))
|
||||
if err != nil {
|
||||
t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithIdentityFirst)
|
||||
}
|
||||
|
||||
aesGcmFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithAesGcmFirst))
|
||||
if err != nil {
|
||||
t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithAesGcmFirst)
|
||||
}
|
||||
|
||||
aesCbcFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithAesCbcFirst))
|
||||
if err != nil {
|
||||
t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithAesCbcFirst)
|
||||
}
|
||||
|
||||
secretboxFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithSecretboxFirst))
|
||||
if err != nil {
|
||||
t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithSecretboxFirst)
|
||||
}
|
||||
|
||||
kmsFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithKMSFirst))
|
||||
if err != nil {
|
||||
t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithKMSFirst)
|
||||
}
|
||||
|
||||
// Pick the transformer for any of the returned resources.
|
||||
identityFirstTransformer := identityFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
|
||||
aesGcmFirstTransformer := aesGcmFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
|
||||
aesCbcFirstTransformer := aesCbcFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
|
||||
secretboxFirstTransformer := secretboxFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
|
||||
kmsFirstTransformer := kmsFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
|
||||
|
||||
context := value.DefaultContext([]byte(sampleContextText))
|
||||
originalText := []byte(sampleText)
|
||||
|
||||
transformers := []struct {
|
||||
Transformer value.Transformer
|
||||
Name string
|
||||
}{
|
||||
{aesGcmFirstTransformer, "aesGcmFirst"},
|
||||
{aesCbcFirstTransformer, "aesCbcFirst"},
|
||||
{secretboxFirstTransformer, "secretboxFirst"},
|
||||
{identityFirstTransformer, "identityFirst"},
|
||||
{kmsFirstTransformer, "kmsFirst"},
|
||||
}
|
||||
|
||||
for _, testCase := range transformers {
|
||||
transformedData, err := testCase.Transformer.TransformToStorage(originalText, context)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error while transforming data to storage: %s", testCase.Name, err)
|
||||
}
|
||||
|
||||
for _, transformer := range transformers {
|
||||
untransformedData, stale, err := transformer.Transformer.TransformFromStorage(transformedData, context)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error while reading using %s transformer: %s", testCase.Name, transformer.Name, err)
|
||||
}
|
||||
if stale != (transformer.Name != testCase.Name) {
|
||||
t.Fatalf("%s: wrong stale information on reading using %s transformer, should be %v", testCase.Name, transformer.Name, testCase.Name == transformer.Name)
|
||||
}
|
||||
if bytes.Compare(untransformedData, originalText) != 0 {
|
||||
t.Fatalf("%s: %s transformer transformed data incorrectly. Expected: %v, got %v", testCase.Name, transformer.Name, originalText, untransformedData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Throw error if key has no secret
|
||||
func TestEncryptionProviderConfigNoSecretForKey(t *testing.T) {
|
||||
if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigNoSecretForKey)); err == nil {
|
||||
t.Fatalf("invalid configuration file (one key has no secret) got parsed:\n%s", incorrectConfigNoSecretForKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Throw error if invalid key for AES
|
||||
func TestEncryptionProviderConfigInvalidKey(t *testing.T) {
|
||||
if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigInvalidKey)); err == nil {
|
||||
t.Fatalf("invalid configuration file (bad AES key) got parsed:\n%s", incorrectConfigInvalidKey)
|
||||
}
|
||||
}
|
||||
118
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go
generated
vendored
118
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go
generated
vendored
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 encryptionconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
|
||||
)
|
||||
|
||||
// Factory is a function that returns an envelope Service for encryption providers.
|
||||
// The config parameter provides an io.Reader handler to the factory in
|
||||
// order to load specific configurations. If no configuration is provided
|
||||
// the parameter is nil.
|
||||
type Factory func(config io.Reader) (envelope.Service, error)
|
||||
|
||||
// KMSPlugins contains all registered KMS options.
|
||||
type KMSPlugins struct {
|
||||
lock sync.RWMutex
|
||||
registry map[string]Factory
|
||||
}
|
||||
|
||||
var (
|
||||
// PluginEnabledFn checks whether a plugin is enabled. By default, if you ask about it, it's enabled.
|
||||
PluginEnabledFn = func(name string, config io.Reader) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// KMSPluginRegistry contains the registered KMS plugins which can be used for configuring
|
||||
// encryption providers.
|
||||
KMSPluginRegistry = KMSPlugins{}
|
||||
)
|
||||
|
||||
// PluginEnabledFunc is a function type that can provide an external check on whether an admission plugin may be enabled
|
||||
type PluginEnabledFunc func(name string, config io.Reader) bool
|
||||
|
||||
// Register registers a plugin Factory by name. This
|
||||
// is expected to happen during app startup. It does not allow
|
||||
// registering a plugin by the same name twice.
|
||||
func (ps *KMSPlugins) Register(name string, plugin Factory) {
|
||||
ps.lock.Lock()
|
||||
defer ps.lock.Unlock()
|
||||
_, found := ps.registry[name]
|
||||
if ps.registry == nil {
|
||||
ps.registry = map[string]Factory{}
|
||||
}
|
||||
if found {
|
||||
glog.Fatalf("KMS plugin %q was registered twice", name)
|
||||
} else {
|
||||
ps.registry[name] = plugin
|
||||
glog.V(1).Infof("Registered KMS plugin %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
// getPlugin creates an instance of the named plugin. It returns `false` if the
|
||||
// the name is not known. The error is returned only when the named provider was
|
||||
// known but failed to initialize. The config parameter specifies the io.Reader
|
||||
// handler of the configuration file for the cloud provider, or nil for no configuration.
|
||||
func (ps *KMSPlugins) getPlugin(name string, config io.Reader) (envelope.Service, bool, error) {
|
||||
f, found := ps.fetchPluginFromRegistry(name)
|
||||
if !found {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
config1, config2, err := splitStream(config)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
if !PluginEnabledFn(name, config1) {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
ret, err := f(config2)
|
||||
return ret, true, err
|
||||
}
|
||||
|
||||
// fetchPluginFromRegistry tries to get a registered plugin with the requested name.
|
||||
func (ps *KMSPlugins) fetchPluginFromRegistry(name string) (Factory, bool) {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
// Map lookup defaults to single value context
|
||||
f, found := ps.registry[name]
|
||||
return f, found
|
||||
}
|
||||
|
||||
// splitStream reads the stream bytes and constructs two copies of it.
|
||||
func splitStream(config io.Reader) (io.Reader, io.Reader, error) {
|
||||
if config == nil || reflect.ValueOf(config).IsNil() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
configBytes, err := ioutil.ReadAll(config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(configBytes), bytes.NewBuffer(configBytes), nil
|
||||
}
|
||||
86
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go
generated
vendored
86
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go
generated
vendored
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 encryptionconfig
|
||||
|
||||
// EncryptionConfig stores the complete configuration for encryption providers.
|
||||
type EncryptionConfig struct {
|
||||
// kind is the type of configuration file.
|
||||
Kind string `json:"kind"`
|
||||
// apiVersion is the API version this file has to be parsed as.
|
||||
APIVersion string `json:"apiVersion"`
|
||||
// resources is a list containing resources, and their corresponding encryption providers.
|
||||
Resources []ResourceConfig `json:"resources"`
|
||||
}
|
||||
|
||||
// ResourceConfig stores per resource configuration.
|
||||
type ResourceConfig struct {
|
||||
// resources is a list of kubernetes resources which have to be encrypted.
|
||||
Resources []string `json:"resources"`
|
||||
// providers is a list of transformers to be used for reading and writing the resources to disk.
|
||||
// eg: aesgcm, aescbc, secretbox, identity.
|
||||
Providers []ProviderConfig `json:"providers"`
|
||||
}
|
||||
|
||||
// ProviderConfig stores the provided configuration for an encryption provider.
|
||||
type ProviderConfig struct {
|
||||
// aesgcm is the configuration for the AES-GCM transformer.
|
||||
AESGCM *AESConfig `json:"aesgcm,omitempty"`
|
||||
// aescbc is the configuration for the AES-CBC transformer.
|
||||
AESCBC *AESConfig `json:"aescbc,omitempty"`
|
||||
// secretbox is the configuration for the Secretbox based transformer.
|
||||
Secretbox *SecretboxConfig `json:"secretbox,omitempty"`
|
||||
// identity is the (empty) configuration for the identity transformer.
|
||||
Identity *IdentityConfig `json:"identity,omitempty"`
|
||||
// kms contains the name, cache size and path to configuration file for a KMS based envelope transformer.
|
||||
KMS *KMSConfig `json:"kms,omitempty"`
|
||||
}
|
||||
|
||||
// AESConfig contains the API configuration for an AES transformer.
|
||||
type AESConfig struct {
|
||||
// keys is a list of keys to be used for creating the AES transformer.
|
||||
// Each key has to be 32 bytes long for AES-CBC and 16, 24 or 32 bytes for AES-GCM.
|
||||
Keys []Key `json:"keys"`
|
||||
}
|
||||
|
||||
// SecretboxConfig contains the API configuration for an Secretbox transformer.
|
||||
type SecretboxConfig struct {
|
||||
// keys is a list of keys to be used for creating the Secretbox transformer.
|
||||
// Each key has to be 32 bytes long.
|
||||
Keys []Key `json:"keys"`
|
||||
}
|
||||
|
||||
// Key contains name and secret of the provided key for a transformer.
|
||||
type Key struct {
|
||||
// name is the name of the key to be used while storing data to disk.
|
||||
Name string `json:"name"`
|
||||
// secret is the actual key, encoded in base64.
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
// IdentityConfig is an empty struct to allow identity transformer in provider configuration.
|
||||
type IdentityConfig struct{}
|
||||
|
||||
// KMSConfig contains the name, cache size and path to configuration file for a KMS based envelope transformer.
|
||||
type KMSConfig struct {
|
||||
// name is the name of the KMS plugin to be used.
|
||||
Name string `json:"name"`
|
||||
// cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000.
|
||||
// +optional
|
||||
CacheSize int `json:"cachesize,omitempty"`
|
||||
// configfile is the path to the configuration file for the named KMS provider.
|
||||
ConfigFile string `json:"configfile"`
|
||||
}
|
||||
275
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
275
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
|
|
@ -1,275 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
"k8s.io/apiserver/pkg/storage/etcd3/preflight"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
)
|
||||
|
||||
type EtcdOptions struct {
|
||||
// The value of Paging on StorageConfig will be overriden by the
|
||||
// calculated feature gate value.
|
||||
StorageConfig storagebackend.Config
|
||||
EncryptionProviderConfigFilepath string
|
||||
|
||||
EtcdServersOverrides []string
|
||||
|
||||
// To enable protobuf as storage format, it is enough
|
||||
// to set it to "application/vnd.kubernetes.protobuf".
|
||||
DefaultStorageMediaType string
|
||||
DeleteCollectionWorkers int
|
||||
EnableGarbageCollection bool
|
||||
|
||||
// Set EnableWatchCache to false to disable all watch caches
|
||||
EnableWatchCache bool
|
||||
// Set DefaultWatchCacheSize to zero to disable watch caches for those resources that have no explicit cache size set
|
||||
DefaultWatchCacheSize int
|
||||
// WatchCacheSizes represents override to a given resource
|
||||
WatchCacheSizes []string
|
||||
}
|
||||
|
||||
var storageTypes = sets.NewString(
|
||||
storagebackend.StorageTypeUnset,
|
||||
storagebackend.StorageTypeETCD2,
|
||||
storagebackend.StorageTypeETCD3,
|
||||
)
|
||||
|
||||
func NewEtcdOptions(backendConfig *storagebackend.Config) *EtcdOptions {
|
||||
return &EtcdOptions{
|
||||
StorageConfig: *backendConfig,
|
||||
DefaultStorageMediaType: "application/json",
|
||||
DeleteCollectionWorkers: 1,
|
||||
EnableGarbageCollection: true,
|
||||
EnableWatchCache: true,
|
||||
DefaultWatchCacheSize: 100,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) Validate() []error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
allErrors := []error{}
|
||||
if len(s.StorageConfig.ServerList) == 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
|
||||
}
|
||||
|
||||
if !storageTypes.Has(s.StorageConfig.Type) {
|
||||
allErrors = append(allErrors, fmt.Errorf("--storage-backend invalid, must be 'etcd3' or 'etcd2'. If not specified, it will default to 'etcd3'"))
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
||||
func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringSliceVar(&s.EtcdServersOverrides, "etcd-servers-overrides", s.EtcdServersOverrides, ""+
|
||||
"Per-resource etcd servers overrides, comma separated. The individual override "+
|
||||
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
|
||||
|
||||
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
|
||||
"The media type to use to store objects in storage. "+
|
||||
"Some resources or storage backends may only support a specific media type and will ignore this setting.")
|
||||
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
|
||||
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
|
||||
|
||||
fs.BoolVar(&s.EnableGarbageCollection, "enable-garbage-collector", s.EnableGarbageCollection, ""+
|
||||
"Enables the generic garbage collector. MUST be synced with the corresponding flag "+
|
||||
"of the kube-controller-manager.")
|
||||
|
||||
fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
|
||||
"Enable watch caching in the apiserver")
|
||||
|
||||
fs.IntVar(&s.DefaultWatchCacheSize, "default-watch-cache-size", s.DefaultWatchCacheSize,
|
||||
"Default watch cache size. If zero, watch cache will be disabled for resources that do not have a default watch size set.")
|
||||
|
||||
fs.StringSliceVar(&s.WatchCacheSizes, "watch-cache-sizes", s.WatchCacheSizes, ""+
|
||||
"List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. "+
|
||||
"The individual override format: resource#size, where size is a number. It takes effect "+
|
||||
"when watch-cache is enabled.")
|
||||
|
||||
fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
|
||||
"The storage backend for persistence. Options: 'etcd3' (default), 'etcd2'.")
|
||||
|
||||
fs.IntVar(&s.StorageConfig.DeserializationCacheSize, "deserialization-cache-size", s.StorageConfig.DeserializationCacheSize,
|
||||
"Number of deserialized json objects to cache in memory.")
|
||||
|
||||
fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList,
|
||||
"List of etcd servers to connect with (scheme://ip:port), comma separated.")
|
||||
|
||||
fs.StringVar(&s.StorageConfig.Prefix, "etcd-prefix", s.StorageConfig.Prefix,
|
||||
"The prefix to prepend to all resource paths in etcd.")
|
||||
|
||||
fs.StringVar(&s.StorageConfig.KeyFile, "etcd-keyfile", s.StorageConfig.KeyFile,
|
||||
"SSL key file used to secure etcd communication.")
|
||||
|
||||
fs.StringVar(&s.StorageConfig.CertFile, "etcd-certfile", s.StorageConfig.CertFile,
|
||||
"SSL certification file used to secure etcd communication.")
|
||||
|
||||
fs.StringVar(&s.StorageConfig.CAFile, "etcd-cafile", s.StorageConfig.CAFile,
|
||||
"SSL Certificate Authority file used to secure etcd communication.")
|
||||
|
||||
fs.BoolVar(&s.StorageConfig.Quorum, "etcd-quorum-read", s.StorageConfig.Quorum,
|
||||
"If true, enable quorum read.")
|
||||
|
||||
fs.StringVar(&s.EncryptionProviderConfigFilepath, "experimental-encryption-provider-config", s.EncryptionProviderConfigFilepath,
|
||||
"The file containing configuration for encryption providers to be used for storing secrets in etcd")
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) ApplyTo(c *server.Config) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.addEtcdHealthEndpoint(c)
|
||||
c.RESTOptionsGetter = &SimpleRestOptionsFactory{Options: *s}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) ApplyWithStorageFactoryTo(factory serverstorage.StorageFactory, c *server.Config) error {
|
||||
s.addEtcdHealthEndpoint(c)
|
||||
c.RESTOptionsGetter = &storageFactoryRestOptionsFactory{Options: *s, StorageFactory: factory}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) addEtcdHealthEndpoint(c *server.Config) {
|
||||
c.HealthzChecks = append(c.HealthzChecks, healthz.NamedCheck("etcd", func(r *http.Request) error {
|
||||
done, err := preflight.EtcdConnection{ServerList: s.StorageConfig.ServerList}.CheckEtcdServers()
|
||||
if !done {
|
||||
return fmt.Errorf("etcd failed")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
type SimpleRestOptionsFactory struct {
|
||||
Options EtcdOptions
|
||||
}
|
||||
|
||||
func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
|
||||
ret := generic.RESTOptions{
|
||||
StorageConfig: &f.Options.StorageConfig,
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
EnableGarbageCollection: f.Options.EnableGarbageCollection,
|
||||
DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
|
||||
ResourcePrefix: resource.Group + "/" + resource.Resource,
|
||||
}
|
||||
if f.Options.EnableWatchCache {
|
||||
sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
|
||||
if err != nil {
|
||||
return generic.RESTOptions{}, err
|
||||
}
|
||||
cacheSize, ok := sizes[resource]
|
||||
if !ok {
|
||||
cacheSize = f.Options.DefaultWatchCacheSize
|
||||
}
|
||||
ret.Decorator = genericregistry.StorageWithCacher(cacheSize)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type storageFactoryRestOptionsFactory struct {
|
||||
Options EtcdOptions
|
||||
StorageFactory serverstorage.StorageFactory
|
||||
}
|
||||
|
||||
func (f *storageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
|
||||
storageConfig, err := f.StorageFactory.NewConfig(resource)
|
||||
if err != nil {
|
||||
return generic.RESTOptions{}, fmt.Errorf("unable to find storage destination for %v, due to %v", resource, err.Error())
|
||||
}
|
||||
|
||||
ret := generic.RESTOptions{
|
||||
StorageConfig: storageConfig,
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
|
||||
EnableGarbageCollection: f.Options.EnableGarbageCollection,
|
||||
ResourcePrefix: f.StorageFactory.ResourcePrefix(resource),
|
||||
}
|
||||
if f.Options.EnableWatchCache {
|
||||
sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
|
||||
if err != nil {
|
||||
return generic.RESTOptions{}, err
|
||||
}
|
||||
cacheSize, ok := sizes[resource]
|
||||
if !ok {
|
||||
cacheSize = f.Options.DefaultWatchCacheSize
|
||||
}
|
||||
ret.Decorator = genericregistry.StorageWithCacher(cacheSize)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ParseWatchCacheSizes turns a list of cache size values into a map of group resources
|
||||
// to requested sizes.
|
||||
func ParseWatchCacheSizes(cacheSizes []string) (map[schema.GroupResource]int, error) {
|
||||
watchCacheSizes := make(map[schema.GroupResource]int)
|
||||
for _, c := range cacheSizes {
|
||||
tokens := strings.Split(c, "#")
|
||||
if len(tokens) != 2 {
|
||||
return nil, fmt.Errorf("invalid value of watch cache size: %s", c)
|
||||
}
|
||||
|
||||
size, err := strconv.Atoi(tokens[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid size of watch cache size: %s", c)
|
||||
}
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("watch cache size cannot be negative: %s", c)
|
||||
}
|
||||
|
||||
watchCacheSizes[schema.ParseGroupResource(tokens[0])] = size
|
||||
}
|
||||
return watchCacheSizes, nil
|
||||
}
|
||||
|
||||
// WriteWatchCacheSizes turns a map of cache size values into a list of string specifications.
|
||||
func WriteWatchCacheSizes(watchCacheSizes map[schema.GroupResource]int) ([]string, error) {
|
||||
var cacheSizes []string
|
||||
|
||||
for resource, size := range watchCacheSizes {
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("watch cache size cannot be negative for resource %s", resource)
|
||||
}
|
||||
cacheSizes = append(cacheSizes, fmt.Sprintf("%s#%d", resource.String(), size))
|
||||
}
|
||||
return cacheSizes, nil
|
||||
}
|
||||
74
vendor/k8s.io/apiserver/pkg/server/options/feature.go
generated
vendored
74
vendor/k8s.io/apiserver/pkg/server/options/feature.go
generated
vendored
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 options
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
)
|
||||
|
||||
type FeatureOptions struct {
|
||||
EnableProfiling bool
|
||||
EnableContentionProfiling bool
|
||||
EnableSwaggerUI bool
|
||||
}
|
||||
|
||||
func NewFeatureOptions() *FeatureOptions {
|
||||
defaults := server.NewConfig(serializer.CodecFactory{})
|
||||
|
||||
return &FeatureOptions{
|
||||
EnableProfiling: defaults.EnableProfiling,
|
||||
EnableContentionProfiling: defaults.EnableContentionProfiling,
|
||||
EnableSwaggerUI: defaults.EnableSwaggerUI,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling,
|
||||
"Enable profiling via web interface host:port/debug/pprof/")
|
||||
fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling,
|
||||
"Enable lock contention profiling, if profiling is enabled")
|
||||
fs.BoolVar(&o.EnableSwaggerUI, "enable-swagger-ui", o.EnableSwaggerUI,
|
||||
"Enables swagger ui on the apiserver at /swagger-ui")
|
||||
}
|
||||
|
||||
func (o *FeatureOptions) ApplyTo(c *server.Config) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.EnableProfiling = o.EnableProfiling
|
||||
c.EnableContentionProfiling = o.EnableContentionProfiling
|
||||
c.EnableSwaggerUI = o.EnableSwaggerUI
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *FeatureOptions) Validate() []error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
return errs
|
||||
}
|
||||
98
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
98
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
|
|
@ -1,98 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
)
|
||||
|
||||
// RecommendedOptions contains the recommended options for running an API server.
|
||||
// If you add something to this list, it should be in a logical grouping.
|
||||
// Each of them can be nil to leave the feature unconfigured on ApplyTo.
|
||||
type RecommendedOptions struct {
|
||||
Etcd *EtcdOptions
|
||||
SecureServing *SecureServingOptions
|
||||
Authentication *DelegatingAuthenticationOptions
|
||||
Authorization *DelegatingAuthorizationOptions
|
||||
Audit *AuditOptions
|
||||
Features *FeatureOptions
|
||||
CoreAPI *CoreAPIOptions
|
||||
}
|
||||
|
||||
func NewRecommendedOptions(prefix string, copier runtime.ObjectCopier, codec runtime.Codec) *RecommendedOptions {
|
||||
return &RecommendedOptions{
|
||||
Etcd: NewEtcdOptions(storagebackend.NewDefaultConfig(prefix, copier, codec)),
|
||||
SecureServing: NewSecureServingOptions(),
|
||||
Authentication: NewDelegatingAuthenticationOptions(),
|
||||
Authorization: NewDelegatingAuthorizationOptions(),
|
||||
Audit: NewAuditOptions(),
|
||||
Features: NewFeatureOptions(),
|
||||
CoreAPI: NewCoreAPIOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
o.Etcd.AddFlags(fs)
|
||||
o.SecureServing.AddFlags(fs)
|
||||
o.Authentication.AddFlags(fs)
|
||||
o.Authorization.AddFlags(fs)
|
||||
o.Audit.AddFlags(fs)
|
||||
o.Features.AddFlags(fs)
|
||||
o.CoreAPI.AddFlags(fs)
|
||||
}
|
||||
|
||||
func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
|
||||
if err := o.Etcd.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.SecureServing.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Authentication.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Authorization.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Audit.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Features.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.CoreAPI.ApplyTo(config); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *RecommendedOptions) Validate() []error {
|
||||
errors := []error{}
|
||||
errors = append(errors, o.Etcd.Validate()...)
|
||||
errors = append(errors, o.SecureServing.Validate()...)
|
||||
errors = append(errors, o.Authentication.Validate()...)
|
||||
errors = append(errors, o.Authorization.Validate()...)
|
||||
errors = append(errors, o.Audit.Validate()...)
|
||||
errors = append(errors, o.Features.Validate()...)
|
||||
errors = append(errors, o.CoreAPI.Validate()...)
|
||||
|
||||
return errors
|
||||
}
|
||||
154
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
154
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
|
|
@ -1,154 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
// add the generic feature gates
|
||||
_ "k8s.io/apiserver/pkg/features"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// ServerRunOptions contains the options while running a generic api server.
|
||||
type ServerRunOptions struct {
|
||||
AdvertiseAddress net.IP
|
||||
|
||||
CorsAllowedOriginList []string
|
||||
ExternalHost string
|
||||
MaxRequestsInFlight int
|
||||
MaxMutatingRequestsInFlight int
|
||||
RequestTimeout time.Duration
|
||||
MinRequestTimeout int
|
||||
TargetRAMMB int
|
||||
}
|
||||
|
||||
func NewServerRunOptions() *ServerRunOptions {
|
||||
defaults := server.NewConfig(serializer.CodecFactory{})
|
||||
return &ServerRunOptions{
|
||||
MaxRequestsInFlight: defaults.MaxRequestsInFlight,
|
||||
MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight,
|
||||
RequestTimeout: defaults.RequestTimeout,
|
||||
MinRequestTimeout: defaults.MinRequestTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyOptions applies the run options to the method receiver and returns self
|
||||
func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
|
||||
c.CorsAllowedOriginList = s.CorsAllowedOriginList
|
||||
c.ExternalAddress = s.ExternalHost
|
||||
c.MaxRequestsInFlight = s.MaxRequestsInFlight
|
||||
c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight
|
||||
c.RequestTimeout = s.RequestTimeout
|
||||
c.MinRequestTimeout = s.MinRequestTimeout
|
||||
c.PublicAddress = s.AdvertiseAddress
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultAdvertiseAddress sets the field AdvertiseAddress if unset. The field will be set based on the SecureServingOptions.
|
||||
func (s *ServerRunOptions) DefaultAdvertiseAddress(secure *SecureServingOptions) error {
|
||||
if secure == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
|
||||
hostIP, err := secure.DefaultExternalAddress()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
|
||||
"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
|
||||
}
|
||||
s.AdvertiseAddress = hostIP
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks validation of ServerRunOptions
|
||||
func (s *ServerRunOptions) Validate() []error {
|
||||
errors := []error{}
|
||||
if s.TargetRAMMB < 0 {
|
||||
errors = append(errors, fmt.Errorf("--target-ram-mb can not be negative value"))
|
||||
}
|
||||
if s.MaxRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
|
||||
}
|
||||
if s.MaxMutatingRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
|
||||
}
|
||||
|
||||
if s.RequestTimeout.Nanoseconds() < 0 {
|
||||
errors = append(errors, fmt.Errorf("--request-timeout can not be negative value"))
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
||||
func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||
// arrange these text blocks sensibly. Grrr.
|
||||
|
||||
fs.IPVar(&s.AdvertiseAddress, "advertise-address", s.AdvertiseAddress, ""+
|
||||
"The IP address on which to advertise the apiserver to members of the cluster. This "+
|
||||
"address must be reachable by the rest of the cluster. If blank, the --bind-address "+
|
||||
"will be used. If --bind-address is unspecified, the host's default interface will "+
|
||||
"be used.")
|
||||
|
||||
fs.StringSliceVar(&s.CorsAllowedOriginList, "cors-allowed-origins", s.CorsAllowedOriginList, ""+
|
||||
"List of allowed origins for CORS, comma separated. An allowed origin can be a regular "+
|
||||
"expression to support subdomain matching. If this list is empty CORS will not be enabled.")
|
||||
|
||||
fs.IntVar(&s.TargetRAMMB, "target-ram-mb", s.TargetRAMMB,
|
||||
"Memory limit for apiserver in MB (used to configure sizes of caches, etc.)")
|
||||
|
||||
fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
|
||||
"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).")
|
||||
|
||||
deprecatedMasterServiceNamespace := metav1.NamespaceDefault
|
||||
fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
|
||||
"DEPRECATED: the namespace from which the kubernetes master services should be injected into pods.")
|
||||
|
||||
fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
|
||||
"The maximum number of non-mutating requests in flight at a given time. When the server exceeds this, "+
|
||||
"it rejects requests. Zero for no limit.")
|
||||
|
||||
fs.IntVar(&s.MaxMutatingRequestsInFlight, "max-mutating-requests-inflight", s.MaxMutatingRequestsInFlight, ""+
|
||||
"The maximum number of mutating requests in flight at a given time. When the server exceeds this, "+
|
||||
"it rejects requests. Zero for no limit.")
|
||||
|
||||
fs.DurationVar(&s.RequestTimeout, "request-timeout", s.RequestTimeout, ""+
|
||||
"An optional field indicating the duration a handler must keep a request open before timing "+
|
||||
"it out. This is the default request timeout for requests but may be overridden by flags such as "+
|
||||
"--min-request-timeout for specific types of requests.")
|
||||
|
||||
fs.IntVar(&s.MinRequestTimeout, "min-request-timeout", s.MinRequestTimeout, ""+
|
||||
"An optional field indicating the minimum number of seconds a handler must keep "+
|
||||
"a request open before timing it out. Currently only honored by the watch request "+
|
||||
"handler, which picks a randomized value above this number as the connection timeout, "+
|
||||
"to spread out load.")
|
||||
|
||||
utilfeature.DefaultFeatureGate.AddFlag(fs)
|
||||
}
|
||||
288
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
288
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
|
|
@ -1,288 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
type SecureServingOptions struct {
|
||||
BindAddress net.IP
|
||||
BindPort int
|
||||
|
||||
// ServerCert is the TLS cert info for serving secure traffic
|
||||
ServerCert GeneratableKeyCert
|
||||
// SNICertKeys are named CertKeys for serving secure traffic with SNI support.
|
||||
SNICertKeys []utilflag.NamedCertKey
|
||||
}
|
||||
|
||||
type CertKey struct {
|
||||
// CertFile is a file containing a PEM-encoded certificate, and possibly the complete certificate chain
|
||||
CertFile string
|
||||
// KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
|
||||
KeyFile string
|
||||
}
|
||||
|
||||
type GeneratableKeyCert struct {
|
||||
CertKey CertKey
|
||||
|
||||
// CACertFile is an optional file containing the certificate chain for CertKey.CertFile
|
||||
CACertFile string
|
||||
// CertDirectory is a directory that will contain the certificates. If the cert and key aren't specifically set
|
||||
// this will be used to derive a match with the "pair-name"
|
||||
CertDirectory string
|
||||
// PairName is the name which will be used with CertDirectory to make a cert and key names
|
||||
// It becomes CertDirector/PairName.crt and CertDirector/PairName.key
|
||||
PairName string
|
||||
}
|
||||
|
||||
func NewSecureServingOptions() *SecureServingOptions {
|
||||
return &SecureServingOptions{
|
||||
BindAddress: net.ParseIP("0.0.0.0"),
|
||||
BindPort: 443,
|
||||
ServerCert: GeneratableKeyCert{
|
||||
PairName: "apiserver",
|
||||
CertDirectory: "apiserver.local.config/certificates",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) DefaultExternalAddress() (net.IP, error) {
|
||||
return utilnet.ChooseBindAddress(s.BindAddress)
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) Validate() []error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errors := []error{}
|
||||
|
||||
if s.BindPort < 0 || s.BindPort > 65535 {
|
||||
errors = append(errors, fmt.Errorf("--secure-port %v must be between 0 and 65535, inclusive. 0 for turning off secure port.", s.BindPort))
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+
|
||||
"The IP address on which to listen for the --secure-port port. The "+
|
||||
"associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+
|
||||
"clients. If blank, all interfaces will be used (0.0.0.0).")
|
||||
|
||||
fs.IntVar(&s.BindPort, "secure-port", s.BindPort, ""+
|
||||
"The port on which to serve HTTPS with authentication and authorization. If 0, "+
|
||||
"don't serve HTTPS at all.")
|
||||
|
||||
fs.StringVar(&s.ServerCert.CertDirectory, "cert-dir", s.ServerCert.CertDirectory, ""+
|
||||
"The directory where the TLS certs are located. "+
|
||||
"If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.")
|
||||
|
||||
fs.StringVar(&s.ServerCert.CertKey.CertFile, "tls-cert-file", s.ServerCert.CertKey.CertFile, ""+
|
||||
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
|
||||
"after server cert). If HTTPS serving is enabled, and --tls-cert-file and "+
|
||||
"--tls-private-key-file are not provided, a self-signed certificate and key "+
|
||||
"are generated for the public address and saved to /var/run/kubernetes.")
|
||||
|
||||
fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile,
|
||||
"File containing the default x509 private key matching --tls-cert-file.")
|
||||
|
||||
fs.StringVar(&s.ServerCert.CACertFile, "tls-ca-file", s.ServerCert.CACertFile, "If set, this "+
|
||||
"certificate authority will used for secure access from Admission "+
|
||||
"Controllers. This must be a valid PEM-encoded CA bundle. Altneratively, the certificate authority "+
|
||||
"can be appended to the certificate provided by --tls-cert-file.")
|
||||
|
||||
fs.Var(utilflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
||||
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
||||
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
||||
"segments. If no domain patterns are provided, the names of the certificate are "+
|
||||
"extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+
|
||||
"trump over extracted names. For multiple key/certificate pairs, use the "+
|
||||
"--tls-sni-cert-key multiple times. "+
|
||||
"Examples: \"example.crt,example.key\" or \"foo.crt,foo.key:*.foo.com,foo.com\".")
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||
fs.IPVar(&s.BindAddress, "public-address-override", s.BindAddress,
|
||||
"DEPRECATED: see --bind-address instead.")
|
||||
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
||||
}
|
||||
|
||||
// ApplyTo fills up serving information in the server configuration.
|
||||
func (s *SecureServingOptions) ApplyTo(c *server.Config) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.BindPort <= 0 {
|
||||
return nil
|
||||
}
|
||||
if err := s.applyServingInfoTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create self-signed cert+key with the fake server.LoopbackClientServerNameOverride and
|
||||
// let the server return it when the loopback client connects.
|
||||
certPem, keyPem, err := certutil.GenerateSelfSignedCertKey(server.LoopbackClientServerNameOverride, nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err)
|
||||
}
|
||||
tlsCert, err := tls.X509KeyPair(certPem, keyPem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err)
|
||||
}
|
||||
|
||||
secureLoopbackClientConfig, err := c.SecureServingInfo.NewLoopbackClientConfig(uuid.NewRandom().String(), certPem)
|
||||
switch {
|
||||
// if we failed and there's no fallback loopback client config, we need to fail
|
||||
case err != nil && c.LoopbackClientConfig == nil:
|
||||
return err
|
||||
|
||||
// if we failed, but we already have a fallback loopback client config (usually insecure), allow it
|
||||
case err != nil && c.LoopbackClientConfig != nil:
|
||||
|
||||
default:
|
||||
c.LoopbackClientConfig = secureLoopbackClientConfig
|
||||
c.SecureServingInfo.SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) applyServingInfoTo(c *server.Config) error {
|
||||
if s.BindPort <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
secureServingInfo := &server.SecureServingInfo{
|
||||
BindAddress: net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.BindPort)),
|
||||
}
|
||||
|
||||
serverCertFile, serverKeyFile := s.ServerCert.CertKey.CertFile, s.ServerCert.CertKey.KeyFile
|
||||
|
||||
// load main cert
|
||||
if len(serverCertFile) != 0 || len(serverKeyFile) != 0 {
|
||||
tlsCert, err := tls.LoadX509KeyPair(serverCertFile, serverKeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load server certificate: %v", err)
|
||||
}
|
||||
secureServingInfo.Cert = &tlsCert
|
||||
}
|
||||
|
||||
// optionally load CA cert
|
||||
if len(s.ServerCert.CACertFile) != 0 {
|
||||
pemData, err := ioutil.ReadFile(s.ServerCert.CACertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read certificate authority from %q: %v", s.ServerCert.CACertFile, err)
|
||||
}
|
||||
block, pemData := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
return fmt.Errorf("no certificate found in certificate authority file %q", s.ServerCert.CACertFile)
|
||||
}
|
||||
if block.Type != "CERTIFICATE" {
|
||||
return fmt.Errorf("expected CERTIFICATE block in certiticate authority file %q, found: %s", s.ServerCert.CACertFile, block.Type)
|
||||
}
|
||||
secureServingInfo.CACert = &tls.Certificate{
|
||||
Certificate: [][]byte{block.Bytes},
|
||||
}
|
||||
}
|
||||
|
||||
// load SNI certs
|
||||
namedTLSCerts := make([]server.NamedTLSCert, 0, len(s.SNICertKeys))
|
||||
for _, nck := range s.SNICertKeys {
|
||||
tlsCert, err := tls.LoadX509KeyPair(nck.CertFile, nck.KeyFile)
|
||||
namedTLSCerts = append(namedTLSCerts, server.NamedTLSCert{
|
||||
TLSCert: tlsCert,
|
||||
Names: nck.Names,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load SNI cert and key: %v", err)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
secureServingInfo.SNICerts, err = server.GetNamedCertificateMap(namedTLSCerts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.SecureServingInfo = secureServingInfo
|
||||
c.ReadWritePort = s.BindPort
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress string, alternateDNS []string, alternateIPs []net.IP) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
keyCert := &s.ServerCert.CertKey
|
||||
if s.BindPort == 0 || len(keyCert.CertFile) != 0 || len(keyCert.KeyFile) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keyCert.CertFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".crt")
|
||||
keyCert.KeyFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".key")
|
||||
|
||||
canReadCertAndKey, err := certutil.CanReadCertAndKey(keyCert.CertFile, keyCert.KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !canReadCertAndKey {
|
||||
// add either the bind address or localhost to the valid alternates
|
||||
bindIP := s.BindAddress.String()
|
||||
if bindIP == "0.0.0.0" {
|
||||
alternateDNS = append(alternateDNS, "localhost")
|
||||
} else {
|
||||
alternateIPs = append(alternateIPs, s.BindAddress)
|
||||
}
|
||||
|
||||
if cert, key, err := certutil.GenerateSelfSignedCertKey(publicAddress, alternateIPs, alternateDNS); err != nil {
|
||||
return fmt.Errorf("unable to generate self signed cert: %v", err)
|
||||
} else {
|
||||
if err := certutil.WriteCert(keyCert.CertFile, cert); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := certutil.WriteKey(keyCert.KeyFile, key); err != nil {
|
||||
return err
|
||||
}
|
||||
glog.Infof("Generated self-signed cert (%s, %s)", keyCert.CertFile, keyCert.KeyFile)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
725
vendor/k8s.io/apiserver/pkg/server/options/serving_test.go
generated
vendored
725
vendor/k8s.io/apiserver/pkg/server/options/serving_test.go
generated
vendored
|
|
@ -1,725 +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.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
. "k8s.io/apiserver/pkg/server"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
func setUp(t *testing.T) Config {
|
||||
scheme := runtime.NewScheme()
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
|
||||
config := NewConfig(codecs)
|
||||
config.RequestContextMapper = genericapirequest.NewRequestContextMapper()
|
||||
|
||||
return *config
|
||||
}
|
||||
|
||||
type TestCertSpec struct {
|
||||
host string
|
||||
names, ips []string // in certificate
|
||||
}
|
||||
|
||||
type NamedTestCertSpec struct {
|
||||
TestCertSpec
|
||||
explicitNames []string // as --tls-sni-cert-key explicit names
|
||||
}
|
||||
|
||||
func TestGetNamedCertificateMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
certs []NamedTestCertSpec
|
||||
explicitNames []string
|
||||
expected map[string]int // name to certs[*] index
|
||||
errorString string
|
||||
}{
|
||||
{
|
||||
// empty certs
|
||||
expected: map[string]int{},
|
||||
},
|
||||
{
|
||||
// only one cert
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"test.com": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
// ips are ignored
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
ips: []string{"1.2.3.4"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"test.com": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
// two certs with the same name
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"test.com": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
// two certs with different names
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test2.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test1.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"test1.com": 1,
|
||||
"test2.com": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
// two certs with the same name, explicit trumps
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
explicitNames: []string{"test.com"},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"test.com": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
// certs with partial overlap; ips are ignored
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "a",
|
||||
names: []string{"a.test.com", "test.com"},
|
||||
},
|
||||
},
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "b",
|
||||
names: []string{"b.test.com", "test.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]int{
|
||||
"a": 0, "b": 1,
|
||||
"a.test.com": 0, "b.test.com": 1,
|
||||
"test.com": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
// wildcards
|
||||
certs: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "a",
|
||||
names: []string{"a.test.com", "test.com"},
|
||||
},
|
||||
explicitNames: []string{"*.test.com", "test.com"},
|
||||
},
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "b",
|
||||
names: []string{"b.test.com", "test.com"},
|
||||
},
|
||||
explicitNames: []string{"dev.test.com", "test.com"},
|
||||
}},
|
||||
expected: map[string]int{
|
||||
"test.com": 0,
|
||||
"*.test.com": 0,
|
||||
"dev.test.com": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
NextTest:
|
||||
for i, test := range tests {
|
||||
var namedTLSCerts []NamedTLSCert
|
||||
bySignature := map[string]int{} // index in test.certs by cert signature
|
||||
for j, c := range test.certs {
|
||||
cert, err := createTestTLSCerts(c.TestCertSpec)
|
||||
if err != nil {
|
||||
t.Errorf("%d - failed to create cert %d: %v", i, j, err)
|
||||
continue NextTest
|
||||
}
|
||||
|
||||
namedTLSCerts = append(namedTLSCerts, NamedTLSCert{
|
||||
TLSCert: cert,
|
||||
Names: c.explicitNames,
|
||||
})
|
||||
|
||||
sig, err := certSignature(cert)
|
||||
if err != nil {
|
||||
t.Errorf("%d - failed to get signature for %d: %v", i, j, err)
|
||||
continue NextTest
|
||||
}
|
||||
bySignature[sig] = j
|
||||
}
|
||||
|
||||
certMap, err := GetNamedCertificateMap(namedTLSCerts)
|
||||
if err == nil && len(test.errorString) != 0 {
|
||||
t.Errorf("%d - expected no error, got: %v", i, err)
|
||||
} else if err != nil && err.Error() != test.errorString {
|
||||
t.Errorf("%d - expected error %q, got: %v", i, test.errorString, err)
|
||||
} else {
|
||||
got := map[string]int{}
|
||||
for name, cert := range certMap {
|
||||
x509Certs, err := x509.ParseCertificates(cert.Certificate[0])
|
||||
assert.NoError(t, err, "%d - invalid certificate for %q", i, name)
|
||||
assert.True(t, len(x509Certs) > 0, "%d - expected at least one x509 cert in tls cert for %q", i, name)
|
||||
got[name] = bySignature[x509CertSignature(x509Certs[0])]
|
||||
}
|
||||
|
||||
assert.EqualValues(t, test.expected, got, "%d - wrong certificate map", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRunWithSNI(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
Cert TestCertSpec
|
||||
SNICerts []NamedTestCertSpec
|
||||
ExpectedCertIndex int
|
||||
|
||||
// passed in the client hello info, "localhost" if unset
|
||||
ServerName string
|
||||
|
||||
// optional ip or hostname to pass to NewLoopbackClientConfig
|
||||
LoopbackClientBindAddressOverride string
|
||||
ExpectLoopbackClientError bool
|
||||
}{
|
||||
"only one cert": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
ips: []string{"127.0.0.1"},
|
||||
},
|
||||
ExpectedCertIndex: -1,
|
||||
},
|
||||
"cert with multiple alternate names": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
names: []string{"test.com"},
|
||||
ips: []string{"127.0.0.1"},
|
||||
},
|
||||
ExpectedCertIndex: -1,
|
||||
ServerName: "test.com",
|
||||
},
|
||||
"one SNI and the default cert with the same name": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
ips: []string{"127.0.0.1"},
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: 0,
|
||||
},
|
||||
"matching SNI cert": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
ips: []string{"127.0.0.1"},
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: 0,
|
||||
ServerName: "test.com",
|
||||
},
|
||||
"matching IP in SNI cert and the server cert": {
|
||||
// IPs must not be passed via SNI. Hence, the ServerName in the
|
||||
// HELLO packet is empty and the server should select the non-SNI cert.
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
ips: []string{"10.0.0.1", "127.0.0.1"},
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
ips: []string{"10.0.0.1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: -1,
|
||||
ServerName: "10.0.0.1",
|
||||
},
|
||||
"wildcards": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
ips: []string{"127.0.0.1"},
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "test.com",
|
||||
names: []string{"*.test.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: 0,
|
||||
ServerName: "www.test.com",
|
||||
},
|
||||
|
||||
"loopback: LoopbackClientServerNameOverride not on any cert": {
|
||||
Cert: TestCertSpec{
|
||||
host: "test.com",
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: 0,
|
||||
},
|
||||
"loopback: LoopbackClientServerNameOverride on server cert": {
|
||||
Cert: TestCertSpec{
|
||||
host: server.LoopbackClientServerNameOverride,
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: "localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: 0,
|
||||
},
|
||||
"loopback: LoopbackClientServerNameOverride on SNI cert": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
},
|
||||
SNICerts: []NamedTestCertSpec{
|
||||
{
|
||||
TestCertSpec: TestCertSpec{
|
||||
host: server.LoopbackClientServerNameOverride,
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCertIndex: -1,
|
||||
},
|
||||
"loopback: bind to 0.0.0.0 => loopback uses localhost": {
|
||||
Cert: TestCertSpec{
|
||||
host: "localhost",
|
||||
},
|
||||
ExpectedCertIndex: -1,
|
||||
LoopbackClientBindAddressOverride: "0.0.0.0",
|
||||
},
|
||||
}
|
||||
|
||||
specToName := func(spec TestCertSpec) string {
|
||||
name := spec.host + "_" + strings.Join(spec.names, ",") + "_" + strings.Join(spec.ips, ",")
|
||||
return strings.Replace(name, "*", "star", -1)
|
||||
}
|
||||
|
||||
NextTest:
|
||||
for title, test := range tests {
|
||||
// create server cert
|
||||
certDir := "testdata/" + specToName(test.Cert)
|
||||
serverCertBundleFile := filepath.Join(certDir, "cert")
|
||||
serverKeyFile := filepath.Join(certDir, "key")
|
||||
err := getOrCreateTestCertFiles(serverCertBundleFile, serverKeyFile, test.Cert)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to create server cert: %v", title, err)
|
||||
continue NextTest
|
||||
}
|
||||
ca, err := caCertFromBundle(serverCertBundleFile)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to extract ca cert from server cert bundle: %v", title, err)
|
||||
continue NextTest
|
||||
}
|
||||
caCerts := []*x509.Certificate{ca}
|
||||
|
||||
// create SNI certs
|
||||
var namedCertKeys []utilflag.NamedCertKey
|
||||
serverSig, err := certFileSignature(serverCertBundleFile, serverKeyFile)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to get server cert signature: %v", title, err)
|
||||
continue NextTest
|
||||
}
|
||||
signatures := map[string]int{
|
||||
serverSig: -1,
|
||||
}
|
||||
for j, c := range test.SNICerts {
|
||||
sniDir := filepath.Join(certDir, specToName(c.TestCertSpec))
|
||||
certBundleFile := filepath.Join(sniDir, "cert")
|
||||
keyFile := filepath.Join(sniDir, "key")
|
||||
err := getOrCreateTestCertFiles(certBundleFile, keyFile, c.TestCertSpec)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to create SNI cert %d: %v", title, j, err)
|
||||
continue NextTest
|
||||
}
|
||||
|
||||
namedCertKeys = append(namedCertKeys, utilflag.NamedCertKey{
|
||||
KeyFile: keyFile,
|
||||
CertFile: certBundleFile,
|
||||
Names: c.explicitNames,
|
||||
})
|
||||
|
||||
ca, err := caCertFromBundle(certBundleFile)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to extract ca cert from SNI cert %d: %v", title, j, err)
|
||||
continue NextTest
|
||||
}
|
||||
caCerts = append(caCerts, ca)
|
||||
|
||||
// store index in namedCertKeys with the signature as the key
|
||||
sig, err := certFileSignature(certBundleFile, keyFile)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed get SNI cert %d signature: %v", title, j, err)
|
||||
continue NextTest
|
||||
}
|
||||
signatures[sig] = j
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
func() {
|
||||
defer close(stopCh)
|
||||
|
||||
// launch server
|
||||
config := setUp(t)
|
||||
|
||||
v := fakeVersion()
|
||||
config.Version = &v
|
||||
|
||||
config.EnableIndex = true
|
||||
secureOptions := &SecureServingOptions{
|
||||
BindAddress: net.ParseIP("127.0.0.1"),
|
||||
BindPort: 6443,
|
||||
ServerCert: GeneratableKeyCert{
|
||||
CertKey: CertKey{
|
||||
CertFile: serverCertBundleFile,
|
||||
KeyFile: serverKeyFile,
|
||||
},
|
||||
},
|
||||
SNICertKeys: namedCertKeys,
|
||||
}
|
||||
config.LoopbackClientConfig = &restclient.Config{}
|
||||
if err := secureOptions.ApplyTo(&config); err != nil {
|
||||
t.Errorf("%q - failed applying the SecureServingOptions: %v", title, err)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := config.Complete(nil).New("test", server.EmptyDelegate)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed creating the server: %v", title, err)
|
||||
return
|
||||
}
|
||||
|
||||
// patch in a 0-port to enable auto port allocation
|
||||
s.SecureServingInfo.BindAddress = "127.0.0.1:0"
|
||||
|
||||
// add poststart hook to know when the server is up.
|
||||
startedCh := make(chan struct{})
|
||||
s.AddPostStartHook("test-notifier", func(context PostStartHookContext) error {
|
||||
close(startedCh)
|
||||
return nil
|
||||
})
|
||||
preparedServer := s.PrepareRun()
|
||||
go func() {
|
||||
if err := preparedServer.Run(stopCh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// load ca certificates into a pool
|
||||
roots := x509.NewCertPool()
|
||||
for _, caCert := range caCerts {
|
||||
roots.AddCert(caCert)
|
||||
}
|
||||
|
||||
<-startedCh
|
||||
|
||||
effectiveSecurePort := fmt.Sprintf("%d", preparedServer.EffectiveSecurePort())
|
||||
// try to dial
|
||||
addr := fmt.Sprintf("localhost:%s", effectiveSecurePort)
|
||||
t.Logf("Dialing %s as %q", addr, test.ServerName)
|
||||
conn, err := tls.Dial("tcp", addr, &tls.Config{
|
||||
RootCAs: roots,
|
||||
ServerName: test.ServerName, // used for SNI in the client HELLO packet
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to connect: %v", title, err)
|
||||
return
|
||||
}
|
||||
|
||||
// check returned server certificate
|
||||
sig := x509CertSignature(conn.ConnectionState().PeerCertificates[0])
|
||||
gotCertIndex, found := signatures[sig]
|
||||
if !found {
|
||||
t.Errorf("%q - unknown signature returned from server: %s", title, sig)
|
||||
}
|
||||
if gotCertIndex != test.ExpectedCertIndex {
|
||||
t.Errorf("%q - expected cert index %d, got cert index %d", title, test.ExpectedCertIndex, gotCertIndex)
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
|
||||
// check that the loopback client can connect
|
||||
host := "127.0.0.1"
|
||||
if len(test.LoopbackClientBindAddressOverride) != 0 {
|
||||
host = test.LoopbackClientBindAddressOverride
|
||||
}
|
||||
s.LoopbackClientConfig.Host = net.JoinHostPort(host, effectiveSecurePort)
|
||||
if test.ExpectLoopbackClientError {
|
||||
if err == nil {
|
||||
t.Errorf("%q - expected error creating loopback client config", title)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed creating loopback client config: %v", title, err)
|
||||
return
|
||||
}
|
||||
client, err := discovery.NewDiscoveryClientForConfig(s.LoopbackClientConfig)
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to create loopback client: %v", title, err)
|
||||
return
|
||||
}
|
||||
got, err := client.ServerVersion()
|
||||
if err != nil {
|
||||
t.Errorf("%q - failed to connect with loopback client: %v", title, err)
|
||||
return
|
||||
}
|
||||
if expected := &v; !reflect.DeepEqual(got, expected) {
|
||||
t.Errorf("%q - loopback client didn't get correct version info: expected=%v got=%v", title, expected, got)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func parseIPList(ips []string) []net.IP {
|
||||
var netIPs []net.IP
|
||||
for _, ip := range ips {
|
||||
netIPs = append(netIPs, net.ParseIP(ip))
|
||||
}
|
||||
return netIPs
|
||||
}
|
||||
|
||||
func createTestTLSCerts(spec TestCertSpec) (tlsCert tls.Certificate, err error) {
|
||||
certPem, keyPem, err := generateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names)
|
||||
if err != nil {
|
||||
return tlsCert, err
|
||||
}
|
||||
|
||||
tlsCert, err = tls.X509KeyPair(certPem, keyPem)
|
||||
return tlsCert, err
|
||||
}
|
||||
|
||||
func getOrCreateTestCertFiles(certFileName, keyFileName string, spec TestCertSpec) (err error) {
|
||||
if _, err := os.Stat(certFileName); err == nil {
|
||||
if _, err := os.Stat(keyFileName); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
certPem, keyPem, err := generateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
os.MkdirAll(filepath.Dir(certFileName), os.FileMode(0755))
|
||||
err = ioutil.WriteFile(certFileName, certPem, os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
os.MkdirAll(filepath.Dir(keyFileName), os.FileMode(0755))
|
||||
err = ioutil.WriteFile(keyFileName, keyPem, os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func caCertFromBundle(bundlePath string) (*x509.Certificate, error) {
|
||||
pemData, err := ioutil.ReadFile(bundlePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fetch last block
|
||||
var block *pem.Block
|
||||
for {
|
||||
var nextBlock *pem.Block
|
||||
nextBlock, pemData = pem.Decode(pemData)
|
||||
if nextBlock == nil {
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("no certificate found in %q", bundlePath)
|
||||
|
||||
}
|
||||
return x509.ParseCertificate(block.Bytes)
|
||||
}
|
||||
block = nextBlock
|
||||
}
|
||||
}
|
||||
|
||||
func x509CertSignature(cert *x509.Certificate) string {
|
||||
return base64.StdEncoding.EncodeToString(cert.Signature)
|
||||
}
|
||||
|
||||
func certFileSignature(certFile, keyFile string) (string, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return certSignature(cert)
|
||||
}
|
||||
|
||||
func certSignature(cert tls.Certificate) (string, error) {
|
||||
x509Certs, err := x509.ParseCertificates(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return x509CertSignature(x509Certs[0]), nil
|
||||
}
|
||||
|
||||
func fakeVersion() version.Info {
|
||||
return version.Info{
|
||||
Major: "42",
|
||||
Minor: "42",
|
||||
GitVersion: "42",
|
||||
GitCommit: "34973274ccef6ab4dfaaf86599792fa9c3fe4689",
|
||||
GitTreeState: "Dirty",
|
||||
}
|
||||
}
|
||||
|
||||
// generateSelfSignedCertKey creates a self-signed certificate and key for the given host.
|
||||
// Host may be an IP or a DNS name
|
||||
// You may also specify additional subject alt names (either ip or dns names) for the certificate
|
||||
func generateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) {
|
||||
priv, err := rsa.GenerateKey(cryptorand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
|
||||
},
|
||||
NotBefore: time.Unix(0, 0),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 365 * 100),
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, host)
|
||||
}
|
||||
|
||||
template.IPAddresses = append(template.IPAddresses, alternateIPs...)
|
||||
template.DNSNames = append(template.DNSNames, alternateDNS...)
|
||||
|
||||
derBytes, err := x509.CreateCertificate(cryptorand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Generate cert
|
||||
certBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Generate key
|
||||
keyBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return certBuffer.Bytes(), keyBuffer.Bytes(), nil
|
||||
}
|
||||
20
vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/cert
generated
vendored
20
vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/cert
generated
vendored
|
|
@ -1,20 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAvMS0wKwYDVQQDDCRhcGlz
|
||||
ZXJ2ZXItbG9vcGJhY2stY2xpZW50QDE0OTYzMzA2NTYwIBcNNzAwMTAxMDAwMDAw
|
||||
WhgPMjExNzA1MDgxNTI0MTZaMC8xLTArBgNVBAMMJGFwaXNlcnZlci1sb29wYmFj
|
||||
ay1jbGllbnRAMTQ5NjMzMDY1NjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAMScrdc+XlUPHsDvnN2fFxSSQrhrKBlrHBcelaiFwR1vWt2EXxErVUoRGA+1
|
||||
jvQ5Y4NePS46Zpq2N+yibiWjaC0fsS4W2UvPAfdD4nxOp5SaTBy5A0XI+JU8QmbI
|
||||
Rls+C/fSeYaXSKp5Jq41uTKGc+QwT9pqCeV7N74DSc6kvNh7mIBc4YCOzMnhQq5H
|
||||
KQVCeDPURxfh7Ew+v13dLYDq7V6O1jBjfg3Rm/RRFnM78kcc51QTOo9ZSs5HgahU
|
||||
eM4YirHz8ujswhgxzH43TeOGds3McGKv1HMHKJKinX02IHJBqV6U5y/AH92wi0Sp
|
||||
IKgJ4GJaj/Vda/kPUtf5cL2sOt0CAwEAAaNeMFwwDgYDVR0PAQH/BAQDAgKkMBMG
|
||||
A1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wJAYDVR0RBB0wG4IZ
|
||||
YXBpc2VydmVyLWxvb3BiYWNrLWNsaWVudDANBgkqhkiG9w0BAQsFAAOCAQEALlZe
|
||||
LJ3i6WQhpgV3jPWuIBTXJ0bb3cbYnk4JLWYW9sIjMakfAlZK9VrfRZKOhI8DsGsG
|
||||
PVcYOyc5TQM0JkcsCKajyA6HktpMFEtxBfSJOlRAdvvj1GtRnifcA5xBqn1SzL2H
|
||||
tFx5etii70spZD3jDht2bKLZmL2NbGGVOWiKdtz6qR+V9U4F+uYCq+phKgnLeDz3
|
||||
RiMIGvDpliWU/R1jgdi3RENtP8QGhjiwVDGYJBB26ZQGDkd4HYPZj9bROMknnRFk
|
||||
fbP/P+cmvXrwScvrXLFkNQe/4LfJAJnod4ropQ84z/Cu2JaFbJau4TSlbp57y9ON
|
||||
7fpK9SV4bTCyO34Uew==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEAxJyt1z5eVQ8ewO+c3Z8XFJJCuGsoGWscFx6VqIXBHW9a3YRf
|
||||
EStVShEYD7WO9Dljg149LjpmmrY37KJuJaNoLR+xLhbZS88B90PifE6nlJpMHLkD
|
||||
Rcj4lTxCZshGWz4L99J5hpdIqnkmrjW5MoZz5DBP2moJ5Xs3vgNJzqS82HuYgFzh
|
||||
gI7MyeFCrkcpBUJ4M9RHF+HsTD6/Xd0tgOrtXo7WMGN+DdGb9FEWczvyRxznVBM6
|
||||
j1lKzkeBqFR4zhiKsfPy6OzCGDHMfjdN44Z2zcxwYq/UcwcokqKdfTYgckGpXpTn
|
||||
L8Af3bCLRKkgqAngYlqP9V1r+Q9S1/lwvaw63QIDAQABAoIBAQCCiJ9mM3M/t80s
|
||||
PSmBflk9gCmp9QLndVRuCRFFlJ/1IfRK89KGPKXgid7WtyzU+rEWC+BEq+NpPid9
|
||||
BQ5qEMZehxcESYk1KpfciYZ6D2J1Z8e2niMNFvPraNmREdCcTWJ2w5eJgzFsdQj4
|
||||
SpTNdbTFwEmT8ijl4dvNXLOI7ZivhJ1vVGW2qUJQyR5xo+GuXZZVVJW6vndkzHoA
|
||||
SJDSii4PMAisibu+Uw8JQM1rYFD2olvSWSnjz+kCk2IbrqhVPOW9PoYETn2DxXfY
|
||||
0miUGq4KwtNjFnqJO+CDTJL6Y7LrZbKdSVTKfiY5ReLckWhx4RKn01T9RhsrS979
|
||||
bee+iynlAoGBAOVDKy9t3kN7FTQJyMGa3QAVUV8B5OPUIyuUOhzMrbIFECtYFXxY
|
||||
jsnRNf1i2PbVsl9WDrPikNCVyn5Tf4xU7YUH7/Jo+Ha978Fu9tNf95RK+A2GKtiO
|
||||
8jQa6nkII8Fmql9o3xjCEQD0VBirrm1h3sbC3ylKL4u+yC0a6W7vFRRfAoGBANuK
|
||||
tIvCRGoEyn8nzSXUez7+/9sIwU7jV6lXL7qgdukr7o/ZBqer48CDlehXU48yiVpB
|
||||
TuMZnloj/Ndf9X07t/yYwfCP7lpdq6lR7EhG5yS0WjgHjv5+QKLVA7ocrEufgBKA
|
||||
Wdb+96eyOb1bgBMprtYA8wbhblhut8rk+i8SkdpDAoGBAJPxY0XI/VvIamdZRP6C
|
||||
Y8iw+QB5JW5Lr6JolZOOFSxCjiuaPMswDnx3kAKCLgYi4mcZDoXQV6jycGhSk4VI
|
||||
LLni5FkmmeduK/BEHe1LCWXddvKrOKzkmbE8CUCvGvurt5e4AfdlDDn0cOw2pWma
|
||||
dXsHt6BaahIgu+Y3bpmSmKS7AoGBAJGlhX2qleSX5RdSemD8g/8ZAPh46HXDkSaA
|
||||
9uMjDYBHau73ldiqyl+vbEZFmOPJLSI5bXJwToOSmGzx9lTsx3TGivNjKUe+GOIt
|
||||
vUl98F6DX88IBK+FZrAgDWbtGsjYugiMKg3d/MK+FFwxVdhgsOK8on4QFDqKyVfL
|
||||
bMbJ1QUtAoGBAK4nM5GZyefXylAnq+pzGTStu0Q1AVzN0iWO0G0Q6gaItvk82Scf
|
||||
wVoEGE9a2pDCR1I1mbJn1jRxd6/GtXvR4TJSxPILS+B8aZFkxl9WIWjv/mnKJkVL
|
||||
PmSNPbieuban9TRBu6nQfWOfLMHmBnG/QXbx2X1WCRoXjICT41gJ5et3
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1NzAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
N1owHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTcwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDhpeY6j6ujZc2W0paC9pmVHlEhbnsH/L0N3JjA
|
||||
WooyZWgsARSlv95Vh2M1gVymu7mah3HHzQkVe6vN5bfngOO4A2d3fxYP0304+3YE
|
||||
TCariZzcEk9Ot90VHNasTVMOqZ2qdGRUvEXbpRWlIhA+T9FgNxpBDQV5yb5w67Dl
|
||||
kBM22wn5l/YM/4HqSOTVQON1SmmLUPlnWtzxVRDKPzI2zxpKkzW4U1bYgdwM/Xeo
|
||||
B2GjU+1UsBlJWGrRQhCkiFuZ92agls1bsu3+PE2leoQf6vZE+pc0m89v0lqlcgOQ
|
||||
TcI19BFvLjUneDbu4kFZWDO+f23hhEcHut26IXtOoAIvk9uhAgMBAAGjTjBMMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAHlVy
|
||||
2H1FxDXAJKeZkFCNAHOiThcm79s7P8+BXnYbQMgdHAiQIQFQDDwbntA607m0FRoZ
|
||||
1H1n/rzkRXRrNJRPEd3aSnurq6oMMZa1Pai4e2f+kyThpIw6FtI2y/Jb7lKB428g
|
||||
9AHtKSd71MEArOvWHi1IcX6rmH/vU5ezBgPpjtEC/5bI8PJMqr2osesjppKwwwjf
|
||||
BTq+AjvxltPDb+fykto41IMzpM7KRO/vat/dZ5OZZOhDpbJlAAWUfCdlWcL0kqTt
|
||||
ok+biBB4xShOwpSyKCmJg4otlvN7qJ34fCjYkQY+PXzGS6YV34Wj64F8mReTt4LO
|
||||
glampIa1cLUWPMlYPQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA4aXmOo+ro2XNltKWgvaZlR5RIW57B/y9DdyYwFqKMmVoLAEU
|
||||
pb/eVYdjNYFcpru5modxx80JFXurzeW354DjuANnd38WD9N9OPt2BEwmq4mc3BJP
|
||||
TrfdFRzWrE1TDqmdqnRkVLxF26UVpSIQPk/RYDcaQQ0Fecm+cOuw5ZATNtsJ+Zf2
|
||||
DP+B6kjk1UDjdUppi1D5Z1rc8VUQyj8yNs8aSpM1uFNW2IHcDP13qAdho1PtVLAZ
|
||||
SVhq0UIQpIhbmfdmoJbNW7Lt/jxNpXqEH+r2RPqXNJvPb9JapXIDkE3CNfQRby41
|
||||
J3g27uJBWVgzvn9t4YRHB7rduiF7TqACL5PboQIDAQABAoIBABg+G6MVBmqyqEjY
|
||||
7SS627tCm5LM7Njp1WHk3mBkGc7aSDvaDd7U400rE4SPFmYvavxoKtg9dglh1Q50
|
||||
7LIpjc2aSAZ1l+gxX5W8pmxFxi3NxhV6vhyF8nGvPH0cfZzoqjDC+niEFblIXi/0
|
||||
newj5SnCIcb1YC46d4RoPgQb24ScBiQi3DeuqiDPQO3cyePyr5TEpeL4djB8YgK3
|
||||
yAgKFotsox1sMz1r0AX4JdoC2cYBh6qmGs+qdkMYW3O5XKjkkWS7dglqHIchhsrr
|
||||
P38kuyp30fMrE40+5G9hKi3WO/nl3FP/eDM8BD60QF1edXobszfd8BsVnrBfbfjP
|
||||
wDP51rECgYEA5/hLWVPXvTkSJeWzkEYx2PvubClr4fZE8j4oYTikD3q86R6UkEhe
|
||||
c/yZd9WNBgwUrLG4SV3TaqEWvyUEnsaNbI1YK7e4PrhMSLLZ0G040jW8TA1SE2kT
|
||||
fnJ5g4ZRWTNvksBTcs3QtMC8FzFazQ7gKIYz+SXopxeww5D8T/ok/WUCgYEA+QXz
|
||||
/mYUnUMt4kWfcMDDbiYCgVSJK71E5M5qH2yxjB7NFLcl0+udQ5FrrW2YEgr3DnSV
|
||||
Okbg4ZcmdnjCOU7Xu5BlU0GWe5lXiOBf0sUxrNU3OY5voVPYgSXJgTPRzguTpetA
|
||||
2Liv/7x5dZ0krIKRTCKWu0iwcdOOaPrEouln740CgYBcrrckXLyBLTFUFP/2sCUw
|
||||
hhBQBQjGwsfvZehqV+AtEyQxnHdNYqzieNW0rI1pEiCck3GHVsam/vAAtUCwU7Kj
|
||||
4aGN7hzeanKIRXWDsnAWhUPTuyrE+KHCTujAJUWRd1yn7NIqt5Mg9TTxq1WVQtFL
|
||||
P7u6W2wmfu+wY9h79/0ZhQKBgQCQoRt/wmvwlmbcxxD+HIakv6Cu2pk8dRXBSf0q
|
||||
uSc5OV5kzKZEudBBwQDn3gH3YLTyiVVuXmIXw4DMSACN5jO3tPqUa0BqErpbPe2J
|
||||
bYwXVFJZtFczPI4/G+I3jxAoemLLd6HW/RUDE8T7QUReiQq4TFJ8/Y+03GkWoaZ4
|
||||
89SwtQKBgQCmWHxz0eXQk3YRk0kupSrK88pZoc9wvcWYhzkiQpP6+hYPxH+n+U6s
|
||||
NjHnQAVlRUIP0VisQRkBC4iy2ca/gVVhKgygVBuHC97fKAHlpUlO6Y7Ow031stAy
|
||||
K3zrTjuVwsz8C6bFCxHl5ojP+0cSoK7qej09vj/te1DNvkYuE/0j4Q==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAvMS0wKwYDVQQDDCRhcGlz
|
||||
ZXJ2ZXItbG9vcGJhY2stY2xpZW50QDE0OTYzMzA2NTgwIBcNNzAwMTAxMDAwMDAw
|
||||
WhgPMjExNzA1MDgxNTI0MThaMC8xLTArBgNVBAMMJGFwaXNlcnZlci1sb29wYmFj
|
||||
ay1jbGllbnRAMTQ5NjMzMDY1ODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAPGTpeR8wkr9yxMV8LLI7UaImRF6T0ZT2HL7cmjZDbV3Ow9L8UXvlQ0SdKbT
|
||||
ph2IU5Ww4h3xSiXXXGh0FSXALs1Ieg8DmMYKHNcnOXpShwuXBJ0NCpPSLnAO+2hg
|
||||
Jq+ULvBTGjQhvCX+cjI5IquYp0sSbERS/+46cGrwWoye67Z9Xo6enNjHG8YZf35B
|
||||
Wspvm0awUw1KcXkp+lJ9zoblBeXm+uXdMhzEyRpghRslwvtPKyU8YhTN63p0Ru1E
|
||||
Kig3pctotL2n1/7+tR8yhjEstLiydHYWhLkX6wsUv+rNirUGVUBjF5VFtERzMPRK
|
||||
0dh/hs3v2JSby56IxRcqqTSzvfECAwEAAaNeMFwwDgYDVR0PAQH/BAQDAgKkMBMG
|
||||
A1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wJAYDVR0RBB0wG4IZ
|
||||
YXBpc2VydmVyLWxvb3BiYWNrLWNsaWVudDANBgkqhkiG9w0BAQsFAAOCAQEAEEd0
|
||||
MOqC0POVtxGCy/BHR6sVcf1r1BVTt28p7u1yJIdrOKuknlILt9iSNfFcNPRWIP+u
|
||||
7SNPT8td6yViBgn7UMjvFxZgQn6kTsgTfdRV7eMxoX/jYzt0g44k0oVGv+xiJ+8q
|
||||
m5Ng+tMOMuY1+JganxNad3mwdff4uKxXuVQsV+mjXBwaJHIdxBmCFqg/dGB60lyb
|
||||
fxFjuTAT8xyL+UE3VUoCLFdNDgIsm0v3uj8nBsASW1LeZSbMQKUJXGlvEpj5U89d
|
||||
B9ZouygfISPKQ02WYYDfSmtGCqX5sFZRh2uSPp0/UPUB+hUk7C0KN6TgsB9kOAD1
|
||||
Sa0X3+KhMRVOk7riaQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA8ZOl5HzCSv3LExXwssjtRoiZEXpPRlPYcvtyaNkNtXc7D0vx
|
||||
Re+VDRJ0ptOmHYhTlbDiHfFKJddcaHQVJcAuzUh6DwOYxgoc1yc5elKHC5cEnQ0K
|
||||
k9IucA77aGAmr5Qu8FMaNCG8Jf5yMjkiq5inSxJsRFL/7jpwavBajJ7rtn1ejp6c
|
||||
2Mcbxhl/fkFaym+bRrBTDUpxeSn6Un3OhuUF5eb65d0yHMTJGmCFGyXC+08rJTxi
|
||||
FM3renRG7UQqKDely2i0vafX/v61HzKGMSy0uLJ0dhaEuRfrCxS/6s2KtQZVQGMX
|
||||
lUW0RHMw9ErR2H+Gze/YlJvLnojFFyqpNLO98QIDAQABAoIBAQCu+8LrSU83ILSr
|
||||
I3ZRGmd8cs9lMJIhn/Ql/Wq29ZoPesjl4J1oig0OBfNHMAGgXLImuJRhGfkahe+i
|
||||
nYr/6EA+ZCQ9od5UfNi9I+VnbEXzqDUoSV0DC/ilJMUIqrT68zw4ygkt/82YO8Ge
|
||||
DXLGlvF+2F5h8zj854msfGMqfqbAbJDynA0ZDuq8SORUb/1RIiAZRrABZ1n6HsXv
|
||||
cZb12wcycbxKTPfISkJDJ+PUVmCcm/eO3jLDgy2hAY5bCG6+HIO/N407Ze83TA81
|
||||
nBRM2WEA9BJbRmmB2yAEy2aJamT5lo5qORElmW0gEpAEceRgYi/VjPyvwjOw7IW3
|
||||
SlEDaYbNAoGBAPzt80mwWzgLH0SIqUadXbJILqZ1j/0sCr4r9CfIPppbZckaXbaC
|
||||
iokh3dRaVBndI8z/aPz5+wmvNjqxQ4Jz+411ILK7G0ogYRJcTaQB7Vc2QTPtdu3t
|
||||
HE1xCktyTAcyVJtrVYfpqaAKZ/eEnDmatxrMW1nmnFlZxBZErnSAjMl7AoGBAPSC
|
||||
anORXVXqbM6d7XKXiXYLkagmB92LP36DQ3OXiVIH3CD2weItRvqup9+nIdMJMDyN
|
||||
PR9CXSQXclFjVqpgPFKEAUNcGbTea45Kykw07CUYEdYRXRYtij0hhsRon+T6vsE7
|
||||
eEQQySG0ub6cTsFi/AuxWlPCkQLIhfCkVW4kvqyDAoGBAKBXEGXkgM9Ubav6nqT/
|
||||
WciNbdVkrbUnWGAaaRtXHCiqTCpiponu03f/mirmYG5M/EcWmy3UI0qOYmhuu4dV
|
||||
k2CnoeTsLG6ffCoxjZ6tAhLJeCg9H6nRKKIHSSlu+beONoiYUI5qmHe2YRZOYOM7
|
||||
q1w3tKmXQgJ6n44mWBnO7HFFAoGBAJF5Rnyb8Dw9zZ7gt3WGU3K4T2ELv4JAZvaO
|
||||
goMzlbAInR+/sHsxFRnw8FBQz/8PaHOeVM9UXLYsfQePYvDbcQhnIZlCIslJzBRM
|
||||
yy+sDRPEzlfe3NNlJOpaGCSjWv6RcQzmpRdaJVC4hgqyVOkaS3tpeaR8Dmrpg0c5
|
||||
ftqZYhihAoGAMRbt+21F1BD3AGDseGIg4MQIEPfk7nh/cVFBcnXAqV49dmm1/g7G
|
||||
L2itzJlTb1oOnlY9qBksocvnj3w8hsrWFvt/s0wv1e3uUJ1elCb18Rm4UQtr9td6
|
||||
XFqEgDaDYyj1iEmn+PrjQc+DqHn6JySLW4LTM82KWwDnMttvwLFhaOM=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1NjAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
NlowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTYwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDozgb3GKC3n9wREqYUm92/T0+NnEYkaWOitXAH
|
||||
BW/Gj9PAF4sggnAey62H7mkBaUpw3s3RXyrqnRqrXVWvWgbSpf0Elp3zfos4raEf
|
||||
hgWhqMh/SEf5ETHNRyfebxTSeQYRuZsvAPEsRWKf3AKFEykfW9y/GnKYM1elL0nx
|
||||
Fgh0tq943epjHuzKfVWp8LxnFd7fyL+BQsvBNnYz0SH0F9oTUU3nDCS6Os/+EtNQ
|
||||
SjP54HQ78XczI9AMvsFUS7yFEQdM8VW9uYhdv/Oyi9SLywhOCHSnV9buJ6F8URzO
|
||||
B5Cawdteew7U+EAXbEwY2D84NARF/J8iA3Eh7+UKd27WA+pJAgMBAAGjTjBMMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEA5vjR
|
||||
Q4Rjx8ko8+Zt9gRceKCVWEmdZLGkjwdW04YaIcrh41svm+tgxwUMdQ2beNjUbLZX
|
||||
DAVvK99HiANBc9Ee4DyQFkLI2z0EiAJpuxMjZlyzMmKLeijOkIkxYIshhfc2Y2Fr
|
||||
NIf6OXmFBEjqsudxkQiGfSqc443GseJmmiuhW3JR1a6ARgut4AtPsPv2TijX7tcR
|
||||
Z9tjzAMiubNDQq0g/Eh9vLZkv8tNTqoJ5N5XV8jcovNWRcIIzl+lXBfy0o68LwO4
|
||||
Hn/MzcMxOdbNfFw5nMaDuQK4oO0vT3D9nedQkdV3keLZtagN9/PO1XtkCSQ5q7Le
|
||||
LS6fs5zA/9sR2kEuGw==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA6M4G9xigt5/cERKmFJvdv09PjZxGJGljorVwBwVvxo/TwBeL
|
||||
IIJwHsuth+5pAWlKcN7N0V8q6p0aq11Vr1oG0qX9BJad836LOK2hH4YFoajIf0hH
|
||||
+RExzUcn3m8U0nkGEbmbLwDxLEVin9wChRMpH1vcvxpymDNXpS9J8RYIdLaveN3q
|
||||
Yx7syn1VqfC8ZxXe38i/gULLwTZ2M9Eh9BfaE1FN5wwkujrP/hLTUEoz+eB0O/F3
|
||||
MyPQDL7BVEu8hREHTPFVvbmIXb/zsovUi8sITgh0p1fW7iehfFEczgeQmsHbXnsO
|
||||
1PhAF2xMGNg/ODQERfyfIgNxIe/lCndu1gPqSQIDAQABAoIBAQDBke1Ar32SsJzu
|
||||
pS7qm975HxzqhjHcPLTXqT0I2YBi/Vv3sJvB4DMRqBEVoSo2PjHjP56qpBKvGQn/
|
||||
yo9gSd66b8G9eu7Cc0mXSudZqror/IcZLiSJ974NDUkdLgeGKZLeUhGyN3pQcTDb
|
||||
8rc1pwTeSid1zqvR2X7ankNA7i0BvP6UXlvWM8kUvfFDwPXhHPZtkFELc4TeGIzB
|
||||
e/l9Uk0DAgplkhM32s+0rTZ7wmcSUK9eh7/kiQCUKvdCVwegsK9iCVMaYIMggut1
|
||||
3KEHuVIbuLdjFu/tF4SN85funMIPxD7rKf38aDrR1vhQc5tq88dKwVrD8EANcA/f
|
||||
34mAWSIBAoGBAPZLAGJ2McxIoK7ymyvGdNta0glzzbww20xLB3MHYpo+cgff4DN0
|
||||
3nA/es49So1m/r0MKjnC0qxVMceTrU4u43nROwbLNlFBZ8hzoEVobCCoykWKkhQO
|
||||
hS6PkxBZ2s8nsSQCr3X+CpHd+JqT7Y98ydWVnE+kDOFIPr16j1SbBJS5AoGBAPH6
|
||||
73BDmHk4fBb9J2edNtx+7/1/+Lbb96qyy7LnA9zxdXgqjeZwFW/tNjtD2l+TPWlR
|
||||
O1L0NkfnhzWPd7rDlQA7Tzr0TLF/H34+ycbaorc22M6GEg9zJwRY42EGbYJE5uRZ
|
||||
Sq4jXOTOAta/lb+UjqWI7eYyH89SKlYcDut1VVoRAoGBANucUvJ427yBAi4dC3nE
|
||||
EszJNcHR7aAhnFlyCWlrK2PHzJvy5xJa4kEKiXE+u6xMK1bccwZgDsQ1jxabOowd
|
||||
SR6FD3HmXz+i52yYlU9uZgPVHc9WWRzjOaQjx4lr5ayTguNONbArXrdkStlikBBC
|
||||
wCHfrqpg6E80wSTpFMbnFvWZAoGAPNSDOqqTeu27LCBJtp9r+jQi6owwHu/fK9c0
|
||||
o+21J+a/TA0OjP5iNTfhqTZegCZIiuAz1J+1wY+visRdKeMe4ucF/OELIpe9eAQa
|
||||
v1WZEAvGpuxHQAEHru0Vg/+UqeneTUsxHeOf55juV8Pjxjx3O5/XhkXVf029fNYi
|
||||
3ggqA7ECgYEAgowePEGL7l27raa6F9h4wuosfuFFdrrcOJeGxNV9jAe2s2KKoQFO
|
||||
lCv/AcCsRepf9G235TqQ+if8a4p7OsHL9kxOspKBJKnwq3u+jgcJTl+HLWgnDjIc
|
||||
Yk2xlnRC4N4OiGQrxjOmFXQdXiBK3T4CJnw5g0MynrdwiJCCCnEIG+A=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDFTCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1OTAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
OVowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTkwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQD2NQ2T3x1nBhqWOCjiED71R+j80XsFxSMZXNJB
|
||||
wUCCGZysf6OGO6M+NYZ2qov58gfGrcZYBJWwuSRF+0NeoVzkCu3AJkTKXSdtv2vi
|
||||
M248yBUhvwPwbTcoMyG7p6LhLlmlPpP/7n9yVfVtRzFgy4UPYAlJmTnakk9jDKXM
|
||||
gi717BjntQ01+2I/HIZls5B5vLwWuHtWrdng39Evn1RwtJrLUVJE5b6/+otvokXB
|
||||
DpKMb/aI230uw9D3Csi+6iAKK9JuhCEe/S3ezJWg5SugG6UrwGBLZYavXP7iiB9p
|
||||
u32XIe8lMqQfsiur7iCQehwxTdMJ7uR5STS5eqfoV2SdnlN/AgMBAAGjWjBYMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcECgAAAYcEfwAAATANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAuVVTMV237szi8c9Oy5ulsmgYkp6MqfkKryy6Zi6r5UtJAWToAFu3
|
||||
dvHKnSQNgiWDewVKn+pMGNZuo3o6PGxdq/E2ZQ6/oCxNRThb7hC5IK4Yot40EUQ4
|
||||
ZavrmON0velXZJ3MwbzSzstLnJCR3maO+Ko0KPC/u4LADCQyeVrEZ4IP/RPQ2KZt
|
||||
mdmeHTm53tLPrcNSnaoW+tMs6JxAT30xOLnjwYfEtbMCVhGB+aHQIGFS620qZ+dn
|
||||
oTqrjempIIos0Vu68ZhCaDwgB9FiNtFMplxrBvOIfWO1Dz9AwPxP1fCMlZwtFJt8
|
||||
vuRu05WPJelfnEKXIuGhuGf369xyfw5cIA==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEA9jUNk98dZwYaljgo4hA+9Ufo/NF7BcUjGVzSQcFAghmcrH+j
|
||||
hjujPjWGdqqL+fIHxq3GWASVsLkkRftDXqFc5ArtwCZEyl0nbb9r4jNuPMgVIb8D
|
||||
8G03KDMhu6ei4S5ZpT6T/+5/clX1bUcxYMuFD2AJSZk52pJPYwylzIIu9ewY57UN
|
||||
NftiPxyGZbOQeby8Frh7Vq3Z4N/RL59UcLSay1FSROW+v/qLb6JFwQ6SjG/2iNt9
|
||||
LsPQ9wrIvuogCivSboQhHv0t3syVoOUroBulK8BgS2WGr1z+4ogfabt9lyHvJTKk
|
||||
H7Irq+4gkHocMU3TCe7keUk0uXqn6FdknZ5TfwIDAQABAoIBAQDKBSg58HZAxcpk
|
||||
/nnVXL08KCAt6nlGd8bgFcDUgYy78+YRyL3V8/NzpRnLHw+yLH1i8c3xBPoKwy/X
|
||||
WF+kM0V0PN9urjf90Ef9DneoaMkIiKiGQyUpT4RVsPb58oh8urqGE33/H6RlndC/
|
||||
NQ54PSbWQdf9EwRcq3cGcCdPUnbUA6Ur/m03kIWYMnPKZeXqTCA8AMfsLuoXyf3G
|
||||
H9Q/ReGWok2fOkw8I/2D2HOXh+vnPoOOWbxf75DAt7tk2tRrgvQ7cI6TOJo6AImD
|
||||
E1rHU7lrVhyo2AK+8BfjihGgtgt1qCwEeviuJn20wRQwTpi3r+aflaVCgsZADoc5
|
||||
6bEkjP/pAoGBAPZVyIIg4W44lHz7xu0DMAbdK2CwaYPPhEewVNTCmtq6wvP/CKz/
|
||||
gZRv7HLFrEAPuMuSPi0+0lzbUf4IfHeP79jzPEsoHlzaSyKVho91uttsTYGRS0yD
|
||||
M2Kd7uavXH/lRR16h6TlGRgNTAfWh8I+WimzBi1IHP8LQPv9hS5CUseLAoGBAP/d
|
||||
/FLXTQJ4bsb3Yune/xoerrMo05cUY8BM6WZ3s2wdPSMnTkh921CyzGzfWLpDHrww
|
||||
rFBrbs0O7YijRU5gjwddxVMT/qcwNEETEWw38X3kfPx8TCYKT5OsD3HoiTKMUVJG
|
||||
ehdADEm8mh918pgSvW/hvFaW98rIWjVwTt9djkJdAoGBAOkQJJMp9N/J3IOb24wn
|
||||
desomn/yqQIy9p61MK3UKZtFFGqyI006uSjt9DJq4BwEQ/0nMniwdWuxfhPxh4G/
|
||||
x1fmWmdpX8DOMERaYGOfKdms0HAEPc/4Wke10XCk/clr7EaFxYy3zVQ6UHMiAHRB
|
||||
diD55qA1GGoeBa/lH3qy+YsdAoGBAKP4j65LGaf+pAdQHIyCAvurNAvOmyKTx4VC
|
||||
BMVM6qfbaQWxN8LPHRBvNQCEdWkQgI7bpmH3J0+0RFcvQsgCq0ZuOnmOM8DS7HnT
|
||||
jXPLujASkGKCCY7LRsn9FvzJp7rEH41Zav6hZf6PJjoJLUl1oP8lK7xWDUBf+yeJ
|
||||
7JHKc9NlAoGBAMhca2WXdxX1R61zdjqa7Da9fC1a8cdkPHsN9CA6ZMxGgfrbZHsY
|
||||
YbqPhjuupOJe5B5MZ12oRqye3u6SuzoJMcSBOjKMLX/ME5fOxNRiAGgm1WEbDeFJ
|
||||
3+ZyymShyUbpRLOg4fUC1vptzSJ1i93rXOZI6Vs0rWMj+PKDEbmFLiT8
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDDDCCAfSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBN0ZXN0
|
||||
LmNvbUAxNDk2MzMwNjU5MCAXDTcwMDEwMTAwMDAwMFoYDzIxMTcwNTA4MTUyNDE5
|
||||
WjAeMRwwGgYDVQQDDBN0ZXN0LmNvbUAxNDk2MzMwNjU5MIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAwRrWvzL0zR9OFg1ipRU+Pvd9v+WN4ILKxU2jxlut
|
||||
vZOevsyxflzRNOQImejpdXEtA/yZTKNYOdU+dMdPDdSsMPFzRgzQfiJDKqJw4jB+
|
||||
SF2XROuZEYMjxoJtueAGnw1DO9tgzn40NtHrPJNKadrYljEF+zycNLcPf78GK/ug
|
||||
+5rK5MkpNVmxO4yjqxk5ZB3KD4Gol3RaheVKYmTfjNIAO0wk8O2NbvG/JxOPTpDS
|
||||
aElgpfdy3Bxv4JJpjgNKrHEUYUqkwlqmrinTw8MSfKJq0MJ8nIx8HRojrYrf6Jh8
|
||||
zDpPYuqlUygcwSz0sQEY6UceaupQmlvDT9QLLVBm6aOibQIDAQABo1MwUTAOBgNV
|
||||
HQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAZBgNVHREEEjAQggh0ZXN0LmNvbYcECgAAATANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||
jdyL+g1UlZ9UsnYA60iu3n9O8nzUU13z6d3TR3vFBiaTAiVYgcEoL5BmhZgn5jcW
|
||||
AlQqmVicma4rypK50GZL7/fJBwiaUjkGNBh4ybfO2TRyXbmTCtMg+1FUe/LptxD4
|
||||
IWvJvf/Y7Vv/Lb1Gh0MXUcNeyLThletz6tJI3NAQX3meZm2J6/PBoERP7KXo7C4F
|
||||
K21/V3aD8Zj7gs7LQLePz14ARAuovd/LDFmAHBcL3EIXiegDGe2c34IKupTPiysE
|
||||
KIWAgOWSBQ9iZw4Ak7eFSDPIO9Xj1X+D1Bcb2EMcYw/9xJt8JFAqFFjMHPcKxCkQ
|
||||
oY+IHfc38TMOEeAr8N+W2g==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwRrWvzL0zR9OFg1ipRU+Pvd9v+WN4ILKxU2jxlutvZOevsyx
|
||||
flzRNOQImejpdXEtA/yZTKNYOdU+dMdPDdSsMPFzRgzQfiJDKqJw4jB+SF2XROuZ
|
||||
EYMjxoJtueAGnw1DO9tgzn40NtHrPJNKadrYljEF+zycNLcPf78GK/ug+5rK5Mkp
|
||||
NVmxO4yjqxk5ZB3KD4Gol3RaheVKYmTfjNIAO0wk8O2NbvG/JxOPTpDSaElgpfdy
|
||||
3Bxv4JJpjgNKrHEUYUqkwlqmrinTw8MSfKJq0MJ8nIx8HRojrYrf6Jh8zDpPYuql
|
||||
UygcwSz0sQEY6UceaupQmlvDT9QLLVBm6aOibQIDAQABAoIBACeo73oNaSHH0C3P
|
||||
SfdFyab9BaKn7t+xfRvQulY+9gv9iZj+SWX+gikuvGV/5JLuT6SF+KY41iHqng01
|
||||
8hKRH1xd+qLkdt2xA8J54l1SQF10e2D4UlO6b1qR5x9J15JLEwf0IonGecrYikvC
|
||||
pIHhJKKUJvpWlG5vOouuHAJkh8ekwz17cEle6IOPY+p9hiivk80npUzbdybnHK26
|
||||
pNGPICich8sUWNaiSUia/TCwIDzU4NkNhsOxoV/QZOTOFnHl4lR81dSeptdVusPg
|
||||
JdC0+VCMc8wGgXdDqWxPzDdT7CIGNZcqpltBEe/27QPVYxckK3kDkOFRXshD5lPv
|
||||
56USHrECgYEA9pB5ChHu9JqkedN8QgUfipl/doAOz80vghG0gi+wvkeD/XrzXaES
|
||||
rXlkGJFKbPkTGhemSzBPQNEbpQa8Y+h+GfKLHux+Kd7pWRym4vXojxeJyaCCG73i
|
||||
d2qtoHi5QeZOY36AJT7bq3T1ZKHG157vEXRghth+ozpzb1w+KeO1ZNcCgYEAyH6j
|
||||
FpowWYdsPljqx+7SfoPdes/LGtfIWnGRM12C6H2Lb9FX6l1yIMNJQgYhyRPSbifL
|
||||
uArj/Jf9LskaaRYHvjXbtBANHHU92kBZszMj3x437otADwL9iWsV/cyIDkei5QTl
|
||||
fP//M5RSZj2WyRQJ8hXTA7Ya5e3rGJYlHQ1aRlsCgYBJMK2dXaFvHpCAUVTrTBYG
|
||||
0HXTuUOsT54woAzTMFDoytXVYq/nNS8UK5qY6FgNbQpMjoSggSClfu0T2aIGjjcQ
|
||||
gLznWxBAYZknCKhJavGzuCsAnRLCJWWaSSJtJijn9POD+UMUy0nt5XQKgTNDQjx5
|
||||
E/CrVoyQ64LkpZ8WVC++VQKBgQCLUMu8cem03FAPxrNluAKWHMTyiJ8mCNjUV+PA
|
||||
YHMNX+dbDIlddg9OysQF18L0OQzYtFhvi0m+hFJOhzkN2lwJBN2kch7aLnGLTXnG
|
||||
9nsvl4zf+ezKQZaxPTLrx4qm+YosP0nDoRLQ4XicSKGVGZKLoDSfeJOaP8dDr1kc
|
||||
peGbzwKBgQC3Tz57NVbIDa3SdMlpgV5iUj+AQ4Q4OLxAWzePttic1+nalQyFLMBI
|
||||
dq4HytJEen/CK/XwelHpMfMv/t2bZcqags+Epm9Qhd7jLMaFsmrscmdjXdp41kRR
|
||||
KOjZHBUuhK7HfeBLJ7oLGDlXHvtfwC59DRLipYrtJLG4Etkcjfav8Q==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDDzCCAfegAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1NDAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
NFowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTQwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQD8AqsPL2/NyBR9LSPSkLedA2pI5DeQ+z7Zfp9K
|
||||
8EmbCcawXZabrkPCr0LwNyylynssZXqGLYWvwpl8zGk0E2Gr++diIg17uZ4lZUKN
|
||||
jYhGdV8Y1Bx2Wl1At4LLe+bmxv01hslT4EDRzHfZU/wy/gTtYMJLuQOKqddW3lkV
|
||||
FXNgJOVGmIm1tehwDCJhL9NIyQcy6w4i86e5B8q+pk3V95mOlKR7lHhk1ZFsMCKh
|
||||
TCYG/qyu+ZUkKvZCoyV9SwuaN8Df3TT6MYSX2ulvmze2okfePwTeKMpwudrfn440
|
||||
0TWrWKJuMdNe9bHXsvhvPZlqBCouIqPC1KiuMg+Pcx0laz9BAgMBAAGjVDBSMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOC
|
||||
AQEAXHWVJ8fuPrF7Bgj3i7fyH0wE6mHeUMSy/bxXdbrkY/H1wGMxHZa8uAodXeNa
|
||||
Nb3pBzroqZcVWjkh56knGgeZE4vmkWWZZ3G0Bj5jr3kzhZ9Tpd1LyFOhIdUttHPs
|
||||
DOVfD7AIl3v4xlMDwlYYQKrt1LzHZX1n7sJHJK1s5pL/lB9PdUGka6XLXo7meKPL
|
||||
KluKBF729MfwBx/GNrQEh4Hw9/KVnBisKKdWqowrKzVzGj3hv2q+wCxDuUZyl7Cs
|
||||
nw07CGIn+t7+5/jRyEoIwUiOydvaOFkXgOpWxHQVEj+7Hw+rstDbMDQ2+p4LpJjC
|
||||
bLBrGtpaitmhTPyT+SSR7AZisg==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA/AKrDy9vzcgUfS0j0pC3nQNqSOQ3kPs+2X6fSvBJmwnGsF2W
|
||||
m65Dwq9C8Dcspcp7LGV6hi2Fr8KZfMxpNBNhq/vnYiINe7meJWVCjY2IRnVfGNQc
|
||||
dlpdQLeCy3vm5sb9NYbJU+BA0cx32VP8Mv4E7WDCS7kDiqnXVt5ZFRVzYCTlRpiJ
|
||||
tbXocAwiYS/TSMkHMusOIvOnuQfKvqZN1feZjpSke5R4ZNWRbDAioUwmBv6srvmV
|
||||
JCr2QqMlfUsLmjfA3900+jGEl9rpb5s3tqJH3j8E3ijKcLna35+ONNE1q1iibjHT
|
||||
XvWx17L4bz2ZagQqLiKjwtSorjIPj3MdJWs/QQIDAQABAoIBACnOZ4JFZE7G+l8p
|
||||
td+gklVB08fz1CQBChQapWJRKmTF4mgvnmSFLEiHupsPDCEUzgo3a3QG6T6XEc9a
|
||||
Obmh3Xoid+gXrhTwXgPmIHxLFmhZ4ETGK1KW+xFZYCFRlKSELk1K5us7MIWdXeR3
|
||||
wkbTTQ30F0dokeXW9xo6GJ0eyd0Q7ZHzePI+Gh9ORLNeRdyk7Px6cFuDtox78r7b
|
||||
teQMGNeEWtdJArWIbjxPprp84uo4qb876W2TBCt/rrFp1CRfUXtjSYQXTEsvon76
|
||||
is64X3lQhZR3HCbtjbRVhq76aNJQweVIO9CHkeLwyzGc/PyblNJNM1blIWbgQHvy
|
||||
Zr8kYAECgYEA/0e4gCGohQILo4E1EnhWuHwKPACsBHkQ/D3JT2H/yo8IZUvnsPZJ
|
||||
0iNhDnnPi892Xe9n7q8LG+9FVO8OYghfiF4n66dAEO8J0UFsA5CLNGr69noQEUvq
|
||||
GJdOvX+NGFOzCaoX8ld3xTt9V+pvMFVPFKIoy6bns4PJlllG88vgweECgYEA/LiW
|
||||
UKYomY3T8e7KgCIilkNrKWYv2qCKgoXMHerI+gz9BvcSdDRz7GHpkV9ZP9GJuJ3n
|
||||
uLHdUNkFam5jtpwfqjiBvrINgqu8/jesPeocxQwJf3x5iGazxUCEK5YonePyuxih
|
||||
e3pR+ez1b3wjBfVshs8tg58F0OdO3qVu+IZM6WECgYEAz+Ie7DD8o7vjsHWSu4TF
|
||||
0hwo1W4Spt3UKCVEn2GFxPUveBYVCjW2Lerjqb8mdYsvsBU6hNOE722s/xphkxGQ
|
||||
gmNyjOO5N1EBpKdrB4gY5EnOLxN9rCgu7XGiDI0nYE0gulkKgS4becEVNJfTjf+a
|
||||
k4nuQNGdU8GZUtdHAVfgouECgYEA5ksrJxkTPEKjFf89ZyA0FmwfVh15lCfhsGlO
|
||||
hSCzvjFhzhwOI/i8fncHCeMyiFZgwuyaAZOLkyYAqmkn0ntY25wcl3LXnvDzC1Ie
|
||||
UllpmCKM8TCz6xlzzlcpWjK+lornYZljZgskcrR9P/eGTuLD3+Ehn6Sk/yYZmAh3
|
||||
JF/17GECgYEA2x7fCZN+wr+CmG74GFdNnghqOkQQ9JleGOseHM+JIRD3J3WkuZ9x
|
||||
Dfhe68OEaUBsmB3ttDiHQ5mS+YyXIZ2st6/0KQ7v6jEM3CwUoq+SZUqV8FEIBf0+
|
||||
r3yQI5sB/ZxWvsshLtlLUgdAby+ava8mG9M5RwUjp8kdmzlkCa54cc8=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1NTAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
NVowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTUwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDfzQINLvjB3E/ea9+PW5SLys8Q4JqE9HUwLTJY
|
||||
obQ6jqf4BTxtQWRpyu+uO3ALT+oCYifZGSlyYbBnnrCNClbwZYAHT6OkDD7f9w/q
|
||||
xCYMosgvZhCCILHfolCYdFLMlYQg+pz4O+ct89J1pqyhEQBZRkUTLrXwqNUOfT1a
|
||||
uBPbIkXBlBn9yG3c9zj7uRiSEiDA6ZcfxDLh2RCEjZezUfL0EExU/ZHCVghew9cg
|
||||
OQ8T9dpMzCSQf8rG/higV4BZA66KCC+ETm2VXkqgWxJre+bnELHGXbiQxP5t21Jt
|
||||
ZXjjYcUs1YluS0nLBJiZdn1lYGM2Nok8JAKzg19XYnlsPJXfAgMBAAGjTjBMMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAIAyV
|
||||
xfmc5DMKgPUt2y6GLICybnI07SaNdzZf/5L3nM9b20Q26VLdZK4TbFsBhR4lfFPU
|
||||
F4oVwvYbw1bPT9u9RSy0wLRz8a/mJJX/cmh+OBhYJf7nrGuvYADHfi8zhfvnmgIG
|
||||
6PFezabzKgz5jkr0rbj32mP6sPpN1dzeDWESl7rcCfS1UHX4dlCKxnRqAYUXS4Kz
|
||||
f4VMQV8y9Q00/D9fH5xLxg2jyHVc+LfD9tA1r0EJKCB7p612k96YGFFqYqxQOYmr
|
||||
/Ut+EN0w/YMHuzMjhaEi+9T6r/VMYr3l8B8U1z0PYPFbbvMCGZUf53cBEjjxjg4n
|
||||
sQgzzTc/yfYXGcVVcA==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA380CDS74wdxP3mvfj1uUi8rPEOCahPR1MC0yWKG0Oo6n+AU8
|
||||
bUFkacrvrjtwC0/qAmIn2RkpcmGwZ56wjQpW8GWAB0+jpAw+3/cP6sQmDKLIL2YQ
|
||||
giCx36JQmHRSzJWEIPqc+DvnLfPSdaasoREAWUZFEy618KjVDn09WrgT2yJFwZQZ
|
||||
/cht3Pc4+7kYkhIgwOmXH8Qy4dkQhI2Xs1Hy9BBMVP2RwlYIXsPXIDkPE/XaTMwk
|
||||
kH/Kxv4YoFeAWQOuiggvhE5tlV5KoFsSa3vm5xCxxl24kMT+bdtSbWV442HFLNWJ
|
||||
bktJywSYmXZ9ZWBjNjaJPCQCs4NfV2J5bDyV3wIDAQABAoIBADoAbsyt5MiRaZ2y
|
||||
hXEpAfms6Tdtjn5wwMJopEi2N/iJKl0sNjn2naiRcMbOHr6/yl0txTgNvmEnkkl4
|
||||
pjcXe+q305ORf06v4ce3x0dH6LiTo6AtKpAfGxpjfdHVK/Rbt6+4Y+At3j9Zlqzp
|
||||
MopX1qhMfvB2xa6GgxlLOhB97p926VtKYOEoDke8uP48HJTabeiFKpn76k+0HwS0
|
||||
J58Kb647DM1rqGpZW17dPb2ovi2eznATMeAgveNvVaXipUCsqnrJI+ywrLP4TBll
|
||||
Mly+DZ42e1YnM+rd0tzgC/YNO8h7lF3YnthdQ77h3Yw09cvtmHPEuURgGiHIH5IY
|
||||
HlYKBEkCgYEA7KXOLnufN1J7QG9CqsWhKI+ZBGGTd3LmXMHTM1tLpFcQaRNd/kxg
|
||||
NVo8y4VEpCdatKj+yRe3wPZ8rO/Q074Rzys4VyTP8BNn9YjtttbP8zBDmLqkXAAc
|
||||
xVKNDiuFQ40HSIdexZVP/YVCp210q6YG3OPoT4W9QvjfPHMfzW+2euUCgYEA8hpB
|
||||
PMyl/RL2WHQHdKRRss0k8AWjtoKzepRkzrwptzgFOQZSmuvfdiPStp126iCinzag
|
||||
EPsCo3T/1E1Fj4LgOIPhRd/ibXYSAParxmmx3rMTrBwo3TRf2c9nZPKAygsMNF59
|
||||
T5ySJzU6tWE0PEtCIITW+WnQeORPzW3vE0nSzXMCgYEAwHyBP8foEryxahDVvkgw
|
||||
NOjQgwLHS0KXY914Z+6bkVoMDBvnuV/wZZU3nCeTVJ56JjbLv0/edENJ1/Tc/E4+
|
||||
+C7kjeVwiYuPZOVyzeTekqWwZftyky64ODxUZbE6nV6KDRGnIbm4rbMGK19ZpgDO
|
||||
1j8/B+f1sRLzqZzOwnBako0CgYAVSR2nPM7zOzGRgVIOfUv5jnPK7pQAPemNw3JB
|
||||
guWgCDrdUqL8n/RbrLaf+6Qy3X+uw9y64XbP7D956PlOrtEL5vxtaku8F/9pOkbM
|
||||
AQr0a4Y1QZyOJkavHb8XbwLHwMTn7c7Sqw9mhxWMUOmIy40a0tMbxqPfnSMvCpVU
|
||||
es8f5QKBgQCeFljjAnEQpuUduug/DAScAjTEbJD/18wAu1PuIM/+/zFEVaOs5w0z
|
||||
uHiiPq3fiaaoBQHZofd8mxsugfLYftAP25Qw8X/WgWPg4CLGz3Br3HgnV6RyWXr6
|
||||
R600l5lWe/ZU5epjEsToc20H9z9TbXaSKWMZiMIaMnAeboSfTtQY3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBN0ZXN0
|
||||
LmNvbUAxNDk2MzMwNjU4MCAXDTcwMDEwMTAwMDAwMFoYDzIxMTcwNTA4MTUyNDE4
|
||||
WjAeMRwwGgYDVQQDDBN0ZXN0LmNvbUAxNDk2MzMwNjU4MIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAtNQ9DkyC1Dza3OYBLcCPeJNKC8BvYVVTL+FFzpS5
|
||||
AEPNdNA/Ezk42SBWNvaY+HYBrZniOSVMkTPFT9i5sT8bBBrUUvwGk1r6tpXDlHw3
|
||||
/S7QThqZLkGcAscmahp0mWnIIGcJxZBVMR1cfFbYNumNR9UyjUDQumCb8hlT3q0n
|
||||
pEH3CL3jRpdcFolczotUzGk9u07v81gIWgQVCyYYu3WuuRjviLq8SVoHlAWvVsdW
|
||||
rGcG1LS/OKAgECYVUxs1Qauw5VjlXPGkY7gOOnjNcl3IHZU2+7dGFw1gBf+gEC5E
|
||||
/qr2fI7Lwx7R71sY0PANuuDLGfrCAaCjG3HZ01MC5Ktx8wIDAQABo00wSzAOBgNV
|
||||
HQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zATBgNVHREEDDAKggh0ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEApTrZW/xo
|
||||
EMiNgBnRyqR0wHXpuQS/V5h75CtDKE4/Yl57cQlh30SX10anRgNpeBmaZjyFQp0P
|
||||
3MAQoxUh8rOeQBcqZp7TiIXAk8w4rYWpFx59GGgiO5yD1vOj+9cIvAFDR0Fe1kbb
|
||||
kLo8s93l4yNFTdxIIIDMgNpPcp2620wkecR3PwRV1jlM/7nMfgfRJagN2+Xq7mKC
|
||||
ELzGatuXBpiy+jwCirmgmE8/MxbFbsR9L4EdW1kdYhRT+rnSNIEN3zI8GXWIH9Hu
|
||||
91cGTgKiz1znXtlmLAaIoGTahv23YUV7tbQlrtZDZjpqvTN6yM3vS0HIoSxQnT2l
|
||||
yizQSNuYSUD4HA==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAtNQ9DkyC1Dza3OYBLcCPeJNKC8BvYVVTL+FFzpS5AEPNdNA/
|
||||
Ezk42SBWNvaY+HYBrZniOSVMkTPFT9i5sT8bBBrUUvwGk1r6tpXDlHw3/S7QThqZ
|
||||
LkGcAscmahp0mWnIIGcJxZBVMR1cfFbYNumNR9UyjUDQumCb8hlT3q0npEH3CL3j
|
||||
RpdcFolczotUzGk9u07v81gIWgQVCyYYu3WuuRjviLq8SVoHlAWvVsdWrGcG1LS/
|
||||
OKAgECYVUxs1Qauw5VjlXPGkY7gOOnjNcl3IHZU2+7dGFw1gBf+gEC5E/qr2fI7L
|
||||
wx7R71sY0PANuuDLGfrCAaCjG3HZ01MC5Ktx8wIDAQABAoIBAQCE4IjVHwfsKaOy
|
||||
OxmWoy9KLQF2TTwLTAXK40DGoqanOSuasQQIfj313zs7PE4AFcb56GBCGdR/xokx
|
||||
OVKKmpKhm412RVgXo/0jej2zuOvzkhjjq8vwH6oiqHDj+vi/WuoCVXTqxjqz0p2J
|
||||
iM9s2oZEyLdS8NPwgNlXN6FXuemtWsao5ramsG8c0XM08zWazkrLGXf63dsNlEoL
|
||||
9zzpP2nNx1DVVDTUhN3mpJE60IG0niBE1X3CuIrq4A/hIOut6qa9VgdOtnnwsAyG
|
||||
hB3ZITeoaRowedmREUSSuzXnWkfHSa5yJoRlhje4mV+RRdhZ+1DSa1jzn1ZtZhjV
|
||||
1/6KQWOxAoGBAMdTlTm+9c3rtqZVgva1WfwRpfd2B+HAy/LuBQMSNEmMXn5ooJSK
|
||||
05eXMoCQC/+3fArCjYl+I7u9GHFKa4JeLjzWbqPbski5cTEHXIINGsnE9OI5pug9
|
||||
EbiZvSeimlL9Lw2BUQVW777cfz0esI+Tg514mn43gV633BWZH/AP3LHtAoGBAOg+
|
||||
R2EnDs60m0d0apR4kuZkoJDfF+uYgqyD+SMDDzgBSr4IDvWRzKAhYn+R1HsWeOxi
|
||||
U+8kx5zmDVw+GHg397FcTIVfnuQKwmBZU/XC7oKVu6wshMXFbXUSQMmIuDbu5xmZ
|
||||
1uZvMHtdszDwBWn5zGRSM3oXSQcwburJ6f1KSbdfAoGBAJE/8jUzV5GoG+BX3eiD
|
||||
vL/36FZMt2+l+7jaA+L6CAo0dMNu4N190LTdpBqVXXkJryV0Iom31rg/EqmzzmYg
|
||||
1VbV96gGN4PRRo+wypOmkwfHM6AK3PrNTbWUqodQcV7aSshvnKfkcy5FJZ9XVtg5
|
||||
aaZ9tS8WqXppRsKiY+ie1nb9AoGBALtl1Y8NRyOAFHP5+i5HhLGnrPB5NAIFFBxE
|
||||
eXnI9DTKxhbExd1dgnILvkEV2RBhN732MagcU33FHC68ZF5NOu7AfXZ5i+qSy/mW
|
||||
2urKGk8Ap2jsm05CWmpHCkQUsCCTcaL0wbU7LzG8j+UDKDs1N7oTojn4JBNK/5Uw
|
||||
zEB3+zedAoGAYAI8WQm20ElzbBB8MqL31zM3LZ5Dp/GIjPWhjwEOsGt2oCSrLxC0
|
||||
xcYRq73St5RS78uGSJxAQaMQna52idifxRE6D3IyAvsMAbn1q+LCqST9zy5jzmO8
|
||||
tUNvhnkJs1jdDjIzWVtbtMWb7/5wWANx5989B1+QWU14Qmb7uziMVR8=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDEjCCAfqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBN0ZXN0
|
||||
LmNvbUAxNDk2MzMwNjYwMCAXDTcwMDEwMTAwMDAwMFoYDzIxMTcwNTA4MTUyNDIw
|
||||
WjAeMRwwGgYDVQQDDBN0ZXN0LmNvbUAxNDk2MzMwNjYwMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAwLNxhHFPJFGnDoOnt/ELutNthoJNYLwus52+GLD1
|
||||
VYDDBA7766rzAxK8wGF9vGbXZX7L1uW3VJyJJLzZR1bBTdeOWXpyscz+33+jETbn
|
||||
Eg2Dp7KbdFAFw66B90vxLbHKbQtH63VtNg9lh+d0K4QI6SGFlI/Mv9VWawpKk1P5
|
||||
X1cgl1EgR5e4kIgQsrkO+MRc0SLZG/s9MvThrHVlZLWPjRaiqk1GDxvBjfcBoPzZ
|
||||
0jOHhWLJGWZcwXZ5brqPcqn+YMceXQlxrjxJvyq02DEWjtfimu7qoZ3+fgQy4rJ0
|
||||
GzPaDvwnkwvJQ2iN59mcybfg6AoblCOt1ypIqouMrI/J3QIDAQABo1kwVzAOBgNV
|
||||
HQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWggh0ZXN0LmNvbYIKKi50ZXN0LmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAGQ+K0dnTaX5Ry9PLA6M8yrMhq5gnX2RfyIMXCuFfMqjdju4BkTR+6zm2
|
||||
El8Z6glQ6QsKYHR4XhlhHFOP+gGyaTrsDSV2qCgphJmtn6QWOSfEmBRNNCTpMXfS
|
||||
5Ek/2dXItMjmnMdDOqcLofQyIIQFE9VpLyaFN0n1w9k6EscwSxsMiBVFwOhHpBex
|
||||
BPJnrKBDWNVHjgocUI3YzN2TzzRxVxB/xc5+Sl/jnpguad+q/wjFgpr9p2a4yAS7
|
||||
W5bXcA1S4iSp8uKVv0JM/cfFlF094ft88A/SIt8Sn8BmeOGQtSk/sf5mFbr7TRqE
|
||||
oDuKNM5AIM/fClQdlbKo7xpcJCiRkQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAwLNxhHFPJFGnDoOnt/ELutNthoJNYLwus52+GLD1VYDDBA77
|
||||
66rzAxK8wGF9vGbXZX7L1uW3VJyJJLzZR1bBTdeOWXpyscz+33+jETbnEg2Dp7Kb
|
||||
dFAFw66B90vxLbHKbQtH63VtNg9lh+d0K4QI6SGFlI/Mv9VWawpKk1P5X1cgl1Eg
|
||||
R5e4kIgQsrkO+MRc0SLZG/s9MvThrHVlZLWPjRaiqk1GDxvBjfcBoPzZ0jOHhWLJ
|
||||
GWZcwXZ5brqPcqn+YMceXQlxrjxJvyq02DEWjtfimu7qoZ3+fgQy4rJ0GzPaDvwn
|
||||
kwvJQ2iN59mcybfg6AoblCOt1ypIqouMrI/J3QIDAQABAoIBADlQ5lHTdgvCcaMC
|
||||
i89NVgTSwEAC38sHDgkEwTcM41v0OY0qe8nkBfYDC7tZBBIWsLiSl0Sq/PWgvbX8
|
||||
qc/rQQHLPJ7mqdiytZh6mWEUaHRZKrClklFtP9mtPSD2KJ1DxYbblR+2xK4QtE1R
|
||||
DZ+n3RKikt3WS7s/VD3wSLA7iO/PMJ+ER3kPxZWsVYJw6KpmR8U/v881eM7NGoK3
|
||||
SwYSqXfcRidNOl68Je3vm3MpK7SiPEOX9AGJUXlkpjJcyOqEE+X23wNSZUpKT+i7
|
||||
NIrXaEml1nKlTRMlDWi5ZPqzhpguc5Nmn0Tu+01ZClwcu+/7b4C5tkIjXQnyjXsO
|
||||
0o1EqcECgYEAyEJwGl6KvvYaRsBiFRWIN1950S87O0grOnwb3/FedW4CEf9Lm/Xj
|
||||
653HTe3zYAJDlsRFCOQ/KXi6nUjAAv8DAydKWmr5EonNj+VXT0Sw32N681lDMPzK
|
||||
4csJek2bWt2alKbachKAq/gr00837HELl1ALr1X3a3HXr6hZHNjUHpECgYEA9lZq
|
||||
tXDDV+emyIf/O9LwDUkctHc06qD+uBfiuW0DqVeYPE7E3QPsPzyjnwSfqmgYlpKm
|
||||
Ku60MfmAVXT8kUSBUuY9ph5AOE/5LwkM3ONc34UBtkruzHUccGXuXelUzmnAQLhi
|
||||
ZJiWJJrHYICcOZNzd9UmqYye66lyzp9NWe7ttI0CgYB8qYcZkzLxz0fqNUaZc275
|
||||
cXDmvG016SYn4SyFCr9PgKy/QVpy+u3oNa7lHzR61s32Y7XJ5DRBf8tDsA7/jnn0
|
||||
k5fgk2j7llcltZHVYaBtX4MhS7bdHvC5AGik/vyv4vWghgHEMypwYyv8/fqFMJYT
|
||||
mpu7iVtdQmAPFFBs+bmKUQKBgQC4Hm8znkzjbymhyMRkmo0B4RurZ04N8LdyMags
|
||||
n+aUs/v9V4KdD0mNGm3RdUtBuvxlzsaUYEYe9DWPqhj9Gw7uP1jkyMeHT38YQNN0
|
||||
ZhwMlQVqkydZek7/U7COUNAqV7Byr14bglD2mxlab8ZU4njzoEV9hLVjvwsolLjj
|
||||
90mEIQKBgF/IE4+wL9sdeQ7MGanYHFzQtyKxWnRzCGWDkHV9InGZ2I7O3AeqDC76
|
||||
fXhiRoRbBMSgddyOYTUoaPhwgqPGoC9H/3ZHnyx5fokl0FTNfzk1mnY1n1HD2roR
|
||||
p76hbMs+TjIGG+lNDso3WuV21Gn+vynDVO9FQumgeaEc+CLXpwEq
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDGTCCAgGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1ODAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
OFowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTgwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDO4DuzjpGF3Em7sIrAv6/19KyTVLxV4jM0XX8G
|
||||
S8Uo04oyovHnHqfCDd+yaGs1glxD95eqZ5kZDgQNXhn+oZkNvcPJJ8O2tPhHwvjC
|
||||
PR3KzNL3dFMo6+7BCmBRIVvSNHkkZ5lyoOSE7deGvoKl3KuEWUGwUiGnPx95snCD
|
||||
HPfgHYto1zSI2NbdnF4hRuOiSFhettMZiwpXEYGhcMh1RYDYxPf+5/XcFz3VCdpF
|
||||
1COXSYIS2r60H08dH1u6rO1iliJaRh+jqk998exdi0TwJvVTiaubMRZxtGkPNxjE
|
||||
tSukjDA9UaqAFBnireXj2qc+a6B7AMsoTymn8Ka6QJyt+3ZdAgMBAAGjXjBcMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MCQGA1UdEQQdMBuCCWxvY2FsaG9zdIIIdGVzdC5jb22HBH8AAAEwDQYJKoZI
|
||||
hvcNAQELBQADggEBAAOc/JL/2xfnPAcwzxvF/ssYK6EpjD6plG+OhlIj5UiXo/z4
|
||||
5IcLCg+N1P7dGaiSMfI/hIM+M/z24QMk6gXFMrVUFh6sm49dNmTry4Qsyp8Up5HD
|
||||
ettKLaWG3YA08VeqJ0C2xsFh7nJnrlzQad1dwtnj6ActWx/2g8SFkfpQYLba/YI/
|
||||
YC3biwKGY9P7lmCP5p4234blenJHJW5hbwNyLManvEA9O39Rr4oph2Z1YtmpsNM/
|
||||
p+xioLTx7oFMtRkBBpmzSKJgLAqCxVg7P+MzjS1s3W49QLI8F1sZ+mXBrZxbALhQ
|
||||
TtOjvUx+vb6Gihkzn8XkGdbgsiOTMBoT0EmIBJE=
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAzuA7s46RhdxJu7CKwL+v9fSsk1S8VeIzNF1/BkvFKNOKMqLx
|
||||
5x6nwg3fsmhrNYJcQ/eXqmeZGQ4EDV4Z/qGZDb3DySfDtrT4R8L4wj0dyszS93RT
|
||||
KOvuwQpgUSFb0jR5JGeZcqDkhO3Xhr6CpdyrhFlBsFIhpz8febJwgxz34B2LaNc0
|
||||
iNjW3ZxeIUbjokhYXrbTGYsKVxGBoXDIdUWA2MT3/uf13Bc91QnaRdQjl0mCEtq+
|
||||
tB9PHR9buqztYpYiWkYfo6pPffHsXYtE8Cb1U4mrmzEWcbRpDzcYxLUrpIwwPVGq
|
||||
gBQZ4q3l49qnPmugewDLKE8pp/CmukCcrft2XQIDAQABAoIBAQC4LgSZAKXook32
|
||||
zt9JaZ+T/yih5r/iSofB6DeN+GloxqT0HgP1+2Hpr4ZoBPTl59CTJlyd9qvkFYlg
|
||||
CVZlT6O/CyLC9ScWhBnDcf8cl2LtydtNOgBLn3mp3b4QnP1tsQ/lbGK+HiY1frby
|
||||
nKweVM9S/lAwVX7mspkoNMhcwq6glLL1QnJmLfmHtsOik4e+eD051aYI4OcfkFFo
|
||||
T5f6Jg5oNC0L9x+ona1avfD2eBmXmUv8kV4+NSeu+pM+hWnc6r5XnHdXgo0Fu+nf
|
||||
CQ6wUkyXQAmANI/qo+73G3lEZ7KA9mqrCTbM8sulC4c7+Qpb1vHjuz7pSMj57k67
|
||||
tI2lPGW1AoGBAPDdooMFZIq6n7wt160MlYDhLujcPaMzgiXWPg9TOLzuWrSZleGH
|
||||
k818LTXKlQP2ffVADlwHvyi0E7yZVzmG2Xt6Gi8lkGIP5LZK81BlsBspX00bvJCM
|
||||
VeyE6flSwLA86bQt8spYNAOMMc12F2i3y+YkoKfQmgMiG3H7RjM4Yeq3AoGBANvf
|
||||
3bh7iHs74oZz40em/W+LdAFBE29FeCloqIXnueHVTLdpHFepmp5OBxogkaYJlVOF
|
||||
0B/cl8sYn/6CtqKHzhCcCc8V/54O15n/yNRMru4GU0Z5mhaxWvypJM3WXTVvC612
|
||||
ODM7shXtFQAF5kgeGSDFOepUG1XRPqPjBmSOFiOLAoGAL/kkzg276bmj6PoEc+4G
|
||||
tOWkzzJWgHPY3ypdr/W2XkLnBAN3C7VSJeIuqwEPTvvAOKGqen/8feHn8G9mJQoL
|
||||
tQErx+omaLGbrwcckQ2/1pkV5yi4FN4umu4aH9Nwl2l6bq2cJtsMeQxqOu7jWLMK
|
||||
xGrVKLduhWM8riYK5Fa9gd8CgYByWA+UOxoVDGWXinjt8FfoRFuFs3QJ79S3pCfP
|
||||
y1yNp0GIOG9230r7fJSQ79MOx/kSQIqlpzCBfELoNs4H5Bwz4xHu0f/nEMzq12x3
|
||||
i5GFU2DHS8Hofz9UGhp7uTkr6p3mDY7YhfjtEihTpL3HT2+97RNbW3YDwReUXyIZ
|
||||
9RJqVQKBgEQzEKMFpA5NTzs4BanS8372XXKBRhP0CCTcxS23k/kkYFd0Swnsmv+s
|
||||
ZCJhV5B1Uz0aSK9jfvCaEfwHjdhxfyYBzoXYVxaxphwNY1Vq7QaEzzyXWKDK3beS
|
||||
9pwnZf6bEQEvvXyJ3ssqLaHWCoViHe0h/Atsj6UOYhQt5mXzZDEK
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBN0ZXN0
|
||||
LmNvbUAxNDk2MzMwNjU1MCAXDTcwMDEwMTAwMDAwMFoYDzIxMTcwNTA4MTUyNDE1
|
||||
WjAeMRwwGgYDVQQDDBN0ZXN0LmNvbUAxNDk2MzMwNjU1MIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEApFk4QTS28tu20CSV1s0aCC7kV7p/V8XziC5g98OI
|
||||
GO9s8uVrzc51xsnJ3Y3+Xnx43x9G9VjgSNhPAuE7+/UnP6iAkZZV0mOD3xwwILwy
|
||||
JK6gZOcZzd9BX9JldSnjv64r5peg5mzdhNqpRs0i3oPcfriW0sGkzl6IQlsowGoS
|
||||
eDkO6+Z0IpQDo4CqcWond78LDyvqwbfFReyHEtz8D17sciGni6QPK3kGBFDiO0Ay
|
||||
keV4GqEXw13ryKzVun/haLmekRf8svAU8+pjpHY0uc1cv0l0nTIZdwnp2EIF0msa
|
||||
EKYyUUpcuFkMQTToYzj9LaIQmvAGIVIouNAydbheBifySwIDAQABo00wSzAOBgNV
|
||||
HQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zATBgNVHREEDDAKggh0ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAWlrvejAW
|
||||
DpKWBfgQpJLpL56v6dFkCjhThtvDrfvpx/gL0p2QQOIrgD7o+/+fmockmpphf8zc
|
||||
lAFS/M2IuuvJUN7qvq/4pnUa527LsQFIQSG4GhNfHHdKfISLdjgy7LRlmjLnnSu3
|
||||
9qa5KvJg9SIWpe41LbeQPB8fLYNuF+tPzrI7QLp/VbMSSyNz4wzpdk8/+r+3KmU8
|
||||
D1SEQcaEIg7/YlyJ7TZiWiFlZRFcObE11lRYo6tnh8t2e7s0IqC1JwiAmCk0j0iZ
|
||||
kHE8yND+CuO8QVDxnmu86STL+q0ldZL6C/1lLlnKFKLp+bZfW+s+kds7lDSmUMDi
|
||||
CbImL3sIf6clIg==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEApFk4QTS28tu20CSV1s0aCC7kV7p/V8XziC5g98OIGO9s8uVr
|
||||
zc51xsnJ3Y3+Xnx43x9G9VjgSNhPAuE7+/UnP6iAkZZV0mOD3xwwILwyJK6gZOcZ
|
||||
zd9BX9JldSnjv64r5peg5mzdhNqpRs0i3oPcfriW0sGkzl6IQlsowGoSeDkO6+Z0
|
||||
IpQDo4CqcWond78LDyvqwbfFReyHEtz8D17sciGni6QPK3kGBFDiO0AykeV4GqEX
|
||||
w13ryKzVun/haLmekRf8svAU8+pjpHY0uc1cv0l0nTIZdwnp2EIF0msaEKYyUUpc
|
||||
uFkMQTToYzj9LaIQmvAGIVIouNAydbheBifySwIDAQABAoIBAC07+UXJMomJe7my
|
||||
OCOU9BNIhMS4qhAIhcz3puzKvozOaVg5WQCeUMBUDeGTEW4EKGiQ/UDOI30pPCX4
|
||||
xD/G6/STdj+b9ycfCM7BvWVlJw/9mFvtV6bYSfALwq0KyIqbb63aEgkZ8aZ9YJYC
|
||||
JBTGiku+lpSPg8LhNfO9j2vWRhsceFEtdkv18T9sCSOQTYIrDKFdbxsl49A/D9WZ
|
||||
YERYVWmWsSHl4CkKAzrQRMIrREgYJk5R3Qt0Qk+3a4BYlmDG6/5Ayfi0sx+bpcK+
|
||||
255GbRPhe9rTUI6uIc57q7TxGOIG+ekTVqkL87bVR8+oLY/5ARW3jXedB+Th2ku4
|
||||
/JziseECgYEAx77MOmRPx5ggNQqmSfcaxozmX8Cil6pEZRQxdtdgum9QnyXhG5q9
|
||||
J8Onw2o5+u+KsTmXIx4CdcA+fL4Z9D/g6GHsi87lJT6KhdHGAmPsEVFQYc0kme3X
|
||||
hEfGppP4G4haHBzhNh5V9CxlZ7aHsB9J/LGZ2Utz+kvGHE/8GKiERNMCgYEA0qJj
|
||||
8pdnnObFW4x+/TrOzf9jxAyB7xp3ZTp1gayzmrG4cQr5OMhAZEXG5t1JOg5SvQXh
|
||||
LRWDr21BtbizJoFcAe0FzMdWIR8fz8RfqiFlfZSnMBnkhQrngu8CghAkg3g0h0m1
|
||||
tSSpaqQGVRdOFG1A/HSjiNdsBpqLGxejdUfZkakCgYEAuIAFdr4nbu6WeUf/93w3
|
||||
EEUfmjx+MudES7VORz6EC1E8v/QmLPBOXkd8U6VwLthKXI8cioRysz9CuMiDgrfq
|
||||
T9v7udv+jtto6listJKFgC2CuQPbFg+6LWZ7GGy/FPdqfGM0p19395V2iUjxpn4Q
|
||||
QkfuGud2FjEdqhM7ga9OlZ8CgYEAvwXM1NYgfnf/Jh6NkEREBygFJ2gccmazPxe8
|
||||
N4UTQUjJt6M3EBrz4rwxPXAUF9WjjY+GfieTzIWuYQqHVnVcptZ5OxTQdKtQY1F5
|
||||
XMZ6z2AAG6xvxYR1HxZ5VNEk/CIIqWTcqNH93xuwLn07L2VB2XJCWTjc3ERNwZ03
|
||||
fYZStzkCgYBtXFo7OC80f6xRDa1NfQfP4vP6dMczZBZBx2A/rCybwtQsJ40duEB2
|
||||
hGmgqIrRfh7H7KC8W792xzE1PKUXztTzxxpIr7Ho/nDUWzambMi39EYyBJ6Fp7z2
|
||||
RkPJFDkAYDpx/v357886y7HFz8pUUNd+z9V9CLemVqhjBWmIaLEX/w==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/cert
generated
vendored
19
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/cert
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRsb2Nh
|
||||
bGhvc3RAMTQ5NjMzMDY1NTAgFw03MDAxMDEwMDAwMDBaGA8yMTE3MDUwODE1MjQx
|
||||
NVowHzEdMBsGA1UEAwwUbG9jYWxob3N0QDE0OTYzMzA2NTUwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQCmZQErnj8vlA5uvizHXnGmvDCpeOkc5Ldbj0Hz
|
||||
zqTCiwOSTBeestdN6oLKvxJVlvyO3UQJxhJWr00QRwdCYIvLIDmiBQjb7ciOPcl8
|
||||
WdLjBtZ36288E9P1nVwFi2RwLo/XzZlCYX0aRe/SM7/h5zzNxBR6FdRvtI1d5as4
|
||||
qiGdj7TqCFIJ/8jaBfxlusjEJd+xc0Cn8IAmSpPJYCCDmxjAzw0D12Ui3toTFHUI
|
||||
J9BA7iXTVvMbfau8KQJTPeu/HQ4zgU//4GW1Qo52gNzfY37iliZaG3HTWD1pxTFO
|
||||
qdDuprFIffsQrQ7mHAkGnAExxZYc2cE4UF+ME8dV0/6nTQA1AgMBAAGjTjBMMA4G
|
||||
A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
|
||||
AQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAdUUo
|
||||
i0A3ttsTca5n9OY4EbDPQz7uAhXkihwoG2YeqnucrNXg+SaS+7hFA9sa1gY5NmDF
|
||||
96OvmQLBEXVz3uLEiv2KGtY5yiAo6iTtk2gtoGAloULEJ018XGQ0yNuDWUfRLyc9
|
||||
5nA8CBPEnBR7MjO6XhvvFMbAjtXoDKFqVeq3okXbL7ygUjlpwv+Sbps+DjQdmnIQ
|
||||
A90S7gcFqaCmy2KnzADartasIImy/78R9r68UdJrsmyy/aPNnJ/9AbbU8Z20JFcu
|
||||
clKOENaKJe/o1nOVzZA2E2oVElT++2wNfomDN5ae77cLoCjZPOBArFlhwyk16YIa
|
||||
wX3ITLz6Ibr9Iy7DvA==
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/key
generated
vendored
27
vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/key
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEApmUBK54/L5QObr4sx15xprwwqXjpHOS3W49B886kwosDkkwX
|
||||
nrLXTeqCyr8SVZb8jt1ECcYSVq9NEEcHQmCLyyA5ogUI2+3Ijj3JfFnS4wbWd+tv
|
||||
PBPT9Z1cBYtkcC6P182ZQmF9GkXv0jO/4ec8zcQUehXUb7SNXeWrOKohnY+06ghS
|
||||
Cf/I2gX8ZbrIxCXfsXNAp/CAJkqTyWAgg5sYwM8NA9dlIt7aExR1CCfQQO4l01bz
|
||||
G32rvCkCUz3rvx0OM4FP/+BltUKOdoDc32N+4pYmWhtx01g9acUxTqnQ7qaxSH37
|
||||
EK0O5hwJBpwBMcWWHNnBOFBfjBPHVdP+p00ANQIDAQABAoIBAEqbVTgCf2BM6V+8
|
||||
Q4WtEhZpoQQL47IB1zjldfPkfrl/7T0Ggzy0AZe9A6H2pDjeNyWzjlM3jXdyqIIY
|
||||
5udbNLMCIvVDfqJl7pvgllv8RnNm2HjyhnCQj2Q8h0sxIfqu1e40EHjUD2zdWNeO
|
||||
PoYC0Z+NQIUxDox7jzs/xFLm7aWgVTYk86iFa0/uYwnCQpGHR5OkBOhVdkqBMUrH
|
||||
7hPIoKgLNHT8/jhugv+GamtAmys1KoqIvZsc/XQCMPVmE55n0OBtooQ3fhBXJC0x
|
||||
UZgJGKNLSjxt7uxHb/BQk5DtFJmPck0derMNkM8WQ6o/XSjlSiKtsct8c7us/c7r
|
||||
9OFkcy0CgYEAwB6uKr3Al1IM16t6yEEdfrNc/koJ9AQ3sVHSE5CjFBLMs6gL+Feo
|
||||
r3oFUglY1QB6v+5YUVsLovJLMHuH1x7fKHmd0Fmx75uVzurG2JdKwCiV39PPKYjr
|
||||
238Yw3Nk6IllPCn+SOIvPDhiuvPwX8FylKGPjsi7AHphKN0f9EEnL6cCgYEA3biT
|
||||
l8yvpgPpZrpTaMlotKvZkTKtb212a5EdHn0bk5fSM9xaRcumRsWd9eWGutHpMbZx
|
||||
wj1jAFaGDleBl08zHAr5jsY7i1C3CFKFEUbYR5Qu5+Ot/gdEyO2+j0ehluPOBFad
|
||||
P514bnWpdct8Khv2dW3OJMzVdFM7M06MXkQFLMMCgYAugT63qecMuhfRvPijsN9q
|
||||
5BAGnfV60+qHSb8IbWKMYWCbvHnpS47Rqz/Oc+TE6rDL9O38A4X1k6EPw1dGg3qR
|
||||
WZ8R6CRiU88Xn00y8Kxvh2OAIs1qyHIPV9yusygiAeA3iBK9ocK9WQjNKG9vPmx1
|
||||
/gW6Emzx2K3cLmqlvX+20QKBgA82yCHlcLQSlqRu6qRJFb83/5DgCliYCUUuSvI5
|
||||
oXfKNilK2ILri3hVvRYPbuRI3RiFLV8nuTBfv4kiZgkM7TPiaOdsIM/ZdQXEK89Y
|
||||
riSTPXi5/cltlEG5VpccUjE5ZnyTuOyRkJ77weoMUXPOQWYjZ77Ms2TtBSXrIOSj
|
||||
BDvjAoGBALAag/LXYvi7l4xIuUMuo1HC4YXZVSqDM7kftLdSUGOl/zGV/0QkSh76
|
||||
KCVOwXOCmzFeImrZYYDf4uu1wW7paprNaCV6EiChhRgCrjkZIpyw6RHAGshp3a3e
|
||||
BjXCIHOW5TsWRdR+IvjzIMp9tbHCEvjSw0jDm3JiaSYGRD1AldhV
|
||||
-----END RSA PRIVATE KEY-----
|
||||
53
vendor/k8s.io/apiserver/pkg/server/routes/BUILD
generated
vendored
53
vendor/k8s.io/apiserver/pkg/server/routes/BUILD
generated
vendored
|
|
@ -1,53 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"index.go",
|
||||
"metrics.go",
|
||||
"openapi.go",
|
||||
"profiling.go",
|
||||
"swagger.go",
|
||||
"swaggerui.go",
|
||||
"version.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/elazarl/go-bindata-assetfs:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/metrics:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/routes/data/swagger:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/etcd/metrics:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/handler:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/routes/data/swagger:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
2
vendor/k8s.io/apiserver/pkg/server/routes/OWNERS
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/routes/OWNERS
generated
vendored
|
|
@ -1,2 +0,0 @@
|
|||
reviewers:
|
||||
- sttts
|
||||
12
vendor/k8s.io/apiserver/pkg/server/routes/data/README.md
generated
vendored
12
vendor/k8s.io/apiserver/pkg/server/routes/data/README.md
generated
vendored
|
|
@ -1,12 +0,0 @@
|
|||
The datafiles contained in these directories were generated by the script
|
||||
```sh
|
||||
hack/build-ui.sh
|
||||
```
|
||||
|
||||
Do not edit by hand.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
||||
24
vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/BUILD
generated
vendored
24
vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/BUILD
generated
vendored
|
|
@ -1,24 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["datafile.go"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
17087
vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/datafile.go
generated
vendored
17087
vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/datafile.go
generated
vendored
File diff suppressed because one or more lines are too long
18
vendor/k8s.io/apiserver/pkg/server/routes/doc.go
generated
vendored
18
vendor/k8s.io/apiserver/pkg/server/routes/doc.go
generated
vendored
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 routes holds a collection of optional genericapiserver http handlers.
|
||||
package routes
|
||||
69
vendor/k8s.io/apiserver/pkg/server/routes/index.go
generated
vendored
69
vendor/k8s.io/apiserver/pkg/server/routes/index.go
generated
vendored
|
|
@ -1,69 +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 routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
)
|
||||
|
||||
// ListedPathProvider is an interface for providing paths that should be reported at /.
|
||||
type ListedPathProvider interface {
|
||||
// ListedPaths is an alphabetically sorted list of paths to be reported at /.
|
||||
ListedPaths() []string
|
||||
}
|
||||
|
||||
// ListedPathProviders is a convenient way to combine multiple ListedPathProviders
|
||||
type ListedPathProviders []ListedPathProvider
|
||||
|
||||
// ListedPaths unions and sorts the included paths.
|
||||
func (p ListedPathProviders) ListedPaths() []string {
|
||||
ret := sets.String{}
|
||||
for _, provider := range p {
|
||||
for _, path := range provider.ListedPaths() {
|
||||
ret.Insert(path)
|
||||
}
|
||||
}
|
||||
|
||||
return ret.List()
|
||||
}
|
||||
|
||||
// Index provides a webservice for the http root / listing all known paths.
|
||||
type Index struct{}
|
||||
|
||||
// Install adds the Index webservice to the given mux.
|
||||
func (i Index) Install(pathProvider ListedPathProvider, mux *mux.PathRecorderMux) {
|
||||
handler := IndexLister{StatusCode: http.StatusOK, PathProvider: pathProvider}
|
||||
|
||||
mux.UnlistedHandle("/", handler)
|
||||
mux.UnlistedHandle("/index.html", handler)
|
||||
}
|
||||
|
||||
// IndexLister lists the available indexes with the status code provided
|
||||
type IndexLister struct {
|
||||
StatusCode int
|
||||
PathProvider ListedPathProvider
|
||||
}
|
||||
|
||||
// ServeHTTP serves the available paths.
|
||||
func (i IndexLister) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
responsewriters.WriteRawJSON(i.StatusCode, metav1.RootPaths{Paths: i.PathProvider.ListedPaths()}, w)
|
||||
}
|
||||
54
vendor/k8s.io/apiserver/pkg/server/routes/metrics.go
generated
vendored
54
vendor/k8s.io/apiserver/pkg/server/routes/metrics.go
generated
vendored
|
|
@ -1,54 +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 routes
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
apimetrics "k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
etcdmetrics "k8s.io/apiserver/pkg/storage/etcd/metrics"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// DefaultMetrics installs the default prometheus metrics handler
|
||||
type DefaultMetrics struct{}
|
||||
|
||||
// Install adds the DefaultMetrics handler
|
||||
func (m DefaultMetrics) Install(c *mux.PathRecorderMux) {
|
||||
c.Handle("/metrics", prometheus.Handler())
|
||||
}
|
||||
|
||||
// MetricsWithReset install the prometheus metrics handler extended with support for the DELETE method
|
||||
// which resets the metrics.
|
||||
type MetricsWithReset struct{}
|
||||
|
||||
// Install adds the MetricsWithReset handler
|
||||
func (m MetricsWithReset) Install(c *mux.PathRecorderMux) {
|
||||
defaultMetricsHandler := prometheus.Handler().ServeHTTP
|
||||
c.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method == "DELETE" {
|
||||
apimetrics.Reset()
|
||||
etcdmetrics.Reset()
|
||||
io.WriteString(w, "metrics reset\n")
|
||||
return
|
||||
}
|
||||
defaultMetricsHandler(w, req)
|
||||
})
|
||||
}
|
||||
39
vendor/k8s.io/apiserver/pkg/server/routes/openapi.go
generated
vendored
39
vendor/k8s.io/apiserver/pkg/server/routes/openapi.go
generated
vendored
|
|
@ -1,39 +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.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/handler"
|
||||
)
|
||||
|
||||
// OpenAPI installs spec endpoints for each web service.
|
||||
type OpenAPI struct {
|
||||
Config *common.Config
|
||||
}
|
||||
|
||||
// Install adds the SwaggerUI webservice to the given mux.
|
||||
func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) {
|
||||
_, err := handler.BuildAndRegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, mux)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to register open api spec for root: %v", err)
|
||||
}
|
||||
}
|
||||
36
vendor/k8s.io/apiserver/pkg/server/routes/profiling.go
generated
vendored
36
vendor/k8s.io/apiserver/pkg/server/routes/profiling.go
generated
vendored
|
|
@ -1,36 +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 routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
)
|
||||
|
||||
// Profiling adds handlers for pprof under /debug/pprof.
|
||||
type Profiling struct{}
|
||||
|
||||
// Install adds the Profiling webservice to the given mux.
|
||||
func (d Profiling) Install(c *mux.PathRecorderMux) {
|
||||
c.UnlistedHandle("/debug/pprof", http.HandlerFunc(pprof.Index))
|
||||
c.UnlistedHandlePrefix("/debug/pprof/", http.HandlerFunc(pprof.Index))
|
||||
c.UnlistedHandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
c.UnlistedHandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
c.UnlistedHandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
}
|
||||
36
vendor/k8s.io/apiserver/pkg/server/routes/swagger.go
generated
vendored
36
vendor/k8s.io/apiserver/pkg/server/routes/swagger.go
generated
vendored
|
|
@ -1,36 +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.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
)
|
||||
|
||||
// Swagger installs the /swaggerapi/ endpoint to allow schema discovery
|
||||
// and traversal. It is optional to allow consumers of the Kubernetes GenericAPIServer to
|
||||
// register their own web services into the Kubernetes mux prior to initialization
|
||||
// of swagger, so that other resource types show up in the documentation.
|
||||
type Swagger struct {
|
||||
Config *swagger.Config
|
||||
}
|
||||
|
||||
// Install adds the SwaggerUI webservice to the given mux.
|
||||
func (s Swagger) Install(c *restful.Container) {
|
||||
s.Config.WebServices = c.RegisteredWebServices()
|
||||
swagger.RegisterSwaggerService(*s.Config, c)
|
||||
}
|
||||
40
vendor/k8s.io/apiserver/pkg/server/routes/swaggerui.go
generated
vendored
40
vendor/k8s.io/apiserver/pkg/server/routes/swaggerui.go
generated
vendored
|
|
@ -1,40 +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 routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
"k8s.io/apiserver/pkg/server/routes/data/swagger"
|
||||
)
|
||||
|
||||
// SwaggerUI exposes files in third_party/swagger-ui/ under /swagger-ui.
|
||||
type SwaggerUI struct{}
|
||||
|
||||
// Install adds the SwaggerUI webservice to the given mux.
|
||||
func (l SwaggerUI) Install(c *mux.PathRecorderMux) {
|
||||
fileServer := http.FileServer(&assetfs.AssetFS{
|
||||
Asset: swagger.Asset,
|
||||
AssetDir: swagger.AssetDir,
|
||||
Prefix: "third_party/swagger-ui",
|
||||
})
|
||||
prefix := "/swagger-ui/"
|
||||
c.HandlePrefix(prefix, http.StripPrefix(prefix, fileServer))
|
||||
}
|
||||
57
vendor/k8s.io/apiserver/pkg/server/routes/version.go
generated
vendored
57
vendor/k8s.io/apiserver/pkg/server/routes/version.go
generated
vendored
|
|
@ -1,57 +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 routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
)
|
||||
|
||||
// Version provides a webservice with version information.
|
||||
type Version struct {
|
||||
Version *version.Info
|
||||
}
|
||||
|
||||
// Install registers the APIServer's `/version` handler.
|
||||
func (v Version) Install(c *restful.Container) {
|
||||
if v.Version == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Set up a service to return the git code version.
|
||||
versionWS := new(restful.WebService)
|
||||
versionWS.Path("/version")
|
||||
versionWS.Doc("git code version from which this is built")
|
||||
versionWS.Route(
|
||||
versionWS.GET("/").To(v.handleVersion).
|
||||
Doc("get the code version").
|
||||
Operation("getCodeVersion").
|
||||
Produces(restful.MIME_JSON).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Writes(version.Info{}))
|
||||
|
||||
c.Add(versionWS)
|
||||
}
|
||||
|
||||
// handleVersion writes the server's version information.
|
||||
func (v Version) handleVersion(req *restful.Request, resp *restful.Response) {
|
||||
responsewriters.WriteRawJSON(http.StatusOK, *v.Version, resp.ResponseWriter)
|
||||
}
|
||||
64
vendor/k8s.io/apiserver/pkg/server/storage/BUILD
generated
vendored
64
vendor/k8s.io/apiserver/pkg/server/storage/BUILD
generated
vendored
|
|
@ -1,64 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"resource_config_test.go",
|
||||
"storage_factory_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/example:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/example/install:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"resource_config.go",
|
||||
"resource_encoding_config.go",
|
||||
"storage_codec.go",
|
||||
"storage_factory.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
18
vendor/k8s.io/apiserver/pkg/server/storage/doc.go
generated
vendored
18
vendor/k8s.io/apiserver/pkg/server/storage/doc.go
generated
vendored
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 storage contains the plumbing to setup the etcd storage of the apiserver.
|
||||
package storage
|
||||
185
vendor/k8s.io/apiserver/pkg/server/storage/resource_config.go
generated
vendored
185
vendor/k8s.io/apiserver/pkg/server/storage/resource_config.go
generated
vendored
|
|
@ -1,185 +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.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// APIResourceConfigSource is the interface to determine which versions and resources are enabled
|
||||
type APIResourceConfigSource interface {
|
||||
AnyVersionOfResourceEnabled(resource schema.GroupResource) bool
|
||||
ResourceEnabled(resource schema.GroupVersionResource) bool
|
||||
AllResourcesForVersionEnabled(version schema.GroupVersion) bool
|
||||
AnyResourcesForVersionEnabled(version schema.GroupVersion) bool
|
||||
AnyResourcesForGroupEnabled(group string) bool
|
||||
}
|
||||
|
||||
// Specifies the overrides for various API group versions.
|
||||
// This can be used to enable/disable entire group versions or specific resources.
|
||||
type GroupVersionResourceConfig struct {
|
||||
// Whether to enable or disable this entire group version. This dominates any enablement check.
|
||||
// Enable=true means the group version is enabled, and EnabledResources/DisabledResources are considered.
|
||||
// Enable=false means the group version is disabled, and EnabledResources/DisabledResources are not considered.
|
||||
Enable bool
|
||||
|
||||
// DisabledResources lists the resources that are specifically disabled for a group/version
|
||||
// DisabledResources trumps EnabledResources
|
||||
DisabledResources sets.String
|
||||
|
||||
// EnabledResources lists the resources that should be enabled by default. This is a little
|
||||
// unusual, but we need it for compatibility with old code for now. An empty set means
|
||||
// enable all, a non-empty set means that all other resources are disabled.
|
||||
EnabledResources sets.String
|
||||
}
|
||||
|
||||
var _ APIResourceConfigSource = &ResourceConfig{}
|
||||
|
||||
type ResourceConfig struct {
|
||||
GroupVersionResourceConfigs map[schema.GroupVersion]*GroupVersionResourceConfig
|
||||
}
|
||||
|
||||
func NewResourceConfig() *ResourceConfig {
|
||||
return &ResourceConfig{GroupVersionResourceConfigs: map[schema.GroupVersion]*GroupVersionResourceConfig{}}
|
||||
}
|
||||
|
||||
func NewGroupVersionResourceConfig() *GroupVersionResourceConfig {
|
||||
return &GroupVersionResourceConfig{Enable: true, DisabledResources: sets.String{}, EnabledResources: sets.String{}}
|
||||
}
|
||||
|
||||
// DisableVersions disables the versions entirely. No resources (even those whitelisted in EnabledResources) will be enabled
|
||||
func (o *ResourceConfig) DisableVersions(versions ...schema.GroupVersion) {
|
||||
for _, version := range versions {
|
||||
_, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
o.GroupVersionResourceConfigs[version] = NewGroupVersionResourceConfig()
|
||||
}
|
||||
|
||||
o.GroupVersionResourceConfigs[version].Enable = false
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) EnableVersions(versions ...schema.GroupVersion) {
|
||||
for _, version := range versions {
|
||||
_, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
o.GroupVersionResourceConfigs[version] = NewGroupVersionResourceConfig()
|
||||
}
|
||||
|
||||
o.GroupVersionResourceConfigs[version].Enable = true
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) DisableResources(resources ...schema.GroupVersionResource) {
|
||||
for _, resource := range resources {
|
||||
version := resource.GroupVersion()
|
||||
_, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
o.GroupVersionResourceConfigs[version] = NewGroupVersionResourceConfig()
|
||||
}
|
||||
|
||||
o.GroupVersionResourceConfigs[version].DisabledResources.Insert(resource.Resource)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) EnableResources(resources ...schema.GroupVersionResource) {
|
||||
for _, resource := range resources {
|
||||
version := resource.GroupVersion()
|
||||
_, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
o.GroupVersionResourceConfigs[version] = NewGroupVersionResourceConfig()
|
||||
}
|
||||
|
||||
o.GroupVersionResourceConfigs[version].EnabledResources.Insert(resource.Resource)
|
||||
o.GroupVersionResourceConfigs[version].DisabledResources.Delete(resource.Resource)
|
||||
}
|
||||
}
|
||||
|
||||
// AnyResourcesForVersionEnabled only considers matches based on exactly group/resource lexical matching. This means that
|
||||
// resource renames across versions are NOT considered to be the same resource by this method. You'll need to manually check
|
||||
// using the ResourceEnabled function.
|
||||
func (o *ResourceConfig) AnyVersionOfResourceEnabled(resource schema.GroupResource) bool {
|
||||
for version := range o.GroupVersionResourceConfigs {
|
||||
if version.Group != resource.Group {
|
||||
continue
|
||||
}
|
||||
|
||||
if o.ResourceEnabled(version.WithResource(resource.Resource)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) ResourceEnabled(resource schema.GroupVersionResource) bool {
|
||||
versionOverride, versionExists := o.GroupVersionResourceConfigs[resource.GroupVersion()]
|
||||
if !versionExists {
|
||||
return false
|
||||
}
|
||||
if !versionOverride.Enable {
|
||||
return false
|
||||
}
|
||||
|
||||
if versionOverride.DisabledResources.Has(resource.Resource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(versionOverride.EnabledResources) > 0 {
|
||||
return versionOverride.EnabledResources.Has(resource.Resource)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) AllResourcesForVersionEnabled(version schema.GroupVersion) bool {
|
||||
versionOverride, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
return false
|
||||
}
|
||||
if !versionOverride.Enable {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(versionOverride.EnabledResources) == 0 && len(versionOverride.DisabledResources) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) AnyResourcesForVersionEnabled(version schema.GroupVersion) bool {
|
||||
versionOverride, versionExists := o.GroupVersionResourceConfigs[version]
|
||||
if !versionExists {
|
||||
return false
|
||||
}
|
||||
|
||||
return versionOverride.Enable
|
||||
}
|
||||
|
||||
func (o *ResourceConfig) AnyResourcesForGroupEnabled(group string) bool {
|
||||
for version := range o.GroupVersionResourceConfigs {
|
||||
if version.Group == group {
|
||||
if o.AnyResourcesForVersionEnabled(version) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
160
vendor/k8s.io/apiserver/pkg/server/storage/resource_config_test.go
generated
vendored
160
vendor/k8s.io/apiserver/pkg/server/storage/resource_config_test.go
generated
vendored
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestDisabledVersion(t *testing.T) {
|
||||
g1v1 := schema.GroupVersion{Group: "group1", Version: "version1"}
|
||||
g1v2 := schema.GroupVersion{Group: "group1", Version: "version2"}
|
||||
g2v1 := schema.GroupVersion{Group: "group2", Version: "version1"}
|
||||
g3v1 := schema.GroupVersion{Group: "group3", Version: "version1"}
|
||||
|
||||
resourceType := "the-resource"
|
||||
disabledResourceType := "the-disabled-resource"
|
||||
|
||||
config := NewResourceConfig()
|
||||
|
||||
config.DisableVersions(g1v1)
|
||||
config.EnableVersions(g1v2, g3v1)
|
||||
config.EnableResources(g1v1.WithResource(resourceType), g2v1.WithResource(resourceType))
|
||||
config.DisableResources(g1v2.WithResource(disabledResourceType))
|
||||
|
||||
expectedEnabledResources := []schema.GroupVersionResource{
|
||||
g1v2.WithResource(resourceType),
|
||||
g2v1.WithResource(resourceType),
|
||||
}
|
||||
expectedDisabledResources := []schema.GroupVersionResource{
|
||||
g1v1.WithResource(resourceType), g1v1.WithResource(disabledResourceType),
|
||||
g1v2.WithResource(disabledResourceType),
|
||||
g2v1.WithResource(disabledResourceType),
|
||||
}
|
||||
|
||||
for _, expectedResource := range expectedEnabledResources {
|
||||
if !config.ResourceEnabled(expectedResource) {
|
||||
t.Errorf("expected enabled for %v, from %v", expectedResource, config)
|
||||
}
|
||||
}
|
||||
for _, expectedResource := range expectedDisabledResources {
|
||||
if config.ResourceEnabled(expectedResource) {
|
||||
t.Errorf("expected disabled for %v, from %v", expectedResource, config)
|
||||
}
|
||||
}
|
||||
|
||||
if e, a := false, config.AnyResourcesForVersionEnabled(g1v1); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := false, config.AllResourcesForVersionEnabled(g1v1); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := true, config.AnyResourcesForVersionEnabled(g1v2); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := false, config.AllResourcesForVersionEnabled(g1v2); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := true, config.AnyResourcesForVersionEnabled(g3v1); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := true, config.AllResourcesForVersionEnabled(g3v1); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
expectedEnabledAnyVersionResources := []schema.GroupResource{
|
||||
{Group: "group1", Resource: resourceType},
|
||||
}
|
||||
expectedDisabledAnyResources := []schema.GroupResource{
|
||||
{Group: "group1", Resource: disabledResourceType},
|
||||
}
|
||||
|
||||
for _, expectedResource := range expectedEnabledAnyVersionResources {
|
||||
if !config.AnyVersionOfResourceEnabled(expectedResource) {
|
||||
t.Errorf("expected enabled for %v, from %v", expectedResource, config)
|
||||
}
|
||||
}
|
||||
for _, expectedResource := range expectedDisabledAnyResources {
|
||||
if config.AnyVersionOfResourceEnabled(expectedResource) {
|
||||
t.Errorf("expected disabled for %v, from %v", expectedResource, config)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAnyResourcesForGroupEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
creator func() APIResourceConfigSource
|
||||
testGroup string
|
||||
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
creator: func() APIResourceConfigSource {
|
||||
return NewResourceConfig()
|
||||
},
|
||||
testGroup: "one",
|
||||
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "present, but disabled",
|
||||
creator: func() APIResourceConfigSource {
|
||||
ret := NewResourceConfig()
|
||||
ret.DisableVersions(schema.GroupVersion{Group: "one", Version: "version1"})
|
||||
return ret
|
||||
},
|
||||
testGroup: "one",
|
||||
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "present, and one version enabled",
|
||||
creator: func() APIResourceConfigSource {
|
||||
ret := NewResourceConfig()
|
||||
ret.DisableVersions(schema.GroupVersion{Group: "one", Version: "version1"})
|
||||
ret.EnableVersions(schema.GroupVersion{Group: "one", Version: "version2"})
|
||||
return ret
|
||||
},
|
||||
testGroup: "one",
|
||||
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "present, and one resource",
|
||||
creator: func() APIResourceConfigSource {
|
||||
ret := NewResourceConfig()
|
||||
ret.DisableVersions(schema.GroupVersion{Group: "one", Version: "version1"})
|
||||
ret.EnableResources(schema.GroupVersionResource{Group: "one", Version: "version2", Resource: "foo"})
|
||||
return ret
|
||||
},
|
||||
testGroup: "one",
|
||||
|
||||
expectedResult: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
if e, a := tc.expectedResult, tc.creator().AnyResourcesForGroupEnabled(tc.testGroup); e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
119
vendor/k8s.io/apiserver/pkg/server/storage/resource_encoding_config.go
generated
vendored
119
vendor/k8s.io/apiserver/pkg/server/storage/resource_encoding_config.go
generated
vendored
|
|
@ -1,119 +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.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type ResourceEncodingConfig interface {
|
||||
// StorageEncoding returns the serialization format for the resource.
|
||||
// TODO this should actually return a GroupVersionKind since you can logically have multiple "matching" Kinds
|
||||
// For now, it returns just the GroupVersion for consistency with old behavior
|
||||
StorageEncodingFor(schema.GroupResource) (schema.GroupVersion, error)
|
||||
|
||||
// InMemoryEncodingFor returns the groupVersion for the in memory representation the storage should convert to.
|
||||
InMemoryEncodingFor(schema.GroupResource) (schema.GroupVersion, error)
|
||||
}
|
||||
|
||||
type DefaultResourceEncodingConfig struct {
|
||||
groups map[string]*GroupResourceEncodingConfig
|
||||
registry *registered.APIRegistrationManager
|
||||
}
|
||||
|
||||
type GroupResourceEncodingConfig struct {
|
||||
DefaultExternalEncoding schema.GroupVersion
|
||||
ExternalResourceEncodings map[string]schema.GroupVersion
|
||||
|
||||
DefaultInternalEncoding schema.GroupVersion
|
||||
InternalResourceEncodings map[string]schema.GroupVersion
|
||||
}
|
||||
|
||||
var _ ResourceEncodingConfig = &DefaultResourceEncodingConfig{}
|
||||
|
||||
func NewDefaultResourceEncodingConfig(registry *registered.APIRegistrationManager) *DefaultResourceEncodingConfig {
|
||||
return &DefaultResourceEncodingConfig{groups: map[string]*GroupResourceEncodingConfig{}, registry: registry}
|
||||
}
|
||||
|
||||
func newGroupResourceEncodingConfig(defaultEncoding, defaultInternalVersion schema.GroupVersion) *GroupResourceEncodingConfig {
|
||||
return &GroupResourceEncodingConfig{
|
||||
DefaultExternalEncoding: defaultEncoding, ExternalResourceEncodings: map[string]schema.GroupVersion{},
|
||||
DefaultInternalEncoding: defaultInternalVersion, InternalResourceEncodings: map[string]schema.GroupVersion{},
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DefaultResourceEncodingConfig) SetVersionEncoding(group string, externalEncodingVersion, internalVersion schema.GroupVersion) {
|
||||
_, groupExists := o.groups[group]
|
||||
if !groupExists {
|
||||
o.groups[group] = newGroupResourceEncodingConfig(externalEncodingVersion, internalVersion)
|
||||
}
|
||||
|
||||
o.groups[group].DefaultExternalEncoding = externalEncodingVersion
|
||||
o.groups[group].DefaultInternalEncoding = internalVersion
|
||||
}
|
||||
|
||||
func (o *DefaultResourceEncodingConfig) SetResourceEncoding(resourceBeingStored schema.GroupResource, externalEncodingVersion, internalVersion schema.GroupVersion) {
|
||||
group := resourceBeingStored.Group
|
||||
_, groupExists := o.groups[group]
|
||||
if !groupExists {
|
||||
o.groups[group] = newGroupResourceEncodingConfig(externalEncodingVersion, internalVersion)
|
||||
}
|
||||
|
||||
o.groups[group].ExternalResourceEncodings[resourceBeingStored.Resource] = externalEncodingVersion
|
||||
o.groups[group].InternalResourceEncodings[resourceBeingStored.Resource] = internalVersion
|
||||
}
|
||||
|
||||
func (o *DefaultResourceEncodingConfig) StorageEncodingFor(resource schema.GroupResource) (schema.GroupVersion, error) {
|
||||
groupMeta, err := o.registry.Group(resource.Group)
|
||||
if err != nil {
|
||||
return schema.GroupVersion{}, err
|
||||
}
|
||||
|
||||
groupEncoding, groupExists := o.groups[resource.Group]
|
||||
|
||||
if !groupExists {
|
||||
// return the most preferred external version for the group
|
||||
return groupMeta.GroupVersion, nil
|
||||
}
|
||||
|
||||
resourceOverride, resourceExists := groupEncoding.ExternalResourceEncodings[resource.Resource]
|
||||
if !resourceExists {
|
||||
return groupEncoding.DefaultExternalEncoding, nil
|
||||
}
|
||||
|
||||
return resourceOverride, nil
|
||||
}
|
||||
|
||||
func (o *DefaultResourceEncodingConfig) InMemoryEncodingFor(resource schema.GroupResource) (schema.GroupVersion, error) {
|
||||
if _, err := o.registry.Group(resource.Group); err != nil {
|
||||
return schema.GroupVersion{}, err
|
||||
}
|
||||
|
||||
groupEncoding, groupExists := o.groups[resource.Group]
|
||||
if !groupExists {
|
||||
return schema.GroupVersion{Group: resource.Group, Version: runtime.APIVersionInternal}, nil
|
||||
}
|
||||
|
||||
resourceOverride, resourceExists := groupEncoding.InternalResourceEncodings[resource.Resource]
|
||||
if !resourceExists {
|
||||
return groupEncoding.DefaultInternalEncoding, nil
|
||||
}
|
||||
|
||||
return resourceOverride, nil
|
||||
}
|
||||
108
vendor/k8s.io/apiserver/pkg/server/storage/storage_codec.go
generated
vendored
108
vendor/k8s.io/apiserver/pkg/server/storage/storage_codec.go
generated
vendored
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// StorageCodecConfig are the arguments passed to newStorageCodecFn
|
||||
type StorageCodecConfig struct {
|
||||
StorageMediaType string
|
||||
StorageSerializer runtime.StorageSerializer
|
||||
StorageVersion schema.GroupVersion
|
||||
MemoryVersion schema.GroupVersion
|
||||
Config storagebackend.Config
|
||||
|
||||
EncoderDecoratorFn func(runtime.Encoder) runtime.Encoder
|
||||
DecoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder
|
||||
}
|
||||
|
||||
// NewStorageCodec assembles a storage codec for the provided storage media type, the provided serializer, and the requested
|
||||
// storage and memory versions.
|
||||
func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) {
|
||||
mediaType, _, err := mime.ParseMediaType(opts.StorageMediaType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType)
|
||||
}
|
||||
|
||||
if opts.Config.Type == storagebackend.StorageTypeETCD2 && mediaType != "application/json" {
|
||||
glog.Warningf(`storage type %q does not support media type %q, using "application/json"`, storagebackend.StorageTypeETCD2, mediaType)
|
||||
mediaType = "application/json"
|
||||
}
|
||||
|
||||
serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to find serializer for %q", mediaType)
|
||||
}
|
||||
|
||||
s := serializer.Serializer
|
||||
|
||||
// make sure the selected encoder supports string data
|
||||
if !serializer.EncodesAsText && opts.Config.Type == storagebackend.StorageTypeETCD2 {
|
||||
return nil, fmt.Errorf("storage type %q does not support binary media type %q", storagebackend.StorageTypeETCD2, mediaType)
|
||||
}
|
||||
|
||||
// Give callers the opportunity to wrap encoders and decoders. For decoders, each returned decoder will
|
||||
// be passed to the recognizer so that multiple decoders are available.
|
||||
var encoder runtime.Encoder = s
|
||||
if opts.EncoderDecoratorFn != nil {
|
||||
encoder = opts.EncoderDecoratorFn(encoder)
|
||||
}
|
||||
decoders := []runtime.Decoder{
|
||||
// selected decoder as the primary
|
||||
s,
|
||||
// universal deserializer as a fallback
|
||||
opts.StorageSerializer.UniversalDeserializer(),
|
||||
// base64-wrapped universal deserializer as a last resort.
|
||||
// this allows reading base64-encoded protobuf, which should only exist if etcd2+protobuf was used at some point.
|
||||
// data written that way could exist in etcd2, or could have been migrated to etcd3.
|
||||
// TODO: flag this type of data if we encounter it, require migration (read to decode, write to persist using a supported encoder), and remove in 1.8
|
||||
runtime.NewBase64Serializer(nil, opts.StorageSerializer.UniversalDeserializer()),
|
||||
}
|
||||
if opts.DecoderDecoratorFn != nil {
|
||||
decoders = opts.DecoderDecoratorFn(decoders)
|
||||
}
|
||||
|
||||
// Ensure the storage receives the correct version.
|
||||
encoder = opts.StorageSerializer.EncoderForVersion(
|
||||
encoder,
|
||||
runtime.NewMultiGroupVersioner(
|
||||
opts.StorageVersion,
|
||||
schema.GroupKind{Group: opts.StorageVersion.Group},
|
||||
schema.GroupKind{Group: opts.MemoryVersion.Group},
|
||||
),
|
||||
)
|
||||
decoder := opts.StorageSerializer.DecoderToVersion(
|
||||
recognizer.NewDecoder(decoders...),
|
||||
runtime.NewMultiGroupVersioner(
|
||||
opts.MemoryVersion,
|
||||
schema.GroupKind{Group: opts.MemoryVersion.Group},
|
||||
schema.GroupKind{Group: opts.StorageVersion.Group},
|
||||
),
|
||||
)
|
||||
|
||||
return runtime.NewCodec(encoder, decoder), nil
|
||||
}
|
||||
353
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
generated
vendored
353
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
generated
vendored
|
|
@ -1,353 +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.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
|
||||
// Backend describes the storage servers, the information here should be enough
|
||||
// for health validations.
|
||||
type Backend struct {
|
||||
// the url of storage backend like: https://etcd.domain:2379
|
||||
Server string
|
||||
// the required tls config
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
// StorageFactory is the interface to locate the storage for a given GroupResource
|
||||
type StorageFactory interface {
|
||||
// New finds the storage destination for the given group and resource. It will
|
||||
// return an error if the group has no storage destination configured.
|
||||
NewConfig(groupResource schema.GroupResource) (*storagebackend.Config, error)
|
||||
|
||||
// ResourcePrefix returns the overridden resource prefix for the GroupResource
|
||||
// This allows for cohabitation of resources with different native types and provides
|
||||
// centralized control over the shape of etcd directories
|
||||
ResourcePrefix(groupResource schema.GroupResource) string
|
||||
|
||||
// Backends gets all backends for all registered storage destinations.
|
||||
// Used for getting all instances for health validations.
|
||||
Backends() []Backend
|
||||
}
|
||||
|
||||
// DefaultStorageFactory takes a GroupResource and returns back its storage interface. This result includes:
|
||||
// 1. Merged etcd config, including: auth, server locations, prefixes
|
||||
// 2. Resource encodings for storage: group,version,kind to store as
|
||||
// 3. Cohabitating default: some resources like hpa are exposed through multiple APIs. They must agree on 1 and 2
|
||||
type DefaultStorageFactory struct {
|
||||
// StorageConfig describes how to create a storage backend in general.
|
||||
// Its authentication information will be used for every storage.Interface returned.
|
||||
StorageConfig storagebackend.Config
|
||||
|
||||
Overrides map[schema.GroupResource]groupResourceOverrides
|
||||
|
||||
DefaultResourcePrefixes map[schema.GroupResource]string
|
||||
|
||||
// DefaultMediaType is the media type used to store resources. If it is not set, "application/json" is used.
|
||||
DefaultMediaType string
|
||||
|
||||
// DefaultSerializer is used to create encoders and decoders for the storage.Interface.
|
||||
DefaultSerializer runtime.StorageSerializer
|
||||
|
||||
// ResourceEncodingConfig describes how to encode a particular GroupVersionResource
|
||||
ResourceEncodingConfig ResourceEncodingConfig
|
||||
|
||||
// APIResourceConfigSource indicates whether the *storage* is enabled, NOT the API
|
||||
// This is discrete from resource enablement because those are separate concerns. How this source is configured
|
||||
// is left to the caller.
|
||||
APIResourceConfigSource APIResourceConfigSource
|
||||
|
||||
// newStorageCodecFn exists to be overwritten for unit testing.
|
||||
newStorageCodecFn func(opts StorageCodecConfig) (codec runtime.Codec, err error)
|
||||
}
|
||||
|
||||
type groupResourceOverrides struct {
|
||||
// etcdLocation contains the list of "special" locations that are used for particular GroupResources
|
||||
// These are merged on top of the StorageConfig when requesting the storage.Interface for a given GroupResource
|
||||
etcdLocation []string
|
||||
// etcdPrefix is the base location for a GroupResource.
|
||||
etcdPrefix string
|
||||
// etcdResourcePrefix is the location to use to store a particular type under the `etcdPrefix` location
|
||||
// If empty, the default mapping is used. If the default mapping doesn't contain an entry, it will use
|
||||
// the ToLowered name of the resource, not including the group.
|
||||
etcdResourcePrefix string
|
||||
// mediaType is the desired serializer to choose. If empty, the default is chosen.
|
||||
mediaType string
|
||||
// serializer contains the list of "special" serializers for a GroupResource. Resource=* means for the entire group
|
||||
serializer runtime.StorageSerializer
|
||||
// cohabitatingResources keeps track of which resources must be stored together. This happens when we have multiple ways
|
||||
// of exposing one set of concepts. autoscaling.HPA and extensions.HPA as a for instance
|
||||
// The order of the slice matters! It is the priority order of lookup for finding a storage location
|
||||
cohabitatingResources []schema.GroupResource
|
||||
// encoderDecoratorFn is optional and may wrap the provided encoder prior to being serialized.
|
||||
encoderDecoratorFn func(runtime.Encoder) runtime.Encoder
|
||||
// decoderDecoratorFn is optional and may wrap the provided decoders (can add new decoders). The order of
|
||||
// returned decoders will be priority for attempt to decode.
|
||||
decoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder
|
||||
// transformer is optional and shall encrypt that resource at rest.
|
||||
transformer value.Transformer
|
||||
// disablePaging will prevent paging on the provided resource.
|
||||
disablePaging bool
|
||||
}
|
||||
|
||||
// Apply overrides the provided config and options if the override has a value in that position
|
||||
func (o groupResourceOverrides) Apply(config *storagebackend.Config, options *StorageCodecConfig) {
|
||||
if len(o.etcdLocation) > 0 {
|
||||
config.ServerList = o.etcdLocation
|
||||
}
|
||||
if len(o.etcdPrefix) > 0 {
|
||||
config.Prefix = o.etcdPrefix
|
||||
}
|
||||
|
||||
if len(o.mediaType) > 0 {
|
||||
options.StorageMediaType = o.mediaType
|
||||
}
|
||||
if o.serializer != nil {
|
||||
options.StorageSerializer = o.serializer
|
||||
}
|
||||
if o.encoderDecoratorFn != nil {
|
||||
options.EncoderDecoratorFn = o.encoderDecoratorFn
|
||||
}
|
||||
if o.decoderDecoratorFn != nil {
|
||||
options.DecoderDecoratorFn = o.decoderDecoratorFn
|
||||
}
|
||||
if o.transformer != nil {
|
||||
config.Transformer = o.transformer
|
||||
}
|
||||
if o.disablePaging {
|
||||
config.Paging = false
|
||||
}
|
||||
}
|
||||
|
||||
var _ StorageFactory = &DefaultStorageFactory{}
|
||||
|
||||
const AllResources = "*"
|
||||
|
||||
// specialDefaultResourcePrefixes are prefixes compiled into Kubernetes.
|
||||
// TODO: move out of this package, it is not generic
|
||||
var specialDefaultResourcePrefixes = map[schema.GroupResource]string{
|
||||
{Group: "", Resource: "replicationControllers"}: "controllers",
|
||||
{Group: "", Resource: "replicationcontrollers"}: "controllers",
|
||||
{Group: "", Resource: "endpoints"}: "services/endpoints",
|
||||
{Group: "", Resource: "nodes"}: "minions",
|
||||
{Group: "", Resource: "services"}: "services/specs",
|
||||
{Group: "extensions", Resource: "ingresses"}: "ingress",
|
||||
{Group: "extensions", Resource: "podsecuritypolicies"}: "podsecuritypolicy",
|
||||
}
|
||||
|
||||
func NewDefaultStorageFactory(config storagebackend.Config, defaultMediaType string, defaultSerializer runtime.StorageSerializer, resourceEncodingConfig ResourceEncodingConfig, resourceConfig APIResourceConfigSource) *DefaultStorageFactory {
|
||||
config.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking)
|
||||
if len(defaultMediaType) == 0 {
|
||||
defaultMediaType = runtime.ContentTypeJSON
|
||||
}
|
||||
return &DefaultStorageFactory{
|
||||
StorageConfig: config,
|
||||
Overrides: map[schema.GroupResource]groupResourceOverrides{},
|
||||
DefaultMediaType: defaultMediaType,
|
||||
DefaultSerializer: defaultSerializer,
|
||||
ResourceEncodingConfig: resourceEncodingConfig,
|
||||
APIResourceConfigSource: resourceConfig,
|
||||
DefaultResourcePrefixes: specialDefaultResourcePrefixes,
|
||||
|
||||
newStorageCodecFn: NewStorageCodec,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) SetEtcdLocation(groupResource schema.GroupResource, location []string) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.etcdLocation = location
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) SetEtcdPrefix(groupResource schema.GroupResource, prefix string) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.etcdPrefix = prefix
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
// SetDisableAPIListChunking allows a specific resource to disable paging at the storage layer, to prevent
|
||||
// exposure of key names in continuations. This may be overriden by feature gates.
|
||||
func (s *DefaultStorageFactory) SetDisableAPIListChunking(groupResource schema.GroupResource) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.disablePaging = true
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
// SetResourceEtcdPrefix sets the prefix for a resource, but not the base-dir. You'll end up in `etcdPrefix/resourceEtcdPrefix`.
|
||||
func (s *DefaultStorageFactory) SetResourceEtcdPrefix(groupResource schema.GroupResource, prefix string) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.etcdResourcePrefix = prefix
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) SetSerializer(groupResource schema.GroupResource, mediaType string, serializer runtime.StorageSerializer) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.mediaType = mediaType
|
||||
overrides.serializer = serializer
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) SetTransformer(groupResource schema.GroupResource, transformer value.Transformer) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.transformer = transformer
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
// AddCohabitatingResources links resources together the order of the slice matters! its the priority order of lookup for finding a storage location
|
||||
func (s *DefaultStorageFactory) AddCohabitatingResources(groupResources ...schema.GroupResource) {
|
||||
for _, groupResource := range groupResources {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.cohabitatingResources = groupResources
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) AddSerializationChains(encoderDecoratorFn func(runtime.Encoder) runtime.Encoder, decoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder, groupResources ...schema.GroupResource) {
|
||||
for _, groupResource := range groupResources {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.encoderDecoratorFn = encoderDecoratorFn
|
||||
overrides.decoderDecoratorFn = decoderDecoratorFn
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
}
|
||||
|
||||
func getAllResourcesAlias(resource schema.GroupResource) schema.GroupResource {
|
||||
return schema.GroupResource{Group: resource.Group, Resource: AllResources}
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) getStorageGroupResource(groupResource schema.GroupResource) schema.GroupResource {
|
||||
for _, potentialStorageResource := range s.Overrides[groupResource].cohabitatingResources {
|
||||
if s.APIResourceConfigSource.AnyVersionOfResourceEnabled(potentialStorageResource) {
|
||||
return potentialStorageResource
|
||||
}
|
||||
}
|
||||
|
||||
return groupResource
|
||||
}
|
||||
|
||||
// New finds the storage destination for the given group and resource. It will
|
||||
// return an error if the group has no storage destination configured.
|
||||
func (s *DefaultStorageFactory) NewConfig(groupResource schema.GroupResource) (*storagebackend.Config, error) {
|
||||
chosenStorageResource := s.getStorageGroupResource(groupResource)
|
||||
|
||||
// operate on copy
|
||||
storageConfig := s.StorageConfig
|
||||
codecConfig := StorageCodecConfig{
|
||||
StorageMediaType: s.DefaultMediaType,
|
||||
StorageSerializer: s.DefaultSerializer,
|
||||
}
|
||||
|
||||
if override, ok := s.Overrides[getAllResourcesAlias(chosenStorageResource)]; ok {
|
||||
override.Apply(&storageConfig, &codecConfig)
|
||||
}
|
||||
if override, ok := s.Overrides[chosenStorageResource]; ok {
|
||||
override.Apply(&storageConfig, &codecConfig)
|
||||
}
|
||||
|
||||
var err error
|
||||
codecConfig.StorageVersion, err = s.ResourceEncodingConfig.StorageEncodingFor(chosenStorageResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
codecConfig.MemoryVersion, err = s.ResourceEncodingConfig.InMemoryEncodingFor(groupResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
codecConfig.Config = storageConfig
|
||||
|
||||
storageConfig.Codec, err = s.newStorageCodecFn(codecConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.V(3).Infof("storing %v in %v, reading as %v from %#v", groupResource, codecConfig.StorageVersion, codecConfig.MemoryVersion, codecConfig.Config)
|
||||
|
||||
return &storageConfig, nil
|
||||
}
|
||||
|
||||
// Backends returns all backends for all registered storage destinations.
|
||||
// Used for getting all instances for health validations.
|
||||
func (s *DefaultStorageFactory) Backends() []Backend {
|
||||
servers := sets.NewString(s.StorageConfig.ServerList...)
|
||||
|
||||
for _, overrides := range s.Overrides {
|
||||
servers.Insert(overrides.etcdLocation...)
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
if len(s.StorageConfig.CertFile) > 0 && len(s.StorageConfig.KeyFile) > 0 {
|
||||
cert, err := tls.LoadX509KeyPair(s.StorageConfig.CertFile, s.StorageConfig.KeyFile)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to load key pair while getting backends: %s", err)
|
||||
} else {
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
}
|
||||
if len(s.StorageConfig.CAFile) > 0 {
|
||||
if caCert, err := ioutil.ReadFile(s.StorageConfig.CAFile); err != nil {
|
||||
glog.Errorf("failed to read ca file while getting backends: %s", err)
|
||||
} else {
|
||||
caPool := x509.NewCertPool()
|
||||
caPool.AppendCertsFromPEM(caCert)
|
||||
tlsConfig.RootCAs = caPool
|
||||
tlsConfig.InsecureSkipVerify = false
|
||||
}
|
||||
}
|
||||
|
||||
backends := []Backend{}
|
||||
for server := range servers {
|
||||
backends = append(backends, Backend{
|
||||
Server: server,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
}
|
||||
return backends
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) ResourcePrefix(groupResource schema.GroupResource) string {
|
||||
chosenStorageResource := s.getStorageGroupResource(groupResource)
|
||||
groupOverride := s.Overrides[getAllResourcesAlias(chosenStorageResource)]
|
||||
exactResourceOverride := s.Overrides[chosenStorageResource]
|
||||
|
||||
etcdResourcePrefix := s.DefaultResourcePrefixes[chosenStorageResource]
|
||||
if len(groupOverride.etcdResourcePrefix) > 0 {
|
||||
etcdResourcePrefix = groupOverride.etcdResourcePrefix
|
||||
}
|
||||
if len(exactResourceOverride.etcdResourcePrefix) > 0 {
|
||||
etcdResourcePrefix = exactResourceOverride.etcdResourcePrefix
|
||||
}
|
||||
if len(etcdResourcePrefix) == 0 {
|
||||
etcdResourcePrefix = strings.ToLower(chosenStorageResource.Resource)
|
||||
}
|
||||
|
||||
return etcdResourcePrefix
|
||||
}
|
||||
175
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory_test.go
generated
vendored
175
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory_test.go
generated
vendored
|
|
@ -1,175 +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.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/apis/example"
|
||||
exampleinstall "k8s.io/apiserver/pkg/apis/example/install"
|
||||
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
)
|
||||
|
||||
var (
|
||||
v1GroupVersion = schema.GroupVersion{Group: "", Version: "v1"}
|
||||
|
||||
registry = registered.NewOrDie(os.Getenv("KUBE_API_VERSIONS"))
|
||||
announce = make(announced.APIGroupFactoryRegistry)
|
||||
scheme = runtime.NewScheme()
|
||||
codecs = serializer.NewCodecFactory(scheme)
|
||||
parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
)
|
||||
|
||||
func init() {
|
||||
metav1.AddToGroupVersion(scheme, metav1.SchemeGroupVersion)
|
||||
scheme.AddUnversionedTypes(v1GroupVersion,
|
||||
&metav1.Status{},
|
||||
&metav1.APIVersions{},
|
||||
&metav1.APIGroupList{},
|
||||
&metav1.APIGroup{},
|
||||
&metav1.APIResourceList{},
|
||||
)
|
||||
|
||||
exampleinstall.Install(announce, registry, scheme)
|
||||
}
|
||||
|
||||
type fakeNegotiater struct {
|
||||
serializer, streamSerializer runtime.Serializer
|
||||
framer runtime.Framer
|
||||
types, streamTypes []string
|
||||
}
|
||||
|
||||
func (n *fakeNegotiater) SupportedMediaTypes() []runtime.SerializerInfo {
|
||||
var out []runtime.SerializerInfo
|
||||
for _, s := range n.types {
|
||||
info := runtime.SerializerInfo{Serializer: n.serializer, MediaType: s, EncodesAsText: true}
|
||||
for _, t := range n.streamTypes {
|
||||
if t == s {
|
||||
info.StreamSerializer = &runtime.StreamSerializerInfo{
|
||||
EncodesAsText: true,
|
||||
Framer: n.framer,
|
||||
Serializer: n.streamSerializer,
|
||||
}
|
||||
}
|
||||
}
|
||||
out = append(out, info)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (n *fakeNegotiater) UniversalDeserializer() runtime.Decoder {
|
||||
return n.serializer
|
||||
}
|
||||
|
||||
func (n *fakeNegotiater) EncoderForVersion(serializer runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
|
||||
return n.serializer
|
||||
}
|
||||
|
||||
func (n *fakeNegotiater) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||
return n.serializer
|
||||
}
|
||||
|
||||
func TestConfigurableStorageFactory(t *testing.T) {
|
||||
ns := &fakeNegotiater{types: []string{"test/test"}}
|
||||
f := NewDefaultStorageFactory(storagebackend.Config{}, "test/test", ns, NewDefaultResourceEncodingConfig(registry), NewResourceConfig())
|
||||
f.AddCohabitatingResources(example.Resource("test"), schema.GroupResource{Resource: "test2", Group: "2"})
|
||||
called := false
|
||||
testEncoderChain := func(e runtime.Encoder) runtime.Encoder {
|
||||
called = true
|
||||
return e
|
||||
}
|
||||
f.AddSerializationChains(testEncoderChain, nil, example.Resource("test"))
|
||||
f.SetEtcdLocation(example.Resource("*"), []string{"/server2"})
|
||||
f.SetEtcdPrefix(example.Resource("test"), "/prefix_for_test")
|
||||
|
||||
config, err := f.NewConfig(example.Resource("test"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if config.Prefix != "/prefix_for_test" || !reflect.DeepEqual(config.ServerList, []string{"/server2"}) {
|
||||
t.Errorf("unexpected config %#v", config)
|
||||
}
|
||||
if !called {
|
||||
t.Errorf("expected encoder chain to be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateEtcdOverrides(t *testing.T) {
|
||||
registry := registered.NewOrDie(os.Getenv("KUBE_API_VERSIONS"))
|
||||
announced := make(announced.APIGroupFactoryRegistry)
|
||||
exampleinstall.Install(announced, registry, scheme)
|
||||
|
||||
testCases := []struct {
|
||||
resource schema.GroupResource
|
||||
servers []string
|
||||
}{
|
||||
{
|
||||
resource: schema.GroupResource{Group: example.GroupName, Resource: "resource"},
|
||||
servers: []string{"http://127.0.0.1:10000"},
|
||||
},
|
||||
{
|
||||
resource: schema.GroupResource{Group: example.GroupName, Resource: "resource"},
|
||||
servers: []string{"http://127.0.0.1:10000", "http://127.0.0.1:20000"},
|
||||
},
|
||||
{
|
||||
resource: schema.GroupResource{Group: example.GroupName, Resource: "resource"},
|
||||
servers: []string{"http://127.0.0.1:10000"},
|
||||
},
|
||||
}
|
||||
|
||||
defaultEtcdLocation := []string{"http://127.0.0.1"}
|
||||
for i, test := range testCases {
|
||||
defaultConfig := storagebackend.Config{
|
||||
Prefix: "/registry",
|
||||
ServerList: defaultEtcdLocation,
|
||||
Copier: scheme,
|
||||
}
|
||||
storageFactory := NewDefaultStorageFactory(defaultConfig, "", codecs, NewDefaultResourceEncodingConfig(registry), NewResourceConfig())
|
||||
storageFactory.SetEtcdLocation(test.resource, test.servers)
|
||||
|
||||
var err error
|
||||
config, err := storageFactory.NewConfig(test.resource)
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(config.ServerList, test.servers) {
|
||||
t.Errorf("%d: expected %v, got %v", i, test.servers, config.ServerList)
|
||||
continue
|
||||
}
|
||||
|
||||
config, err = storageFactory.NewConfig(schema.GroupResource{Group: examplev1.GroupName, Resource: "unlikely"})
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(config.ServerList, defaultEtcdLocation) {
|
||||
t.Errorf("%d: expected %v, got %v", i, defaultEtcdLocation, config.ServerList)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue