Module: Kitchen::Command::RunAction

Included in:
Action, Test
Defined in:
lib/kitchen/command.rb

Overview

Common module to execute a Kitchen action such as create, converge, etc.

Author:

Instance Method Summary collapse

Instance Method Details

#concurrency_setting(instances) ⇒ Integer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determines how many instances may be acted on at once, clamped to the number of instances available.

Parameters:

  • instances (Array<Instance>)

    the instances to be acted on

Returns:

  • (Integer)

    the number of worker threads to start



203
204
205
206
207
208
209
210
# File 'lib/kitchen/command.rb', line 203

def concurrency_setting(instances)
  concurrency = 1
  if options[:concurrency]
    concurrency = options[:concurrency] || instances.size
    concurrency = instances.size if concurrency > instances.size
  end
  concurrency
end

#record_action_error(error) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Records an error raised by an action, synchronized across worker threads.

Parameters:



238
239
240
# File 'lib/kitchen/command.rb', line 238

def record_action_error(error)
  @action_errors_mutex.synchronize { @action_errors << error }
end

#report_errorsObject

private



189
190
191
192
193
194
195
# File 'lib/kitchen/command.rb', line 189

def report_errors
  unless @action_errors.empty?
    msg = ["#{@action_errors.length} actions failed.",
           @action_errors.map { |e| ">>>>>>     #{e.message}" }].join("\n")
    raise ActionFailed.new(msg, @action_errors)
  end
end

#run_action(action, instances, *args) ⇒ Object

Run an instance action (create, converge, setup, verify, destroy) on a collection of instances. The instance actions will take place in a separate thread of execution which may or may not be running concurrently.

Parameters:

  • action (String)

    action to perform

  • instances (Array<Instance>)

    an array of instances



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/kitchen/command.rb', line 160

def run_action(action, instances, *args)
  concurrency = concurrency_setting(instances)

  queue = Queue.new
  instances.each { |i| queue << i }
  concurrency.times { queue << nil }

  threads = []
  @action_errors = []
  @action_errors_mutex = Mutex.new
  previous_abort_on_exception = Thread.abort_on_exception
  begin
    Thread.abort_on_exception = true if options[:fail_fast]
    concurrency.times do
      threads << Thread.new do
        while (instance = queue.pop)
          run_action_in_thread(action, instance, *args)
        end
      end
    end
    threads.map(&:join)
    report_errors
  ensure
    Thread.abort_on_exception = previous_abort_on_exception
  end
end

#run_action_in_thread(action, instance, *args) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Performs an action on a single instance, recording any instance or action failure rather than letting it escape the worker thread.

Parameters:

  • action (String)

    action to perform

  • instance (Instance)

    the instance to act on

  • args (Array)

    additional arguments forwarded to the action



220
221
222
223
224
225
226
227
228
229
230
# File 'lib/kitchen/command.rb', line 220

def run_action_in_thread(action, instance, *args)
  instance.public_send(action, *args)
rescue Kitchen::InstanceFailure => e
  record_action_error(e)
rescue Kitchen::ActionFailed => e
  new_error = Kitchen::ActionFailed.new("#{e.message} on #{instance.name}")
  new_error.set_backtrace(e.backtrace)
  record_action_error(new_error)
ensure
  instance.cleanup!
end