foreman_host_reports 0.0.4 → 1.0.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -447
  3. data/app/controllers/api/v2/host_reports_controller.rb +39 -20
  4. data/app/controllers/concerns/foreman_host_reports/controller/hosts_controller_extensions.rb +18 -0
  5. data/app/controllers/concerns/foreman_host_reports/controller/parameters/host_report.rb +1 -1
  6. data/app/controllers/host_reports_controller.rb +32 -2
  7. data/app/helpers/concerns/foreman_host_reports/hosts_helper_extensions.rb +25 -0
  8. data/app/models/concerns/foreman_host_reports/host_extensions.rb +6 -0
  9. data/app/models/host_report.rb +15 -0
  10. data/app/models/host_status/host_report_status.rb +185 -0
  11. data/app/views/api/v2/host_reports/main.json.rabl +1 -2
  12. data/config/routes.rb +2 -4
  13. data/db/migrate/20220113064436_rename_status_summaries.rb +12 -0
  14. data/lib/foreman_host_reports/engine.rb +11 -5
  15. data/lib/foreman_host_reports/version.rb +1 -1
  16. data/test/controllers/api/v2/host_reports_controller_test.rb +30 -67
  17. data/test/factories/foreman_host_reports_factories.rb +13 -5
  18. data/test/model/host_report_status_test.rb +204 -0
  19. data/test/test_plugin_helper.rb +4 -2
  20. data/webpack/__mocks__/foremanReact/components/Pagination/index.js +2 -0
  21. data/webpack/fills.js +23 -0
  22. data/webpack/global_index.js +2 -0
  23. data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/Formatters/statusFormatter.js +3 -4
  24. data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/StatusCell.js +1 -1
  25. data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/HostReportsTable.js +2 -10
  26. data/webpack/src/Router/HostReports/IndexPage/IndexPage.js +0 -1
  27. data/webpack/src/Router/HostReports/IndexPage/IndexPageActions.js +5 -4
  28. data/webpack/src/Router/HostReports/IndexPage/IndexPageHelpers.js +1 -1
  29. data/webpack/src/Router/HostReports/IndexPage/__tests__/HostReportsIndexPage.test.js +3 -4
  30. data/webpack/src/Router/HostReports/IndexPage/__tests__/__snapshots__/HostReportsIndexPage.test.js.snap +4 -6
  31. data/webpack/src/Router/HostReports/IndexPage/constants.js +4 -3
  32. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Ansible.js +62 -27
  33. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Components/EmptyLogsRow.js +27 -0
  34. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Components/RawMsgModal.js +41 -0
  35. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Puppet.js +38 -37
  36. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/index.js +10 -3
  37. data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogsFilter/index.js +56 -65
  38. data/webpack/src/Router/HostReports/ShowPage/ShowPage.js +34 -8
  39. data/webpack/src/Router/HostReports/constants.js +2 -0
  40. data/webpack/src/components/ReportsTab/ReportsTable.js +117 -0
  41. data/webpack/src/components/ReportsTab/helpers.js +155 -0
  42. data/webpack/src/components/ReportsTab/index.js +132 -0
  43. metadata +18 -19
  44. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -4
@@ -3,6 +3,7 @@
3
3
  module Api
4
4
  module V2
5
5
  class HostReportsController < V2::BaseController
6
+ include Foreman::TelemetryHelper
6
7
  include Api::Version2
7
8
  include Foreman::Controller::CsvResponder
8
9
  include Foreman::Controller::SmartProxyAuth
@@ -23,7 +24,7 @@ module Api
23
24
  @host_reports = resource_scope_for_index(options)
24
25
  end
25
26
 
26
- api :GET, '/host_report/:id', N_('Show host report details')
27
+ api :GET, '/host_reports/:id', N_('Show host report details')
27
28
  param :id, :identifier, required: true
28
29
  def show
29
30
  @host_report = resource_scope.find(params[:id])
@@ -34,38 +35,55 @@ module Api
34
35
  param :host, String, required: true, desc: N_("Hostname of the report's host origin")
35
36
  param :format, HostReport.formats.keys, required: false, desc: N_('Format of the report, e.g. Ansible')
36
37
  param :reported_at, String, required: true, desc: N_('UTC time of the report')
