smart_proxy_ansible 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 9d28a2511a0408d6a44c81eef3be111c62cda0a3b261a65c41421acfb761d0f6
4
- data.tar.gz: 2077acfca79312a7461f2163767620d066522b08208a898a661078435807c635
2
+ SHA1:
3
+ metadata.gz: ce925932dfc2ddf578d2ae15b293ee1a223b8808
4
+ data.tar.gz: 54f6dd7b4d48229be33aef44b7445d8284a7d734
5
5
  SHA512:
6
- metadata.gz: f7416e850bc1db8497ed812172e8f950ffa840154b10df984d22b3f656a430b380228c0cfe18cf1cfc876371be72d26ff088f30d1de03060fdb3b3bea2015298
7
- data.tar.gz: 8cbe2314b24f686a306a781ace03be10254c5ac8021f1c1cc9c1b60f34ce2af3ee7cf78b9aae186c0924a80aa5f87d2e87489b5a3700e7ff2045044afb47bf33
6
+ metadata.gz: a88b68d82b25d7baeff478651fdf159c512be92262d2c7c5ed5af5ed204915043ab08dbe3d7b3200a7261226f0ece19f2e803be10d3e25e105caa3f6d46bc97e
7
+ data.tar.gz: 0c57bf4282a7f4e9699b9108e3e89817a2e2ded17ef448d8d51ae5eeede0a93d8947673d3df034d775fee2238fdb5c2fc40a707c1acc77aa5044953c062c0e97
@@ -1,8 +1,11 @@
1
1
  require 'smart_proxy_dynflow'
2
2
 
3
3
  module Proxy
4
+ # Basic requires for this plugin
4
5
  module Ansible
5
6
  require 'smart_proxy_ansible/version'
6
7
  require 'smart_proxy_ansible/plugin'
8
+ require 'smart_proxy_ansible/roles_reader'
9
+ require 'smart_proxy_ansible/variables_extractor'
7
10
  end
8
11
  end
@@ -1,24 +1,34 @@
1
- require 'foreman_ansible_core'
2
-
3
1
  module Proxy
4
2
  module Ansible
3
+ # API endpoints. Most of the code should be calling other classes,
4
+ # please keep the actual implementation of the endpoints outside
5
+ # of this class.
5
6
  class Api < Sinatra::Base
6
7
  get '/roles' do
7
- ::ForemanAnsibleCore::RolesReader.list_roles.to_json
8
+ RolesReader.list_roles.to_json
9
+ end
10
+
11
+ get '/roles/variables' do
12
+ variables = {}
13
+ RolesReader.list_roles.each do |role_name|
14
+ variables[role_name] = extract_variables(role_name)[role_name]
15
+ end
16
+ variables.to_json
8
17
  end
9
18
 
10
19
  get '/roles/:role_name/variables' do |role_name|
11
- # not anything matching item, }}, {{, ansible_hostname or 'if'
12
- ansible_config = '/etc/ansible/ansible.cfg'
13
- roles_path = ::ForemanAnsibleCore::RolesReader.roles_path(ansible_config)
14
- role_files = Dir.glob("#{roles_path}/#{role_name}/**/*.yml")
15
- variables = role_files.map do |role_file|
16
- File.read(role_file).scan(/{{(.*?)}}/).select do |param|
17
- param.first.scan(/item/) == [] && param.first.scan(/if/) == []
18
- end.first
19
- end.compact
20
- variables.uniq!
21
- variables = variables.map(&:first).map(&:strip).to_json
20
+ extract_variables(role_name).to_json
21
+ end
22
+
23
+ private
24
+
25
+ def extract_variables(role_name)
26
+ variables = {}
27
+ RolesReader.roles_path.split(':').each do |path|
28
+ variables[role_name] = VariablesExtractor
29
+ .extract_variables("#{path}/#{role_name}")
30
+ end
31
+ variables
22
32
  end
23
33
  end
