Browse Source

Add container package for container APIs.

Signed-off-by: Dong Chen <dongluo.chen@docker.com>
Dong Chen 9 years ago
parent
commit
fa8d96ebe2

+ 56 - 0
api/server/router/container/backend_unix.go

@@ -0,0 +1,56 @@
+// +build !windows
+
+package container
+
+import (
+	"io"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/versions/v1p19"
+	"github.com/docker/docker/api/types/versions/v1p20"
+	"github.com/docker/docker/daemon"
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/runconfig"
+)
+
+// Backend is all the methods that need to be implemented to provide
+// container specific functionality
+type Backend interface {
+	ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
+	ContainerAttachWithLogs(prefixOrName string, c *daemon.ContainerAttachWithLogsConfig) error
+	ContainerChanges(name string) ([]archive.Change, error)
+	ContainerCopy(name string, res string) (io.ReadCloser, error)
+	ContainerCreate(params *daemon.ContainerCreateConfig) (types.ContainerCreateResponse, error)
+	ContainerExecCreate(config *runconfig.ExecConfig) (string, error)
+	ContainerExecInspect(id string) (*daemon.ExecConfig, error)
+	ContainerExecResize(name string, height, width int) error
+	ContainerExecStart(name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error
+	ContainerExport(name string, out io.Writer) error
+	ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error
+	ContainerInspect(name string, size bool) (*types.ContainerJSON, error)
+	ContainerInspect120(name string) (*v1p20.ContainerJSON, error)
+	// unix version
+	ContainerInspectPre120(name string) (*v1p19.ContainerJSON, error)
+	// windows version
+	//ContainerInspectPre120(name string) (*types.ContainerJSON, error)
+	ContainerKill(name string, sig uint64) error
+	ContainerLogs(containerName string, config *daemon.ContainerLogsConfig) error
+	ContainerPause(name string) error
+	ContainerRename(oldName, newName string) error
+	ContainerResize(name string, height, width int) error
+	ContainerRestart(name string, seconds int) error
+	ContainerRm(name string, config *daemon.ContainerRmConfig) error
+	Containers(config *daemon.ContainersConfig) ([]*types.Container, error)
+	ContainerStart(name string, hostConfig *runconfig.HostConfig) error
+	ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
+	ContainerStats(prefixOrName string, config *daemon.ContainerStatsConfig) error
+	ContainerStop(name string, seconds int) error
+	ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error)
+	ContainerUnpause(name string) error
+	ContainerWait(name string, timeout time.Duration) (int, error)
+	ContainerWsAttachWithLogs(prefixOrName string, c *daemon.ContainerWsAttachWithLogsConfig) error
+	ExecExists(name string) (bool, error)
+	Exists(id string) bool
+	IsPaused(id string) bool
+}

+ 55 - 0
api/server/router/container/backend_windows.go

@@ -0,0 +1,55 @@
+// +build windows
+
+package container
+
+import (
+	"io"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/versions/v1p20"
+	"github.com/docker/docker/daemon"
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/runconfig"
+)
+
+// Backend is all the methods that need to be implemented to provide
+// container specific functionality
+type Backend interface {
+	ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
+	ContainerAttachWithLogs(prefixOrName string, c *daemon.ContainerAttachWithLogsConfig) error
+	ContainerChanges(name string) ([]archive.Change, error)
+	ContainerCopy(name string, res string) (io.ReadCloser, error)
+	ContainerCreate(params *daemon.ContainerCreateConfig) (types.ContainerCreateResponse, error)
+	ContainerExecCreate(config *runconfig.ExecConfig) (string, error)
+	ContainerExecInspect(id string) (*daemon.ExecConfig, error)
+	ContainerExecResize(name string, height, width int) error
+	ContainerExecStart(name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error
+	ContainerExport(name string, out io.Writer) error
+	ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error
+	ContainerInspect(name string, size bool) (*types.ContainerJSON, error)
+	ContainerInspect120(name string) (*v1p20.ContainerJSON, error)
+	// unix version
+	//ContainerInspectPre120(name string) (*v1p19.ContainerJSON, error)
+	// windows version
+	ContainerInspectPre120(name string) (*types.ContainerJSON, error)
+	ContainerKill(name string, sig uint64) error
+	ContainerLogs(containerName string, config *daemon.ContainerLogsConfig) error
+	ContainerPause(name string) error
+	ContainerRename(oldName, newName string) error
+	ContainerResize(name string, height, width int) error
+	ContainerRestart(name string, seconds int) error
+	ContainerRm(name string, config *daemon.ContainerRmConfig) error
+	Containers(config *daemon.ContainersConfig) ([]*types.Container, error)
+	ContainerStart(name string, hostConfig *runconfig.HostConfig) error
+	ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
+	ContainerStats(prefixOrName string, config *daemon.ContainerStatsConfig) error
+	ContainerStop(name string, seconds int) error
+	ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error)
+	ContainerUnpause(name string) error
+	ContainerWait(name string, timeout time.Duration) (int, error)
+	ContainerWsAttachWithLogs(prefixOrName string, c *daemon.ContainerWsAttachWithLogsConfig) error
+	ExecExists(name string) (bool, error)
+	Exists(id string) bool
+	IsPaused(id string) bool
+}

