smart_proxy_ansible 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 420694bc9e01ed41e40bfccadba84b8457956c26
4
- data.tar.gz: fef11955d696cb2419a2946399d461bbe1a37d5c
2
+ SHA256:
3
+ metadata.gz: 23fef38e05c69af60a7c0d04af33bd49412e60507e869836ff2febcba0bfbad9
4
+ data.tar.gz: b42a49e027b08e77ebf55098b59f8a627ece791c8200d9e3c63eb68f6597002f
5
5
  SHA512:
6
- metadata.gz: 0b9063f73310b470484dfb5d7bcafd9cbc29ede72df76ab3ba8de46e680622ead09f5209d2d5d735e3b2f81e859a779e317b5bb4159d9e7a2ec09d0a805ab2e1
7
- data.tar.gz: 332a065c6ae3a3f150a50f281ea1a5e15a9d693351933690974583dd58159fddc4acd007bcd1fc80345cf3f28278aa9e8e54bcd5a42bc92ff43c694e338769b8
6
+ metadata.gz: b30a91e5065922bb76c0f71e5b3be3762738442848bcbaad9f49ff1cd8ec4cb957fe23db7f6606d98be55019ef909c9a2ab87cca1efc611d6582252356894e20
7
+ data.tar.gz: f6be9a1240b73ac6dc9872fb32a4ffbe24769a54d57d566e4697ab4d81bf6060c34544972d9699de482e67c68aa5d15de1ec8296b3400bdfee929fda8b39d065
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'foreman_tasks_core'
3
+ require 'foreman_remote_execution_core'
4
+ rescue LoadError
5
+ # These gems are not available in a proxy SCLed context
6
+ puts 'Running Foreman Ansible Core in non-SCL context'
7
+ end
8
+
9
+ # Core actions for Foreman Ansible, used by both Foreman and Foreman proxy
10
+ # This comprises running playbooks for the moment
11
+ module ForemanAnsibleCore
12
+ require 'foreman_ansible_core/exception'
13
+ require 'foreman_ansible_core/roles_reader'
14
+ require 'foreman_ansible_core/version'
15
+
16
+ if defined? ForemanTasksCore
17
+ extend ForemanTasksCore::SettingsLoader
18
+ register_settings(:ansible, :ansible_dir => '/etc/ansible',
19
+ :working_dir => nil)
20
+
21
+ if ForemanTasksCore.dynflow_present?
22
+ require 'foreman_tasks_core/runner'
23
+ require 'foreman_ansible_core/playbook_runner'
24
+ require 'foreman_ansible_core/actions'
25
+ end
26
+ end
27
+
28
+ if defined? ForemanTasksCore
29
+ require 'foreman_remote_execution_core/actions'
30
+ require 'foreman_ansible_core/remote_execution_core/ansible_runner'
31
+ require 'foreman_ansible_core/remote_execution_core/settings_override'
32
+ ForemanRemoteExecutionCore::Actions::RunScript.send(
33
+ :prepend,
34
+ ForemanAnsibleCore::RemoteExecutionCore::SettingsOverride
35
+ )
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ require 'foreman_tasks_core/shareable_action'
2
+
3
+ module ForemanAnsibleCore
4
+ module Actions
5
+ # Action that can be run both on Foreman or Foreman proxy side
6
+ # to execute the playbook run
7
+ class RunPlaybook < ForemanTasksCore::Runner::Action
8
+ def initiate_runner
9
+ ForemanAnsibleCore::PlaybookRunner.new(
10
+ input[:inventory],
11
+ input[:playbook],
12
+ input[:options]
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ module ForemanAnsibleCore
2
+ # Creates the actual command to be passed to foreman_tasks_core to run
3
+ class CommandCreator
4
+ attr_reader :command
5
+
6
+ def initialize(inventory_file, playbook_file, options = {})
7
+ @options = options
8
+ @command = [{ 'JSON_INVENTORY_FILE' => inventory_file }]
9
+ @command << 'ansible-playbook'
10
+ @command = command_options(@command)
11
+ @command << playbook_file
12
+ end
13
+
14
+ private
15
+
16
+ def command_options(command)
17
+ command.concat(['-i', json_inventory_script])
18
+ command.concat([setup_verbosity]) if verbose?
19
+ command.concat(['-T', @options[:timeout]]) unless @options[:timeout].nil?
20
+ command
21
+ end
22
+
23
+ def json_inventory_script
24
+ File.expand_path('../../bin/json_inventory.sh', File.dirname(__FILE__))
25
+ end
26
+
27
+ def setup_verbosity
28
+ verbosity_level = @options[:verbosity_level].to_i
29
+ verbosity = '-'
30
+ verbosity_level.times do
31
+ verbosity += 'v'
32
+ end
33
+ verbosity
34
+ end
35
+
36
+ def verbose?
37
+ verbosity_level = @options[:verbosity_level]
38
+ # rubocop:disable Rails/Present
39
+ !verbosity_level.nil? && !verbosity_level.empty? &&
40
+ verbosity_level.to_i > 0
41
+ # rubocop:enable Rails/Present
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ module ForemanAnsibleCore
2
+ # Taken from Foreman core, this class creates an error code for any exception
3
+ class Exception < ::StandardError
4
+ def initialize(message, *params)
5
+ @message = message
6
+ @params = params
7
+ end
8
+
9
+ def self.calculate_error_code(classname, message)
10
+ return 'ERF00-0000' if classname.nil? || message.nil?
11
+ basename = classname.split(':').last
12
+ class_hash = Zlib.crc32(basename) % 100
13
+ msg_hash = Zlib.crc32(message) % 10_000
14
+ format 'ERF%02d-%04d', class_hash, msg_hash
15
+ end
16
+
17
+ def code
18
+ @code ||= Exception.calculate_error_code(self.class.name, @message)
19
+ @code
20
+ end
21
+
22
+ def message
23
+ # make sure it works without gettext too
24
+ translated_msg = @message % @params
25
+ "#{code} [#{self.class.name}]: #{translated_msg}"
26
+ end
27
+
28
+ def to_s
29
+ message
30
+ end
31
+ end
32
+
33
+ class ReadConfigFileException < ForemanAnsibleCore::Exception; end
34
+ class ReadRolesException < ForemanAnsibleCore::Exception; end
35
+ end
@@ -0,0 +1,98 @@
1
+ require 'foreman_tasks_core/runner/command_runner'
2
+ require_relative 'command_creator'
3
+ require 'tmpdir'
4
+
5
+ module ForemanAnsibleCore
6
+ # Implements ForemanTasksCore::Runner::Base interface for running
7
+ # Ansible playbooks, used by the Foreman Ansible plugin and Ansible proxy
8
+ class PlaybookRunner < ForemanTasksCore::Runner::CommandRunner
9
+ attr_reader :command_out, :command_in, :command_pid
10
+
11
+ def initialize(inventory, playbook, options = {})
12
+ super
13
+ @inventory = inventory
14
+ @playbook = playbook
15
+ @options = options
16
+ initialize_dirs
17
+ end
18
+
19
+ def start
20
+ write_inventory
21
+ write_playbook
22
+ command = CommandCreator.new(inventory_file,
23
+ playbook_file,
24
+ @options).command
25
+ logger.debug('[foreman_ansible] - Initializing Ansible Runner')
26
+ Dir.chdir(@ansible_dir) do
27
+ initialize_command(*command)
28
+ logger.debug("[foreman_ansible] - Running command #{command}")
29
+ end
30
+ end
31
+
32
+ def kill
33
+ publish_data('== TASK ABORTED BY USER ==', 'stdout')
34
+ publish_exit_status(1)
35
+ ::Process.kill('SIGTERM', @command_pid)
36
+ close
37
+ end
38
+
39
+ def close
40
+ super
41
+ FileUtils.remove_entry(@working_dir) if @tmp_working_dir
42
+ end
43
+
44
+ private
45
+
46
+ def write_inventory
47
+ ensure_directory(File.dirname(inventory_file))
48
+ File.write(inventory_file, @inventory)
49
+ end
50
+
51
+ def write_playbook
52
+ ensure_directory(File.dirname(playbook_file))
53
+ File.write(playbook_file, @playbook)
54
+ end
55
+
56
+ def inventory_file
57
+ File.join(@working_dir, 'foreman-inventories', id)
58
+ end
59
+
60
+ def playbook_file
61
+ File.join(@working_dir, "foreman-playbook-#{id}.yml")
62
+ end
63
+
64
+ def events_dir
65
+ File.join(@working_dir, 'events', id.to_s)
66
+ end
67
+
68
+ def ensure_directory(path)
69
+ if File.exist?(path)
70
+ raise "#{path} expected to be a directory" unless File.directory?(path)
71
+ else
72
+ FileUtils.mkdir_p(path)
73
+ end
74
+ path
75
+ end
76
+
77
+ def initialize_dirs
78
+ settings = ForemanAnsibleCore.settings
79
+ initialize_working_dir(settings[:working_dir])
80
+ initialize_ansible_dir(settings[:ansible_dir])
81
+ end
82
+
83
+ def initialize_working_dir(working_dir)
84
+ if working_dir.nil?
85
+ @working_dir = Dir.mktmpdir
86
+ @tmp_working_dir = true
87
+ else
88
+ @working_dir = File.expand_path(working_dir)
89
+ end
90
+ end
91
+
92
+ def initialize_ansible_dir(ansible_dir)
93
+ raise "Ansible dir #{ansible_dir} does not exist" unless
94
+ !ansible_dir.nil? && File.exist?(ansible_dir)
95
+ @ansible_dir = ansible_dir
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,42 @@
1
+ module ForemanAnsibleCore
2
+ module RemoteExecutionCore
3
+ # Takes an inventory and runs it through REXCore CommandRunner
4
+ class AnsibleRunner < ::ForemanTasksCore::Runner::CommandRunner
5
+ DEFAULT_REFRESH_INTERVAL = 1
6
+
7
+ def initialize(options)
8
+ super(options)
9
+ @playbook_runner = ForemanAnsibleCore::PlaybookRunner.new(
10
+ options['ansible_inventory'],
11
+ options['script'],
12
+ options
13
+ )
14
+ end
15
+
16
+ def start
17
+ @playbook_runner.start
18
+ rescue StandardError => e
19
+ logger.error(
20
+ 'error while initalizing command'\
21
+ " #{e.class} #{e.message}:\n #{e.backtrace.join("\n")}"
22
+ )
23
+ publish_exception('Error initializing command', e)
24
+ end
25
+
26
+ def fill_continuous_output(continuous_output)
27
+ delegated_output.fetch('result', []).each do |raw_output|
28
+ continuous_output.add_raw_output(raw_output)
29
+ end
30
+ rescue StandardError => e
31
+ continuous_output.add_exception(_('Error loading data from proxy'), e)
32
+ end
33
+
34
+ def refresh
35
+ @command_out = @playbook_runner.command_out
36
+ @command_in = @playbook_runner.command_in
37
+ @command_pid = @playbook_runner.command_pid
38
+ super
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ module ForemanAnsibleCore
2
+ module RemoteExecutionCore
3
+ # Ensure the Ansible provider is used whenever a JobTemplate using this
4
+ # provider is called.
5
+ module SettingsOverride
6
+ def initiate_runner
7
+ return super unless input['ansible_inventory']
8
+ additional_options = {
9
+ :step_id => run_step_id,
10
+ :uuid => execution_plan_id
11
+ }
12
+ ::ForemanAnsibleCore::RemoteExecutionCore::AnsibleRunner.new(
13
+ input.merge(additional_options)
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,61 @@
1
+ module ForemanAnsibleCore
2
+ # Implements the logic needed to read the roles and associated information
3
+ class RolesReader
4
+ class << self
5
+ DEFAULT_CONFIG_FILE = '/etc/ansible/ansible.cfg'.freeze
6
+ DEFAULT_ROLES_PATH = '/etc/ansible/roles'.freeze
7
+
8
+ def list_roles
9
+ roles_path.split(':').map { |path| read_roles(path) }.flatten
10
+ end
11
+
12
+ def roles_path(roles_line = roles_path_from_config)
13
+ # Default to /etc/ansible/roles if none found
14
+ return DEFAULT_ROLES_PATH if roles_line.empty?
15
+ roles_path_key = roles_line.first.split('=').first.strip
16
+ # In case of commented roles_path key "#roles_path", return default
17
+ return DEFAULT_ROLES_PATH unless roles_path_key == 'roles_path'
18
+ roles_line.first.split('=').last.strip
19
+ end
20
+
21
+ def logger
22
+ # Return a different logger depending on where ForemanAnsibleCore is
23
+ # running from
24
+ if defined?(::Foreman::Logging)
25
+ ::Foreman::Logging.logger('foreman_ansible')
26
+ else
27
+ ::Proxy::LogBuffer::Decorator.instance
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def read_roles(roles_path)
34
+ rescue_and_raise_file_exception ReadRolesException,
35
+ roles_path, 'roles' do
36
+ Dir.glob("#{roles_path}/*").map do |path|
37
+ path.split('/').last
38
+ end
39
+ end
40
+ end
41
+
42
+ def roles_path_from_config
43
+ rescue_and_raise_file_exception ReadConfigFileException,
44
+ DEFAULT_CONFIG_FILE, 'config file' do
45
+ File.readlines(DEFAULT_CONFIG_FILE).select do |line|
46
+ line =~ /roles_path/
47
+ end
48
+ end
49
+ end
50
+
51
+ def rescue_and_raise_file_exception(exception, path, type)
52
+ yield
53
+ rescue Errno::ENOENT, Errno::EACCES => e
54
+ logger.debug(e.backtrace)
55
+ exception_message = "Could not read Ansible #{type} "\
56
+ "#{path} - #{e.message}"
57
+ raise exception.new(exception_message)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module ForemanAnsibleCore
2
+ VERSION = '2.0.2'.freeze
3
+ end
@@ -1,14 +1,16 @@
1
+ require 'foreman_ansible_core'
2
+
1
3
  module Proxy
2
4
  module Ansible
3
5
  class Api < Sinatra::Base
4
6
  get '/roles' do
5
- ForemanAnsibleCore::RolesReader.list_roles.to_json
7
+ ::ForemanAnsibleCore::RolesReader.list_roles.to_json
6
8
  end
7
9
 
8
10
  get '/roles/:role_name/variables' do |role_name|
9
11
  # not anything matching item, }}, {{, ansible_hostname or 'if'
10
12
  ansible_config = '/etc/ansible/ansible.cfg'
11
- roles_path = ForemanAnsibleCore::RolesReader.roles_path(ansible_config)
13
+ roles_path = ::ForemanAnsibleCore::RolesReader.roles_path(ansible_config)
12
14
  role_files = Dir.glob("#{roles_path}/#{role_name}/**/*.yml")
13
15
  variables = role_files.map do |role_file|
14
16
  File.read(role_file).scan(/{{(.*?)}}/).select do |param|
@@ -1,5 +1,5 @@
1
1
  module Proxy
2
2
  module Ansible
3
- VERSION = '2.0.1'
3
+ VERSION = '2.0.2'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_ansible
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-02-12 00:00:00.000000000 Z
12
+ date: 2018-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -136,6 +136,15 @@ files:
136
136
  - LICENSE
137
137
  - README.md
138
138
  - bundler.plugins.d/smart_proxy_ansible.rb
139
+ - lib/foreman_ansible_core.rb
140
+ - lib/foreman_ansible_core/actions.rb
141
+ - lib/foreman_ansible_core/command_creator.rb
142
+ - lib/foreman_ansible_core/exception.rb
143
+ - lib/foreman_ansible_core/playbook_runner.rb
144
+ - lib/foreman_ansible_core/remote_execution_core/ansible_runner.rb
145
+ - lib/foreman_ansible_core/remote_execution_core/settings_override.rb
146
+ - lib/foreman_ansible_core/roles_reader.rb
147
+ - lib/foreman_ansible_core/version.rb
139
148
  - lib/smart_proxy_ansible.rb
140
149
  - lib/smart_proxy_ansible/api.rb
141
150
  - lib/smart_proxy_ansible/http_config.ru
@@ -162,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
171
  version: '0'
163
172
  requirements: []
164
173
  rubyforge_project:
165
- rubygems_version: 2.6.14
174
+ rubygems_version: 2.7.3
166
175
  signing_key:
167
176
  specification_version: 4
168
177
  summary: Smart-Proxy Ansible plugin