providers/hyperv: wait for IP on boot

This commit is contained in:
Mitchell Hashimoto 2014-02-26 11:12:24 -08:00
parent 64abd95c6f
commit 5d19285774
11 changed files with 111 additions and 90 deletions

View File

@ -66,6 +66,7 @@ module VagrantPlugins
def self.action_start
Vagrant::Action::Builder.new.tap do |b|
b.use StartInstance
b.use WaitForIPAddress
#b.use ShareFolders
#b.use SyncFolders
end
@ -139,9 +140,10 @@ module VagrantPlugins
autoload :MessageAlreadyCreated, action_root.join('message_already_created')
autoload :MessageNotRunning, action_root.join('message_not_running')
autoload :SyncFolders, action_root.join('sync_folders')
autoload :WaitForState, action_root.join('wait_for_state')
autoload :ReadGuestIP, action_root.join('read_guest_ip')
autoload :ShareFolders, action_root.join('share_folders')
autoload :WaitForIPAddress, action_root.join("wait_for_ip_address")
autoload :WaitForState, action_root.join('wait_for_state')
end
end
end

View File

@ -44,10 +44,10 @@ module VagrantPlugins
vhdx_path: vhdx_path.to_s.gsub("/", "\\")
}
env[:ui].info "Importing a Hyper-V instance"
env[:ui].output("Importing a Hyper-V instance")
server = env[:machine].provider.driver.execute(
'import_vm.ps1', options)
env[:ui].info "Successfully imported a VM with name: #{server['name']}"
env[:ui].detail("Successfully imported a VM with name: #{server['name']}")
env[:machine].id = server["id"]
@app.call(env)
end

View File

@ -1,7 +1,3 @@
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the MIT License.
#--------------------------------------------------------------------------
require "log4r"
require "timeout"
@ -23,13 +19,14 @@ module VagrantPlugins
def read_host_ip(env)
return nil if env[:machine].id.nil?
# Get Network details from WMI Provider
# Wait for 120 sec By then the machine should be ready
host_ip = nil
begin
Timeout.timeout(120) do
begin
options = { vm_id: env[:machine].id }
options = { VmId: env[:machine].id }
network_info = env[:machine].provider.driver.execute('get_network_config.ps1', options)
host_ip = network_info["ip"]
sleep 10 if host_ip.empty?

View File

@ -7,15 +7,10 @@ module VagrantPlugins
end
def call(env)
env[:ui].info('Starting the Machine')
env[:ui].output('Starting the machine...')
options = { vm_id: env[:machine].id }
begin
response = env[:machine].provider.driver.execute('start_vm.ps1', options)
env[:ui].info "Machine #{response["name"]} started"
rescue Error::SubprocessError => e
env[:ui].info e.message
return
end
response = env[:machine].provider.driver.execute('start_vm.ps1', options)
@app.call(env)
end
end

View File

@ -0,0 +1,45 @@
require "timeout"
module VagrantPlugins
module HyperV
module Action
class WaitForIPAddress
def initialize(app, env)
@app = app
end
def call(env)
timeout = env[:machine].provider_config.ip_address_timeout
env[:ui].output("Waiting for the machine to report its IP address...")
env[:ui].detail("Timeout: #{timeout} seconds")
guest_ip = nil
Timeout.timeout(timeout) do
while true
# If a ctrl-c came through, break out
return if env[:interrupted]
# Try to get the IP
network_info = env[:machine].provider.driver.execute(
"get_network_config.ps1", VmId: env[:machine].id)
guest_ip = network_info["ip"]
break if guest_ip && guest_ip != ""
sleep 1
end
end
# If we were interrupted then return now
return if env[:interrupted]
env[:ui].detail("IP: #{guest_ip}")
@app.call(env)
rescue Timeout::Error
raise Errors::IPAddrTimeout
end
end
end
end
end

View File