+ 65 - 0
api/server/router/container/container.go

@@ -0,0 +1,65 @@
+package container
+
+import (
+	"github.com/docker/docker/api/server/router"
+	"github.com/docker/docker/api/server/router/local"
+)
+
+// containerRouter is a router to talk with the container controller
+type containerRouter struct {
+	backend Backend
+	routes  []router.Route
+}
+
+// NewRouter initializes a new container router
+func NewRouter(b Backend) router.Router {
+	r := &containerRouter{
+		backend: b,
+	}
+	r.initRoutes()
+	return r
+}
+
+// Routes returns the available routers to the container controller
+func (r *containerRouter) Routes() []router.Route {
+	return r.routes
+}
+
+// initRoutes initializes the routes in container router
+func (r *containerRouter) initRoutes() {
+	r.routes = []router.Route{
+		// HEAD
+		local.NewHeadRoute("/containers/{name:.*}/archive", r.headContainersArchive),
+		// GET
+		local.NewGetRoute("/containers/json", r.getContainersJSON),
+		local.NewGetRoute("/containers/{name:.*}/export", r.getContainersExport),
+		local.NewGetRoute("/containers/{name:.*}/changes", r.getContainersChanges),
+		local.NewGetRoute("/containers/{name:.*}/json", r.getContainersByName),
+		local.NewGetRoute("/containers/{name:.*}/top", r.getContainersTop),
+		local.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs),
+		local.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats),
+		local.NewGetRoute("/containers/{name:.*}/attach/ws", r.wsContainersAttach),
+		local.NewGetRoute("/exec/{id:.*}/json", r.getExecByID),
+		local.NewGetRoute("/containers/{name:.*}/archive", r.getContainersArchive),
+		// POST
+		local.NewPostRoute("/containers/create", r.postContainersCreate),
+		local.NewPostRoute("/containers/{name:.*}/kill", r.postContainersKill),
+		local.NewPostRoute("/containers/{name:.*}/pause", r.postContainersPause),
+		local.NewPostRoute("/containers/{name:.*}/unpause", r.postContainersUnpause),
+		local.NewPostRoute("/containers/{name:.*}/restart", r.postContainersRestart),
+		local.NewPostRoute("/containers/{name:.*}/start", r.postContainersStart),
+		local.NewPostRoute("/containers/{name:.*}/stop", r.postContainersStop),
+		local.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
+		local.NewPostRoute("/containers/{name:.*}/resize", r.postContainersResize),
+		local.NewPostRoute("/containers/{name:.*}/attach", r.postContainersAttach),
+		local.NewPostRoute("/containers/{name:.*}/copy", r.postContainersCopy),
+		local.NewPostRoute("/containers/{name:.*}/exec", r.postContainerExecCreate),
+		local.NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
+		local.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
+		local.NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
+		// PUT
+		local.NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
+		// DELETE
+		local.NewDeleteRoute("/containers/{name:.*}", r.deleteContainers),
+	}
+}

+ 43 - 43
api/server/router/container/container_routes.go

@@ -1,4 +1,4 @@
-package local
+package container
 
 
 import (
 import (
 	"fmt"
 	"fmt"
@@ -24,7 +24,7 @@ import (
 	"golang.org/x/net/websocket"
 	"golang.org/x/net/websocket"
 )
 )
 
 
-func (s *router) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -45,7 +45,7 @@ func (s *router) getContainersJSON(ctx context.Context, w http.ResponseWriter, r
 		config.Limit = limit
 		config.Limit = limit
 	}
 	}
 
 