37
- param :applied, Integer, required: false, desc: N_('Number of applied resources or tasks')
38
- param :failed, Integer, required: false, desc: N_('Number of failed resources or tasks')
39
- param :pending, Integer, required: false, desc: N_('Number of pending resources or tasks')
40
- param :other, Integer, required: false, desc: N_('Number of other resources or tasks')
38
+ param :change, Integer, required: false, desc: N_('Summary count of actions with change (semantics is different for each report type)')
39
+ param :nochange, Integer, required: false, desc: N_('Summary count of actions without change (semantics is different for each report type)')
40
+ param :failure, Integer, required: false, desc: N_('Summary count of actions with failure (semantics is different for each report type)')
41
41
  param :body, String, required: true, desc: N_('String with JSON formatted body of the report')
42
- param :proxy, String, required: false, desc: N_('Hostname of the proxy processed the report')
42
+ param :proxy, String, required: false, desc: N_('Hostname of the proxy processed the report (will be detected from SSL cert for HTTPS requests)')
43
43
  param :keywords, Array, of: String, required: false, desc: N_('A list of keywords to associate with the report for better searching')
44
44
  end
45
45
  end
46
46
 
47
- api :POST, '/host_report/', N_('Create a host report')
47
+ api :POST, '/host_reports/', N_('Create a host report')
48
48
  param_group :host_report, as: :create
49
-
50
49
  def create
50
+ result = nil
51
+ # version is unused at the moment (version = 1)
51
52
  params[:host_report].delete(:version)
53
+ # check existing host and proxy
54
+ raise("Unknown host: #{@hostname}") unless params[:host_report][:host_id]
55
+ # fetch the body
52
56
  the_body = params[:host_report].delete(:body)
53
57
  if the_body && !the_body.is_a?(String)
54
58
  logger.warn "Report body not as a string, serializing JSON"
55
59
  the_body = JSON.pretty_generate(the_body)
56
60
  end
61
+ # process keywords
57
62
  keywords = params[:host_report].delete(:keywords)
58
- @host_report = HostReport.new(host_report_params.merge(body: the_body))
59
- if keywords.present?
60
- keywords_to_insert = keywords.each_with_object([]) do |n, ks|
61
- ks << { name: n }
63
+ report_keyword_ids = []
64
+ telemetry_duration_histogram(:host_report_create_keywords, :ms) do
65
+ if keywords.present?
66
+ keywords_to_insert = keywords.each_with_object([]) do |n, ks|
67
+ ks << { name: n }
68
+ end
69
+ ReportKeyword.upsert_all(keywords_to_insert, unique_by: :name)
70
+ report_keyword_ids = ReportKeyword.where(name: keywords).distinct.pluck(:id)
62
71
  end
63
- ReportKeyword.upsert_all(keywords_to_insert, unique_by: :name)
64
- @host_report.report_keyword_ids = ReportKeyword.where(name: keywords).distinct.pluck(:id)
65
72
  end
66
- result = @host_report.save
67
- @host_report.body = nil
73
+ # create new record
74
+ @host_report = HostReport.new(host_report_params.merge(body: the_body, report_keyword_ids: report_keyword_ids))
75
+ telemetry_duration_histogram(:host_report_create, :ms) do
76
+ result = @host_report.save
77
+ end
78
+ # refresh status and last_report flag
79
+ telemetry_duration_histogram(:host_report_create_refresh, :ms) do
80
+ time = Time.parse(params[:host_report][:reported_at]).utc
81
+ @host.update_attribute(:last_report, time) if @host.last_report.nil? || @host.last_report.utc < time
82
+ @host.refresh_statuses([HostStatus::HostReportStatus])
83
+ end
68
84
  process_response result
85
+ rescue StandardError => e
86
+ render_exception(e, :status => :unprocessable_entity)
69
87
  end
70
88
 
71
89
  api :DELETE, '/host_reports/:id', N_('Delete a host report')
@@ -86,10 +104,11 @@ module Api
86
104
  private
87
105
 
88
106
  def resolve_ids
89
- hostname = params[:host_report].delete(:host)
90
- proxyname = params[:host_report].delete(:proxy)
91
- params[:host_report][:host_id] ||= Host.find_by(name: hostname)&.id
92
- params[:host_report][:proxy_id] ||= SmartProxy.unscoped.find_by(name: proxyname)&.id
107
+ @hostname = params[:host_report].delete(:host)
108
+ @proxyname = params[:host_report].delete(:proxy)
109
+ @host = Host.find_by(name: @hostname)
110
+ params[:host_report][:host_id] ||= @host&.id
111
+ params[:host_report][:proxy_id] = detected_proxy&.id # provided by SmartProxyAuth concern
93
112
  end