24
34
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proxy
4
+ module Ansible
5
+ # Taken from Foreman core, this class creates an error code for any
6
+ # exception
7
+ class Exception < ::StandardError
8
+ def initialize(message, *params)
9
+ @message = message
10
+ @params = params
11
+ end
12
+
13
+ def self.calculate_error_code(classname, message)
14
+ return 'ERF00-0000' if classname.nil? || message.nil?
15
+ basename = classname.split(':').last
16
+ class_hash = Zlib.crc32(basename) % 100
17
+ msg_hash = Zlib.crc32(message) % 10_000
18
+ format 'ERF%02d-%04d', class_hash, msg_hash
19
+ end
20
+
21
+ def code
22
+ @code ||= Exception.calculate_error_code(self.class.name, @message)
23
+ @code
24
+ end
25
+
26
+ def message
27
+ # make sure it works without gettext too
28
+ translated_msg = @message % @params
29
+ "#{code} [#{self.class.name}]: #{translated_msg}"
30
+ end
31
+
32
+ def to_s
33
+ message
34
+ end
35
+ end
36
+
37
+ class ReadConfigFileException < Proxy::Ansible::Exception; end
38
+ class ReadRolesException < Proxy::Ansible::Exception; end
39
+ end
40
+ end
@@ -1,20 +1,14 @@
1
- module Proxy::Ansible
2
- class Plugin < Proxy::Plugin
3
- http_rackup_path File.expand_path("http_config.ru", File.expand_path("../", __FILE__))
4
- https_rackup_path File.expand_path("http_config.ru", File.expand_path("../", __FILE__))
1
+ module Proxy
2
+ module Ansible
3
+ # Calls for the smart-proxy API to register the plugin
4
+ class Plugin < Proxy::Plugin
5
+ http_rackup_path File.expand_path('http_config.ru',
6
+ File.expand_path('../', __FILE__))
7
+ https_rackup_path File.expand_path('http_config.ru',
8
+ File.expand_path('../', __FILE__))
5
9
 
6
- settings_file "ansible.yml"
7
- plugin :ansible, Proxy::Ansible::VERSION
8
-
9
- after_activation do
10
- begin
11
- require 'smart_proxy_dynflow_core'
12
- require 'foreman_ansible_core'
13
- ForemanAnsibleCore.initialize_settings(Proxy::Ansible::Plugin.settings.to_h)
14
- rescue LoadError => _
15
- # Dynflow core is not available in the proxy, will be handled
16
- # by standalone Dynflow core
17
- end
10
+ settings_file 'ansible.yml'
11
+ plugin :ansible, Proxy::Ansible::VERSION
18
12
  end
19
13
  end
20
14
  end
@@ -0,0 +1,65 @@
1
+ require_relative 'exception'
2
+
3
+ module Proxy
4
+ module Ansible
5
+ # Implements the logic needed to read the roles and associated information
6
+ class RolesReader
7
+ class << self
8
+ DEFAULT_CONFIG_FILE = '/etc/ansible/ansible.cfg'.freeze
9
+ DEFAULT_ROLES_PATH = '/etc/ansible/roles'.freeze
10
+
11
+ def list_roles
12
+ roles_path.split(':').map { |path| read_roles(path) }.flatten
13
+ end
14
+
15
+ def roles_path(roles_line = roles_path_from_config)
16
+ # Default to /etc/ansible/roles if none found
17
+ return DEFAULT_ROLES_PATH if roles_line.empty?
18
+ roles_path_key = roles_line.first.split('=').first.strip
19
+ # In case of commented roles_path key "#roles_path", return default
20
+ return DEFAULT_ROLES_PATH unless roles_path_key == 'roles_path'
21
+ roles_line.first.split('=').last.strip
22
+ end
23
+
24
+ def logger
25
+ # Return a different logger depending on where ForemanAnsibleCore is
26
+ # running from
27
+ if defined?(::Foreman::Logging)
28
+ ::Foreman::Logging.logger('foreman_ansible')
29
+ else
30
+ ::Proxy::LogBuffer::Decorator.instance
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def read_roles(roles_path)
37
+ rescue_and_raise_file_exception ReadRolesException,
38
+ roles_path, 'roles' do
39
+ Dir.glob("#{roles_path}/*").map do |path|
40
+ path.split('/').last
41
+ end
42
+ end
43
+ end
44
+
45
+ def roles_path_from_config
46
+ rescue_and_raise_file_exception ReadConfigFileException,
47
+ DEFAULT_CONFIG_FILE, 'config file' do
48
+ File.readlines(DEFAULT_CONFIG_FILE).select do |line|
49
+ line =~ /^\s*roles_path/
50
+ end
51
+ end
52
+ end
53
+
54
+ def rescue_and_raise_file_exception(exception, path, type)
55
+ yield
56
+ rescue Errno::ENOENT, Errno::EACCES => e
57
+ logger.debug(e.backtrace)
58
+ exception_message = "Could not read Ansible #{type} "\
59
+ "#{path} - #{e.message}"
60
+ raise exception.new(exception_message), exception_message
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,33 @@
1
+ module Proxy
2
+ module Ansible
3
+ # Implements the logic needed to read the roles and associated information
4
+ class VariablesExtractor
5
+ class << self
6
+ def extract_variables(role_path)
7
+ role_files = Dir.glob("#{role_path}/defaults/**/*.yml") +
8
+ Dir.glob("#{role_path}/defaults/**/*.yaml")
9
+ # not anything matching item, }}, {{, ansible_hostname or 'if'
10
+ variables = role_files.map do |role_file|
11
+ candidates = File.read(role_file)
12
+ .scan(/{{(.*?)}}/).select do |param|
13
+ param.first.scan(/item/) == [] && param.first.scan(/if/) == []
14
+ end.flatten
15
+ # Sometimes inside the {{ }} there's a OR condition. In such a case,
16
+ # let's split and choose possible variables (variables cannot
17
+ # contain parenthesis)
18
+
19
+ candidates.map do |variable|
20
+ variable.split('|').map(&:strip).select do |var|
21
+ !var.include?('(') && # variables are not parenthesis
22
+ !var.include?('[') && # variables are not arrays
23
+ !var.include?('.') && # variables are not objects
24
+ !var.include?("'") # variables are not plain strings
25
+ end
26
+ end unless candidates.nil?
27
+ end.compact.flatten.uniq.map(&:strip)
28
+ variables
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,7 @@
1
1
  module Proxy
