Browse code

Refactor container.Start()

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