github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/cmd/dockerd/daemon.go (about)

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