Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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 |
+} |