foreman_ansible 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +6 -27
  3. data/app/controllers/ansible_roles_controller.rb +55 -0
  4. data/app/controllers/api/v2/ansible_roles_controller.rb +52 -0
  5. data/app/controllers/foreman_ansible/concerns/hosts_controller_extensions.rb +11 -10
  6. data/app/helpers/foreman_ansible/ansible_plugin_helper.rb +8 -0
  7. data/app/helpers/foreman_ansible/ansible_reports_helper.rb +6 -4
  8. data/app/helpers/foreman_ansible/ansible_roles_helper.rb +17 -3
  9. data/app/helpers/foreman_ansible/hosts_helper_extensions.rb +4 -3
  10. data/app/lib/actions/foreman_ansible/play_host_roles.rb +56 -0
  11. data/app/lib/actions/foreman_ansible/play_hosts_roles.rb +26 -0
  12. data/app/lib/proxy_api/ansible.rb +28 -0
  13. data/app/models/ansible_role.rb +8 -0
  14. data/app/models/concerns/foreman_ansible/has_many_ansible_roles.rb +13 -0
  15. data/app/models/concerns/foreman_ansible/host_managed_extensions.rb +5 -1
  16. data/app/models/concerns/foreman_ansible/hostgroup_extensions.rb +19 -0
  17. data/app/models/host_ansible_role.rb +0 -2
  18. data/app/models/hostgroup_ansible_role.rb +8 -0
  19. data/app/overrides/ansible_roles_tab.rb +2 -2
  20. data/app/overrides/hostgroup_ansible_roles_tab.rb +14 -0
  21. data/app/services/foreman_ansible/api_roles_importer.rb +16 -0
  22. data/app/services/foreman_ansible/fact_importer.rb +2 -1
  23. data/app/services/foreman_ansible/inventory_creator.rb +37 -5
  24. data/app/services/foreman_ansible/playbook_creator.rb +3 -4
  25. data/app/services/foreman_ansible/proxy_selector.rb +19 -0
  26. data/app/services/foreman_ansible/roles_importer.rb +42 -15
  27. data/app/services/foreman_ansible/ui_roles_importer.rb +26 -0
  28. data/app/views/ansible_roles/import.html.erb +51 -0
  29. data/app/views/ansible_roles/index.html.erb +30 -0
  30. data/app/views/ansible_roles/welcome.html.erb +14 -0
  31. data/app/views/api/v2/ansible_roles/import.json.rabl +3 -0
  32. data/app/views/api/v2/ansible_roles/index.json.rabl +3 -0
  33. data/app/views/api/v2/ansible_roles/obsolete.json.rabl +3 -0
  34. data/app/views/api/v2/ansible_roles/show.json.rabl +3 -0
  35. data/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb +6 -0
  36. data/app/views/foreman_ansible/{hosts/_tab_title.html.erb → ansible_roles/_select_tab_title.html.erb} +0 -0
  37. data/config/routes.rb +25 -2
  38. data/db/migrate/20160705082036_create_ansible_role.rb +2 -1
  39. data/db/migrate/20160706074540_create_join_table_hosts_ansible_roles.rb +1 -0
  40. data/db/migrate/20160707195442_create_host_ansible_roles.rb +1 -0
  41. data/db/migrate/20160729094457_add_columns_to_ansible_role.rb +12 -0
  42. data/db/migrate/20160802153302_create_join_table_hostgroup_ansible_roles.rb +10 -0
  43. data/db/migrate/20160805094233_add_primary_key_hostgroup_ansible_roles.rb +6 -0
  44. data/db/seeds.d/{62-ansible_proxy_feature.rb → 62_ansible_proxy_feature.rb} +0 -0
  45. data/lib/foreman_ansible.rb +1 -0
  46. data/lib/foreman_ansible/engine.rb +54 -4
  47. data/lib/foreman_ansible/version.rb +1 -1
  48. data/locale/en/foreman_ansible.po +139 -2
  49. data/locale/foreman_ansible.pot +200 -8
  50. data/test/factories/ansible_proxy.rb +7 -0
  51. data/test/factories/ansible_roles.rb +2 -2
  52. data/test/fixtures/ansible_permissions.yml +11 -0
  53. data/test/functional/ansible_roles_controller_test.rb +16 -0
  54. data/test/functional/api/v2/ansible_roles_controller_test.rb +24 -0
  55. data/test/functional/hosts_controller_test.rb +65 -24
  56. data/test/support/fixture_support.rb +25 -0
  57. data/test/support/foreman_tasks/task.rb +47 -0
  58. data/test/support/foreman_test_helper_additions.rb +22 -0
  59. data/test/test_plugin_helper.rb +5 -2
  60. data/test/unit/ansible_role_test.rb +6 -2
  61. data/test/unit/concerns/host_managed_extensions_test.rb +37 -0
  62. data/test/unit/concerns/hostgroup_extensions_test.rb +36 -0
  63. data/test/unit/fact_importer_test.rb +11 -8
  64. data/test/unit/fact_parser_test.rb +2 -0
  65. data/test/unit/fact_sparser_test.rb +1 -0
  66. data/test/unit/helpers/foreman_ansible/ansible_reports_helper_test.rb +1 -0
  67. data/test/unit/host_ansible_role_test.rb +10 -0
  68. data/test/unit/hostgroup_ansible_role_test.rb +19 -0
  69. data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +28 -0
  70. data/test/unit/lib/proxy_api/ansible_test.rb +23 -0
  71. data/test/unit/services/api_roles_importer_test.rb +28 -0
  72. data/test/unit/services/proxy_selector_test.rb +28 -0
  73. data/test/unit/services/roles_importer_test.rb +17 -0
  74. data/test/unit/services/ui_roles_importer_test.rb +30 -0
  75. metadata +108 -14
  76. data/app/jobs/foreman_ansible/run_playbook_job.rb +0 -28
  77. data/app/services/foreman_ansible/role_player.rb +0 -26
  78. data/app/views/foreman_ansible/hosts/_tab_content.html.erb +0 -4
  79. data/lib/tasks/foreman_ansible_tasks.rake +0 -40
