Browse code

Merge pull request #24073 from johnharris85/move-restart-policy-check-to-daemon

Move restart-policy validation from client to daemon.

Vincent Demeester authored on 2016/08/26 00:02:30
Showing 4 changed files
... ...
@@ -255,6 +255,23 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon
255 255
 		}
256 256
 	}
257 257
 
258
+	p := hostConfig.RestartPolicy
259
+
260
+	switch p.Name {
261
+	case "always", "unless-stopped", "no":
262
+		if p.MaximumRetryCount != 0 {
263
+			return nil, fmt.Errorf("maximum restart count not valid with restart policy of '%s'", p.Name)
264
+		}
265
+	case "on-failure":
266
+		if p.MaximumRetryCount < 1 {
267
+			return nil, fmt.Errorf("maximum restart count must be a positive integer")
268
+		}
269
+	case "":
270
+	// do nothing
271
+	default:
272
+		return nil, fmt.Errorf("invalid restart policy '%s'", p.Name)
273
+	}
274
+
258 275
 	// Now do platform-specific verification
259 276
 	return verifyPlatformContainerSettings(daemon, hostConfig, config, update)
260 277
 }
... ...
@@ -703,6 +703,66 @@ func (s *DockerSuite) TestContainerApiInvalidPortSyntax(c *check.C) {
703 703
 	c.Assert(string(b[:]), checker.Contains, "invalid port")
704 704
 }
705 705
 
706
+func (s *DockerSuite) TestContainerApiInvalidRestartPolicyName(c *check.C) {
707
+	config := `{
708
+		"Image": "busybox",
709
+		"HostConfig": {
710
+			"RestartPolicy": {
711
+				"Name": "something",
712
+				"MaximumRetryCount": 0
713
+			}
714
+		}
715
+	}`
716
+
717
+	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
718
+	c.Assert(err, checker.IsNil)
719
+	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
720
+
721
+	b, err := readBody(body)
722
+	c.Assert(err, checker.IsNil)
723
+	c.Assert(string(b[:]), checker.Contains, "invalid restart policy")
724
+}
725
+
726
+func (s *DockerSuite) TestContainerApiInvalidRestartPolicyRetryMismatch(c *check.C) {
727
+	config := `{
728
+		"Image": "busybox",
729
+		"HostConfig": {
730
+			"RestartPolicy": {
731
+				"Name": "always",
732
+				"MaximumRetryCount": 2
733
+			}
734
+		}
735
+	}`
736
+
737
+	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
738
+	c.Assert(err, checker.IsNil)
739
+	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
740
+
741
+	b, err := readBody(body)
742
+	c.Assert(err, checker.IsNil)
743
+	c.Assert(string(b[:]), checker.Contains, "maximum restart count not valid with restart policy")
744
+}
745
+
746
+func (s *DockerSuite) TestContainerApiInvalidRestartPolicyPositiveRetryCount(c *check.C) {
747
+	config := `{
748
+		"Image": "busybox",
749
+		"HostConfig": {
750
+			"RestartPolicy": {
751
+				"Name": "on-failure",
752
+				"MaximumRetryCount": -2
753
+			}
754
+		}
755
+	}`
756
+
757
+	res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
758
+	c.Assert(err, checker.IsNil)
759
+	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
760
+
761
+	b, err := readBody(body)
762
+	c.Assert(err, checker.IsNil)
763
+	c.Assert(string(b[:]), checker.Contains, "maximum restart count must be a positive integer")
764
+}
765
+
706 766
 // Issue 7941 - test to make sure a "null" in JSON is just ignored.
707 767
 // W/o this fix a null in JSON would be parsed into a string var as "null"
708 768
 func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
... ...
@@ -729,35 +729,22 @@ func ParseRestartPolicy(policy string) (container.RestartPolicy, error) {
729 729
 		return p, nil
730 730
 	}
731 731
 
732
-	var (
733
-		parts = strings.Split(policy, ":")
734
-		name  = parts[0]
735
-	)
732
+	parts := strings.Split(policy, ":")
736 733
 
737
-	p.Name = name
738
-	switch name {
739
-	case "always", "unless-stopped":
740
-		if len(parts) > 1 {
741
-			return p, fmt.Errorf("maximum restart count not valid with restart policy of \"%s\"", name)
742
-		}
743
-	case "no":
744
-		// do nothing
745
-	case "on-failure":
746
-		if len(parts) > 2 {
747
-			return p, fmt.Errorf("restart count format is not valid, usage: 'on-failure:N' or 'on-failure'")
734
+	if len(parts) > 2 {
735
+		return p, fmt.Errorf("invalid restart policy format")
736
+	}
737
+	if len(parts) == 2 {
738
+		count, err := strconv.Atoi(parts[1])
739
+		if err != nil {
740
+			return p, fmt.Errorf("maximum retry count must be an integer")
748 741
 		}
749
-		if len(parts) == 2 {
750
-			count, err := strconv.Atoi(parts[1])
751
-			if err != nil {
752
-				return p, err
753
-			}
754 742
 
755
-			p.MaximumRetryCount = count
756
-		}
757
-	default:
758
-		return p, fmt.Errorf("invalid restart policy %s", name)
743
+		p.MaximumRetryCount = count
759 744
 	}
760 745
 
746
+	p.Name = parts[0]
747
+
761 748
 	return p, nil
762 749
 }
763 750
 
... ...
@@ -556,11 +556,8 @@ func TestParseModes(t *testing.T) {
556 556
 
557 557
 func TestParseRestartPolicy(t *testing.T) {
558 558
 	invalids := map[string]string{
559
-		"something":          "invalid restart policy something",
560
-		"always:2":           "maximum restart count not valid with restart policy of \"always\"",
561
-		"always:2:3":         "maximum restart count not valid with restart policy of \"always\"",
562
-		"on-failure:invalid": `strconv.ParseInt: parsing "invalid": invalid syntax`,
563
-		"on-failure:2:5":     "restart count format is not valid, usage: 'on-failure:N' or 'on-failure'",
559
+		"always:2:3":         "invalid restart policy format",
560
+		"on-failure:invalid": "maximum retry count must be an integer",
564 561
 	}
565 562
 	valids := map[string]container.RestartPolicy{
566 563
 		"": {},