router: Return explicit error rather than 404 for experimental.

Instead of not adding experimental routes at all, fail with an explicit
message if the daemon is not running in experimental mode.

Added the `router.Experimental` which does this automatically.

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Upstream-commit: 3976a33c1a578827da3726bec3927cc058fe326a
Component: engine
This commit is contained in:
Andrea Luzzardi
2016-11-17 15:51:47 -08:00
parent fddeef3e5c
commit 84fb1a0844
5 changed files with 89 additions and 40 deletions
@@ -29,8 +29,8 @@ func (r *checkpointRouter) Routes() []router.Route {
func (r *checkpointRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
router.Experimental(router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints)),
router.Experimental(router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint)),
router.Experimental(router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint)),
}
}
@@ -0,0 +1,67 @@
package router
import (
"errors"
"net/http"
"golang.org/x/net/context"
apierrors "github.com/docker/docker/api/errors"
"github.com/docker/docker/api/server/httputils"
)
var (
errExperimentalFeature = errors.New("This experimental feature is disabled by default. Start the Docker daemon with --experimental in order to enable it.")
)
// ExperimentalRoute defines an experimental API route that can be enabled or disabled.
type ExperimentalRoute interface {
Route
Enable()
Disable()
}
// experimentalRoute defines an experimental API route that can be enabled or disabled.
// It implements ExperimentalRoute
type experimentalRoute struct {
local Route
handler httputils.APIFunc
}
// Enable enables this experimental route
func (r *experimentalRoute) Enable() {
r.handler = r.local.Handler()
}
// Disable disables the experimental route
func (r *experimentalRoute) Disable() {
r.handler = experimentalHandler
}
func experimentalHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return apierrors.NewErrorWithStatusCode(errExperimentalFeature, http.StatusNotImplemented)
}
// Handler returns returns the APIFunc to let the server wrap it in middlewares.
func (r *experimentalRoute) Handler() httputils.APIFunc {
return r.handler
}
// Method returns the http method that the route responds to.
func (r *experimentalRoute) Method() string {
return r.local.Method()
}
// Path returns the subpath where the route responds to.
func (r *experimentalRoute) Path() string {
return r.local.Path()
}
// Experimental will mark a route as experimental.
func Experimental(r Route) Route {
return &experimentalRoute{
local: r,
handler: experimentalHandler,
}
}
@@ -1,9 +1,6 @@
package swarm
import (
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/daemon"
)
import "github.com/docker/docker/api/server/router"
// swarmRouter is a router to talk with the build controller
type swarmRouter struct {
@@ -12,14 +9,11 @@ type swarmRouter struct {
}
// NewRouter initializes a new build router
func NewRouter(d *daemon.Daemon, b Backend) router.Router {
func NewRouter(b Backend) router.Router {
r := &swarmRouter{
backend: b,
}
r.initRoutes()
if d.HasExperimental() {
r.addExperimentalRoutes()
}
return r
}
@@ -28,12 +22,6 @@ func (sr *swarmRouter) Routes() []router.Route {
return sr.routes
}
func (sr *swarmRouter) addExperimentalRoutes() {
sr.routes = append(sr.routes,
router.Cancellable(router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs)),
)
}
func (sr *swarmRouter) initRoutes() {
sr.routes = []router.Route{
router.NewPostRoute("/swarm/init", sr.initCluster),
@@ -48,6 +36,7 @@ func (sr *swarmRouter) initRoutes() {
router.NewPostRoute("/services/create", sr.createService),
router.NewPostRoute("/services/{id}/update", sr.updateService),
router.NewDeleteRoute("/services/{id}", sr.removeService),
router.Experimental(router.Cancellable(router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs))),
router.NewGetRoute("/nodes", sr.getNodes),
router.NewGetRoute("/nodes/{id}", sr.getNode),
router.NewDeleteRoute("/nodes/{id}", sr.removeNode),
+16 -8
View File
@@ -17,6 +17,7 @@ import (
"github.com/docker/docker/api/server/middleware"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/server/router/build"
checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
"github.com/docker/docker/api/server/router/container"
"github.com/docker/docker/api/server/router/image"
"github.com/docker/docker/api/server/router/network"
@@ -461,25 +462,32 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
decoder := runconfig.ContainerDecoder{}
routers := []router.Router{}
// we need to add the checkpoint router before the container router or the DELETE gets masked
routers = addExperimentalRouters(routers, d, decoder)
routers = append(routers, []router.Router{
routers := []router.Router{
// we need to add the checkpoint router before the container router or the DELETE gets masked
checkpointrouter.NewRouter(d, decoder),
container.NewRouter(d, decoder),
image.NewRouter(d, decoder),
systemrouter.NewRouter(d, c),
volume.NewRouter(d),
build.NewRouter(dockerfile.NewBuildManager(d)),
swarmrouter.NewRouter(d, c),
swarmrouter.NewRouter(c),
pluginrouter.NewRouter(plugin.GetManager()),
}...)
}
if d.NetworkControllerEnabled() {
routers = append(routers, network.NewRouter(d, c))
}
if d.HasExperimental() {
for _, r := range routers {
for _, route := range r.Routes() {
if experimental, ok := route.(router.ExperimentalRoute); ok {
experimental.Enable()
}
}
}
}
s.InitRouter(utils.IsDebugEnabled(), routers...)
}
@@ -1,15 +0,0 @@
package main
import (
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router"
checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
"github.com/docker/docker/daemon"
)
func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
if !d.HasExperimental() {
return []router.Router{}
}
return append(routers, checkpointrouter.NewRouter(d, decoder))
}