@@ -0,0 +1,7 @@
1
+ FactoryGirl.modify do
2
+ factory :smart_proxy do
3
+ trait :with_ansible do
4
+ features { [::Feature.find_or_create_by(:name => 'Ansible')] }
5
+ end
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  FactoryGirl.define do
2
- factory :ansible_role, :class => ForemanAnsible::AnsibleRole do
3
- sequence(:name) { |n| "ansible_role_#{n}"}
2
+ factory :ansible_role do
3
+ sequence(:name) { |n| "ansible_role_#{n}" }
4
4
  end
5
5
  end
@@ -0,0 +1,11 @@
1
+ ---
2
+ view_ansible_roles:
3
+ name: view_ansible_roles
4
+ resource_type: AnsibleRole
5
+ created_at: "2013-12-04 08:41:04.321867"
6
+ updated_at: "2013-12-04 08:41:04.321867"
7
+ destroy_ansible_roles:
8
+ name: destroy_ansible_roles
9
+ resource_type: AnsibleRole
10
+ created_at: "2013-12-04 08:41:04.321867"
11
+ updated_at: "2013-12-04 08:41:04.321867"
@@ -0,0 +1,16 @@
1
+ require 'test_plugin_helper'
2
+ # functional tests for AnsibleRolesController
3
+ class AnsibleRolesControllerTest < ActionController::TestCase
4
+ setup do
5
+ @role = FactoryGirl.create(:ansible_role)
6
+ end
7
+
8
+ basic_index_test
9
+
10
+ test 'should destroy role' do
11
+ assert_difference('AnsibleRole.count', -1) do
12
+ delete :destroy, { :id => @role.id }, set_session_user
13
+ end
14
+ assert_redirected_to ansible_roles_url
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module Api
4
+ module V2
5
+ class AnsibleRolesControllerTest < ActionController::TestCase
6
+ setup do
7
+ @role = FactoryGirl.create(:ansible_role)
8
+ end
9
+
10
+ test 'should get index' do
11
+ get :index, {}, set_session_user
12
+ response = JSON.parse(@response.body)
13
+ refute_empty response['results']
14
+ assert_response :success
15
+ end
16
+
17
+ test 'should destroy' do
18
+ delete :destroy, { :id => @role.id }, set_session_user
19
+ assert_response :ok
20
+ refute AnsibleRole.exists?(@role.id)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,36 +1,77 @@
1
1
  require 'test_plugin_helper'
