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 +4 -4
- data/app/controllers/api/v2/ansible_roles_controller.rb +1 -2
- data/app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb +76 -0
- data/app/controllers/foreman_ansible/api/v2/hosts_controller_extensions.rb +54 -0
- data/app/controllers/foreman_ansible/concerns/hostgroups_controller_extensions.rb +32 -0
- data/app/helpers/foreman_ansible/hosts_helper_extensions.rb +18 -5
- data/app/lib/actions/foreman_ansible/helpers/host_common.rb +41 -0
- data/app/lib/actions/foreman_ansible/helpers/play_roles_description.rb +19 -0
- data/app/lib/actions/foreman_ansible/play_host_roles.rb +23 -36
- data/app/lib/actions/foreman_ansible/play_hostgroup_roles.rb +57 -0
- data/app/models/concerns/foreman_ansible/host_managed_extensions.rb +13 -0
- data/app/models/setting/ansible.rb +81 -14
- data/app/overrides/hostgroup_play_roles.rb +7 -0
- data/app/services/foreman_ansible/fact_parser.rb +6 -1
- data/app/services/foreman_ansible/inventory_creator.rb +13 -3
- data/app/services/foreman_ansible/proxy_selector.rb +8 -0
- data/app/views/foreman_ansible/ansible_roles/_hostgroup_ansible_roles_button.erb +14 -0
- data/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb +14 -4
- data/config/routes.rb +25 -0
- data/lib/foreman_ansible/engine.rb +20 -3
- data/lib/foreman_ansible/version.rb +1 -1
- data/test/functional/api/v2/hostgroups_controller_test.rb +49 -0
- data/test/functional/api/v2/hosts_controller_test.rb +48 -0
- metadata +15 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 840a69169eb96bfdb1a4c9ff9f85bb6cd6ea3b7c
|
4
|
+
data.tar.gz: 1b5f26981963dcdfe6682a97794eb24f2095ff48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
12
|
-
|
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 =>
|
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
|
-
|
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
|
-
#
|
4
|
-
# the host. It
|
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
|
-
|
11
|
-
proxy =
|
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,
|
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}') % {
|
26
|
+
_('on host %{name} through %{proxy}') % {
|
27
|
+
:name => input.fetch(:host, {})[:name],
|
28
|
+
:proxy => running_proxy_name
|
29
|
+
}
|
33
30
|
end
|
34
31
|
|
35
|
-
|
36
|
-
_('Play Ansible roles')
|
37
|
-
end
|
38
|
-
|
39
|
-
def humanized_output
|
40
|
-
continuous_output.humanize
|
41
|
-
end
|
32
|
+
private
|
42
33
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
2
|
-
|
3
|
-
|
4
|
-
self
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
77
|
+
true
|
78
|
+
end
|
14
79
|
|
15
|
-
|
16
|
-
|
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
|
-
|
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(
|
3
|
-
|
4
|
-
|
5
|
-
|
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 :
|
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
|
-
[:
|
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
|
@@ -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.
|
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:
|
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.
|
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
|