-	containers, err := s.daemon.Containers(config)
+	containers, err := s.backend.Containers(config)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -53,7 +53,7 @@ func (s *router) getContainersJSON(ctx context.Context, w http.ResponseWriter, r
 	return httputils.WriteJSON(w, http.StatusOK, containers)
 	return httputils.WriteJSON(w, http.StatusOK, containers)
 }
 }
 
 
-func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersStats(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -81,10 +81,10 @@ func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter,
 		Version:   httputils.VersionFromContext(ctx),
 		Version:   httputils.VersionFromContext(ctx),
 	}
 	}
 
 
-	return s.daemon.ContainerStats(vars["name"], config)
+	return s.backend.ContainerStats(vars["name"], config)
 }
 }
 
 
-func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -115,7 +115,7 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
 
 
 	containerName := vars["name"]
 	containerName := vars["name"]
 
 
-	if !s.daemon.Exists(containerName) {
+	if !s.backend.Exists(containerName) {
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 	}
 	}
 
 
@@ -141,7 +141,7 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
 		Stop:       closeNotifier,
 		Stop:       closeNotifier,
 	}
 	}
 
 
-	if err := s.daemon.ContainerLogs(containerName, logsConfig); err != nil {
+	if err := s.backend.ContainerLogs(containerName, logsConfig); err != nil {
 		// The client may be expecting all of the data we're sending to
 		// The client may be expecting all of the data we're sending to
 		// be multiplexed, so send it through OutStream, which will
 		// be multiplexed, so send it through OutStream, which will
 		// have been set up to handle that if needed.
 		// have been set up to handle that if needed.
@@ -151,11 +151,11 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	return s.daemon.ContainerExport(vars["name"], w)
+func (s *containerRouter) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	return s.backend.ContainerExport(vars["name"], w)
 }
 }
 
 
-func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	// If contentLength is -1, we can assumed chunked encoding
 	// If contentLength is -1, we can assumed chunked encoding
 	// or more technically that the length is unknown
 	// or more technically that the length is unknown
 	// https://golang.org/src/pkg/net/http/request.go#L139
 	// https://golang.org/src/pkg/net/http/request.go#L139
@@ -176,21 +176,21 @@ func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter,
 		hostConfig = c
 		hostConfig = c
 	}
 	}
 
 
-	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
+	if err := s.backend.ContainerStart(vars["name"], hostConfig); err != nil {
 		return err
 		return err
 	}
 	}
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersStop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	seconds, _ := strconv.Atoi(r.Form.Get("t"))
 	seconds, _ := strconv.Atoi(r.Form.Get("t"))
 
 
-	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
+	if err := s.backend.ContainerStop(vars["name"], seconds); err != nil {
 		return err
 		return err
 	}
 	}
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
@@ -198,7 +198,7 @@ func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter,
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -214,7 +214,7 @@ func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter,
 		}
 		}
 	}
 	}
 
 
-	if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
+	if err := s.backend.ContainerKill(name, uint64(sig)); err != nil {
 		theErr, isDerr := err.(errcode.ErrorCoder)
 		theErr, isDerr := err.(errcode.ErrorCoder)
 		isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning
 		isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning
 
 
@@ -231,14 +231,14 @@ func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter,
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersRestart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	timeout, _ := strconv.Atoi(r.Form.Get("t"))
 	timeout, _ := strconv.Atoi(r.Form.Get("t"))
 
 
-	if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
+	if err := s.backend.ContainerRestart(vars["name"], timeout); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -247,12 +247,12 @@ func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWrite
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if err := s.daemon.ContainerPause(vars["name"]); err != nil {
+	if err := s.backend.ContainerPause(vars["name"]); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -261,12 +261,12 @@ func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter,
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
+	if err := s.backend.ContainerUnpause(vars["name"]); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -275,8 +275,8 @@ func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWrite
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
+func (s *containerRouter) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	status, err := s.backend.ContainerWait(vars["name"], -1*time.Second)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -286,8 +286,8 @@ func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter,
 	})
 	})
 }
 }
 
 
-func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	changes, err := s.daemon.ContainerChanges(vars["name"])
+func (s *containerRouter) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	changes, err := s.backend.ContainerChanges(vars["name"])
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -295,12 +295,12 @@ func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter
 	return httputils.WriteJSON(w, http.StatusOK, changes)
 	return httputils.WriteJSON(w, http.StatusOK, changes)
 }
 }
 
 
