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:
parent
422efeeaf6
commit
010d171bec
|
@ -92,9 +92,13 @@ type Driver interface {
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
||||
// Check that there is a virtual dvd drive
|
||||
var script powershell.ScriptBuilder
|
||||
powershell := new(powershell.PowerShellCmd)
|
||||
// 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: ?
|
||||
|
||||
script.Reset()
|
||||
script.WriteLine("param([string]$vmName)")
|
||||
script.WriteLine("(Get-VMDvdDrive -VMName $vmName).ControllerNumber")
|
||||
controllerNumber, err := powershell.Output(script.String(), vmName)
|
||||
// For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1)
|
||||
|
||||
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
|
||||
}
|
||||
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("Mounting dvd drive...")
|
||||
|
||||
ui.Say(fmt.Sprintf("Mounting os dvd drive %s ...", isoPath))
|
||||
err = driver.MountDvdDrive(vmName, isoPath)
|
||||
if err != nil {
|
||||
err := fmt.Errorf(errorMsg, err)
|
||||
|
@ -63,27 +62,38 @@ func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {
|
|||
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...")
|
||||
ui.Say("Clean up os dvd drive...")
|
||||
|
||||
err := driver.UnmountDvdDrive(vmName)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf(errorMsg, err))
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -15,18 +15,29 @@ 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 os dvd drive...")
|
||||
|
||||
ui.Say("Unmounting dvd drive...")
|
||||
dvdController := state.Get("os.dvd.properties").(DvdControllerProperties)
|
||||
|
||||
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
|
||||
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
|
||||
|
|
|
@ -22,11 +22,11 @@ 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 {
|
||||
err := fmt.Errorf(errorMsg, err)
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -19,6 +19,7 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -84,6 +85,7 @@ 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
|
||||
|
@ -91,6 +93,14 @@ type Config struct {
|
|||
// 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.
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
|
@ -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,
|
||||
|
@ -281,6 +335,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
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,
|
||||
},
|
||||
|
||||
|
@ -342,14 +413,14 @@ 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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue