vendor: remove dep and use vndr
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
16f44674a4
commit
148e72d81e
16131 changed files with 73815 additions and 4235138 deletions
18
vendor/k8s.io/apiserver/pkg/server/doc.go
generated
vendored
18
vendor/k8s.io/apiserver/pkg/server/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 server contains the plumbing to create kubernetes-like API server command.
|
||||
package server
|
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
|
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"
|
40
vendor/k8s.io/apiserver/pkg/server/filters/longrunning.go
generated
vendored
40
vendor/k8s.io/apiserver/pkg/server/filters/longrunning.go
generated
vendored
|
@ -1,40 +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"
|
||||
)
|
||||
|
||||
// LongRunningRequestCheck is a predicate which is true for long-running http requests.
|
||||
type LongRunningRequestCheck func(r *http.Request, requestInfo *apirequest.RequestInfo) bool
|
||||
|
||||
// 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) 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
|
||||
}
|
||||
}
|
111
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
111
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
|
@ -1,111 +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"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
|
||||
"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 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:
|
||||
tooManyRequests(r, w)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func tooManyRequests(req *http.Request, w http.ResponseWriter) {
|
||||
// "Too Many Requests" response is returned before logger is setup for the request.
|
||||
// So we need to explicitly log it here.
|
||||
defer httplog.NewLogged(req, &w).Log()
|
||||
|
||||
// Return a 429 status indicating "Too Many Requests"
|
||||
w.Header().Set("Retry-After", retryAfter)
|
||||
http.Error(w, "Too many requests, please try again later.", errors.StatusTooManyRequests)
|
||||
}
|
240
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight_test.go
generated
vendored
240
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight_test.go
generated
vendored
|
@ -1,240 +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/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
apifilters "k8s.io/kubernetes/pkg/genericapiserver/endpoints/filters"
|
||||
)
|
||||
|
||||
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 = apifilters.WithRequestInfo(handler, requestInfoFactory, requestContextMapper)
|
||||
handler = apirequest.WithRequestContext(handler, requestContextMapper)
|
||||
|
||||
return httptest.NewServer(handler)
|
||||
}
|
||||
|
||||
// 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, errors.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/", errors.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) error {
|
||||
r, err := http.Post(url, "text/html", strings.NewReader("foo bar"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if r.StatusCode != code {
|
||||
return fmt.Errorf("unexpected response: %v", r.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
271
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
271
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
|
@ -1,271 +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"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
const globalTimeout = time.Minute
|
||||
|
||||
var errConnKilled = fmt.Errorf("kill connection/stream")
|
||||
|
||||
// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by globalTimeout.
|
||||
func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, longRunning LongRunningRequestCheck) http.Handler {
|
||||
if longRunning == nil {
|
||||
return handler
|
||||
}
|
||||
timeoutFunc := func(req *http.Request) (<-chan time.Time, *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(globalTimeout), 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(globalTimeout), apierrors.NewInternalError(fmt.Errorf("no request info found for request during timeout"))
|
||||
}
|
||||
|
||||
if longRunning(req, requestInfo) {
|
||||
return nil, nil
|
||||
}
|
||||
return time.After(globalTimeout), apierrors.NewServerTimeout(schema.GroupResource{Group: requestInfo.APIGroup, Resource: requestInfo.Resource}, requestInfo.Verb, 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 503 Service Unavailable 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.
|
||||
func WithTimeout(h http.Handler, timeoutFunc func(*http.Request) (timeout <-chan time.Time, err *apierrors.StatusError)) http.Handler {
|
||||
return &timeoutHandler{h, timeoutFunc}
|
||||
}
|
||||
|
||||
type timeoutHandler struct {
|
||||
handler http.Handler
|
||||
timeout func(*http.Request) (<-chan time.Time, *apierrors.StatusError)
|
||||
}
|
||||
|
||||
func (t *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
after, 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:
|
||||
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)
|
||||
} 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()
|
||||
}
|
85
vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go
generated
vendored
85
vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go
generated
vendored
|
@ -1,85 +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 (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
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, *apierrors.StatusError) {
|
||||
return timeout, timeoutErr
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
// No timeouts
|
||||
sendResponse <- struct{}{}
|
||||
res, err := http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(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)
|
||||
}
|
||||
|
||||
// Times out
|
||||
timeout <- time.Time{}
|
||||
res, err = http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if res.StatusCode != http.StatusGatewayTimeout {
|
||||
t.Errorf("got res.StatusCode %d; expected %d", res.StatusCode, http.StatusServiceUnavailable)
|
||||
}
|
||||
body, _ = ioutil.ReadAll(res.Body)
|
||||
if !strings.Contains(string(body), timeoutErr.Error()) {
|
||||
t.Errorf("got body %q; expected it to contain %q", string(body), timeoutErr.Error())
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
76
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
76
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
|
@ -1,76 +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"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
)
|
||||
|
||||
// WithPanicRecovery wraps an http Handler to recover and log panics.
|
||||
func WithPanicRecovery(handler http.Handler, requestContextMapper apirequest.RequestContextMapper) 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)
|
||||
|
||||
var requestInfo *apirequest.RequestInfo
|
||||
ctx, ok := requestContextMapper.Get(req)
|
||||
if !ok {
|
||||
glog.Errorf("no context found for request, handler chain must be wrong")
|
||||
} else {
|
||||
requestInfo, ok = apirequest.RequestInfoFrom(ctx)
|
||||
if !ok {
|
||||
glog.Errorf("no RequestInfo found in context, handler chain must be wrong")
|
||||
}
|
||||
}
|
||||
|
||||
if !ok || requestInfo.Verb != "proxy" {
|
||||
logger.StacktraceWhen(
|
||||
httplog.StatusIsNot(
|
||||
http.StatusOK,
|
||||
http.StatusCreated,
|
||||
http.StatusAccepted,
|
||||
http.StatusBadRequest,
|
||||
http.StatusMovedPermanently,
|
||||
http.StatusTemporaryRedirect,
|
||||
http.StatusConflict,
|
||||
http.StatusNotFound,
|
||||
http.StatusUnauthorized,
|
||||
http.StatusForbidden,
|
||||
http.StatusNotModified,
|
||||
apierrors.StatusUnprocessableEntity,
|
||||
http.StatusSwitchingProtocols,
|
||||
),
|
||||
)
|
||||
}
|
||||
defer logger.Log()
|
||||
|
||||
// Dispatch to the internal handler
|
||||
handler.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
21
vendor/k8s.io/apiserver/pkg/server/healthz/doc.go
generated
vendored
21
vendor/k8s.io/apiserver/pkg/server/healthz/doc.go
generated
vendored
|
@ -1,21 +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 healthz implements basic http server health checking.
|
||||
// Usage:
|
||||
// import "k8s.io/apiserver/pkg/server/healthz"
|
||||
// healthz.DefaultHealthz()
|
||||
package healthz // import "k8s.io/apiserver/pkg/server/healthz"
|
133
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
133
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
|
@ -1,133 +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 healthz
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// HealthzChecker is a named healthz checker.
|
||||
type HealthzChecker interface {
|
||||
Name() string
|
||||
Check(req *http.Request) error
|
||||
}
|
||||
|
||||
var defaultHealthz = sync.Once{}
|
||||
|
||||
// DefaultHealthz installs the default healthz check to the http.DefaultServeMux.
|
||||
func DefaultHealthz(checks ...HealthzChecker) {
|
||||
defaultHealthz.Do(func() {
|
||||
InstallHandler(http.DefaultServeMux, checks...)
|
||||
})
|
||||
}
|
||||
|
||||
// PingHealthz returns true automatically when checked
|
||||
var PingHealthz HealthzChecker = ping{}
|
||||
|
||||
// ping implements the simplest possible healthz checker.
|
||||
type ping struct{}
|
||||
|
||||
func (ping) Name() string {
|
||||
return "ping"
|
||||
}
|
||||
|
||||
// PingHealthz is a health check that returns true.
|
||||
func (ping) Check(_ *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedCheck returns a healthz checker for the given name and function.
|
||||
func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker {
|
||||
return &healthzCheck{name, check}
|
||||
}
|
||||
|
||||
// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
|
||||
func InstallHandler(mux mux, checks ...HealthzChecker) {
|
||||
if len(checks) == 0 {
|
||||
checks = []HealthzChecker{PingHealthz}
|
||||
}
|
||||
mux.Handle("/healthz", handleRootHealthz(checks...))
|
||||
for _, check := range checks {
|
||||
mux.Handle(fmt.Sprintf("/healthz/%v", check.Name()), adaptCheckToHandler(check.Check))
|
||||
}
|
||||
}
|
||||
|
||||
// mux is an interface describing the methods InstallHandler requires.
|
||||
type mux interface {
|
||||
Handle(pattern string, handler http.Handler)
|
||||
}
|
||||
|
||||
// healthzCheck implements HealthzChecker on an arbitrary name and check function.
|
||||
type healthzCheck struct {
|
||||
name string
|
||||
check func(r *http.Request) error
|
||||
}
|
||||
|
||||
var _ HealthzChecker = &healthzCheck{}
|
||||
|
||||
func (c *healthzCheck) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c *healthzCheck) Check(r *http.Request) error {
|
||||
return c.check(r)
|
||||
}
|
||||
|
||||
// handleRootHealthz returns an http.HandlerFunc that serves the provided checks.
|
||||
func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
failed := false
|
||||
var verboseOut bytes.Buffer
|
||||
for _, check := range checks {
|
||||
err := check.Check(r)
|
||||
if err != nil {
|
||||
fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.Name(), err)
|
||||
failed = true
|
||||
} else {
|
||||
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
|
||||
}
|
||||
}
|
||||
// always be verbose on failure
|
||||
if failed {
|
||||
http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, found := r.URL.Query()["verbose"]; !found {
|
||||
fmt.Fprint(w, "ok")
|
||||
return
|
||||
}
|
||||
|
||||
verboseOut.WriteTo(w)
|
||||
fmt.Fprint(w, "healthz check passed\n")
|
||||
})
|
||||
}
|
||||
|
||||
// adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks.
|
||||
func adaptCheckToHandler(c func(r *http.Request) error) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
err := c(r)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("internal server error: %v", err), http.StatusInternalServerError)
|
||||
} else {
|
||||
fmt.Fprint(w, "ok")
|
||||
}
|
||||
})
|
||||
}
|
82
vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go
generated
vendored
82
vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go
generated
vendored
|
@ -1,82 +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 healthz
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInstallHandler(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
InstallHandler(mux)
|
||||
req, err := http.NewRequest("GET", "http://example.com/healthz", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected %v, got %v", http.StatusOK, w.Code)
|
||||
}
|
||||
if w.Body.String() != "ok" {
|
||||
t.Errorf("expected %v, got %v", "ok", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulitipleChecks(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
expectedResponse string
|
||||
expectedStatus int
|
||||
addBadCheck bool
|
||||
}{
|
||||
{"/healthz?verbose", "[+]ping ok\nhealthz check passed\n", http.StatusOK, false},
|
||||
{"/healthz/ping", "ok", http.StatusOK, false},
|
||||
{"/healthz", "ok", http.StatusOK, false},
|
||||
{"/healthz?verbose", "[+]ping ok\n[-]bad failed: this will fail\nhealthz check failed\n", http.StatusInternalServerError, true},
|
||||
{"/healthz/ping", "ok", http.StatusOK, true},
|
||||
{"/healthz/bad", "internal server error: this will fail\n", http.StatusInternalServerError, true},
|
||||
{"/healthz", "[+]ping ok\n[-]bad failed: this will fail\nhealthz check failed\n", http.StatusInternalServerError, true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
mux := http.NewServeMux()
|
||||
checks := []HealthzChecker{PingHealthz}
|
||||
if test.addBadCheck {
|
||||
checks = append(checks, NamedCheck("bad", func(_ *http.Request) error {
|
||||
return errors.New("this will fail")
|
||||
}))
|
||||
}
|
||||
InstallHandler(mux, checks...)
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com%v", test.path), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("case[%d] Unexpected error: %v", i, err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != test.expectedStatus {
|
||||
t.Errorf("case[%d] Expected: %v, got: %v", i, test.expectedStatus, w.Code)
|
||||
}
|
||||
if w.Body.String() != test.expectedResponse {
|
||||
t.Errorf("case[%d] Expected:\n%v\ngot:\n%v\n", i, test.expectedResponse, w.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
175
vendor/k8s.io/apiserver/pkg/server/httplog/log_test.go
generated
vendored
175
vendor/k8s.io/apiserver/pkg/server/httplog/log_test.go
generated
vendored
|
@ -1,175 +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 (
|
||||
"bytes"
|
||||
"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 TestHandler(t *testing.T) {
|
||||
want := &httptest.ResponseRecorder{
|
||||
HeaderMap: make(http.Header),
|
||||
Body: new(bytes.Buffer),
|
||||
}
|
||||
want.WriteHeader(http.StatusOK)
|
||||
mux := http.NewServeMux()
|
||||
handler := Handler(mux, DefaultStacktracePred)
|
||||
mux.HandleFunc("/kube", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
req, err := http.NewRequest("GET", "http://example.com/kube", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, req)
|
||||
if !reflect.DeepEqual(want, w) {
|
||||
t.Errorf("Expected %v, got %v", want, w)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
14
vendor/k8s.io/apiserver/pkg/server/options/OWNERS
generated
vendored
14
vendor/k8s.io/apiserver/pkg/server/options/OWNERS
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
reviewers:
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- sttts
|
||||
- jlowdermilk
|
||||
- soltysh
|
||||
- dims
|
||||
- cjcullen
|
||||
- ericchiang
|
||||
- ping035627
|
||||
- xiangpengzhao
|
175
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
175
vendor/k8s.io/apiserver/pkg/server/options/authentication.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 options
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
||||
authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
|
||||
"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) {
|
||||
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.UsernameHeaders) == 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig() (authenticatorfactory.DelegatingAuthenticatorConfig, error) {
|
||||
tokenClient, err := s.newTokenAccessReview()
|
||||
if err != nil {
|
||||
return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
|
||||
}
|
||||
|
||||
ret := authenticatorfactory.DelegatingAuthenticatorConfig{
|
||||
Anonymous: true,
|
||||
TokenAccessReviewClient: tokenClient,
|
||||
CacheTTL: s.CacheTTL,
|
||||
ClientCAFile: s.ClientCert.ClientCA,
|
||||
RequestHeaderConfig: s.RequestHeader.ToAuthenticationRequestHeaderConfig(),
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authenticationclient.TokenReviewInterface, 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 := authenticationclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client.TokenReviews(), nil
|
||||
}
|
114
vendor/k8s.io/apiserver/pkg/server/options/authorization.go
generated
vendored
114
vendor/k8s.io/apiserver/pkg/server/options/authorization.go
generated
vendored
|
@ -1,114 +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"
|
||||
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) {
|
||||
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) 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
|
||||
}
|
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"
|
88
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
88
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
|
@ -1,88 +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"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultEtcdPathPrefix = "/registry"
|
||||
)
|
||||
|
||||
type EtcdOptions struct {
|
||||
StorageConfig storagebackend.Config
|
||||
|
||||
EtcdServersOverrides []string
|
||||
}
|
||||
|
||||
func NewEtcdOptions(scheme *runtime.Scheme) *EtcdOptions {
|
||||
return &EtcdOptions{
|
||||
StorageConfig: storagebackend.Config{
|
||||
Prefix: DefaultEtcdPathPrefix,
|
||||
// Default cache size to 0 - if unset, its size will be set based on target
|
||||
// memory usage.
|
||||
DeserializationCacheSize: 0,
|
||||
Copier: scheme,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) Validate() []error {
|
||||
allErrors := []error{}
|
||||
if len(s.StorageConfig.ServerList) == 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
||||
func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
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.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.")
|
||||
}
|
204
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
204
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
|
@ -1,204 +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"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
|
||||
// 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 {
|
||||
AdmissionControl string
|
||||
AdmissionControlConfigFile string
|
||||
AdvertiseAddress net.IP
|
||||
|
||||
CorsAllowedOriginList []string
|
||||
// To enable protobuf as storage format, it is enough
|
||||
// to set it to "application/vnd.kubernetes.protobuf".
|
||||
DefaultStorageMediaType string
|
||||
DeleteCollectionWorkers int
|
||||
AuditLogPath string
|
||||
AuditLogMaxAge int
|
||||
AuditLogMaxBackups int
|
||||
AuditLogMaxSize int
|
||||
EnableGarbageCollection bool
|
||||
EnableProfiling bool
|
||||
EnableContentionProfiling bool
|
||||
EnableSwaggerUI bool
|
||||
EnableWatchCache bool
|
||||
ExternalHost string
|
||||
MaxRequestsInFlight int
|
||||
MaxMutatingRequestsInFlight int
|
||||
MinRequestTimeout int
|
||||
RuntimeConfig utilflag.ConfigurationMap
|
||||
TargetRAMMB int
|
||||
WatchCacheSizes []string
|
||||
}
|
||||
|
||||
func NewServerRunOptions() *ServerRunOptions {
|
||||
return &ServerRunOptions{
|
||||
AdmissionControl: "AlwaysAdmit",
|
||||
DefaultStorageMediaType: "application/json",
|
||||
DeleteCollectionWorkers: 1,
|
||||
EnableGarbageCollection: true,
|
||||
EnableProfiling: true,
|
||||
EnableContentionProfiling: false,
|
||||
EnableWatchCache: true,
|
||||
MaxRequestsInFlight: 400,
|
||||
MaxMutatingRequestsInFlight: 200,
|
||||
MinRequestTimeout: 1800,
|
||||
RuntimeConfig: make(utilflag.ConfigurationMap),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultAdvertiseAddress sets the field AdvertiseAddress if
|
||||
// unset. The field will be set based on the SecureServingOptions. If
|
||||
// the SecureServingOptions is not present, DefaultExternalAddress
|
||||
// will fall back to the insecure ServingOptions.
|
||||
func (s *ServerRunOptions) DefaultAdvertiseAddress(secure *SecureServingOptions, insecure *ServingOptions) error {
|
||||
if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
|
||||
switch {
|
||||
case secure != nil:
|
||||
hostIP, err := secure.ServingOptions.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
|
||||
|
||||
case insecure != nil:
|
||||
hostIP, err := insecure.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
|
||||
}
|
||||
|
||||
// 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.StringVar(&s.AdmissionControl, "admission-control", s.AdmissionControl, ""+
|
||||
"Ordered list of plug-ins to do admission control of resources into cluster. "+
|
||||
"Comma-delimited list of: "+strings.Join(admission.GetPlugins(), ", ")+".")
|
||||
|
||||
fs.StringVar(&s.AdmissionControlConfigFile, "admission-control-config-file", s.AdmissionControlConfigFile,
|
||||
"File with admission control configuration.")
|
||||
|
||||
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.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
|
||||
"The media type to use to store objects in storage. Defaults to application/json. "+
|
||||
"Some resources 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.StringVar(&s.AuditLogPath, "audit-log-path", s.AuditLogPath,
|
||||
"If set, all requests coming to the apiserver will be logged to this file.")
|
||||
fs.IntVar(&s.AuditLogMaxAge, "audit-log-maxage", s.AuditLogMaxBackups,
|
||||
"The maximum number of days to retain old audit log files based on the timestamp encoded in their filename.")
|
||||
fs.IntVar(&s.AuditLogMaxBackups, "audit-log-maxbackup", s.AuditLogMaxBackups,
|
||||
"The maximum number of old audit log files to retain.")
|
||||
fs.IntVar(&s.AuditLogMaxSize, "audit-log-maxsize", s.AuditLogMaxSize,
|
||||
"The maximum size in megabytes of the audit log file before it gets rotated. Defaults to 100MB.")
|
||||
|
||||
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.EnableProfiling, "profiling", s.EnableProfiling,
|
||||
"Enable profiling via web interface host:port/debug/pprof/")
|
||||
fs.BoolVar(&s.EnableContentionProfiling, "contention-profiling", s.EnableContentionProfiling,
|
||||
"Enable contention profiling. Requires --profiling to be set to work.")
|
||||
|
||||
fs.BoolVar(&s.EnableSwaggerUI, "enable-swagger-ui", s.EnableSwaggerUI,
|
||||
"Enables swagger ui on the apiserver at /swagger-ui")
|
||||
|
||||
// TODO: enable cache in integration tests.
|
||||
fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
|
||||
"Enable watch caching in the apiserver")
|
||||
|
||||
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).")
|
||||
|
||||
// TODO: remove post-1.6
|
||||
fs.String("long-running-request-regexp", "", ""+
|
||||
"A regular expression matching long running requests which should "+
|
||||
"be excluded from maximum inflight request handling.")
|
||||
fs.MarkDeprecated("long-running-request-regexp", "regular expression matching of long-running requests is no longer supported")
|
||||
|
||||
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.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.")
|
||||
|
||||
fs.Var(&s.RuntimeConfig, "runtime-config", ""+
|
||||
"A set of key=value pairs that describe runtime configuration that may be passed "+
|
||||
"to apiserver. apis/<groupVersion> key can be used to turn on/off specific api versions. "+
|
||||
"apis/<groupVersion>/<resource> can be used to turn on/off specific resources. api/all and "+
|
||||
"api/legacy are special keys to control all and legacy api versions respectively.")
|
||||
|
||||
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.")
|
||||
|
||||
utilfeature.DefaultFeatureGate.AddFlag(fs)
|
||||
}
|
220
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
220
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
|
@ -1,220 +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"
|
||||
"path"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
type ServingOptions struct {
|
||||
BindAddress net.IP
|
||||
BindPort int
|
||||
}
|
||||
|
||||
type SecureServingOptions struct {
|
||||
ServingOptions ServingOptions
|
||||
|
||||
// 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{
|
||||
ServingOptions: ServingOptions{
|
||||
BindAddress: net.ParseIP("0.0.0.0"),
|
||||
BindPort: 6443,
|
||||
},
|
||||
ServerCert: GeneratableKeyCert{
|
||||
PairName: "apiserver",
|
||||
CertDirectory: "/var/run/kubernetes",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) Validate() []error {
|
||||
errors := []error{}
|
||||
if s == nil {
|
||||
return errors
|
||||
}
|
||||
|
||||
errors = append(errors, s.ServingOptions.Validate("secure-port")...)
|
||||
return errors
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.IPVar(&s.ServingOptions.BindAddress, "bind-address", s.ServingOptions.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.ServingOptions.BindPort, "secure-port", s.ServingOptions.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 (by default /var/run/kubernetes). "+
|
||||
"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.key,example.crt\" or \"*.foo.com,foo.com:foo.key,foo.crt\".")
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||
fs.IPVar(&s.ServingOptions.BindAddress, "public-address-override", s.ServingOptions.BindAddress,
|
||||
"DEPRECATED: see --bind-address instead.")
|
||||
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
||||
}
|
||||
|
||||
func NewInsecureServingOptions() *ServingOptions {
|
||||
return &ServingOptions{
|
||||
BindAddress: net.ParseIP("127.0.0.1"),
|
||||
BindPort: 8080,
|
||||
}
|
||||
}
|
||||
|
||||
func (s ServingOptions) Validate(portArg string) []error {
|
||||
errors := []error{}
|
||||
|
||||
if s.BindPort < 0 || s.BindPort > 65535 {
|
||||
errors = append(errors, fmt.Errorf("--%v %v must be between 0 and 65535, inclusive. 0 for turning off secure port.", portArg, s.BindPort))
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
func (s *ServingOptions) DefaultExternalAddress() (net.IP, error) {
|
||||
return utilnet.ChooseBindAddress(s.BindAddress)
|
||||
}
|
||||
|
||||
func (s *ServingOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.IPVar(&s.BindAddress, "insecure-bind-address", s.BindAddress, ""+
|
||||
"The IP address on which to serve the --insecure-port (set to 0.0.0.0 for all interfaces). "+
|
||||
"Defaults to localhost.")
|
||||
|
||||
fs.IntVar(&s.BindPort, "insecure-port", s.BindPort, ""+
|
||||
"The port on which to serve unsecured, unauthenticated access. Default 8080. It is assumed "+
|
||||
"that firewall rules are set up such that this port is not reachable from outside of "+
|
||||
"the cluster and that port 443 on the cluster's public address is proxied to this "+
|
||||
"port. This is performed by nginx in the default setup.")
|
||||
}
|
||||
|
||||
func (s *ServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||
fs.IPVar(&s.BindAddress, "address", s.BindAddress,
|
||||
"DEPRECATED: see --insecure-bind-address instead.")
|
||||
fs.MarkDeprecated("address", "see --insecure-bind-address instead.")
|
||||
|
||||
fs.IntVar(&s.BindPort, "port", s.BindPort, "DEPRECATED: see --insecure-port instead.")
|
||||
fs.MarkDeprecated("port", "see --insecure-port instead.")
|
||||
}
|
||||
|
||||
func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress string, alternateIPs ...net.IP) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
keyCert := &s.ServerCert.CertKey
|
||||
if s.ServingOptions.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 {
|
||||
// TODO: It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
||||
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
||||
// TODO (cjcullen): Is ClusterIP the right address to sign a cert with?
|
||||
alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}
|
||||
|
||||
// add either the bind address or localhost to the valid alternates
|
||||
bindIP := s.ServingOptions.BindAddress.String()
|
||||
if bindIP == "0.0.0.0" {
|
||||
alternateDNS = append(alternateDNS, "localhost")
|
||||
} else {
|
||||
alternateIPs = append(alternateIPs, s.ServingOptions.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
|
||||
}
|
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.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
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
Loading…
Add table
Add a link
Reference in a new issue