@ -1,34 +1,32 @@
require "vagrant"
require_relative "guest_config/config"
require_relative "host_share/config"
module VagrantPlugins
module HyperV
class Config < Vagrant.plugin("2", :config)
# If set to `true`, then VirtualBox will be launched with a GUI.
# The timeout to wait for an IP address when booting the machine,
# in seconds.
#
# @return [Boolean]
attr_accessor :gui
# @return [Integer]
attr_accessor :ip_address_timeout
attr_reader :host_share, :guest
attr_reader :host_share
def initialize
@ip_address_timeout = UNSET_VALUE
@host_share = HostShare::Config.new
end
def host_config(&block)
block.call(@host_share)
end
def guest_config(&block)
block.call(@guest)
end
def finalize!
@gui = nil if @gui == UNSET_VALUE
if @ip_address_timeout == UNSET_VALUE
@ip_address_timeout = 120
end
end
def initialize(region_specific=false)
@gui = UNSET_VALUE
@host_share = HostShare::Config.new
@guest = GuestConfig::Config.new
end
def validate(machine)
errors = _detected_errors
@ -36,10 +34,6 @@ module VagrantPlugins
unless host_share.valid_config?
errors << host_share.errors.flatten.join(" ")
end
unless guest.valid_config?
errors << guest.errors.flatten.join(" ")
end
=end
{ "HyperV" => errors }
end

View File

@ -14,6 +14,10 @@ module VagrantPlugins
error_key(:box_invalid)
end
class IPAddrTimeout < HyperVError
error_key(:ip_addr_timeout)
end
class PowerShellError < HyperVError
error_key(:powershell_error)
end

View File

@ -1,33 +0,0 @@
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the MIT License.
#--------------------------------------------------------------------------
module VagrantPlugins
module HyperV
module GuestConfig
class Config < Vagrant.plugin("2", :config)
attr_accessor :username, :password
def errors
@errors
end
def validate
@errors = []
if username.nil?
@errors << "Please configure a Guest VM's username"
end
if password.nil?
@errors << "Please configure a Guest VM's password"
end
end
def valid_config?
validate
errors.empty?
end
end
end
end
end

View File

@ -1,28 +1,17 @@
#-------------------------------------------------------------------------
# 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"))
try {
$vm = Get-VM -Id $vm_id -ErrorAction "stop"
$network = Get-VMNetworkAdapter -VM $vm
$ip_address = $network.IpAddresses[0]
$resultHash = @{
$vm = Get-VM -Id $VmId -ErrorAction "Stop"
$network = Get-VMNetworkAdapter -VM $vm
$ip_address = $network.IpAddresses[0]
$resultHash = @{
ip = "$ip_address"
}
$result = ConvertTo-Json $resultHash
Write-Output-Message $result
}
catch {
Write-Error-Message "Failed to obtain network info of VM $_"
}
$result = ConvertTo-Json $resultHash
Write-Output-Message $result

View File

@ -20,6 +20,16 @@ en:
these directories or does not contain the files expected. Verify
that you added the correct box. If this problem persists,
please contact the creator of the box for assistance.
ip_addr_timeout: |-
Hyper-V failed to determine your machine's IP address within the
configured timeout. Please verify the machine properly booted and
the network works. To do this, open the Hyper-V manager, find your
virtual machine, and connect to it.
The most common cause for this error is that the running virtual
machine doesn't have the latest Hyper-V integration drivers. Please
research for your operating system how to install these in order
for the VM to properly communicate its IP address to Hyper-V.
powershell_error: |-
An error occurred while executing a PowerShell script. This error
is shown below. Please read the error message and see if this is

View File

@ -0,0 +1,18 @@
require_relative "../../../base"
require Vagrant.source_root.join("plugins/providers/hyperv/config")
describe VagrantPlugins::HyperV::Config do
describe "#ip_address_timeout" do
it "can be set" do
subject.ip_address_timeout = 180
subject.finalize!
expect(subject.ip_address_timeout).to eq(180)
end
it "defaults to a number" do
subject.finalize!
expect(subject.ip_address_timeout).to eq(120)
end
end
end