foreman-mco 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +15 -0
  2. data/Rakefile +40 -0
  3. data/app/assets/javascripts/foreman_mco/application.js +22 -0
  4. data/app/assets/javascripts/foreman_mco/mco_hosts_extensions.js +49 -0
  5. data/app/assets/stylesheets/foreman-mco/application.css +13 -0
  6. data/app/controllers/foreman_mco/command_histories_controller.rb +26 -0
  7. data/app/controllers/foreman_mco/command_statuses_controller.rb +49 -0
  8. data/app/controllers/foreman_mco/commands_controller.rb +48 -0
  9. data/app/controllers/foreman_mco/detailed_command_histories_controller.rb +27 -0
  10. data/app/helpers/foreman_mco/application_helper.rb +4 -0
  11. data/app/helpers/foreman_mco/command_histories_helper.rb +6 -0
  12. data/app/models/concerns/foreman_mco/hosts_helper.rb +25 -0
  13. data/app/models/foreman_mco/command/base.rb +24 -0
  14. data/app/models/foreman_mco/command/filter.rb +15 -0
  15. data/app/models/foreman_mco/command/package_commands.rb +33 -0
  16. data/app/models/foreman_mco/command/ping.rb +11 -0
  17. data/app/models/foreman_mco/command/puppet_commands.rb +31 -0
  18. data/app/models/foreman_mco/command/service_commands.rb +43 -0
  19. data/app/models/foreman_mco/command_status.rb +27 -0
  20. data/app/models/foreman_mco/commands.rb +4 -0
  21. data/app/models/foreman_mco/host_command_status.rb +12 -0
  22. data/app/models/services/foreman_mco/mco_proxy_api.rb +57 -0
  23. data/app/models/setting/mco.rb +15 -0
  24. data/app/overrides/enable_mco_actions_on_hosts.rb +9 -0
  25. data/app/views/foreman_mco/command_histories/index.html.erb +46 -0
  26. data/app/views/foreman_mco/commands/install_package.html.erb +9 -0
  27. data/app/views/foreman_mco/commands/ping.html.erb +6 -0
  28. data/app/views/foreman_mco/commands/puppet_disable.html.erb +8 -0
  29. data/app/views/foreman_mco/commands/puppet_enable.html.erb +8 -0
  30. data/app/views/foreman_mco/commands/puppet_runonce.html.erb +8 -0
  31. data/app/views/foreman_mco/commands/service_status.html.erb +9 -0
  32. data/app/views/foreman_mco/commands/start_service.html.erb +9 -0
  33. data/app/views/foreman_mco/commands/stop_service.html.erb +9 -0
  34. data/app/views/foreman_mco/commands/uninstall_package.html.erb +9 -0
  35. data/app/views/foreman_mco/detailed_command_histories/index.html.erb +26 -0
  36. data/app/views/layouts/foreman-mco/application.html.erb +14 -0
  37. data/config/routes.rb +24 -0
  38. data/db/migrate/20131030154603_create_command_statuses.rb +15 -0
  39. data/db/migrate/20131031113547_add_mcollective_proxy_feature.rb +8 -0
  40. data/db/migrate/20131125123644_create_host_command_statuses.rb +17 -0
  41. data/db/migrate/20131209192923_add_discovered_agents.rb +20 -0
  42. data/lib/foreman-mco.rb +4 -0
  43. data/lib/foreman-mco/engine.rb +60 -0
  44. data/lib/foreman-mco/version.rb +3 -0
  45. data/lib/tasks/foreman-mco_tasks.rake +4 -0
  46. data/test/dummy/README.rdoc +261 -0
  47. data/test/dummy/Rakefile +7 -0
  48. data/test/dummy/app/assets/javascripts/application.js +15 -0
  49. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  50. data/test/dummy/app/controllers/application_controller.rb +3 -0
  51. data/test/dummy/app/helpers/application_helper.rb +2 -0
  52. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/test/dummy/config.ru +4 -0
  54. data/test/dummy/config/application.rb +59 -0
  55. data/test/dummy/config/boot.rb +10 -0
  56. data/test/dummy/config/database.yml +25 -0
  57. data/test/dummy/config/environment.rb +5 -0
  58. data/test/dummy/config/environments/development.rb +37 -0
  59. data/test/dummy/config/environments/production.rb +67 -0
  60. data/test/dummy/config/environments/test.rb +37 -0
  61. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/test/dummy/config/initializers/inflections.rb +15 -0
  63. data/test/dummy/config/initializers/mime_types.rb +5 -0
  64. data/test/dummy/config/initializers/secret_token.rb +7 -0
  65. data/test/dummy/config/initializers/session_store.rb +8 -0
  66. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  67. data/test/dummy/config/locales/en.yml +5 -0
  68. data/test/dummy/config/routes.rb +4 -0
  69. data/test/dummy/public/404.html +26 -0
  70. data/test/dummy/public/422.html +26 -0
  71. data/test/dummy/public/500.html +25 -0
  72. data/test/dummy/public/favicon.ico +0 -0
  73. data/test/dummy/script/rails +6 -0
  74. data/test/foreman-mco_test.rb +7 -0
  75. data/test/integration/navigation_test.rb +10 -0
  76. data/test/test_helper.rb +15 -0
  77. metadata +181 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzdkZDcyMTM0YmFkYmJhNDFjMzMzYTY5ZTc2ZmFhYmM2ZDU5ZjFhOQ==
