smart_proxy_ansible 2.1.0 → 3.1.0

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: ce925932dfc2ddf578d2ae15b293ee1a223b8808
4
- data.tar.gz: 54f6dd7b4d48229be33aef44b7445d8284a7d734
2
+ SHA256:
3
+ metadata.gz: 723f4dc74c428f9eb0d34bda1f492e8b5e49eb2103f16ccb36b279db8dfb3045
4
+ data.tar.gz: 553c1a6918b5f345d7017fe9ce691bffed6903c7d1e5fdbcbe5905a863e70542
5
5
  SHA512:
6
- metadata.gz: a88b68d82b25d7baeff478651fdf159c512be92262d2c7c5ed5af5ed204915043ab08dbe3d7b3200a7261226f0ece19f2e803be10d3e25e105caa3f6d46bc97e
7
- data.tar.gz: 0c57bf4282a7f4e9699b9108e3e89817a2e2ded17ef448d8d51ae5eeede0a93d8947673d3df034d775fee2238fdb5c2fc40a707c1acc77aa5044953c062c0e97
6
+ metadata.gz: 2bde47200bda54b10495128b81a19f3f6471f1c9142e034537df43e6d8b6badfcf7685a59923d5bc008263231a64d414ab5c6aecb4f0adf3342f3dfb300a35d1
7
+ data.tar.gz: 6793a645db2e1e1ac75d1136cfa5e10285a2fb6b100d97b7a67613e7e4cac504f0154b398ed066f9ea17cb8f65589a8b76df60fece50764a9bb658c9181d145a
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Proxy plugin to make [foreman_ansible](https://github.com/theforeman/foreman_ansible) actions run in the proxy
4
4
 
5
+ ## Compatibility
6
+
7
+ This plugin requires at least Foreman Proxy 2.3.
8
+
5
9
  ## Installation (in development)
6
10
 
7
11
  ### Prerequisites
@@ -4,6 +4,8 @@ module Proxy
4
4
  # please keep the actual implementation of the endpoints outside
5
5
  # of this class.
6
6
  class Api < Sinatra::Base
7
+ include ::Proxy::Log
8
+
7
9
  get '/roles' do
8
10
  RolesReader.list_roles.to_json
9
11
  end
@@ -11,22 +13,38 @@ module Proxy
11
13
  get '/roles/variables' do
12
14
  variables = {}
13
15
  RolesReader.list_roles.each do |role_name|
14
- variables[role_name] = extract_variables(role_name)[role_name]
16
+ variables.merge!(extract_variables(role_name))
17
+ rescue ReadVariablesException => e
18
+ # skip what cannot be parsed
19
+ logger.error e
15
20
  end
16
21
  variables.to_json
17
22
  end
18
23
 
19
24
  get '/roles/:role_name/variables' do |role_name|
20
25
  extract_variables(role_name).to_json
26
+ rescue ReadVariablesException => e
27
+ logger.error e
28
+ {}.to_json
21
29
  end
22
30
 
23
31
  private
24
32
 
25
33
  def extract_variables(role_name)
26
34
  variables = {}
27
- RolesReader.roles_path.split(':').each do |path|
28
- variables[role_name] = VariablesExtractor
29
- .extract_variables("#{path}/#{role_name}")
35
+ role_name_parts = role_name.split('.')
36
+ if role_name_parts.count == 3
37
+ RolesReader.collections_paths.split(':').each do |path|
38
+ variables[role_name] ||= VariablesExtractor
39
+ .extract_variables("#{path}/ansible_collections/#{role_name_parts[0]}/#{role_name_parts[1]}/roles/#{role_name_parts[2]}")
40
+ end
41
+ else
42
+ RolesReader.roles_path.split(':').each do |path|
43
+ role_path = "#{path}/#{role_name}"
44
+ if File.directory?(role_path)
45
+ variables[role_name] ||= VariablesExtractor.extract_variables(role_path)
46
+ end
47
+ end
30
48
  end
31
49
  variables
32
50
  end
@@ -36,5 +36,6 @@ module Proxy
36
36
 
37
37
  class ReadConfigFileException < Proxy::Ansible::Exception; end
38
38
  class ReadRolesException < Proxy::Ansible::Exception; end
39
+ class ReadVariablesException < Proxy::Ansible::Exception; end
39
40
  end
40
41
  end
@@ -2,13 +2,20 @@ module Proxy
2
2
  module Ansible
3
3
  # Calls for the smart-proxy API to register the plugin
4
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__))
9
-
5
+ rackup_path File.expand_path('http_config.ru', __dir__)
10
6
  settings_file 'ansible.yml'
