Class: Vagrant::Action::Builtin::GracefulHalt

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant/action/builtin/graceful_halt.rb

Overview

This middleware class will attempt to perform a graceful shutdown of the machine using the guest implementation. This middleware is compatible with the Call middleware so you can branch based on the result, which is true if the halt succeeded and false otherwise.

Instance Method Summary collapse

Constructor Details

#initialize(app, env, target_state, source_state = nil) ⇒ GracefulHalt

Note: Any of the arguments can be arrays as well.

Parameters:

  • target_state (Symbol)

    The target state ID that means that the machine was properly shut down.

  • source_state (Symbol) (defaults to: nil)

    The source state ID that the machine must be in to be shut down.


18
19
20
21
22
23
# File 'lib/vagrant/action/builtin/graceful_halt.rb', line 18

def initialize(app, env, target_state, source_state=nil)
  @app          = app
  @logger       = Log4r::Logger.new("vagrant::action::builtin::graceful_halt")
  @source_state = source_state
  @target_state = target_state
end

Instance Method Details

#call(env) ⇒ Object


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/vagrant/action/builtin/graceful_halt.rb', line 25

def call(env)
  graceful = true
  graceful = !env[:force_halt] if env.key?(:force_halt)

  # By default, we didn't succeed.
  env[:result] = false

  if graceful && @source_state
    @logger.info("Verifying source state of machine: #{@source_state.inspect}")

    # If we're not in the proper source state, then we don't
    # attempt to halt the machine
    current_state = env[:machine].state.id
    if current_state != @source_state
      @logger.info("Invalid source state, not halting: #{current_state}")
      graceful = false
    end
  end

  # Only attempt to perform graceful shutdown under certain cases
  # checked above.
  if graceful
    env[:ui].output(I18n.t("vagrant.actions.vm.halt.graceful"))

    begin
      env[:machine].guest.capability(:halt)

      @logger.debug("Waiting for target graceful halt state: #{@target_state}")
      begin
        Timeout.timeout(env[:machine].config.vm.graceful_halt_timeout) do
          while env[:machine].state.id != @target_state
            sleep 1
          end
        end
      rescue Timeout::Error
        # Don't worry about it, we catch the case later.
      end
    rescue Errors::GuestCapabilityNotFound
      # This happens if insert_public_key is called on a guest that
      # doesn't support it. This will block a destroy so we let it go.
    rescue Errors::MachineGuestNotReady
      env[:ui].detail(I18n.t("vagrant.actions.vm.halt.guest_not_ready"))
    end

    # The result of this matters on whether we reached our
    # proper target state or not.
    env[:result] = env[:machine].state.id == @target_state

    if env[:result]
      @logger.info("Gracefully halted.")
    else
      @logger.info("Graceful halt failed.")
    end
  end

  @app.call(env)
end