2
+ require 'dynflow/testing'
3
+ Mocha::Mock.send :include, Dynflow::Testing::Mimic
4
+ require 'support/foreman_tasks/task'
2
5
 
6
+ # Ensure Hosts controller can CRUD ansible roles
3
7
  class HostsControllerExtensionsTest < ActionController::TestCase
8
+ include Support::ForemanTasks::Task
9
+
4
10
  tests ::HostsController
5
11
 
6
- setup do
7
- @role = FactoryGirl.create(:ansible_role)
8
- end
12
+ context 'role assignment' do
13
+ setup do
14
+ @role = FactoryGirl.create(:ansible_role)
15
+ end
16
+
17
+ test 'create a host with ansible roles' do
18
+ host = { :name => 'foo',
19
+ :managed => false,
20
+ :ansible_role_ids => [@role.id] }
21
+ post :create, { :host => host }, set_session_user
22
+ assert_redirected_to host_url(assigns('host'))
23
+ assert assigns('host').ansible_roles, [@role]
24
+ end
25
+
26
+ test 'update a host with ansible roles' do
27
+ host = FactoryGirl.create(:host, :managed => false)
28
+ post :update, { :id => host.id,
29
+ :host => { :ansible_role_ids => [@role.id] } },
30
+ set_session_user
31
+ assert_redirected_to host_url(assigns('host'))
32
+ assert assigns('host').ansible_roles, [@role]
33
+ end
9
34
 
10
- test 'create a host with ansible roles' do
11
- host = { :name => 'foo',
12
- :managed => false,
13
- :ansible_role_ids => [@role.id] }
14
- post :create, { :host => host },
15
- set_session_user
16
- assert_redirected_to host_url(assigns('host'))
17
- assert assigns('host').ansible_roles, [@role]
35
+ test 'delete a host with ansible roles' do
36
+ host = FactoryGirl.create(:host,
37
+ :managed => false,
38
+ :ansible_roles => [@role])
39
+ assert_include @role.hosts, host
40
+ delete :destroy, { :id => host.id }, set_session_user
41
+ assert_redirected_to hosts_url
42
+ assert @role.hosts.empty?
43
+ end
18
44
  end
19
45
 
20
- test 'update a host with ansible roles' do
21
- host = FactoryGirl.create(:host, :managed => false)
22
- post :update, { :id => host.id, :ansible_role_ids => [@role.id] },
23
- set_session_user
24
- assert_redirected_to host_url(assigns('host'))
25
- assert assigns('host').ansible_roles, [@role]
46
+ context 'playing roles' do
47
+ setup do
48
+ @host = FactoryGirl.create(:host, :managed => false)
49
+ end
50
+
51
+ test 'redirect to task if successful' do
52
+ task_stub = new_task_stub(@host)
53
+ task_to_redirect = ForemanTasks::Task.new
54
+ task_stub.stubs(:to_model).returns(task_to_redirect)
55
+ task_to_redirect.stubs(:persisted?).returns(true)
56
+ task_to_redirect.stubs(:id).returns(1)
57
+ get :play_roles, { :id => @host.id }, set_session_user
58
+ end
59
+
60
+ test 'shows errors when not successful' do
61
+ HostsController.any_instance.expects(:async_task).
62
+ raises(::Foreman::Exception.new('Oh foo'))
63
+ get :play_roles, { :id => @host.id }, set_session_user
64
+ assert flash[:error].present?
65
+ assert_redirected_to host_path(@host)
66
+ end
26
67
  end
