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 +5 -5
- data/lib/smart_proxy_ansible.rb +3 -0
- data/lib/smart_proxy_ansible/api.rb +24 -14
- data/lib/smart_proxy_ansible/exception.rb +40 -0
- data/lib/smart_proxy_ansible/plugin.rb +10 -16
- data/lib/smart_proxy_ansible/roles_reader.rb +65 -0
- data/lib/smart_proxy_ansible/variables_extractor.rb +33 -0
- data/lib/smart_proxy_ansible/version.rb +3 -1
- metadata +34 -12
- data/lib/foreman_ansible_core.rb +0 -37
- data/lib/foreman_ansible_core/actions.rb +0 -17
- data/lib/foreman_ansible_core/command_creator.rb +0 -44
- data/lib/foreman_ansible_core/exception.rb +0 -35
- data/lib/foreman_ansible_core/playbook_runner.rb +0 -98
- data/lib/foreman_ansible_core/remote_execution_core/ansible_runner.rb +0 -42
- data/lib/foreman_ansible_core/remote_execution_core/settings_override.rb +0 -18
- data/lib/foreman_ansible_core/roles_reader.rb +0 -61
- data/lib/foreman_ansible_core/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce925932dfc2ddf578d2ae15b293ee1a223b8808
|
4
|
+
data.tar.gz: 54f6dd7b4d48229be33aef44b7445d8284a7d734
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a88b68d82b25d7baeff478651fdf159c512be92262d2c7c5ed5af5ed204915043ab08dbe3d7b3200a7261226f0ece19f2e803be10d3e25e105caa3f6d46bc97e
|
7
|
+
data.tar.gz: 0c57bf4282a7f4e9699b9108e3e89817a2e2ded17ef448d8d51ae5eeede0a93d8947673d3df034d775fee2238fdb5c2fc40a707c1acc77aa5044953c062c0e97
|
data/lib/smart_proxy_ansible.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
7
|
-
|
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
|
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
|
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-
|
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.
|
197
|
+
rubygems_version: 2.6.8
|
176
198
|
signing_key:
|
177
199
|
specification_version: 4
|
178
200
|
summary: Smart-Proxy Ansible plugin
|
data/lib/foreman_ansible_core.rb
DELETED
@@ -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
|