Skip to content

Commit

Permalink
Merge pull request #12302 from chrisroberts/linux-reboot
Browse files Browse the repository at this point in the history
Properly wait for reboot process to start
  • Loading branch information
chrisroberts authored Apr 14, 2021
2 parents 424d085 + a088fbb commit 7271e02
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
24 changes: 21 additions & 3 deletions plugins/guests/linux/cap/reboot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ class Reboot

def self.reboot(machine)
@logger = Log4r::Logger.new("vagrant::linux::reboot")
reboot_script = "ps -q 1 -o comm=,start= > /tmp/.vagrant-reboot"

if systemd?(machine.communicate)
reboot_script = "systemctl reboot"
reboot_cmd = "systemctl reboot"
else
reboot_script = "reboot"
reboot_cmd = "reboot"
end

comm = machine.communicate
reboot_script += "; #{reboot_cmd}"

@logger.debug("Issuing reboot command for guest")
comm.sudo(reboot_script)
Expand All @@ -43,8 +46,23 @@ def self.reboot(machine)
end

def self.wait_for_reboot(machine)
while !machine.guest.ready?
caught = false
begin
check_script = 'grep "$(ps -q 1 -o comm=,start=)" /tmp/.vagrant-reboot'
while machine.guest.ready? && machine.communicate.execute(check_script, error_check: false) == 0
sleep 10
end
rescue
# The check script execution may result in an exception
# getting raised depending on the state of the communicator
# when executing. We'll allow for it to happen once, and then
# raise if we get an exception again
if caught
raise
end
caught = true
sleep 10
retry
end
end
end
Expand Down
60 changes: 59 additions & 1 deletion test/unit/plugins/guests/linux/cap/reboot_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
VagrantPlugins::GuestLinux::Plugin.components.guest_capabilities[:linux].get(:wait_for_reboot)
end

let(:machine) { double("machine") }
let(:machine) { double("machine", guest: guest) }
let(:guest) { double("guest") }
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:ui) { double("ui") }
Expand Down Expand Up @@ -106,4 +106,62 @@
end
end
end

describe ".wait_for_reboot" do
before do
allow(machine).to receive(:communicate).and_return(communicator)
allow(communicator).to receive(:execute).and_return(0)
allow(guest).to receive(:ready?).and_return(false)
end

context "when guest is ready" do
before { expect(guest).to receive(:ready?).and_return(true) }

it "should sleep" do
expect(described_class).to receive(:sleep).with(10)
described_class.wait_for_reboot(machine)
end

context "when check script fails" do
before { expect(communicator).to receive(:execute).with(/grep/, any_args).and_return(1) }

it "should not sleep" do
expect(described_class).not_to receive(:sleep)
described_class.wait_for_reboot(machine)
end
end

context "when communicator raises an error" do
let(:error) { Class.new(StandardError) }

before do
expect(communicator).to receive(:execute).with(/grep/, any_args).and_raise(error)
expect(guest).to receive(:ready?).and_return(true)
end

it "should sleep once for exception and once for the guest being ready" do
expect(described_class).to receive(:sleep).with(10).twice
described_class.wait_for_reboot(machine)
end

context "when communicator raises error more than once" do
before { expect(communicator).to receive(:execute).with(/grep/, any_args).and_raise(error) }

it "should sleep once and raise error" do
expect(described_class).to receive(:sleep).with(10)
expect { described_class.wait_for_reboot(machine) }.to raise_error(error)
end
end
end
end

context "when guest is not ready" do
before { expect(guest).to receive(:ready?).and_return(false) }

it "should not sleep" do
expect(described_class).not_to receive(:sleep)
described_class.wait_for_reboot(machine)
end
end
end
end

0 comments on commit 7271e02

Please sign in to comment.