27
68
 
28
- test 'delete a host with ansible roles' do
29
- host = FactoryGirl.create(:host, :managed => false,
30
- :ansible_roles => [@role])
31
- assert_include @role.hosts, host
32
- delete :destroy, { :id => host.id }, set_session_user
33
- assert_redirected_to hosts_url
34
- assert @role.hosts.empty?
69
+ private
70
+
71
+ def new_task_stub(host)
72
+ assert_async_task(::Actions::ForemanAnsible::PlayHostRoles,
73
+ host) do |action_host|
74
+ assert_equal host, action_host
75
+ end
35
76
  end
36
77
  end
@@ -0,0 +1,25 @@
1
+ module ForemanAnsible
2
+ module PluginFixtures
3
+ FIXTURE_MAPPING = {
4
+ :ansible_permissions => :permissions
5
+ }.freeze
6
+
7
+ def self.add_fixtures(new_fixture_path)
8
+ FileUtils.cp(Dir.glob("#{Rails.root}/test/fixtures/*"), new_fixture_path)
9
+ copy_plugin_fixtures new_fixture_path
10
+ end
11
+
12
+ def self.copy_plugin_fixtures(new_fixture_path)
13
+ FIXTURE_MAPPING.each do |key, value|
14
+ fixture_path = "#{ForemanAnsible::Engine.root}/test/fixtures/#{key}.yml"
15
+ break unless File.exist?(fixture_path)
16
+ File.open("#{new_fixture_path}/#{value}.yml", 'a') do |file|
17
+ File.open(fixture_path, 'r').each do |line|
18
+ next if line =~ /---/
19
+ file.write line
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ module Support
2
+ module ForemanTasks
3
+ module Task
4
+ def stub_tasks!
5
+ @controller.stubs(:sync_task).returns(build_task_stub)
6
+ @controller.stubs(:async_task).returns(build_task_stub)
7
+ end
8
+
9
+ def build_task_stub
10
+ task_attrs = [:id, :label, :pending, :username, :started_at, :ended_at,
11
+ :state, :result, :progress, :input, :humanized,
12
+ :cli_example].inject({}) { |a, e| a.update e => nil }
13
+ task_attrs[:output] = {}
14
+
15
+ stub('task', task_attrs).mimic!(::ForemanTasks::Task)
16
+ end
17
+
18
+ def assert_async_task(expected_action_class, *args_expected)
19
+ assert_foreman_task(true, expected_action_class, *args_expected)
20
+ end
21
+
22
+ def assert_sync_task(expected_action_class, *args_expected)
23
+ assert_foreman_task(false, expected_action_class, *args_expected)
24
+ end
25
+
26
+ def assert_foreman_task(async, expected_action_class, *args_expected)
27
+ block ||= block_from_args(args_expected)
28
+ method = async ? :async_task : :sync_task
29
+ task_stub = build_task_stub
30
+ @controller.
31
+ expects(method).
32
+ with do |action_class, *args|
33
+ expected_action_class == action_class && block.call(*args)
34
+ end.
35
+ returns(task_stub)
36
+ task_stub
37
+ end
38
+
39
+ private
40
+
41
+ def block_from_args(args_expected)
42
+ ->(*_) { true } if args_expected.empty?
43
+ ->(*args) { args == args_expected }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ require "#{ForemanAnsible::Engine.root}/test/support/fixture_support"
2
+ # loads the permissions for foreman_ansible and makes them available in tests
3
+ module AnsiblePermissionTestCase
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ extend ActiveRecord::TestFixtures
8
+
9
+ new_fixture_path = Dir.mktmpdir('ansible_fixtures')
10
+ self.fixture_path = new_fixture_path
11
+ ForemanAnsible::PluginFixtures.add_fixtures(new_fixture_path)
12
+ fixtures(:all)
13
+ load_fixtures(ActiveRecord::Base)
14
+ end
15
+ end
16
+
17
+ module ActiveSupport
18
+ #:nodoc
19
+ class TestCase
20
+ include AnsiblePermissionTestCase
21
+ end
22
+ end
@@ -1,8 +1,11 @@
1
1
  require 'test_helper'
