foreman_ansible 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/app/controllers/api/v2/ansible_override_values_controller.rb +53 -0
  4. data/app/controllers/api/v2/ansible_roles_controller.rb +2 -1
  5. data/app/controllers/api/v2/ansible_variables_controller.rb +32 -4
  6. data/app/controllers/concerns/foreman/controller/parameters/ansible_override_value.rb +36 -0
  7. data/app/models/concerns/foreman_ansible/host_managed_extensions.rb +56 -37
  8. data/app/services/foreman_ansible/inventory_creator.rb +10 -5
  9. data/app/services/foreman_ansible/operating_system_parser.rb +10 -0
  10. data/app/services/foreman_ansible/roles_importer.rb +1 -2
  11. data/app/views/ansible_variables/index.html.erb +1 -1
  12. data/app/views/api/v2/ansible_override_values/show.json.rabl +3 -0
  13. data/app/views/api/v2/ansible_variables/destroy.json.rabl +3 -0
  14. data/app/views/api/v2/ansible_variables/show.json.rabl +5 -4
  15. data/config/routes.rb +3 -1
  16. data/lib/foreman_ansible/engine.rb +2 -2
  17. data/lib/foreman_ansible/version.rb +1 -1
  18. data/locale/action_names.rb +3 -3
  19. data/locale/de/foreman_ansible.edit.po +238 -87
  20. data/locale/de/foreman_ansible.po +77 -2
  21. data/locale/en/foreman_ansible.edit.po +238 -87
  22. data/locale/en/foreman_ansible.po +77 -2
  23. data/locale/es/foreman_ansible.edit.po +238 -87
  24. data/locale/es/foreman_ansible.po +77 -2
  25. data/locale/foreman_ansible.pot +126 -24
  26. data/locale/fr/foreman_ansible.edit.po +238 -87
  27. data/locale/fr/foreman_ansible.po +77 -2
  28. data/locale/it/foreman_ansible.edit.po +238 -87
  29. data/locale/it/foreman_ansible.po +77 -2
  30. data/locale/ja/foreman_ansible.edit.po +238 -87
  31. data/locale/ja/foreman_ansible.po +77 -2
  32. data/locale/ko/foreman_ansible.edit.po +238 -87
  33. data/locale/ko/foreman_ansible.po +77 -2
  34. data/locale/pt_BR/foreman_ansible.edit.po +238 -87
  35. data/locale/pt_BR/foreman_ansible.po +77 -2
  36. data/locale/ru/foreman_ansible.edit.po +238 -87
  37. data/locale/ru/foreman_ansible.po +77 -2
  38. data/locale/zh_CN/foreman_ansible.edit.po +238 -87
  39. data/locale/zh_CN/foreman_ansible.po +77 -2
  40. data/locale/zh_TW/foreman_ansible.edit.po +238 -87
  41. data/locale/zh_TW/foreman_ansible.po +77 -2
  42. data/test/functional/api/v2/ansible_roles_controller_test.rb +8 -7
  43. data/test/unit/services/fact_parser_test.rb +7 -3
  44. data/test/unit/services/inventory_creator_test.rb +15 -1
  45. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0dc5e5a7b0474fef241b4607911073f5e3b94bbc
4
- data.tar.gz: 0e57147506ec6cac87ca5107e832bfe80d594ecb
3
+ metadata.gz: '08c99d39eecf64143f22351c6320d62cfb1f3314'
4
+ data.tar.gz: 42133e0cf37fedd36eead1368ae2e05411cc9ab7
5
5
  SHA512:
