foreman_ansible 1.3.1 → 1.4.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.

Potentially problematic release.


This version of foreman_ansible might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3462919b9025af83ed45745747a68e372c32d513
4
- data.tar.gz: ac580f584cbdbbe36805788fe2de9f7ab9b1c186
3
+ metadata.gz: 840a69169eb96bfdb1a4c9ff9f85bb6cd6ea3b7c
4
+ data.tar.gz: 1b5f26981963dcdfe6682a97794eb24f2095ff48
5
5
  SHA512:
6
- metadata.gz: fd6bcb7a20188b49fb6f26ebcba09d3e70439968883511db6b919f0e25d11afc97a2ed745e30036de7f40fcee1998f567c8611e20541c9c561381a00e9111d3c
7
- data.tar.gz: 5ff7b8a58b3dbe26db35ce4ebfc31d61c8e3c77b7e734f452cd43385d663e353186e2d4c93fe9f032db669092929219185e12010f30bff758b67662a866291dc
6
+ metadata.gz: 27d7cb312d1d8b87e61cff2176d52c918132640cc4ba0cf159ad94fcd7771d12bd0a01af74302cb01a7fcfd1c53fd7d20a090097f2368111e93f82b256fd5a46
7
+ data.tar.gz: 45fdc84cdc1e0396f3e05976e9c40eb0a53af3561ea583fdaf64a3652fb4e9c8171aacc1271a65bbbbb7db13d580f95dcae6a837f6b3ab423169f8d55c8f17d5
@@ -10,8 +10,7 @@ module Api
10
10
 
11
11
  api :GET, '/ansible/ansible_roles/:id', N_('Show role')
12
12
  param :id, :identifier, :required => true
13
- def show
14
- end
13
+ def show; end
15
14
 
16
15
  api :GET, '/ansible/ansible_roles', N_('List Ansible roles')
17
16
  param_group :search_and_pagination, ::Api::V2::BaseController
@@ -0,0 +1,76 @@
1
+ module ForemanAnsible
2
+ module Api
3
+ module V2
4
+ # Extends the hostgroups controller to support playing ansible roles
5
+ module HostgroupsControllerExtensions
6
+ extend ActiveSupport::Concern
7
+ include ForemanTasks::Triggers
8
+
9
+ # Included blocks shouldn't be bound by length, as otherwise concerns
10
+ # cannot extend the method properly.
11
+ # rubocop:disable BlockLength
12
+ included do
13
+ api :POST, '/hostgroups/play_roles',
14
+ N_('Plays Ansible roles on hostgroups')
15
+ param :id, Array, :required => true
16
+
17
+ def play_roles
18
+ find_resource
19
+
20
+ @result = {
21
+ :hostgroup => @hostgroup, :foreman_tasks => async_task(
22
+ ::Actions::ForemanAnsible::PlayHostgroupRoles, @hostgroup
23
+ )
24
+ }
25
+
26
+ render_message @result
27
+ end
28
+
29
+ api :POST, '/hostgroups/play_roles',
30
+ N_('Plays Ansible roles on hostgroups')
31
+ param :id, Array, :required => true
32
+
33
+ def multiple_play_roles
34
+ find_multiple
35
+
36
+ @result = []
37
+
38
+ @hostgroups.uniq.each do |hostgroup|
39
+ @result.append(
40
+ :hostgroup => hostgroup, :foreman_tasks => async_task(
41
+ ::Actions::ForemanAnsible::PlayHostgroupRoles, hostgroup
42
+ )
43
+ )
44
+ end
45
+
46
+ render_message @result
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def find_multiple
53
+ hostgroup_ids = params.fetch(:hostgroup_ids, [])
54
+ hostgroup_names = params.fetch(:hostgroup_names, [])
55
+
56
+ @hostgroups = []
57
+ hostgroup_ids.uniq.each do |hostgroup_id|
58
+ @hostgroups.append(Hostgroup.find(hostgroup_id))
59
+ end
60
+ hostgroup_names.uniq.each do |hostgroup_name|
61
+ @hostgroups.append(Hostgroup.find_by(:name => hostgroup_name))
62
+ end
63
+ end
64
+
65
+ def action_permission
66
+ case params[:action]
67
+ when 'play_roles'
68
+ :view
69
+ else
70
+ super
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,54 @@
1
+ module ForemanAnsible
2
+ module Api
3
+ module V2
4
+ # Extends the hosts controller to support playing ansible roles
5
+ module HostsControllerExtensions
6
+ extend ActiveSupport::Concern
7
+ include ForemanTasks::Triggers
8
+
9
+ included do
10
+ api :POST, '/hosts/:id/play_roles', N_('Plays Ansible roles on hosts')
11
+ param :id, String, :required => true
12
+
13
+ def play_roles
14
+ @result = {
15
+ :host => @host, :foreman_tasks => async_task(
16
+ ::Actions::ForemanAnsible::PlayHostRoles, @host
17
+ )
18
+ }
19
+
20
+ render_message @result
21
+ end
22
+
23
+ api :POST, '/hosts/play_roles', N_('Plays Ansible roles on hosts')
24
+ param :id, Array, :required => true
25
+
26
+ def multiple_play_roles
27
+ @result = []
28
+
29
+ @host.each do |item|
30
+ @result.append(
31
+ :host => item, :foreman_tasks => async_task(
32
+ ::Actions::ForemanAnsible::PlayHostRoles, item
33
+ )
34
+ )
35
+ end
36
+
37
+ render_message @result
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def action_permission
44
+ case params[:action]
45
+ when 'play_roles', 'multiple_play_roles'
46
+ :view
47
+ else
48
+ super
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ module ForemanAnsible
2
+ module Concerns
3
+ # Extra methods to enforce Ansible roles on a host or multiple hosts
4
+ module HostgroupsControllerExtensions
5
+ extend ActiveSupport::Concern
6
+ include ForemanTasks::Triggers
7
+
8
+ def play_roles
9
+ find_resource
10
+ task = async_task(
11
+ ::Actions::ForemanAnsible::PlayHostgroupRoles,
12
+ @hostgroup
13
+ )
14
+ redirect_to task
15
+ rescue Foreman::Exception => e
16
+ error e.message
17
+ redirect_to hostgroups_path
18
+ end
19
+
20
+ private
21
+
22
+ def action_permission
23
+ case params[:action]
24
+ when 'play_roles'
25
+ :view
26
+ else
27
+ super
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -8,14 +8,27 @@ module ForemanAnsible
8
8
  alias_method_chain(:multiple_actions, :run_ansible_roles)