2
+ # Version, this allows the proxy and other plugins know
3
+ # what version of the Ansible plugin is running
2
4
  module Ansible
3
- VERSION = '2.0.3'
5
+ VERSION = '2.1.0'
4
6
  end
5
7
  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.3
4
+ version: 2.1.0
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-05-23 00:00:00.000000000 Z
12
+ date: 2018-12-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -109,6 +109,34 @@ dependencies:
109
109
  - - '='
110
110
  - !ruby/object:Gem::Version
111
111
  version: 0.32.1
112
+ - !ruby/object:Gem::Dependency
113
+ name: logger
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: smart_proxy
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
112
140
  - !ruby/object:Gem::Dependency
113
141
  name: smart_proxy_dynflow
114
142
  requirement: !ruby/object:Gem::Requirement
@@ -137,19 +165,13 @@ files:
137
165
  - README.md
138
166
  - bin/json_inventory.sh
139
167
  - bundler.plugins.d/smart_proxy_ansible.rb
140
- - lib/foreman_ansible_core.rb
141
- - lib/foreman_ansible_core/actions.rb
142
- - lib/foreman_ansible_core/command_creator.rb
143
- - lib/foreman_ansible_core/exception.rb
144
- - lib/foreman_ansible_core/playbook_runner.rb
145
- - lib/foreman_ansible_core/remote_execution_core/ansible_runner.rb
146
- - lib/foreman_ansible_core/remote_execution_core/settings_override.rb
147
- - lib/foreman_ansible_core/roles_reader.rb
148
- - lib/foreman_ansible_core/version.rb
149
168
  - lib/smart_proxy_ansible.rb
150
169
  - lib/smart_proxy_ansible/api.rb
170
+ - lib/smart_proxy_ansible/exception.rb
151
171
  - lib/smart_proxy_ansible/http_config.ru
152
172
  - lib/smart_proxy_ansible/plugin.rb
173
+ - lib/smart_proxy_ansible/roles_reader.rb
174
+ - lib/smart_proxy_ansible/variables_extractor.rb
153
175
  - lib/smart_proxy_ansible/version.rb
154
176
  - settings.d/ansible.yml.example
155
177
  homepage: https://github.com/theforeman/smart_proxy_ansible
@@ -172,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
194
  version: '0'
173
195
  requirements: []
174
196
  rubyforge_project:
175
- rubygems_version: 2.7.3
197
+ rubygems_version: 2.6.8
176
198
  signing_key:
177
199
  specification_version: 4
178
200
  summary: Smart-Proxy Ansible plugin
@@ -1,37 +0,0 @@
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
@@ -1,17 +0,0 @@
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
@@ -1,44 +0,0 @@
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
@@ -1,35 +0,0 @@
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
@@ -1,98 +0,0 @@
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
@@ -1,42 +0,0 @@
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
@@ -1,18 +0,0 @@
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
@@ -1,61 +0,0 @@
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
@@ -1,3 +0,0 @@
1
- module ForemanAnsibleCore
2
- VERSION = '2.0.2'.freeze
3
- end