94
113
 
95
114
  def resource_scope(options = {})
@@ -0,0 +1,18 @@
1
+ module ForemanHostReports
2
+ module Controller
3
+ module HostsControllerExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ module Overrides
7
+ def preload_reports
8
+ @last_report_ids = HostReport.where(:host_id => @hosts.map(&:id)).reorder('').group(:host_id).maximum(:id)
9
+ @last_reports = HostReport.where(:id => @last_report_ids.values)
10
+ end
11
+ end
12
+
13
+ included do
14
+ prepend Overrides
15
+ end
16
+ end
17
+ end
18
+ end
@@ -11,7 +11,7 @@ module ForemanHostReports
11
11
  Foreman::ParameterFilter.new(::HostReport).tap do |filter|
12
12
  # body is permitted in controller
13
13
  filter.permit :format, :version, :host, :proxy, :reported_at,
14
- :proxy_id, :host_id, :applied, :failed, :pending, :other
14
+ :proxy_id, :host_id, :change, :nochange, :failure
15
15
  filter.permit :keywords => []
16
16
  end
17
17
  end
@@ -2,6 +2,28 @@
2
2
 
3
3
  class HostReportsController < ::ApplicationController
4
4
  include Foreman::Controller::AutoCompleteSearch
5
+ def index
6
+ respond_to do |format|
7
+ format.html do
8
+ render '/react/index'
9
+ end
10
+
11
+ format.json do
12
+ reports = resource_base_search_and_page
13
+ render json: {
14
+ itemCount: reports.count,
15
+ reports: reports.map do |r|
16
+ r.attributes.except('body').merge(
17
+ keywords: r.report_keywords.map(&:name),
18
+ can_delete: can_delete?(r),
19
+ can_view: can_view?(r),
20
+ status: r.status
21
+ )
22
+ end,
23
+ }, status: :ok
24
+ end
25
+ end
26
+ end
5
27
 
6
28
  def show
7
29
  @host_report = resource_scope.find(params[:id])
@@ -29,8 +51,8 @@ class HostReportsController < ::ApplicationController
29
51
  reported_at: @host_report.reported_at,
30
52
  },
31
53
  permissions: {
32
- can_delete: authorized_for(auth_object: @host_report, authorizer: authorizer, permission: "destroy_#{controller_permission}"),
33
- can_view: authorized_for(auth_object: @host_report, authorizer: authorizer, permission: "view_#{controller_permission}"),
54
+ can_delete: can_delete?(@host_report),
55
+ can_view: can_view?(@host_report),
34
56
  },
35
57
  }, status: :ok
36
58
  end
@@ -43,4 +65,12 @@ class HostReportsController < ::ApplicationController
43
65
  options[:permission] = :view_host_reports
44
66
  super(options).my_reports
45
67
  end
68
+
69
+ def can_delete?(report)
70
+ authorized_for(auth_object: report, authorizer: authorizer, permission: "destroy_#{controller_permission}")
71
+ end
72
+
73
+ def can_view?(report)
74
+ authorized_for(auth_object: report, authorizer: authorizer, permission: "view_#{controller_permission}")
75
+ end
46
76
  end
@@ -0,0 +1,25 @@
1
+ module ForemanHostReports
2
+ module HostsHelperExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ module Overrides
6
+ def last_report_column(record)
7
+ opts = { :rel => "twipsy" }
8
+ date = record.last_report.nil? ? '' : "#{date_time_absolute_value(record.last_report)}, "
9
+ time = record.last_report? ? date_time_relative_value(record.last_report) : ""
10
+ if @last_report_ids[record.id]
11
+ opts["data-original-title"] = date + _("view last report details")
12
+ link_to_if_authorized(time, hash_for_host_report_path(:id => record.last_host_report_object_any_format&.id), opts)
13
+ else
14
+ opts.merge!(:disabled => true, :class => "disabled", :onclick => 'return false')
15
+ opts["data-original-title"] = date + _("report already deleted") unless record.last_report.nil?
16
+ link_to_if_authorized(time, hash_for_host_reports_path, opts)
17
+ end
18
+ end
19
+ end
20
+
21
+ included do
22
+ prepend Overrides
23
+ end
24
+ end
25
+ end
@@ -4,6 +4,12 @@ module ForemanHostReports
4
4
 
