|
7 | 7 | "io" |
8 | 8 | "io/ioutil" |
9 | 9 | "os" |
| 10 | + "path" |
10 | 11 | "path/filepath" |
11 | 12 | "regexp" |
12 | 13 | "strings" |
@@ -388,11 +389,101 @@ func (clnt *client) createLinux(containerID string, checkpoint string, checkpoin |
388 | 389 | configuration.NetworkSharedContainerName = spec.Windows.Network.NetworkSharedContainerName |
389 | 390 | } |
390 | 391 |
|
| 392 | + // Add the mounts (volumes, bind mounts etc) to the structure. We have to do |
| 393 | + // some translation for both the mapped directories passed into HCS and in |
| 394 | + // the spec. |
| 395 | + // |
| 396 | + // For HCS, we only pass in the mounts from the spec which are type "bind". |
| 397 | + // Further, the "ContainerPath" field (which is a little mis-leadingly |
| 398 | + // named when it applies to the utility VM rather than the container in the |
| 399 | + // utility VM) is moved to under /tmp/gcs/<ID>/binds, where this is passed |
| 400 | + // by the caller through a 'uvmpath' option. |
| 401 | + // |
| 402 | + // We do similar translation for the mounts in the spec by stripping out |
| 403 | + // the uvmpath option, and translating the Source path to the location in the |
| 404 | + // utility VM calculated above. |
| 405 | + // |
| 406 | + // From inside the utility VM, you would see a 9p mount such as in the following |
| 407 | + // where a host folder has been mapped to /target. The line with /tmp/gcs/<ID>/binds |
| 408 | + // specifically: |
| 409 | + // |
| 410 | + // / # mount |
| 411 | + // rootfs on / type rootfs (rw,size=463736k,nr_inodes=115934) |
| 412 | + // proc on /proc type proc (rw,relatime) |
| 413 | + // sysfs on /sys type sysfs (rw,relatime) |
| 414 | + // udev on /dev type devtmpfs (rw,relatime,size=498100k,nr_inodes=124525,mode=755) |
| 415 | + // tmpfs on /run type tmpfs (rw,relatime) |
| 416 | + // cgroup on /sys/fs/cgroup type cgroup (rw,relatime,cpuset,cpu,cpuacct,blkio,memory,devices,freezer,net_cls,perf_event,net_prio,hugetlb,pids,rdma) |
| 417 | + // mqueue on /dev/mqueue type mqueue (rw,relatime) |
| 418 | + // devpts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000) |
| 419 | + // /binds/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/target on /binds/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/target type 9p (rw,sync,dirsync,relatime,trans=fd,rfdno=6,wfdno=6) |
| 420 | + // /dev/pmem0 on /tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/layer0 type ext4 (ro,relatime,block_validity,delalloc,norecovery,barrier,dax,user_xattr,acl) |
| 421 | + // /dev/sda on /tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/scratch type ext4 (rw,relatime,block_validity,delalloc,barrier,user_xattr,acl) |
| 422 | + // overlay on /tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/rootfs type overlay (rw,relatime,lowerdir=/tmp/base/:/tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/layer0,upperdir=/tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/scratch/upper,workdir=/tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc/scratch/work) |
| 423 | + // |
| 424 | + // /tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc # ls -l |
| 425 | + // total 16 |
| 426 | + // drwx------ 3 0 0 60 Sep 7 18:54 binds |
| 427 | + // -rw-r--r-- 1 0 0 3345 Sep 7 18:54 config.json |
| 428 | + // drwxr-xr-x 10 0 0 4096 Sep 6 17:26 layer0 |
| 429 | + // drwxr-xr-x 1 0 0 4096 Sep 7 18:54 rootfs |
| 430 | + // drwxr-xr-x 5 0 0 4096 Sep 7 18:54 scratch |
| 431 | + // |
| 432 | + // /tmp/gcs/b3ea9126d67702173647ece2744f7c11181c0150e9890fc9a431849838033edc # ls -l binds |
| 433 | + // total 0 |
| 434 | + // drwxrwxrwt 2 0 0 4096 Sep 7 16:51 target |
| 435 | + |
| 436 | + mds := []hcsshim.MappedDir{} |
| 437 | + specMounts := []specs.Mount{} |
| 438 | + for _, mount := range spec.Mounts { |
| 439 | + specMount := mount |
| 440 | + if mount.Type == "bind" { |
| 441 | + // Strip out the uvmpath from the options |
| 442 | + updatedOptions := []string{} |
| 443 | + uvmPath := "" |
| 444 | + readonly := false |
| 445 | + for _, opt := range mount.Options { |
| 446 | + dropOption := false |
| 447 | + elements := strings.SplitN(opt, "=", 2) |
| 448 | + switch elements[0] { |
| 449 | + case "uvmpath": |
| 450 | + uvmPath = elements[1] |
| 451 | + dropOption = true |
| 452 | + case "rw": |
| 453 | + case "ro": |
| 454 | + readonly = true |
| 455 | + case "rbind": |
| 456 | + default: |
| 457 | + return fmt.Errorf("unsupported option %q", opt) |
| 458 | + } |
| 459 | + if !dropOption { |
| 460 | + updatedOptions = append(updatedOptions, opt) |
| 461 | + } |
| 462 | + } |
| 463 | + mount.Options = updatedOptions |
| 464 | + if uvmPath == "" { |
| 465 | + return fmt.Errorf("no uvmpath for bind mount %+v", mount) |
| 466 | + } |
| 467 | + md := hcsshim.MappedDir{ |
| 468 | + HostPath: mount.Source, |
| 469 | + ContainerPath: path.Join(uvmPath, mount.Destination), |
| 470 | + CreateInUtilityVM: true, |
| 471 | + ReadOnly: readonly, |
| 472 | + } |
| 473 | + mds = append(mds, md) |
| 474 | + specMount.Source = path.Join(uvmPath, mount.Destination) |
| 475 | + } |
| 476 | + specMounts = append(specMounts, specMount) |
| 477 | + } |
| 478 | + configuration.MappedDirectories = mds |
| 479 | + |
391 | 480 | hcsContainer, err := hcsshim.CreateContainer(containerID, configuration) |
392 | 481 | if err != nil { |
393 | 482 | return err |
394 | 483 | } |
395 | 484 |
|
| 485 | + spec.Mounts = specMounts |
| 486 | + |
396 | 487 | // Construct a container object for calling start on it. |
397 | 488 | container := &container{ |
398 | 489 | containerCommon: containerCommon{ |
|
0 commit comments