2
2
 
3
3
  def sample_facts_file
4
- File.read(File.join(
5
- ForemanAnsible::Engine.root, 'test', 'fixtures', 'sample_facts.json'))
4
+ File.read(
5
+ File.join(
6
+ ForemanAnsible::Engine.root, 'test', 'fixtures', 'sample_facts.json'
7
+ )
8
+ )
6
9
  end
7
10
 
8
11
  def facts_json
@@ -1,8 +1,12 @@
1
- require 'test_plugin_helper'
1
+ require 'test_plugin_helper'
2
2
 
3
+ # Tests for the behavior of Ansible Role, currently only validations
3
4
  class AnsibleRoleTest < ActiveSupport::TestCase
4
5
  should have_many(:host_ansible_roles)
5
6
  should have_many(:hosts).through(:host_ansible_roles).dependent(:destroy)
6
7
  should validate_presence_of(:name)
7
- should validate_uniqueness_of(:name)
8
+ context 'with new role' do
9
+ subject { AnsibleRole.new(:name => 'foo') }
10
+ should validate_uniqueness_of(:name)
11
+ end
8
12
  end
@@ -0,0 +1,37 @@
1
+ require 'test_plugin_helper'
2
+
3
+ # Tests for the behavior of Host with roles, checks inheritance, etc
4
+ class HostManagedExtensionsTest < ActiveSupport::TestCase
5
+ before do
6
+ @role1 = FactoryGirl.create(:ansible_role)
7
+ @role2 = FactoryGirl.create(:ansible_role)
8
+ @role3 = FactoryGirl.create(:ansible_role)
9
+
10
+ @hostgroup_parent = FactoryGirl.create(:hostgroup,
11
+ :ansible_roles => [@role2])
12
+ @hostgroup = FactoryGirl.create(:hostgroup, :parent => @hostgroup_parent)
13
+ @host = FactoryGirl.build_stubbed(:host, :ansible_roles => [@role1])
14
+ end
15
+
16
+ describe '#all_ansible_roles' do
17
+ test 'returns assigned roles for host without a hostgroup' do
18
+ @host.all_ansible_roles.must_equal [@role1]
19
+ end
20
+
21
+ test 'returns assigned and inherited roles for host with a hostgroup' do
22
+ @host.hostgroup = @hostgroup
23
+ @host.all_ansible_roles.must_equal [@role1, @role2]
24
+ end
25
+ end
26
+
27
+ describe '#inherited_ansible_roles' do
28
+ test 'returns empty array for host without hostgroup' do
29
+ @host.inherited_ansible_roles.must_equal []
30
+ end
31
+
32
+ test 'returns roles inherited from a hostgroup' do
33
+ @host.hostgroup = @hostgroup
34
+ @host.inherited_ansible_roles.must_equal [@role2]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_plugin_helper'
2
+
3
+ # Tests for the behavior of Hostgroup with roles, checks inheritance, etc
4
+ class HostgroupExtensionsTest < ActiveSupport::TestCase
5
+ before do
6
+ @role1 = FactoryGirl.create(:ansible_role)
7
+ @role2 = FactoryGirl.create(:ansible_role)
8
+ @role3 = FactoryGirl.create(:ansible_role)
9
+
10
+ @hostgroup_parent = FactoryGirl.create(:hostgroup,
11
+ :ansible_roles => [@role2])
12
+ @hostgroup = FactoryGirl.create(:hostgroup, :ansible_roles => [@role1])
13
+ end
14
+
15
+ describe '#all_ansible_roles' do
16
+ test 'returns assigned roles without any parent hostgroup' do
17
+ @hostgroup.all_ansible_roles.must_equal [@role1]
18
+ end
19
+
20
+ test 'returns assigned and inherited roles with a parent hostgroup' do
21
+ @hostgroup.parent = @hostgroup_parent
22
+ @hostgroup.all_ansible_roles.must_equal [@role1, @role2]
23
+ end
24
+ end
25
+
26
+ describe '#inherited_ansible_roles' do
27
+ test 'returns empty array for hostgroup without any parent' do
28
+ @hostgroup.inherited_ansible_roles.must_equal []
29
+ end
30
+
31
+ test 'returns roles inherited from a chain of parents' do
32
+ @hostgroup.parent = @hostgroup_parent
33
+ @hostgroup.inherited_ansible_roles.must_equal [@role2]
34
+ end
35
+ end
36
+ end
@@ -1,22 +1,25 @@
1
1
  require 'test_plugin_helper'
