// virtualbox doesn't support templates
func (s *executor) createVM(vmName string) (err error) {
	baseImage := s.Config.VirtualBox.BaseName
	if baseImage == "" {
		return errors.New("Missing Image setting from VirtualBox configuration")
	}

	_, err = vbox.Status(vmName)
	if err != nil {
		vbox.Unregister(vmName)
	}

	if !vbox.Exist(vmName) {
		baseSnapshot := s.determineBaseSnapshot(baseImage)
		if baseSnapshot == "" {
			s.Debugln("Creating testing VM from VM", baseImage, "...")
		} else {
			s.Debugln("Creating testing VM from VM", baseImage, "snapshot", baseSnapshot, "...")
		}

		err = vbox.CreateOsVM(baseImage, vmName, baseSnapshot)
		if err != nil {
			return err
		}
	}

	s.Debugln("Identify SSH Port...")
	s.sshPort, err = vbox.FindSSHPort(s.vmName)
	if err != nil {
		s.Debugln("Creating localhost ssh forwarding...")
		vmSSHPort := s.Config.SSH.Port
		if vmSSHPort == "" {
			vmSSHPort = "22"
		}
		s.sshPort, err = vbox.ConfigureSSH(vmName, vmSSHPort)
		if err != nil {
			return err
		}
	}
	s.Debugln("Using local", s.sshPort, "SSH port to connect to VM...")

	s.Debugln("Bootstraping VM...")
	err = vbox.Start(s.vmName)
	if err != nil {
		return err
	}

	s.Debugln("Waiting for VM to become responsive...")
	time.Sleep(10)
	err = s.verifyMachine(s.vmName, s.sshPort)
	if err != nil {
		return err
	}

	return nil
}
func (s *executor) Prepare(globalConfig *common.Config, config *common.RunnerConfig, build *common.Build) error {
	err := s.AbstractExecutor.Prepare(globalConfig, config, build)
	if err != nil {
		return err
	}

	if s.BuildShell.PassFile {
		return errors.New("virtualbox doesn't support shells that require script file")
	}

	if s.Config.SSH == nil {
		return errors.New("Missing SSH config")
	}

	if s.Config.VirtualBox == nil {
		return errors.New("Missing VirtualBox configuration")
	}

	if s.Config.VirtualBox.BaseName == "" {
		return errors.New("Missing BaseName setting from VirtualBox configuration")
	}

	version, err := vbox.Version()
	if err != nil {
		return err
	}

	s.Println("Using VirtualBox version", version, "executor...")

	if s.Config.VirtualBox.DisableSnapshots {
		s.vmName = s.Config.VirtualBox.BaseName + "-" + s.Build.ProjectUniqueName()
		if vbox.Exist(s.vmName) {
			s.Debugln("Deleting old VM...")
			vbox.Stop(s.vmName)
			vbox.Delete(s.vmName)
			vbox.Unregister(s.vmName)
		}
	} else {
		s.vmName = fmt.Sprintf("%s-runner-%s-concurrent-%d",
			s.Config.VirtualBox.BaseName,
			s.Build.Runner.ShortDescription(),
			s.Build.RunnerID)
	}

	if vbox.Exist(s.vmName) {
		s.Println("Restoring VM from snapshot...")
		err := s.restoreFromSnapshot()
		if err != nil {
			s.Println("Previous VM failed. Deleting, because", err)
			vbox.Stop(s.vmName)
			vbox.Delete(s.vmName)
			vbox.Unregister(s.vmName)
		}
	}

	if !vbox.Exist(s.vmName) {
		s.Println("Creating new VM...")
		err := s.createVM(s.vmName)
		if err != nil {
			return err
		}

		if !s.Config.VirtualBox.DisableSnapshots {
			s.Println("Creating default snapshot...")
			err = vbox.CreateSnapshot(s.vmName, "Started")
			if err != nil {
				return err
			}
		}
	}

	s.Debugln("Checking VM status...")
	status, err := vbox.Status(s.vmName)
	if err != nil {
		return err
	}

	if !vbox.IsStatusOnlineOrTransient(status) {
		s.Println("Starting VM...")
		err := vbox.Start(s.vmName)
		if err != nil {
			return err
		}
	}

	if status != vbox.Running {
		s.Debugln("Waiting for VM to run...")
		err = vbox.WaitForStatus(s.vmName, vbox.Running, 60)
		if err != nil {
			return err
		}
	}

	s.Debugln("Identify SSH Port...")
	sshPort, err := vbox.FindSSHPort(s.vmName)
	s.sshPort = sshPort
	if err != nil {
		return err
	}

	s.Println("Waiting VM to become responsive...")
	err = s.verifyMachine(s.vmName, s.sshPort)
	if err != nil {
		return err
	}

	s.provisioned = true

	s.Println("Starting SSH command...")
	s.sshCommand = ssh.Client{
		Config: *s.Config.SSH,
		Stdout: s.BuildTrace,
		Stderr: s.BuildTrace,
	}
	s.sshCommand.Port = s.sshPort
	s.sshCommand.Host = "localhost"

	s.Debugln("Connecting to SSH server...")
	err = s.sshCommand.Connect()
	if err != nil {
		return err
	}
	return nil
}