Separate API router from server.
Implement basic interfaces to write custom routers that can be plugged to the server. Remove server coupling with the daemon. Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
144abf2a58
commit
da982cf551
32 changed files with 809 additions and 591 deletions
|
@ -1,57 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func boolValue(r *http.Request, k string) bool {
|
||||
s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
|
||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||
}
|
||||
|
||||
// boolValueOrDefault returns the default bool passed if the query param is
|
||||
// missing, otherwise it's just a proxy to boolValue above
|
||||
func boolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
if _, ok := r.Form[k]; !ok {
|
||||
return d
|
||||
}
|
||||
return boolValue(r, k)
|
||||
}
|
||||
|
||||
func int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
type archiveOptions struct {
|
||||
name string
|
||||
path string
|
||||
}
|
||||
|
||||
func archiveFormValues(r *http.Request, vars map[string]string) (archiveOptions, error) {
|
||||
if vars == nil {
|
||||
return archiveOptions{}, fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
return archiveOptions{}, err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
path := filepath.FromSlash(r.Form.Get("path"))
|
||||
|
||||
switch {
|
||||
case name == "":
|
||||
return archiveOptions{}, fmt.Errorf("bad parameter: 'name' cannot be empty")
|
||||
case path == "":
|
||||
return archiveOptions{}, fmt.Errorf("bad parameter: 'path' cannot be empty")
|
||||
}
|
||||
|
||||
return archiveOptions{name, path}, nil
|
||||
}
|
63
api/server/httputils/form.go
Normal file
63
api/server/httputils/form.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
func BoolValue(r *http.Request, k string) bool {
|
||||
s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
|
||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||
}
|
||||
|
||||
// BoolValueOrDefault returns the default bool passed if the query param is
|
||||
// missing, otherwise it's just a proxy to boolValue above
|
||||
func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
if _, ok := r.Form[k]; !ok {
|
||||
return d
|
||||
}
|
||||
return BoolValue(r, k)
|
||||
}
|
||||
|
||||
// Int64ValueOrZero parses a form value into a int64 type.
|
||||
// It returns 0 if the parsing fails.
|
||||
func Int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// ArchiveOptions stores archive information for different operations.
|
||||
type ArchiveOptions struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
|
||||
// It fails if the archive name and path are not in the request.
|
||||
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
|
||||
if vars == nil {
|
||||
return ArchiveOptions{}, fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := ParseForm(r); err != nil {
|
||||
return ArchiveOptions{}, err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
path := filepath.FromSlash(r.Form.Get("path"))
|
||||
|
||||
switch {
|
||||
case name == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'name' cannot be empty")
|
||||
case path == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'path' cannot be empty")
|
||||
}
|
||||
|
||||
return ArchiveOptions{name, path}, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -26,7 +26,7 @@ func TestBoolValue(t *testing.T) {
|
|||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := boolValue(r, "test")
|
||||
a := BoolValue(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func TestBoolValue(t *testing.T) {
|
|||
|
||||
func TestBoolValueOrDefault(t *testing.T) {
|
||||
r, _ := http.NewRequest("GET", "", nil)
|
||||
if !boolValueOrDefault(r, "queryparam", true) {
|
||||
if !BoolValueOrDefault(r, "queryparam", true) {
|
||||
t.Fatal("Expected to get true default value, got false")
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ func TestBoolValueOrDefault(t *testing.T) {
|
|||
v.Set("param", "")
|
||||
r, _ = http.NewRequest("GET", "", nil)
|
||||
r.Form = v
|
||||
if boolValueOrDefault(r, "param", true) {
|
||||
if BoolValueOrDefault(r, "param", true) {
|
||||
t.Fatal("Expected not to get true")
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func TestInt64ValueOrZero(t *testing.T) {
|
|||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := int64ValueOrZero(r, "test")
|
||||
a := Int64ValueOrZero(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
180
api/server/httputils/httputils.go
Normal file
180
api/server/httputils/httputils.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/pkg/version"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
// APIVersionKey is the client's requested API version.
|
||||
const APIVersionKey = "api-version"
|
||||
|
||||
// APIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
|
||||
// Any function that has the appropriate signature can be register as a API endpoint (e.g. getVersion).
|
||||
type APIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
|
||||
|
||||
// HijackConnection interrupts the http response writer to get the
|
||||
// underlying connection and operate with it.
|
||||
func HijackConnection(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Flush the options to make sure the client sets the raw mode
|
||||
conn.Write([]byte{})
|
||||
return conn, conn, nil
|
||||
}
|
||||
|
||||
// CloseStreams ensures that a list for http streams are properly closed.
|
||||
func CloseStreams(streams ...interface{}) {
|
||||
for _, stream := range streams {
|
||||
if tcpc, ok := stream.(interface {
|
||||
CloseWrite() error
|
||||
}); ok {
|
||||
tcpc.CloseWrite()
|
||||
} else if closer, ok := stream.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckForJSON makes sure that the request's Content-Type is application/json.
|
||||
func CheckForJSON(r *http.Request) error {
|
||||
ct := r.Header.Get("Content-Type")
|
||||
|
||||
// No Content-Type header is ok as long as there's no Body
|
||||
if ct == "" {
|
||||
if r.Body == nil || r.ContentLength == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise it better be json
|
||||
if api.MatchesContentType(ct, "application/json") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||
}
|
||||
|
||||
// ParseForm ensures the request form is parsed even with invalid content types.
|
||||
// If we don't do this, POST method without Content-type (even with empty body) will fail.
|
||||
func ParseForm(r *http.Request) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseMultipartForm ensure the request form is parsed, even with invalid content types.
|
||||
func ParseMultipartForm(r *http.Request) error {
|
||||
if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteError decodes a specific docker error and sends it in the response.
|
||||
func WriteError(w http.ResponseWriter, err error) {
|
||||
if err == nil || w == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
|
||||
return
|
||||
}
|
||||
|
||||
statusCode := http.StatusInternalServerError
|
||||
errMsg := err.Error()
|
||||
|
||||
// Based on the type of error we get we need to process things
|
||||
// slightly differently to extract the error message.
|
||||
// In the 'errcode.*' cases there are two different type of
|
||||
// error that could be returned. errocode.ErrorCode is the base
|
||||
// type of error object - it is just an 'int' that can then be
|
||||
// used as the look-up key to find the message. errorcode.Error
|
||||
// extends errorcode.Error by adding error-instance specific
|
||||
// data, like 'details' or variable strings to be inserted into
|
||||
// the message.
|
||||
//
|
||||
// Ideally, we should just be able to call err.Error() for all
|
||||
// cases but the errcode package doesn't support that yet.
|
||||
//
|
||||
// Additionally, in both errcode cases, there might be an http
|
||||
// status code associated with it, and if so use it.
|
||||
switch err.(type) {
|
||||
case errcode.ErrorCode:
|
||||
daError, _ := err.(errcode.ErrorCode)
|
||||
statusCode = daError.Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message()
|
||||
|
||||
case errcode.Error:
|
||||
// For reference, if you're looking for a particular error
|
||||
// then you can do something like :
|
||||
// import ( derr "github.com/docker/docker/errors" )
|
||||
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
|
||||
|
||||
daError, _ := err.(errcode.Error)
|
||||
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message
|
||||
|
||||
default:
|
||||
// This part of will be removed once we've
|
||||
// converted everything over to use the errcode package
|
||||
|
||||
// FIXME: this is brittle and should not be necessary.
|
||||
// If we need to differentiate between different possible error types,
|
||||
// we should create appropriate error types with clearly defined meaning
|
||||
errStr := strings.ToLower(err.Error())
|
||||
for keyword, status := range map[string]int{
|
||||
"not found": http.StatusNotFound,
|
||||
"no such": http.StatusNotFound,
|
||||
"bad parameter": http.StatusBadRequest,
|
||||
"conflict": http.StatusConflict,
|
||||
"impossible": http.StatusNotAcceptable,
|
||||
"wrong login/password": http.StatusUnauthorized,
|
||||
"hasn't been activated": http.StatusForbidden,
|
||||
} {
|
||||
if strings.Contains(errStr, keyword) {
|
||||
statusCode = status
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": utils.GetErrorMessage(err)}).Error("HTTP Error")
|
||||
http.Error(w, errMsg, statusCode)
|
||||
}
|
||||
|
||||
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
|
||||
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
// VersionFromContext returns an API version from the context using APIVersionKey.
|
||||
// It panics if the context value does not have version.Version type.
|
||||
func VersionFromContext(ctx context.Context) (ver version.Version) {
|
||||
if ctx == nil {
|
||||
return
|
||||
}
|
||||
val := ctx.Value(APIVersionKey)
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
return val.(version.Version)
|
||||
}
|
|
@ -7,21 +7,19 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/pkg/version"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// apiVersionKey is the client's requested API version.
|
||||
const apiVersionKey = "api-version"
|
||||
|
||||
// middleware is an adapter to allow the use of ordinary functions as Docker API filters.
|
||||
// Any function that has the appropriate signature can be register as a middleware.
|
||||
type middleware func(handler HTTPAPIFunc) HTTPAPIFunc
|
||||
type middleware func(handler httputils.APIFunc) httputils.APIFunc
|
||||
|
||||
// loggingMiddleware logs each request when logging is enabled.
|
||||
func (s *Server) loggingMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
||||
func (s *Server) loggingMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if s.cfg.Logging {
|
||||
logrus.Infof("%s %s", r.Method, r.RequestURI)
|
||||
|
@ -31,7 +29,7 @@ func (s *Server) loggingMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
}
|
||||
|
||||
// userAgentMiddleware checks the User-Agent header looking for a valid docker client spec.
|
||||
func (s *Server) userAgentMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
||||
func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
|
||||
dockerVersion := version.Version(s.cfg.Version)
|
||||
|
@ -53,7 +51,7 @@ func (s *Server) userAgentMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
}
|
||||
|
||||
// corsMiddleware sets the CORS header expectations in the server.
|
||||
func (s *Server) corsMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
||||
func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
|
||||
// otherwise, all head values will be passed to HTTP handler
|
||||
|
@ -70,7 +68,7 @@ func (s *Server) corsMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
}
|
||||
|
||||
// versionMiddleware checks the api version requirements before passing the request to the server handler.
|
||||
func versionMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
||||
func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
apiVersion := version.Version(vars["version"])
|
||||
if apiVersion == "" {
|
||||
|
@ -85,7 +83,7 @@ func versionMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
}
|
||||
|
||||
w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
|
||||
ctx = context.WithValue(ctx, apiVersionKey, apiVersion)
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +101,8 @@ func versionMiddleware(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
// )
|
||||
// )
|
||||
// )
|
||||
func (s *Server) handleWithGlobalMiddlewares(handler HTTPAPIFunc) HTTPAPIFunc {
|
||||
// )
|
||||
func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
|
||||
middlewares := []middleware{
|
||||
versionMiddleware,
|
||||
s.corsMiddleware,
|
||||
|
@ -117,16 +116,3 @@ func (s *Server) handleWithGlobalMiddlewares(handler HTTPAPIFunc) HTTPAPIFunc {
|
|||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// versionFromContext returns an API version from the context using apiVersionKey.
|
||||
// It panics if the context value does not have version.Version type.
|
||||
func versionFromContext(ctx context.Context) (ver version.Version) {
|
||||
if ctx == nil {
|
||||
return
|
||||
}
|
||||
val := ctx.Value(apiVersionKey)
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
return val.(version.Version)
|
||||
}
|
||||
|
|
|
@ -6,13 +6,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestVersionMiddleware(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if versionFromContext(ctx) == "" {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
|
@ -30,7 +31,7 @@ func TestVersionMiddleware(t *testing.T) {
|
|||
|
||||
func TestVersionMiddlewareWithErrors(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if versionFromContext(ctx) == "" {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *Server) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var config *cliconfig.AuthConfig
|
||||
err := json.NewDecoder(r.Body).Decode(&config)
|
||||
r.Body.Close()
|
||||
|
@ -20,7 +21,7 @@ func (s *Server) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Re
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, &types.AuthResponse{
|
||||
return httputils.WriteJSON(w, http.StatusOK, &types.AuthResponse{
|
||||
Status: status,
|
||||
})
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon"
|
||||
derr "github.com/docker/docker/errors"
|
||||
|
@ -22,14 +23,14 @@ import (
|
|||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := &daemon.ContainersConfig{
|
||||
All: boolValue(r, "all"),
|
||||
Size: boolValue(r, "size"),
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Size: httputils.BoolValue(r, "size"),
|
||||
Since: r.Form.Get("since"),
|
||||
Before: r.Form.Get("before"),
|
||||
Filters: r.Form.Get("filters"),
|
||||
|
@ -48,18 +49,18 @@ func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, containers)
|
||||
return httputils.WriteJSON(w, http.StatusOK, containers)
|
||||
}
|
||||
|
||||
func (s *Server) getContainersStats(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
stream := boolValueOrDefault(r, "stream", true)
|
||||
stream := httputils.BoolValueOrDefault(r, "stream", true)
|
||||
var out io.Writer
|
||||
if !stream {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
@ -77,14 +78,14 @@ func (s *Server) getContainersStats(ctx context.Context, w http.ResponseWriter,
|
|||
Stream: stream,
|
||||
OutStream: out,
|
||||
Stop: closeNotifier,
|
||||
Version: versionFromContext(ctx),
|
||||
Version: httputils.VersionFromContext(ctx),
|
||||
}
|
||||
|
||||
return s.daemon.ContainerStats(vars["name"], config)
|
||||
}
|
||||
|
||||
func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -96,7 +97,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
|
|||
// daemon is going to stream. By sending this initial HTTP 200 we can't report
|
||||
// any error after the stream starts (i.e. container not found, wrong parameters)
|
||||
// with the appropriate status code.
|
||||
stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
|
||||
stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
|
||||
if !(stdout || stderr) {
|
||||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
@ -127,8 +128,8 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
|
|||
outStream.Write(nil)
|
||||
|
||||
logsConfig := &daemon.ContainerLogsConfig{
|
||||
Follow: boolValue(r, "follow"),
|
||||
Timestamps: boolValue(r, "timestamps"),
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: since,
|
||||
Tail: r.Form.Get("tail"),
|
||||
UseStdout: stdout,
|
||||
|
@ -147,7 +148,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ func (s *Server) getContainersExport(ctx context.Context, w http.ResponseWriter,
|
|||
return s.daemon.ContainerExport(vars["name"], w)
|
||||
}
|
||||
|
||||
func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -168,7 +169,7 @@ func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter,
|
|||
// allow a nil body for backwards compatibility
|
||||
var hostConfig *runconfig.HostConfig
|
||||
if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -187,8 +188,8 @@ func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -205,11 +206,11 @@ func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -231,7 +232,7 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
|
|||
// Return error that's not caused because the container is stopped.
|
||||
// Return error if the container is not running and the api is >= 1.20
|
||||
// to keep backwards compatibility.
|
||||
version := versionFromContext(ctx)
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if version.GreaterThanOrEqualTo("1.20") || !isStopped {
|
||||
return fmt.Errorf("Cannot kill container %s: %v", name, err)
|
||||
}
|
||||
|
@ -241,8 +242,8 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersRestart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -260,11 +261,11 @@ func (s *Server) postContainersRestart(ctx context.Context, w http.ResponseWrite
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -277,11 +278,11 @@ func (s *Server) postContainersPause(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -294,7 +295,7 @@ func (s *Server) postContainersUnpause(ctx context.Context, w http.ResponseWrite
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -304,12 +305,12 @@ func (s *Server) postContainersWait(ctx context.Context, w http.ResponseWriter,
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
|
||||
return httputils.WriteJSON(w, http.StatusOK, &types.ContainerWaitResponse{
|
||||
StatusCode: status,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -319,15 +320,15 @@ func (s *Server) getContainersChanges(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, changes)
|
||||
return httputils.WriteJSON(w, http.StatusOK, changes)
|
||||
}
|
||||
|
||||
func (s *Server) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -336,11 +337,11 @@ func (s *Server) getContainersTop(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, procList)
|
||||
return httputils.WriteJSON(w, http.StatusOK, procList)
|
||||
}
|
||||
|
||||
func (s *Server) postContainerRename(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainerRename(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -356,11 +357,11 @@ func (s *Server) postContainerRename(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -370,7 +371,7 @@ func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version := versionFromContext(ctx)
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
adjustCPUShares := version.LessThan("1.19")
|
||||
|
||||
ccr, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
|
||||
|
@ -378,11 +379,11 @@ func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusCreated, ccr)
|
||||
return httputils.WriteJSON(w, http.StatusCreated, ccr)
|
||||
}
|
||||
|
||||
func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -391,9 +392,9 @@ func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
name := vars["name"]
|
||||
config := &daemon.ContainerRmConfig{
|
||||
ForceRemove: boolValue(r, "force"),
|
||||
RemoveVolume: boolValue(r, "v"),
|
||||
RemoveLink: boolValue(r, "link"),
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
RemoveVolume: httputils.BoolValue(r, "v"),
|
||||
RemoveLink: httputils.BoolValue(r, "link"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerRm(name, config); err != nil {
|
||||
|
@ -409,8 +410,8 @@ func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainersResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainersResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -429,8 +430,8 @@ func (s *Server) postContainersResize(ctx context.Context, w http.ResponseWriter
|
|||
return s.daemon.ContainerResize(vars["name"], height, width)
|
||||
}
|
||||
|
||||
func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -442,11 +443,11 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter
|
|||
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
|
||||
}
|
||||
|
||||
inStream, outStream, err := hijackServer(w)
|
||||
inStream, outStream, err := httputils.HijackConnection(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeStreams(inStream, outStream)
|
||||
defer httputils.CloseStreams(inStream, outStream)
|
||||
|
||||
if _, ok := r.Header["Upgrade"]; ok {
|
||||
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
|
||||
|
@ -457,11 +458,11 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter
|
|||
attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
|
||||
InStream: inStream,
|
||||
OutStream: outStream,
|
||||
UseStdin: boolValue(r, "stdin"),
|
||||
UseStdout: boolValue(r, "stdout"),
|
||||
UseStderr: boolValue(r, "stderr"),
|
||||
Logs: boolValue(r, "logs"),
|
||||
Stream: boolValue(r, "stream"),
|
||||
UseStdin: httputils.BoolValue(r, "stdin"),
|
||||
UseStdout: httputils.BoolValue(r, "stdout"),
|
||||
UseStderr: httputils.BoolValue(r, "stderr"),
|
||||
Logs: httputils.BoolValue(r, "logs"),
|
||||
Stream: httputils.BoolValue(r, "stream"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil {
|
||||
|
@ -471,8 +472,8 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -491,8 +492,8 @@ func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
|
|||
InStream: ws,
|
||||
OutStream: ws,
|
||||
ErrStream: ws,
|
||||
Logs: boolValue(r, "logs"),
|
||||
Stream: boolValue(r, "stream"),
|
||||
Logs: httputils.BoolValue(r, "logs"),
|
||||
Stream: httputils.BoolValue(r, "stream"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerWsAttachWithLogs(containerName, wsAttachWithLogsConfig); err != nil {
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
@ -9,17 +9,18 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// postContainersCopy is deprecated in favor of getContainersArchive.
|
||||
func (s *Server) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -68,13 +69,13 @@ func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Heade
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := archiveFormValues(r, vars)
|
||||
func (s *router) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stat, err := s.daemon.ContainerStatPath(v.name, v.path)
|
||||
stat, err := s.daemon.ContainerStatPath(v.Name, v.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -82,13 +83,13 @@ func (s *Server) headContainersArchive(ctx context.Context, w http.ResponseWrite
|
|||
return setContainerPathStatHeader(stat, w.Header())
|
||||
}
|
||||
|
||||
func (s *Server) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := archiveFormValues(r, vars)
|
||||
func (s *router) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
|
||||
tarArchive, stat, err := s.daemon.ContainerArchivePath(v.Name, v.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,12 +105,12 @@ func (s *Server) getContainersArchive(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *Server) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := archiveFormValues(r, vars)
|
||||
func (s *router) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
|
||||
return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
|
||||
noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
|
||||
return s.daemon.ContainerExtractToDir(v.Name, v.Path, noOverwriteDirNonDir, r.Body)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -8,13 +8,14 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *Server) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter 'id'")
|
||||
}
|
||||
|
@ -24,14 +25,14 @@ func (s *Server) getExecByID(ctx context.Context, w http.ResponseWriter, r *http
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, eConfig)
|
||||
return httputils.WriteJSON(w, http.StatusOK, eConfig)
|
||||
}
|
||||
|
||||
func (s *Server) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
name := vars["name"]
|
||||
|
@ -53,14 +54,14 @@ func (s *Server) postContainerExecCreate(ctx context.Context, w http.ResponseWri
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
|
||||
func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
|
@ -77,11 +78,11 @@ func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWrit
|
|||
if !execStartCheck.Detach {
|
||||
var err error
|
||||
// Setting up the streaming http interface.
|
||||
inStream, outStream, err = hijackServer(w)
|
||||
inStream, outStream, err = httputils.HijackConnection(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeStreams(inStream, outStream)
|
||||
defer httputils.CloseStreams(inStream, outStream)
|
||||
|
||||
if _, ok := r.Header["Upgrade"]; ok {
|
||||
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
|
||||
|
@ -106,8 +107,8 @@ func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWrit
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
|
@ -23,19 +24,19 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *Server) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cname := r.Form.Get("container")
|
||||
|
||||
pause := boolValue(r, "pause")
|
||||
version := versionFromContext(ctx)
|
||||
pause := httputils.BoolValue(r, "pause")
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
|
||||
pause = true
|
||||
}
|
||||
|
@ -60,14 +61,14 @@ func (s *Server) postCommit(ctx context.Context, w http.ResponseWriter, r *http.
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
|
||||
ID: imgID,
|
||||
})
|
||||
}
|
||||
|
||||
// Creates an image from Pull or from Import
|
||||
func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -142,7 +143,7 @@ func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -153,7 +154,7 @@ func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
|
|||
metaHeaders[k] = v
|
||||
}
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
authConfig := &cliconfig.AuthConfig{}
|
||||
|
@ -194,11 +195,11 @@ func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -222,12 +223,12 @@ func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return s.daemon.Repositories().Load(r.Body, w)
|
||||
}
|
||||
|
||||
func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -240,18 +241,18 @@ func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
|
|||
return fmt.Errorf("image name cannot be blank")
|
||||
}
|
||||
|
||||
force := boolValue(r, "force")
|
||||
prune := !boolValue(r, "noprune")
|
||||
force := httputils.BoolValue(r, "force")
|
||||
prune := !httputils.BoolValue(r, "noprune")
|
||||
|
||||
list, err := s.daemon.ImageDelete(name, force, prune)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, list)
|
||||
return httputils.WriteJSON(w, http.StatusOK, list)
|
||||
}
|
||||
|
||||
func (s *Server) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -261,10 +262,10 @@ func (s *Server) getImagesByName(ctx context.Context, w http.ResponseWriter, r *
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, imageInspect)
|
||||
return httputils.WriteJSON(w, http.StatusOK, imageInspect)
|
||||
}
|
||||
|
||||
func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var (
|
||||
authConfigs = map[string]cliconfig.AuthConfig{}
|
||||
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
||||
|
@ -282,15 +283,15 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
version := versionFromContext(ctx)
|
||||
if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
|
||||
buildConfig.Remove = true
|
||||
} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
|
||||
buildConfig.Remove = true
|
||||
} else {
|
||||
buildConfig.Remove = boolValue(r, "rm")
|
||||
buildConfig.Remove = httputils.BoolValue(r, "rm")
|
||||
}
|
||||
if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
|
||||
if httputils.BoolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
|
||||
buildConfig.Pull = true
|
||||
}
|
||||
|
||||
|
@ -301,15 +302,15 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
buildConfig.RemoteURL = r.FormValue("remote")
|
||||
buildConfig.DockerfileName = r.FormValue("dockerfile")
|
||||
buildConfig.RepoName = r.FormValue("t")
|
||||
buildConfig.SuppressOutput = boolValue(r, "q")
|
||||
buildConfig.NoCache = boolValue(r, "nocache")
|
||||
buildConfig.ForceRemove = boolValue(r, "forcerm")
|
||||
buildConfig.SuppressOutput = httputils.BoolValue(r, "q")
|
||||
buildConfig.NoCache = httputils.BoolValue(r, "nocache")
|
||||
buildConfig.ForceRemove = httputils.BoolValue(r, "forcerm")
|
||||
buildConfig.AuthConfigs = authConfigs
|
||||
buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
|
||||
buildConfig.Memory = int64ValueOrZero(r, "memory")
|
||||
buildConfig.CPUShares = int64ValueOrZero(r, "cpushares")
|
||||
buildConfig.CPUPeriod = int64ValueOrZero(r, "cpuperiod")
|
||||
buildConfig.CPUQuota = int64ValueOrZero(r, "cpuquota")
|
||||
buildConfig.MemorySwap = httputils.Int64ValueOrZero(r, "memswap")
|
||||
buildConfig.Memory = httputils.Int64ValueOrZero(r, "memory")
|
||||
buildConfig.CPUShares = httputils.Int64ValueOrZero(r, "cpushares")
|
||||
buildConfig.CPUPeriod = httputils.Int64ValueOrZero(r, "cpuperiod")
|
||||
buildConfig.CPUQuota = httputils.Int64ValueOrZero(r, "cpuquota")
|
||||
buildConfig.CPUSetCpus = r.FormValue("cpusetcpus")
|
||||
buildConfig.CPUSetMems = r.FormValue("cpusetmems")
|
||||
buildConfig.CgroupParent = r.FormValue("cgroupparent")
|
||||
|
@ -358,21 +359,21 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: The filter parameter could just be a match filter
|
||||
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
|
||||
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, images)
|
||||
return httputils.WriteJSON(w, http.StatusOK, images)
|
||||
}
|
||||
|
||||
func (s *Server) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -383,11 +384,11 @@ func (s *Server) getImagesHistory(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, history)
|
||||
return httputils.WriteJSON(w, http.StatusOK, history)
|
||||
}
|
||||
|
||||
func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if vars == nil {
|
||||
|
@ -396,7 +397,7 @@ func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
|
||||
repo := r.Form.Get("repo")
|
||||
tag := r.Form.Get("tag")
|
||||
force := boolValue(r, "force")
|
||||
force := httputils.BoolValue(r, "force")
|
||||
name := vars["name"]
|
||||
if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
|
||||
return err
|
||||
|
@ -406,8 +407,8 @@ func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
|
@ -433,5 +434,5 @@ func (s *Server) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, query.Results)
|
||||
return httputils.WriteJSON(w, http.StatusOK, query.Results)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v := &types.Version{
|
||||
Version: dockerversion.VERSION,
|
||||
APIVersion: api.Version,
|
||||
|
@ -31,7 +32,7 @@ func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.
|
|||
BuildTime: dockerversion.BUILDTIME,
|
||||
}
|
||||
|
||||
version := versionFromContext(ctx)
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
if version.GreaterThanOrEqualTo("1.19") {
|
||||
v.Experimental = utils.ExperimentalBuild()
|
||||
|
@ -41,20 +42,20 @@ func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.
|
|||
v.KernelVersion = kernelVersion.String()
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, v)
|
||||
return httputils.WriteJSON(w, http.StatusOK, v)
|
||||
}
|
||||
|
||||
func (s *Server) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info, err := s.daemon.SystemInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, info)
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
||||
func (s *Server) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
var since int64 = -1
|
|
@ -1,14 +1,15 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// getContainersByName inspects containers configuration and serializes it as json.
|
||||
func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *router) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
@ -16,7 +17,7 @@ func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter,
|
|||
var json interface{}
|
||||
var err error
|
||||
|
||||
version := versionFromContext(ctx)
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
switch {
|
||||
case version.LessThan("1.20"):
|
||||
|
@ -31,5 +32,5 @@ func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter,
|
|||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, json)
|
||||
return httputils.WriteJSON(w, http.StatusOK, json)
|
||||
}
|
161
api/server/router/local/local.go
Normal file
161
api/server/router/local/local.go
Normal file
|
@ -0,0 +1,161 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
dkrouter "github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// router is a docker router that talks with the local docker daemon.
|
||||
type router struct {
|
||||
daemon *daemon.Daemon
|
||||
routes []dkrouter.Route
|
||||
}
|
||||
|
||||
// localRoute defines an individual API route to connect with the docker daemon.
|
||||
// It implements router.Route.
|
||||
type localRoute struct {
|
||||
method string
|
||||
path string
|
||||
handler httputils.APIFunc
|
||||
}
|
||||
|
||||
// Handler returns the APIFunc to let the server wrap it in middlewares
|
||||
func (l localRoute) Handler() httputils.APIFunc {
|
||||
return l.handler
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (l localRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
logrus.Debugf("Registering %s, %s", l.method, l.path)
|
||||
m.Path(dkrouter.VersionMatcher + l.path).Methods(l.method).Handler(handler)
|
||||
m.Path(l.path).Methods(l.method).Handler(handler)
|
||||
}
|
||||
|
||||
// NewRoute initialies a new local route for the reouter
|
||||
func NewRoute(method, path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return localRoute{method, path, handler}
|
||||
}
|
||||
|
||||
// NewGetRoute initializes a new route with the http method GET.
|
||||
func NewGetRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("GET", path, handler)
|
||||
}
|
||||
|
||||
// NewPostRoute initializes a new route with the http method POST.
|
||||
func NewPostRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("POST", path, handler)
|
||||
}
|
||||
|
||||
// NewPutRoute initializes a new route with the http method PUT.
|
||||
func NewPutRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("PUT", path, handler)
|
||||
}
|
||||
|
||||
// NewDeleteRoute initializes a new route with the http method DELETE.
|
||||
func NewDeleteRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// NewOptionsRoute initializes a new route with the http method OPTIONS
|
||||
func NewOptionsRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
// NewHeadRoute initializes a new route with the http method HEAD.
|
||||
func NewHeadRoute(path string, handler httputils.APIFunc) dkrouter.Route {
|
||||
return NewRoute("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// NewRouter initializes a local router with a new daemon.
|
||||
func NewRouter(daemon *daemon.Daemon) dkrouter.Router {
|
||||
r := &router{
|
||||
daemon: daemon,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the list of routes registered in the router.
|
||||
func (r *router) Routes() []dkrouter.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
// initRoutes initializes the routes in this router
|
||||
func (r *router) initRoutes() {
|
||||
r.routes = []dkrouter.Route{
|
||||
// HEAD
|
||||
NewHeadRoute("/containers/{name:.*}/archive", r.headContainersArchive),
|
||||
// OPTIONS
|
||||
NewOptionsRoute("/", optionsHandler),
|
||||
// GET
|
||||
NewGetRoute("/_ping", pingHandler),
|
||||
NewGetRoute("/events", r.getEvents),
|
||||
NewGetRoute("/info", r.getInfo),
|
||||
NewGetRoute("/version", r.getVersion),
|
||||
NewGetRoute("/images/json", r.getImagesJSON),
|
||||
NewGetRoute("/images/search", r.getImagesSearch),
|
||||
NewGetRoute("/images/get", r.getImagesGet),
|
||||
NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
|
||||
NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
|
||||
NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
|
||||
NewGetRoute("/containers/json", r.getContainersJSON),
|
||||
NewGetRoute("/containers/{name:.*}/export", r.getContainersExport),
|
||||
NewGetRoute("/containers/{name:.*}/changes", r.getContainersChanges),
|
||||
NewGetRoute("/containers/{name:.*}/json", r.getContainersByName),
|
||||
NewGetRoute("/containers/{name:.*}/top", r.getContainersTop),
|
||||
NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs),
|
||||
NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats),
|
||||
NewGetRoute("/containers/{name:.*}/attach/ws", r.wsContainersAttach),
|
||||
NewGetRoute("/exec/{id:.*}/json", r.getExecByID),
|
||||
NewGetRoute("/containers/{name:.*}/archive", r.getContainersArchive),
|
||||
NewGetRoute("/volumes", r.getVolumesList),
|
||||
NewGetRoute("/volumes/{name:.*}", r.getVolumeByName),
|
||||
// POST
|
||||
NewPostRoute("/auth", r.postAuth),
|
||||
NewPostRoute("/commit", r.postCommit),
|
||||
NewPostRoute("/build", r.postBuild),
|
||||
NewPostRoute("/images/create", r.postImagesCreate),
|
||||
NewPostRoute("/images/load", r.postImagesLoad),
|
||||
NewPostRoute("/images/{name:.*}/push", r.postImagesPush),
|
||||
NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
|
||||
NewPostRoute("/containers/create", r.postContainersCreate),
|
||||
NewPostRoute("/containers/{name:.*}/kill", r.postContainersKill),
|
||||
NewPostRoute("/containers/{name:.*}/pause", r.postContainersPause),
|
||||
NewPostRoute("/containers/{name:.*}/unpause", r.postContainersUnpause),
|
||||
NewPostRoute("/containers/{name:.*}/restart", r.postContainersRestart),
|
||||
NewPostRoute("/containers/{name:.*}/start", r.postContainersStart),
|
||||
NewPostRoute("/containers/{name:.*}/stop", r.postContainersStop),
|
||||
NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
|
||||
NewPostRoute("/containers/{name:.*}/resize", r.postContainersResize),
|
||||
NewPostRoute("/containers/{name:.*}/attach", r.postContainersAttach),
|
||||
NewPostRoute("/containers/{name:.*}/copy", r.postContainersCopy),
|
||||
NewPostRoute("/containers/{name:.*}/exec", r.postContainerExecCreate),
|
||||
NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
|
||||
NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
|
||||
NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
|
||||
NewPostRoute("/volumes", r.postVolumesCreate),
|
||||
// PUT
|
||||
NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
|
||||
// DELETE
|
||||
NewDeleteRoute("/containers/{name:.*}", r.deleteContainers),
|
||||
NewDeleteRoute("/images/{name:.*}", r.deleteImages),
|
||||
NewDeleteRoute("/volumes/{name:.*}", r.deleteVolumes),
|
||||
}
|
||||
}
|
||||
|
||||
func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
_, err := w.Write([]byte{'O', 'K'})
|
||||
return err
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
package server
|
||||
package local
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *Server) getVolumesList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getVolumesList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -17,11 +18,11 @@ func (s *Server) getVolumesList(ctx context.Context, w http.ResponseWriter, r *h
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
|
||||
return httputils.WriteJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
|
||||
}
|
||||
|
||||
func (s *Server) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -29,15 +30,15 @@ func (s *Server) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, v)
|
||||
return httputils.WriteJSON(w, http.StatusOK, v)
|
||||
}
|
||||
|
||||
func (s *Server) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkForJSON(r); err != nil {
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -50,11 +51,11 @@ func (s *Server) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeJSON(w, http.StatusCreated, volume)
|
||||
return httputils.WriteJSON(w, http.StatusCreated, volume)
|
||||
}
|
||||
|
||||
func (s *Server) deleteVolumes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
func (s *router) deleteVolumes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.daemon.VolumeRm(vars["name"]); err != nil {
|
26
api/server/router/network/network.go
Normal file
26
api/server/router/network/network.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
)
|
||||
|
||||
// networkRouter is a router to talk with the network controller
|
||||
type networkRouter struct {
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the network controller
|
||||
func (n networkRouter) Routes() []router.Route {
|
||||
return n.routes
|
||||
}
|
||||
|
||||
type networkRoute struct {
|
||||
path string
|
||||
handler httputils.APIFunc
|
||||
}
|
||||
|
||||
// Handler returns the APIFunc to let the server wrap it in middlewares
|
||||
func (l networkRoute) Handler() httputils.APIFunc {
|
||||
return l.handler
|
||||
}
|
51
api/server/router/network/network_experimental.go
Normal file
51
api/server/router/network/network_experimental.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// +build experimental
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/libnetwork/api"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var httpMethods = []string{"GET", "POST", "PUT", "DELETE"}
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(d *daemon.Daemon) router.Router {
|
||||
c := d.NetworkController()
|
||||
if c == nil {
|
||||
return networkRouter{}
|
||||
}
|
||||
|
||||
var routes []router.Route
|
||||
netHandler := api.NewHTTPHandler(c)
|
||||
|
||||
// TODO: libnetwork should stop hijacking request/response.
|
||||
// It should define API functions to add normally to the router.
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
netHandler(w, r)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, path := range []string{"/networks", "/services", "/sandboxes"} {
|
||||
routes = append(routes, networkRoute{path, handler})
|
||||
}
|
||||
|
||||
return networkRouter{routes}
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
logrus.Debugf("Registering %s, %v", n.path, httpMethods)
|
||||
subrouter := m.PathPrefix(router.VersionMatcher + n.path).Subrouter()
|
||||
subrouter.Methods(httpMethods...).Handler(handler)
|
||||
|
||||
subrouter = m.PathPrefix(n.path).Subrouter()
|
||||
subrouter.Methods(httpMethods...).Handler(handler)
|
||||
}
|
20
api/server/router/network/network_stable.go
Normal file
20
api/server/router/network/network_stable.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
// +build !experimental
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(d *daemon.Daemon) router.Router {
|
||||
return networkRouter{}
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
}
|
25
api/server/router/router.go
Normal file
25
api/server/router/router.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// VersionMatcher defines a variable matcher to be parsed by the router
|
||||
// when a request is about to be served.
|
||||
const VersionMatcher = "/v{version:[0-9.]+}"
|
||||
|
||||
// Router defines an interface to specify a group of routes to add the the docker server.
|
||||
type Router interface {
|
||||
Routes() []Route
|
||||
}
|
||||
|
||||
// Route defines an individual API route in the docker server.
|
||||
type Route interface {
|
||||
// Register adds the handler route to the docker mux.
|
||||
Register(*mux.Router, http.Handler)
|
||||
// Handler returns the raw function to create the http handler.
|
||||
Handler() httputils.APIFunc
|
||||
}
|
|
@ -2,17 +2,17 @@ package server
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/server/router/local"
|
||||
"github.com/docker/docker/api/server/router/network"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/sockets"
|
||||
"github.com/docker/docker/utils"
|
||||
|
@ -32,21 +32,18 @@ type Config struct {
|
|||
|
||||
// Server contains instance details for the server
|
||||
type Server struct {
|
||||
daemon *daemon.Daemon
|
||||
cfg *Config
|
||||
router *mux.Router
|
||||
start chan struct{}
|
||||
servers []serverCloser
|
||||
routers []router.Router
|
||||
}
|
||||
|
||||
// New returns a new instance of the server based on the specified configuration.
|
||||
func New(cfg *Config) *Server {
|
||||
srv := &Server{
|
||||
return &Server{
|
||||
cfg: cfg,
|
||||
start: make(chan struct{}),
|
||||
}
|
||||
srv.router = createRouter(srv)
|
||||
return srv
|
||||
}
|
||||
|
||||
// Close closes servers and thus stop receiving requests
|
||||
|
@ -118,152 +115,6 @@ func (s *HTTPServer) Close() error {
|
|||
return s.l.Close()
|
||||
}
|
||||
|
||||
// HTTPAPIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
|
||||
// Any function that has the appropriate signature can be register as a API endpoint (e.g. getVersion).
|
||||
type HTTPAPIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
|
||||
|
||||
func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Flush the options to make sure the client sets the raw mode
|
||||
conn.Write([]byte{})
|
||||
return conn, conn, nil
|
||||
}
|
||||
|
||||
func closeStreams(streams ...interface{}) {
|
||||
for _, stream := range streams {
|
||||
if tcpc, ok := stream.(interface {
|
||||
CloseWrite() error
|
||||
}); ok {
|
||||
tcpc.CloseWrite()
|
||||
} else if closer, ok := stream.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkForJSON makes sure that the request's Content-Type is application/json.
|
||||
func checkForJSON(r *http.Request) error {
|
||||
ct := r.Header.Get("Content-Type")
|
||||
|
||||
// No Content-Type header is ok as long as there's no Body
|
||||
if ct == "" {
|
||||
if r.Body == nil || r.ContentLength == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise it better be json
|
||||
if api.MatchesContentType(ct, "application/json") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||
}
|
||||
|
||||
//If we don't do this, POST method without Content-type (even with empty body) will fail
|
||||
func parseForm(r *http.Request) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMultipartForm(r *http.Request) error {
|
||||
if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func httpError(w http.ResponseWriter, err error) {
|
||||
if err == nil || w == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
|
||||
return
|
||||
}
|
||||
|
||||
statusCode := http.StatusInternalServerError
|
||||
errMsg := err.Error()
|
||||
|
||||
// Based on the type of error we get we need to process things
|
||||
// slightly differently to extract the error message.
|
||||
// In the 'errcode.*' cases there are two different type of
|
||||
// error that could be returned. errocode.ErrorCode is the base
|
||||
// type of error object - it is just an 'int' that can then be
|
||||
// used as the look-up key to find the message. errorcode.Error
|
||||
// extends errorcode.Error by adding error-instance specific
|
||||
// data, like 'details' or variable strings to be inserted into
|
||||
// the message.
|
||||
//
|
||||
// Ideally, we should just be able to call err.Error() for all
|
||||
// cases but the errcode package doesn't support that yet.
|
||||
//
|
||||
// Additionally, in both errcode cases, there might be an http
|
||||
// status code associated with it, and if so use it.
|
||||
switch err.(type) {
|
||||
case errcode.ErrorCode:
|
||||
daError, _ := err.(errcode.ErrorCode)
|
||||
statusCode = daError.Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message()
|
||||
|
||||
case errcode.Error:
|
||||
// For reference, if you're looking for a particular error
|
||||
// then you can do something like :
|
||||
// import ( derr "github.com/docker/docker/errors" )
|
||||
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
|
||||
|
||||
daError, _ := err.(errcode.Error)
|
||||
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message
|
||||
|
||||
default:
|
||||
// This part of will be removed once we've
|
||||
// converted everything over to use the errcode package
|
||||
|
||||
// FIXME: this is brittle and should not be necessary.
|
||||
// If we need to differentiate between different possible error types,
|
||||
// we should create appropriate error types with clearly defined meaning
|
||||
errStr := strings.ToLower(err.Error())
|
||||
for keyword, status := range map[string]int{
|
||||
"not found": http.StatusNotFound,
|
||||
"no such": http.StatusNotFound,
|
||||
"bad parameter": http.StatusBadRequest,
|
||||
"conflict": http.StatusConflict,
|
||||
"impossible": http.StatusNotAcceptable,
|
||||
"wrong login/password": http.StatusUnauthorized,
|
||||
"hasn't been activated": http.StatusForbidden,
|
||||
} {
|
||||
if strings.Contains(errStr, keyword) {
|
||||
statusCode = status
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": utils.GetErrorMessage(err)}).Error("HTTP Error")
|
||||
http.Error(w, errMsg, statusCode)
|
||||
}
|
||||
|
||||
// writeJSON writes the value v to the http response stream as json with standard
|
||||
// json encoding.
|
||||
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
func (s *Server) optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
|
||||
logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
|
||||
|
@ -271,11 +122,6 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string
|
|||
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
|
||||
}
|
||||
|
||||
func (s *Server) ping(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
_, err := w.Write([]byte{'O', 'K'})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
|
||||
if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
|
||||
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
||||
|
@ -289,10 +135,10 @@ func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc {
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// log the handler generation
|
||||
logrus.Debugf("Calling %s %s", localMethod, localRoute)
|
||||
// log the handler call
|
||||
logrus.Debugf("Calling %s %s", r.Method, r.URL.Path)
|
||||
|
||||
// Define the context that we'll pass around to share info
|
||||
// like the docker-request-id.
|
||||
|
@ -302,108 +148,53 @@ func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHan
|
|||
// immediate function being called should still be passed
|
||||
// as 'args' on the function call.
|
||||
ctx := context.Background()
|
||||
handlerFunc := s.handleWithGlobalMiddlewares(localHandler)
|
||||
handlerFunc := s.handleWithGlobalMiddlewares(handler)
|
||||
|
||||
if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil {
|
||||
logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, utils.GetErrorMessage(err))
|
||||
httpError(w, err)
|
||||
logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
|
||||
httputils.WriteError(w, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// createRouter initializes the main router the server uses.
|
||||
// InitRouters initializes a list of routers for the server.
|
||||
func (s *Server) InitRouters(d *daemon.Daemon) {
|
||||
s.addRouter(local.NewRouter(d))
|
||||
s.addRouter(network.NewRouter(d))
|
||||
}
|
||||
|
||||
// addRouter adds a new router to the server.
|
||||
func (s *Server) addRouter(r router.Router) {
|
||||
s.routers = append(s.routers, r)
|
||||
}
|
||||
|
||||
// CreateMux initializes the main router the server uses.
|
||||
// we keep enableCors just for legacy usage, need to be removed in the future
|
||||
func createRouter(s *Server) *mux.Router {
|
||||
r := mux.NewRouter()
|
||||
func (s *Server) CreateMux() *mux.Router {
|
||||
m := mux.NewRouter()
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
profilerSetup(r, "/debug/")
|
||||
}
|
||||
m := map[string]map[string]HTTPAPIFunc{
|
||||
"HEAD": {
|
||||
"/containers/{name:.*}/archive": s.headContainersArchive,
|
||||
},
|
||||
"GET": {
|
||||
"/_ping": s.ping,
|
||||
"/events": s.getEvents,
|
||||
"/info": s.getInfo,
|
||||
"/version": s.getVersion,
|
||||
"/images/json": s.getImagesJSON,
|
||||
"/images/search": s.getImagesSearch,
|
||||
"/images/get": s.getImagesGet,
|
||||
"/images/{name:.*}/get": s.getImagesGet,
|
||||
"/images/{name:.*}/history": s.getImagesHistory,
|
||||
"/images/{name:.*}/json": s.getImagesByName,
|
||||
"/containers/json": s.getContainersJSON,
|
||||
"/containers/{name:.*}/export": s.getContainersExport,
|
||||
"/containers/{name:.*}/changes": s.getContainersChanges,
|
||||
"/containers/{name:.*}/json": s.getContainersByName,
|
||||
"/containers/{name:.*}/top": s.getContainersTop,
|
||||
"/containers/{name:.*}/logs": s.getContainersLogs,
|
||||
"/containers/{name:.*}/stats": s.getContainersStats,
|
||||
"/containers/{name:.*}/attach/ws": s.wsContainersAttach,
|
||||
"/exec/{id:.*}/json": s.getExecByID,
|
||||
"/containers/{name:.*}/archive": s.getContainersArchive,
|
||||
"/volumes": s.getVolumesList,
|
||||
"/volumes/{name:.*}": s.getVolumeByName,
|
||||
},
|
||||
"POST": {
|
||||
"/auth": s.postAuth,
|
||||
"/commit": s.postCommit,
|
||||
"/build": s.postBuild,
|
||||
"/images/create": s.postImagesCreate,
|
||||
"/images/load": s.postImagesLoad,
|
||||
"/images/{name:.*}/push": s.postImagesPush,
|
||||
"/images/{name:.*}/tag": s.postImagesTag,
|
||||
"/containers/create": s.postContainersCreate,
|
||||
"/containers/{name:.*}/kill": s.postContainersKill,
|
||||
"/containers/{name:.*}/pause": s.postContainersPause,
|
||||
"/containers/{name:.*}/unpause": s.postContainersUnpause,
|
||||
"/containers/{name:.*}/restart": s.postContainersRestart,
|
||||
"/containers/{name:.*}/start": s.postContainersStart,
|
||||
"/containers/{name:.*}/stop": s.postContainersStop,
|
||||
"/containers/{name:.*}/wait": s.postContainersWait,
|
||||
"/containers/{name:.*}/resize": s.postContainersResize,
|
||||
"/containers/{name:.*}/attach": s.postContainersAttach,
|
||||
"/containers/{name:.*}/copy": s.postContainersCopy,
|
||||
"/containers/{name:.*}/exec": s.postContainerExecCreate,
|
||||
"/exec/{name:.*}/start": s.postContainerExecStart,
|
||||
"/exec/{name:.*}/resize": s.postContainerExecResize,
|
||||
"/containers/{name:.*}/rename": s.postContainerRename,
|
||||
"/volumes": s.postVolumesCreate,
|
||||
},
|
||||
"PUT": {
|
||||
"/containers/{name:.*}/archive": s.putContainersArchive,
|
||||
},
|
||||
"DELETE": {
|
||||
"/containers/{name:.*}": s.deleteContainers,
|
||||
"/images/{name:.*}": s.deleteImages,
|
||||
"/volumes/{name:.*}": s.deleteVolumes,
|
||||
},
|
||||
"OPTIONS": {
|
||||
"": s.optionsHandler,
|
||||
},
|
||||
profilerSetup(m, "/debug/")
|
||||
}
|
||||
|
||||
for method, routes := range m {
|
||||
for route, fct := range routes {
|
||||
logrus.Debugf("Registering %s, %s", method, route)
|
||||
// NOTE: scope issue, make sure the variables are local and won't be changed
|
||||
localRoute := route
|
||||
localFct := fct
|
||||
localMethod := method
|
||||
|
||||
// build the handler function
|
||||
f := s.makeHTTPHandler(localMethod, localRoute, localFct)
|
||||
|
||||
// add the new route
|
||||
if localRoute == "" {
|
||||
r.Methods(localMethod).HandlerFunc(f)
|
||||
} else {
|
||||
r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
|
||||
r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
|
||||
}
|
||||
logrus.Debugf("Registering routers")
|
||||
for _, router := range s.routers {
|
||||
for _, r := range router.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
r.Register(m, f)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
return m
|
||||
}
|
||||
|
||||
// AcceptConnections allows clients to connect to the API server.
|
||||
// Referenced Daemon is notified about this server, and waits for the
|
||||
// daemon acknowledgement before the incoming connections are accepted.
|
||||
func (s *Server) AcceptConnections() {
|
||||
// close the lock so the listeners start accepting connections
|
||||
select {
|
||||
case <-s.start:
|
||||
default:
|
||||
close(s.start)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
// +build experimental,!windows
|
||||
|
||||
package server
|
||||
|
||||
func (s *Server) registerSubRouter() {
|
||||
httpHandler := s.daemon.NetworkAPIRouter()
|
||||
|
||||
subrouter := s.router.PathPrefix("/v{version:[0-9.]+}/networks").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
subrouter = s.router.PathPrefix("/networks").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
|
||||
subrouter = s.router.PathPrefix("/v{version:[0-9.]+}/services").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
subrouter = s.router.PathPrefix("/services").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
|
||||
subrouter = s.router.PathPrefix("/v{version:[0-9.]+}/sandboxes").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
subrouter = s.router.PathPrefix("/sandboxes").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
// +build !experimental windows
|
||||
|
||||
package server
|
||||
|
||||
func (s *Server) registerSubRouter() {
|
||||
}
|
|
@ -5,6 +5,8 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -19,7 +21,7 @@ func TestMiddlewares(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
localHandler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if versionFromContext(ctx) == "" {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -8,12 +8,10 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/sockets"
|
||||
"github.com/docker/libnetwork/portallocator"
|
||||
|
||||
systemdActivation "github.com/coreos/go-systemd/activation"
|
||||
systemdDaemon "github.com/coreos/go-systemd/daemon"
|
||||
)
|
||||
|
||||
// newServer sets up the required serverClosers and does protocol specific checking.
|
||||
|
@ -52,7 +50,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
res = append(res, &HTTPServer{
|
||||
&http.Server{
|
||||
Addr: addr,
|
||||
Handler: s.router,
|
||||
Handler: s.CreateMux(),
|
||||
},
|
||||
l,
|
||||
})
|
||||
|
@ -60,22 +58,6 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// AcceptConnections allows clients to connect to the API server.
|
||||
// Referenced Daemon is notified about this server, and waits for the
|
||||
// daemon acknowledgement before the incoming connections are accepted.
|
||||
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
||||
// Tell the init daemon we are accepting requests
|
||||
s.daemon = d
|
||||
s.registerSubRouter()
|
||||
go systemdDaemon.SdNotify("READY=1")
|
||||
// close the lock so the listeners start accepting connections
|
||||
select {
|
||||
case <-s.start:
|
||||
default:
|
||||
close(s.start)
|
||||
}
|
||||
}
|
||||
|
||||
func allocateDaemonPort(addr string) error {
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/daemon"
|
||||
)
|
||||
|
||||
// NewServer sets up the required Server and does protocol specific checking.
|
||||
|
@ -32,7 +30,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
res = append(res, &HTTPServer{
|
||||
&http.Server{
|
||||
Addr: addr,
|
||||
Handler: s.router,
|
||||
Handler: s.CreateMux(),
|
||||
},
|
||||
l,
|
||||
})
|
||||
|
@ -41,18 +39,6 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
|
||||
}
|
||||
|
||||
// AcceptConnections allows router to start listening for the incoming requests.
|
||||
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
||||
s.daemon = d
|
||||
s.registerSubRouter()
|
||||
// close the lock so the listeners start accepting connections
|
||||
select {
|
||||
case <-s.start:
|
||||
default:
|
||||
close(s.start)
|
||||
}
|
||||
}
|
||||
|
||||
func allocateDaemonPort(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1131,6 +1131,11 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
|
|||
return verifyPlatformContainerSettings(daemon, hostConfig, config)
|
||||
}
|
||||
|
||||
// NetworkController exposes the libnetwork interface to manage networks.
|
||||
func (daemon *Daemon) NetworkController() libnetwork.NetworkController {
|
||||
return daemon.netController
|
||||
}
|
||||
|
||||
func configureVolumes(config *Config) (*store.VolumeStore, error) {
|
||||
volumesDriver, err := local.New(config.Root)
|
||||
if err != nil {
|
||||
|
|
|
@ -5,7 +5,6 @@ package daemon
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -22,7 +21,6 @@ import (
|
|||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
"github.com/docker/libnetwork"
|
||||
nwapi "github.com/docker/libnetwork/api"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
|
@ -489,12 +487,6 @@ func setupInitLayer(initLayer string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// NetworkAPIRouter implements a feature for server-experimental,
|
||||
// directly calling into libnetwork.
|
||||
func (daemon *Daemon) NetworkAPIRouter() func(w http.ResponseWriter, req *http.Request) {
|
||||
return nwapi.NewHTTPHandler(daemon.netController)
|
||||
}
|
||||
|
||||
// registerLinks writes the links to a file.
|
||||
func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
if hostConfig == nil || hostConfig.Links == nil {
|
||||
|
|
|
@ -224,21 +224,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
serverConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
|
||||
api := apiserver.New(serverConfig)
|
||||
|
||||
// The serve API routine never exits unless an error occurs
|
||||
// We need to start it as a goroutine and wait on it so
|
||||
// daemon doesn't exit
|
||||
serveAPIWait := make(chan error)
|
||||
go func() {
|
||||
if err := api.ServeAPI(commonFlags.Hosts); err != nil {
|
||||
logrus.Errorf("ServeAPI error: %v", err)
|
||||
serveAPIWait <- err
|
||||
return
|
||||
}
|
||||
serveAPIWait <- nil
|
||||
}()
|
||||
|
||||
if err := migrateKey(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
@ -264,6 +249,22 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
"graphdriver": d.GraphDriver().String(),
|
||||
}).Info("Docker daemon")
|
||||
|
||||
api := apiserver.New(serverConfig)
|
||||
api.InitRouters(d)
|
||||
|
||||
// The serve API routine never exits unless an error occurs
|
||||
// We need to start it as a goroutine and wait on it so
|
||||
// daemon doesn't exit
|
||||
serveAPIWait := make(chan error)
|
||||
go func() {
|
||||
if err := api.ServeAPI(commonFlags.Hosts); err != nil {
|
||||
logrus.Errorf("ServeAPI error: %v", err)
|
||||
serveAPIWait <- err
|
||||
return
|
||||
}
|
||||
serveAPIWait <- nil
|
||||
}()
|
||||
|
||||
signal.Trap(func() {
|
||||
api.Close()
|
||||
<-serveAPIWait
|
||||
|
@ -277,7 +278,8 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
|
||||
// after the daemon is done setting up we can tell the api to start
|
||||
// accepting connections with specified daemon
|
||||
api.AcceptConnections(d)
|
||||
notifySystem()
|
||||
api.AcceptConnections()
|
||||
|
||||
// Daemon is fully initialized and handling API traffic
|
||||
// Wait for serve API to complete
|
||||
|
|
7
docker/daemon_freebsd.go
Normal file
7
docker/daemon_freebsd.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build daemon
|
||||
|
||||
package docker
|
||||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
func notifySystem() {
|
||||
}
|
|
@ -3,5 +3,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
systemdDaemon "github.com/coreos/go-systemd/daemon"
|
||||
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
||||
)
|
||||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
func notifySystem() {
|
||||
// Tell the init daemon we are accepting requests
|
||||
go systemdDaemon.SdNotify("READY=1")
|
||||
}
|
||||
|
|
|
@ -10,3 +10,7 @@ var daemonCli cli.Handler
|
|||
|
||||
// TODO: remove once `-d` is retired
|
||||
func handleGlobalDaemonFlag() {}
|
||||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
func notifySystem() {
|
||||
}
|
||||
|
|
|
@ -27,3 +27,7 @@ func setDefaultUmask() error {
|
|||
func getDaemonConfDir() string {
|
||||
return os.Getenv("PROGRAMDATA") + `\docker\config`
|
||||
}
|
||||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
func notifySystem() {
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue