GuestAdditionsMode and GuestAdditionsPath can be set in config. If GuestAdditionsMode == "attach" it will mount the HyperV Integration Services ISO. If GuestAdditionsPath is set, then it will be used as an alternative to where the HyperV Integration Service ISO is.

Included the build step to download ISO, so iso_urls works properly now.
Online activation should be done via provisioner
Installation of integration services should be done via provisioner
Cleaned up the way dvd drives are mounted and unmounted (still need to implement feature to find unused drives before adding a new one)
Cleaned up the way floppies are mounted and unmounted
This commit is contained in:
Taliesin Sisson 2015-10-30 17:19:25 +00:00 committed by Taliesin Sisson
parent 422efeeaf6
commit 010d171bec
13 changed files with 196 additions and 554 deletions

View File

@ -91,10 +91,14 @@ type Driver interface {
MountDvdDrive(string, string) error
MountDvdDriveByLocation(string, string, uint, uint) error
SetBootDvdDrive(string, uint, uint) error
UnmountDvdDrive(string) error
DeleteDvdDrive(string, string, string) error
DeleteDvdDrive(string, uint, uint) error
UnmountFloppyDrive(vmName string) error
MountFloppyDrive(string, string) error
UnmountFloppyDrive(string) error
}

View File

@ -217,14 +217,22 @@ func (d *HypervPS4Driver) MountDvdDriveByLocation(vmName string, path string, co
return hyperv.MountDvdDriveByLocation(vmName, path, controllerNumber, controllerLocation)
}
func (d *HypervPS4Driver) SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
return hyperv.SetBootDvdDrive(vmName, controllerNumber, controllerLocation)
}
func (d *HypervPS4Driver) UnmountDvdDrive(vmName string) error {
return hyperv.UnmountDvdDrive(vmName)
}
func (d *HypervPS4Driver) DeleteDvdDrive(vmName string, controllerNumber string, controllerLocation string) error {
func (d *HypervPS4Driver) DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
return hyperv.DeleteDvdDrive(vmName, controllerNumber, controllerLocation)
}
func (d *HypervPS4Driver) MountFloppyDrive(vmName string, path string) error {
return hyperv.MountFloppyDrive(vmName, path)
}
func (d *HypervPS4Driver) UnmountFloppyDrive(vmName string) error {
return hyperv.UnmountFloppyDrive(vmName)
}

View File

@ -1,62 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
package common
import (
"fmt"
"bytes"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"strings"
"log"
)
type StepExecuteOnlineActivation struct {
}
func (s *StepExecuteOnlineActivation) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
comm := state.Get("communicator").(packer.Communicator)
errorMsg := "Error Executing Online Activation: %s"
var remoteCmd packer.RemoteCmd
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
var err error
ui.Say("Executing Online Activation...")
var blockBuffer bytes.Buffer
blockBuffer.WriteString("{ cscript \"$env:SystemRoot/system32/slmgr.vbs\" -ato //nologo }")
remoteCmd.Command = "-ScriptBlock " + blockBuffer.String()
remoteCmd.Stdout = stdout
remoteCmd.Stderr = stderr
err = comm.Start(&remoteCmd)
stderrString := strings.TrimSpace(stderr.String())
stdoutString := strings.TrimSpace(stdout.String())
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
if len(stderrString) > 0 {
err = fmt.Errorf(errorMsg, stderrString)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say(stdoutString)
return multistep.ActionContinue
}
func (s *StepExecuteOnlineActivation) Cleanup(state multistep.StateBag) {
// do nothing
}

View File

@ -1,90 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
package common
import (
"fmt"
"bytes"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"strings"
"log"
)
type StepExecuteOnlineActivationFull struct {
Pk string
}
func (s *StepExecuteOnlineActivationFull) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
comm := state.Get("communicator").(packer.Communicator)
errorMsg := "Error Executing Online Activation: %s"
var remoteCmd packer.RemoteCmd
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
var err error
var stderrString string
var stdoutString string
ui.Say("Executing Online Activation Full version...")
var blockBuffer bytes.Buffer
blockBuffer.WriteString("{ cscript \"$env:SystemRoot/system32/slmgr.vbs\" /ipk "+ s.Pk +" //nologo }")
log.Printf("cmd: %s", blockBuffer.String())
remoteCmd.Command = "-ScriptBlock " + blockBuffer.String()
remoteCmd.Stdout = stdout
remoteCmd.Stderr = stderr
err = comm.Start(&remoteCmd)
stderrString = strings.TrimSpace(stderr.String())
stdoutString = strings.TrimSpace(stdout.String())
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
if len(stderrString) > 0 {
err = fmt.Errorf(errorMsg, stderrString)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// ui.Say(stdoutString)
/*
blockBuffer.Reset()
blockBuffer.WriteString("{ cscript \"$env:SystemRoot/system32/slmgr.vbs\" -ato //nologo }")
log.Printf("cmd: %s", blockBuffer.String())
remoteCmd.Command = "-ScriptBlock " + blockBuffer.String()
err = comm.Start(&remoteCmd)
stderrString = strings.TrimSpace(stderr.String())
stdoutString = strings.TrimSpace(stdout.String())
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
if len(stderrString) > 0 {
err = fmt.Errorf(errorMsg, stderrString)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say(stdoutString)
*/
return multistep.ActionContinue
}
func (s *StepExecuteOnlineActivationFull) Cleanup(state multistep.StateBag) {
// do nothing
}

View File

@ -8,12 +8,13 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
powershell "github.com/mitchellh/packer/powershell"
"log"
)
type StepMountDvdDrive struct {
RawSingleISOUrl string
path string
Generation uint
cleanup bool
dvdProperties DvdControllerProperties
}
func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {
@ -22,39 +23,37 @@ func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {
errorMsg := "Error mounting dvd drive: %s"
vmName := state.Get("vmName").(string)
isoPath := s.RawSingleISOUrl
isoPath := state.Get("iso_path").(string)
// should be able to mount up to 60 additional iso images using SCSI
// but Windows would only allow a max of 22 due to available drive letters
// Will Windows assign DVD drives to A: and B: ?
// Check that there is a virtual dvd drive
var script powershell.ScriptBuilder
powershell := new(powershell.PowerShellCmd)
// For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1)
script.Reset()
script.WriteLine("param([string]$vmName)")
script.WriteLine("(Get-VMDvdDrive -VMName $vmName).ControllerNumber")
controllerNumber, err := powershell.Output(script.String(), vmName)
var dvdControllerProperties DvdControllerProperties
controllerNumber, controllerLocation, err := driver.CreateDvdDrive(vmName, s.Generation)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if controllerNumber == "" {
// Add a virtual dvd drive as there is none
script.Reset()
script.WriteLine("param([string]$vmName)")
script.WriteLine("Add-VMDvdDrive -VMName $vmName")
script.WriteLine("$dvdDrive = Get-VMDvdDrive -VMName $vmName | Select-Object -first 1")
script.WriteLine("Set-VMFirmware -VMName $vmName -FirstBootDevice $dvdDrive")
err = powershell.Run(script.String(), vmName)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
ui.Say("Mounting dvd drive...")
dvdControllerProperties.ControllerNumber = controllerNumber
dvdControllerProperties.ControllerLocation = controllerLocation
s.cleanup = true
s.dvdProperties = dvdControllerProperties
ui.Say("Setting boot drive to os dvd drive %s ...")
err = driver.SetBootDvdDrive(vmName, controllerNumber, controllerLocation)
if err != nil {
err := fmt.Errorf(errorMsg, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say(fmt.Sprintf("Mounting os dvd drive %s ...", isoPath))
err = driver.MountDvdDrive(vmName, isoPath)
if err != nil {
err := fmt.Errorf(errorMsg, err)
@ -62,28 +61,39 @@ func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {
ui.Error(err.Error())
return multistep.ActionHalt
}
s.path = isoPath
state.Put("os.dvd.properties", dvdControllerProperties)
return multistep.ActionContinue
}
func (s *StepMountDvdDrive) Cleanup(state multistep.StateBag) {
if s.path == "" {
if !s.cleanup {
return
}
driver := state.Get("driver").(Driver)
errorMsg := "Error unmounting dvd drive: %s"
errorMsg := "Error unmounting os dvd drive: %s"
vmName := state.Get("vmName").(string)
ui := state.Get("ui").(packer.Ui)
ui.Say("Unmounting dvd drive...")
err := driver.UnmountDvdDrive(vmName)
if err != nil {
ui.Error(fmt.Sprintf(errorMsg, err))
ui.Say("Clean up os dvd drive...")
dvdControllerProperties := s.dvdProperties
if dvdControllerProperties.Existing {
err := driver.UnmountDvdDrive(vmName)
if err != nil {
err := fmt.Errorf("Error unmounting dvd drive: %s", err)
log.Print(fmt.Sprintf(errorMsg, err))
}
} else {
err := driver.DeleteDvdDrive(vmName, dvdControllerProperties.ControllerNumber, dvdControllerProperties.ControllerLocation)
if err != nil {
err := fmt.Errorf("Error deleting dvd drive: %s", err)
log.Print(fmt.Sprintf(errorMsg, err))
}
}
}

View File

@ -8,93 +8,29 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/powershell"
"github.com/mitchellh/packer/powershell/hyperv"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
const (
FloppyFileName = "assets.vfd"
)
type StepSetUnattendedProductKey struct {
Files []string
ProductKey string
}
func (s *StepSetUnattendedProductKey) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.ProductKey == "" {
ui.Say("No product key specified...")
return multistep.ActionContinue
}
index := -1
for i, value := range s.Files {
if s.caseInsensitiveContains(value, "Autounattend.xml") {
index = i
break
}
}
ui.Say("Setting product key in Autounattend.xml...")
copyOfAutounattend, err := s.copyAutounattend(s.Files[index])
if err != nil {
state.Put("error", fmt.Errorf("Error copying Autounattend.xml: %s", err))
return multistep.ActionHalt
}
powershell.SetUnattendedProductKey(copyOfAutounattend, s.ProductKey)
s.Files[index] = copyOfAutounattend
return multistep.ActionContinue
}
func (s *StepSetUnattendedProductKey) caseInsensitiveContains(str, substr string) bool {
str, substr = strings.ToUpper(str), strings.ToUpper(substr)
return strings.Contains(str, substr)
}
func (s *StepSetUnattendedProductKey) copyAutounattend(path string) (string, error) {
tempdir, err := ioutil.TempDir("", "packer")
if err != nil {
return "", err
}
autounattend := filepath.Join(tempdir, "Autounattend.xml")
f, err := os.Create(autounattend)
if err != nil {
return "", err
}
defer f.Close()
sourceF, err := os.Open(path)
if err != nil {
return "", err
}
defer sourceF.Close()
log.Printf("Copying %s to temp location: %s", path, autounattend)
if _, err := io.Copy(f, sourceF); err != nil {
return "", err
}
return autounattend, nil
}
func (s *StepSetUnattendedProductKey) Cleanup(state multistep.StateBag) {
}
type StepMountFloppydrive struct {
Generation uint
floppyPath string
}
func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepAction {
if s.Generation > 1 {
return multistep.ActionContinue
}
driver := state.Get("driver").(Driver)
// Determine if we even have a floppy disk to attach
var floppyPath string
if floppyPathRaw, ok := state.GetOk("floppy_path"); ok {
@ -118,7 +54,7 @@ func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepActio
ui.Say("Mounting floppy drive...")
err = hyperv.MountFloppyDrive(vmName, floppyPath)
err = driver.MountFloppyDrive(vmName, floppyPath)
if err != nil {
state.Put("error", fmt.Errorf("Error mounting floppy drive: %s", err))
return multistep.ActionHalt
@ -131,6 +67,10 @@ func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepActio
}
func (s *StepMountFloppydrive) Cleanup(state multistep.StateBag) {
if s.Generation > 1 {
return
}
driver := state.Get("driver").(Driver)
if s.floppyPath == "" {
return
}
@ -140,17 +80,17 @@ func (s *StepMountFloppydrive) Cleanup(state multistep.StateBag) {
vmName := state.Get("vmName").(string)
ui := state.Get("ui").(packer.Ui)
ui.Say("Unmounting floppy drive (cleanup)...")
ui.Say("Cleanup floppy drive...")
err := hyperv.UnmountFloppyDrive(vmName)
err := driver.UnmountFloppyDrive(vmName)
if err != nil {
ui.Error(fmt.Sprintf(errorMsg, err))
log.Print(fmt.Sprintf(errorMsg, err))
}
err = os.Remove(s.floppyPath)
if err != nil {
ui.Error(fmt.Sprintf(errorMsg, err))
log.Print(fmt.Sprintf(errorMsg, err))
}
}

View File

@ -1,110 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
package common
import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
hyperv "github.com/mitchellh/packer/powershell/hyperv"
"log"
"os"
"strconv"
)
type StepMountSecondaryDvdImages struct {
Files []string
Generation uint
dvdProperties []DvdControllerProperties
}
type DvdControllerProperties struct {
ControllerNumber string
ControllerLocation string
}
func (s *StepMountSecondaryDvdImages) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ui.Say("Mounting secondary DVD images...")
vmName := state.Get("vmName").(string)
// should be able to mount up to 60 additional iso images using SCSI
// but Windows would only allow a max of 22 due to available drive letters
// Will Windows assign DVD drives to A: and B: ?
// For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1)
dvdProperties, err := s.mountFiles(vmName)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
log.Println(fmt.Sprintf("Saving DVD properties %d DVDs", len(dvdProperties)))
state.Put("secondary.dvd.properties", dvdProperties)
return multistep.ActionContinue
}
func (s *StepMountSecondaryDvdImages) Cleanup(state multistep.StateBag) {
}
func (s *StepMountSecondaryDvdImages) mountFiles(vmName string) ([]DvdControllerProperties, error) {
var dvdProperties []DvdControllerProperties
properties, err := s.addAndMountIntegrationServicesSetupDisk(vmName)
if err != nil {
return dvdProperties, err
}
dvdProperties = append(dvdProperties, properties)
for _, value := range s.Files {
properties, err := s.addAndMountDvdDisk(vmName, value)
if err != nil {
return dvdProperties, err
}
dvdProperties = append(dvdProperties, properties)
}
return dvdProperties, nil
}
func (s *StepMountSecondaryDvdImages) addAndMountIntegrationServicesSetupDisk(vmName string) (DvdControllerProperties, error) {
isoPath := os.Getenv("WINDIR") + "\\system32\\vmguest.iso"
properties, err := s.addAndMountDvdDisk(vmName, isoPath)
if err != nil {
return properties, err
}
return properties, nil
}
func (s *StepMountSecondaryDvdImages) addAndMountDvdDisk(vmName string, isoPath string) (DvdControllerProperties, error) {
var properties DvdControllerProperties
controllerNumber, controllerLocation, err := hyperv.CreateDvdDrive(vmName, s.Generation)
if err != nil {
return properties, err
}
properties.ControllerNumber = strconv.FormatInt(int64(controllerNumber), 10)
properties.ControllerLocation = strconv.FormatInt(int64(controllerLocation), 10)
err = hyperv.MountDvdDriveByLocation(vmName, isoPath, controllerNumber, controllerLocation)
if err != nil {
return properties, err
}
log.Println(fmt.Sprintf("ISO %s mounted on DVD controller %v, location %v", isoPath, controllerNumber, controllerLocation))
return properties, nil
}

View File

@ -15,20 +15,31 @@ type StepUnmountDvdDrive struct {
func (s *StepUnmountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
vmName := state.Get("vmName").(string)
ui := state.Get("ui").(packer.Ui)
vmName := state.Get("vmName").(string)
ui.Say("Unmounting dvd drive...")
err := driver.UnmountDvdDrive(vmName)
if err != nil {
err := fmt.Errorf("Error unmounting dvd drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
ui.Say("Unmounting os dvd drive...")
dvdController := state.Get("os.dvd.properties").(DvdControllerProperties)
if dvdController.Existing {
err := driver.UnmountDvdDrive(vmName)
if err != nil {
err := fmt.Errorf("Error unmounting os dvd drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
} else {
err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation)
if err != nil {
err := fmt.Errorf("Error deleting os dvd drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}

View File

@ -22,10 +22,10 @@ func (s *StepUnmountFloppyDrive) Run(state multistep.StateBag) multistep.StepAct
return multistep.ActionContinue
}
errorMsg := "Error Unmounting floppy drive: %s"
vmName := state.Get("vmName").(string)
ui.Say("Unmounting floppy drive (Run)...")
errorMsg := "Error Unmounting floppy drive: %s"
err := driver.UnmountFloppyDrive(vmName)
if err != nil {

View File

@ -1,43 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
package common
import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
type StepUnmountSecondaryDvdImages struct {
}
func (s *StepUnmountSecondaryDvdImages) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
ui.Say("Unmounting Integration Services Setup Disk...")
vmName := state.Get("vmName").(string)
// todo: should this message say removing the dvd?
dvdProperties := state.Get("secondary.dvd.properties").([]DvdControllerProperties)
log.Println(fmt.Sprintf("Found DVD properties %d", len(dvdProperties)))
for _, dvdProperty := range dvdProperties {
err := driver.DeleteDvdDrive(vmName, dvdProperty.ControllerNumber, dvdProperty.ControllerLocation)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *StepUnmountSecondaryDvdImages) Cleanup(state multistep.StateBag) {
}

View File

@ -1,110 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
package common
import (
//"fmt"
"os"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
powershell "github.com/mitchellh/packer/powershell"
)
type StepUpdateIntegrationServices struct {
Username string
Password string
newDvdDriveProperties dvdDriveProperties
}
type dvdDriveProperties struct {
ControllerNumber string
ControllerLocation string
}
func (s *StepUpdateIntegrationServices) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vmName := state.Get("vmName").(string)
ui.Say("Mounting Integration Services Setup Disk...")
_, err := s.mountIntegrationServicesSetupDisk(vmName);
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// dvdDriveLetter, err := s.getDvdDriveLetter(vmName)
// if err != nil {
// state.Put("error", err)
// ui.Error(err.Error())
// return multistep.ActionHalt
// }
// setup := dvdDriveLetter + ":\\support\\"+osArchitecture+"\\setup.exe /quiet /norestart"
// ui.Say("Run: " + setup)
return multistep.ActionContinue
}
func (s *StepUpdateIntegrationServices) Cleanup(state multistep.StateBag) {
vmName := state.Get("vmName").(string)
var script powershell.ScriptBuilder
script.WriteLine("param([string]$vmName)")
script.WriteLine("Set-VMDvdDrive -VMName $vmName -Path $null")
powershell := new(powershell.PowerShellCmd)
_ = powershell.Run(script.String(), vmName)
}
func (s *StepUpdateIntegrationServices) mountIntegrationServicesSetupDisk(vmName string) (dvdDriveProperties, error) {
var dvdProperties dvdDriveProperties
var script powershell.ScriptBuilder
script.WriteLine("param([string]$vmName)")
script.WriteLine("Add-VMDvdDrive -VMName $vmName")
powershell := new(powershell.PowerShellCmd)
err := powershell.Run(script.String(), vmName)
if err != nil {
return dvdProperties, err
}
script.Reset()
script.WriteLine("param([string]$vmName)")
script.WriteLine("(Get-VMDvdDrive -VMName $vmName | Where-Object {$_.Path -eq $null}).ControllerLocation")
controllerLocation, err := powershell.Output(script.String(), vmName)
if err != nil {
return dvdProperties, err
}
script.Reset()
script.WriteLine("param([string]$vmName)")
script.WriteLine("(Get-VMDvdDrive -VMName $vmName | Where-Object {$_.Path -eq $null}).ControllerNumber")
controllerNumber, err := powershell.Output(script.String(), vmName)
if err != nil {
return dvdProperties, err
}
isoPath := os.Getenv("WINDIR") + "\\system32\\vmguest.iso"
script.Reset()
script.WriteLine("param([string]$vmName,[string]$path,[string]$controllerNumber,[string]$controllerLocation)")
script.WriteLine("Set-VMDvdDrive -VMName $vmName -Path $path -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation")
err = powershell.Run(script.String(), vmName, isoPath, controllerNumber, controllerLocation)
if err != nil {
return dvdProperties, err
}
dvdProperties.ControllerNumber = controllerNumber
dvdProperties.ControllerLocation = controllerLocation
return dvdProperties, err
}

View File

@ -19,6 +19,7 @@ import (
"log"
"strings"
"time"
"os"
)
const (
@ -84,12 +85,21 @@ type Config struct {
// either an HTTP URL or a file URL (or path to a file). If this is an
// HTTP URL, Packer will download it and cache it between runs.
RawSingleISOUrl string `mapstructure:"iso_url"`
// Multiple URLs for the ISO to download. Packer will try these in order.
// If anything goes wrong attempting to download or while downloading a
// single URL, it will move on to the next. All URLs must point to the
// same file (same checksum). By default this is empty and iso_url is
// used. Only one of iso_url or iso_urls can be specified.
ISOUrls []string `mapstructure:"iso_urls"`
TargetPath string `mapstructure:"iso_target_path"`
// Should integration services iso be mounted
GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
// The path to the integration services iso
GuestAdditionsPath string `mapstructure:"guest_additions_path"`
// This is the name of the new virtual machine.
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
@ -234,6 +244,50 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
log.Println(fmt.Sprintf("%s: %v", "RawSingleISOUrl", b.config.RawSingleISOUrl))
if b.config.GuestAdditionsMode == "" {
b.config.GuestAdditionsMode = "attach"
}
if b.config.GuestAdditionsPath == "" {
b.config.GuestAdditionsPath = os.Getenv("WINDIR") + "\\system32\\vmguest.iso"
}
for _, isoPath := range b.config.SecondaryDvdImages {
if _, err := os.Stat(isoPath); os.IsNotExist(err) {
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Secondary Dvd image does not exist: %s", err))
}
}
}
numberOfIsos := len(b.config.SecondaryDvdImages)
if b.config.GuestAdditionsMode == "attach" {
if _, err := os.Stat(b.config.GuestAdditionsPath); os.IsNotExist(err) {
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Guest additions iso does not exist: %s", err))
}
}
numberOfIsos = numberOfIsos + 1
}
if b.config.Generation < 2 && numberOfIsos > 2 {
if b.config.GuestAdditionsMode == "attach" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("There are only 2 ide controllers available, so we can't support guest additions and these secondary dvds: %s", strings.Join(b.config.SecondaryDvdImages, ", ")))
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("There are only 2 ide controllers available, so we can't support these secondary dvds: %s", strings.Join(b.config.SecondaryDvdImages, ", ")))
}
} else if b.config.Generation > 1 && len(b.config.SecondaryDvdImages) > 16 {
if b.config.GuestAdditionsMode == "attach" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("There are not enough drive letters available for scsi (limited to 16), so we can't support guest additions and these secondary dvds: %s", strings.Join(b.config.SecondaryDvdImages, ", ")))
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("There are not enough drive letters available for scsi (limited to 16), so we can't support these secondary dvds: %s", strings.Join(b.config.SecondaryDvdImages, ", ")))
}
}
// Warnings
if b.config.ISOChecksumType == "none" {
warnings = append(warnings,
@ -275,12 +329,21 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state.Put("hook", hook)
state.Put("ui", ui)
steps := []multistep.Step{
steps := []multistep.Step{
&hypervcommon.StepCreateTempDir{},
&hypervcommon.StepOutputDir{
Force: b.config.PackerForce,
Path: b.config.OutputDir,
},
&common.StepDownload{
Checksum: b.config.ISOChecksum,
ChecksumType: b.config.ISOChecksumType,
Description: "ISO",
ResultKey: "iso_path",
Url: b.config.ISOUrls,
Extension: "iso",
TargetPath: b.config.TargetPath,
},
&common.StepCreateFloppy{
Files: b.config.FloppyFiles,
},
@ -304,12 +367,20 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&hypervcommon.StepEnableIntegrationService{},
&hypervcommon.StepMountDvdDrive{
RawSingleISOUrl: b.config.RawSingleISOUrl,
Generation: b.config.Generation,
},
&hypervcommon.StepMountFloppydrive{
Generation: b.config.Generation,
},
&hypervcommon.StepMountGuestAdditions{
GuestAdditionsMode: b.config.GuestAdditionsMode,
GuestAdditionsPath: b.config.GuestAdditionsPath,
Generation: b.config.Generation,
},
&hypervcommon.StepMountFloppydrive{},
&hypervcommon.StepMountSecondaryDvdImages{
Files: b.config.SecondaryDvdImages,
IsoPaths: b.config.SecondaryDvdImages,
Generation: b.config.Generation,
},
@ -341,15 +412,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
// wait for the vm to be powered off
&hypervcommon.StepWaitForPowerOff{},
// remove the integration services dvd drive
// remove the secondary dvd images
// after we power down
&hypervcommon.StepUnmountSecondaryDvdImages{},
&hypervcommon.StepUnmountGuestAdditions{},
&hypervcommon.StepUnmountDvdDrive{},
&hypervcommon.StepUnmountFloppyDrive{
Generation: b.config.Generation,
},
&hypervcommon.StepUnmountDvdDrive{},
&hypervcommon.StepExportVm{
OutputDir: b.config.OutputDir,
SkipCompaction: b.config.SkipCompaction,

View File

@ -153,7 +153,20 @@ Get-VMDvdDrive -VMName $vmName | Set-VMDvdDrive -Path $null
return err
}
func DeleteDvdDrive(vmName string, controllerNumber string, controllerLocation string) error {
func SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
var script = `
param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation)
$vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation
if (!$vmDvdDrive) {throw 'unable to find dvd drive'}
Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDvdDrive
`
var ps powershell.PowerShellCmd
err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10))
return err
}
func DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
var script = `
param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation)
$vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation
@ -162,7 +175,7 @@ Remove-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -Controlle
`
var ps powershell.PowerShellCmd
err := ps.Run(script, vmName, controllerNumber, controllerLocation)
err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10))
return err
}