foreman_abrt 0.0.1

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.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +191 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/javascripts/abrt_reports.js +2 -0
  6. data/app/assets/stylesheets/abrt_reports.css +4 -0
  7. data/app/controllers/abrt_reports_controller.rb +62 -0
  8. data/app/controllers/api/v2/abrt_reports_controller.rb +37 -0
  9. data/app/helpers/abrt_reports_helper.rb +9 -0
  10. data/app/models/abrt_report.rb +120 -0
  11. data/app/models/abrt_report_response_destination.rb +5 -0
  12. data/app/models/abrt_report_response_solution.rb +5 -0
  13. data/app/models/concerns/foreman_abrt/host_extensions.rb +18 -0
  14. data/app/models/setting/abrt.rb +28 -0
  15. data/app/overrides/add_host_bug_report_tab.rb +11 -0
  16. data/app/views/abrt_reports/_host_tab.html.erb +1 -0
  17. data/app/views/abrt_reports/_host_tab_pane.html.erb +21 -0
  18. data/app/views/abrt_reports/_list.html.erb +33 -0
  19. data/app/views/abrt_reports/_show_response.html.erb +59 -0
  20. data/app/views/abrt_reports/index.html.erb +3 -0
  21. data/app/views/abrt_reports/show.html.erb +35 -0
  22. data/config/routes.rb +22 -0
  23. data/db/migrate/20140414095631_create_abrt_reports.rb +33 -0
  24. data/lib/foreman_abrt.rb +5 -0
  25. data/lib/foreman_abrt/engine.rb +61 -0
  26. data/lib/foreman_abrt/version.rb +3 -0
  27. data/lib/tasks/foreman_abrt_tasks.rake +21 -0
  28. data/test/factories/foreman_abrt_factories.rb +5 -0
  29. data/test/fixtures/abrt_reports.yml +11 -0
  30. data/test/functional/abrt_reports_controller_test.rb +7 -0
  31. data/test/test_plugin_helper.rb +6 -0
  32. data/test/unit/abrt_report_test.rb +7 -0
  33. data/test/unit/foreman_abrt_test.rb +12 -0
  34. data/test/unit/helpers/abrt_reports_helper_test.rb +4 -0
  35. metadata +98 -0
