From 422efeeaf6719a731b450952529f744b5221c1fa Mon Sep 17 00:00:00 2001 From: Taliesin Sisson Date: Fri, 30 Oct 2015 08:23:30 +0000 Subject: [PATCH] Make use of driver instead of directly referencing hyper Move inline powershell to hyperv --- builder/hyperv/common/driver.go | 60 +++++++ builder/hyperv/common/driver_ps_4.go | 112 +++++++++++++ builder/hyperv/common/step_configure_ip.go | 16 +- builder/hyperv/common/step_configure_vlan.go | 20 +-- .../common/step_create_external_switch.go | 25 ++- builder/hyperv/common/step_create_switch.go | 21 ++- builder/hyperv/common/step_create_vm.go | 39 ++--- builder/hyperv/common/step_disable_vlan.go | 6 +- .../common/step_enable_integration_service.go | 4 +- builder/hyperv/common/step_export_vm.go | 8 +- builder/hyperv/common/step_mount_dvddrive.go | 9 +- .../hyperv/common/step_mount_floppydrive.go | 37 ++--- .../common/step_mount_integration_services.go | 56 +------ .../common/step_polling_installation.go | 41 +---- builder/hyperv/common/step_reboot_vm.go | 5 +- .../hyperv/common/step_unmount_dvddrive.go | 8 +- .../hyperv/common/step_unmount_floppydrive.go | 5 +- .../step_unmount_integration_services.go | 14 +- .../step_wait_for_install_to_complete.go | 44 ++---- powershell/hyperv/hyperv.go | 148 +++++++++++++++++- 20 files changed, 432 insertions(+), 246 deletions(-) diff --git a/builder/hyperv/common/driver.go b/builder/hyperv/common/driver.go index 2d5044576..5afa15d77 100644 --- a/builder/hyperv/common/driver.go +++ b/builder/hyperv/common/driver.go @@ -15,6 +15,12 @@ type Driver interface { // Checks if the VM named is running. IsRunning(string) (bool, error) + // Checks if the VM named is off. + IsOff(string) (bool, error) + + //How long has VM been on + Uptime(vmName string) (uint64, error) + // Start starts a VM specified by the name given. Start(string) error @@ -32,9 +38,63 @@ type Driver interface { // Finds the IP address of a VM connected that uses DHCP by its MAC address IpAddress(string) (string, error) + // Finds the hostname for the ip address + GetHostName(string) (string, error) + // Finds the IP address of a host adapter connected to switch GetHostAdapterIpAddressForSwitch(string) (string, error) // Type scan codes to virtual keyboard of vm TypeScanCodes(string, string) error + + //Get the ip address for network adaptor + GetVirtualMachineNetworkAdapterAddress(string) (string, error) + + //Set the vlan to use for switch + SetNetworkAdapterVlanId(string, string) error + + //Set the vlan to use for machine + SetVirtualMachineVlanId(string, string) error + + UntagVirtualMachineNetworkAdapterVlan(string, string) error + + CreateExternalVirtualSwitch(string, string) error + + GetVirtualMachineSwitchName(string) (string, error) + + ConnectVirtualMachineNetworkAdapterToSwitch(string, string) error + + CreateVirtualSwitch(string, string) (bool, error) + + DeleteVirtualSwitch(string) error + + CreateVirtualMachine(string, string, int64, int64, string, uint) error + + DeleteVirtualMachine(string) error + + SetVirtualMachineCpu(string, uint) error + + SetSecureBoot(string, bool) error + + EnableVirtualMachineIntegrationService(string, string) error + + ExportVirtualMachine(string, string) error + + CompactDisks(string, string) error + + CopyExportedVirtualMachine(string, string, string, string) error + + RestartVirtualMachine(string) error + + CreateDvdDrive(string, uint) (uint, uint, error) + + MountDvdDrive(string, string) error + + MountDvdDriveByLocation(string, string, uint, uint) error + + UnmountDvdDrive(string) error + + DeleteDvdDrive(string, string, string) error + + UnmountFloppyDrive(vmName string) error } diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go index b9371a8c0..5662ce0d8 100644 --- a/builder/hyperv/common/driver_ps_4.go +++ b/builder/hyperv/common/driver_ps_4.go @@ -39,6 +39,14 @@ func (d *HypervPS4Driver) IsRunning(vmName string) (bool, error) { return hyperv.IsRunning(vmName) } +func (d *HypervPS4Driver) IsOff(vmName string) (bool, error) { + return hyperv.IsOff(vmName) +} + +func (d *HypervPS4Driver) Uptime(vmName string) (uint64, error) { + return hyperv.Uptime(vmName) +} + // Start starts a VM specified by the name given. func (d *HypervPS4Driver) Start(vmName string) error { return hyperv.StartVirtualMachine(vmName) @@ -97,6 +105,11 @@ func (d *HypervPS4Driver) IpAddress(mac string) (string, error) { return res, err } +// Get host name from ip address +func (d *HypervPS4Driver) GetHostName(ip string) (string, error) { + return powershell.GetHostName(ip) +} + // Finds the IP address of a host adapter connected to switch func (d *HypervPS4Driver) GetHostAdapterIpAddressForSwitch(switchName string) (string, error) { res, err := hyperv.GetHostAdapterIpAddressForSwitch(switchName) @@ -117,6 +130,105 @@ func (d *HypervPS4Driver) TypeScanCodes(vmName string, scanCodes string) error { return hyperv.TypeScanCodes(vmName, scanCodes) } +// Get network adapter address +func (d *HypervPS4Driver) GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) { + return hyperv.GetVirtualMachineNetworkAdapterAddress(vmName) +} + +//Set the vlan to use for switch +func (d *HypervPS4Driver) SetNetworkAdapterVlanId(switchName string, vlanId string) error { + return hyperv.SetNetworkAdapterVlanId(switchName, vlanId) +} + +//Set the vlan to use for machine +func (d *HypervPS4Driver) SetVirtualMachineVlanId(vmName string, vlanId string) error { + return hyperv.SetVirtualMachineVlanId(vmName, vlanId) +} + +func (d *HypervPS4Driver) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { + return hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) +} + +func (d *HypervPS4Driver) CreateExternalVirtualSwitch(vmName string, switchName string) error { + return hyperv.CreateExternalVirtualSwitch(vmName, switchName) +} + +func (d *HypervPS4Driver) GetVirtualMachineSwitchName(vmName string) (string, error) { + return hyperv.GetVirtualMachineSwitchName(vmName) +} + +func (d *HypervPS4Driver) ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { + return hyperv.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, switchName) +} + +func (d *HypervPS4Driver) DeleteVirtualSwitch(switchName string) error { + return hyperv.DeleteVirtualSwitch(switchName) +} + +func (d *HypervPS4Driver) CreateVirtualSwitch(switchName string, switchType string) (bool, error) { + return hyperv.CreateVirtualSwitch(switchName, switchType) +} + +func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, ram int64, diskSize int64, switchName string, generation uint) error { + return hyperv.CreateVirtualMachine(vmName, path, ram, diskSize, switchName, generation) +} + +func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error { + return hyperv.DeleteVirtualMachine(vmName) +} + +func (d *HypervPS4Driver) SetVirtualMachineCpu(vmName string, cpu uint) error { + return hyperv.SetVirtualMachineCpu(vmName, cpu) +} + +func (d *HypervPS4Driver) SetSecureBoot(vmName string, enable bool) error { + return hyperv.SetSecureBoot(vmName, enable) +} + +func (d *HypervPS4Driver) EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error { + return hyperv.EnableVirtualMachineIntegrationService(vmName, integrationServiceName) +} + +func (d *HypervPS4Driver) ExportVirtualMachine(vmName string, path string) error { + return hyperv.ExportVirtualMachine(vmName, path) +} + +func (d *HypervPS4Driver) CompactDisks(expPath string, vhdDir string) error { + return hyperv.CompactDisks(expPath, vhdDir) +} + +func (d *HypervPS4Driver) CopyExportedVirtualMachine(expPath string, outputPath string, vhdDir string, vmDir string) error { + return hyperv.CopyExportedVirtualMachine(expPath, outputPath, vhdDir, vmDir) +} + +func (d *HypervPS4Driver) RestartVirtualMachine(vmName string) error { + return hyperv.RestartVirtualMachine(vmName) +} + +func (d *HypervPS4Driver) CreateDvdDrive(vmName string, generation uint) (uint, uint, error) { + return hyperv.CreateDvdDrive(vmName, generation) +} + +func (d *HypervPS4Driver) MountDvdDrive(vmName string, path string) error { + return hyperv.MountDvdDrive(vmName, path) +} + +func (d *HypervPS4Driver) MountDvdDriveByLocation(vmName string, path string, controllerNumber uint, controllerLocation uint) error { + return hyperv.MountDvdDriveByLocation(vmName, path, controllerNumber, controllerLocation) +} + +func (d *HypervPS4Driver) UnmountDvdDrive(vmName string) error { + return hyperv.UnmountDvdDrive(vmName) +} + +func (d *HypervPS4Driver) DeleteDvdDrive(vmName string, controllerNumber string, controllerLocation string) error { + return hyperv.DeleteDvdDrive(vmName, controllerNumber, controllerLocation) +} + +func (d *HypervPS4Driver) UnmountFloppyDrive(vmName string) error { + return hyperv.UnmountFloppyDrive(vmName) +} + func (d *HypervPS4Driver) verifyPSVersion() error { log.Printf("Enter method: %s", "verifyPSVersion") diff --git a/builder/hyperv/common/step_configure_ip.go b/builder/hyperv/common/step_configure_ip.go index ea35818e9..4396a1b9a 100644 --- a/builder/hyperv/common/step_configure_ip.go +++ b/builder/hyperv/common/step_configure_ip.go @@ -8,19 +8,16 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "log" "strings" "time" - "log" - powershell "github.com/mitchellh/packer/powershell" - "github.com/mitchellh/packer/powershell/hyperv" ) - type StepConfigureIp struct { } func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { -// driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error configuring ip address: %s" @@ -34,7 +31,7 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { var ip string for count != 0 { - cmdOut, err := hyperv.GetVirtualMachineNetworkAdapterAddress(vmName) + cmdOut, err := driver.GetVirtualMachineNetworkAdapterAddress(vmName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) @@ -45,7 +42,7 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { ip = strings.TrimSpace(string(cmdOut)) if ip != "False" { - break; + break } log.Println(fmt.Sprintf("Waiting for another %v minutes...", uint(duration))) @@ -53,7 +50,7 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { count-- } - if(count == 0){ + if count == 0 { err := fmt.Errorf(errorMsg, "IP address assigned to the adapter is empty") state.Put("error", err) ui.Error(err.Error()) @@ -62,7 +59,7 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { ui.Say("ip address is " + ip) - hostName, err := powershell.GetHostName(ip); + hostName, err := driver.GetHostName(ip) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -80,4 +77,3 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction { func (s *StepConfigureIp) Cleanup(state multistep.StateBag) { // do nothing } - diff --git a/builder/hyperv/common/step_configure_vlan.go b/builder/hyperv/common/step_configure_vlan.go index 508b43e98..94f445ddd 100644 --- a/builder/hyperv/common/step_configure_vlan.go +++ b/builder/hyperv/common/step_configure_vlan.go @@ -8,20 +8,14 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" -) - - -const( - vlanId = "1724" ) type StepConfigureVlan struct { + vlanId string } func (s *StepConfigureVlan) Run(state multistep.StateBag) multistep.StepAction { - //config := state.Get("config").(*config) - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error configuring vlan: %s" @@ -30,7 +24,13 @@ func (s *StepConfigureVlan) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Configuring vlan...") - err := hyperv.SetNetworkAdapterVlanId(switchName, vlanId) + vlanId := s.vlanId + + if vlanId == "" { + vlanId = "1724" + } + + err := driver.SetNetworkAdapterVlanId(switchName, vlanId) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) @@ -38,7 +38,7 @@ func (s *StepConfigureVlan) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - err = hyperv.SetVirtualMachineVlanId(vmName, vlanId) + err = driver.SetVirtualMachineVlanId(vmName, vlanId) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) diff --git a/builder/hyperv/common/step_create_external_switch.go b/builder/hyperv/common/step_create_external_switch.go index 1685d069e..4ab1c335b 100644 --- a/builder/hyperv/common/step_create_external_switch.go +++ b/builder/hyperv/common/step_create_external_switch.go @@ -5,11 +5,10 @@ package common import ( + "code.google.com/p/go-uuid/uuid" "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "code.google.com/p/go-uuid/uuid" - "github.com/mitchellh/packer/powershell/hyperv" ) // This step creates switch for VM. @@ -17,12 +16,12 @@ import ( // Produces: // SwitchName string - The name of the Switch type StepCreateExternalSwitch struct { - SwitchName string + SwitchName string oldSwitchName string } func (s *StepCreateExternalSwitch) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) @@ -33,16 +32,16 @@ func (s *StepCreateExternalSwitch) Run(state multistep.StateBag) multistep.StepA packerExternalSwitchName := "paes_" + uuid.New() - err = hyperv.CreateExternalVirtualSwitch(vmName, packerExternalSwitchName) + err = driver.CreateExternalVirtualSwitch(vmName, packerExternalSwitchName) if err != nil { err := fmt.Errorf("Error creating switch: %s", err) state.Put(errorMsg, err) ui.Error(err.Error()) - s.SwitchName = ""; + s.SwitchName = "" return multistep.ActionHalt } - - switchName, err := hyperv.GetVirtualMachineSwitchName(vmName) + + switchName, err := driver.GetVirtualMachineSwitchName(vmName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) @@ -59,10 +58,10 @@ func (s *StepCreateExternalSwitch) Run(state multistep.StateBag) multistep.StepA ui.Say("External switch name is: '" + switchName + "'") - if(switchName != packerExternalSwitchName){ + if switchName != packerExternalSwitchName { s.SwitchName = "" } else { - s.SwitchName = packerExternalSwitchName + s.SwitchName = packerExternalSwitchName s.oldSwitchName = state.Get("SwitchName").(string) } @@ -76,7 +75,7 @@ func (s *StepCreateExternalSwitch) Cleanup(state multistep.StateBag) { if s.SwitchName == "" { return } - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) @@ -92,7 +91,7 @@ func (s *StepCreateExternalSwitch) Cleanup(state multistep.StateBag) { return } - err = hyperv.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, s.oldSwitchName) + err = driver.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, s.oldSwitchName) if err != nil { ui.Error(fmt.Sprintf(errMsg, err)) return @@ -100,7 +99,7 @@ func (s *StepCreateExternalSwitch) Cleanup(state multistep.StateBag) { state.Put("SwitchName", s.oldSwitchName) - err = hyperv.DeleteVirtualSwitch(s.SwitchName) + err = driver.DeleteVirtualSwitch(s.SwitchName) if err != nil { ui.Error(fmt.Sprintf(errMsg, err)) } diff --git a/builder/hyperv/common/step_create_switch.go b/builder/hyperv/common/step_create_switch.go index 5620e3f93..b8eb02962 100644 --- a/builder/hyperv/common/step_create_switch.go +++ b/builder/hyperv/common/step_create_switch.go @@ -8,13 +8,12 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" ) const ( SwitchTypeInternal = "Internal" - SwitchTypePrivate = "Private" - DefaultSwitchType = SwitchTypeInternal + SwitchTypePrivate = "Private" + DefaultSwitchType = SwitchTypeInternal ) // This step creates switch for VM. @@ -23,21 +22,21 @@ const ( // SwitchName string - The name of the Switch type StepCreateSwitch struct { // Specifies the name of the switch to be created. - SwitchName string + SwitchName string // Specifies the type of the switch to be created. Allowed values are Internal and Private. To create an External // virtual switch, specify either the NetAdapterInterfaceDescription or the NetAdapterName parameter, which // implicitly set the type of the virtual switch to External. - SwitchType string + SwitchType string // Specifies the name of the network adapter to be bound to the switch to be created. NetAdapterName string // Specifies the interface description of the network adapter to be bound to the switch to be created. NetAdapterInterfaceDescription string - createdSwitch bool + createdSwitch bool } func (s *StepCreateSwitch) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) if len(s.SwitchType) == 0 { @@ -46,12 +45,12 @@ func (s *StepCreateSwitch) Run(state multistep.StateBag) multistep.StepAction { ui.Say(fmt.Sprintf("Creating switch '%v' if required...", s.SwitchName)) - createdSwitch, err := hyperv.CreateVirtualSwitch(s.SwitchName, s.SwitchType) + createdSwitch, err := driver.CreateVirtualSwitch(s.SwitchName, s.SwitchType) if err != nil { err := fmt.Errorf("Error creating switch: %s", err) state.Put("error", err) ui.Error(err.Error()) - s.SwitchName = ""; + s.SwitchName = "" return multistep.ActionHalt } @@ -72,11 +71,11 @@ func (s *StepCreateSwitch) Cleanup(state multistep.StateBag) { return } - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Unregistering and deleting switch...") - err := hyperv.DeleteVirtualSwitch(s.SwitchName) + err := driver.DeleteVirtualSwitch(s.SwitchName) if err != nil { ui.Error(fmt.Sprintf("Error deleting switch: %s", err)) } diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go index 6418dbea0..6d142cb0b 100644 --- a/builder/hyperv/common/step_create_vm.go +++ b/builder/hyperv/common/step_create_vm.go @@ -8,8 +8,6 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" - "strconv" ) // This step creates the actual virtual machine. @@ -17,50 +15,47 @@ import ( // Produces: // VMName string - The name of the VM type StepCreateVM struct { - VMName string - SwitchName string - RamSizeMB uint - DiskSize uint - Generation uint - Cpu uint + VMName string + SwitchName string + RamSizeMB uint + DiskSize uint + Generation uint + Cpu uint EnabeSecureBoot bool } func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Creating virtual machine...") path := state.Get("packerTempDir").(string) // convert the MB to bytes - ramBytes := int64(s.RamSizeMB * 1024 * 1024) - diskSizeBytes := int64(s.DiskSize * 1024 * 1024) + ram := int64(s.RamSizeMB * 1024 * 1024) + diskSize := int64(s.DiskSize * 1024 * 1024) - ram := strconv.FormatInt(ramBytes, 10) - diskSize := strconv.FormatInt(diskSizeBytes, 10) switchName := s.SwitchName - generation := strconv.FormatInt(int64(s.Generation), 10) - cpu := strconv.FormatInt(int64(s.Cpu), 10) enabeSecureBoot := s.EnabeSecureBoot - err := hyperv.CreateVirtualMachine(s.VMName, path, ram, diskSize, switchName, generation) + err := driver.CreateVirtualMachine(s.VMName, path, ram, diskSize, switchName, s.Generation) if err != nil { err := fmt.Errorf("Error creating virtual machine: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - - err = hyperv.SetVirtualMachineCpu(s.VMName, cpu) + + err = driver.SetVirtualMachineCpu(s.VMName, s.Cpu) if err != nil { err := fmt.Errorf("Error creating setting virtual machine cpu: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - - if generation == "2" { - err = hyperv.SetSecureBoot(s.VMName, enabeSecureBoot) + + if s.Generation == 2 { + err = driver.SetSecureBoot(s.VMName, enabeSecureBoot) if err != nil { err := fmt.Errorf("Error setting secure boot: %s", err) state.Put("error", err) @@ -80,11 +75,11 @@ func (s *StepCreateVM) Cleanup(state multistep.StateBag) { return } - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Unregistering and deleting virtual machine...") - err := hyperv.DeleteVirtualMachine(s.VMName) + err := driver.DeleteVirtualMachine(s.VMName) if err != nil { ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err)) } diff --git a/builder/hyperv/common/step_disable_vlan.go b/builder/hyperv/common/step_disable_vlan.go index 264affbdd..631c941d2 100644 --- a/builder/hyperv/common/step_disable_vlan.go +++ b/builder/hyperv/common/step_disable_vlan.go @@ -8,15 +8,13 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" ) type StepDisableVlan struct { } func (s *StepDisableVlan) Run(state multistep.StateBag) multistep.StepAction { - //config := state.Get("config").(*config) - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error disabling vlan: %s" @@ -25,7 +23,7 @@ func (s *StepDisableVlan) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Disabling vlan...") - err := hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) + err := driver.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) diff --git a/builder/hyperv/common/step_enable_integration_service.go b/builder/hyperv/common/step_enable_integration_service.go index 89259d4d8..05b148232 100644 --- a/builder/hyperv/common/step_enable_integration_service.go +++ b/builder/hyperv/common/step_enable_integration_service.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" ) type StepEnableIntegrationService struct { @@ -16,13 +15,14 @@ type StepEnableIntegrationService struct { } func (s *StepEnableIntegrationService) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Enabling Integration Service...") vmName := state.Get("vmName").(string) s.name = "Guest Service Interface" - err := hyperv.EnableVirtualMachineIntegrationService(vmName, s.name) + err := driver.EnableVirtualMachineIntegrationService(vmName, s.name) if err != nil { err := fmt.Errorf("Error enabling Integration Service: %s", err) diff --git a/builder/hyperv/common/step_export_vm.go b/builder/hyperv/common/step_export_vm.go index d226c25d1..2ee10e16c 100644 --- a/builder/hyperv/common/step_export_vm.go +++ b/builder/hyperv/common/step_export_vm.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" "io/ioutil" "path/filepath" ) @@ -24,6 +23,7 @@ type StepExportVm struct { } func (s *StepExportVm) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) var err error @@ -45,7 +45,7 @@ func (s *StepExportVm) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Exporting vm...") - err = hyperv.ExportVirtualMachine(vmName, vmExportPath) + err = driver.ExportVirtualMachine(vmName, vmExportPath) if err != nil { errorMsg = "Error exporting vm: %s" err := fmt.Errorf(errorMsg, err) @@ -61,7 +61,7 @@ func (s *StepExportVm) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Skipping disk compaction...") } else { ui.Say("Compacting disks...") - err = hyperv.CompactDisks(expPath, vhdDir) + err = driver.CompactDisks(expPath, vhdDir) if err != nil { errorMsg = "Error compacting disks: %s" err := fmt.Errorf(errorMsg, err) @@ -72,7 +72,7 @@ func (s *StepExportVm) Run(state multistep.StateBag) multistep.StepAction { } ui.Say("Coping to output dir...") - err = hyperv.CopyExportedVirtualMachine(expPath, outputPath, vhdDir, vmDir) + err = driver.CopyExportedVirtualMachine(expPath, outputPath, vhdDir, vmDir) if err != nil { errorMsg = "Error exporting vm: %s" err := fmt.Errorf(errorMsg, err) diff --git a/builder/hyperv/common/step_mount_dvddrive.go b/builder/hyperv/common/step_mount_dvddrive.go index 56856566f..a9129a378 100644 --- a/builder/hyperv/common/step_mount_dvddrive.go +++ b/builder/hyperv/common/step_mount_dvddrive.go @@ -9,7 +9,6 @@ import ( "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" powershell "github.com/mitchellh/packer/powershell" - "github.com/mitchellh/packer/powershell/hyperv" ) type StepMountDvdDrive struct { @@ -18,7 +17,7 @@ type StepMountDvdDrive struct { } func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error mounting dvd drive: %s" @@ -56,7 +55,7 @@ func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Mounting dvd drive...") - err = hyperv.MountDvdDrive(vmName, isoPath) + err = driver.MountDvdDrive(vmName, isoPath) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) @@ -74,6 +73,8 @@ func (s *StepMountDvdDrive) Cleanup(state multistep.StateBag) { return } + driver := state.Get("driver").(Driver) + errorMsg := "Error unmounting dvd drive: %s" vmName := state.Get("vmName").(string) @@ -81,7 +82,7 @@ func (s *StepMountDvdDrive) Cleanup(state multistep.StateBag) { ui.Say("Unmounting dvd drive...") - err := hyperv.UnmountDvdDrive(vmName) + err := driver.UnmountDvdDrive(vmName) if err != nil { ui.Error(fmt.Sprintf(errorMsg, err)) } diff --git a/builder/hyperv/common/step_mount_floppydrive.go b/builder/hyperv/common/step_mount_floppydrive.go index c30054141..78f9f0914 100644 --- a/builder/hyperv/common/step_mount_floppydrive.go +++ b/builder/hyperv/common/step_mount_floppydrive.go @@ -6,28 +6,24 @@ package common import ( "fmt" - "os" - "strings" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/powershell" "github.com/mitchellh/packer/powershell/hyperv" - "log" "io" "io/ioutil" + "log" + "os" "path/filepath" + "strings" ) - -const( +const ( FloppyFileName = "assets.vfd" ) - - - type StepSetUnattendedProductKey struct { - Files []string + Files []string ProductKey string } @@ -36,15 +32,15 @@ func (s *StepSetUnattendedProductKey) Run(state multistep.StateBag) multistep.St if s.ProductKey == "" { ui.Say("No product key specified...") - return multistep.ActionContinue + return multistep.ActionContinue } index := -1 for i, value := range s.Files { - if s.caseInsensitiveContains(value, "Autounattend.xml") { - index = i - break - } + if s.caseInsensitiveContains(value, "Autounattend.xml") { + index = i + break + } } ui.Say("Setting product key in Autounattend.xml...") @@ -59,10 +55,9 @@ func (s *StepSetUnattendedProductKey) Run(state multistep.StateBag) multistep.St return multistep.ActionContinue } - func (s *StepSetUnattendedProductKey) caseInsensitiveContains(str, substr string) bool { - str, substr = strings.ToUpper(str), strings.ToUpper(substr) - return strings.Contains(str, substr) + str, substr = strings.ToUpper(str), strings.ToUpper(substr) + return strings.Contains(str, substr) } func (s *StepSetUnattendedProductKey) copyAutounattend(path string) (string, error) { @@ -92,12 +87,9 @@ func (s *StepSetUnattendedProductKey) copyAutounattend(path string) (string, err return autounattend, nil } - func (s *StepSetUnattendedProductKey) Cleanup(state multistep.StateBag) { } - - type StepMountFloppydrive struct { floppyPath string } @@ -119,7 +111,7 @@ func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepActio if err != nil { state.Put("error", fmt.Errorf("Error preparing floppy: %s", err)) return multistep.ActionHalt - } + } ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) @@ -135,7 +127,8 @@ func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepActio // Track the path so that we can unregister it from Hyper-V later s.floppyPath = floppyPath - return multistep.ActionContinue} + return multistep.ActionContinue +} func (s *StepMountFloppydrive) Cleanup(state multistep.StateBag) { if s.floppyPath == "" { diff --git a/builder/hyperv/common/step_mount_integration_services.go b/builder/hyperv/common/step_mount_integration_services.go index 63e775a0d..317296916 100644 --- a/builder/hyperv/common/step_mount_integration_services.go +++ b/builder/hyperv/common/step_mount_integration_services.go @@ -8,9 +8,10 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - powershell "github.com/mitchellh/packer/powershell" + hyperv "github.com/mitchellh/packer/powershell/hyperv" "log" "os" + "strconv" ) type StepMountSecondaryDvdImages struct { @@ -88,67 +89,22 @@ func (s *StepMountSecondaryDvdImages) addAndMountIntegrationServicesSetupDisk(vm } func (s *StepMountSecondaryDvdImages) addAndMountDvdDisk(vmName string, isoPath string) (DvdControllerProperties, error) { - var properties DvdControllerProperties - var script powershell.ScriptBuilder - powershell := new(powershell.PowerShellCmd) - - controllerNumber := "0" - if s.Generation < 2 { - // get the controller number that the OS install disk is mounted on - // generation 1 requires dvd to be added to ide controller, generation 2 uses scsi for dvd drives - script.Reset() - script.WriteLine("param([string]$vmName)") - script.WriteLine("$dvdDrives = (Get-VMDvdDrive -VMName $vmName)") - script.WriteLine("$lastControllerNumber = $dvdDrives | Sort-Object ControllerNumber | Select-Object -Last 1 | %{$_.ControllerNumber}") - script.WriteLine("if (!$lastControllerNumber) {") - script.WriteLine(" $lastControllerNumber = 0") - script.WriteLine("} elseif (!$lastControllerNumber -or ($dvdDrives | ?{ $_.ControllerNumber -eq $lastControllerNumber} | measure).count -gt 1) {") - script.WriteLine(" $lastControllerNumber += 1") - script.WriteLine("}") - script.WriteLine("$lastControllerNumber") - controllerNumber, err := powershell.Output(script.String(), vmName) - if err != nil { - return properties, err - } - - if controllerNumber != "0" && controllerNumber != "1" { - //There are only 2 ide controllers, try to use the one the hdd is attached too - controllerNumber = "0" - } - } - script.Reset() - script.WriteLine("param([string]$vmName,[int]$controllerNumber)") - script.WriteLine("Add-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber") - err := powershell.Run(script.String(), vmName, controllerNumber) + controllerNumber, controllerLocation, err := hyperv.CreateDvdDrive(vmName, s.Generation) if err != nil { return properties, err } - // we could try to get the controller location and number in one call, but this way we do not - // need to parse the output - 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 properties, err - } + properties.ControllerNumber = strconv.FormatInt(int64(controllerNumber), 10) + properties.ControllerLocation = strconv.FormatInt(int64(controllerLocation), 10) - 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) + 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)) - properties.ControllerNumber = controllerNumber - properties.ControllerLocation = controllerLocation - return properties, nil } diff --git a/builder/hyperv/common/step_polling_installation.go b/builder/hyperv/common/step_polling_installation.go index c462f3da9..34577de54 100644 --- a/builder/hyperv/common/step_polling_installation.go +++ b/builder/hyperv/common/step_polling_installation.go @@ -5,15 +5,14 @@ package common import ( + "bytes" "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "time" -// "net" "log" "os/exec" "strings" - "bytes" + "time" ) const port string = "13000" @@ -29,36 +28,6 @@ func (s *StepPollingInstalation) Run(state multistep.StateBag) multistep.StepAct vmIp := state.Get("ip").(string) ui.Say("Start polling VM to check the installation is complete...") -/* - count := 30 - var minutes time.Duration = 1 - sleepMin := time.Minute * minutes - host := vmIp + ":" + port - - timeoutSec := time.Second * 15 - - for count > 0 { - ui.Say(fmt.Sprintf("Connecting vm (%s)...", host )) - conn, err := net.DialTimeout("tcp", host, timeoutSec) - if err == nil { - ui.Say("Done!") - conn.Close() - break; - } - - log.Println(err) - ui.Say(fmt.Sprintf("Waiting more %v minutes...", uint(minutes))) - time.Sleep(sleepMin) - count-- - } - - if count == 0 { - err := fmt.Errorf(errorMsg, "a signal from vm was not received in a given time period ") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } -*/ host := "'" + vmIp + "'," + port var blockBuffer bytes.Buffer @@ -73,7 +42,7 @@ func (s *StepPollingInstalation) Run(state multistep.StateBag) multistep.StepAct var res string for count > 0 { - log.Println(fmt.Sprintf("Connecting vm (%s)...", host )) + log.Println(fmt.Sprintf("Connecting vm (%s)...", host)) cmd := exec.Command("powershell", blockBuffer.String()) cmdOut, err := cmd.Output() if err != nil { @@ -88,8 +57,8 @@ func (s *StepPollingInstalation) Run(state multistep.StateBag) multistep.StepAct if res != "False" { ui.Say("Signal was received from the VM") // Sleep before starting provision - time.Sleep(time.Second*30) - break; + time.Sleep(time.Second * 30) + break } log.Println(fmt.Sprintf("Slipping for more %v seconds...", uint(duration))) diff --git a/builder/hyperv/common/step_reboot_vm.go b/builder/hyperv/common/step_reboot_vm.go index 3053a0855..7be0f3517 100644 --- a/builder/hyperv/common/step_reboot_vm.go +++ b/builder/hyperv/common/step_reboot_vm.go @@ -9,14 +9,13 @@ import ( "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" "time" - "github.com/mitchellh/packer/powershell/hyperv" ) type StepRebootVm struct { } func (s *StepRebootVm) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error rebooting vm: %s" @@ -24,7 +23,7 @@ func (s *StepRebootVm) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Rebooting vm...") - err := hyperv.RestartVirtualMachine(vmName) + err := driver.RestartVirtualMachine(vmName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) diff --git a/builder/hyperv/common/step_unmount_dvddrive.go b/builder/hyperv/common/step_unmount_dvddrive.go index 57ffb422d..c5a4f2f84 100644 --- a/builder/hyperv/common/step_unmount_dvddrive.go +++ b/builder/hyperv/common/step_unmount_dvddrive.go @@ -8,22 +8,20 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" ) - type StepUnmountDvdDrive struct { } func (s *StepUnmountDvdDrive) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) - + ui.Say("Unmounting dvd drive...") - err := hyperv.UnmountDvdDrive(vmName) + err := driver.UnmountDvdDrive(vmName) if err != nil { err := fmt.Errorf("Error unmounting dvd drive: %s", err) state.Put("error", err) diff --git a/builder/hyperv/common/step_unmount_floppydrive.go b/builder/hyperv/common/step_unmount_floppydrive.go index 87d1fd4a3..21ae1dcc1 100644 --- a/builder/hyperv/common/step_unmount_floppydrive.go +++ b/builder/hyperv/common/step_unmount_floppydrive.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/powershell/hyperv" ) type StepUnmountFloppyDrive struct { @@ -16,7 +15,7 @@ type StepUnmountFloppyDrive struct { } func (s *StepUnmountFloppyDrive) Run(state multistep.StateBag) multistep.StepAction { - //driver := state.Get("driver").(Driver) + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) if s.Generation > 1 { @@ -28,7 +27,7 @@ func (s *StepUnmountFloppyDrive) Run(state multistep.StateBag) multistep.StepAct ui.Say("Unmounting floppy drive (Run)...") - err := hyperv.UnmountFloppyDrive(vmName) + err := driver.UnmountFloppyDrive(vmName) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) diff --git a/builder/hyperv/common/step_unmount_integration_services.go b/builder/hyperv/common/step_unmount_integration_services.go index d79245782..d2719744b 100644 --- a/builder/hyperv/common/step_unmount_integration_services.go +++ b/builder/hyperv/common/step_unmount_integration_services.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - powershell "github.com/mitchellh/packer/powershell" "log" ) @@ -16,6 +15,7 @@ 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...") @@ -28,17 +28,7 @@ func (s *StepUnmountSecondaryDvdImages) Run(state multistep.StateBag) multistep. log.Println(fmt.Sprintf("Found DVD properties %d", len(dvdProperties))) for _, dvdProperty := range dvdProperties { - controllerNumber := dvdProperty.ControllerNumber - controllerLocation := dvdProperty.ControllerLocation - - var script powershell.ScriptBuilder - powershell := new(powershell.PowerShellCmd) - - script.WriteLine("param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation)") - script.WriteLine("$vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation") - script.WriteLine("if (!$vmDvdDrive) {throw 'unable to find dvd drive'}") - script.WriteLine("Remove-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation") - err := powershell.Run(script.String(), vmName, controllerNumber, controllerLocation) + err := driver.DeleteDvdDrive(vmName, dvdProperty.ControllerNumber, dvdProperty.ControllerLocation) if err != nil { state.Put("error", err) ui.Error(err.Error()) diff --git a/builder/hyperv/common/step_wait_for_install_to_complete.go b/builder/hyperv/common/step_wait_for_install_to_complete.go index c4fafbef0..46fc7e5cd 100644 --- a/builder/hyperv/common/step_wait_for_install_to_complete.go +++ b/builder/hyperv/common/step_wait_for_install_to_complete.go @@ -8,10 +8,7 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "strings" - "strconv" "time" - powershell "github.com/mitchellh/packer/powershell" ) const ( @@ -22,29 +19,25 @@ type StepWaitForPowerOff struct { } func (s *StepWaitForPowerOff) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) ui.Say("Waiting for vm to be powered down...") - var script powershell.ScriptBuilder - script.WriteLine("param([string]$vmName)") - script.WriteLine("(Get-VM -Name $vmName).State -eq [Microsoft.HyperV.PowerShell.VMState]::Off") - isOffScript := script.String() - for { - powershell := new(powershell.PowerShellCmd) - cmdOut, err := powershell.Output(isOffScript, vmName); + isOff, err := driver.IsOff(vmName) + if err != nil { - err := fmt.Errorf("Error checking VM's state: %s", err) + err := fmt.Errorf("Error checking if vm is off: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - if cmdOut == "True" { + if isOff { break } else { - time.Sleep(time.Second * SleepSeconds); + time.Sleep(time.Second * SleepSeconds) } } @@ -56,29 +49,24 @@ func (s *StepWaitForPowerOff) Cleanup(state multistep.StateBag) { type StepWaitForInstallToComplete struct { ExpectedRebootCount uint - ActionName string + ActionName string } func (s *StepWaitForInstallToComplete) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) - if(len(s.ActionName)>0){ - ui.Say(fmt.Sprintf("%v ! Waiting for VM to reboot %v times...",s.ActionName, s.ExpectedRebootCount)) + if len(s.ActionName) > 0 { + ui.Say(fmt.Sprintf("%v ! Waiting for VM to reboot %v times...", s.ActionName, s.ExpectedRebootCount)) } var rebootCount uint var lastUptime uint64 - var script powershell.ScriptBuilder - script.WriteLine("param([string]$vmName)") - script.WriteLine("(Get-VM -Name $vmName).Uptime.TotalSeconds") - - uptimeScript := script.String() - for rebootCount < s.ExpectedRebootCount { - powershell := new(powershell.PowerShellCmd) - cmdOut, err := powershell.Output(uptimeScript, vmName); + uptime, err := driver.Uptime(vmName) + if err != nil { err := fmt.Errorf("Error checking uptime: %s", err) state.Put("error", err) @@ -86,20 +74,18 @@ func (s *StepWaitForInstallToComplete) Run(state multistep.StateBag) multistep.S return multistep.ActionHalt } - uptime, _ := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 64) - if uint64(uptime) < lastUptime { + if uptime < lastUptime { rebootCount++ ui.Say(fmt.Sprintf("%v -> Detected reboot %v after %v seconds...", s.ActionName, rebootCount, lastUptime)) } lastUptime = uptime - if (rebootCount < s.ExpectedRebootCount) { - time.Sleep(time.Second * SleepSeconds); + if rebootCount < s.ExpectedRebootCount { + time.Sleep(time.Second * SleepSeconds) } } - return multistep.ActionContinue } diff --git a/powershell/hyperv/hyperv.go b/powershell/hyperv/hyperv.go index 3cf5d8a38..162b048fa 100644 --- a/powershell/hyperv/hyperv.go +++ b/powershell/hyperv/hyperv.go @@ -2,6 +2,7 @@ package hyperv import ( "github.com/mitchellh/packer/powershell" + "strconv" "strings" ) @@ -50,6 +51,73 @@ $ip return cmdOut, err } +func CreateDvdDrive(vmName string, generation uint) (uint, uint, error) { + var ps powershell.PowerShellCmd + var script string + var controllerNumber uint + controllerNumber = 0 + if generation < 2 { + // get the controller number that the OS install disk is mounted on + // generation 1 requires dvd to be added to ide controller, generation 2 uses scsi for dvd drives + script = ` +param([string]$vmName) +$dvdDrives = (Get-VMDvdDrive -VMName $vmName) +$lastControllerNumber = $dvdDrives | Sort-Object ControllerNumber | Select-Object -Last 1 | %{$_.ControllerNumber} +if (!$lastControllerNumber) { + $lastControllerNumber = 0 +} elseif (!$lastControllerNumber -or ($dvdDrives | ?{ $_.ControllerNumber -eq $lastControllerNumber} | measure).count -gt 1) { + $lastControllerNumber += 1 +} +$lastControllerNumber +` + cmdOut, err := ps.Output(script, vmName) + if err != nil { + return 0, 0, err + } + + controllerNumberTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64) + if err != nil { + return 0, 0, err + } + + controllerNumber = uint(controllerNumberTemp) + + if controllerNumber != 0 && controllerNumber != 1 { + //There are only 2 ide controllers, try to use the one the hdd is attached too + controllerNumber = 0 + } + } + + script = ` +param([string]$vmName,[int]$controllerNumber) +Add-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber +` + cmdOut, err := ps.Output(script, vmName) + if err != nil { + return controllerNumber, 0, err + } + + // we could try to get the controller location and number in one call, but this way we do not + // need to parse the output + script = ` +param([string]$vmName) +(Get-VMDvdDrive -VMName $vmName | Where-Object {$_.Path -eq $null}).ControllerLocation +` + + cmdOut, err = ps.Output(script, vmName) + if err != nil { + return controllerNumber, 0, err + } + + controllerLocationTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64) + if err != nil { + return controllerNumber, 0, err + } + + controllerLocation := uint(controllerLocationTemp) + return controllerNumber, controllerLocation, err +} + func MountDvdDrive(vmName string, path string) error { var script = ` @@ -62,6 +130,18 @@ Set-VMDvdDrive -VMName $vmName -Path $path return err } +func MountDvdDriveByLocation(vmName string, path string, controllerNumber uint, controllerLocation uint) error { + + var script = ` +param([string]$vmName,[string]$path,[string]$controllerNumber,[string]$controllerLocation) +Set-VMDvdDrive -VMName $vmName -Path $path -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation +` + + var ps powershell.PowerShellCmd + err := ps.Run(script, vmName, path, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) + return err +} + func UnmountDvdDrive(vmName string) error { var script = ` param([string]$vmName) @@ -73,6 +153,19 @@ Get-VMDvdDrive -VMName $vmName | Set-VMDvdDrive -Path $null return err } +func DeleteDvdDrive(vmName string, controllerNumber string, controllerLocation string) 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'} +Remove-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation +` + + var ps powershell.PowerShellCmd + err := ps.Run(script, vmName, controllerNumber, controllerLocation) + return err +} + func MountFloppyDrive(vmName string, path string) error { var script = ` param([string]$vmName, [string]$path) @@ -96,9 +189,9 @@ Set-VMFloppyDiskDrive -VMName $vmName -Path $null return err } -func CreateVirtualMachine(vmName string, path string, ram string, diskSize string, switchName string, generation string) error { +func CreateVirtualMachine(vmName string, path string, ram int64, diskSize int64, switchName string, generation uint) error { - if generation == "2" { + if generation == 2 { var script = ` param([string]$vmName, [string]$path, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [int]$generation) $vhdx = $vmName + '.vhdx' @@ -106,7 +199,7 @@ $vhdPath = Join-Path -Path $path -ChildPath $vhdx New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName -Generation $generation ` var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, path, ram, diskSize, switchName, generation) + err := ps.Run(script, vmName, path, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatInt(int64(generation), 10)) return err } else { var script = ` @@ -116,12 +209,12 @@ $vhdPath = Join-Path -Path $path -ChildPath $vhdx New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName ` var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, path, ram, diskSize, switchName) + err := ps.Run(script, vmName, path, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName) return err } } -func SetVirtualMachineCpu(vmName string, cpu string) error { +func SetVirtualMachineCpu(vmName string, cpu uint) error { var script = ` param([string]$vmName, [int]$cpu) @@ -129,7 +222,7 @@ Set-VMProcessor -VMName $vmName -Count $cpu ` var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, cpu) + err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10)) return err } @@ -425,10 +518,53 @@ $vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running var ps powershell.PowerShellCmd cmdOut, err := ps.Output(script, vmName) + + if err != nil { + return false, err + } + var isRunning = strings.TrimSpace(cmdOut) == "True" return isRunning, err } +func IsOff(vmName string) (bool, error) { + + var script = ` +param([string]$vmName) +$vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue +$vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off +` + + var ps powershell.PowerShellCmd + cmdOut, err := ps.Output(script, vmName) + + if err != nil { + return false, err + } + + var isRunning = strings.TrimSpace(cmdOut) == "True" + return isRunning, err +} + +func Uptime(vmName string) (uint64, error) { + + var script = ` +param([string]$vmName) +$vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue +$vm.Uptime.TotalSeconds +` + var ps powershell.PowerShellCmd + cmdOut, err := ps.Output(script, vmName) + + if err != nil { + return 0, err + } + + uptime, err := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 64) + + return uptime, err +} + func Mac(vmName string) (string, error) { var script = ` param([string]$vmName, [int]$adapterIndex)