mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Merge pull request #835 from smarterclayton/apiserver_cleanup
Centralize path magic in apiserver into the New method
This commit is contained in:
commit
d52492111f
@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
@ -48,12 +49,11 @@ type Codec interface {
|
||||
//
|
||||
// TODO: consider migrating this to go-restful which is a more full-featured version of the same thing.
|
||||
type APIServer struct {
|
||||
prefix string
|
||||
storage map[string]RESTStorage
|
||||
codec Codec
|
||||
ops *Operations
|
||||
mux *http.ServeMux
|
||||
asyncOpWait time.Duration
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
// New creates a new APIServer object. 'storage' contains a map of handlers. 'codec'
|
||||
@ -65,31 +65,43 @@ type APIServer struct {
|
||||
// TODO: add multitype codec serialization
|
||||
func New(storage map[string]RESTStorage, codec Codec, prefix string) *APIServer {
|
||||
s := &APIServer{
|
||||
prefix: strings.TrimRight(prefix, "/"),
|
||||
storage: storage,
|
||||
codec: codec,
|
||||
ops: NewOperations(),
|
||||
mux: http.NewServeMux(),
|
||||
// Delay just long enough to handle most simple write operations
|
||||
asyncOpWait: time.Millisecond * 25,
|
||||
}
|
||||
|
||||
// Primary API methods
|
||||
s.mux.HandleFunc(s.prefix+"/", s.handleREST)
|
||||
s.mux.HandleFunc(s.watchPrefix()+"/", s.handleWatch)
|
||||
mux := http.NewServeMux()
|
||||
|
||||
prefix = strings.TrimRight(prefix, "/")
|
||||
|
||||
// Primary API handlers
|
||||
restPrefix := prefix + "/"
|
||||
mux.Handle(restPrefix, http.StripPrefix(restPrefix, http.HandlerFunc(s.handleREST)))
|
||||
|
||||
// Watch API handlers
|
||||
watchPrefix := path.Join(prefix, "watch") + "/"
|
||||
mux.Handle(watchPrefix, http.StripPrefix(watchPrefix, &WatchHandler{storage}))
|
||||
|
||||
// Support services for the apiserver
|
||||
s.mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/"))))
|
||||
healthz.InstallHandler(s.mux)
|
||||
s.mux.HandleFunc("/version", handleVersion)
|
||||
s.mux.HandleFunc("/", handleIndex)
|
||||
logsPrefix := "/logs/"
|
||||
mux.Handle(logsPrefix, http.StripPrefix(logsPrefix, http.FileServer(http.Dir("/var/log/"))))
|
||||
healthz.InstallHandler(mux)
|
||||
mux.HandleFunc("/version", handleVersion)
|
||||
mux.HandleFunc("/", handleIndex)
|
||||
|
||||
// Handle both operations and operations/* with the same handler
|
||||
s.mux.HandleFunc(s.operationPrefix(), s.handleOperation)
|
||||
s.mux.HandleFunc(s.operationPrefix()+"/", s.handleOperation)
|
||||
handler := &OperationHandler{s.ops, s.codec}
|
||||
operationPrefix := path.Join(prefix, "operations")
|
||||
mux.Handle(operationPrefix, http.StripPrefix(operationPrefix, handler))
|
||||
operationsPrefix := operationPrefix + "/"
|
||||
mux.Handle(operationsPrefix, http.StripPrefix(operationsPrefix, handler))
|
||||
|
||||
// Proxy minion requests
|
||||
s.mux.Handle("/proxy/minion/", http.StripPrefix("/proxy/minion", http.HandlerFunc(handleProxyMinion)))
|
||||
mux.Handle("/proxy/minion/", http.StripPrefix("/proxy/minion", http.HandlerFunc(handleProxyMinion)))
|
||||
|
||||
s.handler = mux
|
||||
|
||||
return s
|
||||
}
|
||||
@ -112,29 +124,25 @@ func (s *APIServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
),
|
||||
).Log()
|
||||
|
||||
// Dispatch via our mux.
|
||||
s.mux.ServeHTTP(w, req)
|
||||
// Dispatch to the internal handler
|
||||
s.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
// handleREST handles requests to all our RESTStorage objects.
|
||||
func (s *APIServer) handleREST(w http.ResponseWriter, req *http.Request) {
|
||||
if !strings.HasPrefix(req.URL.Path, s.prefix) {
|
||||
parts := splitPath(req.URL.Path)
|
||||
if len(parts) < 1 {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
requestParts := strings.Split(req.URL.Path[len(s.prefix):], "/")[1:]
|
||||
if len(requestParts) < 1 {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
storage := s.storage[requestParts[0]]
|
||||
storage := s.storage[parts[0]]
|
||||
if storage == nil {
|
||||
httplog.LogOf(w).Addf("'%v' has no storage object", requestParts[0])
|
||||
httplog.LogOf(w).Addf("'%v' has no storage object", parts[0])
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
s.handleRESTStorage(requestParts, req, w, storage)
|
||||
s.handleRESTStorage(parts, req, w, storage)
|
||||
}
|
||||
|
||||
// handleRESTStorage is the main dispatcher for a storage object. It switches on the HTTP method, and then
|
||||
@ -347,3 +355,12 @@ func readBody(req *http.Request) ([]byte, error) {
|
||||
defer req.Body.Close()
|
||||
return ioutil.ReadAll(req.Body)
|
||||
}
|
||||
|
||||
// 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, "/")
|
||||
}
|
||||
|
@ -18,10 +18,8 @@ package apiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -30,37 +28,25 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
func (s *APIServer) operationPrefix() string {
|
||||
return path.Join(s.prefix, "operations")
|
||||
type OperationHandler struct {
|
||||
ops *Operations
|
||||
codec Codec
|
||||
}
|
||||
|
||||
func (s *APIServer) handleOperation(w http.ResponseWriter, req *http.Request) {
|
||||
opPrefix := s.operationPrefix()
|
||||
if !strings.HasPrefix(req.URL.Path, opPrefix) {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
trimmed := strings.TrimLeft(req.URL.Path[len(opPrefix):], "/")
|
||||
parts := strings.Split(trimmed, "/")
|
||||
if trimmed == "" {
|
||||
parts = []string{}
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
func (h *OperationHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
parts := splitPath(req.URL.Path)
|
||||
if len(parts) > 1 || req.Method != "GET" {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
// List outstanding operations.
|
||||
list := s.ops.List()
|
||||
writeJSON(http.StatusOK, s.codec, list, w)
|
||||
list := h.ops.List()
|
||||
writeJSON(http.StatusOK, h.codec, list, w)
|
||||
return
|
||||
}
|
||||
|
||||
op := s.ops.Get(parts[0])
|
||||
op := h.ops.Get(parts[0])
|
||||
if op == nil {
|
||||
notFound(w, req)
|
||||
return
|
||||
@ -68,9 +54,9 @@ func (s *APIServer) handleOperation(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
obj, complete := op.StatusOrResult()
|
||||
if complete {
|
||||
writeJSON(http.StatusOK, s.codec, obj, w)
|
||||
writeJSON(http.StatusOK, h.codec, obj, w)
|
||||
} else {
|
||||
writeJSON(http.StatusAccepted, s.codec, obj, w)
|
||||
writeJSON(http.StatusAccepted, h.codec, obj, w)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,6 @@ package apiserver
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.net/websocket"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
@ -28,22 +26,17 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
func (s *APIServer) watchPrefix() string {
|
||||
return path.Join(s.prefix, "watch")
|
||||
type WatchHandler struct {
|
||||
storage map[string]RESTStorage
|
||||
}
|
||||
|
||||
// handleWatch processes a watch request
|
||||
func (s *APIServer) handleWatch(w http.ResponseWriter, req *http.Request) {
|
||||
prefix := s.watchPrefix()
|
||||
if !strings.HasPrefix(req.URL.Path, prefix) {
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
parts := strings.Split(req.URL.Path[len(prefix):], "/")[1:]
|
||||
if req.Method != "GET" || len(parts) < 1 {
|
||||
func (h *WatchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
parts := splitPath(req.URL.Path)
|
||||
if len(parts) < 1 || req.Method != "GET" {
|
||||
notFound(w, req)
|
||||
}
|
||||
storage := s.storage[parts[0]]
|
||||
storage := h.storage[parts[0]]
|
||||
if storage == nil {
|
||||
notFound(w, req)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user