Commit 9430bb38 authored by Daniel Smith's avatar Daniel Smith

Merge pull request #2282 from bgrant0607/docgen

Automatic API generation via go-restful
parents e3d75dbd 7583e1a6
...@@ -105,7 +105,7 @@ func NewInvalid(kind, name string, errs ValidationErrorList) error { ...@@ -105,7 +105,7 @@ func NewInvalid(kind, name string, errs ValidationErrorList) error {
} }
return &statusError{api.Status{ return &statusError{api.Status{
Status: api.StatusFailure, Status: api.StatusFailure,
Code: 422, // RFC 4918 Code: 422, // RFC 4918: StatusUnprocessableEntity
Reason: api.StatusReasonInvalid, Reason: api.StatusReasonInvalid,
Details: &api.StatusDetails{ Details: &api.StatusDetails{
Kind: kind, Kind: kind,
...@@ -121,7 +121,7 @@ func NewBadRequest(reason string) error { ...@@ -121,7 +121,7 @@ func NewBadRequest(reason string) error {
return &statusError{ return &statusError{
api.Status{ api.Status{
Status: api.StatusFailure, Status: api.StatusFailure,
Code: 400, Code: http.StatusBadRequest,
Reason: api.StatusReasonBadRequest, Reason: api.StatusReasonBadRequest,
Details: &api.StatusDetails{ Details: &api.StatusDetails{
Causes: []api.StatusCause{ Causes: []api.StatusCause{
...@@ -136,7 +136,7 @@ func NewBadRequest(reason string) error { ...@@ -136,7 +136,7 @@ func NewBadRequest(reason string) error {
func NewInternalError(err error) error { func NewInternalError(err error) error {
return &statusError{api.Status{ return &statusError{api.Status{
Status: api.StatusFailure, Status: api.StatusFailure,
Code: 500, Code: http.StatusInternalServerError,
Reason: api.StatusReasonInternalError, Reason: api.StatusReasonInternalError,
Details: &api.StatusDetails{ Details: &api.StatusDetails{
Causes: []api.StatusCause{{Message: err.Error()}}, Causes: []api.StatusCause{{Message: err.Error()}},
......
...@@ -20,6 +20,8 @@ import ( ...@@ -20,6 +20,8 @@ import (
"strings" "strings"
) )
// TODO: Address these per #1502
func IsPullAlways(p PullPolicy) bool { func IsPullAlways(p PullPolicy) bool {
return pullPoliciesEqual(p, PullAlways) return pullPoliciesEqual(p, PullAlways)
} }
......
/*
Copyright 2014 Google Inc. All rights reserved.
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 api
// This file contains API types that are unversioned.
// APIVersions lists the api versions that are available, to allow
// version negotiation. APIVersions isn't just an unnamed array of
// strings in order to allow for future evolution, though unversioned
type APIVersions struct {
Versions []string `json:"versions" yaml:"versions"`
}
...@@ -121,6 +121,7 @@ func RecoverPanics(handler http.Handler) http.Handler { ...@@ -121,6 +121,7 @@ func RecoverPanics(handler http.Handler) http.Handler {
}) })
} }
// TODO: use restful.CrossOriginResourceSharing
// Simple CORS implementation that wraps an http Handler // Simple CORS implementation that wraps an http Handler
// For a more detailed implementation use https://github.com/martini-contrib/cors // For a more detailed implementation use https://github.com/martini-contrib/cors
// or implement CORS at your proxy layer // or implement CORS at your proxy layer
......
...@@ -19,16 +19,19 @@ package apiserver ...@@ -19,16 +19,19 @@ package apiserver
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/emicklei/go-restful"
) )
// handleIndex is the root index page for Kubernetes. // handleIndex is the root index page for Kubernetes.
func handleIndex(w http.ResponseWriter, req *http.Request) { func handleIndex(req *restful.Request, resp *restful.Response) {
if req.URL.Path != "/" && req.URL.Path != "/index.html" { // TODO: use restful's Request/Response methods
notFound(w, req) if req.Request.URL.Path != "/" && req.Request.URL.Path != "/index.html" {
notFound(resp.ResponseWriter, req.Request)
return return
} }
w.WriteHeader(http.StatusOK) resp.ResponseWriter.WriteHeader(http.StatusOK)
// TODO: serve this out of a file? // TODO: serve this out of a file
data := "<html><body>Welcome to Kubernetes</body></html>" data := "<html><body>Welcome to Kubernetes</body></html>"
fmt.Fprint(w, data) fmt.Fprint(resp.ResponseWriter, data)
} }
...@@ -113,7 +113,7 @@ func TestOperationsList(t *testing.T) { ...@@ -113,7 +113,7 @@ func TestOperationsList(t *testing.T) {
} }
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/prefix/version", selfLinker) }, codec, "/prefix", "version", selfLinker)
handler.(*defaultAPIServer).group.handler.asyncOpWait = 0 handler.(*defaultAPIServer).group.handler.asyncOpWait = 0
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
...@@ -170,7 +170,7 @@ func TestOpGet(t *testing.T) { ...@@ -170,7 +170,7 @@ func TestOpGet(t *testing.T) {
} }
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/prefix/version", selfLinker) }, codec, "/prefix", "version", selfLinker)
handler.(*defaultAPIServer).group.handler.asyncOpWait = 0 handler.(*defaultAPIServer).group.handler.asyncOpWait = 0
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
......
...@@ -165,7 +165,7 @@ func TestProxy(t *testing.T) { ...@@ -165,7 +165,7 @@ func TestProxy(t *testing.T) {
} }
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/prefix/version", selfLinker) }, codec, "/prefix", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
......
...@@ -31,7 +31,7 @@ func TestRedirect(t *testing.T) { ...@@ -31,7 +31,7 @@ func TestRedirect(t *testing.T) {
} }
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/prefix/version", selfLinker) }, codec, "/prefix", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
......
...@@ -50,7 +50,7 @@ func TestWatchWebsocket(t *testing.T) { ...@@ -50,7 +50,7 @@ func TestWatchWebsocket(t *testing.T) {
_ = ResourceWatcher(simpleStorage) // Give compile error if this doesn't work. _ = ResourceWatcher(simpleStorage) // Give compile error if this doesn't work.
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/api/version", selfLinker) }, codec, "/api", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
...@@ -104,7 +104,7 @@ func TestWatchHTTP(t *testing.T) { ...@@ -104,7 +104,7 @@ func TestWatchHTTP(t *testing.T) {
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/api/version", selfLinker) }, codec, "/api", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
client := http.Client{} client := http.Client{}
...@@ -167,7 +167,7 @@ func TestWatchParamParsing(t *testing.T) { ...@@ -167,7 +167,7 @@ func TestWatchParamParsing(t *testing.T) {
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/api/version", selfLinker) }, codec, "/api", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
...@@ -239,7 +239,7 @@ func TestWatchProtocolSelection(t *testing.T) { ...@@ -239,7 +239,7 @@ func TestWatchProtocolSelection(t *testing.T) {
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := Handle(map[string]RESTStorage{ handler := Handle(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, codec, "/api/version", selfLinker) }, codec, "/api", "version", selfLinker)
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
defer server.CloseClientConnections() defer server.CloseClientConnections()
......
...@@ -63,7 +63,7 @@ func (c *Client) Services(namespace string) ServiceInterface { ...@@ -63,7 +63,7 @@ func (c *Client) Services(namespace string) ServiceInterface {
// VersionInterface has a method to retrieve the server version. // VersionInterface has a method to retrieve the server version.
type VersionInterface interface { type VersionInterface interface {
ServerVersion() (*version.Info, error) ServerVersion() (*version.Info, error)
ServerAPIVersions() (*version.APIVersions, error) ServerAPIVersions() (*api.APIVersions, error)
} }
// APIStatus is exposed by errors that can be converted to an api.Status object // APIStatus is exposed by errors that can be converted to an api.Status object
...@@ -92,12 +92,12 @@ func (c *Client) ServerVersion() (*version.Info, error) { ...@@ -92,12 +92,12 @@ func (c *Client) ServerVersion() (*version.Info, error) {
} }
// ServerAPIVersions retrieves and parses the list of API versions the server supports. // ServerAPIVersions retrieves and parses the list of API versions the server supports.
func (c *Client) ServerAPIVersions() (*version.APIVersions, error) { func (c *Client) ServerAPIVersions() (*api.APIVersions, error) {
body, err := c.Get().AbsPath("/api").Do().Raw() body, err := c.Get().AbsPath("/api").Do().Raw()
if err != nil { if err != nil {
return nil, err return nil, err
} }
var v version.APIVersions var v api.APIVersions
err = json.Unmarshal(body, &v) err = json.Unmarshal(body, &v)
if err != nil { if err != nil {
return nil, fmt.Errorf("Got '%s': %v", string(body), err) return nil, fmt.Errorf("Got '%s': %v", string(body), err)
......
...@@ -71,7 +71,7 @@ func (c *Fake) ServerVersion() (*version.Info, error) { ...@@ -71,7 +71,7 @@ func (c *Fake) ServerVersion() (*version.Info, error) {
return &versionInfo, nil return &versionInfo, nil
} }
func (c *Fake) ServerAPIVersions() (*version.APIVersions, error) { func (c *Fake) ServerAPIVersions() (*api.APIVersions, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-apiversions", Value: nil}) c.Actions = append(c.Actions, FakeAction{Action: "get-apiversions", Value: nil})
return &version.APIVersions{Versions: []string{"v1beta1", "v1beta2"}}, nil return &api.APIVersions{Versions: []string{"v1beta1", "v1beta2"}}, nil
} }
...@@ -20,20 +20,24 @@ import ( ...@@ -20,20 +20,24 @@ import (
"net/http" "net/http"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
"github.com/emicklei/go-restful"
) )
// handleWhoAmI returns the user-string which this request is authenticated as (if any). // handleWhoAmI returns the user-string which this request is authenticated as (if any).
// Useful for debugging authentication. Always returns HTTP status okay and a human // Useful for debugging authentication. Always returns HTTP status okay and a human
// readable (not intended as API) description of authentication state of request. // readable (not intended as API) description of authentication state of request.
func handleWhoAmI(auth authenticator.Request) func(w http.ResponseWriter, req *http.Request) { func handleWhoAmI(auth authenticator.Request) restful.RouteFunction {
return func(w http.ResponseWriter, req *http.Request) { return func(req *restful.Request, resp *restful.Response) {
// This is supposed to go away, so it's not worth the effort to convert to restful
w := resp.ResponseWriter
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
if auth == nil { if auth == nil {
w.Write([]byte("NO AUTHENTICATION SUPPORT")) w.Write([]byte("NO AUTHENTICATION SUPPORT"))
return return
} }
userInfo, ok, err := auth.AuthenticateRequest(req) userInfo, ok, err := auth.AuthenticateRequest(req.Request)
if err != nil { if err != nil {
w.Write([]byte("ERROR WHILE AUTHENTICATING")) w.Write([]byte("ERROR WHILE AUTHENTICATING"))
return return
......
...@@ -17,10 +17,13 @@ limitations under the License. ...@@ -17,10 +17,13 @@ limitations under the License.
package master package master
import ( import (
"bytes"
_ "expvar"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
rt "runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
...@@ -51,6 +54,8 @@ import ( ...@@ -51,6 +54,8 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/ui" "github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful/swagger"
"github.com/golang/glog" "github.com/golang/glog"
) )
...@@ -64,7 +69,6 @@ type Config struct { ...@@ -64,7 +69,6 @@ type Config struct {
MinionRegexp string MinionRegexp string
KubeletClient client.KubeletClient KubeletClient client.KubeletClient
PortalNet *net.IPNet PortalNet *net.IPNet
Mux apiserver.Mux
EnableLogsSupport bool EnableLogsSupport bool
EnableUISupport bool EnableUISupport bool
APIPrefix string APIPrefix string
...@@ -101,6 +105,8 @@ type Master struct { ...@@ -101,6 +105,8 @@ type Master struct {
client *client.Client client *client.Client
portalNet *net.IPNet portalNet *net.IPNet
mux apiserver.Mux mux apiserver.Mux
handlerContainer *restful.Container
rootWebService *restful.WebService
enableLogsSupport bool enableLogsSupport bool
enableUISupport bool enableUISupport bool
apiPrefix string apiPrefix string
...@@ -218,6 +224,7 @@ func New(c *Config) *Master { ...@@ -218,6 +224,7 @@ func New(c *Config) *Master {
if c.KubeletClient == nil { if c.KubeletClient == nil {
glog.Fatalf("master.New() called with config.KubeletClient == nil") glog.Fatalf("master.New() called with config.KubeletClient == nil")
} }
mx := http.NewServeMux()
m := &Master{ m := &Master{
podRegistry: etcd.NewRegistry(c.EtcdHelper, boundPodFactory), podRegistry: etcd.NewRegistry(c.EtcdHelper, boundPodFactory),
controllerRegistry: etcd.NewRegistry(c.EtcdHelper, nil), controllerRegistry: etcd.NewRegistry(c.EtcdHelper, nil),
...@@ -228,7 +235,9 @@ func New(c *Config) *Master { ...@@ -228,7 +235,9 @@ func New(c *Config) *Master {
minionRegistry: minionRegistry, minionRegistry: minionRegistry,
client: c.Client, client: c.Client,
portalNet: c.PortalNet, portalNet: c.PortalNet,
mux: http.NewServeMux(), mux: mx,
handlerContainer: NewHandlerContainer(mx),
rootWebService: new(restful.WebService),
enableLogsSupport: c.EnableLogsSupport, enableLogsSupport: c.EnableLogsSupport,
enableUISupport: c.EnableUISupport, enableUISupport: c.EnableUISupport,
apiPrefix: c.APIPrefix, apiPrefix: c.APIPrefix,
...@@ -253,6 +262,7 @@ func (m *Master) HandleWithAuth(pattern string, handler http.Handler) { ...@@ -253,6 +262,7 @@ func (m *Master) HandleWithAuth(pattern string, handler http.Handler) {
// URLs into attributes that an Authorizer can understand, and have // URLs into attributes that an Authorizer can understand, and have
// sensible policy defaults for plugged-in endpoints. This will be different // sensible policy defaults for plugged-in endpoints. This will be different
// for generic endpoints versus REST object endpoints. // for generic endpoints versus REST object endpoints.
// TODO: convert to go-restful
m.mux.Handle(pattern, handler) m.mux.Handle(pattern, handler)
} }
...@@ -260,9 +270,31 @@ func (m *Master) HandleWithAuth(pattern string, handler http.Handler) { ...@@ -260,9 +270,31 @@ func (m *Master) HandleWithAuth(pattern string, handler http.Handler) {
// Applies the same authentication and authorization (if any is configured) // Applies the same authentication and authorization (if any is configured)
// to the request is used for the master's built-in endpoints. // to the request is used for the master's built-in endpoints.
func (m *Master) HandleFuncWithAuth(pattern string, handler func(http.ResponseWriter, *http.Request)) { func (m *Master) HandleFuncWithAuth(pattern string, handler func(http.ResponseWriter, *http.Request)) {
// TODO: convert to go-restful
m.mux.HandleFunc(pattern, handler) m.mux.HandleFunc(pattern, handler)
} }
func NewHandlerContainer(mux *http.ServeMux) *restful.Container {
container := restful.NewContainer()
container.ServeMux = mux
container.RecoverHandler(logStackOnRecover)
return container
}
//TODO: Unify with RecoverPanics?
func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason))
for i := 2; ; i += 1 {
_, file, line, ok := rt.Caller(i)
if !ok {
break
}
buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line))
}
glog.Errorln(buffer.String())
}
func makeMinionRegistry(c *Config) minion.Registry { func makeMinionRegistry(c *Config) minion.Registry {
var minionRegistry minion.Registry = etcd.NewRegistry(c.EtcdHelper, nil) var minionRegistry minion.Registry = etcd.NewRegistry(c.EtcdHelper, nil)
if c.HealthCheckMinions { if c.HealthCheckMinions {
...@@ -286,6 +318,7 @@ func (m *Master) init(c *Config) { ...@@ -286,6 +318,7 @@ func (m *Master) init(c *Config) {
authenticator = bearertoken.New(tokenAuthenticator) authenticator = bearertoken.New(tokenAuthenticator)
} }
// TODO: Factor out the core API registration
m.storage = map[string]apiserver.RESTStorage{ m.storage = map[string]apiserver.RESTStorage{
"pods": pod.NewREST(&pod.RESTConfig{ "pods": pod.NewREST(&pod.RESTConfig{
CloudProvider: c.Cloud, CloudProvider: c.Cloud,
...@@ -304,13 +337,17 @@ func (m *Master) init(c *Config) { ...@@ -304,13 +337,17 @@ func (m *Master) init(c *Config) {
"bindings": binding.NewREST(m.bindingRegistry), "bindings": binding.NewREST(m.bindingRegistry),
} }
apiserver.NewAPIGroup(m.API_v1beta1()).InstallREST(m.mux, c.APIPrefix+"/v1beta1") apiserver.NewAPIGroupVersion(m.API_v1beta1()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta1")
apiserver.NewAPIGroup(m.API_v1beta2()).InstallREST(m.mux, c.APIPrefix+"/v1beta2") apiserver.NewAPIGroupVersion(m.API_v1beta2()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta2")
// TODO: InstallREST should register each version automatically
versionHandler := apiserver.APIVersionHandler("v1beta1", "v1beta2") versionHandler := apiserver.APIVersionHandler("v1beta1", "v1beta2")
m.mux.Handle(c.APIPrefix, versionHandler) m.rootWebService.Route(m.rootWebService.GET(c.APIPrefix).To(versionHandler))
apiserver.InstallSupport(m.mux)
serversToValidate := m.getServersToValidate(c)
apiserver.InstallSupport(m.handlerContainer, m.rootWebService)
// TODO: use go-restful
serversToValidate := m.getServersToValidate(c)
apiserver.InstallValidator(m.mux, serversToValidate) apiserver.InstallValidator(m.mux, serversToValidate)
if c.EnableLogsSupport { if c.EnableLogsSupport {
apiserver.InstallLogsSupport(m.mux) apiserver.InstallLogsSupport(m.mux)
...@@ -319,8 +356,15 @@ func (m *Master) init(c *Config) { ...@@ -319,8 +356,15 @@ func (m *Master) init(c *Config) {
ui.InstallSupport(m.mux) ui.InstallSupport(m.mux)
} }
// TODO: install runtime/pprof handler
// See github.com/emicklei/go-restful/blob/master/examples/restful-cpuprofiler-service.go
handler := http.Handler(m.mux.(*http.ServeMux)) handler := http.Handler(m.mux.(*http.ServeMux))
// TODO: handle CORS and auth using go-restful
// 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
if len(c.CorsAllowedOriginList) > 0 { if len(c.CorsAllowedOriginList) > 0 {
allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList) allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList)
if err != nil { if err != nil {
...@@ -338,7 +382,23 @@ func (m *Master) init(c *Config) { ...@@ -338,7 +382,23 @@ func (m *Master) init(c *Config) {
if authenticator != nil { if authenticator != nil {
handler = handlers.NewRequestAuthenticator(userContexts, authenticator, handlers.Unauthorized, handler) handler = handlers.NewRequestAuthenticator(userContexts, authenticator, handlers.Unauthorized, handler)
} }
m.mux.HandleFunc("/_whoami", handleWhoAmI(authenticator)) // TODO: Remove temporary _whoami handler
m.rootWebService.Route(m.rootWebService.GET("/_whoami").To(handleWhoAmI(authenticator)))
// Install root web services
m.handlerContainer.Add(m.rootWebService)
// TODO: Make this optional?
// Enable swagger UI and discovery API
swaggerConfig := swagger.Config{
WebServices: m.handlerContainer.RegisteredWebServices(),
// TODO: Parameterize the path?
ApiPath: "/swaggerapi/",
// TODO: Distribute UI javascript and enable the UI
//SwaggerPath: "/swaggerui/",
//SwaggerFilePath: "/srv/apiserver/swagger/dist"
}
swagger.RegisterSwaggerService(swaggerConfig, m.handlerContainer)
m.Handler = handler m.Handler = handler
......
...@@ -96,11 +96,8 @@ func RunApiServer(cl *client.Client, etcdClient tools.EtcdClient, addr string, p ...@@ -96,11 +96,8 @@ func RunApiServer(cl *client.Client, etcdClient tools.EtcdClient, addr string, p
ReadOnlyPort: port, ReadOnlyPort: port,
PublicAddress: addr, PublicAddress: addr,
}) })
mux := http.NewServeMux()
apiserver.NewAPIGroup(m.API_v1beta1()).InstallREST(mux, "/api/v1beta1") handler.delegate = m.InsecureHandler
apiserver.NewAPIGroup(m.API_v1beta2()).InstallREST(mux, "/api/v1beta2")
apiserver.InstallSupport(mux)
handler.delegate = mux
go http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), &handler) go http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), &handler)
} }
......
...@@ -45,9 +45,3 @@ func Get() Info { ...@@ -45,9 +45,3 @@ func Get() Info {
func (info Info) String() string { func (info Info) String() string {
return info.GitVersion return info.GitVersion
} }
// APIVersions lists the api versions that are available, to allow
// version negotiation.
type APIVersions struct {
Versions []string `json:"versions" yaml:"versions"`
}
...@@ -242,6 +242,7 @@ var code200 = map[int]bool{200: true} ...@@ -242,6 +242,7 @@ var code200 = map[int]bool{200: true}
var code400 = map[int]bool{400: true} var code400 = map[int]bool{400: true}
var code403 = map[int]bool{403: true} var code403 = map[int]bool{403: true}
var code404 = map[int]bool{404: true} var code404 = map[int]bool{404: true}
var code405 = map[int]bool{405: true}
var code409 = map[int]bool{409: true} var code409 = map[int]bool{409: true}
var code422 = map[int]bool{422: true} var code422 = map[int]bool{422: true}
var code500 = map[int]bool{500: true} var code500 = map[int]bool{500: true}
...@@ -269,14 +270,14 @@ func getTestRequests() []struct { ...@@ -269,14 +270,14 @@ func getTestRequests() []struct {
// Non-standard methods (not expected to work, // Non-standard methods (not expected to work,
// but expected to pass/fail authorization prior to // but expected to pass/fail authorization prior to
// failing validation. // failing validation.
{"PATCH", "/api/v1beta1/pods/a", "", code404}, {"PATCH", "/api/v1beta1/pods/a", "", code405},
{"OPTIONS", "/api/v1beta1/pods", "", code404}, {"OPTIONS", "/api/v1beta1/pods", "", code405},
{"OPTIONS", "/api/v1beta1/pods/a", "", code404}, {"OPTIONS", "/api/v1beta1/pods/a", "", code405},
{"HEAD", "/api/v1beta1/pods", "", code404}, {"HEAD", "/api/v1beta1/pods", "", code405},
{"HEAD", "/api/v1beta1/pods/a", "", code404}, {"HEAD", "/api/v1beta1/pods/a", "", code405},
{"TRACE", "/api/v1beta1/pods", "", code404}, {"TRACE", "/api/v1beta1/pods", "", code405},
{"TRACE", "/api/v1beta1/pods/a", "", code404}, {"TRACE", "/api/v1beta1/pods/a", "", code405},
{"NOSUCHVERB", "/api/v1beta1/pods", "", code404}, {"NOSUCHVERB", "/api/v1beta1/pods", "", code405},
// Normal methods on services // Normal methods on services
{"GET", "/api/v1beta1/services", "", code200}, {"GET", "/api/v1beta1/services", "", code200},
...@@ -320,12 +321,12 @@ func getTestRequests() []struct { ...@@ -320,12 +321,12 @@ func getTestRequests() []struct {
{"DELETE", "/api/v1beta1/events/a" + syncFlags, "", code200}, {"DELETE", "/api/v1beta1/events/a" + syncFlags, "", code200},
// Normal methods on bindings // Normal methods on bindings
{"GET", "/api/v1beta1/bindings", "", code404}, // Bindings are write-only, so 404 {"GET", "/api/v1beta1/bindings", "", code405}, // Bindings are write-only
{"POST", "/api/v1beta1/pods" + syncFlags, aPod, code200}, // Need a pod to bind or you get a 404 {"POST", "/api/v1beta1/pods" + syncFlags, aPod, code200}, // Need a pod to bind or you get a 404
{"POST", "/api/v1beta1/bindings" + syncFlags, aBinding, code200}, {"POST", "/api/v1beta1/bindings" + syncFlags, aBinding, code200},
{"PUT", "/api/v1beta1/bindings/a" + syncFlags, aBinding, code500}, // See #2114 about why 500 {"PUT", "/api/v1beta1/bindings/a" + syncFlags, aBinding, code500}, // See #2114 about why 500
{"GET", "/api/v1beta1/bindings", "", code404}, {"GET", "/api/v1beta1/bindings", "", code405},
{"GET", "/api/v1beta1/bindings/a", "", code404}, {"GET", "/api/v1beta1/bindings/a", "", code404}, // No bindings instances
{"DELETE", "/api/v1beta1/bindings/a" + syncFlags, "", code404}, {"DELETE", "/api/v1beta1/bindings/a" + syncFlags, "", code404},
// Non-existent object type. // Non-existent object type.
...@@ -340,7 +341,8 @@ func getTestRequests() []struct { ...@@ -340,7 +341,8 @@ func getTestRequests() []struct {
{"GET", "/api/v1beta1/operations", "", code200}, {"GET", "/api/v1beta1/operations", "", code200},
{"GET", "/api/v1beta1/operations/1234567890", "", code404}, {"GET", "/api/v1beta1/operations/1234567890", "", code404},
// Special verbs on pods // Special verbs on nodes
// TODO: Will become 405 once these are converted to go-restful
{"GET", "/api/v1beta1/proxy/minions/a", "", code404}, {"GET", "/api/v1beta1/proxy/minions/a", "", code404},
{"GET", "/api/v1beta1/redirect/minions/a", "", code404}, {"GET", "/api/v1beta1/redirect/minions/a", "", code404},
// TODO: test .../watch/..., which doesn't end before the test timeout. // TODO: test .../watch/..., which doesn't end before the test timeout.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment