class ForemanAnsibleCore::Runner::AnsibleRunner
Public Class Methods
new(input, suspended_action:)
click to toggle source
Calls superclass method
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 6 def initialize(input, suspended_action:) super input, :suspended_action => suspended_action @inventory = rebuild_inventory(input) @playbook = input.values.first[:input][:action_input][:script] @root = working_dir end
Public Instance Methods
refresh()
click to toggle source
Calls superclass method
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 20 def refresh return unless super @counter ||= 1 @uuid ||= File.basename(Dir["#{@root}/artifacts/*"].first) job_event_dir = File.join(@root, 'artifacts', @uuid, 'job_events') loop do files = Dir["#{job_event_dir}/*.json"].map do |file| num = File.basename(file)[/\A\d+/].to_i unless file.include?('partial') [file, num] end files_with_nums = files.select { |(_, num)| num && num >= @counter }.sort_by(&:last) break if files_with_nums.empty? logger.debug("[foreman_ansible] - processing event files: #{files_with_nums.map(&:first).inspect}}") files_with_nums.map(&:first).each { |event_file| handle_event_file(event_file) } @counter = files_with_nums.last.last + 1 end end
start()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 13 def start prepare_directory_structure write_inventory write_playbook start_ansible_runner end
Private Instance Methods
handle_broadcast_data(event)
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 69 def handle_broadcast_data(event) log_event("broadcast", event) if event['event'] == 'playbook_on_stats' header, *rows = event['stdout'].strip.lines.map(&:chomp) @outputs.keys.select { |key| key.is_a? String }.each do |host| line = rows.find { |row| row =~ /#{host}/ } publish_data_for(host, [header, line].join("\n"), 'stdout') end else broadcast_data(event['stdout'] + "\n", 'stdout') end end
handle_event_file(event_file)
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 40 def handle_event_file(event_file) logger.debug("[foreman_ansible] - parsing event file #{event_file}") begin event = JSON.parse(File.read(event_file)) if (hostname = event['event_data']['host']) handle_host_event(hostname, event) else handle_broadcast_data(event) end true rescue JSON::ParserError => e logger.error("[foreman_ansible] - Error parsing runner event at #{event_file}: #{e.class}: #{e.message}") logger.debug(e.backtrace.join("\n")) end end
handle_host_event(hostname, event)
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 56 def handle_host_event(hostname, event) log_event("for host: #{hostname.inspect}", event) publish_data_for(hostname, event['stdout'] + "\n", 'stdout') if event['stdout'] case event['event'] when 'runner_on_ok' publish_exit_status_for(hostname, 0) if @exit_statuses[hostname].nil? when 'runner_on_unreachable' publish_exit_status_for(hostname, 1) when 'runner_on_failed' publish_exit_status_for(hostname, 2) if event['ignore_errors'].nil? end end
log_event(description, event)
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 111 def log_event(description, event) # TODO: replace this ugly code with block variant once https://github.com/Dynflow/dynflow/pull/323 # arrives in production logger.debug("[foreman_ansible] - handling event #{description}: #{JSON.pretty_generate(event)}") if logger.level <= ::Logger::DEBUG end
prepare_directory_structure()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 104 def prepare_directory_structure inner = %w[inventory project].map { |part| File.join(@root, part) } ([@root] + inner).each do |path| FileUtils.mkdir_p path end end
rebuild_inventory(input)
click to toggle source
Each per-host task has inventory only for itself, we must collect all the partial inventories into one large inventory containing all the hosts.
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 120 def rebuild_inventory(input) action_inputs = input.values.map { |hash| hash[:input][:action_input] } hostnames = action_inputs.map { |hash| hash[:name] } inventories = action_inputs.map { |hash| JSON.parse(hash[:ansible_inventory]) } host_vars = inventories.map { |i| i['_meta']['hostvars'] }.reduce(&:merge) { '_meta' => { 'hostvars' => host_vars }, 'all' => { 'hosts' => hostnames, 'vars' => inventories.first['all']['vars'] } } end
start_ansible_runner()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 98 def start_ansible_runner command = ['ansible-runner', 'run', @root, '-p', 'playbook.yml'] initialize_command(*command) logger.debug("[foreman_ansible] - Running command '#{command.join(' ')}'") end
working_dir()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 131 def working_dir return @root if @root dir = ForemanAnsibleCore.settings[:working_dir] @tmp_working_dir = true if dir.nil? Dir.mktmpdir else Dir.mktmpdir(nil, File.expand_path(dir)) end end
write_inventory()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 82 def write_inventory inventory_script = <<~INVENTORY_SCRIPT #!/bin/sh cat <<-EOS #{JSON.dump(@inventory)} EOS INVENTORY_SCRIPT path = File.join(@root, 'inventory', 'hosts') File.write(path, inventory_script) File.chmod(0o0755, path) end
write_playbook()
click to toggle source
# File lib/foreman_ansible_core/runner/ansible_runner.rb, line 94 def write_playbook File.write(File.join(@root, 'project', 'playbook.yml'), @playbook) end