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