cmd/dockerd/daemon.go
1b95590d
 package main
 
 import (
59d45c38
 	"context"
bfed4b7c
 	"crypto/tls"
007ef161
 	"fmt"
 	"os"
 	"path/filepath"
96ce3a19
 	"strings"
531f4122
 	"time"
007ef161
 
7841d6ab
 	"github.com/docker/distribution/uuid"
8d346762
 	"github.com/docker/docker/api"
a0bf80fe
 	apiserver "github.com/docker/docker/api/server"
0296797f
 	buildbackend "github.com/docker/docker/api/server/backend/build"
8d346762
 	"github.com/docker/docker/api/server/middleware"
a793564b
 	"github.com/docker/docker/api/server/router"
1af76ef5
 	"github.com/docker/docker/api/server/router/build"
3976a33c
 	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
1af76ef5
 	"github.com/docker/docker/api/server/router/container"
41b27de4
 	distributionrouter "github.com/docker/docker/api/server/router/distribution"
1af76ef5
 	"github.com/docker/docker/api/server/router/image"
 	"github.com/docker/docker/api/server/router/network"
c410222e
 	pluginrouter "github.com/docker/docker/api/server/router/plugin"
ec7b6238
 	sessionrouter "github.com/docker/docker/api/server/router/session"
534a90a9
 	swarmrouter "github.com/docker/docker/api/server/router/swarm"
1af76ef5
 	systemrouter "github.com/docker/docker/api/server/router/system"
 	"github.com/docker/docker/api/server/router/volume"
5c3d2d55
 	"github.com/docker/docker/builder/dockerfile"
 	"github.com/docker/docker/builder/fscache"
ce375503
 	"github.com/docker/docker/cli/debug"
63503caf
 	"github.com/docker/docker/daemon"
534a90a9
 	"github.com/docker/docker/daemon/cluster"
db63f937
 	"github.com/docker/docker/daemon/config"
c204fce2
 	"github.com/docker/docker/daemon/listeners"
9b782d3a
 	"github.com/docker/docker/daemon/logger"
8054a303
 	"github.com/docker/docker/dockerversion"
9c4570a9
 	"github.com/docker/docker/libcontainerd"
fb833947
 	dopts "github.com/docker/docker/opts"
8d346762
 	"github.com/docker/docker/pkg/authorization"
27cfa68a
 	"github.com/docker/docker/pkg/jsonmessage"
531f4122
 	"github.com/docker/docker/pkg/pidfile"
2b045027
 	"github.com/docker/docker/pkg/plugingetter"
c9f3fd3f
 	"github.com/docker/docker/pkg/signal"
fe5b34ba
 	"github.com/docker/docker/pkg/system"
38de272b
 	"github.com/docker/docker/plugin"
afade423
 	"github.com/docker/docker/registry"
f0d26e16
 	"github.com/docker/docker/runconfig"
8e034802
 	"github.com/docker/go-connections/tlsconfig"
59d45c38
 	swarmapi "github.com/docker/swarmkit/api"
41445a47
 	"github.com/moby/buildkit/session"
ec7b6238
 	"github.com/pkg/errors"
1009e6a4
 	"github.com/sirupsen/logrus"
fb833947
 	"github.com/spf13/pflag"
1b95590d
 )
 
677a6b35
 // DaemonCli represents the daemon CLI.
 type DaemonCli struct {
db63f937
 	*config.Config
fb833947
 	configFile *string
 	flags      *pflag.FlagSet
57aef3b4
 
4192fe9c
 	api             *apiserver.Server
 	d               *daemon.Daemon
 	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
677a6b35
 }
 
fb833947
 // NewDaemonCli returns a daemon CLI
96ce3a19
 func NewDaemonCli() *DaemonCli {
fb833947
 	return &DaemonCli{}
353b7c8e
 }
 
9ff9a91a
 func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
57aef3b4
 	stopc := make(chan bool)
 	defer close(stopc)
 
7841d6ab
 	// warn from uuid package when running the daemon
 	uuid.Loggerf = logrus.Warnf
 
9ff9a91a
 	opts.SetDefaultOptions(opts.flags)
96ce3a19
 
fb833947
 	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
57aef3b4
 		return err
677a6b35
 	}
fb833947
 	cli.configFile = &opts.configFile
 	cli.flags = opts.flags
677a6b35
 
 	if cli.Config.Debug {
ce375503
 		debug.Enable()
677a6b35
 	}
78578125
 
7781a1bf
 	if cli.Config.Experimental {
96ce3a19
 		logrus.Warn("Running experimental build")
1b95590d
 	}
