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