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