5
+ data.tar.gz: !binary |-
6
+ Y2YyM2M5ZThlMDExNzdjZjhkYzhhNGVjOTFjZTVmZjMxMzA1OTdkMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZjY2MWZhODg5ZTM3YzAyYTQ2OTg2ZTNlMzc4ZjViYjNjZjQ3NDI2Y2ZkYmMy
10
+ MGRmYjYxNmQyNTgwOTU0OTgzOGU5YWVmZTkxNGE2YjU2YjhhNTM5MzhhYjkw
11
+ MTdjOTEyMGE2OGVmMWE4OTg1ZTM3YmIwZmMxZjhjNWFkNGI3NTA=
12
+ data.tar.gz: !binary |-
13
+ NjkxZTllM2FiMDE4MWY0ZmVhNzZkMDczMjQ4YmI3MmYyYWVhMTcxMDY4ZTBm
14
+ OWRhZTZkM2UzZGVmODJlYzM5Mzc3YTc4Njk1Y2NiNjZiNjkyNDVmNzgxYjNh
15
+ YzI4Mzc3NTliYTkwOTY3MzdkODE0NjAzMDI4ZmVkYzk0OWE5NmQ=
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'ForemanMco'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,22 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
16
+ //= require scoped_search
17
+ //= require twitter/bootstrap
18
+ //= require topbar
19
+ //= require two-pane
20
+ //= require vendor
21
+ //= require about
22
+ //= require jquery.extentions
@@ -0,0 +1,49 @@
1
+ $(function() {
2
+ $('#mco_submit_multiple a').click(function(){
3
+ if ($(this).hasClass('dropdown-toggle')) { return false }
4
+ if ($(this).hasClass('disabled')) { return false }
5
+ var title = $(this).attr('data-original-title');
6
+ var url = $(this).attr('href') + "?" + $.param({host_ids: $.foremanSelectedHosts});
7
+ $('#confirmation-modal .modal-header h3').text(title);
8
+ $('#confirmation-modal .modal-body').empty().append("<img class='modal-loading' src='/assets/spinner.gif'>");
9
+ $('#confirmation-modal').modal({show: "true", backdrop: "static"});
10
+ $("#confirmation-modal .modal-body").load(url + " #content",
11
+ function(response, status, xhr) {
12
+ $("#loading").hide();
13
+ $('#submit_multiple').val('');
14
+ var b = $("#confirmation-modal .btn-primary");
15
+ if ($(response).find('#content form select').size() > 0)
16
+ b.addClass("disabled").attr("disabled", true);
17
+ else
18
+ b.removeClass("disabled").attr("disabled", false);
19
+ });
20
+ return false;
21
+ });
22
+
23
+ $('#confirmation-modal .btn-primary').click(function(){
24
+ $("#confirmation-modal form").submit();
25
+ $('#confirmation-modal').modal('hide');
26
+ });
27
+
28
+ $('#confirmation-modal .secondary').click(function(){
29
+ $('#confirmation-modal').modal('hide');
30
+ });
31
+ });
32
+
33
+ original_toggle_actions = toggle_actions
34
+ function mco_toggle_actions() {
35
+ original_toggle_actions();
36
+ var dropdown = $("ul.dropdown-menu li a.mco-filtered");
37
+ if ($.foremanSelectedHosts.length == 0) {
38
+ dropdown.each(function() {
39
+ $(this).addClass('disabled')
40
+ $(this).css({'color': 'lightgray'})
41
+ });
42
+ } else {
43
+ dropdown.each(function() {
44
+ $(this).removeClass('disabled')
45
+ $(this).css({'color': 'black'})
46
+ });
47
+ }
48
+ }
49
+ toggle_actions = mco_toggle_actions
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,26 @@
1
+ module ForemanMco
2
+ class CommandHistoriesController < ::ApplicationController
3
+ include Foreman::Controller::TaxonomyMultiple
4
+ include Foreman::Controller::AutoCompleteSearch
5
+
6
+ SEARCHABLE_ACTIONS= %w[index]
7
+
8
+ def index
9
+ begin
10
+ search = CommandStatus.search_for(params[:search],:order => params[:order])
11
+ rescue => e
12
+ error e.to_s
13
+ search = CommandStatus.search_for ''
14
+ end
15
+ @command_statuses = search.paginate(:page => params[:page])
16
+ end
17
+
18
+ def detailed
19
+ @details = HostCommandStatus.where(:command_status_id => params[:id])
20
+ end
21
+
22
+ def model_of_controller
23
+ CommandStatus
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ module ForemanMco
2
+ class CommandStatusesController < ::Api::V2::BaseController
3
+ include ::Foreman::Controller::SmartProxyAuth
4
+
5
+ add_puppetmaster_filters([:update])
6
+
7
+ before_filter :find_status, :only => [:update]
8
+ before_filter :parse_results, :only => [:update]
9
+
10
+ def update
11
+ process_response @command_status.update_attributes!(params[:command_status])
12
+ end
13
+
14
+ def find_status
15
+ @command_status = ForemanMco::CommandStatus.find_by_jid(params[:id])
16
+ render_error 'not_found', :status => :not_found and return false unless @command_status
17
+ end
18
+
19
+ def parse_results
20
+ return if params[:command_status][:result].nil?
21
+ @host_statuses = params[:command_status][:result].each {|host_status| @command_status.host_command_statuses.build(to_foreman_schema(host_status))}
22
+ end
23
+
24
+ def to_foreman_schema(a_hash)
25
+ to_ret = {}
26
+ our_schema = { "sender" => "host", "statuscode" => "status_code", "statusmsg" => "status_message", "data" => "result" }
27
+
28
+ a_hash.each_pair do |k,v|
29
+ our_schema.has_key?(k) ? to_ret[our_schema[k]] = v : to_ret[k] = v
30
+ end
31
+
32
+ to_ret
33
+ end
34
+
35
+ def require_mco_proxy_or_login
36
+ if auth_smart_proxy(SmartProxy.mcollective_proxies, false)
37
+ set_admin_user
38
+ return true
39
+ end
40
+
41
+ require_login
42
+ unless User.current
43
+ render_error 'access_denied', :status => :forbidden unless performed? and api_request?
44
+ return false
45
+ end
46
+ authorize
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ require 'foreman_mco/commands'
2
+
3
+ module ForemanMco
4
+ class CommandsController < ::ApplicationController
5
+ COMMANDS = [:install_package, :uninstall_package, :service_status, :start_service,
6
+ :stop_service, :install_package, :uninstall_package,
7
+ :puppet_runonce, :puppet_enable, :puppet_disable,
8
+ :ping]
9
+
10
+ attr_reader :command
11
+ before_filter :find_command, :only => [:submit_command]
12
+ before_filter :filter_by_hosts, :only => COMMANDS
13
+
14
+ COMMANDS.each do |cmd|
15
+ define_method(cmd) {}
16
+ end
17
+
18
+ #TODO: a possible race condition here -- proxy *can* process remote job before we get to CommandStatus creation
19
+ def submit_command
20
+ if @command.execute
21
+ process_success :success_redirect => :back, :success_msg => _("'%s' command has been queued up for execution") % command
22
+ else
23
+ process_error :redirect => :back, :error_msg => _("'%s' command has not been queued up: %s") % [command, 'fail!']
24
+ end
25
+ rescue => e
26
+ process_error :redirect => :back, :error_msg => _("'%s' command has not been queued up: %s") % [command, e]
27
+ end
28
+
29
+ def find_command
30
+ return process_error :redirect => :back, :error_msg => _("No command to execute") unless params[:command]
31
+
32
+ command_hash = params[:command]
33
+ clazz = ("ForemanMco::Command::" + command_hash[:command].camelize).constantize
34
+ @command = clazz.new(command_hash)
35
+
36
+ return process_error(:redirect => :back, :object => @command, :error_msg => _("Invalid command parametres: %s") % command.errors.full_messages) unless @command.valid?
37
+
38
+ @command
39
+ rescue NameError => e
40
+ return process_error(:redirect => :back, :object => @command, :error_msg => _("Invalid command '%s'") % params[:command])
41
+ end
42
+
43
+ def filter_by_hosts
44
+ @hosts = params[:host_ids].nil? ? [] : Host.select(:name).where(:id => params[:host_ids])
45
+ @filters = @hosts.collect(&:name).collect {|n| ::ForemanMco::Command::Filter.identity_filter(n)}.to_json
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module ForemanMco
2
+ class DetailedCommandHistoriesController < ::ApplicationController
3
+ include Foreman::Controller::TaxonomyMultiple
4
+ include Foreman::Controller::AutoCompleteSearch
5
+
6
+ SEARCHABLE_ACTIONS= %w[index]
7
+
8
+ def index
9
+ begin
10
+ search = HostCommandStatus.where(:command_status_id => params[:command_history_id]).search_for(params[:search],:order => params[:order])
11
+ rescue => e
12
+ error e.to_s
13
+ search = HostCommandStatus.where(:command_status_id => params[:command_history_id])
14
+ end
15
+ @details = search.paginate(:page => params[:page])
16
+ @hosts = Host.my_hosts.select([:id, :name]).where(:name => @details.collect(&:host)).index_by(&:name)
17
+ end
18
+
19
+ def controller_name
20
+ "command_history_detailed_command_histories"
21
+ end
22
+
23
+ def model_of_controller
24
+ HostCommandStatus
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module ForemanMco
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module ForemanMco::CommandHistoriesHelper
2
+ def any_commands_run?
3
+ return true unless (@command_statuses.count == 0)
4
+ false
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module ForemanMco::HostsHelper
2
+ extend ActiveSupport::Concern
3
+
4
+ def mco_multiple_actions_select
5
+ actions = []
6
+
7
+ if Setting[:use_mco]
8
+ actions << [_('Ping'), ping_commands_path, 'pencil']
9
+ actions << [_('Install Package'), install_package_commands_path, 'pencil', 'mco-filtered']
10
+ actions << [_('Uninstall Package'), uninstall_package_commands_path, 'pencil', 'mco-filtered']
11
+ actions << [_('Service Status'), service_status_commands_path, 'pencil', 'mco-filtered']
12
+ actions << [_('Start Service'), start_service_commands_path, 'pencil', 'mco-filtered']
13
+ actions << [_('Stop Service'), stop_service_commands_path, 'pencil', 'mco-filtered']
14
+ actions << [_('Puppet Runonce'), puppet_runonce_commands_path, 'pencil', 'mco-filtered']
15
+ actions << [_('Puppet Enable'), puppet_enable_commands_path, 'pencil', 'mco-filtered']
16
+ actions << [_('Puppet Disable'), puppet_disable_commands_path, 'pencil', 'mco-filtered']
17
+ end
18
+
19
+ content_tag :span, :id => 'mco_submit_multiple' do
20
+ select_action_button( _("Select MCO Action"), actions.map do |action|
21
+ link_to(icon_text(action[2], action[0]) , action[1], :class=>'btn ' + (action.try(:[], 3) || ''), :title => _("%s - The following hosts are about to be changed") % action[0])
22
+ end.flatten)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ module ForemanMco::Command
2
+ class Base
3
+ include ::ActiveModel::Validations
4
+ attr_reader :filters
5
+
6
+ def initialize(attrs = {})
7
+ @filters = attrs[:filters] || []
8
+ end
9
+
10
+ def execute
11
+ response = remote_call
12
+ ::ForemanMco::CommandStatus.create!(:command => self.to_s, :jid => response.split("/tasks/")[1])
13
+ end
14
+
15
+ def mco_proxy
16
+ return @mco_proxy if @mco_proxy
17
+
18
+ db_proxy_record = SmartProxy.joins(:features).where("features.name" => "MCollective").first
19
+ raise ::Foreman::Exception.new(N_("There are no configured mcollective proxies")) unless db_proxy_record
20
+
21
+ @mco_proxy = ForemanMco::McoProxyApi.new(:url => db_proxy_record.url)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module ForemanMco::Command
2
+ class Filter
3
+ def self.identity_filter(val)
4
+ {:identity => val}
5
+ end
6
+
7
+ def self.class_filter(val)
8
+ {:class => val}
9
+ end
10
+
11
+ def self.fact_filter(val)
12
+ {:fact => val}
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module ForemanMco::Command
2
+ class BasePackage < Base
3
+ include ::ActiveModel::Validations
4
+
5
+ attr_reader :package_name
6
+ validates :package_name, :presence => true
7
+
8
+ def initialize(attrs)
9
+ super
10
+ @package_name = attrs[:package_name]
11
+ end
12
+ end
13
+
14
+ class InstallPackage < BasePackage
15
+ def remote_call
16
+ mco_proxy.install_package(@package_name, filters)
17
+ end
18
+
19
+ def to_s
20
+ "package install #{package_name}"
21
+ end
22
+ end
23
+
24
+ class UninstallPackage < BasePackage
25
+ def remote_call
26
+ mco_proxy.uninstall_package(@package_name, filters)
27
+ end
28
+
29
+ def to_s
30
+ "package uninstall #{package_name}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ module ForemanMco::Command
2
+ class Ping < Base
3
+ def remote_call
4
+ mco_proxy.ping(filters)
5
+ end
6
+
7
+ def to_s
8
+ "ping"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module ForemanMco::Command
2
+ class PuppetRunOnce < Base
3
+ def remote_call
4
+ mco_proxy.puppet_runonce(filters)
5
+ end
6
+
7
+ def to_s
8
+ "puppet runonce"
9
+ end
10
+ end
11
+
12
+ class PuppetEnable < Base
13
+ def remote_call
14
+ mco_proxy.puppet_enable(filters)
15
+ end
16
+
17
+ def to_s
18
+ "puppet start"
19
+ end
20
+ end
21
+
22
+ class PuppetDisable < Base
23
+ def remote_call
24
+ mco_proxy.puppet_disable(filters)
25
+ end
26
+
27
+ def to_s
28
+ "puppet stop"
29
+ end
30
+ end
31
+ end