Signed-off-by: Michael Crosby <michael@docker.com>
| ... | ... |
@@ -501,6 +501,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
|
| 501 | 501 |
err error |
| 502 | 502 |
exitCode int |
| 503 | 503 |
failCount int |
| 504 |
+ exit bool |
|
| 504 | 505 |
|
| 505 | 506 |
policy = container.hostConfig.RestartPolicy |
| 506 | 507 |
) |
| ... | ... |
@@ -522,8 +523,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
|
| 522 | 522 |
if exitCode, err = container.daemon.Run(container, pipes, callback); err != nil {
|
| 523 | 523 |
failCount++ |
| 524 | 524 |
|
| 525 |
- if failCount == 100 {
|
|
| 526 |
- container.requestedStop = true |
|
| 525 |
+ if failCount == policy.MaximumRetryCount {
|
|
| 526 |
+ exit = true |
|
| 527 | 527 |
} |
| 528 | 528 |
|
| 529 | 529 |
utils.Errorf("Error running container: %s", err)
|
| ... | ... |
@@ -561,7 +562,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
|
| 561 | 561 |
container.daemon.srv.LogEvent("die", container.ID, container.daemon.repositories.ImageName(container.Image))
|
| 562 | 562 |
} |
| 563 | 563 |
|
| 564 |
- if (policy == "always" || (policy == "on-failure" && exitCode != 0)) && !container.requestedStop {
|
|
| 564 |
+ if (policy.Name == "always" || (policy.Name == "on-failure" && exitCode != 0)) && !container.requestedStop || !exit {
|
|
| 565 | 565 |
container.command.Cmd = copyCmd(&container.command.Cmd) |
| 566 | 566 |
|
| 567 | 567 |
time.Sleep(1 * time.Second) |
| ... | ... |
@@ -25,6 +25,11 @@ type DeviceMapping struct {
|
| 25 | 25 |
CgroupPermissions string |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
+type RestartPolicy struct {
|
|
| 29 |
+ Name string |
|
| 30 |
+ MaximumRetryCount int |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 28 | 33 |
type HostConfig struct {
|
| 29 | 34 |
Binds []string |
| 30 | 35 |
ContainerIDFile string |
| ... | ... |
@@ -40,7 +45,7 @@ type HostConfig struct {
|
| 40 | 40 |
NetworkMode NetworkMode |
| 41 | 41 |
CapAdd []string |
| 42 | 42 |
CapDrop []string |
| 43 |
- RestartPolicy string |
|
| 43 |
+ RestartPolicy RestartPolicy |
|
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 | 46 |
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| ... | ... |
@@ -49,11 +54,12 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| 49 | 49 |
Privileged: job.GetenvBool("Privileged"),
|
| 50 | 50 |
PublishAllPorts: job.GetenvBool("PublishAllPorts"),
|
| 51 | 51 |
NetworkMode: NetworkMode(job.Getenv("NetworkMode")),
|
| 52 |
- RestartPolicy: job.Getenv("RestartPolicy"),
|
|
| 53 | 52 |
} |
| 53 |
+ |
|
| 54 | 54 |
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
| 55 | 55 |
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
| 56 | 56 |
job.GetenvJson("Devices", &hostConfig.Devices)
|
| 57 |
+ job.GetenvJson("RestartPolicy", &hostConfig.RestartPolicy)
|
|
| 57 | 58 |
if Binds := job.GetenvList("Binds"); Binds != nil {
|
| 58 | 59 |
hostConfig.Binds = Binds |
| 59 | 60 |
} |
| ... | ... |
@@ -75,5 +81,6 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| 75 | 75 |
if CapDrop := job.GetenvList("CapDrop"); CapDrop != nil {
|
| 76 | 76 |
hostConfig.CapDrop = CapDrop |
| 77 | 77 |
} |
| 78 |
+ |
|
| 78 | 79 |
return hostConfig |
| 79 | 80 |
} |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io/ioutil" |
| 6 | 6 |
"path" |
| 7 |
+ "strconv" |
|
| 7 | 8 |
"strings" |
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/docker/nat" |
| ... | ... |
@@ -234,6 +235,11 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 234 | 234 |
return nil, nil, cmd, fmt.Errorf("--net: invalid net mode: %v", err)
|
| 235 | 235 |
} |
| 236 | 236 |
|
| 237 |
+ restartPolicy, err := parseRestartPolicy(*flRestartPolicy) |
|
| 238 |
+ if err != nil {
|
|
| 239 |
+ return nil, nil, cmd, err |
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 237 | 242 |
config := &Config{
|
| 238 | 243 |
Hostname: hostname, |
| 239 | 244 |
Domainname: domainname, |
| ... | ... |
@@ -272,7 +278,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 272 | 272 |
Devices: deviceMappings, |
| 273 | 273 |
CapAdd: flCapAdd.GetAll(), |
| 274 | 274 |
CapDrop: flCapDrop.GetAll(), |
| 275 |
- RestartPolicy: *flRestartPolicy, |
|
| 275 |
+ RestartPolicy: restartPolicy, |
|
| 276 | 276 |
} |
| 277 | 277 |
|
| 278 | 278 |
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
| ... | ... |
@@ -287,6 +293,38 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 287 | 287 |
return config, hostConfig, cmd, nil |
| 288 | 288 |
} |
| 289 | 289 |
|
| 290 |
+// parseRestartPolicy returns the parsed policy or an error indicating what is incorrect |
|
| 291 |
+func parseRestartPolicy(policy string) (RestartPolicy, error) {
|
|
| 292 |
+ p := RestartPolicy{}
|
|
| 293 |
+ |
|
| 294 |
+ if policy == "" {
|
|
| 295 |
+ return p, nil |
|
| 296 |
+ } |
|
| 297 |
+ |
|
| 298 |
+ var ( |
|
| 299 |
+ parts = strings.Split(policy, ":") |
|
| 300 |
+ name = parts[0] |
|
| 301 |
+ ) |
|
| 302 |
+ |
|
| 303 |
+ switch name {
|
|
| 304 |
+ case "no", "on-failure", "always": |
|
| 305 |
+ p.Name = name |
|
| 306 |
+ |
|
| 307 |
+ if len(parts) == 2 {
|
|
| 308 |
+ count, err := strconv.Atoi(parts[1]) |
|
| 309 |
+ if err != nil {
|
|
| 310 |
+ return p, err |
|
| 311 |
+ } |
|
| 312 |
+ |
|
| 313 |
+ p.MaximumRetryCount = count |
|
| 314 |
+ } |
|
| 315 |
+ default: |
|
| 316 |
+ return p, fmt.Errorf("invalid restart policy %s", name)
|
|
| 317 |
+ } |
|
| 318 |
+ |
|
| 319 |
+ return p, nil |
|
| 320 |
+} |
|
| 321 |
+ |
|
| 290 | 322 |
// options will come in the format of name.key=value or name.option |
| 291 | 323 |
func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) {
|
| 292 | 324 |
out := make(map[string][]string, len(opts.GetAll())) |