6
- metadata.gz: aca0209523ab2b7eac8ad76877ef2946a1a7fa9ce04c860cb972dcee73296f8d9c7afeac575170265a0a946084e5f5d2d0393628deeaf624a5d18784809bcae2
7
- data.tar.gz: 44db93653e958c13d72d80e68f8c7b188c59059078b942397d25664cbda18ec1756b0a709e3e15c75ba4aee319622f31a77f615894b4210f0a155f9fcca5634d
6
+ metadata.gz: c3d1e4d553a4621b0a40a19206369dcc3263cdbbb37ad81a23f2a65c36b2a3f06c7bb91d39f2e4f02051409b19be0323112b5949b2c3aeaa267304c5253e8090
7
+ data.tar.gz: 58a3841d303c241512ee7a8ff947f851fd55ed34132b482919bbea8d6a256262dc15a3b4a774cdc4a63a4575acd1aa94d9849ec9b9b7600f2ea14f4420cfba25
data/README.md CHANGED
@@ -23,7 +23,7 @@ Reporting and facts import from Ansible to Foreman.
23
23
  * Looking for an Ansible dynamic inventory for Foreman? Use [foreman_ansible_inventory](https://github.com/theforeman/foreman_ansible_inventory/)
24
24
 
25
25
  ## Documentation (installation and configuration)
26
- Check out the official manual at [theforeman.org](http://theforeman.org/plugins/foreman_ansible/1.x/index.html)
26
+ Check out the official manual at [theforeman.org](http://theforeman.org/plugins/foreman_ansible/2.x/index.html)
27
27
 
28
28
  ##### Registering a new host in Foreman
29
29
  ![sign up gif](http://i.imgur.com/mlnVFJj.gif)
@@ -41,12 +41,14 @@ Check out the official manual at [theforeman.org](http://theforeman.org/plugins/
41
41
 
42
42
  | Foreman | Plugin |
43
43
  | ---------------:| --------------:|
44
- | >= 1.9 | 0 - 0.3 |
45
- | >= 1.12 | 1.0 - TBD |
44
+ | >= 1.15 | 1.4 |
45
+ | >= 1.16 | 2.0 |
46
+ | >= 1.18 | 2.2 |
47
+ | >= 1.21 | 2.3 |
46
48
 
47
49
  ### Devs
48
50
 
49
- The callback sends a POST request to /api/v2/hosts/facts with the format you can see [in the API docs](http://theforeman.org/api/1.9/apidoc/v2/hosts/facts.html).
51
+ The callback sends a POST request to /api/v2/hosts/facts with the format you can see [in the API docs](http://theforeman.org/api/1.20/apidoc/v2/hosts/facts.html).
50
52
 
51
53
  Facts must contain the output of `ansible -m setup $HOSTNAME`, plus a '_type' and '_timestamp' keys. You can see an example on test/fixtures/sample_facts.json in this repository.
52
54
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Api
4
+ module V2
5
+ # API controller for Ansible Roles
6
+ class AnsibleOverrideValuesController < ::Api::V2::BaseController
7
+ include ::Api::Version2
8
+ include Foreman::Controller::Parameters::AnsibleOverrideValue
9
+
10
+ resource_description do
11
+ api_version 'v2'
12
+ api_base_url '/ansible/api'
13
+ end
14
+
15
+ def_param_group :ansible_override_value do
16
+ param :override_value, Hash, :required => true, :action_aware => true do
17
+ param :match, String, :required => true, :desc => N_("Override match")
18
+ param :value, :any_type, :of => LookupKey::KEY_TYPES, :required => false, :desc => N_("Override value, required if omit is false")
19
+ end
20
+ end
21
+
22
+ api :POST, "/ansible_override_values/", N_("Create an override value for a specific ansible variable")
23
+ param :ansible_variable_id, :identifier, :required => true
24
+ param_group :ansible_override_value, :as => :create
25
+
26
+ def create
27
+ @ansible_variable = AnsibleVariable.authorized(:edit_external_variables).
28
+ find_by_id(params[:ansible_variable_id].to_i)
29
+ @override_value = @ansible_variable.lookup_values.create!(lookup_value_params['override_value'])
30
+ @ansible_variable.update_attribute(:override, true)
31
+ render 'api/v2/ansible_override_values/show'
32
+ end
33
+
34
+ api :DELETE, "/ansible_override_values/:id", N_("Destroy an override value")
35
+ param :id, :identifier, :required => true
36
+
37
+ def destroy
38
+ @override_value = LookupValue.find_by_id(params[:id])
39
+ if @override_value
40
+ @ansible_variable = AnsibleVariable.where(:id => @override_value.lookup_key_id)
41
+ @override_value.destroy
42
+ render 'api/v2/ansible_override_values/show'
43
+ else
44
+ not_found
45
+ end
46
+ end
47
+
48
+ def resource_name
49
+ 'ansible_variable'
50
+ end
51
+ end
52
+ end
53
+ end
@@ -46,7 +46,8 @@ module Api
46
46
 
47
47
  api :GET, '/ansible_roles/fetch',
48
48
  N_('Fetch Ansible roles available to be imported')
49
- param :proxy_id, :identifier, N_('Smart Proxy to fetch from')
49
+ param :proxy_id, :identifier, N_('Smart Proxy to fetch from'),
50
+ :required => true
50
51
  def fetch
51
52
  fetched = []
52
53
  @importer.fetch!.each do |role_name|
@@ -5,13 +5,14 @@ module Api
5
5
  # API controller for Ansible Variables
6
6
  class AnsibleVariablesController < ::Api::V2::BaseController
7
7
  include ::Api::Version2
8
+ include Foreman::Controller::Parameters::VariableLookupKey
8
9
 
9
10
  resource_description do
10
11
  api_version 'v2'
11
12
  api_base_url '/ansible/api'
12
13
  end
13
14
 
14
- before_action :find_resource, :only => [:show, :destroy]
15
+ before_action :find_resource, :only => [:show, :destroy, :update]
15
16
  before_action :find_proxy, :only => [:import, :obsolete]
16
17
  before_action :create_importer, :only => [:import, :obsolete]
17
18
 
@@ -28,13 +29,40 @@ module Api
28
29
  api :DELETE, '/ansible_variables/:id', N_('Deletes Ansible variable')
29
30
  param :id, :identifier, :required => true
30
31
  def destroy
31
- process_response @ansible_variable.destroy
32
+ @ansible_variable.destroy
33
+ render 'api/v2/ansible_variables/destroy'
34
+ end
35
+
36
+ def_param_group :ansible_variable do
37
+ param :ansible_variable, Hash, :required => true, :action_aware => true do
38
+ param :variable, String, :required => true, :desc => N_("Name of variable")
39
+ param :ansible_role_id, :number, :desc => N_("Role ID")
40
+ param :default_value, :any_type, :of => LookupKey::KEY_TYPES, :desc => N_("Default value of variable")
41
+ param :hidden_value, :bool, :desc => N_("When enabled the parameter is hidden in the UI")
42
+ param :override_value_order, String, :desc => N_("The order in which values are resolved")
43
+ param :description, String, :desc => N_("Description of variable")
44
+ param :validator_type, LookupKey::VALIDATOR_TYPES, :desc => N_("Types of validation values")
45
+ param :validator_rule, String, :desc => N_("Used to enforce certain values for the parameter values")
46
+ param :variable_type, LookupKey::KEY_TYPES, :desc => N_("Types of variable values")
47
+ param :merge_overrides, :bool, :desc => N_("Merge all matching values (only array/hash type)")
48
+ param :merge_default, :bool, :desc => N_("Include default value when merging all matching values")
49
+ param :avoid_duplicates, :bool, :desc => N_("Remove duplicate values (only array type)")
50
+ end
51
+ end
52
+
53
+ api :PUT, '/ansible_variables/:id', N_('Updates Ansible variable')
54
+ param :id, :identifier, :required => true
55
+ param_group :ansible_variable, :as => :update
56
+
57
+ def update
58
+ @ansible_variable.update!(variable_lookup_key_params)
59
+ render 'api/v2/ansible_variables/show'
32
60
  end
33
61
 
34
62
  api :PUT, '/ansible_variables/import',
35
63
  N_('Import Ansible variables. This will only import variables '\
36
64
  'for already existing roles, it will not import any new roles')
37
- param :proxy_id, :identifier, N_('Smart Proxy to import from')
65
+ param :proxy_id, :identifier, N_('Smart Proxy to import from'), :required => true
38
66
  def import
39
67
  new_variables = @importer.import_variable_names([])[:new]
40
68
  new_variables.map(&:save)
@@ -44,7 +72,7 @@ module Api
44
72
  api :PUT, '/ansible_variables/obsolete',
45
73
  N_('Obsolete Ansible variables. This will only obsolete variables '\
46
74
  'for already existing roles, it will not delete any old roles')
47
- param :proxy_id, :identifier, N_('Smart Proxy to import from')
75
+ param :proxy_id, :identifier, N_('Smart Proxy to import from'), :required => true
48
76
  def obsolete
49
77
  old_variables = @importer.import_variable_names([])[:obsolete]
50
78
  old_variables.map(&:destroy)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foreman
4
+ module Controller
5
+ module Parameters
6
+ # Keys to allow as parameters in the AnsibleVariable controller
7
+ module AnsibleOverrideValue
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def lookup_value_params_filter
12
+ Foreman::ParameterFilter.new(::LookupValue).tap do |filter|
13
+ filter.permit :ansible_variable_id, :override_value => {}
14
+
15
+ filter.permit_by_context :hidden_value,
16
+ :host_or_hostgroup,
17
+ :lookup_key, :lookup_key_id,
18
+ :match,
19
+ :omit,
20
+ :value,
21
+ :nested => true
22
+
23
+ filter.permit_by_context :id,
24
+ :_destroy,
25
+ :ui => false, :api => false, :nested => true
26
+ end
27
+ end
28
+ end
29
+
30
+ def lookup_value_params
31
+ self.class.lookup_value_params_filter.filter_params(params, parameter_filter_context)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -4,51 +4,70 @@ require 'ipaddress'
4
4
  module ForemanAnsible
5
5
  # Relations to make Host::Managed 'have' ansible roles
6
6
  module HostManagedExtensions
7
- extend ActiveSupport::Concern
8
- include ::ForemanAnsible::Concerns::JobInvocationHelper
9
-
10
7
  # rubocop:disable Metrics/BlockLength
11
- included do
12
- has_many :host_ansible_roles, :foreign_key => :host_id
13
- has_many :ansible_roles, :through => :host_ansible_roles,
14
- :dependent => :destroy
15
- scoped_search :relation => :ansible_roles, :on => :name,
16
- :complete_value => true, :rename => :role,
17
- :only_explicit => true
8
+ def self.prepended(base)
9
+ base.instance_eval do
10
+ include ::ForemanAnsible::Concerns::JobInvocationHelper
18
11
 
19
- before_provision :play_ansible_roles
20
- audit_associations :ansible_roles
12
+ has_many :host_ansible_roles, :foreign_key => :host_id
13
+ has_many :ansible_roles, :through => :host_ansible_roles,
14
+ :dependent => :destroy
15
+ scoped_search :relation => :ansible_roles, :on => :name,
16
+ :complete_value => true, :rename => :role,
17
+ :only_explicit => true
21
18
 
22
- def inherited_ansible_roles
23
- return [] unless hostgroup
24
- hostgroup.inherited_and_own_ansible_roles
19
+ before_provision :play_ansible_roles
20
+ audit_associations :ansible_roles
25
21
  end
26
22
 
27
- # This one should be fixed, disabled for the moment as we're
28
- # in a rush to get the release out
29
- # rubocop:disable Metrics/AbcSize
30
- def play_ansible_roles
31
- return true unless ansible_roles.present? ||
32
- inherited_ansible_roles.present?
33
- composer = job_composer(:ansible_run_host, self)
34
- composer.triggering.mode = :future
35
- composer.triggering.start_at = (
36
- Time.zone.now +
37
- Setting::Ansible[:ansible_post_provision_timeout].to_i.seconds
38
- )
39
- composer.trigger!
40
- logger.info("Task for Ansible roles on #{self} before_provision: "\
41
- "#{job_invocation_path(composer.job_invocation)}")
42
- rescue Foreman::Exception => e
43
- logger.info("Error running Ansible roles on #{self} before_provision: "\
44
- "#{e.message}")
45
- end
46
- # rubocop:enable Metrics/AbcSize
23
+ base.singleton_class.prepend ClassMethods
24
+ end
25
+
26
+ def inherited_ansible_roles
27
+ return [] unless hostgroup
28
+ hostgroup.inherited_and_own_ansible_roles
29
+ end
30
+
31
+ # This one should be fixed, disabled for the moment as we're
32
+ # in a rush to get the release out
33
+ # rubocop:disable Metrics/AbcSize
34
+ def play_ansible_roles
35
+ return true unless ansible_roles.present? ||
36
+ inherited_ansible_roles.present?
37
+ composer = job_composer(:ansible_run_host, self)
38
+ composer.triggering.mode = :future
39
+ composer.triggering.start_at = (
40
+ Time.zone.now +
41
+ Setting::Ansible[:ansible_post_provision_timeout].to_i.seconds
42
+ )
43
+ composer.trigger!
44
+ logger.info("Task for Ansible roles on #{self} before_provision: "\
45
+ "#{job_invocation_path(composer.job_invocation)}")
46
+ rescue Foreman::Exception => e
47
+ logger.info("Error running Ansible roles on #{self} before_provision: "\
48
+ "#{e.message}")
49
+ end
50
+ # rubocop:enable Metrics/AbcSize
51
+
52
+ def all_ansible_roles
53
+ (ansible_roles + inherited_ansible_roles).uniq
54
+ end
47
55
 
48
- def all_ansible_roles
49
- (ansible_roles + inherited_ansible_roles).uniq
56
+ def host_params_hash
57
+ values = AnsibleVariable.where(:ansible_role_id => all_ansible_roles.pluck(:id)).
58
+ values_hash(self).raw.values
59
+ transformed = values.each_with_object({}) do |item, memo|
60
+ item.map do |name, hash|
61
+ variable = AnsibleVariable.find_by :key => name
62
+ safe_value = variable.hidden_value? ? variable.safe_value : hash[:value]
63
+ memo[name] = { :value => hash[:value], :safe_value => safe_value, :source => 'global' }
64
+ end
65
+ memo
50
66
  end
67
+
68
+ super.merge transformed
51
69
  end
70
+
52
71
  # rubocop:enable Metrics/BlockLength
53
72
  # Class methods we may need to override or add
54
73
  module ClassMethods
@@ -19,9 +19,7 @@ module ForemanAnsible
19
19
  # more advanced cases). Therefore we have only the 'all' group
20
20
  # with all hosts.
21
21
  def to_hash
22
- hosts = @hosts.map do |h|
23
- RemoteExecutionProvider.find_ip_or_hostname(h)
24
- end
22
+ hosts = @hosts.map(&:name)
25
23
 
26
24
  { 'all' => { 'hosts' => hosts,
27
25
  'vars' => template_inputs(@template_invocation) },
@@ -31,7 +29,7 @@ module ForemanAnsible
31
29
  def hosts_vars
32
30
  hosts.reduce({}) do |hash, host|
33
31
  hash.update(
34
- RemoteExecutionProvider.find_ip_or_hostname(host) => host_vars(host)
32
+ host.name => host_vars(host)
35
33
  )
36
34
  end
37
35
  end
@@ -94,8 +92,10 @@ module ForemanAnsible
94
92
  'ansible_become_user' => @template_invocation.effective_user,
95
93
  'ansible_user' => host_setting(host, 'remote_execution_ssh_user'),
96
94
  'ansible_ssh_pass' => rex_ssh_password(host),
95
+ 'ansible_sudo_pass' => rex_sudo_password(host),
97
96
  'ansible_ssh_private_key_file' => ansible_or_rex_ssh_private_key(host),
98
- 'ansible_port' => host_setting(host, 'remote_execution_ssh_port')
97
+ 'ansible_port' => host_setting(host, 'remote_execution_ssh_port'),
98
+ 'ansible_host' => AnsibleProvider.find_ip_or_hostname(host)
99
99
  }
100
100
  params['ansible_become'] = true if params['ansible_become_user'].present?
101
101
  # Backward compatibility for Ansible 1.x
@@ -117,6 +117,11 @@ module ForemanAnsible
117
117
  host_setting(host, 'remote_execution_ssh_password')
118
118
  end
119
119
 
120
+ def rex_sudo_password(host)
121
+ @template_invocation.job_invocation.sudo_password ||
122
+ host_setting(host, 'remote_execution_sudo_password')
123
+ end
124
+
120
125
  def ansible_or_rex_ssh_private_key(host)
121
126
  ansible_private_file = host_setting(host, 'ansible_ssh_private_key_file')
122
127
  if !ansible_private_file.empty?
@@ -5,6 +5,7 @@ module ForemanAnsible
5
5
  module OperatingSystemParser
6
6
  def operatingsystem
7
7
  args = { :name => os_name, :major => os_major, :minor => os_minor }
8
+ args[:release_name] = os_release_name if os_name == 'Debian'
8
9
  return @local_os if local_os(args).present?
9
10
  return @new_os if new_os(args).present?
10
11
  logger.debug do
@@ -39,6 +40,15 @@ module ForemanAnsible
39
40
  end
40
41
  end
41
42
 
43
+ def deb_release_map
44
+ { '7' => 'wheezy', '8' => 'jessie', '9' => 'stretch', '10' => 'buster' }
45
+ end
46
+
47
+ def os_release_name
48
+ return '' unless os_name == 'Debian'
49
+ deb_release_map[debian_os_major_sid]
50
+ end
51
+
42
52
  # rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity
43
53
  def os_major
44
54
  if os_name == 'Debian' &&
@@ -14,8 +14,7 @@ module ForemanAnsible
14
14
  end
15
15
 
16
16
  def fetch_role_names
17
- return remote_roles if ansible_proxy
18
- local_roles
17
+ remote_roles if ansible_proxy
19
18
  end
20
19
 
21
20
  def import_roles(roles)
@@ -26,7 +26,7 @@
26
26
  variable.ansible_role.name,
27
27
  hash_for_ansible_variables_path(:search => "ansible_role = #{variable.ansible_role}")
28
28
  ) %></td>
29
- <td class="ellipsis"><%= "String" %></td>
29
+ <td class="ellipsis"><%= variable.key_type || 'string' %></td>
30
30
  <td class="ellipsis">
31
31
  <% links = [
32
32
  display_delete_if_authorized(
@@ -0,0 +1,3 @@
1
+ object @override_value
2
+
3
+ attributes :id, :match, :value, :ansible_variable_id
@@ -0,0 +1,3 @@
1
+ object @ansible_variable
2
+
3
+ extends "api/v2/ansible_variables/show"
@@ -1,10 +1,11 @@
1
1
  object @ansible_variable
2
2
 
3
3
  attribute :parameter
4
- attributes :id, :ansible_role, :description, :override, :parameter_type,
5
- :hidden_value?, :omit, :required, :validator_type, :validator_rule,
6
- :merge_overrides, :merge_default, :avoid_duplicates,
7
- :override_value_order, :created_at, :updated_at
4
+ attributes :id, :variable, :ansible_role, :ansible_role_id, :description, :override,
5
+ :variable_type, :hidden_value?, :validator_type,
6
+ :validator_rule, :merge_overrides, :merge_default,
7
+ :avoid_duplicates, :override_value_order, :created_at, :updated_at,
8
+ :default_value
8
9
 
9
10
  node do |ansible_variable|
10
11
  {
@@ -79,12 +79,14 @@ Rails.application.routes.draw do
79
79
  end
80
80
  end
81
81
 
82
- resources :ansible_variables, :only => [:show, :index, :destroy] do
82
+ resources :ansible_variables, :only => [:show, :index, :destroy, :update] do
83
83
  collection do
84
84
  put :import
85
85
  put :obsolete
86
86
  end
87
87
  end
88
+
89
+ resources :ansible_override_values, :only => [:create, :destroy]
88
90
  end
89
91
  end
90
92
  end