data/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # ForemanAbrt
2
+
3
+ This plugin allows your Foreman instance to receive bug reports generated on
4
+ your hosts by [ABRT](https://github.com/abrt/abrt) (Automatic Bug Reporting
5
+ Tool). These reports can be inspected and eventually forwarded to the ABRT
6
+ server.
7
+
8
+ ## Overview
9
+
10
+ 1. Whenever a bug is caught by ABRT on the managed host, it is sent to the Smart
11
+ proxy instead of being sent directly to the ABRT server.
12
+ 2. The Smart proxy receives the report and stores it to the disk. Stored
13
+ reports are then sent to Foreman every 30 minutes (by means of cron job).
14
+ The proxy may optionally:
15
+ - Forward the report to an ABRT server immediately after being received.
16
+ Server's response is discarded.
17
+ - Aggregate stored reports prior to sending them to the Foreman. Only one
18
+ instance of set of similar reports from a host is sent, together with
19
+ number of the reports in the set.
20
+ 3. Foreman receives the aggregated report and stores it to the database. The
21
+ reports can be inspected and forwarded to the ABRT server. If the server
22
+ responds with additional information about the report, such as links to bug
23
+ trackers or suggested solutions, it is displayed alongside the report.
24
+
25
+ ```
26
+
27
+ +--------------+ ureport +-------------+ aggregated ureports +---------+
28
+ | Managed host | ---------> | Smart proxy | ---------------------> | Foreman |
29
+ +--------------+ +-------------+ +---------+
30
+ : : ^
31
+ : ureport : :
32
+ : : : server response
33
+ : V :
34
+ : ureport +-------------+
35
+ + - - - - - - - - - - - - - ->| ABRT server |
36
+ +-------------+
37
+
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ To be able to see ABRT bug reports in your Foreman instance, you need to
43
+ install the plugin itself, install ABRT plugin for your smart proxies and
44
+ configure your hosts to send the bug reports to their smart proxy.
45
+
46
+ ### Installing the Foreman plugin
47
+
48
+ To install the Foreman plugin, follow the [plugin installation
49
+ instructions](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin).
50
+
51
+ ### Setting up smart proxies
52
+
53
+ You need smart-proxy version 1.6 or later (e.g. installed from git) in order to
54
+ install the ABRT plugin.
55
+
56
+ - If you want to use the report aggregation (reports are grouped on the proxy
57
+ and the same reports are sent only once), you have to install the satyr ruby
58
+ gem:
59
+
60
+ ```
61
+ ~# yum install satyr rubygem-ffi
62
+ ~# gem install satyr
63
+ ```
64
+
65
+ - Install the ABRT smart-proxy plugin:
66
+
67
+ ```
68
+ ~$ git clone https://github.com/abrt/smart-proxy-abrt.git
69
+ ~$ cd smart-proxy-abrt
70
+ ~/smart-proxy-abrt$ gem build smart_proxy_abrt.gemspec
71
+ ~/smart-proxy-abrt$ yum install rubygems-devel rubygem-minitest
72
+ ~/smart-proxy-abrt$ rpmbuild --define "_sourcedir `pwd`" -ba extra/rubygem-smart_proxy_abrt.spec
73
+ ~/smart-proxy-abrt$ yum install ~/rpmbuild/RPMS/noarch/rubygem-smart_proxy_abrt*rpm
74
+ ```
75
+
76
+ - Edit `/etc/foreman-proxy/settings.yml` to configure the main Foreman host,
77
+ which is normally not needed. Assuming Foreman runs on `f19-foreman.tld` the
78
+ file should contain following:
79
+
80
+ ```
81
+ # URL of your foreman instance
82
+ :foreman_url: https://f19-foreman.tld
83
+ ```
84
+
85
+ - Rename `/etc/foreman-proxy/settings.d/abrt.yml.example` to `abrt.yml` to enable the ABRT proxy plugin:
86
+ ```
87
+ ~$ cd /etc/foreman-proxy/settings.d/
88
+ /etc/foreman-proxy/settings.d/$ mv abrt.yml.example abrt.yml
89
+ ```
90
+
91
+ - Start the smart-proxy.
92
+
93
+ ```
94
+ ~# systemctl start foreman-proxy
95
+ ```
96
+
97
+ ### Configuring hosts to send bug reports to Foreman
98
+
99
+ - Make sure that ABRT is installed and running.
100
+ ```
101
+ ~# yum install abrt-cli
102
+ ~# systemctl start abrtd
103
+ ~# systemctl start abrt-ccpp
104
+ ```
105
+
106
+ - Configure ABRT reporting destination -
107
+ `/etc/libreport/plugins/ureport.conf` should contain following:
108
+
109
+ ```
110
+ # URL of your foreman-proxy, with /abrt path.
111
+ URL = https://f19-smartproxy.tld:8443/abrt
112
+ # Do not verify server certificate.
113
+ SSLVerify = no
114
+ # This asks puppet config for the path to the ceritificates. you can
115
+ # explicitly provide path by using /path/to/cert:/path/to/key on the
116
+ # right hand side.
117
+ SSLClientAuth = puppet
118
+ ```
119
+
120
+ - Enable autoreporting by running the following command:
121
+
122
+ ```
123
+ ~# abrt-auto-reporting enabled
124
+ ```
125
+
126
+ ### Verifying that the setup works
127
+
128
+ You can verify your setup by crashing something on your managed host. We have a
129
+ set of utilities in the Fedora repository especially for this purpose:
130
+
131
+ ```
132
+ ~# yum -y install will-crash
133
+ ~$ will_segfault
134
+ Will segfault.
135
+ Segmentation fault (core dumped)
136
+ ```
137
+
138
+ After a couple of seconds, a new file should appear in
139
+ `/var/spool/foreman-proxy/abrt-send` on the smart-proxy host. The reports from
140
+ the smart-proxy are sent to the Foreman in batches every half an hour (by
141
+ default). This means that within half an hour you should be able to see the bug
142
+ report in the Foreman web interface. You can send the reports to Foreman
143
+ manually by running the `smart-proxy-abrt-send` command.
144
+
145
+ ## Usage
146
+
147
+ The list of received bug reports can be accessed by clicking on *Bug reports*
148
+ link in the *Monitor* menu. To see detailed information for a report, click on
149
+ its reported date.
150
+
151
+ List of bug reports coming from a particular host is also displayed on the page
152
+ with the details about the host in the *Bug reports* tab on the left.
153
+
154
+ ### Forwarding the report to the ABRT server
155
+
156
+ On the bug report details page you can forward the bug report to an actual
157
+ ABRT server by clicking the *Forward report* button. The ABRT server may
158
+ respond with some information it knows about the bug, such as the list of URLs
159
+ related to the bug (e.g. Bugzilla link) and list of possible solutions to the
160
+ problem that caused the bug to occur.
161
+
162
+ The forwarding functionality may have to be configured in *Abrt* tab of the
163
+ configuration screen (*Administer*->*Settings*).
164
+
165
+ ## TODO
166
+
167
+ - Graph with number of reports vs. time on the dashboard.
168
+ - Forwarding reports on the proxy - drop it altogether, or forward the server
169
+ response to the client?
170
+ - Use puppet to configure managed hosts to send ureports to Foreman.
171
+ - Figure out how to import the Puppet CA cert on managed hosts to the system
172
+ certificates so that the reporter-ureport doesn't have to skip server
173
+ certificate validation.
174
+
175
+ ## Copyright
176
+
177
+ Copyright (c) 2014 Red Hat
178
+
179
+ This program is free software: you can redistribute it and/or modify
180
+ it under the terms of the GNU General Public License as published by
181
+ the Free Software Foundation, either version 3 of the License, or
182
+ (at your option) any later version.
183
+
184
+ This program is distributed in the hope that it will be useful,
185
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
186
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
187
+ GNU General Public License for more details.
188
+
189
+ You should have received a copy of the GNU General Public License
190
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
191
+
data/Rakefile ADDED
@@ -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 = 'ForemanAbrt'
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,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,62 @@
1
+ class AbrtReportsController < ApplicationController
2
+ include Foreman::Controller::AutoCompleteSearch
3
+ before_filter :setup_search_options, :only => :index
4
+
5
+ def action_permission
6
+ case params[:action]
7
+ when 'json'
8
+ :view
9
+ when 'forward'
10
+ :forward
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ # GET /abrt_reports
17
+ def index
18
+ @abrt_reports = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page]).includes(:host)
19
+ end
20
+
21
+ # GET /abrt_reports/42
22
+ def show
23
+ @abrt_report = resource_base.find(params[:id])
24
+ end
25
+
26
+ # DELETE /abrt_reports/42
27
+ def destroy
28
+ @abrt_report = resource_base.find(params[:id])
29
+ if @abrt_report.destroy
30
+ notice _("Successfully deleted bug report.")
31
+ else
32
+ error @abrt_reports.errors.full_messages.join("<br/>")
33
+ end
34
+ redirect_to abrt_reports_url
35
+ end
36
+
37
+ # GET /abrt_reports/42/json
38
+ def json
39
+ @abrt_report = resource_base.find(params[:id])
40
+ render :json => JSON.parse(@abrt_report.json)
41
+ end
42
+
43
+ # POST /abrt_reports/42/forward
44
+ def forward
45
+ @abrt_report = resource_base.find(params[:id])
46
+ redirect_to abrt_report_url(@abrt_report)
47
+
48
+ begin
49
+ response = @abrt_report.forward
50
+ rescue => e
51
+ error _("Server rejected our report: #{e.message}") and return
52
+ end
53
+
54
+ begin
55
+ @abrt_report.add_response response
56
+ rescue => e
57
+ error _("Cannot process server response: #{e.message}") and return
58
+ end
59
+
60
+ notice _("Report successfully forwarded")
61
+ end
62
+ end
@@ -0,0 +1,37 @@
1
+ module Api
2
+ module V2
3
+ class AbrtReportsController < V2::BaseController
4
+ include Api::Version2
5
+ include Foreman::Controller::SmartProxyAuth
6
+
7
+ add_puppetmaster_filters :create
8
+
9
+ def create
10
+ begin
11
+ abrt_reports = AbrtReport.import(params[:abrt_report])
12
+ rescue => e
13
+ logger.error "Failed to import ABRT report: #{e.message}"
14
+ logger.debug e.backtrace.join("\n")
15
+ render :json => { "message" => e.message }, :status => :unprocessable_entity
16
+ return
17
+ end
18
+
19
+ if Setting[:abrt_automatically_forward]
20
+ abrt_reports.each do |report|
21
+ begin
22
+ response = report.forward
23
+ report.add_response response
24
+ rescue => e
25
+ logger.error "Failed to forward ABRT report: #{e.message}"
26
+ end
27
+ end
28
+ end
29
+
30
+ # Do not report forwarding error to the proxy, we can manually resend
31
+ # it later and the proxy probably can't do anything about it anyway.
32
+ render :json => { "message" => "OK" }
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ module AbrtReportsHelper
2
+ def simple_format_if_multiline str
3
+ if str.include? "\n"
4
+ simple_format str
5
+ else
6
+ str
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,120 @@
1
+ class AbrtReport < ActiveRecord::Base
2
+ include Authorizable
3
+
4
+ audited :associated_with => :host, :allow_mass_assignment => true
5
+
6
+ belongs_to_host
7
+ has_one :environment, :through => :host
8
+ has_one :hostgroup, :through => :host
9
+
10
+ has_many :abrt_report_response_destinations, :dependent => :destroy
11
+ has_many :abrt_report_response_solutions, :dependent => :destroy
12
+
13
+ validates :json, :presence => true
14
+ validates :count, :numericality => { :only_integer => true, :greater_than => 0 }
15
+ validates :duphash, :format => { :with => /\A[0-9a-fA-F]+\z/ }, :allow_blank => true
16
+
17
+ scoped_search :in => :host, :on => :name, :complete_value => true, :rename => :host
18
+ scoped_search :in => :environment, :on => :name, :complete_value => true, :rename => :environment
19
+ scoped_search :in => :hostgroup, :on => :name, :complete_value => true, :rename => :hostgroup
20
+ scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_fullname
21
+ scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_title
22
+
23
+ scoped_search :on => :reason, :complete_value => true
24
+ scoped_search :on => :duphash, :complete_value => true
25
+ scoped_search :on => :count, :complete_value => true, :only_explicit => true
26
+ scoped_search :on => :reported_at, :complete_value => true, :default_order => :desc, :rename => :reported, :only_explicit => true
27
+
28
+ scoped_search :on => :forwarded_at, :complete_value => true, :rename => :forwarded, :only_explicit => true
29
+ scoped_search :on => :response_known, :complete_value => true, :rename => :known, :only_explicit => true
30
+ scoped_search :on => :response_message, :complete_value => true, :rename => :response
31
+ scoped_search :on => :response_bthash, :complete_value => true, :rename => :bthash
32
+
33
+ scoped_search :in => :abrt_report_response_destination, :on => :reporter, :complete_value => true, :rename => :destination_reporter
34
+ scoped_search :in => :abrt_report_response_destination, :on => :desttype, :complete_value => true, :rename => :destination_type
35
+ scoped_search :in => :abrt_report_response_destination, :on => :value , :complete_value => true, :rename => :destination_value
36
+
37
+ scoped_search :in => :abrt_report_response_solution, :on => :cause, :complete_value => true, :rename => :solution_cause
38
+ scoped_search :in => :abrt_report_response_solution, :on => :note, :complete_value => true, :rename => :solution_note
39
+ scoped_search :in => :abrt_report_response_solution, :on => :url, :complete_value => true, :rename => :solution_url
40
+
41
+ def self.import(json)
42
+ host = Host.find_by_name(json[:host])
43
+ reports = []
44
+ AbrtReport.transaction do
45
+ json[:reports].each do |report|
46
+ # import one report
47
+ reason = nil # try extracting reason from the report
48
+ reason ||= report[:full][:reason] if report[:full].has_key? :reason
49
+ reports << AbrtReport.create!(:host => host, :count => report[:count], :json => report[:full].to_json,
50
+ :duphash => report[:duphash], :reason => reason,
51
+ :reported_at => report[:reported_at])
52
+ end
53
+ end
54
+ reports
55
+ end
56
+
57
+ # XXX is the network communication acceptable in a model?
58
+ def forward
59
+ request_params = {
60
+ :timeout => 60,
61
+ :open_timeout => 10,
62
+ :verify_ssl => Setting[:abrt_server_verify_ssl] ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
63
+ }
64
+
65
+ if Setting[:abrt_server_ssl_ca_file] && !Setting[:abrt_server_ssl_ca_file].empty?
66
+ request_params[:ssl_ca_file] = Setting[:abrt_server_ssl_ca_file]
67
+ end
68
+
69
+ # XXX what certificates will be used if communicating with e.g. customer portal?
70
+ if Setting[:abrt_server_ssl_certificate] && !Setting[:abrt_server_ssl_certificate].empty? \
71
+ && Setting[:abrt_server_ssl_priv_key] && !Setting[:abrt_server_ssl_priv_key].empty?
72
+ request_params[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(Setting[:abrt_server_ssl_certificate]))
73
+ request_params[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(Setting[:abrt_server_ssl_priv_key]))
74
+ end
75
+
76
+ resource = RestClient::Resource.new(Setting[:abrt_server_url], request_params)
77
+ response = resource['reports/new/'].post({:file => json, :multipart => true}, :content_type => :json, :accept => :json)
78
+
79
+ if response.code != 202
80
+ logger.error "Failed to forward bug report: #{response.code}: #{response.to_str}"
81
+ raise ::Foreman::Exception.new(N_("Failed to forward bug report: %s: %s", response.code, response.to_str))
82
+ end
83
+
84
+ JSON.parse(response.body)
85
+ end
86
+
87
+ def add_response(response)
88
+ self.transaction do
89
+ abrt_report_response_solutions.clear
90
+ abrt_report_response_destinations.clear
91
+
92
+ self.forwarded_at = Time.now
93
+ self.response_known = response['result']
94
+ self.response_message = response['message']
95
+ self.response_bthash = response['bthash']
96
+
97
+ if response['solutions']
98
+ response['solutions'].each do |solution|
99
+ abrt_report_response_solutions.create!(
100
+ :cause => solution['cause'],
101
+ :note => solution['note'],
102
+ :url => solution['url']
103
+ )
104
+ end
105
+ end
106
+
107
+ if response['reported_to']
108
+ response['reported_to'].each do |destination|
109
+ abrt_report_response_destinations.create!(
110
+ :desttype => destination['type'],
111
+ :value => destination['value'],
112
+ :reporter => destination['reporter']
113
+ )
114
+ end
115
+ end
116
+
117
+ save!
118
+ end
119
+ end
120
+ end