-func (s *router) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
+	procList, err := s.backend.ContainerTop(vars["name"], r.Form.Get("ps_args"))
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -308,21 +308,21 @@ func (s *router) getContainersTop(ctx context.Context, w http.ResponseWriter, r
 	return httputils.WriteJSON(w, http.StatusOK, procList)
 	return httputils.WriteJSON(w, http.StatusOK, procList)
 }
 }
 
 
-func (s *router) postContainerRename(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainerRename(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	name := vars["name"]
 	name := vars["name"]
 	newName := r.Form.Get("name")
 	newName := r.Form.Get("name")
-	if err := s.daemon.ContainerRename(name, newName); err != nil {
+	if err := s.backend.ContainerRename(name, newName); err != nil {
 		return err
 		return err
 	}
 	}
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -339,7 +339,7 @@ func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter
 	version := httputils.VersionFromContext(ctx)
 	version := httputils.VersionFromContext(ctx)
 	adjustCPUShares := version.LessThan("1.19")
 	adjustCPUShares := version.LessThan("1.19")
 
 
-	ccr, err := s.daemon.ContainerCreate(&daemon.ContainerCreateConfig{
+	ccr, err := s.backend.ContainerCreate(&daemon.ContainerCreateConfig{
 		Name:            name,
 		Name:            name,
 		Config:          config,
 		Config:          config,
 		HostConfig:      hostConfig,
 		HostConfig:      hostConfig,
@@ -352,7 +352,7 @@ func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter
 	return httputils.WriteJSON(w, http.StatusCreated, ccr)
 	return httputils.WriteJSON(w, http.StatusCreated, ccr)
 }
 }
 
 
-func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -364,7 +364,7 @@ func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r
 		RemoveLink:   httputils.BoolValue(r, "link"),
 		RemoveLink:   httputils.BoolValue(r, "link"),
 	}
 	}
 
 
-	if err := s.daemon.ContainerRm(name, config); err != nil {
+	if err := s.backend.ContainerRm(name, config); err != nil {
 		// Force a 404 for the empty string
 		// Force a 404 for the empty string
 		if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
 		if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
 			return fmt.Errorf("no such id: \"\"")
 			return fmt.Errorf("no such id: \"\"")
@@ -377,7 +377,7 @@ func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainersResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -391,20 +391,20 @@ func (s *router) postContainersResize(ctx context.Context, w http.ResponseWriter
 		return err
 		return err
 	}
 	}
 
 
-	return s.daemon.ContainerResize(vars["name"], height, width)
+	return s.backend.ContainerResize(vars["name"], height, width)
 }
 }
 
 
-func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 	containerName := vars["name"]
 	containerName := vars["name"]
 
 
-	if !s.daemon.Exists(containerName) {
+	if !s.backend.Exists(containerName) {
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 	}
 	}
 
 
-	if s.daemon.IsPaused(containerName) {
+	if s.backend.IsPaused(containerName) {
 		return derr.ErrorCodePausedContainer.WithArgs(containerName)
 		return derr.ErrorCodePausedContainer.WithArgs(containerName)
 	}
 	}
 
 
@@ -430,20 +430,20 @@ func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter
 		Stream:    httputils.BoolValue(r, "stream"),
 		Stream:    httputils.BoolValue(r, "stream"),
 	}
 	}
 
 
-	if err := s.daemon.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil {
+	if err := s.backend.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil {
 		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
 		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
 	}
 	}
 
 
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
 	containerName := vars["name"]
 	containerName := vars["name"]
 
 
-	if !s.daemon.Exists(containerName) {
+	if !s.backend.Exists(containerName) {
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
 	}
 	}
 
 
@@ -458,7 +458,7 @@ func (s *router) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
 			Stream:    httputils.BoolValue(r, "stream"),
 			Stream:    httputils.BoolValue(r, "stream"),
 		}
 		}
 
 
-		if err := s.daemon.ContainerWsAttachWithLogs(containerName, wsAttachWithLogsConfig); err != nil {
+		if err := s.backend.ContainerWsAttachWithLogs(containerName, wsAttachWithLogsConfig); err != nil {
 			logrus.Errorf("Error attaching websocket: %s", err)
 			logrus.Errorf("Error attaching websocket: %s", err)
 		}
 		}
 	})
 	})

+ 9 - 9
api/server/router/container/copy.go