11
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
18
+ end
12
19
  end
13
20
  end
14
21
  end
@@ -6,19 +6,32 @@ module Proxy
6
6
  class RolesReader
7
7
  class << self
8
8
  DEFAULT_CONFIG_FILE = '/etc/ansible/ansible.cfg'.freeze
9
- DEFAULT_ROLES_PATH = '/etc/ansible/roles'.freeze
9
+ DEFAULT_ROLES_PATH = '/etc/ansible/roles:/usr/share/ansible/roles'.freeze
10
+ DEFAULT_COLLECTIONS_PATHS = '/etc/ansible/collections:/usr/share/ansible/collections'.freeze
10
11
 
11
12
  def list_roles
12
- roles_path.split(':').map { |path| read_roles(path) }.flatten
13
+ roles = roles_path.split(':').map { |path| read_roles(path) }.flatten
14
+ collection_roles = collections_paths.split(':').map { |path| read_collection_roles(path) }.flatten
15
+ roles + collection_roles
13
16
  end
14
17
 
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
18
+ def roles_path
19
+ config_path(path_from_config('roles_path'), DEFAULT_ROLES_PATH)
20
+ end
21
+
22
+ def collections_paths
23
+ config_path(path_from_config('collections_paths'), DEFAULT_COLLECTIONS_PATHS)
24
+ end
25
+
26
+ def config_path(config_line, default)
27
+ # Default to /etc/ansible/roles if config_line is empty
28
+ return default if config_line.empty?
29
+
30
+ config_line_key = config_line.first.split('=').first.strip
31
+ # In case of commented roles_path key "#roles_path" or #collections_paths, return default
32
+ return default if ['#roles_path', '#collections_paths'].include?(config_line_key)
33
+
34
+ config_line.first.split('=').last.strip
22
35
  end
23
36
 
24
37
  def logger
@@ -34,30 +47,43 @@ module Proxy
34
47
  private
35
48
 
36
49
  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
50
+ glob_path("#{roles_path}/*").map do |path|
51
+ path.split('/').last
42
52
  end
53
+ rescue Errno::ENOENT, Errno::EACCES => e
54
+ logger.debug(e.backtrace)
55
+ message = "Could not read Ansible roles #{roles_path} - #{e.message}"
56
+ raise ReadRolesException.new(message), message
57
+ end
58
+
59
+ def glob_path(path)
60
+ Dir.glob path
61
+
43
62
  end
44
63
 
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
64
+ def read_collection_roles(collections_path)
65
+ Dir.glob("#{collections_path}/ansible_collections/*/*/roles/*").map do |path|
66
+ parts = path.split('/')
67
+ role = parts.pop
68
+ parts.pop
69
+ collection = parts.pop
70
+ author = parts.pop
71
+ "#{author}.#{collection}.#{role}"
51
72
  end
73
+ rescue Errno::ENOENT, Errno::EACCES => e
74
+ logger.debug(e.backtrace)
75
+ message = "Could not read Ansible roles #{collections_path} - #{e.message}"
76
+ raise ReadRolesException.new(message), message
52
77
  end
53
78
 
54
- def rescue_and_raise_file_exception(exception, path, type)
55
- yield
79
+ def path_from_config(config_key)
80
+ File.readlines(DEFAULT_CONFIG_FILE).select do |line|
81
+ line =~ /^\s*#{config_key}/
82
+ end
56
83
  rescue Errno::ENOENT, Errno::EACCES => e
57
84
  logger.debug(e.backtrace)
58
- exception_message = "Could not read Ansible #{type} "\
59
- "#{path} - #{e.message}"
60
- raise exception.new(exception_message), exception_message
85
+ message = "Could not read Ansible config file #{DEFAULT_CONFIG_FILE} - #{e.message}"
86
+ raise ReadConfigFileException.new(message), message
61
87
  end
62
88
  end
63
89
  end
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  module Proxy
2
4
  module Ansible
3
5
  # Implements the logic needed to read the roles and associated information
@@ -6,26 +8,16 @@ module Proxy
6
8
  def extract_variables(role_path)
7
9
  role_files = Dir.glob("#{role_path}/defaults/**/*.yml") +
8
10
  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