5
5
  included do
6
6
  has_many :host_reports, foreign_key: :host_id, class_name: 'HostReport', inverse_of: :host, dependent: :destroy
7
+ has_one :last_host_report_object_any_format, -> { order("#{HostReport.table_name}.reported_at DESC, #{HostReport.table_name}.id").limit(1) }, foreign_key: :host_id, class_name: 'HostReport', inverse_of: :host, dependent: :delete
8
+ has_one :host_report_status_object, class_name: 'HostStatus::HostReportStatus', foreign_key: :host_id, inverse_of: :host, dependent: :delete
9
+
10
+ scoped_search relation: :host_reports, on: :change, rename: :report_changes, only_explicit: true
11
+ scoped_search relation: :host_reports, on: :nochange, rename: :report_nochanges, only_explicit: true
12
+ scoped_search relation: :host_reports, on: :failure, rename: :report_failures, only_explicit: true
7
13
  end
8
14
  end
9
15
  end
@@ -24,6 +24,9 @@ class HostReport < ApplicationRecord
24
24
  scoped_search relation: :proxy, on: :name, complete_value: true, rename: :proxy
25
25
  scoped_search relation: :organization, on: :name, complete_value: true, rename: :organization
26
26
  scoped_search relation: :location, on: :name, complete_value: true, rename: :location
27
+ scoped_search on: :change, aliases: %i[changed changes]
28
+ scoped_search on: :nochange, aliases: %i[unchanged nochanges]
29
+ scoped_search on: :failure, aliases: %i[failed failures]
27
30
  scoped_search on: :reported_at, complete_value: true, default_order: :desc, rename: :reported, only_explicit: true, aliases: %i[last_report reported_at]
28
31
  scoped_search on: :format, complete_value: { plain: 0, puppet: 1, ansible: 2 }
29
32
  # This is to simulate has_many :report_keywords relation for scoped_search library to work
@@ -52,4 +55,16 @@ class HostReport < ApplicationRecord
52
55
  conditions: sanitize_sql_for_conditions(["host_reports.report_keyword_ids @> ?", "{#{keyword_ids.join(',')}}"]),
53
56
  }
54
57
  end
58
+
59
+ def status
60
+ if failure&.positive?
61
+ :failure
62
+ elsif change&.positive?
63
+ :change
64
+ elsif nochange&.positive?
65
+ :nochange
66
+ else
67
+ :empty
68
+ end
69
+ end
55
70
  end
