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 }