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