9
9
  end
10
10
 
11
- def host_title_actions_with_run_ansible_roles(*args)
12
- button = link_to(
11
+ def ansible_roles_present?(host)
12
+ host.ansible_roles.present? ||
13
+ host.inherited_ansible_roles.present?
14
+ end
15
+
16
+ def ansible_roles_button(host)
17
+ link_to(
13
18
  icon_text('play', ' ' + _('Ansible roles'), :kind => 'fa'),
14
- play_roles_host_path(:id => args.first.id),
19
+ play_roles_host_path(:id => host.id),
15
20
  :id => :ansible_roles_button,
16
- :class => 'btn btn-default'
21
+ :class => 'btn btn-default',
22
+ :'data-no-turbolink' => true
17
23
  )
18
- title_actions(button_group(button)) if args.first.ansible_roles.present?
24
+ end
25
+
26
+ def host_title_actions_with_run_ansible_roles(*args)
27
+ host = args.first
28
+ if ansible_roles_present?(host)
29
+ button = ansible_roles_button(host)
30
+ title_actions(button_group(button))
31
+ end
19
32
  host_title_actions_without_run_ansible_roles(*args)
20
33
  end
21
34
 
@@ -0,0 +1,41 @@
1
+ module Actions
2
+ module ForemanAnsible
3
+ module Helpers
4
+ # Shared task methods between hostgroup and host roles actions
5
+ module HostCommon
6
+ def finalize
7
+ return unless delegated_output[:exit_status].to_s != '0'
8
+ error! _('Playbook execution failed')
9
+ end
10
+
11
+ def rescue_strategy
12
+ ::Dynflow::Action::Rescue::Fail
13
+ end
14
+
15
+ def humanized_name
16
+ _('Play Ansible roles')
17
+ end
18
+
19
+ def humanized_output
20
+ continuous_output.humanize
21
+ end
22
+
23
+ def continuous_output_providers
24
+ super << self
25
+ end
26
+
27
+ def fill_continuous_output(continuous_output)
28
+ delegated_output.fetch('result', []).each do |raw_output|
29
+ continuous_output.add_raw_output(raw_output)
30
+ end
31
+ rescue => e
32
+ continuous_output.add_exception(_('Error loading data from proxy'), e)
33
+ end
34
+
35
+ def find_options
36
+ { :verbosity_level => Setting[:ansible_verbosity] }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ module Actions
2
+ module ForemanAnsible
3
+ module Helpers
4
+ # Returns the name of the proxy running the specified action, or Foreman
5
+ # if it's the one running the action instead.
6
+ module PlayRolesDescription
7
+ def running_proxy_name
8
+ proxy = input.fetch(:host, {})[:proxy_used]
9
+ proxy ||= input.fetch(:hostgroup, {})[:proxy_used]
10
+ if [:not_defined, 'Foreman'].include? proxy
11
+ _('Foreman')
12
+ else
13
+ proxy
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,55 +1,42 @@
1
1
  module Actions
2
2
  module ForemanAnsible
3
- # Actions that initiaztes the playbook run for roles assigned to
4
- # the host. It doest that either locally or via a proxy when available.
3
+ # Action that initiates the playbook run for roles assigned to
4
+ # the host. It does that either locally or via a proxy when available.
5
5
  class PlayHostRoles < Actions::EntryAction
6
6
  include ::Actions::Helpers::WithContinuousOutput
7
7
  include ::Actions::Helpers::WithDelegatedAction
8
+ include Helpers::PlayRolesDescription
9
+ include Helpers::HostCommon
8
10
 
9
- def plan(host, proxy_selector = ::ForemanAnsible::ProxySelector.new)
10
- input[:host] = { :id => host.id, :name => host.fqdn }
11
- proxy = proxy_selector.determine_proxy(host)
12
- inventory_creator = ::ForemanAnsible::InventoryCreator.new([host])
11
+ def plan(host, proxy_selector = ::ForemanAnsible::ProxySelector.new,
12
+ options = {})
13
+ proxy = find_host_and_proxy(host, proxy_selector)
13
14
  role_names = host.all_ansible_roles.map(&:name)
15
+ inventory_creator = ::ForemanAnsible::InventoryCreator.new([host])
14
16
  playbook_creator = ::ForemanAnsible::PlaybookCreator.new(role_names)
15
- plan_delegated_action(proxy, ::ForemanAnsibleCore::Actions::RunPlaybook,
17
+ plan_delegated_action(proxy,
18
+ ::ForemanAnsibleCore::Actions::RunPlaybook,
16
19
  :inventory => inventory_creator.to_hash.to_json,
17
- :playbook => playbook_creator.roles_playbook)
20
+ :playbook => playbook_creator.roles_playbook,
21
+ :options => find_options.merge(options))
18
22
  plan_self
19
23
  end
20
24
 
21
- def finalize
22
- if delegated_output[:exit_status].to_s != '0'
23
- error! _('Playbook execution failed')
24
- end
25
- end
26
-
27
- def rescue_strategy
28
- ::Dynflow::Action::Rescue::Fail
29
- end
30
-
31
25
  def humanized_input
32
- _('on host %{name}') % { :name => input.fetch(:host, {})[:name] }
26
+ _('on host %{name} through %{proxy}') % {
27
+ :name => input.fetch(:host, {})[:name],
28
+ :proxy => running_proxy_name
29
+ }
33
30
  end
34
31
 
35
- def humanized_name
36
- _('Play Ansible roles')
37
- end
38
-
39
- def humanized_output
40
- continuous_output.humanize
41
- end
32
+ private
42
33
 
43
- def continuous_output_providers
44
- super << self
45
- end
46
-
47
- def fill_continuous_output(continuous_output)
48
- delegated_output.fetch('result', []).each do |raw_output|
49
- continuous_output.add_raw_output(raw_output)
50
- end
51
- rescue => e
52
- continuous_output.add_exception(_('Error loading data from proxy'), e)
34
+ def find_host_and_proxy(host, proxy_selector)
35
+ proxy = proxy_selector.determine_proxy(host)
36
+ input[:host] = { :id => host.id,
37
+ :name => host.fqdn,
38
+ :proxy_used => proxy.try(:name) || :not_defined }
39
+ proxy
53
40
  end
54
41
  end
55
42
  end
@@ -0,0 +1,57 @@
1
+ module Actions
2
+ module ForemanAnsible
3
+ # Action that initiates the playbook run for roles assigned to
4
+ # the hostgroup. It does that either locally or via a proxy when available.
5
+ class PlayHostgroupRoles < Actions::EntryAction
6
+ include ::Actions::Helpers::WithContinuousOutput
7
+ include ::Actions::Helpers::WithDelegatedAction
8
+ include Helpers::PlayRolesDescription
9
+ include Helpers::HostCommon
10
+
11
+ def plan(hostgroup, proxy_selector = ::ForemanAnsible::ProxySelector.new,
12
+ options = {})
13
+ proxy = find_hostgroup_and_proxy(hostgroup, proxy_selector)
14
+ inventory_creator = ::ForemanAnsible::
15
+ InventoryCreator.new(hostgroup.hosts)
16
+ playbook_creator = ::ForemanAnsible::
17
+ PlaybookCreator.new(hostgroup_ansible_roles(hostgroup))
18
+ plan_delegated_action(proxy, ::ForemanAnsibleCore::Actions::RunPlaybook,
19
+ :inventory => inventory_creator.to_hash.to_json,
20
+ :playbook => playbook_creator.roles_playbook,
21
+ :options => find_options.merge(options))
22
+ plan_self
23
+ end
24
+
25
+ def humanized_input
26
+ _('on host group %{name} through proxy %{proxy}') % {
27
+ :name => input.fetch(:hostgroup, {})[:name],
28
+ :proxy => running_proxy_name
29
+ }
30
+ end
31
+
32
+ private
33
+
34
+ def hostgroup_ansible_roles(hostgroup)
35
+ role_names = []
36
+ hostgroup.hostgroup_ansible_roles.each do |ansible_role|
37
+ role_names.append(ansible_role.ansible_role_name)
38
+ end
39
+ role_names
40
+ end
41
+
42
+ def hostgroup_contains_hosts(hostgroup)
43
+ return unless hostgroup.hosts.empty?
44
+ raise ::Foreman::Exception.new(N_('host group is empty'))
45
+ end
46
+
47
+ def find_hostgroup_and_proxy(hostgroup, proxy_selector)
48
+ hostgroup_contains_hosts(hostgroup)
49
+ proxy = proxy_selector.determine_proxy(hostgroup.hosts[0])
50
+ input[:hostgroup] = { :id => hostgroup.id,
51
+ :name => hostgroup.name,
52
+ :proxy_used => proxy.try(:name) || :not_defined }
53
+ proxy
54
+ end
55
+ end
56
+ end
57
+ end
@@ -7,12 +7,25 @@ module ForemanAnsible
7
7
  has_many :host_ansible_roles, :foreign_key => :host_id
8
8
  has_many :ansible_roles, :through => :host_ansible_roles,
9
9
  :dependent => :destroy
10
+ before_provision :play_ansible_roles
10
11
  include ForemanAnsible::HasManyAnsibleRoles
11
12
 
12
13
  def inherited_ansible_roles
13
14
  return [] unless hostgroup
14
15
  hostgroup.all_ansible_roles
15
16
  end
17
+
18
+ def play_ansible_roles
19
+ return unless ansible_roles.present? || inherited_ansible_roles.present?
20
+ task = ::ForemanTasks.async_task(
21
+ ::Actions::ForemanAnsible::PlayHostRoles,
22
+ self,
23
+ ::ForemanAnsible::ProxySelector.new,
24
+ :timeout => Setting['ansible_post_provision_timeout']
25
+ )
26
+ logger.info("Task for Ansible roles on #{self} before_provision: "\
27
+ "#{Rails.application.routes.url_helpers.task_path(task)}.")
28
+ end
16
29
  end
17
30
  end
18
31
  end
@@ -1,18 +1,85 @@
1
- class Setting::Ansible < ::Setting
2
- def self.load_defaults
3
- return unless super
4
- self.transaction do
5
- [
6
- self.set('ansible_port', N_('Foreman will use this port to ssh into hosts for running playbooks'), 22, N_('Default port')),
7
- self.set('ansible_user', N_('Foreman will try to connect as this user to hosts when running Ansible playbooks.'), 'root', N_('Default user')),
8
- self.set('ansible_ssh_pass', N_('Foreman will use this password when running Ansible playbooks.'), 'ansible', N_('Default password'))
9
- ].compact.each { |s| self.create s.update(:category => 'Setting::Ansible') }
10
- end
1
+ class Setting
2
+ # Provide settings related with Ansible
3
+ class Ansible < ::Setting
4
+ class << self
5
+ # It would be more disadvantages than advantages to split up
6
+ # load_defaults into multiple methods, this way it's already very
7
+ # manageable.
8
+ # rubocop:disable AbcSize
9
+ # rubocop:disable MethodLength
10
+ # rubocop:disable BlockLength
11
+ def load_defaults
12
+ return unless super
13
+ transaction do
14
+ [
15
+ set(
16
+ 'ansible_port',
17
+ N_('Use this port to connect to hosts '\
18
+ 'and run Ansible. You can override this on hosts'\
19
+ ' by adding a parameter "ansible_port"'),
20
+ 22,
21
+ N_('Port')
22
+ ),
23
+ set(
24
+ 'ansible_user',
25
+ N_('Foreman will try to connect to hosts as this user by default'\
26
+ ' when running Ansible playbooks. You can override this '\
27
+ ' on hosts by adding a parameter "ansible_user"'),
28
+ 'root',
29
+ N_('User')
30
+ ),
31
+ set(
32
+ 'ansible_ssh_pass',
33
+ N_('Use this password by default when running Ansible '\
34
+ 'playbooks. You can override this on hosts '\
35
+ 'by adding a parameter "ansible_ssh_pass"'),
36
+ 'ansible',
37
+ N_('Password')
38
+ ),
39
+ set(
40
+ 'ansible_connection',
41
+ N_('Use this connection type by default when running '\
42
+ 'Ansible playbooks. You can override this on hosts by '\
43
+ 'adding a parameter "ansible_connection"'),
44
+ 'ssh',
45
+ N_('Connection type')
46
+ ),
47
+ set(
48
+ 'ansible_winrm_server_cert_validation',
49
+ N_('Enable/disable WinRM server certificate '\
50
+ 'validation when running Ansible playbooks. You can override '\
51
+ 'this on hosts by adding a parameter '\
52
+ '"ansible_winrm_server_cert_validation"'),
53
+ 'validate',
54
+ N_('WinRM cert Validation')
55
+ ),
56
+ set(
57
+ 'ansible_verbosity',
58
+ N_('Foreman will add the this level of verbosity for '\
59
+ 'additional debugging output when running Ansible playbooks.'),
60
+ '0',
61
+ N_('Default verbosity level')
62
+ ),
63
+ set(
64
+ 'ansible_post_provision_timeout',
65
+ N_('Timeout (in seconds) to set when Foreman will trigger a '\
66
+ 'play Ansible roles task after a host is fully provisioned. '\
67
+ 'Set this to the maximum time you expect a host to take until'\
68
+ ' it is ready after a reboot.'),
69
+ '360',
70
+ N_('Post-provision timeout')
71
+ )
72
+ ].compact.each do |s|
73
+ create(s.update(:category => 'Setting::Ansible'))
74
+ end
75
+ end
11
76
 
12
- true
13
- end
77
+ true
78
+ end
14
79
 
15
- def self.humanized_category
16
- N_('Ansible')
80
+ def humanized_category
81
+ N_('Ansible')
82
+ end
83
+ end
17
84
  end
18
85
  end
@@ -0,0 +1,7 @@
1
+ # Displays Ansible roles button in host group action buttons
2
+ Deface::Override.new(
3
+ :virtual_path => 'hostgroups/index',
4
+ :name => 'hostgroup_ansible_roles_button',
5
+ :replace => "erb[loud]:contains('action_buttons')",
6
+ :partial => 'foreman_ansible/ansible_roles/hostgroup_ansible_roles_button'
7
+ )
@@ -49,7 +49,7 @@ module ForemanAnsible
49
49
  if pref.present?
50
50
  (facts[:ansible_interfaces] - [pref]).unshift(pref)
51
51
  else
52
- (facts[:ansible_interfaces].sort unless facts[:ansible_interfaces].nil?) || []
52
+ ansible_interfaces
53
53
  end
54
54
  end
55
55
 
@@ -64,6 +64,11 @@ module ForemanAnsible
64
64
 
65
65
  private
66
66
 
67
+ def ansible_interfaces
68
+ return [] unless facts[:ansible_interfaces].present?
69
+ facts[:ansible_interfaces].sort
70
+ end
71
+
67
72
  def ip_from_interface(interface)
68
73
  return unless facts[:"ansible_#{interface}"]['ipv4'].present?
69
74
  facts[:"ansible_#{interface}"]['ipv4']['address']
@@ -38,15 +38,25 @@ module ForemanAnsible
38
38
  params = {
39
39
  'ansible_port' => host_port(host),
40
40
  'ansible_user' => host_user(host),
41
- 'ansible_ssh_pass' => host_ssh_pass(host)
41
+ 'ansible_ssh_pass' => host_ssh_pass(host),
42
+ 'ansible_connection' => connection_type(host),
43
+ 'ansible_winrm_server_cert_validation' => winrm_cert_validation(host)
42
44
  }
43
-
44
- #Backward compatibility for Ansible 1.x
45
+ # Backward compatibility for Ansible 1.x
45
46
  params['ansible_ssh_port'] = params['ansible_port']
46
47
  params['ansible_ssh_user'] = params['ansible_user']
47
48
  params
48
49
  end
49
50
 
51
+ def winrm_cert_validation(host)
52
+ host.host_params['ansible_winrm_server_cert_validation'] ||
53
+ Setting['ansible_winrm_server_cert_validation']
54
+ end
55
+
56
+ def connection_type(host)
57
+ host.host_params['ansible_connection'] || Setting['ansible_connection']
58
+ end
59
+
50
60
  def host_roles(host)
51
61
  host.all_ansible_roles.map(&:name)
52
62
  end
@@ -8,6 +8,14 @@ module ForemanAnsible
8
8
  proxies
9
9
  end
10
10
 
11
+ def determine_proxy(*args)
12
+ result = super
13
+ return result unless result == :not_available
14
+ # Always run roles in some way, even if there are no proxies, Foreman
15
+ # should take that role in that case.
16
+ :not_defined
17
+ end
18
+
11
19
  private
12
20
 
13
21
  def proxy_scope(host)
@@ -0,0 +1,14 @@
1
+ <%=
2
+ if hostgroup.all_ansible_roles.empty?
3
+ action_buttons(
4
+ display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)),
5
+ display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup)),
6
+ display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :data => { :confirm => warning_message(hostgroup) }))
7
+ else
8
+ action_buttons(
9
+ display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)),
10
+ display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup)),
11
+ display_link_if_authorized(_('Play Roles'), hash_for_play_roles_hostgroup_path(:id => hostgroup), :'data-no-turbolink' => true),
12
+ display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :data => { :confirm => warning_message(hostgroup) }))
13
+ end
14
+ %>
@@ -1,6 +1,16 @@
1
1
  <div class='tab-pane' id='ansible_roles'>
