github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/cmd/dockerd/daemon.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  	"time"
    13  
    14  	containerddefaults "github.com/containerd/containerd/defaults"
    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/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/sysinfo"
    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  	opts.SetDefaultOptions(opts.flags)
    79  
    80  	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
    81  		return err
    82  	}
    83  
    84  	if opts.Validate {
    85  		// If config wasn't OK we wouldn't have made it this far.
    86  		fmt.Fprintln(os.Stderr, "configuration OK")
    87  		return nil
    88  	}
    89  
    90  	warnOnDeprecatedConfigOptions(cli.Config)
    91  
    92  	if err := configureDaemonLogs(cli.Config); err != nil {
    93  		return err
    94  	}
    95  
    96  	logrus.Info("Starting up")
    97  
    98  	cli.configFile = &opts.configFile
    99  	cli.flags = opts.flags
   100  
   101  	if cli.Config.Debug {
   102  		debug.Enable()
   103  	}
   104  
   105  	if cli.Config.Experimental {
   106  		logrus.Warn("Running experimental build")
   107  	}
   108  
   109  	if cli.Config.IsRootless() {
   110  		logrus.Warn("Running in rootless mode. This mode has feature limitations.")
   111  	}
   112  	if rootless.RunningWithRootlessKit() {
   113  		logrus.Info("Running with RootlessKit integration")
   114  		if !cli.Config.IsRootless() {
   115  			return fmt.Errorf("rootless mode needs to be enabled for running with RootlessKit")
   116  		}
   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  	if err := setDefaultUmask(); err != nil {
   125  		return err
   126  	}
   127  
   128  	// Create the daemon root before we create ANY other files (PID, or migrate keys)
   129  	// to ensure the appropriate ACL is set (particularly relevant on Windows)
   130  	if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
   131  		return err
   132  	}
   133  
   134  	if err := system.MkdirAll(cli.Config.ExecRoot, 0700); err != nil {
   135  		return err
   136  	}
   137  
   138  	potentiallyUnderRuntimeDir := []string{cli.Config.ExecRoot}
   139  
   140  	if cli.Pidfile != "" {
   141  		pf, err := pidfile.New(cli.Pidfile)
   142  		if err != nil {
   143  			return errors.Wrap(err, "failed to start daemon")
   144  		}
   145  		potentiallyUnderRuntimeDir = append(potentiallyUnderRuntimeDir, cli.Pidfile)
   146  		defer func() {
   147  			if err := pf.Remove(); err != nil {
   148  				logrus.Error(err)
   149  			}
   150  		}()
   151  	}
   152  
   153  	if cli.Config.IsRootless() {
   154  		// Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIR
   155  		if _, err := homedir.StickRuntimeDirContents(potentiallyUnderRuntimeDir); err != nil {
   156  			// StickRuntimeDirContents returns nil error if XDG_RUNTIME_DIR is just unset
   157  			logrus.WithError(err).Warn("cannot set sticky bit on files under XDG_RUNTIME_DIR")
   158  		}
   159  	}
   160  
   161  	serverConfig, err := newAPIServerConfig(cli)
   162  	if err != nil {
   163  		return errors.Wrap(err, "failed to create API server")
   164  	}
   165  	cli.api = apiserver.New(serverConfig)
   166  
   167  	hosts, err := loadListeners(cli, serverConfig)
   168  	if err != nil {
   169  		return errors.Wrap(err, "failed to load listeners")
   170  	}
   171  
   172  	ctx, cancel := context.WithCancel(context.Background())
   173  	waitForContainerDShutdown, err := cli.initContainerD(ctx)
   174  	if waitForContainerDShutdown != nil {
   175  		defer waitForContainerDShutdown(10 * time.Second)
   176  	}
   177  	if err != nil {
   178  		cancel()
   179  		return err
   180  	}
   181  	defer cancel()
   182  
   183  	stopc := make(chan bool)
   184  	defer close(stopc)
   185  
   186  	signal.Trap(func() {
   187  		cli.stop()
   188  		<-stopc // wait for daemonCli.start() to return
   189  	}, logrus.StandardLogger())
   190  
   191  	// Notify that the API is active, but before daemon is set up.
   192  	preNotifyReady()
   193  
   194  	pluginStore := plugin.NewStore()
   195  
   196  	if err := cli.initMiddlewares(cli.api, serverConfig, pluginStore); err != nil {
   197  		logrus.Fatalf("Error creating middlewares: %v", err)
   198  	}
   199  
   200  	d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore)
   201  	if err != nil {
   202  		return errors.Wrap(err, "failed to start daemon")
   203  	}
   204  
   205  	d.StoreHosts(hosts)
   206  
   207  	// validate after NewDaemon has restored enabled plugins. Don't change order.
   208  	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
   209  		return errors.Wrap(err, "failed to validate authorization plugin")
   210  	}
   211  
   212  	cli.d = d
   213  
   214  	if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
   215  		return errors.Wrap(err, "failed to start metrics server")
   216  	}
   217  
   218  	c, err := createAndStartCluster(cli, d)
   219  	if err != nil {
   220  		logrus.Fatalf("Error starting cluster component: %v", err)
   221  	}
   222  
   223  	// Restart all autostart containers which has a swarm endpoint
   224  	// and is not yet running now that we have successfully
   225  	// initialized the cluster.
   226  	d.RestartSwarmContainers()
   227  
   228  	logrus.Info("Daemon has completed initialization")
   229  
   230  	routerOptions, err := newRouterOptions(cli.Config, d)
   231  	if err != nil {
   232  		return err
   233  	}
   234  	routerOptions.api = cli.api
   235  	routerOptions.cluster = c
   236  
   237  	initRouter(routerOptions)
   238  
   239  	go d.ProcessClusterNotifications(ctx, c.GetWatchStream())
   240  
   241  	cli.setupConfigReloadTrap()
   242  
   243  	// The serve API routine never exits unless an error occurs
   244  	// We need to start it as a goroutine and wait on it so
   245  	// daemon doesn't exit
   246  	serveAPIWait := make(chan error)
   247  	go cli.api.Wait(serveAPIWait)
   248  
   249  	// after the daemon is done setting up we can notify systemd api
   250  	notifyReady()
   251  
   252  	// Daemon is fully initialized and handling API traffic
   253  	// Wait for serve API to complete
   254  	errAPI := <-serveAPIWait
   255  	c.Cleanup()
   256  
   257  	// notify systemd that we're shutting down
   258  	notifyStopping()
   259  	shutdownDaemon(d)
   260  
   261  	// Stop notification processing and any background processes
   262  	cancel()
   263  
   264  	if errAPI != nil {
   265  		return errors.Wrap(errAPI, "shutting down due to ServeAPI error")
   266  	}
   267  
   268  	logrus.Info("Daemon shutdown complete")
   269  	return nil
   270  }
   271  
   272  type routerOptions struct {
   273  	sessionManager *session.Manager
   274  	buildBackend   *buildbackend.Backend
   275  	features       *map[string]bool
   276  	buildkit       *buildkit.Builder
   277  	daemon         *daemon.Daemon
   278  	api            *apiserver.Server
   279  	cluster        *cluster.Cluster
   280  }
   281  
   282  func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, error) {
   283  	opts := routerOptions{}
   284  	sm, err := session.NewManager()
   285  	if err != nil {
   286  		return opts, errors.Wrap(err, "failed to create sessionmanager")
   287  	}
   288  
   289  	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), d.IdentityMapping())
   290  	if err != nil {
   291  		return opts, err
   292  	}
   293  	cgroupParent := newCgroupParent(config)
   294  	bk, err := buildkit.New(buildkit.Opt{
   295  		SessionManager:      sm,
   296  		Root:                filepath.Join(config.Root, "buildkit"),
   297  		Dist:                d.DistributionServices(),
   298  		NetworkController:   d.NetworkController(),
   299  		DefaultCgroupParent: cgroupParent,
   300  		RegistryHosts:       d.RegistryHosts(),
   301  		BuilderConfig:       config.Builder,
   302  		Rootless:            d.Rootless(),
   303  		IdentityMapping:     d.IdentityMapping(),
   304  		DNSConfig:           config.DNSConfig,
   305  		ApparmorProfile:     daemon.DefaultApparmorProfile(),
   306  	})
   307  	if err != nil {
   308  		return opts, err
   309  	}
   310  
   311  	bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService)
   312  	if err != nil {
   313  		return opts, errors.Wrap(err, "failed to create buildmanager")
   314  	}
   315  	return routerOptions{
   316  		sessionManager: sm,
   317  		buildBackend:   bb,
   318  		buildkit:       bk,
   319  		features:       d.Features(),
   320  		daemon:         d,
   321  	}, nil
   322  }
   323  
   324  func (cli *DaemonCli) reloadConfig() {
   325  	reload := func(c *config.Config) {
   326  
   327  		// Revalidate and reload the authorization plugins
   328  		if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil {
   329  			logrus.Fatalf("Error validating authorization plugin: %v", err)
   330  			return
   331  		}
   332  		cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins)
   333  
   334  		if err := cli.d.Reload(c); err != nil {
   335  			logrus.Errorf("Error reconfiguring the daemon: %v", err)
   336  			return
   337  		}
   338  
   339  		if c.IsValueSet("debug") {
   340  			debugEnabled := debug.IsEnabled()
   341  			switch {
   342  			case debugEnabled && !c.Debug: // disable debug
   343  				debug.Disable()
   344  			case c.Debug && !debugEnabled: // enable debug
   345  				debug.Enable()
   346  			}
   347  		}
   348  	}
   349  
   350  	if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
   351  		logrus.Error(err)
   352  	}
   353  }
   354  
   355  func (cli *DaemonCli) stop() {
   356  	cli.api.Close()
   357  }
   358  
   359  // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
   360  // d.Shutdown() is waiting too long to kill container or worst it's
   361  // blocked there
   362  func shutdownDaemon(d *daemon.Daemon) {
   363  	shutdownTimeout := d.ShutdownTimeout()
   364  	ch := make(chan struct{})
   365  	go func() {
   366  		d.Shutdown()
   367  		close(ch)
   368  	}()
   369  	if shutdownTimeout < 0 {
   370  		<-ch
   371  		logrus.Debug("Clean shutdown succeeded")
   372  		return
   373  	}
   374  
   375  	timeout := time.NewTimer(time.Duration(shutdownTimeout) * time.Second)
   376  	defer timeout.Stop()
   377  
   378  	select {
   379  	case <-ch:
   380  		logrus.Debug("Clean shutdown succeeded")
   381  	case <-timeout.C:
   382  		logrus.Error("Force shutdown daemon")
   383  	}
   384  }
   385  
   386  func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
   387  	conf := opts.daemonConfig
   388  	flags := opts.flags
   389  	conf.Debug = opts.Debug
   390  	conf.Hosts = opts.Hosts
   391  	conf.LogLevel = opts.LogLevel
   392  
   393  	if opts.flags.Changed(FlagTLS) {
   394  		conf.TLS = &opts.TLS
   395  	}
   396  	if opts.flags.Changed(FlagTLSVerify) {
   397  		conf.TLSVerify = &opts.TLSVerify
   398  		v := true
   399  		conf.TLS = &v
   400  	}
   401  
   402  	conf.CommonTLSOptions = config.CommonTLSOptions{}
   403  
   404  	if opts.TLSOptions != nil {
   405  		conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
   406  		conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
   407  		conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
   408  	}
   409  
   410  	if conf.TrustKeyPath == "" {
   411  		daemonConfDir, err := getDaemonConfDir(conf.Root)
   412  		if err != nil {
   413  			return nil, err
   414  		}
   415  		conf.TrustKeyPath = filepath.Join(daemonConfDir, defaultTrustKeyFile)
   416  	}
   417  
   418  	if flags.Changed("graph") && flags.Changed("data-root") {
   419  		return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`)
   420  	}
   421  
   422  	if opts.configFile != "" {
   423  		c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
   424  		if err != nil {
   425  			if flags.Changed("config-file") || !os.IsNotExist(err) {
   426  				return nil, errors.Wrapf(err, "unable to configure the Docker daemon with file %s", opts.configFile)
   427  			}
   428  		}
   429  
   430  		// the merged configuration can be nil if the config file didn't exist.
   431  		// leave the current configuration as it is if when that happens.
   432  		if c != nil {
   433  			conf = c
   434  		}
   435  	}
   436  
   437  	if err := config.Validate(conf); err != nil {
   438  		return nil, err
   439  	}
   440  
   441  	if flags.Changed("graph") {
   442  		logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`)
   443  	}
   444  
   445  	// Check if duplicate label-keys with different values are found
   446  	newLabels, err := config.GetConflictFreeLabels(conf.Labels)
   447  	if err != nil {
   448  		return nil, err
   449  	}
   450  	conf.Labels = newLabels
   451  
   452  	// Regardless of whether the user sets it to true or false, if they
   453  	// specify TLSVerify at all then we need to turn on TLS
   454  	if conf.IsValueSet(FlagTLSVerify) {
   455  		v := true
   456  		conf.TLS = &v
   457  	}
   458  
   459  	if conf.TLSVerify == nil && conf.TLS != nil {
   460  		conf.TLSVerify = conf.TLS
   461  	}
   462  
   463  	return conf, nil
   464  }
   465  
   466  func warnOnDeprecatedConfigOptions(config *config.Config) {
   467  	if config.ClusterAdvertise != "" {
   468  		logrus.Warn(`The "cluster-advertise" option is deprecated. To be removed soon.`)
   469  	}
   470  	if config.ClusterStore != "" {
   471  		logrus.Warn(`The "cluster-store" option is deprecated. To be removed soon.`)
   472  	}
   473  	if len(config.ClusterOpts) > 0 {
   474  		logrus.Warn(`The "cluster-store-opt" option is deprecated. To be removed soon.`)
   475  	}
   476  }
   477  
   478  func initRouter(opts routerOptions) {
   479  	decoder := runconfig.ContainerDecoder{
   480  		GetSysInfo: func() *sysinfo.SysInfo {
   481  			return opts.daemon.RawSysInfo(true)
   482  		},
   483  	}
   484  
   485  	routers := []router.Router{
   486  		// we need to add the checkpoint router before the container router or the DELETE gets masked
   487  		checkpointrouter.NewRouter(opts.daemon, decoder),
   488  		container.NewRouter(opts.daemon, decoder, opts.daemon.RawSysInfo(true).CgroupUnified),
   489  		image.NewRouter(opts.daemon.ImageService()),
   490  		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features),
   491  		volume.NewRouter(opts.daemon.VolumesService()),
   492  		build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
   493  		sessionrouter.NewRouter(opts.sessionManager),
   494  		swarmrouter.NewRouter(opts.cluster),
   495  		pluginrouter.NewRouter(opts.daemon.PluginManager()),
   496  		distributionrouter.NewRouter(opts.daemon.ImageService()),
   497  	}
   498  
   499  	grpcBackends := []grpcrouter.Backend{}
   500  	for _, b := range []interface{}{opts.daemon, opts.buildBackend} {
   501  		if b, ok := b.(grpcrouter.Backend); ok {
   502  			grpcBackends = append(grpcBackends, b)
   503  		}
   504  	}
   505  	if len(grpcBackends) > 0 {
   506  		routers = append(routers, grpcrouter.NewRouter(grpcBackends...))
   507  	}
   508  
   509  	if opts.daemon.NetworkControllerEnabled() {
   510  		routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
   511  	}
   512  
   513  	if opts.daemon.HasExperimental() {
   514  		for _, r := range routers {
   515  			for _, route := range r.Routes() {
   516  				if experimental, ok := route.(router.ExperimentalRoute); ok {
   517  					experimental.Enable()
   518  				}
   519  			}
   520  		}
   521  	}
   522  
   523  	opts.api.InitRouter(routers...)
   524  }
   525  
   526  // TODO: remove this from cli and return the authzMiddleware
   527  func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config, pluginStore plugingetter.PluginGetter) error {
   528  	v := cfg.Version
   529  
   530  	exp := middleware.NewExperimentalMiddleware(cli.Config.Experimental)
   531  	s.UseMiddleware(exp)
   532  
   533  	vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
   534  	s.UseMiddleware(vm)
   535  
   536  	if cfg.CorsHeaders != "" {
   537  		c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
   538  		s.UseMiddleware(c)
   539  	}
   540  
   541  	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, pluginStore)
   542  	cli.Config.AuthzMiddleware = cli.authzMiddleware
   543  	s.UseMiddleware(cli.authzMiddleware)
   544  	return nil
   545  }
   546  
   547  func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
   548  	opts, err := cli.getPlatformContainerdDaemonOpts()
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  
   553  	if cli.Config.Debug {
   554  		opts = append(opts, supervisor.WithLogLevel("debug"))
   555  	} else if cli.Config.LogLevel != "" {
   556  		opts = append(opts, supervisor.WithLogLevel(cli.Config.LogLevel))
   557  	}
   558  
   559  	if !cli.Config.CriContainerd {
   560  		opts = append(opts, supervisor.WithPlugin("cri", nil))
   561  	}
   562  
   563  	return opts, nil
   564  }
   565  
   566  func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
   567  	serverConfig := &apiserver.Config{
   568  		Logging:     true,
   569  		SocketGroup: cli.Config.SocketGroup,
   570  		Version:     dockerversion.Version,
   571  		CorsHeaders: cli.Config.CorsHeaders,
   572  	}
   573  
   574  	if cli.Config.TLS != nil && *cli.Config.TLS {
   575  		tlsOptions := tlsconfig.Options{
   576  			CAFile:             cli.Config.CommonTLSOptions.CAFile,
   577  			CertFile:           cli.Config.CommonTLSOptions.CertFile,
   578  			KeyFile:            cli.Config.CommonTLSOptions.KeyFile,
   579  			ExclusiveRootPools: true,
   580  		}
   581  
   582  		if cli.Config.TLSVerify == nil || *cli.Config.TLSVerify {
   583  			// server requires and verifies client's certificate
   584  			tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
   585  		}
   586  		tlsConfig, err := tlsconfig.Server(tlsOptions)
   587  		if err != nil {
   588  			return nil, err
   589  		}
   590  		serverConfig.TLSConfig = tlsConfig
   591  	}
   592  
   593  	if len(cli.Config.Hosts) == 0 {
   594  		cli.Config.Hosts = make([]string, 1)
   595  	}
   596  
   597  	return serverConfig, nil
   598  }
   599  
   600  // checkTLSAuthOK checks basically for an explicitly disabled TLS/TLSVerify
   601  // Going forward we do not want to support a scenario where dockerd listens
   602  //   on TCP without either TLS client auth (or an explicit opt-in to disable it)
   603  func checkTLSAuthOK(c *config.Config) bool {
   604  	if c.TLS == nil {
   605  		// Either TLS is enabled by default, in which case TLS verification should be enabled by default, or explicitly disabled
   606  		// Or TLS is disabled by default... in any of these cases, we can just take the default value as to how to proceed
   607  		return DefaultTLSValue
   608  	}
   609  
   610  	if !*c.TLS {
   611  		// TLS is explicitly disabled, which is supported
   612  		return true
   613  	}
   614  
   615  	if c.TLSVerify == nil {
   616  		// this actually shouldn't happen since we set TLSVerify on the config object anyway
   617  		// But in case it does get here, be cautious and assume this is not supported.
   618  		return false
   619  	}
   620  
   621  	// Either TLSVerify is explicitly enabled or disabled, both cases are supported
   622  	return true
   623  }
   624  
   625  func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
   626  	var hosts []string
   627  	seen := make(map[string]struct{}, len(cli.Config.Hosts))
   628  
   629  	useTLS := DefaultTLSValue
   630  	if cli.Config.TLS != nil {
   631  		useTLS = *cli.Config.TLS
   632  	}
   633  
   634  	for i := 0; i < len(cli.Config.Hosts); i++ {
   635  		var err error
   636  		if cli.Config.Hosts[i], err = dopts.ParseHost(useTLS, honorXDG, cli.Config.Hosts[i]); err != nil {
   637  			return nil, errors.Wrapf(err, "error parsing -H %s", cli.Config.Hosts[i])
   638  		}
   639  		if _, ok := seen[cli.Config.Hosts[i]]; ok {
   640  			continue
   641  		}
   642  		seen[cli.Config.Hosts[i]] = struct{}{}
   643  
   644  		protoAddr := cli.Config.Hosts[i]
   645  		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
   646  		if len(protoAddrParts) != 2 {
   647  			return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
   648  		}
   649  
   650  		proto := protoAddrParts[0]
   651  		addr := protoAddrParts[1]
   652  
   653  		// It's a bad idea to bind to TCP without tlsverify.
   654  		authEnabled := serverConfig.TLSConfig != nil && serverConfig.TLSConfig.ClientAuth == tls.RequireAndVerifyClientCert
   655  		if proto == "tcp" && !authEnabled {
   656  			logrus.WithField("host", protoAddr).Warn("Binding to IP address without --tlsverify is insecure and gives root access on this machine to everyone who has access to your network.")
   657  			logrus.WithField("host", protoAddr).Warn("Binding to an IP address, even on localhost, can also give access to scripts run in a browser. Be safe out there!")
   658  			time.Sleep(time.Second)
   659  
   660  			// If TLSVerify is explicitly set to false we'll take that as "Please let me shoot myself in the foot"
   661  			// We do not want to continue to support a default mode where tls verification is disabled, so we do some extra warnings here and eventually remove support
   662  			if !checkTLSAuthOK(cli.Config) {
   663  				ipAddr, _, err := net.SplitHostPort(addr)
   664  				if err != nil {
   665  					return nil, errors.Wrap(err, "error parsing tcp address")
   666  				}
   667  
   668  				// shortcut all this extra stuff for literal "localhost"
   669  				// -H supports specifying hostnames, since we want to bypass this on loopback interfaces we'll look it up here.
   670  				if ipAddr != "localhost" {
   671  					ip := net.ParseIP(ipAddr)
   672  					if ip == nil {
   673  						ipA, err := net.ResolveIPAddr("ip", ipAddr)
   674  						if err != nil {
   675  							logrus.WithError(err).WithField("host", ipAddr).Error("Error looking up specified host address")
   676  						}
   677  						if ipA != nil {
   678  							ip = ipA.IP
   679  						}
   680  					}
   681  					if ip == nil || !ip.IsLoopback() {
   682  						logrus.WithField("host", protoAddr).Warn("Binding to an IP address without --tlsverify is deprecated. Startup is intentionally being slowed down to show this message")
   683  						logrus.WithField("host", protoAddr).Warn("Please consider generating tls certificates with client validation to prevent exposing unauthenticated root access to your network")
   684  						logrus.WithField("host", protoAddr).Warnf("You can override this by explicitly specifying '--%s=false' or '--%s=false'", FlagTLS, FlagTLSVerify)
   685  						logrus.WithField("host", protoAddr).Warnf("Support for listening on TCP without authentication or explicit intent to run without authentication will be removed in the next release")
   686  
   687  						time.Sleep(15 * time.Second)
   688  					}
   689  				}
   690  			}
   691  		}
   692  		ls, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
   693  		if err != nil {
   694  			return nil, err
   695  		}
   696  		// If we're binding to a TCP port, make sure that a container doesn't try to use it.
   697  		if proto == "tcp" {
   698  			if err := allocateDaemonPort(addr); err != nil {
   699  				return nil, err
   700  			}
   701  		}
   702  		logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
   703  		hosts = append(hosts, protoAddrParts[1])
   704  		cli.api.Accept(addr, ls...)
   705  	}
   706  
   707  	return hosts, nil
   708  }
   709  
   710  func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
   711  	name, _ := os.Hostname()
   712  
   713  	// Use a buffered channel to pass changes from store watch API to daemon
   714  	// A buffer allows store watch API and daemon processing to not wait for each other
   715  	watchStream := make(chan *swarmapi.WatchMessage, 32)
   716  
   717  	c, err := cluster.New(cluster.Config{
   718  		Root:                   cli.Config.Root,
   719  		Name:                   name,
   720  		Backend:                d,
   721  		VolumeBackend:          d.VolumesService(),
   722  		ImageBackend:           d.ImageService(),
   723  		PluginBackend:          d.PluginManager(),
   724  		NetworkSubnetsProvider: d,
   725  		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
   726  		RaftHeartbeatTick:      cli.Config.SwarmRaftHeartbeatTick,
   727  		RaftElectionTick:       cli.Config.SwarmRaftElectionTick,
   728  		RuntimeRoot:            cli.getSwarmRunRoot(),
   729  		WatchStream:            watchStream,
   730  	})
   731  	if err != nil {
   732  		return nil, err
   733  	}
   734  	d.SetCluster(c)
   735  	err = c.Start()
   736  
   737  	return c, err
   738  }
   739  
   740  // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
   741  // plugins present on the host and available to the daemon
   742  func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
   743  	for _, reqPlugin := range requestedPlugins {
   744  		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
   745  			return err
   746  		}
   747  	}
   748  	return nil
   749  }
   750  
   751  func systemContainerdRunning(honorXDG bool) (string, bool, error) {
   752  	addr := containerddefaults.DefaultAddress
   753  	if honorXDG {
   754  		runtimeDir, err := homedir.GetRuntimeDir()
   755  		if err != nil {
   756  			return "", false, err
   757  		}
   758  		addr = filepath.Join(runtimeDir, "containerd", "containerd.sock")
   759  	}
   760  	_, err := os.Lstat(addr)
   761  	return addr, err == nil, nil
   762  }
   763  
   764  // configureDaemonLogs sets the logrus logging level and formatting
   765  func configureDaemonLogs(conf *config.Config) error {
   766  	if conf.LogLevel != "" {
   767  		lvl, err := logrus.ParseLevel(conf.LogLevel)
   768  		if err != nil {
   769  			return fmt.Errorf("unable to parse logging level: %s", conf.LogLevel)
   770  		}
   771  		logrus.SetLevel(lvl)
   772  	} else {
   773  		logrus.SetLevel(logrus.InfoLevel)
   774  	}
   775  	logrus.SetFormatter(&logrus.TextFormatter{
   776  		TimestampFormat: jsonmessage.RFC3339NanoFixed,
   777  		DisableColors:   conf.RawLogs,
   778  		FullTimestamp:   true,
   779  	})
   780  	return nil
   781  }