diff --git a/api/server/router/checkpoint/checkpoint.go b/api/server/router/checkpoint/checkpoint.go index a668176a78..c1e93926f5 100644 --- a/api/server/router/checkpoint/checkpoint.go +++ b/api/server/router/checkpoint/checkpoint.go @@ -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)), } } diff --git a/api/server/router/experimental.go b/api/server/router/experimental.go new file mode 100644 index 0000000000..51385c2552 --- /dev/null +++ b/api/server/router/experimental.go @@ -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, + } +} diff --git a/api/server/router/swarm/cluster.go b/api/server/router/swarm/cluster.go index e7181a4d1b..352a80db14 100644 --- a/api/server/router/swarm/cluster.go +++ b/api/server/router/swarm/cluster.go @@ -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), diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index 866c2ec3e2..be8025fd98 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -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...) } diff --git a/cmd/dockerd/routes_experimental.go b/cmd/dockerd/routes_experimental.go deleted file mode 100644 index 8c8abf2a3e..0000000000 --- a/cmd/dockerd/routes_experimental.go +++ /dev/null @@ -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)) -}