Make Start() slightly more readable.
| ... | ... |
@@ -541,160 +541,18 @@ func (container *Container) Start() (err error) {
|
| 541 | 541 |
log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
|
| 542 | 542 |
} |
| 543 | 543 |
|
| 544 |
- // Create the requested bind mounts |
|
| 545 |
- binds := make(map[string]BindMap) |
|
| 546 |
- // Define illegal container destinations |
|
| 547 |
- illegalDsts := []string{"/", "."}
|
|
| 548 |
- |
|
| 549 |
- for _, bind := range container.hostConfig.Binds {
|
|
| 550 |
- // FIXME: factorize bind parsing in parseBind |
|
| 551 |
- var src, dst, mode string |
|
| 552 |
- arr := strings.Split(bind, ":") |
|
| 553 |
- if len(arr) == 2 {
|
|
| 554 |
- src = arr[0] |
|
| 555 |
- dst = arr[1] |
|
| 556 |
- mode = "rw" |
|
| 557 |
- } else if len(arr) == 3 {
|
|
| 558 |
- src = arr[0] |
|
| 559 |
- dst = arr[1] |
|
| 560 |
- mode = arr[2] |
|
| 561 |
- } else {
|
|
| 562 |
- return fmt.Errorf("Invalid bind specification: %s", bind)
|
|
| 563 |
- } |
|
| 564 |
- |
|
| 565 |
- // Bail if trying to mount to an illegal destination |
|
| 566 |
- for _, illegal := range illegalDsts {
|
|
| 567 |
- if dst == illegal {
|
|
| 568 |
- return fmt.Errorf("Illegal bind destination: %s", dst)
|
|
| 569 |
- } |
|
| 570 |
- } |
|
| 571 |
- |
|
| 572 |
- bindMap := BindMap{
|
|
| 573 |
- SrcPath: src, |
|
| 574 |
- DstPath: dst, |
|
| 575 |
- Mode: mode, |
|
| 576 |
- } |
|
| 577 |
- binds[path.Clean(dst)] = bindMap |
|
| 578 |
- } |
|
| 579 |
- |
|
| 580 | 544 |
if container.Volumes == nil || len(container.Volumes) == 0 {
|
| 581 | 545 |
container.Volumes = make(map[string]string) |
| 582 | 546 |
container.VolumesRW = make(map[string]bool) |
| 583 | 547 |
} |
| 584 | 548 |
|
| 585 | 549 |
// Apply volumes from another container if requested |
| 586 |
- container.joinVolumes() |
|
| 587 |
- |
|
| 588 |
- volumesDriver := container.runtime.volumes.driver |
|
| 589 |
- // Create the requested volumes if they don't exist |
|
| 590 |
- for volPath := range container.Config.Volumes {
|
|
| 591 |
- volPath = path.Clean(volPath) |
|
| 592 |
- volIsDir := true |
|
| 593 |
- // Skip existing volumes |
|
| 594 |
- if _, exists := container.Volumes[volPath]; exists {
|
|
| 595 |
- continue |
|
| 596 |
- } |
|
| 597 |
- var srcPath string |
|
| 598 |
- var isBindMount bool |
|
| 599 |
- srcRW := false |
|
| 600 |
- // If an external bind is defined for this volume, use that as a source |
|
| 601 |
- if bindMap, exists := binds[volPath]; exists {
|
|
| 602 |
- isBindMount = true |
|
| 603 |
- srcPath = bindMap.SrcPath |
|
| 604 |
- if strings.ToLower(bindMap.Mode) == "rw" {
|
|
| 605 |
- srcRW = true |
|
| 606 |
- } |
|
| 607 |
- if file, err := os.Open(bindMap.SrcPath); err != nil {
|
|
| 608 |
- return err |
|
| 609 |
- } else {
|
|
| 610 |
- defer file.Close() |
|
| 611 |
- if stat, err := file.Stat(); err != nil {
|
|
| 612 |
- return err |
|
| 613 |
- } else {
|
|
| 614 |
- volIsDir = stat.IsDir() |
|
| 615 |
- } |
|
| 616 |
- } |
|
| 617 |
- // Otherwise create an directory in $ROOT/volumes/ and use that |
|
| 618 |
- } else {
|
|
| 619 |
- |
|
| 620 |
- // Do not pass a container as the parameter for the volume creation. |
|
| 621 |
- // The graph driver using the container's information ( Image ) to |
|
| 622 |
- // create the parent. |
|
| 623 |
- c, err := container.runtime.volumes.Create(nil, nil, "", "", nil) |
|
| 624 |
- if err != nil {
|
|
| 625 |
- return err |
|
| 626 |
- } |
|
| 627 |
- srcPath, err = volumesDriver.Get(c.ID) |
|
| 628 |
- if err != nil {
|
|
| 629 |
- return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
|
|
| 630 |
- } |
|
| 631 |
- srcRW = true // RW by default |
|
| 632 |
- } |
|
| 633 |
- container.Volumes[volPath] = srcPath |
|
| 634 |
- container.VolumesRW[volPath] = srcRW |
|
| 635 |
- // Create the mountpoint |
|
| 636 |
- rootVolPath := path.Join(container.RootfsPath(), volPath) |
|
| 637 |
- if volIsDir {
|
|
| 638 |
- if err := os.MkdirAll(rootVolPath, 0755); err != nil {
|
|
| 639 |
- return err |
|
| 640 |
- } |
|
| 641 |
- } |
|
| 642 |
- |
|
| 643 |
- volPath = path.Join(container.RootfsPath(), volPath) |
|
| 644 |
- if _, err := os.Stat(volPath); err != nil {
|
|
| 645 |
- if os.IsNotExist(err) {
|
|
| 646 |
- if volIsDir {
|
|
| 647 |
- if err := os.MkdirAll(volPath, 0755); err != nil {
|
|
| 648 |
- return err |
|
| 649 |
- } |
|
| 650 |
- } else {
|
|
| 651 |
- if err := os.MkdirAll(path.Dir(volPath), 0755); err != nil {
|
|
| 652 |
- return err |
|
| 653 |
- } |
|
| 654 |
- if f, err := os.OpenFile(volPath, os.O_CREATE, 0755); err != nil {
|
|
| 655 |
- return err |
|
| 656 |
- } else {
|
|
| 657 |
- f.Close() |
|
| 658 |
- } |
|
| 659 |
- } |
|
| 660 |
- } |
|
| 661 |
- } |
|
| 662 |
- |
|
| 663 |
- // Do not copy or change permissions if we are mounting from the host |
|
| 664 |
- if srcRW && !isBindMount {
|
|
| 665 |
- volList, err := ioutil.ReadDir(rootVolPath) |
|
| 666 |
- if err != nil {
|
|
| 667 |
- return err |
|
| 668 |
- } |
|
| 669 |
- if len(volList) > 0 {
|
|
| 670 |
- srcList, err := ioutil.ReadDir(srcPath) |
|
| 671 |
- if err != nil {
|
|
| 672 |
- return err |
|
| 673 |
- } |
|
| 674 |
- if len(srcList) == 0 {
|
|
| 675 |
- // If the source volume is empty copy files from the root into the volume |
|
| 676 |
- if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
|
|
| 677 |
- return err |
|
| 678 |
- } |
|
| 550 |
+ if err := container.applyExternalVolumes(); err != nil {
|
|
| 551 |
+ return err |
|
| 552 |
+ } |
|
| 679 | 553 |
|
| 680 |
- var stat syscall.Stat_t |
|
| 681 |
- if err := syscall.Stat(rootVolPath, &stat); err != nil {
|
|
| 682 |
- return err |
|
| 683 |
- } |
|
| 684 |
- var srcStat syscall.Stat_t |
|
| 685 |
- if err := syscall.Stat(srcPath, &srcStat); err != nil {
|
|
| 686 |
- return err |
|
| 687 |
- } |
|
| 688 |
- // Change the source volume's ownership if it differs from the root |
|
| 689 |
- // files that where just copied |
|
| 690 |
- if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
|
|
| 691 |
- if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
|
|
| 692 |
- return err |
|
| 693 |
- } |
|
| 694 |
- } |
|
| 695 |
- } |
|
| 696 |
- } |
|
| 697 |
- } |
|
| 554 |
+ if err := container.createVolumes(); err != nil {
|
|
| 555 |
+ return err |
|
| 698 | 556 |
} |
| 699 | 557 |
|
| 700 | 558 |
if err := container.generateLXCConfig(); err != nil {
|
| ... | ... |
@@ -880,7 +738,165 @@ func (container *Container) Start() (err error) {
|
| 880 | 880 |
return ErrContainerStart |
| 881 | 881 |
} |
| 882 | 882 |
|
| 883 |
-func (container *Container) joinVolumes() error {
|
|
| 883 |
+func (container *Container) getBindMap() (map[string]BindMap, error) {
|
|
| 884 |
+ // Create the requested bind mounts |
|
| 885 |
+ binds := make(map[string]BindMap) |
|
| 886 |
+ // Define illegal container destinations |
|
| 887 |
+ illegalDsts := []string{"/", "."}
|
|
| 888 |
+ |
|
| 889 |
+ for _, bind := range container.hostConfig.Binds {
|
|
| 890 |
+ // FIXME: factorize bind parsing in parseBind |
|
| 891 |
+ var src, dst, mode string |
|
| 892 |
+ arr := strings.Split(bind, ":") |
|
| 893 |
+ if len(arr) == 2 {
|
|
| 894 |
+ src = arr[0] |
|
| 895 |
+ dst = arr[1] |
|
| 896 |
+ mode = "rw" |
|
| 897 |
+ } else if len(arr) == 3 {
|
|
| 898 |
+ src = arr[0] |
|
| 899 |
+ dst = arr[1] |
|
| 900 |
+ mode = arr[2] |
|
| 901 |
+ } else {
|
|
| 902 |
+ return nil, fmt.Errorf("Invalid bind specification: %s", bind)
|
|
| 903 |
+ } |
|
| 904 |
+ |
|
| 905 |
+ // Bail if trying to mount to an illegal destination |
|
| 906 |
+ for _, illegal := range illegalDsts {
|
|
| 907 |
+ if dst == illegal {
|
|
| 908 |
+ return nil, fmt.Errorf("Illegal bind destination: %s", dst)
|
|
| 909 |
+ } |
|
| 910 |
+ } |
|
| 911 |
+ |
|
| 912 |
+ bindMap := BindMap{
|
|
| 913 |
+ SrcPath: src, |
|
| 914 |
+ DstPath: dst, |
|
| 915 |
+ Mode: mode, |
|
| 916 |
+ } |
|
| 917 |
+ binds[path.Clean(dst)] = bindMap |
|
| 918 |
+ } |
|
| 919 |
+ return binds, nil |
|
| 920 |
+} |
|
| 921 |
+ |
|
| 922 |
+func (container *Container) createVolumes() error {
|
|
| 923 |
+ binds, err := container.getBindMap() |
|
| 924 |
+ if err != nil {
|
|
| 925 |
+ return err |
|
| 926 |
+ } |
|
| 927 |
+ volumesDriver := container.runtime.volumes.driver |
|
| 928 |
+ // Create the requested volumes if they don't exist |
|
| 929 |
+ for volPath := range container.Config.Volumes {
|
|
| 930 |
+ volPath = path.Clean(volPath) |
|
| 931 |
+ volIsDir := true |
|
| 932 |
+ // Skip existing volumes |
|
| 933 |
+ if _, exists := container.Volumes[volPath]; exists {
|
|
| 934 |
+ continue |
|
| 935 |
+ } |
|
| 936 |
+ var srcPath string |
|
| 937 |
+ var isBindMount bool |
|
| 938 |
+ srcRW := false |
|
| 939 |
+ // If an external bind is defined for this volume, use that as a source |
|
| 940 |
+ if bindMap, exists := binds[volPath]; exists {
|
|
| 941 |
+ isBindMount = true |
|
| 942 |
+ srcPath = bindMap.SrcPath |
|
| 943 |
+ if strings.ToLower(bindMap.Mode) == "rw" {
|
|
| 944 |
+ srcRW = true |
|
| 945 |
+ } |
|
| 946 |
+ if file, err := os.Open(bindMap.SrcPath); err != nil {
|
|
| 947 |
+ return err |
|
| 948 |
+ } else {
|
|
| 949 |
+ defer file.Close() |
|
| 950 |
+ if stat, err := file.Stat(); err != nil {
|
|
| 951 |
+ return err |
|
| 952 |
+ } else {
|
|
| 953 |
+ volIsDir = stat.IsDir() |
|
| 954 |
+ } |
|
| 955 |
+ } |
|
| 956 |
+ // Otherwise create an directory in $ROOT/volumes/ and use that |
|
| 957 |
+ } else {
|
|
| 958 |
+ |
|
| 959 |
+ // Do not pass a container as the parameter for the volume creation. |
|
| 960 |
+ // The graph driver using the container's information ( Image ) to |
|
| 961 |
+ // create the parent. |
|
| 962 |
+ c, err := container.runtime.volumes.Create(nil, nil, "", "", nil) |
|
| 963 |
+ if err != nil {
|
|
| 964 |
+ return err |
|
| 965 |
+ } |
|
| 966 |
+ srcPath, err = volumesDriver.Get(c.ID) |
|
| 967 |
+ if err != nil {
|
|
| 968 |
+ return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
|
|
| 969 |
+ } |
|
| 970 |
+ srcRW = true // RW by default |
|
| 971 |
+ } |
|
| 972 |
+ container.Volumes[volPath] = srcPath |
|
| 973 |
+ container.VolumesRW[volPath] = srcRW |
|
| 974 |
+ // Create the mountpoint |
|
| 975 |
+ rootVolPath := path.Join(container.RootfsPath(), volPath) |
|
| 976 |
+ if volIsDir {
|
|
| 977 |
+ if err := os.MkdirAll(rootVolPath, 0755); err != nil {
|
|
| 978 |
+ return err |
|
| 979 |
+ } |
|
| 980 |
+ } |
|
| 981 |
+ |
|
| 982 |
+ volPath = path.Join(container.RootfsPath(), volPath) |
|
| 983 |
+ if _, err := os.Stat(volPath); err != nil {
|
|
| 984 |
+ if os.IsNotExist(err) {
|
|
| 985 |
+ if volIsDir {
|
|
| 986 |
+ if err := os.MkdirAll(volPath, 0755); err != nil {
|
|
| 987 |
+ return err |
|
| 988 |
+ } |
|
| 989 |
+ } else {
|
|
| 990 |
+ if err := os.MkdirAll(path.Dir(volPath), 0755); err != nil {
|
|
| 991 |
+ return err |
|
| 992 |
+ } |
|
| 993 |
+ if f, err := os.OpenFile(volPath, os.O_CREATE, 0755); err != nil {
|
|
| 994 |
+ return err |
|
| 995 |
+ } else {
|
|
| 996 |
+ f.Close() |
|
| 997 |
+ } |
|
| 998 |
+ } |
|
| 999 |
+ } |
|
| 1000 |
+ } |
|
| 1001 |
+ |
|
| 1002 |
+ // Do not copy or change permissions if we are mounting from the host |
|
| 1003 |
+ if srcRW && !isBindMount {
|
|
| 1004 |
+ volList, err := ioutil.ReadDir(rootVolPath) |
|
| 1005 |
+ if err != nil {
|
|
| 1006 |
+ return err |
|
| 1007 |
+ } |
|
| 1008 |
+ if len(volList) > 0 {
|
|
| 1009 |
+ srcList, err := ioutil.ReadDir(srcPath) |
|
| 1010 |
+ if err != nil {
|
|
| 1011 |
+ return err |
|
| 1012 |
+ } |
|
| 1013 |
+ if len(srcList) == 0 {
|
|
| 1014 |
+ // If the source volume is empty copy files from the root into the volume |
|
| 1015 |
+ if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
|
|
| 1016 |
+ return err |
|
| 1017 |
+ } |
|
| 1018 |
+ |
|
| 1019 |
+ var stat syscall.Stat_t |
|
| 1020 |
+ if err := syscall.Stat(rootVolPath, &stat); err != nil {
|
|
| 1021 |
+ return err |
|
| 1022 |
+ } |
|
| 1023 |
+ var srcStat syscall.Stat_t |
|
| 1024 |
+ if err := syscall.Stat(srcPath, &srcStat); err != nil {
|
|
| 1025 |
+ return err |
|
| 1026 |
+ } |
|
| 1027 |
+ // Change the source volume's ownership if it differs from the root |
|
| 1028 |
+ // files that where just copied |
|
| 1029 |
+ if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
|
|
| 1030 |
+ if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
|
|
| 1031 |
+ return err |
|
| 1032 |
+ } |
|
| 1033 |
+ } |
|
| 1034 |
+ } |
|
| 1035 |
+ } |
|
| 1036 |
+ } |
|
| 1037 |
+ } |
|
| 1038 |
+ return nil |
|
| 1039 |
+} |
|
| 1040 |
+ |
|
| 1041 |
+func (container *Container) applyExternalVolumes() error {
|
|
| 884 | 1042 |
if container.Config.VolumesFrom != "" {
|
| 885 | 1043 |
containerSpecs := strings.Split(container.Config.VolumesFrom, ",") |
| 886 | 1044 |
for _, containerSpec := range containerSpecs {
|
| ... | ... |
@@ -917,6 +933,7 @@ func (container *Container) joinVolumes() error {
|
| 917 | 917 |
|
| 918 | 918 |
} |
| 919 | 919 |
} |
| 920 |
+ return nil |
|
| 920 | 921 |
} |
| 921 | 922 |
|
| 922 | 923 |
func (container *Container) Run() error {
|