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>
This commit is contained in:
parent
956ff8f773
commit
3976a33c1a
5 changed files with 89 additions and 40 deletions
|
@ -29,8 +29,8 @@ func (r *checkpointRouter) Routes() []router.Route {
|
||||||
|
|
||||||
func (r *checkpointRouter) initRoutes() {
|
func (r *checkpointRouter) initRoutes() {
|
||||||
r.routes = []router.Route{
|
r.routes = []router.Route{
|
||||||
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
|
router.Experimental(router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints)),
|
||||||
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
|
router.Experimental(router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint)),
|
||||||
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
|
router.Experimental(router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
api/server/router/experimental.go
Normal file
67
api/server/router/experimental.go
Normal file
|
@ -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
|
package swarm
|
||||||
|
|
||||||
import (
|
import "github.com/docker/docker/api/server/router"
|
||||||
"github.com/docker/docker/api/server/router"
|
|
||||||
"github.com/docker/docker/daemon"
|
|
||||||
)
|
|
||||||
|
|
||||||
// swarmRouter is a router to talk with the build controller
|
// swarmRouter is a router to talk with the build controller
|
||||||
type swarmRouter struct {
|
type swarmRouter struct {
|
||||||
|
@ -12,14 +9,11 @@ type swarmRouter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRouter initializes a new build router
|
// NewRouter initializes a new build router
|
||||||
func NewRouter(d *daemon.Daemon, b Backend) router.Router {
|
func NewRouter(b Backend) router.Router {
|
||||||
r := &swarmRouter{
|
r := &swarmRouter{
|
||||||
backend: b,
|
backend: b,
|
||||||
}
|
}
|
||||||
r.initRoutes()
|
r.initRoutes()
|
||||||
if d.HasExperimental() {
|
|
||||||
r.addExperimentalRoutes()
|
|
||||||
}
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +22,6 @@ func (sr *swarmRouter) Routes() []router.Route {
|
||||||
return sr.routes
|
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() {
|
func (sr *swarmRouter) initRoutes() {
|
||||||
sr.routes = []router.Route{
|
sr.routes = []router.Route{
|
||||||
router.NewPostRoute("/swarm/init", sr.initCluster),
|
router.NewPostRoute("/swarm/init", sr.initCluster),
|
||||||
|
@ -48,6 +36,7 @@ func (sr *swarmRouter) initRoutes() {
|
||||||
router.NewPostRoute("/services/create", sr.createService),
|
router.NewPostRoute("/services/create", sr.createService),
|
||||||
router.NewPostRoute("/services/{id}/update", sr.updateService),
|
router.NewPostRoute("/services/{id}/update", sr.updateService),
|
||||||
router.NewDeleteRoute("/services/{id}", sr.removeService),
|
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", sr.getNodes),
|
||||||
router.NewGetRoute("/nodes/{id}", sr.getNode),
|
router.NewGetRoute("/nodes/{id}", sr.getNode),
|
||||||
router.NewDeleteRoute("/nodes/{id}", sr.removeNode),
|
router.NewDeleteRoute("/nodes/{id}", sr.removeNode),
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/docker/docker/api/server/middleware"
|
"github.com/docker/docker/api/server/middleware"
|
||||||
"github.com/docker/docker/api/server/router"
|
"github.com/docker/docker/api/server/router"
|
||||||
"github.com/docker/docker/api/server/router/build"
|
"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/container"
|
||||||
"github.com/docker/docker/api/server/router/image"
|
"github.com/docker/docker/api/server/router/image"
|
||||||
"github.com/docker/docker/api/server/router/network"
|
"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) {
|
func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
|
||||||
decoder := runconfig.ContainerDecoder{}
|
decoder := runconfig.ContainerDecoder{}
|
||||||
|
|
||||||
routers := []router.Router{}
|
routers := []router.Router{
|
||||||
|
// we need to add the checkpoint router before the container router or the DELETE gets masked
|
||||||
// we need to add the checkpoint router before the container router or the DELETE gets masked
|
checkpointrouter.NewRouter(d, decoder),
|
||||||
routers = addExperimentalRouters(routers, d, decoder)
|
|
||||||
|
|
||||||
routers = append(routers, []router.Router{
|
|
||||||
container.NewRouter(d, decoder),
|
container.NewRouter(d, decoder),
|
||||||
image.NewRouter(d, decoder),
|
image.NewRouter(d, decoder),
|
||||||
systemrouter.NewRouter(d, c),
|
systemrouter.NewRouter(d, c),
|
||||||
volume.NewRouter(d),
|
volume.NewRouter(d),
|
||||||
build.NewRouter(dockerfile.NewBuildManager(d)),
|
build.NewRouter(dockerfile.NewBuildManager(d)),
|
||||||
swarmrouter.NewRouter(d, c),
|
swarmrouter.NewRouter(c),
|
||||||
pluginrouter.NewRouter(plugin.GetManager()),
|
pluginrouter.NewRouter(plugin.GetManager()),
|
||||||
}...)
|
}
|
||||||
|
|
||||||
if d.NetworkControllerEnabled() {
|
if d.NetworkControllerEnabled() {
|
||||||
routers = append(routers, network.NewRouter(d, c))
|
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...)
|
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))
|
|
||||||
}
|
|
Loading…
Reference in a new issue