Class: Vagrant::Action::Warden
- Inherits:
-
Object
- Object
- Vagrant::Action::Warden
- 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
-
#actions ⇒ Object
Returns the value of attribute actions.
-
#stack ⇒ Object
Returns the value of attribute stack.
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#finalize_action(action, env) ⇒ Object
A somewhat confusing function which simply initializes each middleware properly to call the next middleware in the sequence.
-
#initialize(actions, env) ⇒ Warden
constructor
A new instance of Warden.
-
#recover(env) ⇒ Object
We implement the recover method ourselves in case a Warden is embedded within another Warden.
Constructor Details
#initialize(actions, env) ⇒ Warden
Returns a new instance of Warden.
22 23 24 25 26 27 |
# File 'lib/vagrant/action/warden.rb', line 22 def initialize(actions, env) @stack = [] @actions = actions.map { |m| finalize_action(m, env) }.flatten @logger = Log4r::Logger.new("vagrant::action::warden") @last_error = nil end |
Instance Attribute Details
#actions ⇒ Object
Returns the value of attribute actions.
20 21 22 |
# File 'lib/vagrant/action/warden.rb', line 20 def actions @actions end |
#stack ⇒ Object
Returns the value of attribute stack.
20 21 22 |
# File 'lib/vagrant/action/warden.rb', line 20 def stack @stack end |
Instance Method Details
#call(env) ⇒ Object
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 |
# File 'lib/vagrant/action/warden.rb', line 29 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 IN action: #{action}") @stack.unshift(action).first.call(env) raise Errors::VagrantInterrupt if env[:interrupted] @logger.info("Calling OUT action: #{action}") rescue SystemExit, NoMemoryError # This means that an "exit" or "abort" was called, or we have run out # of memory. In these cases, we just exit immediately. raise rescue Exception => e # We guard this so that the Warden only outputs this once for # an exception that bubbles up. if e != @last_error @logger.error("Error occurred: #{e}") @last_error = e end env["vagrant.error"] = e # Something went horribly wrong. Start the rescue chain then # reraise the exception to properly kick us out of limbo here. recover(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.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/vagrant/action/warden.rb', line 84 def finalize_action(action, env) if action.is_a?(Builder::StackItem) klass = action.middleware args = action.arguments.parameters keywords = action.arguments.keywords block = action.arguments.block else klass = action args = [] keywords = {} end args = nil if args.empty? keywords = nil if keywords.empty? if klass.is_a?(Class) # NOTE: We need to detect if we are passing args and/or # keywords and do it explicitly. Earlier versions # are not as lax about splatting keywords when the # target method is not expecting them. if args && keywords klass.new(self, env, *args, **keywords, &block) elsif args klass.new(self, env, *args, &block) elsif keywords klass.new(self, env, **keywords, &block) else klass.new(self, env, &block) end 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 |
#recover(env) ⇒ Object
We implement the recover method ourselves in case a Warden is embedded within another Warden. To recover, we just do our own recovery process on our stack.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/vagrant/action/warden.rb', line 65 def recover(env) @logger.info("Beginning recovery process...") @stack.each do |act| if act.respond_to?(:recover) @logger.info("Calling recover: #{act}") act.recover(env) end end @logger.info("Recovery complete.") # Clear stack so that warden down the middleware chain doesn't # rescue again. @stack.clear end |