711e5803
 
87a450a3
 	logrus.SetFormatter(&logrus.TextFormatter{
27cfa68a
 		TimestampFormat: jsonmessage.RFC3339NanoFixed,
87a450a3
 		DisableColors:   cli.Config.RawLogs,
af64e396
 		FullTimestamp:   true,
87a450a3
 	})
711e5803
 
ff686743
 	system.InitLCOW(cli.Config.Experimental)
 
6578ad90
 	if err := setDefaultUmask(); err != nil {
57aef3b4
 		return fmt.Errorf("Failed to set umask: %v", err)
6578ad90
 	}
 
96ce3a19
 	if len(cli.LogConfig.Config) > 0 {
 		if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil {
57aef3b4
 			return fmt.Errorf("Failed to set log opts: %v", err)
9b782d3a
 		}
 	}
 
46ec4c1a
 	// Create the daemon root before we create ANY other files (PID, or migrate keys)
 	// to ensure the appropriate ACL is set (particularly relevant on Windows)
 	if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
 		return err
 	}
 
96ce3a19
 	if cli.Pidfile != "" {
 		pf, err := pidfile.New(cli.Pidfile)
531f4122
 		if err != nil {
57aef3b4
 			return fmt.Errorf("Error starting daemon: %v", err)
531f4122
 		}
 		defer func() {
57aef3b4
 			if err := pf.Remove(); err != nil {
531f4122
 				logrus.Error(err)
 			}
 		}()
 	}
afade423
 
8f68adfa
 	// TODO: extract to newApiServerConfig()
351f6b8e
 	serverConfig := &apiserver.Config{
8d346762
 		Logging:     true,
 		SocketGroup: cli.Config.SocketGroup,
 		Version:     dockerversion.Version,
2feb88cb
 		CorsHeaders: cli.Config.CorsHeaders,
bfed4b7c
 	}
 
677a6b35
 	if cli.Config.TLS {
 		tlsOptions := tlsconfig.Options{
ddd5278b
 			CAFile:             cli.Config.CommonTLSOptions.CAFile,
 			CertFile:           cli.Config.CommonTLSOptions.CertFile,
 			KeyFile:            cli.Config.CommonTLSOptions.KeyFile,
 			ExclusiveRootPools: true,
677a6b35
 		}
 
 		if cli.Config.TLSVerify {
96ce3a19
 			// server requires and verifies client's certificate
677a6b35
 			tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
bfed4b7c
 		}
677a6b35
 		tlsConfig, err := tlsconfig.Server(tlsOptions)
bfed4b7c
 		if err != nil {
57aef3b4
 			return err
bfed4b7c
 		}
 		serverConfig.TLSConfig = tlsConfig
50f09060
 	}
 
677a6b35
 	if len(cli.Config.Hosts) == 0 {
 		cli.Config.Hosts = make([]string, 1)
e38767e1
 	}
34c29277
 
8f68adfa
 	cli.api = apiserver.New(serverConfig)
34c29277
 
7318eba5
 	var hosts []string
 
677a6b35
 	for i := 0; i < len(cli.Config.Hosts); i++ {
50f09060
 		var err error
fb833947
 		if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
57aef3b4
 			return fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
50f09060
 		}
677a6b35
 
 		protoAddr := cli.Config.Hosts[i]
5eda566f
 		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
 		if len(protoAddrParts) != 2 {
57aef3b4
 			return fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
5eda566f
 		}
5ee0a941
 
 		proto := protoAddrParts[0]
 		addr := protoAddrParts[1]
 
 		// It's a bad idea to bind to TCP without tlsverify.
 		if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
f25e5cee
 			logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
5ee0a941
 		}
3d6f5984
 		ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
34c29277
 		if err != nil {
57aef3b4
 			return err
34c29277
 		}
3d6f5984
 		ls = wrapListeners(proto, ls)
5ee0a941
 		// If we're binding to a TCP port, make sure that a container doesn't try to use it.
 		if proto == "tcp" {
 			if err := allocateDaemonPort(addr); err != nil {
57aef3b4
 				return err
5ee0a941
 			}
 		}
dc4dcf89
 		logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
7318eba5
 		hosts = append(hosts, protoAddrParts[1])
8f68adfa
 		cli.api.Accept(addr, ls...)
5eda566f
 	}
a0bf80fe
 
5258297d
 	registryService, err := registry.NewService(cli.Config.ServiceOptions)
 	if err != nil {
 		return err
 	}
 
77a50ffa
 	containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)
