From 58a75cebdd08f3d504a5be79cc405cf33c4cbf43 Mon Sep 17 00:00:00 2001 From: Anda Xu Date: Tue, 21 Aug 2018 23:05:26 -0700 Subject: [PATCH] allow features option live reloadable Signed-off-by: Anda Xu --- api/server/router/build/build.go | 31 ++++++++++++++++++----- api/server/router/build/build_routes.go | 3 ++- api/server/router/system/system.go | 27 ++++++++++---------- api/server/router/system/system_routes.go | 4 ++- cmd/dockerd/daemon.go | 17 +++---------- daemon/daemon.go | 5 ++++ daemon/reload.go | 11 ++++++++ 7 files changed, 63 insertions(+), 35 deletions(-) diff --git a/api/server/router/build/build.go b/api/server/router/build/build.go index 90e3bb707c..e6b42ad163 100644 --- a/api/server/router/build/build.go +++ b/api/server/router/build/build.go @@ -7,15 +7,19 @@ import ( // buildRouter is a router to talk with the build controller type buildRouter struct { - backend Backend - daemon experimentalProvider - routes []router.Route - builderVersion types.BuilderVersion + backend Backend + daemon experimentalProvider + routes []router.Route + features *map[string]bool } // NewRouter initializes a new build router -func NewRouter(b Backend, d experimentalProvider, bv types.BuilderVersion) router.Router { - r := &buildRouter{backend: b, daemon: d, builderVersion: bv} +func NewRouter(b Backend, d experimentalProvider, features *map[string]bool) router.Router { + r := &buildRouter{ + backend: b, + daemon: d, + features: features, + } r.initRoutes() return r } @@ -32,3 +36,18 @@ func (r *buildRouter) initRoutes() { router.NewPostRoute("/build/cancel", r.postCancel), } } + +// BuilderVersion derives the default docker builder version from the config +// Note: it is valid to have BuilderVersion unset which means it is up to the +// client to choose which builder to use. +func BuilderVersion(features map[string]bool) types.BuilderVersion { + var bv types.BuilderVersion + if v, ok := features["buildkit"]; ok { + if v { + bv = types.BuilderBuildKit + } else { + bv = types.BuilderV1 + } + } + return bv +} diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index c2a15c0ad3..17272c8f24 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -230,8 +230,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode")) } + builderVersion := BuilderVersion(*br.features) // check if the builder feature has been enabled from daemon as well. - if buildOptions.Version == types.BuilderBuildKit && br.builderVersion != "" && br.builderVersion != types.BuilderBuildKit { + if buildOptions.Version == types.BuilderBuildKit && builderVersion != "" && builderVersion != types.BuilderBuildKit { return errdefs.InvalidParameter(errors.New("buildkit is not enabled on daemon")) } diff --git a/api/server/router/system/system.go b/api/server/router/system/system.go index 6f73c1e1c1..bbe32fb4bb 100644 --- a/api/server/router/system/system.go +++ b/api/server/router/system/system.go @@ -2,30 +2,29 @@ package system // import "github.com/docker/docker/api/server/router/system" import ( "github.com/docker/docker/api/server/router" - "github.com/docker/docker/api/types" - buildkit "github.com/docker/docker/builder/builder-next" + "github.com/docker/docker/builder/builder-next" "github.com/docker/docker/builder/fscache" ) // systemRouter provides information about the Docker system overall. // It gathers information about host, daemon and container events. type systemRouter struct { - backend Backend - cluster ClusterBackend - routes []router.Route - fscache *fscache.FSCache // legacy - builder *buildkit.Builder - builderVersion types.BuilderVersion + backend Backend + cluster ClusterBackend + routes []router.Route + fscache *fscache.FSCache // legacy + builder *buildkit.Builder + features *map[string]bool } // NewRouter initializes a new system router -func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, bv types.BuilderVersion) router.Router { +func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, features *map[string]bool) router.Router { r := &systemRouter{ - backend: b, - cluster: c, - fscache: fscache, - builder: builder, - builderVersion: bv, + backend: b, + cluster: c, + fscache: fscache, + builder: builder, + features: features, } r.routes = []router.Route{ diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index 010a74ac3a..a2ff692de3 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -8,6 +8,7 @@ import ( "time" "github.com/docker/docker/api/server/httputils" + "github.com/docker/docker/api/server/router/build" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" @@ -26,7 +27,8 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, } func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - if bv := s.builderVersion; bv != "" { + builderVersion := build.BuilderVersion(*s.features) + if bv := builderVersion; bv != "" { w.Header().Set("Builder-Version", string(bv)) } _, err := w.Write([]byte{'O', 'K'}) diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index 7e8049c80d..8ad372547c 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -27,7 +27,6 @@ import ( swarmrouter "github.com/docker/docker/api/server/router/swarm" systemrouter "github.com/docker/docker/api/server/router/system" "github.com/docker/docker/api/server/router/volume" - "github.com/docker/docker/api/types" buildkit "github.com/docker/docker/builder/builder-next" "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/builder/fscache" @@ -253,8 +252,8 @@ type routerOptions struct { sessionManager *session.Manager buildBackend *buildbackend.Backend buildCache *fscache.FSCache // legacy + features *map[string]bool buildkit *buildkit.Builder - builderVersion types.BuilderVersion daemon *daemon.Daemon api *apiserver.Server cluster *cluster.Cluster @@ -300,20 +299,12 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio if err != nil { return opts, errors.Wrap(err, "failed to create buildmanager") } - var bv types.BuilderVersion - if v, ok := config.Features["buildkit"]; ok { - if v { - bv = types.BuilderBuildKit - } else { - bv = types.BuilderV1 - } - } return routerOptions{ sessionManager: sm, buildBackend: bb, buildCache: buildCache, buildkit: bk, - builderVersion: bv, + features: daemon.Features(), daemon: daemon, }, nil } @@ -487,9 +478,9 @@ func initRouter(opts routerOptions) { checkpointrouter.NewRouter(opts.daemon, decoder), container.NewRouter(opts.daemon, decoder), image.NewRouter(opts.daemon.ImageService()), - systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.builderVersion), + systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.features), volume.NewRouter(opts.daemon.VolumesService()), - build.NewRouter(opts.buildBackend, opts.daemon, opts.builderVersion), + build.NewRouter(opts.buildBackend, opts.daemon, opts.features), sessionrouter.NewRouter(opts.sessionManager), swarmrouter.NewRouter(opts.cluster), pluginrouter.NewRouter(opts.daemon.PluginManager()), diff --git a/daemon/daemon.go b/daemon/daemon.go index 377e1ee51b..51cdee7594 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -136,6 +136,11 @@ func (daemon *Daemon) HasExperimental() bool { return daemon.configStore != nil && daemon.configStore.Experimental } +// Features returns the features map from configStore +func (daemon *Daemon) Features() *map[string]bool { + return &daemon.configStore.Features +} + func (daemon *Daemon) restore() error { containers := make(map[string]*container.Container) diff --git a/daemon/reload.go b/daemon/reload.go index 0b9785a3a9..026d7dd517 100644 --- a/daemon/reload.go +++ b/daemon/reload.go @@ -45,6 +45,7 @@ func (daemon *Daemon) Reload(conf *config.Config) (err error) { daemon.reloadDebug(conf, attributes) daemon.reloadMaxConcurrentDownloadsAndUploads(conf, attributes) daemon.reloadShutdownTimeout(conf, attributes) + daemon.reloadFeatures(conf, attributes) if err := daemon.reloadClusterDiscovery(conf, attributes); err != nil { return err @@ -322,3 +323,13 @@ func (daemon *Daemon) reloadNetworkDiagnosticPort(conf *config.Config, attribute return nil } + +// reloadFeatures updates configuration with enabled/disabled features +func (daemon *Daemon) reloadFeatures(conf *config.Config, attributes map[string]string) { + // update corresponding configuration + // note that we allow features option to be entirely unset + daemon.configStore.Features = conf.Features + + // prepare reload event attributes with updatable configurations + attributes["features"] = fmt.Sprintf("%v", daemon.configStore.Features) +}