2
2
 
3
3
  module ForemanAnsible
4
+ # Test for the facts importer - only verify that given
5
+ # a set of facts it's able to import them
4
6
  class FactImporterTest < ActiveSupport::TestCase
5
7
  setup do
6
- @host = FactoryGirl.build_stubbed(:host)
8
+ @host = FactoryGirl.build(:host)
7
9
  end
8
10
 
9
11
  test 'add new facts adds all fact names in the fixture' do
10
12
  @fact_importer = FactImporter.new(@host, facts_json)
11
13
  facts_to_be_added = FactSparser.sparse(facts_json[:ansible_facts]).keys +
12
- FactSparser.unsparse(facts_json[:ansible_facts]).keys
14
+ FactSparser.unsparse(facts_json[:ansible_facts]).keys
13
15
  @fact_importer.send(:add_new_facts)
14
- assert (facts_to_be_added - FactName.all.map(&:name)).empty?
16
+ assert((facts_to_be_added - FactName.all.map(&:name)).empty?)
15
17
  end
16
18
 
17
19
  test 'missing_facts returns facts we do not have in the database' do
18
20
  @fact_importer = FactImporter.new(@host, facts_json)
19
- @fact_importer.expects(:db_facts).returns('ansible_cmdline' => 'fakevalue')
21
+ @fact_importer.expects(:db_facts).
22
+ returns('ansible_cmdline' => 'fakevalue')
20
23
  refute @fact_importer.send(:missing_facts).include?('ansible_cmdline')
21
24
  end
22
25
 
@@ -36,12 +39,12 @@ module ForemanAnsible
36
39
  @fact_importer.counters[:added] = 0
37
40
  assert_difference('@host.fact_values.count', 1) do
38
41
  @fact_importer.send(:add_fact_value, 'missing_value', missing_fact)
42
+ @host.save
43
+ # We have to save the host in order to ensure @host.fact_values.count
44
+ # resolves properly (otherwise) :add_fact_value just won't save the
45
+ # relation
39
46
  end
40
47
  end
41
48
  end
42
-
43
- test 'add_fact_value works for hosts that have not been created yet' do
44
- end
45
49
  end
46
50
  end
47
-
@@ -1,6 +1,8 @@
1
1
  require 'test_plugin_helper'
2
2
 
3
3
  module ForemanAnsible
4
+ # Checks sample Ansible facts to see if it can assign them to
5
+ # Host properties
4
6
  class FactParserTest < ActiveSupport::TestCase
5
7
  setup do
6
8
  @facts_parser = ForemanAnsible::FactParser.new(facts_json)
@@ -1,6 +1,7 @@
1
1
  require 'test_plugin_helper'
2
2
 
3
3
  module ForemanAnsible
4
+ # Tests for checking if FactSparser can sparse a hash and unsparse it
4
5
  class FactSparserTest < ActiveSupport::TestCase
5
6
  setup do
6
7
  @original_os_facts = { 'operatingsystem' => { 'major' => 20, 'minor' => 1,