11
+ role_files.reduce({}) do |memo, role_file|
12
+ loaded_yaml = {}
13
+ begin
14
+ loaded_yaml = YAML.load_file(role_file)
15
+ rescue Psych::SyntaxError
16
+ raise ReadVariablesException.new "#{role_file} is not YAML file"
17
+ end
18
+ raise ReadVariablesException.new "Could not parse YAML file: #{role_file}" unless loaded_yaml.is_a? Hash
19
+ memo.merge loaded_yaml
20
+ end
29
21
  end
30
22
  end
31
23
  end
@@ -2,6 +2,6 @@ module Proxy
2
2
  # Version, this allows the proxy and other plugins know
3
3
  # what version of the Ansible plugin is running
4
4
  module Ansible
5
- VERSION = '2.1.0'
5
+ VERSION = '3.1.0'
6
6
  end
7
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.1.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
@@ -9,50 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-12-06 00:00:00.000000000 Z
12
+ date: 2021-05-17 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: bundler
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - "~>"
19
- - !ruby/object:Gem::Version
20
- version: '1.7'
21
- type: :development
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: '1.7'
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: rake
30
16
  requirement: !ruby/object:Gem::Requirement
31
17
  requirements:
32
18
  - - "~>"
33
19
  - !ruby/object:Gem::Version
34
- version: '10.0'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: '10.0'
42
- - !ruby/object:Gem::Dependency
43
- name: minitest
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '0'
20
+ version: '13.0'
49
21
  type: :development
50
22
  prerelease: false
51
23
  version_requirements: !ruby/object:Gem::Requirement
52
24
  requirements:
53
25
  - - "~>"
54
26
  - !ruby/object:Gem::Version
55
- version: '0'
27
+ version: '13.0'
56
28
  - !ruby/object:Gem::Dependency
57
29
  name: mocha
58
30
  requirement: !ruby/object:Gem::Requirement
@@ -73,14 +45,14 @@ dependencies:
73
45
  requirements:
74
46
  - - "~>"
75
47
  - !ruby/object:Gem::Version
76
- version: '1'
48
+ version: '3'
77
49
  type: :development
78
50
  prerelease: false
79
51
  version_requirements: !ruby/object:Gem::Requirement
80
52
  requirements:
81
53
  - - "~>"
82
54
  - !ruby/object:Gem::Version
83
- version: '1'
55
+ version: '3'
84
56
  - !ruby/object:Gem::Dependency
85
57
  name: rack-test
86
58
  requirement: !ruby/object:Gem::Requirement
@@ -95,20 +67,6 @@ dependencies:
95
67
  - - "~>"
96
68
  - !ruby/object:Gem::Version
97
69
  version: '0'
98
- - !ruby/object:Gem::Dependency
99
- name: rubocop
100
- requirement: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - '='
103
- - !ruby/object:Gem::Version
104
- version: 0.32.1
105
- type: :development
106
- prerelease: false
107
- version_requirements: !ruby/object:Gem::Requirement
108
- requirements:
109
- - - '='
110
- - !ruby/object:Gem::Version
111
- version: 0.32.1
112
70
  - !ruby/object:Gem::Dependency
113
71
  name: logger
114
72
  requirement: !ruby/object:Gem::Requirement
@@ -163,8 +121,7 @@ extra_rdoc_files:
163
121
  files:
164
122
  - LICENSE
165
123
  - README.md
166
- - bin/json_inventory.sh
167
- - bundler.plugins.d/smart_proxy_ansible.rb
124
+ - bundler.d/ansible.rb
168
125
  - lib/smart_proxy_ansible.rb
169
126
  - lib/smart_proxy_ansible/api.rb
170
127
  - lib/smart_proxy_ansible/exception.rb
@@ -186,15 +143,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
143
  requirements:
187
144
  - - ">="
188
145
  - !ruby/object:Gem::Version
189
- version: '0'
146
+ version: '2.5'
190
147
  required_rubygems_version: !ruby/object:Gem::Requirement
191
148
  requirements:
192
149
  - - ">="
193
150
  - !ruby/object:Gem::Version
194
151
  version: '0'
195
152
  requirements: []
196
- rubyforge_project:
197
- rubygems_version: 2.6.8
153
+ rubygems_version: 3.1.2
198
154
  signing_key:
199
155
  specification_version: 4
200
156
  summary: Smart-Proxy Ansible plugin
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env bash
2
- # An inventory script to load the inventory from JSON file.
3
- #
4
-
5
- if [ -z "$JSON_INVENTORY_FILE" ]; then
6
- echo "JSON_INVENTORY_FILE not specified"
7
- exit 1
8
- fi
9
-
10
- cat $JSON_INVENTORY_FILE