Rework prevent destroy if provider completed (#1422)

Adjust handling to use a method reference instead of attempting to
update the env value as that only appears to be available to actions
further down the chain and any changes are not visible during recovery
when exercised for real.

By passing a function reference can limit the actions that can be taken
to only allow a single call that will set a flag internal to the clean
up action.

Fixes: #1328
This commit is contained in:
Darragh Bailey 2021-12-04 21:03:53 +00:00 committed by GitHub
parent 1f9fd6dc2e
commit 87ec540994
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 7 deletions

View File

@ -8,10 +8,16 @@ module VagrantPlugins
def initialize(app, _env) def initialize(app, _env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::cleanup_on_failure') @logger = Log4r::Logger.new('vagrant_libvirt::action::cleanup_on_failure')
@app = app @app = app
@cleanup = true
end end
def call(env) def call(env)
env['vagrant-libvirt.provider'] = :starting # passing a value doesn't work as the env that is updated may be dupped from
# the original meaning the latter action's update is discarded. Instead pass
# a reference to the method on this class that will toggle the instance
# variable indicating whether cleanup is needed or not.
env['vagrant-libvirt.complete'] = method(:completed)
@app.call(env) @app.call(env)
end end
@ -19,8 +25,8 @@ module VagrantPlugins
return unless env[:machine] && env[:machine].state.id != :not_created return unless env[:machine] && env[:machine].state.id != :not_created
# only destroy if failed to complete bring up # only destroy if failed to complete bring up
if env['vagrant-libvirt.provider'] == :finished unless @cleanup
@logger.info("VM completed provider setup, no need to teardown") @logger.debug('VM provider setup was completed, no need to halt/destroy')
return return
end end
@ -40,22 +46,27 @@ module VagrantPlugins
env[:action_runner].run(Action.action_destroy, destroy_env) env[:action_runner].run(Action.action_destroy, destroy_env)
end end
end end
def completed
@cleanup = false
end
end end
class SetupComplete class SetupComplete
def initialize(app, _env) def initialize(app, _env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::cleanup_on_failure') @logger = Log4r::Logger.new('vagrant_libvirt::action::setup_complete')
@app = app @app = app
end end
def call(env) def call(env)
if env['vagrant-libvirt.provider'].nil? if env['vagrant-libvirt.complete'].nil? or !env['vagrant-libvirt.complete'].respond_to? :call
raise Errors::CallChainError, require_action: CleanupOnFailure.name, current_action: SetupComplete.name raise Errors::CallChainError, require_action: CleanupOnFailure.name, current_action: SetupComplete.name
end end
@logger.debug('Marking provider setup as completed')
# mark provider as finished setup so that any failure after this # mark provider as finished setup so that any failure after this
# point doesn't result in destroying or shutting down the VM # point doesn't result in destroying or shutting down the VM
env['vagrant-libvirt.provider'] = :finished env['vagrant-libvirt.complete'].call
@app.call(env) @app.call(env)
end end

View File

@ -40,6 +40,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::CleanupOnFailure do
allow(machine).to receive(:state).and_return(state) allow(machine).to receive(:state).and_return(state)
allow(logger).to receive(:info) allow(logger).to receive(:info)
allow(logger).to receive(:debug)
allow(logger).to receive(:error) allow(logger).to receive(:error)
allow(runner).to receive(:run).and_call_original allow(runner).to receive(:run).and_call_original
@ -120,7 +121,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::CleanupOnFailure do
it 'should not perform halt or destroy' do it 'should not perform halt or destroy' do
expect(VagrantPlugins::ProviderLibvirt::Action).to_not receive(:action_halt) expect(VagrantPlugins::ProviderLibvirt::Action).to_not receive(:action_halt)
expect(VagrantPlugins::ProviderLibvirt::Action).to_not receive(:action_destroy) expect(VagrantPlugins::ProviderLibvirt::Action).to_not receive(:action_destroy)
expect(logger).to receive(:info).with('VM completed provider setup, no need to teardown') expect(logger).to receive(:debug).with('VM provider setup was completed, no need to halt/destroy')
expect { runner.run(action_chain) }.to raise_error(Exception, "some action failed") expect { runner.run(action_chain) }.to raise_error(Exception, "some action failed")
end end