move no k8s.io/kubernetes dependencies round one

This commit is contained in:
deads2k 2017-01-04 10:38:42 -05:00
parent 561304be0f
commit f22426d63f
8 changed files with 602 additions and 0 deletions

View File

@ -0,0 +1,68 @@
/*
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 authenticator
import (
"net/http"
"k8s.io/apiserver/pkg/authentication/user"
)
// Token checks a string value against a backing authentication store and returns
// information about the current user and true if successful, false if not successful,
// or an error if the token could not be checked.
type Token interface {
AuthenticateToken(token string) (user.Info, bool, error)
}
// Request attempts to extract authentication information from a request and returns
// information about the current user and true if successful, false if not successful,
// or an error if the request could not be checked.
type Request interface {
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
}
// Password checks a username and password against a backing authentication store and
// returns information about the user and true if successful, false if not successful,
// or an error if the username and password could not be checked
type Password interface {
AuthenticatePassword(user, password string) (user.Info, bool, error)
}
// TokenFunc is a function that implements the Token interface.
type TokenFunc func(token string) (user.Info, bool, error)
// AuthenticateToken implements authenticator.Token.
func (f TokenFunc) AuthenticateToken(token string) (user.Info, bool, error) {
return f(token)
}
// RequestFunc is a function that implements the Request interface.
type RequestFunc func(req *http.Request) (user.Info, bool, error)
// AuthenticateRequest implements authenticator.Request.
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
return f(req)
}
// PasswordFunc is a function that implements the Password interface.
type PasswordFunc func(user, password string) (user.Info, bool, error)
// AuthenticatePassword implements authenticator.Password.
func (f PasswordFunc) AuthenticatePassword(user, password string) (user.Info, bool, error) {
return f(user, password)
}

View File

@ -0,0 +1,140 @@
/*
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 authorizer
import (
"net/http"
"k8s.io/apiserver/pkg/authentication/user"
)
// Attributes is an interface used by an Authorizer to get information about a request
// that is used to make an authorization decision.
type Attributes interface {
// GetUser returns the user.Info object to authorize
GetUser() user.Info
// GetVerb returns the kube verb associated with API requests (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy),
// or the lowercased HTTP verb associated with non-API requests (this includes get, put, post, patch, and delete)
GetVerb() string
// When IsReadOnly() == true, the request has no side effects, other than
// caching, logging, and other incidentals.
IsReadOnly() bool
// The namespace of the object, if a request is for a REST object.
GetNamespace() string
// The kind of object, if a request is for a REST object.
GetResource() string
// GetSubresource returns the subresource being requested, if present
GetSubresource() string
// GetName returns the name of the object as parsed off the request. This will not be present for all request types, but
// will be present for: get, update, delete
GetName() string
// The group of the resource, if a request is for a REST object.
GetAPIGroup() string
// GetAPIVersion returns the version of the group requested, if a request is for a REST object.
GetAPIVersion() string
// IsResourceRequest returns true for requests to API resources, like /api/v1/nodes,
// and false for non-resource endpoints like /api, /healthz, and /swaggerapi
IsResourceRequest() bool
// GetPath returns the path of the request
GetPath() string
}
// Authorizer makes an authorization decision based on information gained by making
// zero or more calls to methods of the Attributes interface. It returns nil when an action is
// authorized, otherwise it returns an error.
type Authorizer interface {
Authorize(a Attributes) (authorized bool, reason string, err error)
}
type AuthorizerFunc func(a Attributes) (bool, string, error)
func (f AuthorizerFunc) Authorize(a Attributes) (bool, string, error) {
return f(a)
}
// RequestAttributesGetter provides a function that extracts Attributes from an http.Request
type RequestAttributesGetter interface {
GetRequestAttributes(user.Info, *http.Request) Attributes
}
// AttributesRecord implements Attributes interface.
type AttributesRecord struct {
User user.Info
Verb string
Namespace string
APIGroup string
APIVersion string
Resource string
Subresource string
Name string
ResourceRequest bool
Path string
}
func (a AttributesRecord) GetUser() user.Info {
return a.User
}
func (a AttributesRecord) GetVerb() string {
return a.Verb
}
func (a AttributesRecord) IsReadOnly() bool {
return a.Verb == "get" || a.Verb == "list" || a.Verb == "watch"
}
func (a AttributesRecord) GetNamespace() string {
return a.Namespace
}
func (a AttributesRecord) GetResource() string {
return a.Resource
}
func (a AttributesRecord) GetSubresource() string {
return a.Subresource
}
func (a AttributesRecord) GetName() string {
return a.Name
}
func (a AttributesRecord) GetAPIGroup() string {
return a.APIGroup
}
func (a AttributesRecord) GetAPIVersion() string {
return a.APIVersion
}
func (a AttributesRecord) IsResourceRequest() bool {
return a.ResourceRequest
}
func (a AttributesRecord) GetPath() string {
return a.Path
}

21
pkg/healthz/doc.go Normal file
View File

@ -0,0 +1,21 @@
/*
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/healthz"
// healthz.DefaultHealthz()
package healthz // import "k8s.io/apiserver/pkg/healthz"

133
pkg/healthz/healthz.go Normal file
View File

@ -0,0 +1,133 @@
/*
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")
}
})
}

View File

@ -0,0 +1,82 @@
/*
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())
}
}
}

View File

@ -0,0 +1,19 @@
/*
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 flushwriter implements a wrapper for a writer that flushes on every
// write if that writer implements the io.Flusher interface
package flushwriter // import "k8s.io/kubernetes/pkg/util/flushwriter"

View File

@ -0,0 +1,53 @@
/*
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 flushwriter
import (
"io"
"net/http"
)
// Wrap wraps an io.Writer into a writer that flushes after every write if
// the writer implements the Flusher interface.
func Wrap(w io.Writer) io.Writer {
fw := &flushWriter{
writer: w,
}
if flusher, ok := w.(http.Flusher); ok {
fw.flusher = flusher
}
return fw
}
// flushWriter provides wrapper for responseWriter with HTTP streaming capabilities
type flushWriter struct {
flusher http.Flusher
writer io.Writer
}
// Write is a FlushWriter implementation of the io.Writer that sends any buffered
// data to the client.
func (fw *flushWriter) Write(p []byte) (n int, err error) {
n, err = fw.writer.Write(p)
if err != nil {
return
}
if fw.flusher != nil {
fw.flusher.Flush()
}
return
}

View File

@ -0,0 +1,86 @@
/*
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 flushwriter
import (
"fmt"
"testing"
)
type writerWithFlush struct {
writeCount, flushCount int
err error
}
func (w *writerWithFlush) Flush() {
w.flushCount++
}
func (w *writerWithFlush) Write(p []byte) (n int, err error) {
w.writeCount++
return len(p), w.err
}
type writerWithNoFlush struct {
writeCount int
}
func (w *writerWithNoFlush) Write(p []byte) (n int, err error) {
w.writeCount++
return len(p), nil
}
func TestWriteWithFlush(t *testing.T) {
w := &writerWithFlush{}
fw := Wrap(w)
for i := 0; i < 10; i++ {
_, err := fw.Write([]byte("Test write"))
if err != nil {
t.Errorf("Unexpected error while writing with flush writer: %v", err)
}
}
if w.flushCount != 10 {
t.Errorf("Flush not called the expected number of times. Actual: %d", w.flushCount)
}
if w.writeCount != 10 {
t.Errorf("Write not called the expected number of times. Actual: %d", w.writeCount)
}
}
func TestWriteWithoutFlush(t *testing.T) {
w := &writerWithNoFlush{}
fw := Wrap(w)
for i := 0; i < 10; i++ {
_, err := fw.Write([]byte("Test write"))
if err != nil {
t.Errorf("Unexpected error while writing with flush writer: %v", err)
}
}
if w.writeCount != 10 {
t.Errorf("Write not called the expected number of times. Actual: %d", w.writeCount)
}
}
func TestWriteError(t *testing.T) {
e := fmt.Errorf("Error")
w := &writerWithFlush{err: e}
fw := Wrap(w)
_, err := fw.Write([]byte("Test write"))
if err != e {
t.Errorf("Did not get expected error. Got: %#v", err)
}
}