Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly wait for reboot process to start #12302

Merged
merged 1 commit into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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