Browse code

Move ParseLink and validators into runconfig.parse where they are used.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2015/12/16 11:36:35
Showing 7 changed files
... ...
@@ -19,7 +19,6 @@ import (
19 19
 	"github.com/docker/docker/layer"
20 20
 	pblkiodev "github.com/docker/docker/pkg/blkiodev"
21 21
 	"github.com/docker/docker/pkg/idtools"
22
-	"github.com/docker/docker/pkg/parsers"
23 22
 	"github.com/docker/docker/pkg/parsers/kernel"
24 23
 	"github.com/docker/docker/pkg/sysinfo"
25 24
 	"github.com/docker/docker/runconfig"
... ...
@@ -648,7 +647,7 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *
648 648
 	}
649 649
 
650 650
 	for _, l := range hostConfig.Links {
651
-		name, alias, err := parsers.ParseLink(l)
651
+		name, alias, err := runconfig.ParseLink(l)
652 652
 		if err != nil {
653 653
 			return err
654 654
 		}
... ...
@@ -4,13 +4,11 @@ import (
4 4
 	"fmt"
5 5
 	"net"
6 6
 	"os"
7
-	"path"
8 7
 	"regexp"
9 8
 	"strconv"
10 9
 	"strings"
11 10
 
12 11
 	"github.com/docker/docker/pkg/blkiodev"
13
-	"github.com/docker/docker/pkg/parsers"
14 12
 	"github.com/docker/go-units"
15 13
 )
16 14
 
... ...
@@ -221,82 +219,6 @@ func ValidateThrottleBpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
221 221
 	}, nil
222 222
 }
223 223
 
224
-// ValidateLink validates that the specified string has a valid link format (containerName:alias).
225
-func ValidateLink(val string) (string, error) {
226
-	if _, _, err := parsers.ParseLink(val); err != nil {
227
-		return val, err
228
-	}
229
-	return val, nil
230
-}
231
-
232
-// ValidDeviceMode checks if the mode for device is valid or not.
233
-// Valid mode is a composition of r (read), w (write), and m (mknod).
234
-func ValidDeviceMode(mode string) bool {
235
-	var legalDeviceMode = map[rune]bool{
236
-		'r': true,
237
-		'w': true,
238
-		'm': true,
239
-	}
240
-	if mode == "" {
241
-		return false
242
-	}
243
-	for _, c := range mode {
244
-		if !legalDeviceMode[c] {
245
-			return false
246
-		}
247
-		legalDeviceMode[c] = false
248
-	}
249
-	return true
250
-}
251
-
252
-// ValidateDevice validates a path for devices
253
-// It will make sure 'val' is in the form:
254
-//    [host-dir:]container-path[:mode]
255
-// It also validates the device mode.
256
-func ValidateDevice(val string) (string, error) {
257
-	return validatePath(val, ValidDeviceMode)
258
-}
259
-
260
-func validatePath(val string, validator func(string) bool) (string, error) {
261
-	var containerPath string
262
-	var mode string
263
-
264
-	if strings.Count(val, ":") > 2 {
265
-		return val, fmt.Errorf("bad format for path: %s", val)
266
-	}
267
-
268
-	split := strings.SplitN(val, ":", 3)
269
-	if split[0] == "" {
270
-		return val, fmt.Errorf("bad format for path: %s", val)
271
-	}
272
-	switch len(split) {
273
-	case 1:
274
-		containerPath = split[0]
275
-		val = path.Clean(containerPath)
276
-	case 2:
277
-		if isValid := validator(split[1]); isValid {
278
-			containerPath = split[0]
279
-			mode = split[1]
280
-			val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
281
-		} else {
282
-			containerPath = split[1]
283
-			val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
284
-		}
285
-	case 3:
286
-		containerPath = split[1]
287
-		mode = split[2]
288
-		if isValid := validator(split[2]); !isValid {
289
-			return val, fmt.Errorf("bad mode specified: %s", mode)
290
-		}
291
-		val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
292
-	}
293
-
294
-	if !path.IsAbs(containerPath) {
295
-		return val, fmt.Errorf("%s is not an absolute path", containerPath)
296
-	}
297
-	return val, nil
298
-}
299
-
300 224
 // ValidateEnv validates an environment variable and returns it.
301 225
 // If no value is specified, it returns the current value using os.Getenv.
302 226
 //
