diff --git a/daemon/create.go b/daemon/create.go index e659ec526d..93576f521f 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -69,6 +69,10 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *containe return nil, err } + if err := daemon.mergeAndVerifyLogConfig(¶ms.HostConfig.LogConfig); err != nil { + return nil, err + } + if container, err = daemon.newContainer(params.Name, params.Config, imgID); err != nil { return nil, err } diff --git a/daemon/daemon.go b/daemon/daemon.go index f7b71e5161..55c76742e5 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -35,7 +35,6 @@ import ( "github.com/docker/engine-api/types/strslice" // register graph drivers _ "github.com/docker/docker/daemon/graphdriver/register" - "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/network" dmetadata "github.com/docker/docker/distribution/metadata" "github.com/docker/docker/distribution/xfer" @@ -669,12 +668,6 @@ func NewDaemon(config *Config, registryService *registry.Service, containerdRemo return nil, fmt.Errorf("error setting default isolation mode: %v", err) } - // Verify logging driver type - if config.LogConfig.Type != "none" { - if _, err := logger.GetLogDriver(config.LogConfig.Type); err != nil { - return nil, fmt.Errorf("error finding the logging driver: %v", err) - } - } logrus.Debugf("Using default logging driver %s", config.LogConfig.Type) if err := configureMaxThreads(config); err != nil { @@ -1351,11 +1344,6 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon return nil, nil } - logCfg := daemon.getLogConfig(hostConfig.LogConfig) - if err := logger.ValidateLogOpts(logCfg.Type, logCfg.Config); err != nil { - return nil, err - } - for port := range hostConfig.PortBindings { _, portStr := nat.SplitProtoPort(string(port)) if _, err := nat.ParsePort(portStr); err != nil { diff --git a/daemon/logger/factory.go b/daemon/logger/factory.go index 5ec0f6731d..9cf716b09a 100644 --- a/daemon/logger/factory.go +++ b/daemon/logger/factory.go @@ -19,16 +19,23 @@ type logdriverFactory struct { } func (lf *logdriverFactory) register(name string, c Creator) error { - lf.m.Lock() - defer lf.m.Unlock() - - if _, ok := lf.registry[name]; ok { + if lf.driverRegistered(name) { return fmt.Errorf("logger: log driver named '%s' is already registered", name) } + + lf.m.Lock() lf.registry[name] = c + lf.m.Unlock() return nil } +func (lf *logdriverFactory) driverRegistered(name string) bool { + lf.m.Lock() + _, ok := lf.registry[name] + lf.m.Unlock() + return ok +} + func (lf *logdriverFactory) registerLogOptValidator(name string, l LogOptValidator) error { lf.m.Lock() defer lf.m.Unlock() @@ -81,9 +88,17 @@ func GetLogDriver(name string) (Creator, error) { // ValidateLogOpts checks the options for the given log driver. The // options supported are specific to the LogDriver implementation. func ValidateLogOpts(name string, cfg map[string]string) error { - l := factory.getLogOptValidator(name) - if l != nil { - return l(cfg) + if name == "none" { + return nil + } + + if !factory.driverRegistered(name) { + return fmt.Errorf("logger: no log driver named '%s' is registered", name) + } + + validator := factory.getLogOptValidator(name) + if validator != nil { + return validator(cfg) } return nil } diff --git a/daemon/logs.go b/daemon/logs.go index 4d4d2376be..57d44acb3b 100644 --- a/daemon/logs.go +++ b/daemon/logs.go @@ -107,24 +107,16 @@ func (daemon *Daemon) getLogger(container *container.Container) (logger.Logger, if container.LogDriver != nil && container.IsRunning() { return container.LogDriver, nil } - cfg := daemon.getLogConfig(container.HostConfig.LogConfig) - if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil { - return nil, err - } - return container.StartLogger(cfg) + return container.StartLogger(container.HostConfig.LogConfig) } // StartLogging initializes and starts the container logging stream. func (daemon *Daemon) StartLogging(container *container.Container) error { - cfg := daemon.getLogConfig(container.HostConfig.LogConfig) - if cfg.Type == "none" { + if container.HostConfig.LogConfig.Type == "none" { return nil // do not start logging routines } - if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil { - return err - } - l, err := container.StartLogger(cfg) + l, err := container.StartLogger(container.HostConfig.LogConfig) if err != nil { return fmt.Errorf("Failed to initialize logging driver: %v", err) } @@ -142,15 +134,19 @@ func (daemon *Daemon) StartLogging(container *container.Container) error { return nil } -// getLogConfig returns the log configuration for the container. -func (daemon *Daemon) getLogConfig(cfg containertypes.LogConfig) containertypes.LogConfig { - if cfg.Type != "" || len(cfg.Config) > 0 { // container has log driver configured - if cfg.Type == "" { - cfg.Type = jsonfilelog.Name - } - return cfg +// mergeLogConfig merges the daemon log config to the container's log config if the container's log driver is not specified. +func (daemon *Daemon) mergeAndVerifyLogConfig(cfg *containertypes.LogConfig) error { + if cfg.Type == "" { + cfg.Type = daemon.defaultLogConfig.Type } - // Use daemon's default log config for containers - return daemon.defaultLogConfig + if cfg.Type == daemon.defaultLogConfig.Type { + for k, v := range daemon.defaultLogConfig.Config { + if _, ok := cfg.Config[k]; !ok { + cfg.Config[k] = v + } + } + } + + return logger.ValidateLogOpts(cfg.Type, cfg.Config) } diff --git a/daemon/start.go b/daemon/start.go index 483f61b506..002b37b4a0 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -41,6 +41,9 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos if err := daemon.setSecurityOptions(container, hostConfig); err != nil { return err } + if err := daemon.mergeAndVerifyLogConfig(&hostConfig.LogConfig); err != nil { + return err + } if err := daemon.setHostConfig(container, hostConfig); err != nil { return err } diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 2509b8b364..62307add8b 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -1748,17 +1748,21 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithContainerWithRestartPolicyAlway } func (s *DockerDaemonSuite) TestDaemonWideLogConfig(c *check.C) { - if err := s.d.StartWithBusybox("--log-driver=json-file", "--log-opt=max-size=1k"); err != nil { + if err := s.d.StartWithBusybox("--log-opt=max-size=1k"); err != nil { c.Fatal(err) } - out, err := s.d.Cmd("run", "-d", "--name=logtest", "busybox", "top") + name := "logtest" + out, err := s.d.Cmd("run", "-d", "--log-opt=max-file=5", "--name", name, "busybox", "top") c.Assert(err, check.IsNil, check.Commentf("Output: %s, err: %v", out, err)) - out, err = s.d.Cmd("inspect", "-f", "{{ .HostConfig.LogConfig.Config }}", "logtest") + + out, err = s.d.Cmd("inspect", "-f", "{{ .HostConfig.LogConfig.Config }}", name) c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) - cfg := strings.TrimSpace(out) - if cfg != "map[max-size:1k]" { - c.Fatalf("Unexpected log-opt: %s, expected map[max-size:1k]", cfg) - } + c.Assert(out, checker.Contains, "max-size:1k") + c.Assert(out, checker.Contains, "max-file:5") + + out, err = s.d.Cmd("inspect", "-f", "{{ .HostConfig.LogConfig.Type }}", name) + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) + c.Assert(strings.TrimSpace(out), checker.Equals, "json-file") } func (s *DockerDaemonSuite) TestDaemonRestartWithPausedContainer(c *check.C) {