diff --git a/daemon/container.go b/daemon/container.go index 6bf6aca2a3..3383276e6d 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -501,6 +501,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { err error exitCode int failCount int + exit bool policy = container.hostConfig.RestartPolicy ) @@ -522,8 +523,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { if exitCode, err = container.daemon.Run(container, pipes, callback); err != nil { failCount++ - if failCount == 100 { - container.requestedStop = true + if failCount == policy.MaximumRetryCount { + exit = true } utils.Errorf("Error running container: %s", err) @@ -561,7 +562,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { container.daemon.srv.LogEvent("die", container.ID, container.daemon.repositories.ImageName(container.Image)) } - if (policy == "always" || (policy == "on-failure" && exitCode != 0)) && !container.requestedStop { + if (policy.Name == "always" || (policy.Name == "on-failure" && exitCode != 0)) && !container.requestedStop || !exit { container.command.Cmd = copyCmd(&container.command.Cmd) time.Sleep(1 * time.Second) diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index f2a369842a..4dd4766e5e 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -25,6 +25,11 @@ type DeviceMapping struct { CgroupPermissions string } +type RestartPolicy struct { + Name string + MaximumRetryCount int +} + type HostConfig struct { Binds []string ContainerIDFile string @@ -40,7 +45,7 @@ type HostConfig struct { NetworkMode NetworkMode CapAdd []string CapDrop []string - RestartPolicy string + RestartPolicy RestartPolicy } func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { @@ -49,11 +54,12 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { Privileged: job.GetenvBool("Privileged"), PublishAllPorts: job.GetenvBool("PublishAllPorts"), NetworkMode: NetworkMode(job.Getenv("NetworkMode")), - RestartPolicy: job.Getenv("RestartPolicy"), } + job.GetenvJson("LxcConf", &hostConfig.LxcConf) job.GetenvJson("PortBindings", &hostConfig.PortBindings) job.GetenvJson("Devices", &hostConfig.Devices) + job.GetenvJson("RestartPolicy", &hostConfig.RestartPolicy) if Binds := job.GetenvList("Binds"); Binds != nil { hostConfig.Binds = Binds } @@ -75,5 +81,6 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { if CapDrop := job.GetenvList("CapDrop"); CapDrop != nil { hostConfig.CapDrop = CapDrop } + return hostConfig } diff --git a/runconfig/parse.go b/runconfig/parse.go index 3cab86234f..ea6e9ebca2 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "path" + "strconv" "strings" "github.com/docker/docker/nat" @@ -234,6 +235,11 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf return nil, nil, cmd, fmt.Errorf("--net: invalid net mode: %v", err) } + restartPolicy, err := parseRestartPolicy(*flRestartPolicy) + if err != nil { + return nil, nil, cmd, err + } + config := &Config{ Hostname: hostname, Domainname: domainname, @@ -272,7 +278,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf Devices: deviceMappings, CapAdd: flCapAdd.GetAll(), CapDrop: flCapDrop.GetAll(), - RestartPolicy: *flRestartPolicy, + RestartPolicy: restartPolicy, } if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit { @@ -287,6 +293,38 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf return config, hostConfig, cmd, nil } +// parseRestartPolicy returns the parsed policy or an error indicating what is incorrect +func parseRestartPolicy(policy string) (RestartPolicy, error) { + p := RestartPolicy{} + + if policy == "" { + return p, nil + } + + var ( + parts = strings.Split(policy, ":") + name = parts[0] + ) + + switch name { + case "no", "on-failure", "always": + p.Name = name + + if len(parts) == 2 { + count, err := strconv.Atoi(parts[1]) + if err != nil { + return p, err + } + + p.MaximumRetryCount = count + } + default: + return p, fmt.Errorf("invalid restart policy %s", name) + } + + return p, nil +} + // options will come in the format of name.key=value or name.option func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) { out := make(map[string][]string, len(opts.GetAll()))