... ...
@@ -244,86 +244,6 @@ func TestValidateAttach(t *testing.T) {
244 244
 	}
245 245
 }
246 246
 
247
-func TestValidateLink(t *testing.T) {
248
-	valid := []string{
249
-		"name",
250
-		"dcdfbe62ecd0:alias",
251
-		"7a67485460b7642516a4ad82ecefe7f57d0c4916f530561b71a50a3f9c4e33da",
252
-		"angry_torvalds:linus",
253
-	}
254
-	invalid := map[string]string{
255
-		"":               "empty string specified for links",
256
-		"too:much:of:it": "bad format for links: too:much:of:it",
257
-	}
258
-
259
-	for _, link := range valid {
260
-		if _, err := ValidateLink(link); err != nil {
261
-			t.Fatalf("ValidateLink(`%q`) should succeed: error %q", link, err)
262
-		}
263
-	}
264
-
265
-	for link, expectedError := range invalid {
266
-		if _, err := ValidateLink(link); err == nil {
267
-			t.Fatalf("ValidateLink(`%q`) should have failed validation", link)
268
-		} else {
269
-			if !strings.Contains(err.Error(), expectedError) {
270
-				t.Fatalf("ValidateLink(`%q`) error should contain %q", link, expectedError)
271
-			}
272
-		}
273
-	}
274
-}
275
-
276
-func TestValidateDevice(t *testing.T) {
277
-	valid := []string{
278
-		"/home",
279
-		"/home:/home",
280
-		"/home:/something/else",
281
-		"/with space",
282
-		"/home:/with space",
283
-		"relative:/absolute-path",
284
-		"hostPath:/containerPath:r",
285
-		"/hostPath:/containerPath:rw",
286
-		"/hostPath:/containerPath:mrw",
287
-	}
288
-	invalid := map[string]string{
289
-		"":        "bad format for path: ",
290
-		"./":      "./ is not an absolute path",
291
-		"../":     "../ is not an absolute path",
292
-		"/:../":   "../ is not an absolute path",
293
-		"/:path":  "path is not an absolute path",
294
-		":":       "bad format for path: :",
295
-		"/tmp:":   " is not an absolute path",
296
-		":test":   "bad format for path: :test",
297
-		":/test":  "bad format for path: :/test",
298
-		"tmp:":    " is not an absolute path",
299
-		":test:":  "bad format for path: :test:",
300
-		"::":      "bad format for path: ::",
301
-		":::":     "bad format for path: :::",
302
-		"/tmp:::": "bad format for path: /tmp:::",
303
-		":/tmp::": "bad format for path: :/tmp::",
304
-		"path:ro": "ro is not an absolute path",
305
-		"path:rr": "rr is not an absolute path",
306
-		"a:/b:ro": "bad mode specified: ro",
307
-		"a:/b:rr": "bad mode specified: rr",
308
-	}
309
-
310
-	for _, path := range valid {
311
-		if _, err := ValidateDevice(path); err != nil {
312
-			t.Fatalf("ValidateDevice(`%q`) should succeed: error %q", path, err)
313
-		}
314
-	}
315
-
316
-	for path, expectedError := range invalid {
317
-		if _, err := ValidateDevice(path); err == nil {
318
-			t.Fatalf("ValidateDevice(`%q`) should have failed validation", path)
319
-		} else {
320
-			if err.Error() != expectedError {
321
-				t.Fatalf("ValidateDevice(`%q`) error should contain %q, got %q", path, expectedError, err.Error())
322
-			}
323
-		}
324
-	}
325
-}
326
-
327 247
 func TestValidateEnv(t *testing.T) {
328 248
 	valids := map[string]string{
329 249
 		"a":                   "a",
... ...
@@ -5,7 +5,6 @@ package parsers
5 5
 
6 6
 import (
7 7
 	"fmt"
8
-	"path"
9 8
 	"strconv"
10 9
 	"strings"
11 10
 )
... ...
@@ -68,28 +67,6 @@ func ParsePortRange(ports string) (uint64, uint64, error) {
68 68
 	return start, end, nil
69 69
 }
70 70
 
71
-// ParseLink parses and validates the specified string as a link format (name:alias)
72
-func ParseLink(val string) (string, string, error) {
73
-	if val == "" {
74
-		return "", "", fmt.Errorf("empty string specified for links")
75
-	}
76
-	arr := strings.Split(val, ":")
77
-	if len(arr) > 2 {
78
-		return "", "", fmt.Errorf("bad format for links: %s", val)
79
-	}
80
-	if len(arr) == 1 {
81
-		return val, val, nil
82
-	}
83
-	// This is kept because we can actually get an HostConfig with links
84
-	// from an already created container and the format is not `foo:bar`
85
-	// but `/foo:/c1/bar`
86
-	if strings.HasPrefix(arr[0], "/") {
87
-		_, alias := path.Split(arr[1])
88
-		return arr[0][1:], alias, nil
89
-	}
90
-	return arr[0], arr[1], nil
91
-}
92
-
93 71
 // ParseUintList parses and validates the specified string as the value
94 72
 // found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
95 73
 // one of the formats below. Note that duplicates are actually allowed in the
... ...
@@ -81,38 +81,6 @@ func TestParsePortRangeIncorrectStartRange(t *testing.T) {
81 81
 	}
82 82
 }
83 83
 
84
-func TestParseLink(t *testing.T) {
85
-	name, alias, err := ParseLink("name:alias")
86
-	if err != nil {
87
-		t.Fatalf("Expected not to error out on a valid name:alias format but got: %v", err)
88
-	}
89
-	if name != "name" {
90
-		t.Fatalf("Link name should have been name, got %s instead", name)
91
-	}
92
-	if alias != "alias" {
93
-		t.Fatalf("Link alias should have been alias, got %s instead", alias)
94
-	}
95
-	// short format definition
96
-	name, alias, err = ParseLink("name")
97
-	if err != nil {
98
-		t.Fatalf("Expected not to error out on a valid name only format but got: %v", err)
99
-	}
100
-	if name != "name" {
101
-		t.Fatalf("Link name should have been name, got %s instead", name)
102
-	}
103
-	if alias != "name" {
104
-		t.Fatalf("Link alias should have been name, got %s instead", alias)
105
-	}
106
-	// empty string link definition is not allowed
107
-	if _, _, err := ParseLink(""); err == nil || !strings.Contains(err.Error(), "empty string specified for links") {
108
-		t.Fatalf("Expected error 'empty string specified for links' but got: %v", err)
109
-	}
110
-	// more than two colons are not allowed
111
-	if _, _, err := ParseLink("link:alias:wrong"); err == nil || !strings.Contains(err.Error(), "bad format for links: link:alias:wrong") {
112
-		t.Fatalf("Expected error 'bad format for links: link:alias:wrong' but got: %v", err)
113
-	}
114
-}
115
-
116 84
 func TestParseUintList(t *testing.T) {
117 85
 	valids := map[string]map[int]bool{
118 86
 		"":             {},
... ...
@@ -2,6 +2,7 @@ package runconfig
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"path"
5 6
 	"strconv"
6 7
 	"strings"
7 8
 
... ...
@@ -55,10 +56,10 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
55 55
 		flBlkioWeightDevice = opts.NewWeightdeviceOpt(opts.ValidateWeightDevice)
56 56
 		flDeviceReadBps     = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
57 57
 		flDeviceWriteBps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
58
-		flLinks             = opts.NewListOpts(opts.ValidateLink)
58
+		flLinks             = opts.NewListOpts(ValidateLink)
59 59
 		flEnv               = opts.NewListOpts(opts.ValidateEnv)
60 60
 		flLabels            = opts.NewListOpts(opts.ValidateEnv)
61
-		flDevices           = opts.NewListOpts(opts.ValidateDevice)
61
+		flDevices           = opts.NewListOpts(ValidateDevice)
62 62
 
63 63
 		flUlimits = opts.NewUlimitOpt(nil)
64 64
 
... ...
@@ -532,7 +533,7 @@ func ParseDevice(device string) (DeviceMapping, error) {
532 532
 		permissions = arr[2]
533 533
 		fallthrough
534 534
 	case 2:
535
-		if opts.ValidDeviceMode(arr[1]) {
535
+		if ValidDeviceMode(arr[1]) {
536 536
 			permissions = arr[1]
537 537
 		} else {
538 538
 			dst = arr[1]
... ...
@@ -555,3 +556,101 @@ func ParseDevice(device string) (DeviceMapping, error) {
555 555
 	}
556 556
 	return deviceMapping, nil
557 557
 }
558
+
559
+// ParseLink parses and validates the specified string as a link format (name:alias)
560
+func ParseLink(val string) (string, string, error) {
561
+	if val == "" {
562
+		return "", "", fmt.Errorf("empty string specified for links")
563
+	}
564
+	arr := strings.Split(val, ":")
565
+	if len(arr) > 2 {
566
+		return "", "", fmt.Errorf("bad format for links: %s", val)
567
+	}
568
+	if len(arr) == 1 {
569
+		return val, val, nil
570
+	}
571
+	// This is kept because we can actually get an HostConfig with links
572
+	// from an already created container and the format is not `foo:bar`
573
+	// but `/foo:/c1/bar`
574
+	if strings.HasPrefix(arr[0], "/") {
575
+		_, alias := path.Split(arr[1])
576
+		return arr[0][1:], alias, nil
577
+	}
578
+	return arr[0], arr[1], nil
579
+}
580
+
581
+// ValidateLink validates that the specified string has a valid link format (containerName:alias).
582
+func ValidateLink(val string) (string, error) {
583
+	if _, _, err := ParseLink(val); err != nil {
584
+		return val, err
585
+	}
586
+	return val, nil
587
+}
588
+
589
+// ValidDeviceMode checks if the mode for device is valid or not.
590
+// Valid mode is a composition of r (read), w (write), and m (mknod).
591
+func ValidDeviceMode(mode string) bool {
592
+	var legalDeviceMode = map[rune]bool{
593
+		'r': true,
594
+		'w': true,
595
+		'm': true,
596
+	}
597
+	if mode == "" {
598
+		return false
599
+	}
600
+	for _, c := range mode {
601
+		if !legalDeviceMode[c] {
602
+			return false
603
+		}
604
+		legalDeviceMode[c] = false
605
+	}
606
+	return true
607
+}
608
+
609
+// ValidateDevice validates a path for devices
610
+// It will make sure 'val' is in the form:
611
+//    [host-dir:]container-path[:mode]
612
+// It also validates the device mode.
613
+func ValidateDevice(val string) (string, error) {
614
+	return validatePath(val, ValidDeviceMode)
615
+}
616
+
617
+func validatePath(val string, validator func(string) bool) (string, error) {
618
+	var containerPath string
619
+	var mode string
620
+
621
+	if strings.Count(val, ":") > 2 {
622
+		return val, fmt.Errorf("bad format for path: %s", val)
623
+	}
624
+
625
+	split := strings.SplitN(val, ":", 3)
626
+	if split[0] == "" {
627
+		return val, fmt.Errorf("bad format for path: %s", val)
628
+	}
629
+	switch len(split) {
630
+	case 1:
631
+		containerPath = split[0]
632
+		val = path.Clean(containerPath)
633
+	case 2:
634
+		if isValid := validator(split[1]); isValid {
635
+			containerPath = split[0]
636
+			mode = split[1]
637
+			val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
638
+		} else {
639
+			containerPath = split[1]
640
+			val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
641
+		}
642
+	case 3:
643
+		containerPath = split[1]
644
+		mode = split[2]
645
+		if isValid := validator(split[2]); !isValid {
646
+			return val, fmt.Errorf("bad mode specified: %s", mode)
647
+		}
648
+		val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
649
+	}
650
+
651
+	if !path.IsAbs(containerPath) {
652
+		return val, fmt.Errorf("%s is not an absolute path", containerPath)
653
+	}
654
+	return val, nil
655
+}
... ...
@@ -649,3 +649,115 @@ func TestParseEntryPoint(t *testing.T) {
649 649
 		t.Fatalf("Expected entrypoint 'anything', got %v", config.Entrypoint)
650 650
 	}
651 651
 }
652
+
653
+func TestValidateLink(t *testing.T) {
654
+	valid := []string{
655
+		"name",
656
+		"dcdfbe62ecd0:alias",
657
+		"7a67485460b7642516a4ad82ecefe7f57d0c4916f530561b71a50a3f9c4e33da",
658
+		"angry_torvalds:linus",
659
+	}
660
+	invalid := map[string]string{
661
+		"":               "empty string specified for links",
662
+		"too:much:of:it": "bad format for links: too:much:of:it",
663
+	}
664
+
665
+	for _, link := range valid {
666
+		if _, err := ValidateLink(link); err != nil {
667
+			t.Fatalf("ValidateLink(`%q`) should succeed: error %q", link, err)
668
+		}
669
+	}
670
+
671
+	for link, expectedError := range invalid {
672
+		if _, err := ValidateLink(link); err == nil {
673
+			t.Fatalf("ValidateLink(`%q`) should have failed validation", link)
674
+		} else {
675
+			if !strings.Contains(err.Error(), expectedError) {
676
+				t.Fatalf("ValidateLink(`%q`) error should contain %q", link, expectedError)
677
+			}
678
+		}
679
+	}
680
+}
681
+
682
+func TestParseLink(t *testing.T) {
683
+	name, alias, err := ParseLink("name:alias")
684
+	if err != nil {
685
+		t.Fatalf("Expected not to error out on a valid name:alias format but got: %v", err)
686
+	}
687
+	if name != "name" {
688
+		t.Fatalf("Link name should have been name, got %s instead", name)
689
+	}
690
+	if alias != "alias" {
691
+		t.Fatalf("Link alias should have been alias, got %s instead", alias)
692
+	}
693
+	// short format definition
694
+	name, alias, err = ParseLink("name")
695
+	if err != nil {
696
+		t.Fatalf("Expected not to error out on a valid name only format but got: %v", err)
697
+	}
698
+	if name != "name" {
699
+		t.Fatalf("Link name should have been name, got %s instead", name)
700
+	}
701
+	if alias != "name" {
702
+		t.Fatalf("Link alias should have been name, got %s instead", alias)
703
+	}
704
+	// empty string link definition is not allowed
705
+	if _, _, err := ParseLink(""); err == nil || !strings.Contains(err.Error(), "empty string specified for links") {
706
+		t.Fatalf("Expected error 'empty string specified for links' but got: %v", err)
707
+	}
708
+	// more than two colons are not allowed
709
+	if _, _, err := ParseLink("link:alias:wrong"); err == nil || !strings.Contains(err.Error(), "bad format for links: link:alias:wrong") {
710
+		t.Fatalf("Expected error 'bad format for links: link:alias:wrong' but got: %v", err)
711
+	}
712
+}
713
+
714
+func TestValidateDevice(t *testing.T) {
715
+	valid := []string{
716
+		"/home",
717
+		"/home:/home",
718
+		"/home:/something/else",
719
+		"/with space",
720
+		"/home:/with space",
721
+		"relative:/absolute-path",
722
+		"hostPath:/containerPath:r",
723
+		"/hostPath:/containerPath:rw",
724
+		"/hostPath:/containerPath:mrw",
725
+	}
726
+	invalid := map[string]string{
727
+		"":        "bad format for path: ",
728
+		"./":      "./ is not an absolute path",
729
+		"../":     "../ is not an absolute path",
730
+		"/:../":   "../ is not an absolute path",
731
+		"/:path":  "path is not an absolute path",
732
+		":":       "bad format for path: :",
733
+		"/tmp:":   " is not an absolute path",
734
+		":test":   "bad format for path: :test",
735
+		":/test":  "bad format for path: :/test",
736
+		"tmp:":    " is not an absolute path",
737
+		":test:":  "bad format for path: :test:",
738
+		"::":      "bad format for path: ::",
739
+		":::":     "bad format for path: :::",
740
+		"/tmp:::": "bad format for path: /tmp:::",
741
+		":/tmp::": "bad format for path: :/tmp::",
742
+		"path:ro": "ro is not an absolute path",
743
+		"path:rr": "rr is not an absolute path",
744
+		"a:/b:ro": "bad mode specified: ro",
745
+		"a:/b:rr": "bad mode specified: rr",
746
+	}
747
+
748
+	for _, path := range valid {
749
+		if _, err := ValidateDevice(path); err != nil {
750
+			t.Fatalf("ValidateDevice(`%q`) should succeed: error %q", path, err)
751
+		}
752
+	}
753
+
754
+	for path, expectedError := range invalid {
755
+		if _, err := ValidateDevice(path); err == nil {
756
+			t.Fatalf("ValidateDevice(`%q`) should have failed validation", path)
757
+		} else {
758
+			if err.Error() != expectedError {
759
+				t.Fatalf("ValidateDevice(`%q`) error should contain %q, got %q", path, expectedError, err.Error())
760
+			}
761
+		}
762
+	}
763
+}