@@ -0,0 +1,185 @@
1
+ module HostStatus
2
+ # rubocop:disable Style/GuardClause
3
+ class HostReportStatus < Status
4
+ def last_report
5
+ self.last_report = host.last_host_report_object_any_format unless @last_report_set
6
+ @last_report
7
+ end
8
+
9
+ def last_report=(report)
10
+ @last_report_set = true
11
+ @last_report = report
12
+ end
13
+
14
+ # <host report fields>
15
+ def change
16
+ last_report&.change || 0
17
+ end
18
+
19
+ def nochange
20
+ last_report&.nochange || 0
21
+ end
22
+
23
+ def failure
24
+ last_report&.failure || 0
25
+ end
26
+
27
+ def change?
28
+ change.positive?
29
+ end
30
+
31
+ def nochange?
32
+ nochange.positive?
33
+ end
34
+
35
+ def failure?
36
+ failure.positive?
37
+ end
38
+ # </host report fields>
39
+
40
+ # <legacy report compatibility fields>
41
+ def restarted
42
+ 0
43
+ end
44
+
45
+ def failed_restarts
46
+ 0
47
+ end
48
+
49
+ def skipped
50
+ 0
51
+ end
52
+ # </legacy report compatibility fields>
53
+
54
+ def expected_report_interval
55
+ (reported_format_interval.presence || default_report_interval).to_i.minutes
56
+ end
57
+
58
+ def reported_format_interval
59
+ if host.params.key? "#{last_report.format.downcase}_interval"
60
+ host.params["#{last_report.format.downcase}_interval"]
61
+ else
62
+ Setting[:"#{last_report.format.downcase}_interval"]
63
+ end
64
+ end
65
+
66
+ def out_of_sync?
67
+ if (host && !host.enabled?) || no_reports? || out_of_sync_disabled?
68
+ false
69
+ else
70
+ !reported_at.nil? && reported_at < (Time.now.utc - expected_report_interval)
71
+ end
72
+ end
73
+
74
+ def no_reports?
75
+ host && last_report.nil?
76
+ end
77
+
78
+ def self.status_name
79
+ N_("Configuration")
80
+ end
81
+
82
+ # Constants are bit-mask friendly in case we want to query them in the DB
83
+ UNKNOWN = -0b000000000000010000000000000000 # -65536
84
+ FAILURES = -0b000000000000000000000000000001 # -1
85
+ EMPTY = 0b000000000000000000000000000000 # 0
86
+ NO_CHANGES = 0b000000000000000000000100000000 # 256
87
+ CHANGES = 0b000000000000010000000000000000 # 65536
88
+
89
+ LABELS = {
90
+ FAILURES => N_("Failure(s)"),
91
+ EMPTY => N_("Empty"),
92
+ NO_CHANGES => N_("No changes"),
93
+ CHANGES => N_("Changes applied"),
94
+ }.freeze
95
+
96
+ def to_label(_options = {})
97
+ if host && !host.enabled
98
+ return N_("Alerts disabled")
99
+ elsif out_of_sync?
100
+ return N_("Out of sync")
101
+ end
102
+
103
+ LABELS.fetch(to_status, N_("Unknown config status"))
104
+ end
105
+
106
+ def to_global(options = {})
107
+ handle_options(options)
108
+
109
+ if failure?
110
+ HostStatus::Global::ERROR
111
+ elsif out_of_sync?
112
+ HostStatus::Global::WARN
113
+ elsif no_reports? && (host.configuration? || Setting[:always_show_configuration_status])
114
+ HostStatus::Global::WARN
115
+ else
116
+ HostStatus::Global::OK
117
+ end
118
+ end
119
+
120
+ def to_status(options = {})
121
+ handle_options(options)
122
+
123
+ if host&.enabled && last_report.present?
124
+ if last_report.failure.positive?
125
+ FAILURES
126
+ elsif last_report.change.positive?
127
+ CHANGES
128
+ elsif last_report.nochange.positive?
129
+ NO_CHANGES
130
+ else
131
+ EMPTY
132
+ end
133
+ else
134
+ UNKNOWN
135
+ end
136
+ end
137
+
138
+ def relevant?(options = {})
139
+ handle_options(options)
140
+
141
+ host.configuration? || last_report.present? || Setting[:always_show_configuration_status]
142
+ end
143
+
144
+ def status_link
145
+ return @status_link if defined?(@status_link)
146
+ return @status_link = nil if last_report.nil?
147
+ return @status_link = nil unless User.current.can?(:view_host_reports, last_report, false)
148
+
149
+ @status_link = last_report && Rails.application.routes.url_helpers.host_report_path(last_report)
150
+ end
151
+
152
+ private
153
+
154
+ # Configuration status can be calculated from database state, but also reports can be
155
+ # passed in via options. In that case, report is matched with the host and set.
156
+ # Don't ask me why this is implemented this way, this is copy-paste from the original
157
+ # ConfigurationStatus in Foreman core.
158
+ def handle_options(options)
159
+ if options.key?(:last_reports) && !options[:last_reports].nil?
160
+ cached_report = options[:last_reports].find { |r| r.host_id == host_id }
161
+ self.last_report = cached_report
162
+ end
163
+ end
164
+
165
+ def update_timestamp
166
+ self.reported_at = last_report.try(:reported_at) || Time.now.utc
167
+ end
168
+
169
+ def default_report_interval
170
+ if host.params.key? 'outofsync_interval'
171
+ host.params['outofsync_interval']
172
+ else
173
+ Setting[:outofsync_interval]
174
+ end
175
+ end
176
+
177
+ def out_of_sync_disabled?
178
+ Setting[:"#{last_report.format.downcase}_out_of_sync_disabled"]
179
+ end
180
+ end
181
+ # rubocop:enable Style/GuardClause
182
+ end
183
+
184
+ HostStatus.status_registry.delete(HostStatus::ConfigurationStatus)
185
+ HostStatus.status_registry.add(HostStatus::HostReportStatus)
@@ -5,8 +5,7 @@ object @host_report
5
5
  extends 'api/v2/host_reports/base'
