| ... | ... |
@@ -567,262 +567,270 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
| 567 | 567 |
container.State.Lock() |
| 568 | 568 |
defer container.State.Unlock() |
| 569 | 569 |
|
| 570 |
- if hostConfig == nil { // in docker start of docker restart we want to reuse previous HostConfigFile
|
|
| 571 |
- hostConfig, _ = container.ReadHostConfig() |
|
| 572 |
- } |
|
| 570 |
+ startFct := func(hostConfig *HostConfig) error {
|
|
| 573 | 571 |
|
| 574 |
- if container.State.Running {
|
|
| 575 |
- return fmt.Errorf("The container %s is already running.", container.ID)
|
|
| 576 |
- } |
|
| 577 |
- if err := container.EnsureMounted(); err != nil {
|
|
| 578 |
- return err |
|
| 579 |
- } |
|
| 580 |
- if container.runtime.networkManager.disabled {
|
|
| 581 |
- container.Config.NetworkDisabled = true |
|
| 582 |
- } else {
|
|
| 583 |
- if err := container.allocateNetwork(); err != nil {
|
|
| 572 |
+ if hostConfig == nil { // in docker start of docker restart we want to reuse previous HostConfigFile
|
|
| 573 |
+ hostConfig, _ = container.ReadHostConfig() |
|
| 574 |
+ } |
|
| 575 |
+ |
|
| 576 |
+ if container.State.Running {
|
|
| 577 |
+ return fmt.Errorf("The container %s is already running.", container.ID)
|
|
| 578 |
+ } |
|
| 579 |
+ if err := container.EnsureMounted(); err != nil {
|
|
| 584 | 580 |
return err |
| 585 | 581 |
} |
| 586 |
- } |
|
| 582 |
+ if container.runtime.networkManager.disabled {
|
|
| 583 |
+ container.Config.NetworkDisabled = true |
|
| 584 |
+ } else {
|
|
| 585 |
+ if err := container.allocateNetwork(); err != nil {
|
|
| 586 |
+ return err |
|
| 587 |
+ } |
|
| 588 |
+ } |
|
| 587 | 589 |
|
| 588 |
- // Make sure the config is compatible with the current kernel |
|
| 589 |
- if container.Config.Memory > 0 && !container.runtime.capabilities.MemoryLimit {
|
|
| 590 |
- log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
|
| 591 |
- container.Config.Memory = 0 |
|
| 592 |
- } |
|
| 593 |
- if container.Config.Memory > 0 && !container.runtime.capabilities.SwapLimit {
|
|
| 594 |
- log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
|
| 595 |
- container.Config.MemorySwap = -1 |
|
| 596 |
- } |
|
| 590 |
+ // Make sure the config is compatible with the current kernel |
|
| 591 |
+ if container.Config.Memory > 0 && !container.runtime.capabilities.MemoryLimit {
|
|
| 592 |
+ log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
|
| 593 |
+ container.Config.Memory = 0 |
|
| 594 |
+ } |
|
| 595 |
+ if container.Config.Memory > 0 && !container.runtime.capabilities.SwapLimit {
|
|
| 596 |
+ log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
|
| 597 |
+ container.Config.MemorySwap = -1 |
|
| 598 |
+ } |
|
| 597 | 599 |
|
| 598 |
- if container.runtime.capabilities.IPv4ForwardingDisabled {
|
|
| 599 |
- log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
|
|
| 600 |
- } |
|
| 600 |
+ if container.runtime.capabilities.IPv4ForwardingDisabled {
|
|
| 601 |
+ log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
|
|
| 602 |
+ } |
|
| 601 | 603 |
|
| 602 |
- // Create the requested bind mounts |
|
| 603 |
- binds := make(map[string]BindMap) |
|
| 604 |
- // Define illegal container destinations |
|
| 605 |
- illegalDsts := []string{"/", "."}
|
|
| 604 |
+ // Create the requested bind mounts |
|
| 605 |
+ binds := make(map[string]BindMap) |
|
| 606 |
+ // Define illegal container destinations |
|
| 607 |
+ illegalDsts := []string{"/", "."}
|
|
| 608 |
+ |
|
| 609 |
+ for _, bind := range hostConfig.Binds {
|
|
| 610 |
+ // FIXME: factorize bind parsing in parseBind |
|
| 611 |
+ var src, dst, mode string |
|
| 612 |
+ arr := strings.Split(bind, ":") |
|
| 613 |
+ if len(arr) == 2 {
|
|
| 614 |
+ src = arr[0] |
|
| 615 |
+ dst = arr[1] |
|
| 616 |
+ mode = "rw" |
|
| 617 |
+ } else if len(arr) == 3 {
|
|
| 618 |
+ src = arr[0] |
|
| 619 |
+ dst = arr[1] |
|
| 620 |
+ mode = arr[2] |
|
| 621 |
+ } else {
|
|
| 622 |
+ return fmt.Errorf("Invalid bind specification: %s", bind)
|
|
| 623 |
+ } |
|
| 606 | 624 |
|
| 607 |
- for _, bind := range hostConfig.Binds {
|
|
| 608 |
- // FIXME: factorize bind parsing in parseBind |
|
| 609 |
- var src, dst, mode string |
|
| 610 |
- arr := strings.Split(bind, ":") |
|
| 611 |
- if len(arr) == 2 {
|
|
| 612 |
- src = arr[0] |
|
| 613 |
- dst = arr[1] |
|
| 614 |
- mode = "rw" |
|
| 615 |
- } else if len(arr) == 3 {
|
|
| 616 |
- src = arr[0] |
|
| 617 |
- dst = arr[1] |
|
| 618 |
- mode = arr[2] |
|
| 619 |
- } else {
|
|
| 620 |
- return fmt.Errorf("Invalid bind specification: %s", bind)
|
|
| 621 |
- } |
|
| 625 |
+ // Bail if trying to mount to an illegal destination |
|
| 626 |
+ for _, illegal := range illegalDsts {
|
|
| 627 |
+ if dst == illegal {
|
|
| 628 |
+ return fmt.Errorf("Illegal bind destination: %s", dst)
|
|
| 629 |
+ } |
|
| 630 |
+ } |
|
| 622 | 631 |
|
| 623 |
- // Bail if trying to mount to an illegal destination |
|
| 624 |
- for _, illegal := range illegalDsts {
|
|
| 625 |
- if dst == illegal {
|
|
| 626 |
- return fmt.Errorf("Illegal bind destination: %s", dst)
|
|
| 632 |
+ bindMap := BindMap{
|
|
| 633 |
+ SrcPath: src, |
|
| 634 |
+ DstPath: dst, |
|
| 635 |
+ Mode: mode, |
|
| 627 | 636 |
} |
| 637 |
+ binds[path.Clean(dst)] = bindMap |
|
| 628 | 638 |
} |
| 629 | 639 |
|
| 630 |
- bindMap := BindMap{
|
|
| 631 |
- SrcPath: src, |
|
| 632 |
- DstPath: dst, |
|
| 633 |
- Mode: mode, |
|
| 640 |
+ if container.Volumes == nil || len(container.Volumes) == 0 {
|
|
| 641 |
+ container.Volumes = make(map[string]string) |
|
| 642 |
+ container.VolumesRW = make(map[string]bool) |
|
| 634 | 643 |
} |
| 635 |
- binds[path.Clean(dst)] = bindMap |
|
| 636 |
- } |
|
| 637 | 644 |
|
| 638 |
- if container.Volumes == nil || len(container.Volumes) == 0 {
|
|
| 639 |
- container.Volumes = make(map[string]string) |
|
| 640 |
- container.VolumesRW = make(map[string]bool) |
|
| 641 |
- } |
|
| 642 |
- |
|
| 643 |
- // Apply volumes from another container if requested |
|
| 644 |
- if container.Config.VolumesFrom != "" {
|
|
| 645 |
- volumes := strings.Split(container.Config.VolumesFrom, ",") |
|
| 646 |
- for _, v := range volumes {
|
|
| 647 |
- c := container.runtime.Get(v) |
|
| 648 |
- if c == nil {
|
|
| 649 |
- return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
|
|
| 650 |
- } |
|
| 651 |
- for volPath, id := range c.Volumes {
|
|
| 652 |
- if _, exists := container.Volumes[volPath]; exists {
|
|
| 653 |
- continue |
|
| 654 |
- } |
|
| 655 |
- if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
|
|
| 656 |
- return err |
|
| 645 |
+ // Apply volumes from another container if requested |
|
| 646 |
+ if container.Config.VolumesFrom != "" {
|
|
| 647 |
+ volumes := strings.Split(container.Config.VolumesFrom, ",") |
|
| 648 |
+ for _, v := range volumes {
|
|
| 649 |
+ c := container.runtime.Get(v) |
|
| 650 |
+ if c == nil {
|
|
| 651 |
+ return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
|
|
| 657 | 652 |
} |
| 658 |
- container.Volumes[volPath] = id |
|
| 659 |
- if isRW, exists := c.VolumesRW[volPath]; exists {
|
|
| 660 |
- container.VolumesRW[volPath] = isRW |
|
| 653 |
+ for volPath, id := range c.Volumes {
|
|
| 654 |
+ if _, exists := container.Volumes[volPath]; exists {
|
|
| 655 |
+ continue |
|
| 656 |
+ } |
|
| 657 |
+ if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
|
|
| 658 |
+ return err |
|
| 659 |
+ } |
|
| 660 |
+ container.Volumes[volPath] = id |
|
| 661 |
+ if isRW, exists := c.VolumesRW[volPath]; exists {
|
|
| 662 |
+ container.VolumesRW[volPath] = isRW |
|
| 663 |
+ } |
|
| 661 | 664 |
} |
| 662 |
- } |
|
| 663 | 665 |
|
| 666 |
+ } |
|
| 664 | 667 |
} |
| 665 |
- } |
|
| 666 | 668 |
|
| 667 |
- // Create the requested volumes if they don't exist |
|
| 668 |
- for volPath := range container.Config.Volumes {
|
|
| 669 |
- volPath = path.Clean(volPath) |
|
| 670 |
- // Skip existing volumes |
|
| 671 |
- if _, exists := container.Volumes[volPath]; exists {
|
|
| 672 |
- continue |
|
| 673 |
- } |
|
| 674 |
- var srcPath string |
|
| 675 |
- var isBindMount bool |
|
| 676 |
- srcRW := false |
|
| 677 |
- // If an external bind is defined for this volume, use that as a source |
|
| 678 |
- if bindMap, exists := binds[volPath]; exists {
|
|
| 679 |
- isBindMount = true |
|
| 680 |
- srcPath = bindMap.SrcPath |
|
| 681 |
- if strings.ToLower(bindMap.Mode) == "rw" {
|
|
| 682 |
- srcRW = true |
|
| 669 |
+ // Create the requested volumes if they don't exist |
|
| 670 |
+ for volPath := range container.Config.Volumes {
|
|
| 671 |
+ volPath = path.Clean(volPath) |
|
| 672 |
+ // Skip existing volumes |
|
| 673 |
+ if _, exists := container.Volumes[volPath]; exists {
|
|
| 674 |
+ continue |
|
| 683 | 675 |
} |
| 684 |
- // Otherwise create an directory in $ROOT/volumes/ and use that |
|
| 685 |
- } else {
|
|
| 686 |
- c, err := container.runtime.volumes.Create(nil, container, "", "", nil) |
|
| 687 |
- if err != nil {
|
|
| 688 |
- return err |
|
| 676 |
+ var srcPath string |
|
| 677 |
+ var isBindMount bool |
|
| 678 |
+ srcRW := false |
|
| 679 |
+ // If an external bind is defined for this volume, use that as a source |
|
| 680 |
+ if bindMap, exists := binds[volPath]; exists {
|
|
| 681 |
+ isBindMount = true |
|
| 682 |
+ srcPath = bindMap.SrcPath |
|
| 683 |
+ if strings.ToLower(bindMap.Mode) == "rw" {
|
|
| 684 |
+ srcRW = true |
|
| 685 |
+ } |
|
| 686 |
+ // Otherwise create an directory in $ROOT/volumes/ and use that |
|
| 687 |
+ } else {
|
|
| 688 |
+ c, err := container.runtime.volumes.Create(nil, container, "", "", nil) |
|
| 689 |
+ if err != nil {
|
|
| 690 |
+ return err |
|
| 691 |
+ } |
|
| 692 |
+ srcPath, err = c.layer() |
|
| 693 |
+ if err != nil {
|
|
| 694 |
+ return err |
|
| 695 |
+ } |
|
| 696 |
+ srcRW = true // RW by default |
|
| 689 | 697 |
} |
| 690 |
- srcPath, err = c.layer() |
|
| 691 |
- if err != nil {
|
|
| 692 |
- return err |
|
| 698 |
+ container.Volumes[volPath] = srcPath |
|
| 699 |
+ container.VolumesRW[volPath] = srcRW |
|
| 700 |
+ // Create the mountpoint |
|
| 701 |
+ rootVolPath := path.Join(container.RootfsPath(), volPath) |
|
| 702 |
+ if err := os.MkdirAll(rootVolPath, 0755); err != nil {
|
|
| 703 |
+ return nil |
|
| 693 | 704 |
} |
| 694 |
- srcRW = true // RW by default |
|
| 695 |
- } |
|
| 696 |
- container.Volumes[volPath] = srcPath |
|
| 697 |
- container.VolumesRW[volPath] = srcRW |
|
| 698 |
- // Create the mountpoint |
|
| 699 |
- rootVolPath := path.Join(container.RootfsPath(), volPath) |
|
| 700 |
- if err := os.MkdirAll(rootVolPath, 0755); err != nil {
|
|
| 701 |
- return nil |
|
| 702 |
- } |
|
| 703 | 705 |
|
| 704 |
- // Do not copy or change permissions if we are mounting from the host |
|
| 705 |
- if srcRW && !isBindMount {
|
|
| 706 |
- volList, err := ioutil.ReadDir(rootVolPath) |
|
| 707 |
- if err != nil {
|
|
| 708 |
- return err |
|
| 709 |
- } |
|
| 710 |
- if len(volList) > 0 {
|
|
| 711 |
- srcList, err := ioutil.ReadDir(srcPath) |
|
| 706 |
+ // Do not copy or change permissions if we are mounting from the host |
|
| 707 |
+ if srcRW && !isBindMount {
|
|
| 708 |
+ volList, err := ioutil.ReadDir(rootVolPath) |
|
| 712 | 709 |
if err != nil {
|
| 713 | 710 |
return err |
| 714 | 711 |
} |
| 715 |
- if len(srcList) == 0 {
|
|
| 716 |
- // If the source volume is empty copy files from the root into the volume |
|
| 717 |
- if err := CopyWithTar(rootVolPath, srcPath); err != nil {
|
|
| 712 |
+ if len(volList) > 0 {
|
|
| 713 |
+ srcList, err := ioutil.ReadDir(srcPath) |
|
| 714 |
+ if err != nil {
|
|
| 718 | 715 |
return err |
| 719 | 716 |
} |
| 717 |
+ if len(srcList) == 0 {
|
|
| 718 |
+ // If the source volume is empty copy files from the root into the volume |
|
| 719 |
+ if err := CopyWithTar(rootVolPath, srcPath); err != nil {
|
|
| 720 |
+ return err |
|
| 721 |
+ } |
|
| 720 | 722 |
|
| 721 |
- var stat syscall.Stat_t |
|
| 722 |
- if err := syscall.Stat(rootVolPath, &stat); err != nil {
|
|
| 723 |
- return err |
|
| 724 |
- } |
|
| 725 |
- var srcStat syscall.Stat_t |
|
| 726 |
- if err := syscall.Stat(srcPath, &srcStat); err != nil {
|
|
| 727 |
- return err |
|
| 728 |
- } |
|
| 729 |
- // Change the source volume's ownership if it differs from the root |
|
| 730 |
- // files that where just copied |
|
| 731 |
- if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
|
|
| 732 |
- if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
|
|
| 723 |
+ var stat syscall.Stat_t |
|
| 724 |
+ if err := syscall.Stat(rootVolPath, &stat); err != nil {
|
|
| 725 |
+ return err |
|
| 726 |
+ } |
|
| 727 |
+ var srcStat syscall.Stat_t |
|
| 728 |
+ if err := syscall.Stat(srcPath, &srcStat); err != nil {
|
|
| 733 | 729 |
return err |
| 734 | 730 |
} |
| 731 |
+ // Change the source volume's ownership if it differs from the root |
|
| 732 |
+ // files that where just copied |
|
| 733 |
+ if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
|
|
| 734 |
+ if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
|
|
| 735 |
+ return err |
|
| 736 |
+ } |
|
| 737 |
+ } |
|
| 735 | 738 |
} |
| 736 | 739 |
} |
| 737 | 740 |
} |
| 738 | 741 |
} |
| 739 |
- } |
|
| 740 |
- |
|
| 741 |
- if err := container.generateLXCConfig(hostConfig); err != nil {
|
|
| 742 |
- return err |
|
| 743 |
- } |
|
| 744 | 742 |
|
| 745 |
- params := []string{
|
|
| 746 |
- "-n", container.ID, |
|
| 747 |
- "-f", container.lxcConfigPath(), |
|
| 748 |
- "--", |
|
| 749 |
- "/.dockerinit", |
|
| 750 |
- } |
|
| 751 |
- |
|
| 752 |
- // Networking |
|
| 753 |
- if !container.Config.NetworkDisabled {
|
|
| 754 |
- params = append(params, "-g", container.network.Gateway.String()) |
|
| 755 |
- } |
|
| 743 |
+ if err := container.generateLXCConfig(hostConfig); err != nil {
|
|
| 744 |
+ return err |
|
| 745 |
+ } |
|
| 756 | 746 |
|
| 757 |
- // User |
|
| 758 |
- if container.Config.User != "" {
|
|
| 759 |
- params = append(params, "-u", container.Config.User) |
|
| 760 |
- } |
|
| 747 |
+ params := []string{
|
|
| 748 |
+ "-n", container.ID, |
|
| 749 |
+ "-f", container.lxcConfigPath(), |
|
| 750 |
+ "--", |
|
| 751 |
+ "/.dockerinit", |
|
| 752 |
+ } |
|
| 761 | 753 |
|
| 762 |
- if container.Config.Tty {
|
|
| 763 |
- params = append(params, "-e", "TERM=xterm") |
|
| 764 |
- } |
|
| 754 |
+ // Networking |
|
| 755 |
+ if !container.Config.NetworkDisabled {
|
|
| 756 |
+ params = append(params, "-g", container.network.Gateway.String()) |
|
| 757 |
+ } |
|
| 765 | 758 |
|
| 766 |
- // Setup environment |
|
| 767 |
- params = append(params, |
|
| 768 |
- "-e", "HOME=/", |
|
| 769 |
- "-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
|
| 770 |
- "-e", "container=lxc", |
|
| 771 |
- "-e", "HOSTNAME="+container.Config.Hostname, |
|
| 772 |
- ) |
|
| 773 |
- if container.Config.WorkingDir != "" {
|
|
| 774 |
- workingDir := path.Clean(container.Config.WorkingDir) |
|
| 775 |
- utils.Debugf("[working dir] working dir is %s", workingDir)
|
|
| 759 |
+ // User |
|
| 760 |
+ if container.Config.User != "" {
|
|
| 761 |
+ params = append(params, "-u", container.Config.User) |
|
| 762 |
+ } |
|
| 776 | 763 |
|
| 777 |
- if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil {
|
|
| 778 |
- return nil |
|
| 764 |
+ if container.Config.Tty {
|
|
| 765 |
+ params = append(params, "-e", "TERM=xterm") |
|
| 779 | 766 |
} |
| 780 | 767 |
|
| 768 |
+ // Setup environment |
|
| 781 | 769 |
params = append(params, |
| 782 |
- "-w", workingDir, |
|
| 770 |
+ "-e", "HOME=/", |
|
| 771 |
+ "-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
|
| 772 |
+ "-e", "container=lxc", |
|
| 773 |
+ "-e", "HOSTNAME="+container.Config.Hostname, |
|
| 783 | 774 |
) |
| 784 |
- } |
|
| 775 |
+ if container.Config.WorkingDir != "" {
|
|
| 776 |
+ workingDir := path.Clean(container.Config.WorkingDir) |
|
| 777 |
+ utils.Debugf("[working dir] working dir is %s", workingDir)
|
|
| 785 | 778 |
|
| 786 |
- for _, elem := range container.Config.Env {
|
|
| 787 |
- params = append(params, "-e", elem) |
|
| 788 |
- } |
|
| 779 |
+ if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil {
|
|
| 780 |
+ return nil |
|
| 781 |
+ } |
|
| 789 | 782 |
|
| 790 |
- // Program |
|
| 791 |
- params = append(params, "--", container.Path) |
|
| 792 |
- params = append(params, container.Args...) |
|
| 783 |
+ params = append(params, |
|
| 784 |
+ "-w", workingDir, |
|
| 785 |
+ ) |
|
| 786 |
+ } |
|
| 793 | 787 |
|
| 794 |
- container.cmd = exec.Command("lxc-start", params...)
|
|
| 788 |
+ for _, elem := range container.Config.Env {
|
|
| 789 |
+ params = append(params, "-e", elem) |
|
| 790 |
+ } |
|
| 795 | 791 |
|
| 796 |
- // Setup logging of stdout and stderr to disk |
|
| 797 |
- if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
|
| 798 |
- return err |
|
| 799 |
- } |
|
| 800 |
- if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
|
|
| 801 |
- return err |
|
| 802 |
- } |
|
| 792 |
+ // Program |
|
| 793 |
+ params = append(params, "--", container.Path) |
|
| 794 |
+ params = append(params, container.Args...) |
|
| 803 | 795 |
|
| 804 |
- container.cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
|
| 796 |
+ container.cmd = exec.Command("lxc-start", params...)
|
|
| 805 | 797 |
|
| 806 |
- var err error |
|
| 807 |
- if container.Config.Tty {
|
|
| 808 |
- err = container.startPty() |
|
| 809 |
- } else {
|
|
| 810 |
- err = container.start() |
|
| 798 |
+ // Setup logging of stdout and stderr to disk |
|
| 799 |
+ if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
|
| 800 |
+ return err |
|
| 801 |
+ } |
|
| 802 |
+ if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
|
|
| 803 |
+ return err |
|
| 804 |
+ } |
|
| 805 |
+ |
|
| 806 |
+ container.cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
|
| 807 |
+ |
|
| 808 |
+ var err error |
|
| 809 |
+ if container.Config.Tty {
|
|
| 810 |
+ err = container.startPty() |
|
| 811 |
+ } else {
|
|
| 812 |
+ err = container.start() |
|
| 813 |
+ } |
|
| 814 |
+ if err != nil {
|
|
| 815 |
+ return err |
|
| 816 |
+ } |
|
| 817 |
+ // FIXME: save state on disk *first*, then converge |
|
| 818 |
+ // this way disk state is used as a journal, eg. we can restore after crash etc. |
|
| 819 |
+ container.State.setRunning(container.cmd.Process.Pid) |
|
| 820 |
+ |
|
| 821 |
+ // Init the lock |
|
| 822 |
+ container.waitLock = make(chan struct{})
|
|
| 823 |
+ |
|
| 824 |
+ container.ToDisk() |
|
| 825 |
+ container.SaveHostConfig(hostConfig) |
|
| 826 |
+ go container.monitor(hostConfig) |
|
| 827 |
+ return nil |
|
| 811 | 828 |
} |
| 829 |
+ err := startFct(hostConfig) |
|
| 812 | 830 |
if err != nil {
|
| 813 |
- return err |
|
| 831 |
+ container.cleanup() |
|
| 814 | 832 |
} |
| 815 |
- // FIXME: save state on disk *first*, then converge |
|
| 816 |
- // this way disk state is used as a journal, eg. we can restore after crash etc. |
|
| 817 |
- container.State.setRunning(container.cmd.Process.Pid) |
|
| 818 |
- |
|
| 819 |
- // Init the lock |
|
| 820 |
- container.waitLock = make(chan struct{})
|
|
| 821 |
- |
|
| 822 |
- container.ToDisk() |
|
| 823 |
- container.SaveHostConfig(hostConfig) |
|
| 824 |
- go container.monitor(hostConfig) |
|
| 825 |
- return nil |
|
| 833 |
+ return err |
|
| 826 | 834 |
} |
| 827 | 835 |
|
| 828 | 836 |
func (container *Container) Run() error {
|
| ... | ... |
@@ -981,6 +989,28 @@ func (container *Container) monitor(hostConfig *HostConfig) {
|
| 981 | 981 |
} |
| 982 | 982 |
|
| 983 | 983 |
// Cleanup |
| 984 |
+ container.cleanup() |
|
| 985 |
+ |
|
| 986 |
+ // Re-create a brand new stdin pipe once the container exited |
|
| 987 |
+ if container.Config.OpenStdin {
|
|
| 988 |
+ container.stdin, container.stdinPipe = io.Pipe() |
|
| 989 |
+ } |
|
| 990 |
+ |
|
| 991 |
+ // Release the lock |
|
| 992 |
+ close(container.waitLock) |
|
| 993 |
+ |
|
| 994 |
+ if err := container.ToDisk(); err != nil {
|
|
| 995 |
+ // FIXME: there is a race condition here which causes this to fail during the unit tests. |
|
| 996 |
+ // If another goroutine was waiting for Wait() to return before removing the container's root |
|
| 997 |
+ // from the filesystem... At this point it may already have done so. |
|
| 998 |
+ // This is because State.setStopped() has already been called, and has caused Wait() |
|
| 999 |
+ // to return. |
|
| 1000 |
+ // FIXME: why are we serializing running state to disk in the first place? |
|
| 1001 |
+ //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
|
|
| 1002 |
+ } |
|
| 1003 |
+} |
|
| 1004 |
+ |
|
| 1005 |
+func (container *Container) cleanup() {
|
|
| 984 | 1006 |
container.releaseNetwork() |
| 985 | 1007 |
if container.Config.OpenStdin {
|
| 986 | 1008 |
if err := container.stdin.Close(); err != nil {
|
| ... | ... |
@@ -1003,24 +1033,6 @@ func (container *Container) monitor(hostConfig *HostConfig) {
|
| 1003 | 1003 |
if err := container.Unmount(); err != nil {
|
| 1004 | 1004 |
log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
|
| 1005 | 1005 |
} |
| 1006 |
- |
|
| 1007 |
- // Re-create a brand new stdin pipe once the container exited |
|
| 1008 |
- if container.Config.OpenStdin {
|
|
| 1009 |
- container.stdin, container.stdinPipe = io.Pipe() |
|
| 1010 |
- } |
|
| 1011 |
- |
|
| 1012 |
- // Release the lock |
|
| 1013 |
- close(container.waitLock) |
|
| 1014 |
- |
|
| 1015 |
- if err := container.ToDisk(); err != nil {
|
|
| 1016 |
- // FIXME: there is a race condition here which causes this to fail during the unit tests. |
|
| 1017 |
- // If another goroutine was waiting for Wait() to return before removing the container's root |
|
| 1018 |
- // from the filesystem... At this point it may already have done so. |
|
| 1019 |
- // This is because State.setStopped() has already been called, and has caused Wait() |
|
| 1020 |
- // to return. |
|
| 1021 |
- // FIXME: why are we serializing running state to disk in the first place? |
|
| 1022 |
- //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
|
|
| 1023 |
- } |
|
| 1024 | 1006 |
} |
| 1025 | 1007 |
|
| 1026 | 1008 |
func (container *Container) kill() error {
|