From 3cca16824879731315dac32bc2df1c643f30d461 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Tue, 7 May 2013 11:07:35 -0300 Subject: [PATCH] Stop container with lxc-stop if lxc-shutdown does not succeed --- lib/vagrant-lxc/action/forced_halt.rb | 4 +--- lib/vagrant-lxc/driver.rb | 6 +++--- lib/vagrant-lxc/driver/cli.rb | 22 ++++++++++++++++++++-- spec/unit/driver/cli_spec.rb | 11 +++++------ spec/unit/driver_spec.rb | 12 ++++++++++-- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/lib/vagrant-lxc/action/forced_halt.rb b/lib/vagrant-lxc/action/forced_halt.rb index 264c66a..da9b072 100644 --- a/lib/vagrant-lxc/action/forced_halt.rb +++ b/lib/vagrant-lxc/action/forced_halt.rb @@ -9,9 +9,7 @@ module Vagrant def call(env) if env[:machine].provider.state.id == :running env[:ui].info I18n.t("vagrant_lxc.messages.force_shutdown") - # TODO: Driver#halt is kinda graceful as well, if it doesn't - # work we can issue a lxc-stop. - env[:machine].provider.driver.halt + env[:machine].provider.driver.forced_halt end @app.call(env) diff --git a/lib/vagrant-lxc/driver.rb b/lib/vagrant-lxc/driver.rb index 3c43e64..428963f 100644 --- a/lib/vagrant-lxc/driver.rb +++ b/lib/vagrant-lxc/driver.rb @@ -69,11 +69,11 @@ module Vagrant @cli.transition_to(:running) { |c| c.start(customizations, (extra || nil)) } end - def halt + def forced_halt @logger.info('Shutting down container...') - - # TODO: issue an lxc-stop if a timeout gets reached @cli.transition_to(:stopped) { |c| c.shutdown } + rescue CLI::TargetStateNotReached + @cli.transition_to(:stopped) { |c| c.stop } end def destroy diff --git a/lib/vagrant-lxc/driver/cli.rb b/lib/vagrant-lxc/driver/cli.rb index 9bbcf4a..0898595 100644 --- a/lib/vagrant-lxc/driver/cli.rb +++ b/lib/vagrant-lxc/driver/cli.rb @@ -10,6 +10,12 @@ module Vagrant attr_accessor :name class TransitionBlockNotProvided < RuntimeError; end + class TargetStateNotReached < RuntimeError + def initialize(target_state, state) + msg = "Target state '#{target_state}' not reached, currently on '#{state}'" + super(msg) + end + end # Include this so we can use `Subprocess` more easily. include Vagrant::Util::Retryable @@ -60,6 +66,10 @@ module Vagrant run :start, '-d', '--name', @name, *options end + def stop + run :stop, '--name', @name + end + def shutdown run :shutdown, '--name', @name end @@ -76,12 +86,20 @@ module Vagrant run :attach, '--name', @name, *((extra || []) + cmd) end - def transition_to(state, &block) + def transition_to(target_state, tries = 30, timeout = 1, &block) raise TransitionBlockNotProvided unless block_given? yield self - run :wait, '--name', @name, '--state', state.to_s.upcase + while (last_state = self.state) != target_state && tries > 0 + @logger.debug "Target state '#{target_state}' not reached, currently on '#{last_state}'" + sleep timeout + tries -= 1 + end + + unless last_state == target_state + raise TargetStateNotReached.new target_state, last_state + end end private diff --git a/spec/unit/driver/cli_spec.rb b/spec/unit/driver/cli_spec.rb index 3d91de7..9394459 100644 --- a/spec/unit/driver/cli_spec.rb +++ b/spec/unit/driver/cli_spec.rb @@ -157,9 +157,11 @@ describe Vagrant::LXC::Driver::CLI do let(:name) { 'a-running-container' } subject { described_class.new(name) } - before { subject.stub(:run) } + before do + subject.stub(run: true, sleep: true, state: :stopped) + end - it 'yields cli object' do + it 'yields a cli object' do subject.stub(:shutdown) subject.transition_to(:stopped) { |c| c.shutdown } subject.should have_received(:shutdown) @@ -171,9 +173,6 @@ describe Vagrant::LXC::Driver::CLI do }.to raise_error(described_class::TransitionBlockNotProvided) end - it 'waits for the expected container state using lxc-wait' do - subject.transition_to(:running) { } - subject.should have_received(:run).with(:wait, '--name', name, '--state', 'RUNNING') - end + pending 'waits for the expected container state' end end diff --git a/spec/unit/driver_spec.rb b/spec/unit/driver_spec.rb index ff606ac..1b0833d 100644 --- a/spec/unit/driver_spec.rb +++ b/spec/unit/driver_spec.rb @@ -2,6 +2,7 @@ require 'unit_helper' require 'vagrant' require 'vagrant-lxc/driver' +require 'vagrant-lxc/driver/cli' describe Vagrant::LXC::Driver do describe 'container name validation' do @@ -101,12 +102,19 @@ describe Vagrant::LXC::Driver do it 'delegates to cli shutdown' do cli.should_receive(:shutdown) - subject.halt + subject.forced_halt end it 'expects a transition to running state to take place' do cli.should_receive(:transition_to).with(:stopped) - subject.halt + subject.forced_halt + end + + it 'attempts to force the container to stop in case a shutdown doesnt work' do + cli.stub(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::TargetStateNotReached.new :target, :source) + cli.should_receive(:transition_to).with(:stopped).twice + cli.should_receive(:stop) + subject.forced_halt end end