func (d *Driver) Create() error {
	b2dutils := mcnutils.NewB2dUtils(d.StorePath)
	if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
		return err
	}

	log.Infof("Creating VM...")
	if err := os.MkdirAll(d.ResolveStorePath("."), 0755); err != nil {
		return err
	}

	log.Infof("Extracting vmlinuz64 and initrd.img from %s...", isoFilename)
	if err := d.extractKernelImages(); err != nil {
		return err
	}

	log.Infof("Generating %dMB disk image...", d.DiskSize)
	if err := d.generateDiskImage(d.DiskSize); err != nil {
		return err
	}

	// Fix file permission root to current user for vmnet.framework
	log.Infof("Fix file permission...")
	os.Chown(d.ResolveStorePath("."), syscall.Getuid(), syscall.Getegid())
	files, _ := ioutil.ReadDir(d.ResolveStorePath("."))
	for _, f := range files {
		log.Debugf(d.ResolveStorePath(f.Name()))
		os.Chown(d.ResolveStorePath(f.Name()), syscall.Getuid(), syscall.Getegid())
	}

	log.Infof("Generate UUID...")
	d.UUID = uuidgen()
	log.Debugf("Generated UUID: %s", d.UUID)

	log.Infof("Convert UUID to MAC address...")
	rawUUID, err := d.getMACAdress()
	if err != nil {
		return err
	}
	d.MacAddr = trimMacAddress(rawUUID)
	log.Debugf("Converted MAC address: %s", d.MacAddr)

	log.Infof("Starting %s...", d.MachineName)
	if err := d.Start(); err != nil {
		return err
	}

	// Setup NFS sharing
	if d.NFSShare {
		log.Infof("NFS share folder must be root. Please insert root password.")
		err = d.setupNFSShare()
		if err != nil {
			log.Errorf("NFS setup failed: %s", err.Error())
		}
	}

	return nil
}
func (d *Driver) CopyIsoToMachineDir(isoURL, machineName string) error {
	b2d := b2d.NewB2dUtils(d.StorePath)
	mcnutils := mcnutils.NewB2dUtils(d.StorePath)

	if err := d.UpdateISOCache(isoURL); err != nil {
		return err
	}

	isoPath := filepath.Join(b2d.ImgCachePath, isoFilename)
	if isoStat, err := os.Stat(isoPath); err == nil {
		if int(isoStat.Sys().(*syscall.Stat_t).Uid) == 0 {
			log.Debugf("Fix %s file permission...", isoStat.Name())
			os.Chown(isoPath, syscall.Getuid(), syscall.Getegid())
		}
	}

	// TODO: This is a bit off-color.
	machineDir := filepath.Join(d.StorePath, "machines", machineName)
	machineIsoPath := filepath.Join(machineDir, isoFilename)

	// By default just copy the existing "cached" iso to the machine's directory...
	defaultISO := filepath.Join(b2d.ImgCachePath, defaultISOFilename)
	if isoURL == "" {
		log.Infof("Copying %s to %s...", defaultISO, machineIsoPath)
		return CopyFile(defaultISO, machineIsoPath)
	}

	// if ISO is specified, check if it matches a github releases url or fallback to a direct download
	downloadURL, err := b2d.GetReleaseURL(isoURL)
	if err != nil {
		return err
	}

	return mcnutils.DownloadISO(machineDir, b2d.Filename(), downloadURL)
}
func (d *Driver) UpdateISOCache(isoURL string) error {
	b2d := b2d.NewB2dUtils(d.StorePath)
	mcnutils := mcnutils.NewB2dUtils(d.StorePath)

	// recreate the cache dir if it has been manually deleted
	if _, err := os.Stat(b2d.ImgCachePath); os.IsNotExist(err) {
		log.Infof("Image cache directory does not exist, creating it at %s...", b2d.ImgCachePath)
		if err := os.Mkdir(b2d.ImgCachePath, 0700); err != nil {
			return err
		}
	}

	// Check owner of storage cache directory
	cacheStat, _ := os.Stat(b2d.ImgCachePath)

	if int(cacheStat.Sys().(*syscall.Stat_t).Uid) == 0 {
		log.Debugf("Fix %s directory permission...", cacheStat.Name())
		os.Chown(b2d.ImgCachePath, syscall.Getuid(), syscall.Getegid())
	}

	if isoURL != "" {
		// Non-default B2D are not cached
		return nil
	}

	exists := b2d.Exists()
	if !exists {
		log.Info("No default Boot2Docker ISO found locally, downloading the latest release...")
		return mcnutils.DownloadLatestBoot2Docker("")
	}

	latest := b2d.IsLatest()
	if !latest {
		log.Info("Default Boot2Docker ISO is out-of-date, downloading the latest release...")
		return mcnutils.DownloadLatestBoot2Docker("")
	}

	return nil
}
Example #4
0
func isRoot() bool {
	return syscall.Getuid() == 0 || syscall.Geteuid() == 0 ||
		syscall.Getgid() == 0 || syscall.Getegid() == 0
}
Example #5
0
// Getegid returns the numeric effective group id of the caller.
func Getegid() int { return syscall.Getegid() }
Example #6
0
// RunInContainer will execute a set of commands within a running Docker container
func (d *ImageManager) RunInContainer(opts RunInContainerOpts) (exitCode int, container *dockerclient.Container, err error) {

	// Get current user info to map to container
	// os/user.Current() isn't supported when cross-compiling hence this code
	currentUID := syscall.Geteuid()
	currentGID := syscall.Getegid()
	var actualCmd, containerCmd []string
	if opts.KeepContainer {
		// Sleep effectively forever so if something goes wrong we can
		// docker exec -it bash into the container, investigate, and
		// manually kill the container. Most of the time the compile step
		// will succeed and the container will be killed and removed.
		containerCmd = []string{"sleep", "365d"}
		actualCmd = opts.Cmd
	} else {
		containerCmd = opts.Cmd
		// actualCmd not used
	}

	env := []string{
		fmt.Sprintf("HOST_USERID=%d", currentUID),
		fmt.Sprintf("HOST_USERGID=%d", currentGID),
	}
	for _, name := range []string{"http_proxy", "https_proxy"} {
		var proxyURL *url.URL
		var err error
		if val, ok := os.LookupEnv(name); ok {
			env = append(env, fmt.Sprintf("%s=%s", name, val))
			if proxyURL, err = url.Parse(val); err != nil {
				proxyURL = nil
			}
		}
		name = strings.ToUpper(name)
		if val, ok := os.LookupEnv(name); ok {
			env = append(env, fmt.Sprintf("%s=%s", name, val))
			if proxyURL == nil {
				// Follow curl, lower case env vars have precedence
				if proxyURL, err = url.Parse(val); err != nil {
					proxyURL = nil
				}
			}
		}
	}

	cco := dockerclient.CreateContainerOptions{
		Config: &dockerclient.Config{
			Tty:          false,
			AttachStdin:  false,
			AttachStdout: true,
			AttachStderr: true,
			Hostname:     "compiler",
			Domainname:   "fissile",
			Cmd:          containerCmd,
			WorkingDir:   "/",
			Image:        opts.ImageName,
			Env:          env,
		},
		HostConfig: &dockerclient.HostConfig{
			Privileged:     false,
			Binds:          []string{},
			ReadonlyRootfs: false,
		},
		Name: opts.ContainerName,
	}

	for name, dirverOpts := range opts.Volumes {
		name = fmt.Sprintf("volume_%s_%s", opts.ContainerName, name)
		_, err := d.client.CreateVolume(dockerclient.CreateVolumeOptions{
			Name:       name,
			DriverOpts: dirverOpts,
		})
		if err != nil {
			return -1, nil, err
		}
	}

	for src, dest := range opts.Mounts {
		if _, ok := opts.Volumes[src]; ok {
			// Attempt to mount a volume; use the generated name
			src = fmt.Sprintf("volume_%s_%s", opts.ContainerName, src)
		}
		mountString := fmt.Sprintf("%s:%s", src, dest)
		if dest == ContainerInPath {
			mountString += ":ro"
		}
		cco.HostConfig.Binds = append(cco.HostConfig.Binds, mountString)
	}

	container, err = d.client.CreateContainer(cco)
	if err != nil {
		return -1, nil, err
	}

	attached := make(chan struct{})

	attachCloseWaiter, attachErr := d.client.AttachToContainerNonBlocking(dockerclient.AttachToContainerOptions{
		Container: container.ID,

		InputStream:  nil,
		OutputStream: opts.StdoutWriter,
		ErrorStream:  opts.StderrWriter,

		Stdin:       false,
		Stdout:      opts.StdoutWriter != nil,
		Stderr:      opts.StderrWriter != nil,
		Stream:      true,
		RawTerminal: false,
		Success:     attached,
	})
	if attachErr != nil {
		return -1, container, fmt.Errorf("Error running in container: %s. Error attaching to container: %s", container.ID, attachErr.Error())
	}
	attached <- <-attached

	err = d.client.StartContainer(container.ID, container.HostConfig)
	if err != nil {
		return -1, container, err
	}

	closeFiles := func() {
		if stdoutCloser, ok := opts.StdoutWriter.(io.Closer); ok {
			stdoutCloser.Close()
		}
		if stderrCloser, ok := opts.StderrWriter.(io.Closer); ok {
			stderrCloser.Close()
		}
	}

	if !opts.KeepContainer {
		exitCode, err = d.client.WaitContainer(container.ID)
		attachCloseWaiter.Wait()
		closeFiles()
		if err != nil {
			exitCode = -1
		}
		return exitCode, container, nil
	}
	// KeepContainer mode:
	// Run the cmd with 'docker exec ...' so we can keep the container around.
	// Note that this time we'll need to stop it if it doesn't fail
	cmdArgs := append([]string{"exec", "-i", container.ID}, actualCmd...)

	// Couldn't get this to work with dockerclient.Exec, so do it this way
	execCmd := exec.Command("docker", cmdArgs...)
	execCmd.Stdout = opts.StdoutWriter
	execCmd.Stderr = opts.StderrWriter
	err = execCmd.Run()
	// No need to wait on execCmd or on attachCloseWaiter
	if err == nil {
		exitCode = 0
	} else {
		exitCode = -1
	}
	closeFiles()
	return exitCode, container, err
}
func (d *Driver) Create() error {
	if err := d.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
		return err
	}

	log.Infof("Creating VM...")
	if err := os.MkdirAll(d.ResolveStorePath("."), 0755); err != nil {
		return err
	}

	if err := d.extractKernelImages(); err != nil {
		return err
	}

	log.Infof("Generating %dMB disk image...", d.DiskSize)

	if d.Qcow2 {
		if err := d.generateQcow2Image(d.DiskSize); err != nil {
			return err
		}
	} else {
		if err := d.generateSparseBundleDiskImage(d.DiskSize); err != nil {
			return err
		}
	}

	// Fix file permission root to current user for vmnet.framework
	log.Infof("Fix file permission...")
	os.Chown(d.ResolveStorePath("."), syscall.Getuid(), syscall.Getegid())
	files, _ := ioutil.ReadDir(d.ResolveStorePath("."))
	for _, f := range files {
		log.Debugf(d.ResolveStorePath(f.Name()))
		os.Chown(d.ResolveStorePath(f.Name()), syscall.Getuid(), syscall.Getegid())
	}

	if d.UUID == "" {
		log.Infof("Generate UUID...")
		d.UUID = uuidgen()
		log.Debugf("Generated UUID: %s", d.UUID)
	} else {
		log.Infof("Using Supplied UUID: %s", d.UUID)
	}

	log.Infof("Convert UUID to MAC address...")
	rawUUID, err := d.getMACAdress()
	if err != nil {
		return fmt.Errorf("Could not convert the UUID to MAC address: %s", err.Error())
	}
	d.MacAddr = trimMacAddress(rawUUID)
	log.Debugf("Converted MAC address: %s", d.MacAddr)

	log.Infof("Starting %s...", d.MachineName)
	if err := d.Start(); err != nil {
		return err
	}

	if d.Virtio9p {
		err = d.setupVirt9pShare()
		if err != nil {
			log.Errorf("virtio-9p setup failed: %s", err.Error())
		}
	}

	// Setup NFS sharing
	if d.NFSShare {
		log.Infof("NFS share folder must be root. Please insert root password.")
		err = d.setupNFSShare()
		if err != nil {
			log.Errorf("NFS setup failed: %s", err.Error())
		}
	}

	return nil
}
func (d *Driver) Create() error {
	b2dutils := mcnutils.NewB2dUtils(d.StorePath)
	if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
		return err
	}

	log.Infof("Creating VM...")
	if err := os.MkdirAll(d.ResolveStorePath("."), 0755); err != nil {
		return err
	}

	log.Infof("Extracting vmlinuz64 and initrd.img from %s...", isoFilename)
	if err := d.extractKernelImages(); err != nil {
		return err
	}

	log.Infof("Generating %dMB disk image...", d.DiskSize)
	if err := d.generateDiskImage(d.DiskSize); err != nil {
		return err
	}

	// Fix file permission root to current user for vmnet.framework
	log.Infof("Fix file permission...")
	os.Chown(d.ResolveStorePath("."), syscall.Getuid(), syscall.Getegid())
	files, _ := ioutil.ReadDir(d.ResolveStorePath("."))
	for _, f := range files {
		log.Debugf(d.ResolveStorePath(f.Name()))
		os.Chown(d.ResolveStorePath(f.Name()), syscall.Getuid(), syscall.Getegid())
	}

	log.Infof("Generate UUID...")
	d.UUID = uuidgen()
	log.Debugf("Generated UUID: %s", d.UUID)

	log.Infof("Convert UUID to MAC address...")
	rawUUID, err := d.getMACAdress()
	if err != nil {
		return err
	}
	d.MacAddr = trimMacAddress(rawUUID)
	log.Debugf("Converted MAC address: %s", d.MacAddr)

	log.Infof("Starting %s...", d.MachineName)
	if err := d.Start(); err != nil {
		return err
	}
	log.Infof("Waiting for VM to come online...")

	var ip string
	for i := 1; i <= 60; i++ {
		ip, err = d.getIPfromDHCPLease()
		if err != nil {
			log.Debugf("Not there yet %d/%d, error: %s", i, 60, err)
			time.Sleep(2 * time.Second)
			continue
		}

		if ip != "" {
			log.Debugf("Got an ip: %s", ip)
			break
		}
	}

	if ip == "" {
		return fmt.Errorf("Machine didn't return an IP after 120 seconds, aborting")
	}

	// We got an IP, let's copy ssh keys over
	d.IPAddress = ip

	// Setup NFS sharing
	if d.NFSShare {
		err = d.setupNFSShare()
		if err != nil {
			log.Errorf("NFS setup failed: %s", err.Error())
		}
	}

	return nil
}