Support force halt behaviour (#1270)

Vagrant subcommand halt accepts an argument -f that should result in
VMs being halted immediately instead of attempting a graceful shutdown.

Add support for this option and include tests to cover the rest of the
halt behaviour.

Fixes: #1265
This commit is contained in:
Darragh Bailey
2021-05-08 17:14:13 +01:00
committed by GitHub
parent 4830182ef8
commit fbf32889d7
2 changed files with 98 additions and 0 deletions

View File

@@ -17,6 +17,11 @@ module VagrantPlugins
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s) domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain.nil? raise Errors::NoDomainError if domain.nil?
if env[:force_halt]
domain.poweroff
return @app.call(env)
end
begin begin
Timeout.timeout(timeout) do Timeout.timeout(timeout) do
begin begin
@@ -39,6 +44,9 @@ module VagrantPlugins
rescue Timeout::Error rescue Timeout::Error
@logger.info('VM is still running. Calling force poweroff.') @logger.info('VM is still running. Calling force poweroff.')
domain.poweroff domain.poweroff
rescue
@logger.error('Failed to shutdown cleanly. Calling force poweroff.')
domain.poweroff
end end
@app.call(env) @app.call(env)

View File

@@ -0,0 +1,90 @@
require 'spec_helper'
require 'support/sharedcontext'
require 'support/libvirt_context'
require 'vagrant-libvirt/action/destroy_domain'
describe VagrantPlugins::ProviderLibvirt::Action::HaltDomain do
subject { described_class.new(app, env) }
include_context 'unit'
include_context 'libvirt'
let(:libvirt_domain) { double('libvirt_domain') }
let(:servers) { double('servers') }
describe '#call' do
before do
allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
.to receive(:connection).and_return(connection)
allow(connection).to receive(:servers).and_return(servers)
allow(servers).to receive(:get).and_return(domain)
# always see this at the start of #call
expect(ui).to receive(:info).with('Halting domain...')
end
context 'with graceful timeout' do
it "should shutdown" do
expect(guest).to receive(:capability).with(:halt).and_return(true)
expect(domain).to receive(:wait_for).with(60).and_return(false)
expect(subject.call(env)).to be_nil
end
context 'when halt fails' do
before do
expect(logger).to receive(:info).with('Trying Libvirt graceful shutdown.')
expect(guest).to receive(:capability).with(:halt).and_raise(IOError)
expect(domain).to receive(:state).and_return('running')
end
it "should call shutdown" do
expect(domain).to receive(:shutdown)
expect(domain).to receive(:wait_for).with(60).and_return(false)
expect(subject.call(env)).to be_nil
end
context 'when shutdown fails' do
it "should call power off" do
expect(logger).to receive(:error).with('Failed to shutdown cleanly. Calling force poweroff.')
expect(domain).to receive(:shutdown).and_raise(IOError)
expect(domain).to receive(:poweroff)
expect(subject.call(env)).to be_nil
end
end
context 'when shutdown exceeds the timeout' do
it "should call poweroff" do
expect(logger).to receive(:info).with('VM is still running. Calling force poweroff.')
expect(domain).to receive(:shutdown).and_raise(Timeout::Error)
expect(domain).to receive(:poweroff)
expect(subject.call(env)).to be_nil
end
end
end
context 'when halt exceeds the timeout' do
before do
expect(logger).to_not receive(:info).with('Trying Libvirt graceful shutdown.')
expect(guest).to receive(:capability).with(:halt).and_raise(Timeout::Error)
end
it "should call poweroff" do
expect(logger).to receive(:info).with('VM is still running. Calling force poweroff.')
expect(domain).to receive(:poweroff)
expect(subject.call(env)).to be_nil
end
end
end
context 'with force halt enabled' do
before do
allow(env).to receive(:[]).and_call_original
expect(env).to receive(:[]).with(:force_halt).and_return(true)
end
it "should just call poweroff" do
expect(domain).to receive(:poweroff)
expect(subject.call(env)).to be_nil
end
end
end
end