git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server
subrepo:
subdir: "metrics-server"
merged: "92d8412"
upstream:
origin: "https://github.com/kubernetes-incubator/metrics-server.git"
branch: "master"
commit: "92d8412"
git-subrepo:
version: "0.4.0"
origin: "???"
commit: "???"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS
new file mode 100755
index 0000000..9d268c4
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS
@@ -0,0 +1,2 @@
+reviewers:
+- sttts
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/context.go b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/context.go
new file mode 100644
index 0000000..95166f5
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/context.go
@@ -0,0 +1,93 @@
+/*
+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 request
+
+import (
+ "context"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apiserver/pkg/apis/audit"
+ "k8s.io/apiserver/pkg/authentication/user"
+)
+
+// The key type is unexported to prevent collisions
+type key int
+
+const (
+ // namespaceKey is the context key for the request namespace.
+ namespaceKey key = iota
+
+ // userKey is the context key for the request user.
+ userKey
+
+ // auditKey is the context key for the audit event.
+ auditKey
+)
+
+// NewContext instantiates a base context object for request flows.
+func NewContext() context.Context {
+ return context.TODO()
+}
+
+// NewDefaultContext instantiates a base context object for request flows in the default namespace
+func NewDefaultContext() context.Context {
+ return WithNamespace(NewContext(), metav1.NamespaceDefault)
+}
+
+// WithValue returns a copy of parent in which the value associated with key is val.
+func WithValue(parent context.Context, key interface{}, val interface{}) context.Context {
+ return context.WithValue(parent, key, val)
+}
+
+// WithNamespace returns a copy of parent in which the namespace value is set
+func WithNamespace(parent context.Context, namespace string) context.Context {
+ return WithValue(parent, namespaceKey, namespace)
+}
+
+// NamespaceFrom returns the value of the namespace key on the ctx
+func NamespaceFrom(ctx context.Context) (string, bool) {
+ namespace, ok := ctx.Value(namespaceKey).(string)
+ return namespace, ok
+}
+
+// NamespaceValue returns the value of the namespace key on the ctx, or the empty string if none
+func NamespaceValue(ctx context.Context) string {
+ namespace, _ := NamespaceFrom(ctx)
+ return namespace
+}
+
+// WithUser returns a copy of parent in which the user value is set
+func WithUser(parent context.Context, user user.Info) context.Context {
+ return WithValue(parent, userKey, user)
+}
+
+// UserFrom returns the value of the user key on the ctx
+func UserFrom(ctx context.Context) (user.Info, bool) {
+ user, ok := ctx.Value(userKey).(user.Info)
+ return user, ok
+}
+
+// WithAuditEvent returns set audit event struct.
+func WithAuditEvent(parent context.Context, ev *audit.Event) context.Context {
+ return WithValue(parent, auditKey, ev)
+}
+
+// AuditEventFrom returns the audit event struct on the ctx
+func AuditEventFrom(ctx context.Context) *audit.Event {
+ ev, _ := ctx.Value(auditKey).(*audit.Event)
+ return ev
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/doc.go b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/doc.go
new file mode 100644
index 0000000..96da6f2
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/doc.go
@@ -0,0 +1,20 @@
+/*
+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 request contains everything around extracting info from
+// a http request object.
+// TODO: this package is temporary. Handlers must move into pkg/apiserver/handlers to avoid dependency cycle
+package request // import "k8s.io/apiserver/pkg/endpoints/request"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go
new file mode 100644
index 0000000..1520bb3
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go
@@ -0,0 +1,273 @@
+/*
+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 request
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/api/validation/path"
+ metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/sets"
+
+ "github.com/golang/glog"
+)
+
+// LongRunningRequestCheck is a predicate which is true for long-running http requests.
+type LongRunningRequestCheck func(r *http.Request, requestInfo *RequestInfo) bool
+
+type RequestInfoResolver interface {
+ NewRequestInfo(req *http.Request) (*RequestInfo, error)
+}
+
+// RequestInfo holds information parsed from the http.Request
+type RequestInfo struct {
+ // IsResourceRequest indicates whether or not the request is for an API resource or subresource
+ IsResourceRequest bool
+ // Path is the URL path of the request
+ Path string
+ // Verb is the kube verb associated with the request for API requests, not the http verb. This includes things like list and watch.
+ // for non-resource requests, this is the lowercase http verb
+ Verb string
+
+ APIPrefix string
+ APIGroup string
+ APIVersion string
+ Namespace string
+ // Resource is the name of the resource being requested. This is not the kind. For example: pods
+ Resource string
+ // Subresource is the name of the subresource being requested. This is a different resource, scoped to the parent resource, but it may have a different kind.
+ // For instance, /pods has the resource "pods" and the kind "Pod", while /pods/foo/status has the resource "pods", the sub resource "status", and the kind "Pod"
+ // (because status operates on pods). The binding resource for a pod though may be /pods/foo/binding, which has resource "pods", subresource "binding", and kind "Binding".
+ Subresource string
+ // Name is empty for some verbs, but if the request directly indicates a name (not in body content) then this field is filled in.
+ Name string
+ // Parts are the path parts for the request, always starting with /{resource}/{name}
+ Parts []string
+}
+
+// specialVerbs contains just strings which are used in REST paths for special actions that don't fall under the normal
+// CRUDdy GET/POST/PUT/DELETE actions on REST objects.
+// TODO: find a way to keep this up to date automatically. Maybe dynamically populate list as handlers added to
+// master's Mux.
+var specialVerbs = sets.NewString("proxy", "watch")
+
+// specialVerbsNoSubresources contains root verbs which do not allow subresources
+var specialVerbsNoSubresources = sets.NewString("proxy")
+
+// namespaceSubresources contains subresources of namespace
+// this list allows the parser to distinguish between a namespace subresource, and a namespaced resource
+var namespaceSubresources = sets.NewString("status", "finalize")
+
+// NamespaceSubResourcesForTest exports namespaceSubresources for testing in pkg/master/master_test.go, so we never drift
+var NamespaceSubResourcesForTest = sets.NewString(namespaceSubresources.List()...)
+
+type RequestInfoFactory struct {
+ APIPrefixes sets.String // without leading and trailing slashes
+ GrouplessAPIPrefixes sets.String // without leading and trailing slashes
+}
+
+// TODO write an integration test against the swagger doc to test the RequestInfo and match up behavior to responses
+// NewRequestInfo returns the information from the http request. If error is not nil, RequestInfo holds the information as best it is known before the failure
+// It handles both resource and non-resource requests and fills in all the pertinent information for each.
+// Valid Inputs:
+// Resource paths
+// /apis/{api-group}/{version}/namespaces
+// /api/{version}/namespaces
+// /api/{version}/namespaces/{namespace}
+// /api/{version}/namespaces/{namespace}/{resource}
+// /api/{version}/namespaces/{namespace}/{resource}/{resourceName}
+// /api/{version}/{resource}
+// /api/{version}/{resource}/{resourceName}
+//
+// Special verbs without subresources:
+// /api/{version}/proxy/{resource}/{resourceName}
+// /api/{version}/proxy/namespaces/{namespace}/{resource}/{resourceName}
+//
+// Special verbs with subresources:
+// /api/{version}/watch/{resource}
+// /api/{version}/watch/namespaces/{namespace}/{resource}
+//
+// NonResource paths
+// /apis/{api-group}/{version}
+// /apis/{api-group}
+// /apis
+// /api/{version}
+// /api
+// /healthz
+// /
+func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, error) {
+ // start with a non-resource request until proven otherwise
+ requestInfo := RequestInfo{
+ IsResourceRequest: false,
+ Path: req.URL.Path,
+ Verb: strings.ToLower(req.Method),
+ }
+
+ currentParts := splitPath(req.URL.Path)
+ if len(currentParts) < 3 {
+ // return a non-resource request
+ return &requestInfo, nil
+ }
+
+ if !r.APIPrefixes.Has(currentParts[0]) {
+ // return a non-resource request
+ return &requestInfo, nil
+ }
+ requestInfo.APIPrefix = currentParts[0]
+ currentParts = currentParts[1:]
+
+ if !r.GrouplessAPIPrefixes.Has(requestInfo.APIPrefix) {
+ // one part (APIPrefix) has already been consumed, so this is actually "do we have four parts?"
+ if len(currentParts) < 3 {
+ // return a non-resource request
+ return &requestInfo, nil
+ }
+
+ requestInfo.APIGroup = currentParts[0]
+ currentParts = currentParts[1:]
+ }
+
+ requestInfo.IsResourceRequest = true
+ requestInfo.APIVersion = currentParts[0]
+ currentParts = currentParts[1:]
+
+ // handle input of form /{specialVerb}/*
+ if specialVerbs.Has(currentParts[0]) {
+ if len(currentParts) < 2 {
+ return &requestInfo, fmt.Errorf("unable to determine kind and namespace from url, %v", req.URL)
+ }
+
+ requestInfo.Verb = currentParts[0]
+ currentParts = currentParts[1:]
+
+ } else {
+ switch req.Method {
+ case "POST":
+ requestInfo.Verb = "create"
+ case "GET", "HEAD":
+ requestInfo.Verb = "get"
+ case "PUT":
+ requestInfo.Verb = "update"
+ case "PATCH":
+ requestInfo.Verb = "patch"
+ case "DELETE":
+ requestInfo.Verb = "delete"
+ default:
+ requestInfo.Verb = ""
+ }
+ }
+
+ // URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
+ if currentParts[0] == "namespaces" {
+ if len(currentParts) > 1 {
+ requestInfo.Namespace = currentParts[1]
+
+ // if there is another step after the namespace name and it is not a known namespace subresource
+ // move currentParts to include it as a resource in its own right
+ if len(currentParts) > 2 && !namespaceSubresources.Has(currentParts[2]) {
+ currentParts = currentParts[2:]
+ }
+ }
+ } else {
+ requestInfo.Namespace = metav1.NamespaceNone
+ }
+
+ // parsing successful, so we now know the proper value for .Parts
+ requestInfo.Parts = currentParts
+
+ // parts look like: resource/resourceName/subresource/other/stuff/we/don't/interpret
+ switch {
+ case len(requestInfo.Parts) >= 3 && !specialVerbsNoSubresources.Has(requestInfo.Verb):
+ requestInfo.Subresource = requestInfo.Parts[2]
+ fallthrough
+ case len(requestInfo.Parts) >= 2:
+ requestInfo.Name = requestInfo.Parts[1]
+ fallthrough
+ case len(requestInfo.Parts) >= 1:
+ requestInfo.Resource = requestInfo.Parts[0]
+ }
+
+ // if there's no name on the request and we thought it was a get before, then the actual verb is a list or a watch
+ if len(requestInfo.Name) == 0 && requestInfo.Verb == "get" {
+ opts := metainternalversion.ListOptions{}
+ if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), metav1.SchemeGroupVersion, &opts); err != nil {
+ // An error in parsing request will result in default to "list" and not setting "name" field.
+ glog.Errorf("Couldn't parse request %#v: %v", req.URL.Query(), err)
+ // Reset opts to not rely on partial results from parsing.
+ // However, if watch is set, let's report it.
+ opts = metainternalversion.ListOptions{}
+ if values := req.URL.Query()["watch"]; len(values) > 0 {
+ switch strings.ToLower(values[0]) {
+ case "false", "0":
+ default:
+ opts.Watch = true
+ }
+ }
+ }
+
+ if opts.Watch {
+ requestInfo.Verb = "watch"
+ } else {
+ requestInfo.Verb = "list"
+ }
+
+ if opts.FieldSelector != nil {
+ if name, ok := opts.FieldSelector.RequiresExactMatch("metadata.name"); ok {
+ if len(path.IsValidPathSegmentName(name)) == 0 {
+ requestInfo.Name = name
+ }
+ }
+ }
+ }
+ // if there's no name on the request and we thought it was a delete before, then the actual verb is deletecollection
+ if len(requestInfo.Name) == 0 && requestInfo.Verb == "delete" {
+ requestInfo.Verb = "deletecollection"
+ }
+
+ return &requestInfo, nil
+}
+
+type requestInfoKeyType int
+
+// requestInfoKey is the RequestInfo key for the context. It's of private type here. Because
+// keys are interfaces and interfaces are equal when the type and the value is equal, this
+// does not conflict with the keys defined in pkg/api.
+const requestInfoKey requestInfoKeyType = iota
+
+// WithRequestInfo returns a copy of parent in which the request info value is set
+func WithRequestInfo(parent context.Context, info *RequestInfo) context.Context {
+ return WithValue(parent, requestInfoKey, info)
+}
+
+// RequestInfoFrom returns the value of the RequestInfo key on the ctx
+func RequestInfoFrom(ctx context.Context) (*RequestInfo, bool) {
+ info, ok := ctx.Value(requestInfoKey).(*RequestInfo)
+ return info, ok
+}
+
+// splitPath returns the segments for a URL path.
+func splitPath(path string) []string {
+ path = strings.Trim(path, "/")
+ if path == "" {
+ return []string{}
+ }
+ return strings.Split(path, "/")
+}