Remove legacy_boot and replace with first_boot_device (initial)
This commit is contained in:
parent
807f39284d
commit
d7300f4635
|
@ -148,13 +148,21 @@ type CommonConfig struct {
|
|||
// built. When this value is set to true, the machine will start without a
|
||||
// console.
|
||||
Headless bool `mapstructure:"headless" required:"false"`
|
||||
// Over time the Hyper-V builder has been modified to change the original
|
||||
// boot order that is used when an ISO is mounted. Hyper-V's default is to
|
||||
// boot from the CD first, the original Hyper-V builder included code to
|
||||
// codify this setting when the primary ISO is mounted, that code was eventually
|
||||
// modified to place the IDE adapter before the the CD (only in generation 1).
|
||||
// Setting this value to true, forces the original method of operation.
|
||||
LegacyGen1BootOrder bool `mapstructure:"legacy_gen1_boot_order" required:"false"`
|
||||
// When configured, determines the device or device type that is given preferential
|
||||
// treatment when choosing a boot device.
|
||||
//
|
||||
// For Generation 1:
|
||||
// - `IDE`
|
||||
// - `CD` *or* `DVD`
|
||||
// - `Floppy`
|
||||
// - `NET`
|
||||
//
|
||||
// For Generation 2:
|
||||
// - `IDE:x:y`
|
||||
// - `SCSI:x:y`
|
||||
// - `CD` *or* `DVD`
|
||||
// - `NET`
|
||||
FirstBootDevice string `mapstructure:"first_boot_device" required:"false"`
|
||||
}
|
||||
|
||||
func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) ([]error, []string) {
|
||||
|
|
|
@ -111,7 +111,9 @@ type Driver interface {
|
|||
|
||||
MountDvdDrive(string, string, uint, uint) error
|
||||
|
||||
SetBootDvdDrive(string, uint, uint, uint, bool) error
|
||||
SetBootDvdDrive(string, uint, uint, uint) error
|
||||
|
||||
SetFirstBootDevice(string, string, uint, uint, uint) error
|
||||
|
||||
UnmountDvdDrive(string, uint, uint) error
|
||||
|
||||
|
|
|
@ -263,8 +263,13 @@ func (d *HypervPS4Driver) MountDvdDrive(vmName string, path string, controllerNu
|
|||
}
|
||||
|
||||
func (d *HypervPS4Driver) SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint,
|
||||
generation uint, legacyGen1BootOrder bool) error {
|
||||
return hyperv.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, generation, legacyGen1BootOrder)
|
||||
generation uint) error {
|
||||
return hyperv.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, generation)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) SetFirstBootDevice(vmName string, controllerType string, controllerNumber uint,
|
||||
controllerLocation uint, generation uint) error {
|
||||
return hyperv.SetFirstBootDevice(vmName, controllerType, controllerNumber, controllerLocation, generation)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
type StepMountDvdDrive struct {
|
||||
Generation uint
|
||||
LegacyGen1BootOrder bool
|
||||
FirstBootDevice string
|
||||
}
|
||||
|
||||
func (s *StepMountDvdDrive) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -58,18 +58,24 @@ func (s *StepMountDvdDrive) Run(ctx context.Context, state multistep.StateBag) m
|
|||
|
||||
state.Put("os.dvd.properties", dvdControllerProperties)
|
||||
|
||||
if (s.Generation == 1) && (!s.LegacyGen1BootOrder) {
|
||||
ui.Say("Setting boot drive to IDE and then CD drive. Use legacy_gen1_boot_order to override.")
|
||||
} else {
|
||||
ui.Say(fmt.Sprintf("Setting boot drive to os dvd drive %s ...", isoPath))
|
||||
}
|
||||
// the "first_boot_device" setting has precedence over the legacy boot order
|
||||
// configuration, but only if its been assigned a value.
|
||||
|
||||
if s.FirstBootDevice == "" {
|
||||
|
||||
if s.Generation > 1 {
|
||||
// only print this message for Gen2, it's not a true statement for Gen1 VMs
|
||||
ui.Say(fmt.Sprintf("Setting boot drive to os dvd drive %s ...", isoPath))
|
||||
}
|
||||
|
||||
err = driver.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, s.Generation)
|
||||
if err != nil {
|
||||
err := fmt.Errorf(errorMsg, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = driver.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, s.Generation, s.LegacyGen1BootOrder)
|
||||
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))
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepSetFirstBootDevice struct {
|
||||
Generation uint
|
||||
FirstBootDevice string
|
||||
}
|
||||
|
||||
func ParseBootDeviceIdentifier(deviceIdentifier string, generation uint) (string, uint, uint, error) {
|
||||
|
||||
captureExpression := "^(FLOPPY|IDE|NET)|(CD|DVD)$"
|
||||
if generation > 1 {
|
||||
captureExpression = "^((IDE|SCSI):(\\d+):(\\d+))|(DVD|CD)|(NET)$"
|
||||
}
|
||||
|
||||
r, err := regexp.Compile(captureExpression)
|
||||
if err != nil {
|
||||
return "", 0, 0, err
|
||||
}
|
||||
|
||||
// match against the appropriate set of values.. we force to uppercase to ensure that
|
||||
// all devices are always in the same case
|
||||
|
||||
identifierMatches := r.FindStringSubmatch(strings.ToUpper(deviceIdentifier))
|
||||
if identifierMatches == nil {
|
||||
return "", 0, 0, fmt.Errorf("The value %q is not a properly formatted device or device group identifier.", deviceIdentifier)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
// CD or DVD are always returned as "CD"
|
||||
case ((generation == 1) && (identifierMatches[2] != "")) || ((generation > 1) && (identifierMatches[5] != "")):
|
||||
return "CD", 0, 0, nil
|
||||
|
||||
// generation 1 only has FLOPPY, IDE or NET remaining..
|
||||
case (generation == 1):
|
||||
return identifierMatches[0], 0, 0, nil
|
||||
|
||||
// generation 2, check for IDE or SCSI and parse location and number
|
||||
case (identifierMatches[2] != ""):
|
||||
{
|
||||
|
||||
var controllerLocation int64
|
||||
var controllerNumber int64
|
||||
|
||||
// NOTE: controllerNumber and controllerLocation cannot be negative, the regex expression
|
||||
// would not have matched if either number was signed
|
||||
|
||||
controllerNumber, err = strconv.ParseInt(identifierMatches[3], 10, 8)
|
||||
if err == nil {
|
||||
|
||||
controllerLocation, err = strconv.ParseInt(identifierMatches[4], 10, 8)
|
||||
if err == nil {
|
||||
|
||||
return identifierMatches[2], uint(controllerNumber), uint(controllerLocation), nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return "", 0, 0, err
|
||||
|
||||
}
|
||||
|
||||
// only "NET" left on generation 2
|
||||
default:
|
||||
return "NET", 0, 0, nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *StepSetFirstBootDevice) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if s.FirstBootDevice != "" {
|
||||
|
||||
controllerType, controllerNumber, controllerLocation, err := ParseBootDeviceIdentifier(s.FirstBootDevice, s.Generation)
|
||||
if err == nil {
|
||||
|
||||
switch {
|
||||
|
||||
case controllerType == "CD":
|
||||
{
|
||||
// the "DVD" controller is special, we only apply the setting if we actually mounted
|
||||
// an ISO and only if that was mounted as the "IsoUrl" not a secondary ISO.
|
||||
|
||||
dvdControllerState := state.Get("os.dvd.properties")
|
||||
if dvdControllerState == nil {
|
||||
|
||||
ui.Say("First Boot Device is DVD, but no primary ISO mounted. Ignoring.")
|
||||
return multistep.ActionContinue
|
||||
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Setting boot device to %q", s.FirstBootDevice))
|
||||
dvdController := dvdControllerState.(DvdControllerProperties)
|
||||
err = driver.SetFirstBootDevice(vmName, controllerType, dvdController.ControllerNumber, dvdController.ControllerLocation, s.Generation)
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// anything else, we just pass as is..
|
||||
ui.Say(fmt.Sprintf("Setting boot device to %q", s.FirstBootDevice))
|
||||
err = driver.SetFirstBootDevice(vmName, controllerType, controllerNumber, controllerLocation, s.Generation)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error setting first boot device: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSetFirstBootDevice) Cleanup(state multistep.StateBag) {
|
||||
// do nothing
|
||||
}
|
|
@ -243,7 +243,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
|
||||
&hypervcommon.StepMountDvdDrive{
|
||||
Generation: b.config.Generation,
|
||||
LegacyGen1BootOrder: b.config.LegacyGen1BootOrder,
|
||||
FirstBootDevice: b.config.FirstBootDevice,
|
||||
},
|
||||
&hypervcommon.StepMountFloppydrive{
|
||||
Generation: b.config.Generation,
|
||||
|
@ -265,6 +265,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
SwitchVlanId: b.config.SwitchVlanId,
|
||||
},
|
||||
|
||||
&hypervcommon.StepSetFirstBootDevice{
|
||||
Generation: b.config.Generation,
|
||||
FirstBootDevice: b.config.FirstBootDevice,
|
||||
},
|
||||
|
||||
&hypervcommon.StepRun{
|
||||
Headless: b.config.Headless,
|
||||
SwitchName: b.config.SwitchName,
|
||||
|
|
|
@ -283,7 +283,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
|
||||
&hypervcommon.StepMountDvdDrive{
|
||||
Generation: b.config.Generation,
|
||||
LegacyGen1BootOrder: b.config.LegacyGen1BootOrder,
|
||||
FirstBootDevice: b.config.FirstBootDevice,
|
||||
},
|
||||
&hypervcommon.StepMountFloppydrive{
|
||||
Generation: b.config.Generation,
|
||||
|
@ -305,6 +305,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
SwitchVlanId: b.config.SwitchVlanId,
|
||||
},
|
||||
|
||||
&hypervcommon.StepSetFirstBootDevice{
|
||||
Generation: b.config.Generation,
|
||||
FirstBootDevice: b.config.FirstBootDevice,
|
||||
},
|
||||
|
||||
&hypervcommon.StepRun{
|
||||
Headless: b.config.Headless,
|
||||
SwitchName: b.config.SwitchName,
|
||||
|
|
|
@ -156,21 +156,13 @@ Hyper-V\Set-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -Cont
|
|||
return err
|
||||
}
|
||||
|
||||
func SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, generation uint, legacyGen1BootOrder bool) error {
|
||||
func SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, generation uint) error {
|
||||
|
||||
if generation < 2 {
|
||||
var script string
|
||||
if legacyGen1BootOrder {
|
||||
script = `
|
||||
param([string]$vmName)
|
||||
Hyper-V\Set-VMBios -VMName $vmName -StartupOrder @("CD","IDE","LegacyNetworkAdapter","Floppy")
|
||||
`
|
||||
} else {
|
||||
script = `
|
||||
script := `
|
||||
param([string]$vmName)
|
||||
Hyper-V\Set-VMBios -VMName $vmName -StartupOrder @("IDE","CD","LegacyNetworkAdapter","Floppy")
|
||||
`
|
||||
}
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, vmName)
|
||||
return err
|
||||
|
@ -188,6 +180,56 @@ Hyper-V\Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDvdDrive -ErrorAction
|
|||
}
|
||||
}
|
||||
|
||||
func SetFirstBootDeviceGen1(vmName string, controllerType string) error {
|
||||
|
||||
// for Generation 1 VMs, we read the value of the VM's boot order, strip the value specified in
|
||||
// controllerType and insert that value back at the beginning of the list.
|
||||
//
|
||||
// controllerType must be 'NET', 'DVD', 'IDE' or 'FLOPPY' (case sensitive)
|
||||
// The 'NET' value is always replaced with 'LegacyNetworkAdapter'
|
||||
|
||||
if (controllerType == "NET") {
|
||||
controllerType = "LegacyNetworkAdapter"
|
||||
}
|
||||
|
||||
script := `
|
||||
param([string] $vmName, [string] $controllerType)
|
||||
$vmBootOrder = Hyper-V\Get-VMBios -VMName $vmName | Select-Object -ExpandProperty StartupOrder | Where-Object { $_ -ne $controllerType }
|
||||
Hyper-V\Set-VMBios -VMName $vmName -StartupOrder (@($controllerType) + $vmBootOrder)
|
||||
`
|
||||
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, vmName, controllerType)
|
||||
return err
|
||||
}
|
||||
|
||||
func SetFirstBootDeviceGen2(vmName string, controllerType string, controllerNumber uint, controllerLocation uint) error {
|
||||
|
||||
|
||||
|
||||
// script := `
|
||||
// param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation)
|
||||
// $vmDvdDrive = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation
|
||||
// if (!$vmDvdDrive) {throw 'unable to find dvd drive'}
|
||||
// Hyper-V\Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDvdDrive -ErrorAction SilentlyContinue
|
||||
// `
|
||||
|
||||
// script := `
|
||||
// param([string] $vmName, [string] $controllerType, )
|
||||
//`
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetFirstBootDevice(vmName string, controllerType string, controllerNumber uint, controllerLocation uint, generation uint) error {
|
||||
|
||||
if generation == 1 {
|
||||
return SetFirstBootDeviceGen1(vmName, controllerType)
|
||||
} else {
|
||||
return SetFirstBootDeviceGen2(vmName, controllerType, controllerNumber, controllerLocation)
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
|
||||
var script = `
|
||||
param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation)
|
||||
|
|
Loading…
Reference in New Issue