2
- <%= multiple_selects(f, :ansible_roles, AnsibleRole, f.object.all_ansible_roles.map(&:id),
3
- {:disabled => f.object.inherited_ansible_roles.map(&:id),
4
- :label => _('Available roles')},
5
- { 'data-inheriteds' => f.object.inherited_ansible_roles.map(&:id).to_json }) %>
2
+ <%= multiple_selects(
3
+ f,
4
+ :ansible_roles,
5
+ AnsibleRole,
6
+ f.object.all_ansible_roles.map(&:id),
7
+ {
8
+ :disabled => f.object.inherited_ansible_roles.map(&:id),
9
+ :label => _('Available roles'),
10
+ :help_inline => popover('' ,
11
+ _('This list of roles will be applied when the host finishes '\
12
+ 'provisioning. Users can also play these roles through the API '\
13
+ 'or by clicking on the Play Roles button on the Host page '))
14
+ },
15
+ { 'data-inheriteds' => f.object.inherited_ansible_roles.map(&:id).to_json }) %>
6
16
  </div>
data/config/routes.rb CHANGED
@@ -9,6 +9,11 @@ Rails.application.routes.draw do
9
9
  get :multiple_play_roles
10
10
  end
11
11
  end
12
+ resources :hostgroups, :only => [] do
13
+ member do
14
+ get :play_roles
15
+ end
16
+ end
12
17
  end
13
18
 
14
19
  resources :ansible_roles, :only => [:index, :destroy] do
@@ -25,6 +30,26 @@ Rails.application.routes.draw do
25
30
  :apiv => /v1|v2/,
26
31
  :constraints => ApiConstraints.new(:version => 2) do
27
32
 
33
+ constraints(:id => %r{[^\/]+}) do
34
+ resources :hosts, :only => [] do
35
+ member do
36
+ post :play_roles
37
+ end
38
+ collection do
39
+ post :multiple_play_roles
40
+ end
41
+ end
42
+
43
+ resources :hostgroups, :only => [] do
44
+ member do
45
+ post :play_roles
46
+ end
47
+ collection do
48
+ post :multiple_play_roles
49
+ end
50
+ end
51
+ end
52
+
28
53
  resources :ansible_roles, :only => [:show, :index, :destroy] do
29
54
  collection do
30
55
  put :import
@@ -35,9 +35,16 @@ module ForemanAnsible
35
35
  requires_foreman '>= 1.12'
36
36
 
37
37
  security_block :foreman_ansible do
38
- permission :play_roles,
39
- { :hosts => [:play_roles, :multiple_play_roles] },
38
+ permission :play_roles_on_host,
39
+ { :hosts => [:play_roles, :multiple_play_roles],
40
+ :'api/v2/hosts' => [:play_roles,
41
+ :multiple_play_roles] },
40
42
  :resource_type => 'Host'
