func (s *ParallelsExecutor) createVM() error {
	baseImage := s.Config.Parallels.BaseName
	if baseImage == "" {
		return errors.New("Missing Image setting from Parallels config")
	}

	templateName := helpers.StringOrDefault(s.Config.Parallels.TemplateName, baseImage+"-template")

	// remove invalid template (removed?)
	templateStatus, _ := prl.Status(templateName)
	if templateStatus == prl.Invalid {
		prl.Unregister(templateName)
	}

	if !prl.Exist(templateName) {
		s.Debugln("Creating template from VM", baseImage, "...")
		err := prl.CreateTemplate(baseImage, templateName)
		if err != nil {
			return err
		}
	}

	s.Debugln("Creating runner from VM template...")
	err := prl.CreateOsVM(s.vmName, templateName)
	if err != nil {
		return err
	}

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

	s.Debugln("Waiting for VM to start...")
	err = prl.TryExec(s.vmName, 120, "exit", "0")
	if err != nil {
		return err
	}

	s.Debugln("Waiting for VM to become responsive...")
	err = s.verifyMachine(s.vmName)
	if err != nil {
		return err
	}
	return nil
}
func (s *ParallelsExecutor) 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.ShellScript.PassFile {
		return errors.New("Parallels doesn't support shells that require script file")
	}

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

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

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

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

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

	// remove invalid VM (removed?)
	vmStatus, _ := prl.Status(s.vmName)
	if vmStatus == prl.Invalid {
		prl.Unregister(s.vmName)
	}

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

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

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

		if !helpers.BoolOrDefault(s.Config.Parallels.DisableSnapshots, false) {
			s.Println("Creating default snapshot...")
			err = prl.CreateSnapshot(s.vmName, "Started")
			if err != nil {
				return err
			}
		}
	}

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

	// Start VM if stopped
	if status == prl.Stopped || status == prl.Suspended {
		s.Println("Starting VM...")
		err := prl.Start(s.vmName)
		if err != nil {
			return err
		}
	}

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

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

	s.provisioned = true

	s.Debugln("Updating VM date...")
	err = prl.TryExec(s.vmName, 20, "sudo", "ntpdate", "-u", "time.apple.com")
	if err != nil {
		return err
	}
	return nil
}