9c4570a9
 	if err != nil {
57aef3b4
 		return err
9c4570a9
 	}
3c25656e
 	signal.Trap(func() {
 		cli.stop()
 		<-stopc // wait for daemonCli.start() to return
cc4da811
 	}, logrus.StandardLogger())
9c4570a9
 
e128a656
 	// Notify that the API is active, but before daemon is set up.
 	preNotifySystem()
 
38de272b
 	pluginStore := plugin.NewStore()
 
8f68adfa
 	if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil {
38de272b
 		logrus.Fatalf("Error creating middlewares: %v", err)
 	}
 
 	d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote, pluginStore)
08230703
 	if err != nil {
57aef3b4
 		return fmt.Errorf("Error starting daemon: %v", err)
08230703
 	}
 
7318eba5
 	d.StoreHosts(hosts)
 
38de272b
 	// validate after NewDaemon has restored enabled plugins. Dont change order.
 	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
 		return fmt.Errorf("Error validating authorization plugin: %v", err)
 	}
 
8f68adfa
 	// TODO: move into startMetricsServer()
3343d234
 	if cli.Config.MetricsAddress != "" {
 		if !d.HasExperimental() {
 			return fmt.Errorf("metrics-addr is only supported when experimental is enabled")
 		}
 		if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
 			return err
 		}
 	}
 
8f68adfa
 	// TODO: createAndStartCluster()
534a90a9
 	name, _ := os.Hostname()
 
59d45c38
 	// Use a buffered channel to pass changes from store watch API to daemon
 	// A buffer allows store watch API and daemon processing to not wait for each other
 	watchStream := make(chan *swarmapi.WatchMessage, 32)
 
534a90a9
 	c, err := cluster.New(cluster.Config{
a0ccd0d4
 		Root:                   cli.Config.Root,
 		Name:                   name,
 		Backend:                d,
72c3bcf2
 		PluginBackend:          d.PluginManager(),
a0ccd0d4
 		NetworkSubnetsProvider: d,
 		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
4d95ea31
 		RuntimeRoot:            cli.getSwarmRunRoot(),
59d45c38
 		WatchStream:            watchStream,
534a90a9
 	})
 	if err != nil {
 		logrus.Fatalf("Error creating cluster component: %v", err)
 	}
e2ec0067
 	d.SetCluster(c)
 	err = c.Start()
 	if err != nil {
 		logrus.Fatalf("Error starting cluster component: %v", err)
 	}
534a90a9
 
c9fb551d
 	// Restart all autostart containers which has a swarm endpoint
 	// and is not yet running now that we have successfully
 	// initialized the cluster.
 	d.RestartSwarmContainers()
 
08230703
 	logrus.Info("Daemon has completed initialization")
 
c5393ee1
 	cli.d = d
 
8f68adfa
 	routerOptions, err := newRouterOptions(cli.Config, d)
 	if err != nil {
 		return err
 	}
 	routerOptions.api = cli.api
 	routerOptions.cluster = c
 
 	initRouter(routerOptions)
da982cf5
 
59d45c38
 	// process cluster change notifications
 	watchCtx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go d.ProcessClusterNotifications(watchCtx, watchStream)
 
57aef3b4
 	cli.setupConfigReloadTrap()
677a6b35
 
a8b84cd8
 	// The serve API routine never exits unless an error occurs
 	// We need to start it as a goroutine and wait on it so
 	// daemon doesn't exit
 	serveAPIWait := make(chan error)
8f68adfa
 	go cli.api.Wait(serveAPIWait)
a8b84cd8
 
ca5795ce
 	// after the daemon is done setting up we can notify systemd api
da982cf5
 	notifySystem()
181fea24
 
459e58ff
 	// Daemon is fully initialized and handling API traffic
531f4122
 	// Wait for serve API to complete
459e58ff
 	errAPI := <-serveAPIWait
534a90a9
 	c.Cleanup()
cc703784
 	shutdownDaemon(d)
9c4570a9
 	containerdRemote.Cleanup()
459e58ff
 	if errAPI != nil {
57aef3b4
 		return fmt.Errorf("Shutting down due to ServeAPI error: %v", errAPI)
 	}
 
 	return nil
 }
 