@@ -1,4 +1,4 @@
-package local
+package container
 
 
 import (
 import (
 	"encoding/base64"
 	"encoding/base64"
@@ -15,7 +15,7 @@ import (
 )
 )
 
 
 // postContainersCopy is deprecated in favor of getContainersArchive.
 // postContainersCopy is deprecated in favor of getContainersArchive.
-func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.CheckForJSON(r); err != nil {
 	if err := httputils.CheckForJSON(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -29,7 +29,7 @@ func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter,
 		return fmt.Errorf("Path cannot be empty")
 		return fmt.Errorf("Path cannot be empty")
 	}
 	}
 
 
-	data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
+	data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
 	if err != nil {
 	if err != nil {
 		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
 		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
 			w.WriteHeader(http.StatusNotFound)
 			w.WriteHeader(http.StatusNotFound)
@@ -65,13 +65,13 @@ func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Heade
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	v, err := httputils.ArchiveFormValues(r, vars)
 	v, err := httputils.ArchiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	stat, err := s.daemon.ContainerStatPath(v.Name, v.Path)
+	stat, err := s.backend.ContainerStatPath(v.Name, v.Path)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -79,13 +79,13 @@ func (s *router) headContainersArchive(ctx context.Context, w http.ResponseWrite
 	return setContainerPathStatHeader(stat, w.Header())
 	return setContainerPathStatHeader(stat, w.Header())
 }
 }
 
 
-func (s *router) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	v, err := httputils.ArchiveFormValues(r, vars)
 	v, err := httputils.ArchiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	tarArchive, stat, err := s.daemon.ContainerArchivePath(v.Name, v.Path)
+	tarArchive, stat, err := s.backend.ContainerArchivePath(v.Name, v.Path)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -101,12 +101,12 @@ func (s *router) getContainersArchive(ctx context.Context, w http.ResponseWriter
 	return err
 	return err
 }
 }
 
 
-func (s *router) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	v, err := httputils.ArchiveFormValues(r, vars)
 	v, err := httputils.ArchiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
 	noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
-	return s.daemon.ContainerExtractToDir(v.Name, v.Path, noOverwriteDirNonDir, r.Body)
+	return s.backend.ContainerExtractToDir(v.Name, v.Path, noOverwriteDirNonDir, r.Body)
 }
 }

+ 10 - 10
api/server/router/container/exec.go

@@ -1,4 +1,4 @@
-package local
+package container
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
@@ -15,8 +15,8 @@ import (
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 )
 )
 
 
-func (s *router) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
+func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	eConfig, err := s.backend.ContainerExecInspect(vars["id"])
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -24,7 +24,7 @@ func (s *router) getExecByID(ctx context.Context, w http.ResponseWriter, r *http
 	return httputils.WriteJSON(w, http.StatusOK, eConfig)
 	return httputils.WriteJSON(w, http.StatusOK, eConfig)
 }
 }
 
 
-func (s *router) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -44,7 +44,7 @@ func (s *router) postContainerExecCreate(ctx context.Context, w http.ResponseWri
 	}
 	}
 
 
 	// Register an instance of Exec in container.
 	// Register an instance of Exec in container.
-	id, err := s.daemon.ContainerExecCreate(execConfig)
+	id, err := s.backend.ContainerExecCreate(execConfig)
 	if err != nil {
 	if err != nil {
 		logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
 		logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
 		return err
 		return err
@@ -56,7 +56,7 @@ func (s *router) postContainerExecCreate(ctx context.Context, w http.ResponseWri
 }
 }
 
 
 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
-func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -79,7 +79,7 @@ func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWrit
 		return err
 		return err
 	}
 	}
 
 
-	if exists, err := s.daemon.ExecExists(execName); !exists {
+	if exists, err := s.backend.ExecExists(execName); !exists {
 		return err
 		return err
 	}
 	}
 
 
@@ -109,7 +109,7 @@ func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWrit
 	}
 	}
 
 
 	// Now run the user process in container.
 	// Now run the user process in container.
-	if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
+	if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
 		if execStartCheck.Detach {
 		if execStartCheck.Detach {
 			return err
 			return err
 		}
 		}
@@ -118,7 +118,7 @@ func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWrit
 	return nil
 	return nil
 }
 }
 
 
-func (s *router) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -131,5 +131,5 @@ func (s *router) postContainerExecResize(ctx context.Context, w http.ResponseWri
 		return err
 		return err
 	}
 	}
 
 
-	return s.daemon.ContainerExecResize(vars["name"], height, width)
+	return s.backend.ContainerExecResize(vars["name"], height, width)
 }
 }

+ 5 - 5
api/server/router/container/inspect.go

