From d4bd05883dcbbd62f07a08a4780e78bb7407cc0c Mon Sep 17 00:00:00 2001 From: Shawn Neal Date: Mon, 9 Jun 2014 22:46:03 -0700 Subject: [PATCH] Fixed issue 3987 Reboot the Windows guest after renaming the computer so changes take affect immediately before attempting to provision the box. - Changed rename from wmic to netdom since netdom seems to work correctly in Windows 2008R2 and newer OSs. - Fixed Windows guest error translations, the wrong namespace was specified in the yaml file. --- .../guests/windows/cap/change_host_name.rb | 21 +++++++++++++++---- plugins/guests/windows/errors.rb | 4 ++++ templates/locales/guest_windows.yml | 9 +++++++- .../windows/cap/change_host_name_test.rb | 16 ++++++++++---- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/plugins/guests/windows/cap/change_host_name.rb b/plugins/guests/windows/cap/change_host_name.rb index 6b1af2b8a..9902c8565 100644 --- a/plugins/guests/windows/cap/change_host_name.rb +++ b/plugins/guests/windows/cap/change_host_name.rb @@ -2,11 +2,24 @@ module VagrantPlugins module GuestWindows module Cap module ChangeHostName + def self.change_host_name(machine, name) - # On windows, renaming a computer seems to require a reboot - machine.communicate.execute( - "wmic computersystem where name=\"%COMPUTERNAME%\" call rename name=\"#{name}\"", - shell: :cmd) + change_host_name_and_wait(machine, name, machine.config.vm.graceful_halt_timeout) + end + + def self.change_host_name_and_wait(machine, name, sleep_timeout) + # If the configured name matches the current name, then bail + return if machine.communicate.test("if ($env:ComputerName -eq '#{name}') { exit 0 } exit 1") + + # Rename and then reboot in one step + exit_code = machine.communicate.execute( + "netdom renamecomputer \"$Env:COMPUTERNAME\" /NewName:#{name} /Force /Reboot:0", + error_check: false) + + raise Errors::RenameComputerFailed if exit_code != 0 + + # Don't continue until the machine has shutdown and rebooted + sleep(sleep_timeout) end end end diff --git a/plugins/guests/windows/errors.rb b/plugins/guests/windows/errors.rb index ca1e3fb36..d5be14ce6 100644 --- a/plugins/guests/windows/errors.rb +++ b/plugins/guests/windows/errors.rb @@ -13,6 +13,10 @@ module VagrantPlugins class NetworkWinRMRequired < WindowsError error_key(:network_winrm_required) end + + class RenameComputerFailed < WindowsError + error_key(:rename_computer_failed) + end end end end diff --git a/templates/locales/guest_windows.yml b/templates/locales/guest_windows.yml index 4f247930d..a648f5a09 100644 --- a/templates/locales/guest_windows.yml +++ b/templates/locales/guest_windows.yml @@ -1,5 +1,5 @@ en: - vagrant_winrm: + vagrant_windows: errors: cant_read_mac_addresses: |- The provider being used to start Windows ('%{provider}') @@ -18,3 +18,10 @@ en: Note that the Windows guest must be configured to accept insecure WinRM connections, and the WinRM port must be forwarded properly from the guest machine. This is not always done by default. + rename_computer_failed: |- + Renaming the Windows guest failed. Most often this is because you've + specified a FQDN instead of just a host name. + + Ensure the new guest name is properly formatted. Standard names may + contain letters (a-z, A-Z), numbers (0-9), and hypens (-), but no + spaces or periods (.). The name may not consist entirely of digits. diff --git a/test/unit/plugins/guests/windows/cap/change_host_name_test.rb b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb index bf17d7854..b90df3d3f 100644 --- a/test/unit/plugins/guests/windows/cap/change_host_name_test.rb +++ b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb @@ -8,7 +8,7 @@ describe "VagrantPlugins::GuestWindows::Cap::ChangeHostName" do end let(:machine) { double("machine") } let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) } - let(:old_hostname) {'oldhostname.olddomain.tld' } + let(:old_hostname) { 'oldhostname' } before do allow(machine).to receive(:communicate).and_return(communicator) @@ -19,11 +19,19 @@ describe "VagrantPlugins::GuestWindows::Cap::ChangeHostName" do end describe ".change_host_name" do - it "changes the hostname" do - communicator.expect_command('wmic computersystem where name="%COMPUTERNAME%" call rename name="newhostname.newdomain.tld"') - described_class.change_host_name(machine, 'newhostname.newdomain.tld') + communicator.stub_command('if (!($env:ComputerName -eq \'newhostname\')) { exit 0 } exit 1', exit_code: 0) + communicator.stub_command('netdom renamecomputer "$Env:COMPUTERNAME" /NewName:newhostname /Force /Reboot:0', + exit_code: 0) + described_class.change_host_name_and_wait(machine, 'newhostname', 0) end + it "raises RenameComputerFailed when exit code is non-zero" do + communicator.stub_command('if (!($env:ComputerName -eq \'newhostname\')) { exit 0 } exit 1', exit_code: 0) + communicator.stub_command('netdom renamecomputer "$Env:COMPUTERNAME" /NewName:newhostname /Force /Reboot:0', + exit_code: 123) + expect { described_class.change_host_name_and_wait(machine, 'newhostname', 0) }. + to raise_error(VagrantPlugins::GuestWindows::Errors::RenameComputerFailed) + end end end