43
+ permission :play_roles_on_hostgroup,
44
+ { :hostgroups => [:play_roles],
45
+ :'api/v2/hostgroups' => [:play_roles,
46
+ :multiple_play_roles] },
47
+ :resource_type => 'Hostgroup'
41
48
  permission :view_ansible_roles,
42
49
  { :ansible_roles => [:index],
43
50
  :'api/v2/ansible_roles' => [:index, :show] },
@@ -53,7 +60,8 @@ module ForemanAnsible
53
60
  end
54
61
 
55
62
  role 'Ansible Roles Manager',
56
- [:play_roles, :view_ansible_roles, :destroy_ansible_roles,
63
+ [:play_roles_on_host, :play_roles_on_hostgroup,
64
+ :view_ansible_roles, :destroy_ansible_roles,
57
65
  :import_ansible_roles]
58
66
 
59
67
  role_assignment_params = { :ansible_role_ids => [],
@@ -113,6 +121,15 @@ module ForemanAnsible
113
121
  ::HostsController.send(
114
122
  :include, ForemanAnsible::Concerns::HostsControllerExtensions
115
123
  )
124
+ ::Api::V2::HostsController.send(
125
+ :include, ForemanAnsible::Api::V2::HostsControllerExtensions
126
+ )
127
+ ::HostgroupsController.send(
128
+ :include, ForemanAnsible::Concerns::HostgroupsControllerExtensions
129
+ )
130
+ ::Api::V2::HostgroupsController.send(
131
+ :include, ForemanAnsible::Api::V2::HostgroupsControllerExtensions
132
+ )
116
133
  rescue => e
117
134
  Rails.logger.warn "Foreman Ansible: skipping engine hook (#{e})"
118
135
  end
@@ -2,5 +2,5 @@
2
2
  # This way other parts of Foreman can just call ForemanAnsible::VERSION
3
3
  # and detect what version the plugin is running.
4
4
  module ForemanAnsible
5
- VERSION = '1.3.1'.freeze
5
+ VERSION = '1.4.0'.freeze
6
6
  end
@@ -0,0 +1,49 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module Api
4
+ module V2
5
+ class HostgroupsControllerTest < ActionController::TestCase
6
+ include ::Dynflow::Testing
7
+
8
+ setup do
9
+ @host1 = FactoryGirl.create(:host, :with_hostgroup)
10
+ @host2 = FactoryGirl.create(:host, :with_hostgroup)
11
+ end
12
+
13
+ after do
14
+ ::ForemanTasks::Task::DynflowTask.all.each do |task|
15
+ task.destroy
16
+ task.delete
17
+ end
18
+ end
19
+
20
+ test 'should return an not_found due to non-existent host_id' do
21
+ post :play_roles, :id => 'non-existent'
22
+ response = JSON.parse(@response.body)
23
+ refute_empty response
24
+ assert_response :not_found
25
+ end
26
+
27
+ test 'should trigger task on host group' do
28
+ post :play_roles, :id => @host1.hostgroup.id
29
+ response = JSON.parse(@response.body)
30
+
31
+ assert response['message']['foreman_tasks'].key?('id'),
32
+ 'task id not contained in response'
33
+ assert_equal response['message']['hostgroup']['name'],
34
+ @host1.hostgroup.name,
35
+ 'host group name not contained in response'
36
+ assert_response :success
37
+ end
38
+
39
+ test 'should trigger two host group tasks' do
40
+ post :multiple_play_roles,
41
+ :hostgroup_names => [@host1.hostgroup.name, @host2.hostgroup.name]
42
+ response = JSON.parse(@response.body)
43
+
44
+ assert response['message'].length == 2, 'should trigger two tasks'
45
+ assert_response :success
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module Api
4
+ module V2
5
+ class HostsControllerTest < ActionController::TestCase
6
+ include ::Dynflow::Testing
7
+
8
+ setup do
9
+ @host1 = FactoryGirl.create(:host)
10
+ @host2 = FactoryGirl.create(:host)
11
+ end
12
+
13
+ after do
14
+ ::ForemanTasks::Task::DynflowTask.all.each do |task|
15
+ task.destroy
16
+ task.delete
17
+ end
18
+ end
19
+
20
+ test 'should return an not_found due to non-existent host_id' do
21
+ post :play_roles, :id => 'non-existent'
22
+ response = JSON.parse(@response.body)
23
+ refute_empty response
24
+ assert_response :not_found
25
+ end
26
+
27
+ test 'should trigger task on host' do
28
+ post :play_roles, :id => @host1.id
29
+ response = JSON.parse(@response.body)
30
+
31
+ assert response['message']['foreman_tasks'].key?('id'),
32
+ 'task id not contained in response'
33
+ assert_equal response['message']['host']['name'],
34
+ @host1.name,
35
+ 'host name not contained in response'
36
+ assert_response :success
37
+ end
38
+
39
+ test 'should trigger two host tasks' do
40
+ post :multiple_play_roles, :id => [@host1.id, @host2.id]
41
+ response = JSON.parse(@response.body)
42
+
43
+ assert response['message'].length == 2, 'should trigger two tasks'
44
+ assert_response :success
45
+ end
46
+ end
47
+ end
48
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_ansible
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Lobato Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-19 00:00:00.000000000 Z
11
+ date: 2017-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -93,12 +93,18 @@ files:
93
93
  - app/assets/images/Ansible.png
94
94
  - app/controllers/ansible_roles_controller.rb
95
95
  - app/controllers/api/v2/ansible_roles_controller.rb
96
+ - app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb
97
+ - app/controllers/foreman_ansible/api/v2/hosts_controller_extensions.rb
98
+ - app/controllers/foreman_ansible/concerns/hostgroups_controller_extensions.rb
96
99
  - app/controllers/foreman_ansible/concerns/hosts_controller_extensions.rb
97
100
  - app/helpers/foreman_ansible/ansible_plugin_helper.rb
98
101
  - app/helpers/foreman_ansible/ansible_reports_helper.rb
99
102
  - app/helpers/foreman_ansible/ansible_roles_helper.rb
100
103
  - app/helpers/foreman_ansible/hosts_helper_extensions.rb
104
+ - app/lib/actions/foreman_ansible/helpers/host_common.rb
105
+ - app/lib/actions/foreman_ansible/helpers/play_roles_description.rb
101
106
  - app/lib/actions/foreman_ansible/play_host_roles.rb
107
+ - app/lib/actions/foreman_ansible/play_hostgroup_roles.rb
102
108
  - app/lib/actions/foreman_ansible/play_hosts_roles.rb
103
109
  - app/lib/proxy_api/ansible.rb
104
110
  - app/models/ansible_role.rb
@@ -111,6 +117,7 @@ files:
111
117
  - app/models/setting/ansible.rb
112
118
  - app/overrides/ansible_roles_tab.rb
113
119
  - app/overrides/hostgroup_ansible_roles_tab.rb
120
+ - app/overrides/hostgroup_play_roles.rb
114
121
  - app/overrides/report_output.rb
115
122
  - app/services/foreman_ansible/api_roles_importer.rb
116
123
  - app/services/foreman_ansible/fact_importer.rb
@@ -129,6 +136,7 @@ files:
129
136
  - app/views/api/v2/ansible_roles/index.json.rabl
130
137
  - app/views/api/v2/ansible_roles/obsolete.json.rabl
131
138
  - app/views/api/v2/ansible_roles/show.json.rabl
139
+ - app/views/foreman_ansible/ansible_roles/_hostgroup_ansible_roles_button.erb
132
140
  - app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb
133
141
  - app/views/foreman_ansible/ansible_roles/_select_tab_title.html.erb
134
142
  - app/views/foreman_ansible/api/v2/ansible_roles/import.json.rabl
@@ -159,6 +167,8 @@ files:
159
167
  - test/fixtures/sample_facts.json
160
168
  - test/functional/ansible_roles_controller_test.rb
161
169
  - test/functional/api/v2/ansible_roles_controller_test.rb
170
+ - test/functional/api/v2/hostgroups_controller_test.rb
171
+ - test/functional/api/v2/hosts_controller_test.rb
162
172
  - test/functional/hosts_controller_test.rb
163
173
  - test/support/fixture_support.rb
164
174
  - test/support/foreman_tasks/task.rb
@@ -200,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
210
  version: '0'
201
211
  requirements: []
202
212
  rubyforge_project:
203
- rubygems_version: 2.5.0
213
+ rubygems_version: 2.4.5.1
204
214
  signing_key:
205
215
  specification_version: 4
206
216
  summary: Ansible integration with Foreman (theforeman.org)
@@ -213,6 +223,8 @@ test_files:
213
223
  - test/support/foreman_test_helper_additions.rb
214
224
  - test/support/foreman_tasks/task.rb
215
225
  - test/functional/api/v2/ansible_roles_controller_test.rb
226
+ - test/functional/api/v2/hostgroups_controller_test.rb
227
+ - test/functional/api/v2/hosts_controller_test.rb
216
228
  - test/functional/ansible_roles_controller_test.rb
217
229
  - test/functional/hosts_controller_test.rb
218
230
  - test/test_plugin_helper.rb