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