8f68adfa
 type routerOptions struct {
 	sessionManager *session.Manager
 	buildBackend   *buildbackend.Backend
 	buildCache     *fscache.FSCache
 	daemon         *daemon.Daemon
 	api            *apiserver.Server
 	cluster        *cluster.Cluster
 }
 
 func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptions, error) {
 	opts := routerOptions{}
 	sm, err := session.NewManager()
 	if err != nil {
 		return opts, errors.Wrap(err, "failed to create sessionmanager")
 	}
 
 	builderStateDir := filepath.Join(config.Root, "builder")
 
 	buildCache, err := fscache.NewFSCache(fscache.Opt{
 		Backend: fscache.NewNaiveCacheBackend(builderStateDir),
 		Root:    builderStateDir,
 		GCPolicy: fscache.GCPolicy{ // TODO: expose this in config
 			MaxSize:         1024 * 1024 * 512,  // 512MB
 			MaxKeepDuration: 7 * 24 * time.Hour, // 1 week
 		},
 	})
 	if err != nil {
 		return opts, errors.Wrap(err, "failed to create fscache")
 	}
 
 	manager, err := dockerfile.NewBuildManager(daemon, sm, buildCache, daemon.IDMappings())
 	if err != nil {
 		return opts, err
 	}
 
 	bb, err := buildbackend.NewBackend(daemon, manager, buildCache)
 	if err != nil {
 		return opts, errors.Wrap(err, "failed to create buildmanager")
 	}
 
 	return routerOptions{
 		sessionManager: sm,
 		buildBackend:   bb,
 		buildCache:     buildCache,
 		daemon:         daemon,
 	}, nil
 }
 
57aef3b4
 func (cli *DaemonCli) reloadConfig() {
db63f937
 	reload := func(config *config.Config) {
4192fe9c
 
2b045027
 		// Revalidate and reload the authorization plugins
 		if err := validateAuthzPlugins(config.AuthorizationPlugins, cli.d.PluginStore); err != nil {
 			logrus.Fatalf("Error validating authorization plugin: %v", err)
 			return
 		}
4192fe9c
 		cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins)
 
57aef3b4
 		if err := cli.d.Reload(config); err != nil {
 			logrus.Errorf("Error reconfiguring the daemon: %v", err)
 			return
 		}
4192fe9c
 
57aef3b4
 		if config.IsValueSet("debug") {
ce375503
 			debugEnabled := debug.IsEnabled()
57aef3b4
 			switch {
 			case debugEnabled && !config.Debug: // disable debug
ce375503
 				debug.Disable()
57aef3b4
 			case config.Debug && !debugEnabled: // enable debug
ce375503
 				debug.Enable()
531f4122
 			}
57aef3b4
 
531f4122
 		}
459e58ff
 	}
57aef3b4
 
db63f937
 	if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
57aef3b4
 		logrus.Error(err)
 	}
 }
 
 func (cli *DaemonCli) stop() {
 	cli.api.Close()
1b95590d
 }
01724c1c
 
531f4122
 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
 // d.Shutdown() is waiting too long to kill container or worst it's
 // blocked there
cc703784
 func shutdownDaemon(d *daemon.Daemon) {
 	shutdownTimeout := d.ShutdownTimeout()
531f4122
 	ch := make(chan struct{})
 	go func() {
b08f071e
 		d.Shutdown()
531f4122
 		close(ch)
 	}()
cc703784
 	if shutdownTimeout < 0 {
 		<-ch
 		logrus.Debug("Clean shutdown succeeded")
 		return
 	}
531f4122
 	select {
 	case <-ch:
51462327
 		logrus.Debug("Clean shutdown succeeded")
cc703784
 	case <-time.After(time.Duration(shutdownTimeout) * time.Second):
531f4122
 		logrus.Error("Force shutdown daemon")
 	}
 }
677a6b35
 
9ff9a91a
 func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
db63f937
 	conf := opts.daemonConfig
fb833947
 	flags := opts.flags
9ff9a91a
 	conf.Debug = opts.Debug
 	conf.Hosts = opts.Hosts
 	conf.LogLevel = opts.LogLevel
 	conf.TLS = opts.TLS
 	conf.TLSVerify = opts.TLSVerify
db63f937
 	conf.CommonTLSOptions = config.CommonTLSOptions{}
677a6b35
 
9ff9a91a
 	if opts.TLSOptions != nil {
 		conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
 		conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
 		conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
677a6b35
 	}
 
e428c824
 	if conf.TrustKeyPath == "" {
 		conf.TrustKeyPath = filepath.Join(
 			getDaemonConfDir(conf.Root),
 			defaultTrustKeyFile)
 	}
 
df7a72cf
 	if flags.Changed("graph") && flags.Changed("data-root") {
 		return nil, fmt.Errorf(`cannot specify both "--graph" and "--data-root" option`)
 	}
 
fb833947
 	if opts.configFile != "" {
db63f937
 		c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
677a6b35
 		if err != nil {
9894576f
 			if flags.Changed("config-file") || !os.IsNotExist(err) {
9b47b7b1
 				return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v", opts.configFile, err)
677a6b35
 			}
 		}
 		// the merged configuration can be nil if the config file didn't exist.
 		// leave the current configuration as it is if when that happens.
 		if c != nil {
db63f937
 			conf = c
677a6b35
 		}
 	}
 
db63f937
 	if err := config.Validate(conf); err != nil {
7b2e5216
 		return nil, err
 	}
 
f7f101d5
 	if !conf.V2Only {
12828001
 		logrus.Warnf(`The "disable-legacy-registry" option is deprecated and wil be removed in Docker v17.12. Interacting with legacy (v1) registries will no longer be supported in Docker v17.12"`)
 	}
 
df7a72cf
 	if flags.Changed("graph") {
12828001
 		logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`)
df7a72cf
 	}
 
e4c9079d
 	// Labels of the docker engine used to allow multiple values associated with the same key.
 	// This is deprecated in 1.13, and, be removed after 3 release cycles.
 	// The following will check the conflict of labels, and report a warning for deprecation.
 	//
5a9cee7b
 	// TODO: After 3 release cycles (17.12) an error will be returned, and labels will be
e4c9079d
 	// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels):
 	//
 	// newLabels, err := daemon.GetConflictFreeLabels(config.Labels)
 	// if err != nil {
 	//	return nil, err
 	// }
 	// config.Labels = newLabels
 	//
db63f937
 	if _, err := config.GetConflictFreeLabels(conf.Labels); err != nil {
e4c9079d
 		logrus.Warnf("Engine labels with duplicate keys and conflicting values have been deprecated: %s", err)
 	}
 
cd344697
 	// Regardless of whether the user sets it to true or false, if they
 	// specify TLSVerify at all then we need to turn on TLS
9ff9a91a
 	if conf.IsValueSet(FlagTLSVerify) {
db63f937
 		conf.TLS = true
cd344697
 	}
 
 	// ensure that the log level is the one set after merging configurations
9ff9a91a
 	setLogLevel(conf.LogLevel)
cd344697
 
db63f937
 	return conf, nil
677a6b35
 }
1af76ef5
 
8f68adfa
 func initRouter(opts routerOptions) {
f0d26e16
 	decoder := runconfig.ContainerDecoder{}
 
3976a33c
 	routers := []router.Router{
 		// we need to add the checkpoint router before the container router or the DELETE gets masked
8f68adfa
 		checkpointrouter.NewRouter(opts.daemon, decoder),
 		container.NewRouter(opts.daemon, decoder),
 		image.NewRouter(opts.daemon, decoder),
 		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache),
 		volume.NewRouter(opts.daemon),
 		build.NewRouter(opts.buildBackend, opts.daemon),
 		sessionrouter.NewRouter(opts.sessionManager),
 		swarmrouter.NewRouter(opts.cluster),
 		pluginrouter.NewRouter(opts.daemon.PluginManager()),
 		distributionrouter.NewRouter(opts.daemon),
3976a33c
 	}
0dfbf960
 
8f68adfa
 	if opts.daemon.NetworkControllerEnabled() {
 		routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
a793564b
 	}
 
8f68adfa
 	if opts.daemon.HasExperimental() {
3976a33c
 		for _, r := range routers {
 			for _, route := range r.Routes() {
 				if experimental, ok := route.(router.ExperimentalRoute); ok {
 					experimental.Enable()
 				}
 			}
 		}
 	}
 
408c7ade
 	opts.api.InitRouter(routers...)
1af76ef5
 }
8d346762
 
8f68adfa
 // TODO: remove this from cli and return the authzMiddleware
709bf8b7
 func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error {
7534f172
 	v := cfg.Version
8d346762
 
38de272b
 	exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental)
7781a1bf
 	s.UseMiddleware(exp)
 
8d346762
 	vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
 	s.UseMiddleware(vm)
 
7d4eab55
 	if cfg.CorsHeaders != "" {
8d346762
 		c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
 		s.UseMiddleware(c)
 	}
 
38de272b
 	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore)
 	cli.Config.AuthzMiddleware = cli.authzMiddleware
4192fe9c
 	s.UseMiddleware(cli.authzMiddleware)
2b045027
 	return nil
 }
 
 // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
 // plugins present on the host and available to the daemon
 func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
 	for _, reqPlugin := range requestedPlugins {
42860010
 		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
2b045027
 			return err
 		}
 	}
 	return nil
8d346762
 }