github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/cmd/dockerd/daemon.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  	"time"
    12  
    13  	containerddefaults "github.com/containerd/containerd/defaults"
    14  	"github.com/docker/distribution/uuid"
    15  	"github.com/docker/docker/api"
    16  	apiserver "github.com/docker/docker/api/server"
    17  	buildbackend "github.com/docker/docker/api/server/backend/build"
    18  	"github.com/docker/docker/api/server/middleware"
    19  	"github.com/docker/docker/api/server/router"
    20  	"github.com/docker/docker/api/server/router/build"
    21  	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
    22  	"github.com/docker/docker/api/server/router/container"
    23  	distributionrouter "github.com/docker/docker/api/server/router/distribution"
    24  	"github.com/docker/docker/api/server/router/image"
    25  	"github.com/docker/docker/api/server/router/network"
    26  	pluginrouter "github.com/docker/docker/api/server/router/plugin"
    27  	sessionrouter "github.com/docker/docker/api/server/router/session"
    28  	swarmrouter "github.com/docker/docker/api/server/router/swarm"
    29  	systemrouter "github.com/docker/docker/api/server/router/system"
    30  	"github.com/docker/docker/api/server/router/volume"
    31  	buildkit "github.com/docker/docker/builder/builder-next"
    32  	"github.com/docker/docker/builder/dockerfile"
    33  	"github.com/docker/docker/builder/fscache"
    34  	"github.com/docker/docker/cli/debug"
    35  	"github.com/docker/docker/daemon"
    36  	"github.com/docker/docker/daemon/cluster"
    37  	"github.com/docker/docker/daemon/config"
    38  	"github.com/docker/docker/daemon/listeners"
    39  	"github.com/docker/docker/dockerversion"
    40  	"github.com/docker/docker/libcontainerd/supervisor"
    41  	dopts "github.com/docker/docker/opts"
    42  	"github.com/docker/docker/pkg/authorization"
    43  	"github.com/docker/docker/pkg/homedir"
    44  	"github.com/docker/docker/pkg/jsonmessage"
    45  	"github.com/docker/docker/pkg/pidfile"
    46  	"github.com/docker/docker/pkg/plugingetter"
    47  	"github.com/docker/docker/pkg/signal"
    48  	"github.com/docker/docker/pkg/system"
    49  	"github.com/docker/docker/plugin"
    50  	"github.com/docker/docker/rootless"
    51  	"github.com/docker/docker/runconfig"
    52  	"github.com/docker/go-connections/tlsconfig"
    53  	swarmapi "github.com/docker/swarmkit/api"
    54  	"github.com/moby/buildkit/session"
    55  	"github.com/pkg/errors"
    56  	"github.com/sirupsen/logrus"
    57  	"github.com/spf13/pflag"
    58  )
    59  
    60  // DaemonCli represents the daemon CLI.
    61  type DaemonCli struct {
    62  	*config.Config
    63  	configFile *string
    64  	flags      *pflag.FlagSet
    65  
    66  	api             *apiserver.Server
    67  	d               *daemon.Daemon
    68  	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
    69  }
    70  
    71  // NewDaemonCli returns a daemon CLI
    72  func NewDaemonCli() *DaemonCli {
    73  	return &DaemonCli{}
    74  }
    75  
    76  func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
    77  	stopc := make(chan bool)
    78  	defer close(stopc)
    79  
    80  	// warn from uuid package when running the daemon
    81  	uuid.Loggerf = logrus.Warnf
    82  
    83  	opts.SetDefaultOptions(opts.flags)
    84  
    85  	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
    86  		return err
    87  	}
    88  
    89  	if err := configureDaemonLogs(cli.Config); err != nil {
    90  		return err
    91  	}
    92  
    93  	cli.configFile = &opts.configFile
    94  	cli.flags = opts.flags
    95  
    96  	if cli.Config.Debug {
    97  		debug.Enable()
    98  	}
    99  
   100  	if cli.Config.Experimental {
   101  		logrus.Warn("Running experimental build")
   102  		if cli.Config.IsRootless() {
   103  			logrus.Warn("Running in rootless mode. Cgroups, AppArmor, and CRIU are disabled.")
   104  		}
   105  	} else {
   106  		if cli.Config.IsRootless() {
   107  			return fmt.Errorf("rootless mode is supported only when running in experimental mode")
   108  		}
   109  	}
   110  	// return human-friendly error before creating files
   111  	if runtime.GOOS == "linux" && os.Geteuid() != 0 {
   112  		return fmt.Errorf("dockerd needs to be started with root. To see how to run dockerd in rootless mode with unprivileged user, see the documentation")
   113  	}
   114  
   115  	system.InitLCOW(cli.Config.Experimental)
   116  
   117  	if err := setDefaultUmask(); err != nil {
   118  		return err
   119  	}
   120  
   121  	// Create the daemon root before we create ANY other files (PID, or migrate keys)
   122  	// to ensure the appropriate ACL is set (particularly relevant on Windows)
   123  	if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
   124  		return err
   125  	}
   126  
   127  	if err := system.MkdirAll(cli.Config.ExecRoot, 0700, ""); err != nil {
   128  		return err
   129  	}
   130  
   131  	potentiallyUnderRuntimeDir := []string{cli.Config.ExecRoot}
   132  
   133  	if cli.Pidfile != "" {
   134  		pf, err := pidfile.New(cli.Pidfile)
   135  		if err != nil {
   136  			return errors.Wrap(err, "failed to start daemon")
   137  		}
   138  		potentiallyUnderRuntimeDir = append(potentiallyUnderRuntimeDir, cli.Pidfile)
   139  		defer func() {
   140  			if err := pf.Remove(); err != nil {
   141  				logrus.Error(err)
   142  			}
   143  		}()
   144  	}
   145  
   146  	if cli.Config.IsRootless() {
   147  		// Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIR
   148  		if _, err := homedir.StickRuntimeDirContents(potentiallyUnderRuntimeDir); err != nil {
   149  			// StickRuntimeDirContents returns nil error if XDG_RUNTIME_DIR is just unset
   150  			logrus.WithError(err).Warn("cannot set sticky bit on files under XDG_RUNTIME_DIR")
   151  		}
   152  	}
   153  
   154  	serverConfig, err := newAPIServerConfig(cli)
   155  	if err != nil {
   156  		return errors.Wrap(err, "failed to create API server")
   157  	}
   158  	cli.api = apiserver.New(serverConfig)
   159  
   160  	hosts, err := loadListeners(cli, serverConfig)
   161  	if err != nil {
   162  		return errors.Wrap(err, "failed to load listeners")
   163  	}
   164  
   165  	ctx, cancel := context.WithCancel(context.Background())
   166  	if err := cli.initContainerD(ctx); err != nil {
   167  		cancel()
   168  		return err
   169  	}
   170  	defer cancel()
   171  
   172  	signal.Trap(func() {
   173  		cli.stop()
   174  		<-stopc // wait for daemonCli.start() to return
   175  	}, logrus.StandardLogger())
   176  
   177  	// Notify that the API is active, but before daemon is set up.
   178  	preNotifySystem()
   179  
   180  	pluginStore := plugin.NewStore()
   181  
   182  	if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil {
   183  		logrus.Fatalf("Error creating middlewares: %v", err)
   184  	}
   185  
   186  	d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore)
   187  	if err != nil {
   188  		return errors.Wrap(err, "failed to start daemon")
   189  	}
   190  
   191  	d.StoreHosts(hosts)
   192  
   193  	// validate after NewDaemon has restored enabled plugins. Don't change order.
   194  	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
   195  		return errors.Wrap(err, "failed to validate authorization plugin")
   196  	}
   197  
   198  	// TODO: move into startMetricsServer()
   199  	if cli.Config.MetricsAddress != "" {
   200  		if !d.HasExperimental() {
   201  			return errors.Wrap(err, "metrics-addr is only supported when experimental is enabled")
   202  		}
   203  		if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
   204  			return err
   205  		}
   206  	}
   207  
   208  	c, err := createAndStartCluster(cli, d)
   209  	if err != nil {
   210  		logrus.Fatalf("Error starting cluster component: %v", err)
   211  	}
   212  
   213  	// Restart all autostart containers which has a swarm endpoint
   214  	// and is not yet running now that we have successfully
   215  	// initialized the cluster.
   216  	d.RestartSwarmContainers()
   217  
   218  	logrus.Info("Daemon has completed initialization")
   219  
   220  	cli.d = d
   221  
   222  	routerOptions, err := newRouterOptions(cli.Config, d)
   223  	if err != nil {
   224  		return err
   225  	}
   226  	routerOptions.api = cli.api
   227  	routerOptions.cluster = c
   228  
   229  	initRouter(routerOptions)
   230  
   231  	go d.ProcessClusterNotifications(ctx, c.GetWatchStream())
   232  
   233  	cli.setupConfigReloadTrap()
   234  
   235  	// The serve API routine never exits unless an error occurs
   236  	// We need to start it as a goroutine and wait on it so
   237  	// daemon doesn't exit
   238  	serveAPIWait := make(chan error)
   239  	go cli.api.Wait(serveAPIWait)
   240  
   241  	// after the daemon is done setting up we can notify systemd api
   242  	notifySystem()
   243  
   244  	// Daemon is fully initialized and handling API traffic
   245  	// Wait for serve API to complete
   246  	errAPI := <-serveAPIWait
   247  	c.Cleanup()
   248  
   249  	shutdownDaemon(d)
   250  
   251  	// Stop notification processing and any background processes
   252  	cancel()
   253  
   254  	if errAPI != nil {
   255  		return errors.Wrap(errAPI, "shutting down due to ServeAPI error")
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  type routerOptions struct {
   262  	sessionManager *session.Manager
   263  	buildBackend   *buildbackend.Backend
   264  	buildCache     *fscache.FSCache // legacy
   265  	features       *map[string]bool
   266  	buildkit       *buildkit.Builder
   267  	daemon         *daemon.Daemon
   268  	api            *apiserver.Server
   269  	cluster        *cluster.Cluster
   270  }
   271  
   272  func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, error) {
   273  	opts := routerOptions{}
   274  	sm, err := session.NewManager()
   275  	if err != nil {
   276  		return opts, errors.Wrap(err, "failed to create sessionmanager")
   277  	}
   278  
   279  	builderStateDir := filepath.Join(config.Root, "builder")
   280  
   281  	buildCache, err := fscache.NewFSCache(fscache.Opt{
   282  		Backend: fscache.NewNaiveCacheBackend(builderStateDir),
   283  		Root:    builderStateDir,
   284  		GCPolicy: fscache.GCPolicy{ // TODO: expose this in config
   285  			MaxSize:         1024 * 1024 * 512,  // 512MB
   286  			MaxKeepDuration: 7 * 24 * time.Hour, // 1 week
   287  		},
   288  	})
   289  	if err != nil {
   290  		return opts, errors.Wrap(err, "failed to create fscache")
   291  	}
   292  
   293  	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), sm, buildCache, d.IdentityMapping())
   294  	if err != nil {
   295  		return opts, err
   296  	}
   297  	cgroupParent := newCgroupParent(config)
   298  	bk, err := buildkit.New(buildkit.Opt{
   299  		SessionManager:      sm,
   300  		Root:                filepath.Join(config.Root, "buildkit"),
   301  		Dist:                d.DistributionServices(),
   302  		NetworkController:   d.NetworkController(),
   303  		DefaultCgroupParent: cgroupParent,
   304  		ResolverOpt:         d.NewResolveOptionsFunc(),
   305  		BuilderConfig:       config.Builder,
   306  		Rootless:            d.Rootless(),
   307  	})
   308  	if err != nil {
   309  		return opts, err
   310  	}
   311  
   312  	bb, err := buildbackend.NewBackend(d.ImageService(), manager, buildCache, bk)
   313  	if err != nil {
   314  		return opts, errors.Wrap(err, "failed to create buildmanager")
   315  	}
   316  	return routerOptions{
   317  		sessionManager: sm,
   318  		buildBackend:   bb,
   319  		buildCache:     buildCache,
   320  		buildkit:       bk,
   321  		features:       d.Features(),
   322  		daemon:         d,
   323  	}, nil
   324  }
   325  
   326  func (cli *DaemonCli) reloadConfig() {
   327  	reload := func(c *config.Config) {
   328  
   329  		// Revalidate and reload the authorization plugins
   330  		if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil {
   331  			logrus.Fatalf("Error validating authorization plugin: %v", err)
   332  			return
   333  		}
   334  		cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins)
   335  
   336  		// The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
   337  		// to be reserved for Docker's internal use, but this was never enforced.  Allowing
   338  		// configured labels to use these namespaces are deprecated for 18.05.
   339  		//
   340  		// The following will check the usage of such labels, and report a warning for deprecation.
   341  		//
   342  		// TODO: At the next stable release, the validation should be folded into the other
   343  		// configuration validation functions and an error will be returned instead, and this
   344  		// block should be deleted.
   345  		if err := config.ValidateReservedNamespaceLabels(c.Labels); err != nil {
   346  			logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
   347  		}
   348  
   349  		if err := cli.d.Reload(c); err != nil {
   350  			logrus.Errorf("Error reconfiguring the daemon: %v", err)
   351  			return
   352  		}
   353  
   354  		if c.IsValueSet("debug") {
   355  			debugEnabled := debug.IsEnabled()
   356  			switch {
   357  			case debugEnabled && !c.Debug: // disable debug
   358  				debug.Disable()
   359  			case c.Debug && !debugEnabled: // enable debug
   360  				debug.Enable()
   361  			}
   362  		}
   363  	}
   364  
   365  	if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
   366  		logrus.Error(err)
   367  	}
   368  }
   369  
   370  func (cli *DaemonCli) stop() {
   371  	cli.api.Close()
   372  }
   373  
   374  // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
   375  // d.Shutdown() is waiting too long to kill container or worst it's
   376  // blocked there
   377  func shutdownDaemon(d *daemon.Daemon) {
   378  	shutdownTimeout := d.ShutdownTimeout()
   379  	ch := make(chan struct{})
   380  	go func() {
   381  		d.Shutdown()
   382  		close(ch)
   383  	}()
   384  	if shutdownTimeout < 0 {
   385  		<-ch
   386  		logrus.Debug("Clean shutdown succeeded")
   387  		return
   388  	}
   389  	select {
   390  	case <-ch:
   391  		logrus.Debug("Clean shutdown succeeded")
   392  	case <-time.After(time.Duration(shutdownTimeout) * time.Second):
   393  		logrus.Error("Force shutdown daemon")
   394  	}
   395  }
   396  
   397  func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
   398  	conf := opts.daemonConfig
   399  	flags := opts.flags
   400  	conf.Debug = opts.Debug
   401  	conf.Hosts = opts.Hosts
   402  	conf.LogLevel = opts.LogLevel
   403  	conf.TLS = opts.TLS
   404  	conf.TLSVerify = opts.TLSVerify
   405  	conf.CommonTLSOptions = config.CommonTLSOptions{}
   406  
   407  	if opts.TLSOptions != nil {
   408  		conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
   409  		conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
   410  		conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
   411  	}
   412  
   413  	if flags.Changed("graph") && flags.Changed("data-root") {
   414  		return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`)
   415  	}
   416  
   417  	if opts.configFile != "" {
   418  		c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
   419  		if err != nil {
   420  			if flags.Changed("config-file") || !os.IsNotExist(err) {
   421  				return nil, errors.Wrapf(err, "unable to configure the Docker daemon with file %s", opts.configFile)
   422  			}
   423  		}
   424  		// the merged configuration can be nil if the config file didn't exist.
   425  		// leave the current configuration as it is if when that happens.
   426  		if c != nil {
   427  			conf = c
   428  		}
   429  	}
   430  
   431  	if err := config.Validate(conf); err != nil {
   432  		return nil, err
   433  	}
   434  
   435  	if flags.Changed("graph") {
   436  		logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`)
   437  	}
   438  
   439  	// Check if duplicate label-keys with different values are found
   440  	newLabels, err := config.GetConflictFreeLabels(conf.Labels)
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  	// The namespaces com.docker.*, io.docker.*, org.dockerproject.* have been documented
   445  	// to be reserved for Docker's internal use, but this was never enforced.  Allowing
   446  	// configured labels to use these namespaces are deprecated for 18.05.
   447  	//
   448  	// The following will check the usage of such labels, and report a warning for deprecation.
   449  	//
   450  	// TODO: At the next stable release, the validation should be folded into the other
   451  	// configuration validation functions and an error will be returned instead, and this
   452  	// block should be deleted.
   453  	if err := config.ValidateReservedNamespaceLabels(newLabels); err != nil {
   454  		logrus.Warnf("Configured labels using reserved namespaces is deprecated: %s", err)
   455  	}
   456  	conf.Labels = newLabels
   457  
   458  	// Regardless of whether the user sets it to true or false, if they
   459  	// specify TLSVerify at all then we need to turn on TLS
   460  	if conf.IsValueSet(FlagTLSVerify) {
   461  		conf.TLS = true
   462  	}
   463  
   464  	return conf, nil
   465  }
   466  
   467  func initRouter(opts routerOptions) {
   468  	decoder := runconfig.ContainerDecoder{}
   469  
   470  	routers := []router.Router{
   471  		// we need to add the checkpoint router before the container router or the DELETE gets masked
   472  		checkpointrouter.NewRouter(opts.daemon, decoder),
   473  		container.NewRouter(opts.daemon, decoder),
   474  		image.NewRouter(opts.daemon.ImageService()),
   475  		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.features),
   476  		volume.NewRouter(opts.daemon.VolumesService()),
   477  		build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
   478  		sessionrouter.NewRouter(opts.sessionManager),
   479  		swarmrouter.NewRouter(opts.cluster),
   480  		pluginrouter.NewRouter(opts.daemon.PluginManager()),
   481  		distributionrouter.NewRouter(opts.daemon.ImageService()),
   482  	}
   483  
   484  	if opts.daemon.NetworkControllerEnabled() {
   485  		routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
   486  	}
   487  
   488  	if opts.daemon.HasExperimental() {
   489  		for _, r := range routers {
   490  			for _, route := range r.Routes() {
   491  				if experimental, ok := route.(router.ExperimentalRoute); ok {
   492  					experimental.Enable()
   493  				}
   494  			}
   495  		}
   496  	}
   497  
   498  	opts.api.InitRouter(routers...)
   499  }
   500  
   501  // TODO: remove this from cli and return the authzMiddleware
   502  func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error {
   503  	v := cfg.Version
   504  
   505  	exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental)
   506  	s.UseMiddleware(exp)
   507  
   508  	vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
   509  	s.UseMiddleware(vm)
   510  
   511  	if cfg.CorsHeaders != "" {
   512  		c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
   513  		s.UseMiddleware(c)
   514  	}
   515  
   516  	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore)
   517  	cli.Config.AuthzMiddleware = cli.authzMiddleware
   518  	s.UseMiddleware(cli.authzMiddleware)
   519  	return nil
   520  }
   521  
   522  func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
   523  	opts, err := cli.getPlatformContainerdDaemonOpts()
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	if cli.Config.Debug {
   529  		opts = append(opts, supervisor.WithLogLevel("debug"))
   530  	} else if cli.Config.LogLevel != "" {
   531  		opts = append(opts, supervisor.WithLogLevel(cli.Config.LogLevel))
   532  	}
   533  
   534  	if !cli.Config.CriContainerd {
   535  		opts = append(opts, supervisor.WithPlugin("cri", nil))
   536  	}
   537  
   538  	return opts, nil
   539  }
   540  
   541  func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
   542  	serverConfig := &apiserver.Config{
   543  		Logging:     true,
   544  		SocketGroup: cli.Config.SocketGroup,
   545  		Version:     dockerversion.Version,
   546  		CorsHeaders: cli.Config.CorsHeaders,
   547  	}
   548  
   549  	if cli.Config.TLS {
   550  		tlsOptions := tlsconfig.Options{
   551  			CAFile:             cli.Config.CommonTLSOptions.CAFile,
   552  			CertFile:           cli.Config.CommonTLSOptions.CertFile,
   553  			KeyFile:            cli.Config.CommonTLSOptions.KeyFile,
   554  			ExclusiveRootPools: true,
   555  		}
   556  
   557  		if cli.Config.TLSVerify {
   558  			// server requires and verifies client's certificate
   559  			tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
   560  		}
   561  		tlsConfig, err := tlsconfig.Server(tlsOptions)
   562  		if err != nil {
   563  			return nil, err
   564  		}
   565  		serverConfig.TLSConfig = tlsConfig
   566  	}
   567  
   568  	if len(cli.Config.Hosts) == 0 {
   569  		cli.Config.Hosts = make([]string, 1)
   570  	}
   571  
   572  	return serverConfig, nil
   573  }
   574  
   575  func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
   576  	var hosts []string
   577  	for i := 0; i < len(cli.Config.Hosts); i++ {
   578  		var err error
   579  		if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, rootless.RunningWithNonRootUsername(), cli.Config.Hosts[i]); err != nil {
   580  			return nil, errors.Wrapf(err, "error parsing -H %s", cli.Config.Hosts[i])
   581  		}
   582  
   583  		protoAddr := cli.Config.Hosts[i]
   584  		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
   585  		if len(protoAddrParts) != 2 {
   586  			return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
   587  		}
   588  
   589  		proto := protoAddrParts[0]
   590  		addr := protoAddrParts[1]
   591  
   592  		// It's a bad idea to bind to TCP without tlsverify.
   593  		if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
   594  			logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
   595  		}
   596  		ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
   597  		if err != nil {
   598  			return nil, err
   599  		}
   600  		ls = wrapListeners(proto, ls)
   601  		// If we're binding to a TCP port, make sure that a container doesn't try to use it.
   602  		if proto == "tcp" {
   603  			if err := allocateDaemonPort(addr); err != nil {
   604  				return nil, err
   605  			}
   606  		}
   607  		logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
   608  		hosts = append(hosts, protoAddrParts[1])
   609  		cli.api.Accept(addr, ls...)
   610  	}
   611  
   612  	return hosts, nil
   613  }
   614  
   615  func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
   616  	name, _ := os.Hostname()
   617  
   618  	// Use a buffered channel to pass changes from store watch API to daemon
   619  	// A buffer allows store watch API and daemon processing to not wait for each other
   620  	watchStream := make(chan *swarmapi.WatchMessage, 32)
   621  
   622  	c, err := cluster.New(cluster.Config{
   623  		Root:                   cli.Config.Root,
   624  		Name:                   name,
   625  		Backend:                d,
   626  		VolumeBackend:          d.VolumesService(),
   627  		ImageBackend:           d.ImageService(),
   628  		PluginBackend:          d.PluginManager(),
   629  		NetworkSubnetsProvider: d,
   630  		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
   631  		RaftHeartbeatTick:      cli.Config.SwarmRaftHeartbeatTick,
   632  		RaftElectionTick:       cli.Config.SwarmRaftElectionTick,
   633  		RuntimeRoot:            cli.getSwarmRunRoot(),
   634  		WatchStream:            watchStream,
   635  	})
   636  	if err != nil {
   637  		return nil, err
   638  	}
   639  	d.SetCluster(c)
   640  	err = c.Start()
   641  
   642  	return c, err
   643  }
   644  
   645  // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
   646  // plugins present on the host and available to the daemon
   647  func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
   648  	for _, reqPlugin := range requestedPlugins {
   649  		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
   650  			return err
   651  		}
   652  	}
   653  	return nil
   654  }
   655  
   656  func systemContainerdRunning(isRootless bool) (string, bool, error) {
   657  	addr := containerddefaults.DefaultAddress
   658  	if isRootless {
   659  		runtimeDir, err := homedir.GetRuntimeDir()
   660  		if err != nil {
   661  			return "", false, err
   662  		}
   663  		addr = filepath.Join(runtimeDir, "containerd", "containerd.sock")
   664  	}
   665  	_, err := os.Lstat(addr)
   666  	return addr, err == nil, nil
   667  }
   668  
   669  // configureDaemonLogs sets the logrus logging level and formatting
   670  func configureDaemonLogs(conf *config.Config) error {
   671  	if conf.LogLevel != "" {
   672  		lvl, err := logrus.ParseLevel(conf.LogLevel)
   673  		if err != nil {
   674  			return fmt.Errorf("unable to parse logging level: %s", conf.LogLevel)
   675  		}
   676  		logrus.SetLevel(lvl)
   677  	} else {
   678  		logrus.SetLevel(logrus.InfoLevel)
   679  	}
   680  	logrus.SetFormatter(&logrus.TextFormatter{
   681  		TimestampFormat: jsonmessage.RFC3339NanoFixed,
   682  		DisableColors:   conf.RawLogs,
   683  		FullTimestamp:   true,
   684  	})
   685  	return nil
   686  }