6
6
  extends 'api/v2/layouts/permissions'
7
7
 
8
- attributes :format, :host_id, :proxy_id, :reported_at, :applied, :failed,
9
- :pending, :other
8
+ attributes :format, :host_id, :proxy_id, :reported_at, :change, :nochange, :failure
10
9
 
11
10
  node(:host_name) do |report|
12
11
  report.host.name
data/config/routes.rb CHANGED
@@ -1,13 +1,11 @@
1
1
  Rails.application.routes.draw do
2
- match '/host_reports' => 'react#index', via: :get
3
-
4
2
  resources :hosts do
5
3
  member do
6
4
  match 'host_reports', to: 'react#index', via: :get
7
5
  end
8
6
  end
9
7
 
10
- resources :host_reports, only: %i[show] do
8
+ resources :host_reports, only: %i[index show] do
11
9
  collection do
12
10
  get 'auto_complete_search'
13
11
  end
@@ -15,7 +13,7 @@ Rails.application.routes.draw do
15
13
 
16
14
  namespace :api, defaults: { format: 'json' } do
17
15
  scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v2/,
18
- constraints: ApiConstraints.new(version: 2, default: true) do
16
+ constraints: ApiConstraints.new(version: 2, default: true) do
19
17
  resources :host_reports, only: %i[index show create destroy] do
20
18
  collection do
21
19
  get 'export'
@@ -0,0 +1,12 @@
1
+ class RenameStatusSummaries < ActiveRecord::Migration[6.0]
2
+ def change
3
+ remove_column :host_reports, :applied, :integer
4
+ remove_column :host_reports, :pending, :integer
5
+ remove_column :host_reports, :other, :integer
6
+ remove_column :host_reports, :failed, :integer
7
+
8
+ add_column :host_reports, :change, :integer, default: 0
9
+ add_column :host_reports, :nochange, :integer, default: 0
10
+ add_column :host_reports, :failure, :integer, default: 0
11
+ end
12
+ end
@@ -18,7 +18,7 @@ module ForemanHostReports
18
18
 
19
19
  initializer 'foreman_host_reports.register_plugin', :before => :finisher_hook do |_app|
20
20
  Foreman::Plugin.register :foreman_host_reports do
21
- requires_foreman '>= 3.0.0'
21
+ requires_foreman '>= 3.2.0'
22
22
 
23
23
  apipie_documented_controllers ["#{ForemanHostReports::Engine.root}/app/controllers/api/v2/*.rb"]
24
24
  # Add Global files for extending foreman-core components and routes
@@ -36,10 +36,14 @@ module ForemanHostReports
36
36
 
37
37
  # add menu entry
38
38
  menu :top_menu, :host_reports, url: '/host_reports',
39
- url_hash: { controller: :host_reports, action: :index },
40
- caption: N_('Host Reports'),
41
- parent: :monitor_menu,
42
- before: :reports
39
+ url_hash: { controller: :host_reports, action: :index },
40
+ caption: N_('Host Reports'),
41
+ parent: :monitor_menu,
42
+ before: :reports
43
+
44
+ add_histogram_telemetry(:host_report_create_keywords, 'Time spent processing keywords (ms)')
45
+ add_histogram_telemetry(:host_report_create_refresh, 'Time spent processing status refresh (ms)')
46
+ add_histogram_telemetry(:host_report_create, 'Time spent saving record (ms)')
43
47
  end
44
48
  end
45
49
 
@@ -48,6 +52,8 @@ module ForemanHostReports
48
52
  config.to_prepare do
49
53
  Host::Managed.include ForemanHostReports::HostExtensions
50
54
  SmartProxy.include ForemanHostReports::HostExtensions
55
+ ::HostsController.include ForemanHostReports::Controller::HostsControllerExtensions
56
+ ::HostsHelper.include ForemanHostReports::HostsHelperExtensions
51
57
  rescue => e
52
58
  Rails.logger.warn "ForemanHostReports: skipping engine hook (#{e})"
53
59
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanHostReports
2
- VERSION = '0.0.4'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end