diff --git a/plugins/providers/hyperv/action.rb b/plugins/providers/hyperv/action.rb index 532c5b353..c5da842b6 100644 --- a/plugins/providers/hyperv/action.rb +++ b/plugins/providers/hyperv/action.rb @@ -28,6 +28,28 @@ module VagrantPlugins end end + def self.action_destroy + Vagrant::Action::Builder.new.tap do |b| + b.use Call, IsCreated do |env1, b1| + if !env1[:result] + b2.use MessageNotCreated + next + end + + b2.use Call, DestroyConfirm do |env2, b3| + if !env2[:result] + b3.use MessageWillNotDestroy + next + end + + b3.use ConfigValidate + b3.use StopInstance + b3.use DeleteVM + end + end + end + end + def self.action_halt Vagrant::Action::Builder.new.tap do |b| b.use ConfigValidate diff --git a/plugins/providers/hyperv/action/read_state.rb b/plugins/providers/hyperv/action/read_state.rb index f0ad3456e..31f5f2371 100644 --- a/plugins/providers/hyperv/action/read_state.rb +++ b/plugins/providers/hyperv/action/read_state.rb @@ -11,15 +11,9 @@ module VagrantPlugins def call(env) if env[:machine].id - begin - options = { vm_id: env[:machine].id } - response = env[:machine].provider.driver.execute('get_vm_status.ps1', options) - env[:machine_state_id] = response["state"].downcase.to_sym - rescue Error::SubprocessError - env[:machine].id = nil - env[:ui].info "Could not find a machine, assuming it to be deleted or terminated." - env[:machine_state_id] = :not_created - end + options = { VmId: env[:machine].id } + response = env[:machine].provider.driver.execute('get_vm_status.ps1', options) + env[:machine_state_id] = response["state"].downcase.to_sym else env[:machine_state_id] = :not_created end diff --git a/plugins/providers/hyperv/action/stop_instance.rb b/plugins/providers/hyperv/action/stop_instance.rb index 7dc2244ec..d6693cdc2 100644 --- a/plugins/providers/hyperv/action/stop_instance.rb +++ b/plugins/providers/hyperv/action/stop_instance.rb @@ -1,24 +1,18 @@ -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Open Technologies, Inc. -# All Rights Reserved. Licensed under the MIT License. -#-------------------------------------------------------------------------- - -require "log4r" module VagrantPlugins module HyperV module Action - class StopInstance - def initialize(app, env) - @app = app - end - - def call(env) - env[:ui].info('Stopping the Machine') - options = { vm_id: env[:machine].id } - response = env[:machine].provider.driver.execute('stop_vm.ps1', options) - @app.call(env) - end + class StopInstance + def initialize(app, env) + @app = app end + + def call(env) + env[:ui].info('Stopping the Machine') + options = { vm_id: env[:machine].id } + env[:machine].provider.driver.execute('stop_vm.ps1', options) + @app.call(env) + end + end end end end diff --git a/plugins/providers/hyperv/provider.rb b/plugins/providers/hyperv/provider.rb index d7d985f80..818227735 100644 --- a/plugins/providers/hyperv/provider.rb +++ b/plugins/providers/hyperv/provider.rb @@ -38,11 +38,16 @@ module VagrantPlugins end def state - # Run a custom action we define called "read_state" which does - # what it says. It puts the state in the `:machine_state_id` - # key in the environment. - env = @machine.action("read_state") - state_id = env[:machine_state_id] + state_id = nil + state_id = :not_created if !@machine.id + + if !state_id + # Run a custom action we define called "read_state" which does + # what it says. It puts the state in the `:machine_state_id` + # key in the environment. + env = @machine.action(:read_state) + state_id = env[:machine_state_id] + end # Get the short and long description short = "Machine's current state is #{state_id}" diff --git a/plugins/providers/hyperv/scripts/get_vm_status.ps1 b/plugins/providers/hyperv/scripts/get_vm_status.ps1 index d7bfcc0ba..739560190 100644 --- a/plugins/providers/hyperv/scripts/get_vm_status.ps1 +++ b/plugins/providers/hyperv/scripts/get_vm_status.ps1 @@ -1,30 +1,25 @@ -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Open Technologies, Inc. -# All Rights Reserved. Licensed under the MIT License. -#-------------------------------------------------------------------------- - -param ( - [string]$vm_id = $(throw "-vm_id is required.") - ) +Param( + [Parameter(Mandatory=$true)] + [string]$VmId +) # Include the following modules -$presentDir = Split-Path -parent $PSCommandPath -$modules = @() -$modules += $presentDir + "\utils\write_messages.ps1" -forEach ($module in $modules) { . $module } +$Dir = Split-Path $script:MyInvocation.MyCommand.Path +. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1")) +# Get the VM with the given name try { - $vm = Get-VM -Id $vm_id -ErrorAction "stop" - $state = $vm.state - $status = $vm.status - $resultHash = @{ - state = "$state" - status = "$status" - } - $result = ConvertTo-Json $resultHash - Write-Output-Message $result + $VM = Get-VM -Id $VmId -ErrorAction "Stop" + $State = $VM.state + $Status = $VM.status +} catch [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException] { + $State = "not_created" + $Status = $State +} +$resultHash = @{ + state = "$State" + status = "$Status" } -catch { - Write-Error-Message $_ -} +$result = ConvertTo-Json $resultHash +Write-Output-Message $result diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index 42de437ee..a24351b6f 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -1,144 +1,138 @@ -param ( +Param( [string]$vm_xml_config = $(throw "-vm_xml_config is required."), [string]$vhdx_path = $(throw "-vhdx_path is required.") - ) +) + +$ErrorActionPreference = "Stop" # Include the following modules -$presentDir = Split-Path -parent $PSCommandPath -$modules = @() -$modules += $presentDir + "\utils\write_messages.ps1" -forEach ($module in $modules) { . $module } +$Dir = Split-Path $script:MyInvocation.MyCommand.Path +. [System.IO.Path]::Combine($Dir, "utils\write_messages.ps1") -try { - [xml]$vmconfig = Get-Content -Path $vm_xml_config +[xml]$vmconfig = Get-Content -Path $vm_xml_config - $vm_name = $vmconfig.configuration.properties.name.'#text' - $processors = $vmconfig.configuration.settings.processors.count.'#text' +$vm_name = $vmconfig.configuration.properties.name.'#text' +$processors = $vmconfig.configuration.settings.processors.count.'#text' - function Get_unique_name($name) { +function GetUniqueName($name) { Get-VM | ForEach-Object -Process { - if ($name -eq $_.Name) { - $name = $name + "_1" - } + if ($name -eq $_.Name) { + $name = $name + "_1" + } } return $name - } +} - do { +do { $name = $vm_name - $vm_name = Get_unique_name $name - } while ($vm_name -ne $name) + $vm_name = GetUniqueName $name +} while ($vm_name -ne $name) - $memory = (Select-Xml -xml $vmconfig -XPath "//memory").node.Bank - if ($memory.dynamic_memory_enabled."#text" -eq "True") { - $dynamicmemory = $True - } - else { - $dynamicmemory = $False - } +$memory = (Select-Xml -xml $vmconfig -XPath "//memory").node.Bank +if ($memory.dynamic_memory_enabled."#text" -eq "True") { + $dynamicmemory = $True +} +else { + $dynamicmemory = $False +} - # Memory values need to be in bytes - $MemoryMaximumBytes = ($memory.limit."#text" -as [int]) * 1MB - $MemoryStartupBytes = ($memory.size."#text" -as [int]) * 1MB - $MemoryMinimumBytes = ($memory.reservation."#text" -as [int]) * 1MB +# Memory values need to be in bytes +$MemoryMaximumBytes = ($memory.limit."#text" -as [int]) * 1MB +$MemoryStartupBytes = ($memory.size."#text" -as [int]) * 1MB +$MemoryMinimumBytes = ($memory.reservation."#text" -as [int]) * 1MB - # Get the name of the virtual switch - $switchname = (Select-Xml -xml $vmconfig -XPath "//AltSwitchName").node."#text" +# Get the name of the virtual switch +$switchname = (Select-Xml -xml $vmconfig -XPath "//AltSwitchName").node."#text" - # Determine boot device - Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") { - "Floppy" { $bootdevice = "floppy" } - "HardDrive" { $bootdevice = "IDE" } - "Optical" { $bootdevice = "CD" } - "Network" { $bootdevice = "LegacyNetworkAdapter" } - "Default" { $bootdevice = "IDE" } - } #switch +# Determine boot device +Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") { + "Floppy" { $bootdevice = "floppy" } + "HardDrive" { $bootdevice = "IDE" } + "Optical" { $bootdevice = "CD" } + "Network" { $bootdevice = "LegacyNetworkAdapter" } + "Default" { $bootdevice = "IDE" } +} #switch - # Define a hash map of parameter values for New-VM +# Define a hash map of parameter values for New-VM - $vm_params = @{ - Name = $vm_name - NoVHD = $True - MemoryStartupBytes = $MemoryStartupBytes - SwitchName = $switchname - BootDevice = $bootdevice - ErrorAction = "Stop" - } +$vm_params = @{ + Name = $vm_name + NoVHD = $True + MemoryStartupBytes = $MemoryStartupBytes + SwitchName = $switchname + BootDevice = $bootdevice + ErrorAction = "Stop" +} - # Create the VM using the values in the hash map +# Create the VM using the values in the hash map - $vm = New-VM @vm_params +$vm = New-VM @vm_params - $notes = (Select-Xml -xml $vmconfig -XPath "//notes").node.'#text' +$notes = (Select-Xml -xml $vmconfig -XPath "//notes").node.'#text' - # Set-VM parameters to configure new VM with old values +# Set-VM parameters to configure new VM with old values - $more_vm_params = @{ - ProcessorCount = $processors - MemoryStartupBytes = $MemoryStartupBytes - } +$more_vm_params = @{ + ProcessorCount = $processors + MemoryStartupBytes = $MemoryStartupBytes +} - If ($dynamicmemory) { - $more_vm_params.Add("DynamicMemory",$True) - $more_vm_params.Add("MemoryMinimumBytes",$MemoryMinimumBytes) - $more_vm_params.Add("MemoryMaximumBytes", $MemoryMaximumBytes) - } - else { +If ($dynamicmemory) { + $more_vm_params.Add("DynamicMemory",$True) + $more_vm_params.Add("MemoryMinimumBytes",$MemoryMinimumBytes) + $more_vm_params.Add("MemoryMaximumBytes", $MemoryMaximumBytes) +} +else { $more_vm_params.Add("StaticMemory",$True) - } +} - if ($notes) { +if ($notes) { $more_vm_params.Add("Notes",$notes) - } +} - # Set the values on the VM - $vm | Set-VM @more_vm_params -Passthru +# Set the values on the VM +$vm | Set-VM @more_vm_params -Passthru - # Add drives to the virtual machine - $controllers = Select-Xml -xml $vmconfig -xpath "//*[starts-with(name(.),'controller')]" - # A regular expression pattern to pull the number from controllers - [regex]$rx="\d" +# Add drives to the virtual machine +$controllers = Select-Xml -xml $vmconfig -xpath "//*[starts-with(name(.),'controller')]" +# A regular expression pattern to pull the number from controllers +[regex]$rx="\d" - foreach ($controller in $controllers) { +foreach ($controller in $controllers) { $node = $controller.Node - # Check for SCSI - if ($node.ParentNode.ChannelInstanceGuid) { - $ControllerType = "SCSI" - } - else { - $ControllerType = "IDE" - } +# Check for SCSI + if ($node.ParentNode.ChannelInstanceGuid) { + $ControllerType = "SCSI" + } + else { + $ControllerType = "IDE" + } $drives = $node.ChildNodes | where {$_.pathname."#text"} foreach ($drive in $drives) { - #if drive type is ISO then set DVD Drive accordingly +#if drive type is ISO then set DVD Drive accordingly $driveType = $drive.type."#text" - $addDriveParam = @{ - ControllerNumber = $rx.Match($controller.node.name).value - Path = $vhdx_path - } + $addDriveParam = @{ + ControllerNumber = $rx.Match($controller.node.name).value + Path = $vhdx_path + } if ($drive.pool_id."#text") { - $ResourcePoolName = $drive.pool_id."#text" - $addDriveParam.Add("ResourcePoolname",$ResourcePoolName) + $ResourcePoolName = $drive.pool_id."#text" + $addDriveParam.Add("ResourcePoolname",$ResourcePoolName) } if ($drivetype -eq 'VHD') { $addDriveParam.add("ControllerType",$ControllerType) - $vm | Add-VMHardDiskDrive @AddDriveparam + $vm | Add-VMHardDiskDrive @AddDriveparam } } - } +} - $vm_id = (Get-VM $vm_name).id.guid - $resultHash = @{ +$vm_id = (Get-VM $vm_name).id.guid +$resultHash = @{ name = $vm_name - id = $vm_id - } - $result = ConvertTo-Json $resultHash - Write-Output-Message $result -} -catch { - Write-Error-Message $_ - return + id = $vm_id } +$result = ConvertTo-Json $resultHash +Write-Output-Message $result diff --git a/plugins/providers/hyperv/scripts/stop_vm.ps1 b/plugins/providers/hyperv/scripts/stop_vm.ps1 index 759930b68..4ac442ab1 100644 --- a/plugins/providers/hyperv/scripts/stop_vm.ps1 +++ b/plugins/providers/hyperv/scripts/stop_vm.ps1 @@ -1,8 +1,3 @@ -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Open Technologies, Inc. -# All Rights Reserved. Licensed under the MIT License. -#-------------------------------------------------------------------------- - param ( [string]$vm_id = $(throw "-vm_id is required.") ) diff --git a/test/unit/plugins/providers/hyperv/provider_test.rb b/test/unit/plugins/providers/hyperv/provider_test.rb index d431a2d2f..cbe77dcb0 100644 --- a/test/unit/plugins/providers/hyperv/provider_test.rb +++ b/test/unit/plugins/providers/hyperv/provider_test.rb @@ -45,4 +45,20 @@ describe VagrantPlugins::HyperV::Provider do expect(subject.driver).to be_kind_of(VagrantPlugins::HyperV::Driver) end end + + describe "#state" do + it "returns not_created if no ID" do + machine.stub(id: nil) + + expect(subject.state.id).to eq(:not_created) + end + + it "calls an action to determine the ID" do + machine.stub(id: "foo") + machine.should_receive(:action).with(:read_state). + and_return({ machine_state_id: :bar }) + + expect(subject.state.id).to eq(:bar) + end + end end