Class: Vagrant::Action::Warden

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

Overview

The action warden is a middleware which injects itself between every other middleware, watching for exceptions which are raised and performing proper cleanup on every action by calling the recover method. The warden therefore allows middlewares to not worry about exceptional events, and by providing a simple callback, can clean up in any erroneous case.

Warden will "just work" behind the scenes, and is not of particular interest except to those who are curious about the internal workings of Vagrant.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(actions, env) ⇒ Warden

Returns a new instance of Warden.



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

def initialize(actions, env)
  @stack = []
  @actions = actions.map { |m| finalize_action(m, env) }
  @logger  = Log4r::Logger.new("vagrant::action::warden")
end

Instance Attribute Details

#actionsObject

Returns the value of attribute actions.



16
17
18
# File 'lib/vagrant/action/warden.rb', line 16

def actions
  @actions
end

#stackObject

Returns the value of attribute stack.



16
17
18
# File 'lib/vagrant/action/warden.rb', line 16

def stack
  @stack
end

Instance Method Details

#begin_rescue(env) ⇒ Object

Begins the recovery sequence for all middlewares which have run. It does this by calling recover (if it exists) on each middleware which has already run, in reverse order.



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/vagrant/action/warden.rb', line 53

def begin_rescue(env)
  @stack.each do |act|
    if act.respond_to?(:recover)
      @logger.info("Calling recover: #{act}")
      act.recover(env)
    end
  end

  # Clear stack so that warden down the middleware chain doesn't
  # rescue again.
  @stack.clear
end

#call(env) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/vagrant/action/warden.rb', line 24

def call(env)
  return if @actions.empty?

  begin
    # Call the next middleware in the sequence, appending to the stack
    # of "recoverable" middlewares in case something goes wrong!
    raise Errors::VagrantInterrupt if env[:interrupted]
    action = @actions.shift
    @logger.info("Calling action: #{action}")
    @stack.unshift(action).first.call(env)
    raise Errors::VagrantInterrupt if env[:interrupted]
  rescue SystemExit
    # This means that an "exit" or "abort" was called. In these cases,
    # we just exit immediately.
    raise
  rescue Exception => e
    @logger.error("Error occurred: #{e}")
    env["vagrant.error"] = e

    # Something went horribly wrong. Start the rescue chain then
    # reraise the exception to properly kick us out of limbo here.
    begin_rescue(env)
    raise
  end
end

#finalize_action(action, env) ⇒ Object

A somewhat confusing function which simply initializes each middleware properly to call the next middleware in the sequence.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/vagrant/action/warden.rb', line 68

def finalize_action(action, env)
  klass, args, block = action

  # Default the arguments to an empty array. Otherwise in Ruby 1.8
  # a `nil` args will actually pass `nil` into the class.
  args ||= []

  if klass.is_a?(Class)
    # A action klass which is to be instantiated with the
    # app, env, and any arguments given
    klass.new(self, env, *args, &block)
  elsif klass.respond_to?(:call)
    # Make it a lambda which calls the item then forwards
    # up the chain
    lambda do |e|
      klass.call(e)
      self.call(e)
    end
  else
    raise "Invalid action: #{action.inspect}"
  end
end