@@ -1,4 +1,4 @@
-package local
+package container
 
 
 import (
 import (
 	"net/http"
 	"net/http"
@@ -8,7 +8,7 @@ import (
 )
 )
 
 
 // getContainersByName inspects containers configuration and serializes it as json.
 // getContainersByName inspects containers configuration and serializes it as json.
-func (s *router) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *containerRouter) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	displaySize := httputils.BoolValue(r, "size")
 	displaySize := httputils.BoolValue(r, "size")
 
 
 	var json interface{}
 	var json interface{}
@@ -18,11 +18,11 @@ func (s *router) getContainersByName(ctx context.Context, w http.ResponseWriter,
 
 
 	switch {
 	switch {
 	case version.LessThan("1.20"):
 	case version.LessThan("1.20"):
-		json, err = s.daemon.ContainerInspectPre120(vars["name"])
+		json, err = s.backend.ContainerInspectPre120(vars["name"])
 	case version.Equal("1.20"):
 	case version.Equal("1.20"):
-		json, err = s.daemon.ContainerInspect120(vars["name"])
+		json, err = s.backend.ContainerInspect120(vars["name"])
 	default:
 	default:
-		json, err = s.daemon.ContainerInspect(vars["name"], displaySize)
+		json, err = s.backend.ContainerInspect(vars["name"], displaySize)
 	}
 	}
 
 
 	if err != nil {
 	if err != nil {

+ 0 - 30
api/server/router/local/local.go

@@ -91,8 +91,6 @@ func (r *router) Routes() []dkrouter.Route {
 // initRoutes initializes the routes in this router
 // initRoutes initializes the routes in this router
 func (r *router) initRoutes() {
 func (r *router) initRoutes() {
 	r.routes = []dkrouter.Route{
 	r.routes = []dkrouter.Route{
-		// HEAD
-		NewHeadRoute("/containers/{name:.*}/archive", r.headContainersArchive),
 		// OPTIONS
 		// OPTIONS
 		NewOptionsRoute("/", optionsHandler),
 		NewOptionsRoute("/", optionsHandler),
 		// GET
 		// GET
@@ -106,16 +104,6 @@ func (r *router) initRoutes() {
 		NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
 		NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
 		NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
 		NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
 		NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
 		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),
 		// POST
 		// POST
 		NewPostRoute("/auth", r.postAuth),
 		NewPostRoute("/auth", r.postAuth),
 		NewPostRoute("/commit", r.postCommit),
 		NewPostRoute("/commit", r.postCommit),
@@ -124,25 +112,7 @@ func (r *router) initRoutes() {
 		NewPostRoute("/images/load", r.postImagesLoad),
 		NewPostRoute("/images/load", r.postImagesLoad),
 		NewPostRoute("/images/{name:.*}/push", r.postImagesPush),
 		NewPostRoute("/images/{name:.*}/push", r.postImagesPush),
 		NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
 		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),
-		// PUT
-		NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
 		// DELETE
 		// DELETE
-		NewDeleteRoute("/containers/{name:.*}", r.deleteContainers),
 		NewDeleteRoute("/images/{name:.*}", r.deleteImages),
 		NewDeleteRoute("/images/{name:.*}", r.deleteImages),
 	}
 	}
 }
 }

+ 2 - 0
api/server/server.go

@@ -10,6 +10,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/server/router"
 	"github.com/docker/docker/api/server/router"
+	"github.com/docker/docker/api/server/router/container"
 	"github.com/docker/docker/api/server/router/local"
 	"github.com/docker/docker/api/server/router/local"
 	"github.com/docker/docker/api/server/router/network"
 	"github.com/docker/docker/api/server/router/network"
 	"github.com/docker/docker/api/server/router/volume"
 	"github.com/docker/docker/api/server/router/volume"
@@ -172,6 +173,7 @@ func (s *Server) InitRouters(d *daemon.Daemon) {
 	s.addRouter(local.NewRouter(d))
 	s.addRouter(local.NewRouter(d))
 	s.addRouter(network.NewRouter(d))
 	s.addRouter(network.NewRouter(d))
 	s.addRouter(volume.NewRouter(d))
 	s.addRouter(volume.NewRouter(d))
+	s.addRouter(container.NewRouter(d))
 
 
 	for _, srv := range s.servers {
 	for _, srv := range s.servers {
 		srv.srv.Handler = s.CreateMux()
 		srv.srv.Handler = s.CreateMux()