foreman_rh_cloud 2.0.10 → 2.0.11

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -2
  3. data/app/controllers/insights_cloud/hits_controller.rb +17 -0
  4. data/app/models/concerns/rh_cloud_host.rb +12 -0
  5. data/app/views/hosts/_insights_tab.html.erb +15 -0
  6. data/config/routes.rb +1 -0
  7. data/lib/foreman_inventory_upload/async/generate_report_job.rb +1 -1
  8. data/lib/foreman_inventory_upload/async/shell_process.rb +15 -9
  9. data/lib/foreman_inventory_upload/async/upload_report_job.rb +19 -1
  10. data/lib/foreman_inventory_upload/generators/metadata.rb +3 -0
  11. data/lib/foreman_inventory_upload/generators/queries.rb +2 -4
  12. data/lib/foreman_rh_cloud/engine.rb +10 -0
  13. data/lib/foreman_rh_cloud/version.rb +1 -1
  14. data/lib/tasks/insights.rake +15 -0
  15. data/lib/tasks/{generator.rake → rh_cloud_inventory.rake} +7 -1
  16. data/package.json +3 -1
  17. data/test/jobs/upload_report_job_test.rb +34 -0
  18. data/test/unit/metadata_generator_test.rb +2 -0
  19. data/test/unit/slice_generator_test.rb +17 -0
  20. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilterReducer.js +13 -2
  21. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterReducer.test.js +10 -1
  22. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterReducer.test.js.snap +6 -0
  23. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +3 -0
  24. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +1 -1
  25. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +1 -1
  26. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +1 -1
  27. data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +1 -1
  28. data/webpack/ForemanRhCloudPages.js +2 -0
  29. data/webpack/ForemanRhCloudReducers.js +2 -0
  30. data/webpack/ForemanRhCloudSelectors.js +5 -0
  31. data/webpack/ForemanRhCloudTestHelpers.js +6 -1
  32. data/webpack/InsightsHostDetailsTab/InsightsTab.js +64 -0
  33. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +86 -0
  34. data/webpack/InsightsHostDetailsTab/InsightsTabActions.js +30 -0
  35. data/webpack/InsightsHostDetailsTab/InsightsTabConstants.js +3 -0
  36. data/webpack/InsightsHostDetailsTab/InsightsTabReducer.js +26 -0
  37. data/webpack/InsightsHostDetailsTab/InsightsTabSelectors.js +3 -0
  38. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js +25 -0
  39. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js +13 -0
  40. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js +13 -0
  41. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js +17 -0
  42. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js +35 -0
  43. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js +13 -0
  44. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap +30 -0
  45. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap +20 -0
  46. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap +41 -0
  47. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap +20 -0
  48. data/webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js +69 -0
  49. data/webpack/InsightsHostDetailsTab/components/ListItem/index.js +1 -0
  50. data/webpack/InsightsHostDetailsTab/index.js +20 -0
  51. data/webpack/__mocks__/foremanReact/components/Layout/LayoutConstants.js +1 -0
  52. data/webpack/__tests__/__snapshots__/ForemanRhCloudSelectors.test.js.snap +1 -0
  53. data/webpack/__tests__/__snapshots__/ForemanRhCloudTestHelpers.test.js.snap +3 -0
  54. metadata +38 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a340f8085bfc6d4d08048369230ab9b90a392cc460b86d53c30bbe8a90ed3c86
4
- data.tar.gz: dd76bc695e8d183ac9b9afd05e84ca8650730584919243f9b99d10da522dd707
3
+ metadata.gz: beb9afa713376417b3673803766cb7502efeabb52640e5d4a392eadf75b0f1b3
4
+ data.tar.gz: 1ee3c8b02c4748412ebdbc1547278460d19ced4fddfb55c913ecc38e07e71d2b
5
5
  SHA512:
6
- metadata.gz: dbd457318e1c1b23db3e5d2e9a71974f30f6d089fa7df5af02d4b6fbce6487c8b3cedd0749da05d76b32aa5af22a2a1cc99ffaef3d141c77a1edffd838d8bc70
7
- data.tar.gz: 7269c01c4e2599456f4d340425ad60b56a9f65749642d0e5cbda9c2217fd792b8cf1d61808a787c36a644d0f785e7c623a22d47b58af83e693530acbb77824fd
6
+ metadata.gz: 650e22398af35c4cc866c53d33988ca02d1c30909e62b6b9b6839c0c354d6d2ab56c6928b839b490119c350246520f9c8ca3d2aacc6c05d23bf7fbd22d6fd8e5
7
+ data.tar.gz: 8a501092f95cbb44def78a581fa70fff1d245b72af0332362c5efe3de2f3cc3db70e4842111644d0ed27c0e96a9458e28e0fbc8850e810efe4660a9bce39cb0c
data/README.md CHANGED
@@ -13,11 +13,36 @@ for how to install Foreman plugins
13
13
 
14
14
  ### In Satellite
15
15
 
16
- Normally you run it via UI in RH Cloud -> Inventory Upload -> Restart, but if you need to run from command-line for some reason:
16
+ #### Inventory upload
17
+
18
+ In UI: Configure -> Inventory Upload -> Restart
19
+
20
+ From command-line:
17
21
 
18
22
  export organization_id=1
19
23
  export target=/var/lib/foreman/red_hat_inventory/generated_reports/
20
- /usr/sbin/foreman-rake foreman_inventory_upload:report:generate
24
+ /usr/sbin/foreman-rake rh_cloud_inventory:report:generate
25
+
26
+ #### Fetch hosts remediation data
27
+
28
+ In UI: Configure -> Insights -> Sync now
29
+
30
+ From command-line:
31
+
32
+ /usr/sbin/foreman-rake rh_cloud_inventory:sync
33
+
34
+ #### Synchronize inventory status
35
+
36
+ In UI: Configure -> Inventory Upload -> Sync inventory status
37
+
38
+ From command-line:
39
+
40
+ # all organizations
41
+ /usr/sbin/foreman-rake rh_cloud_insights:sync
42
+
43
+ # specific organization with id 1
44
+ export organization_id=1
45
+ /usr/sbin/foreman-rake rh_cloud_insights:sync
21
46
 
22
47
  ## TODO
23
48
 
@@ -0,0 +1,17 @@
1
+ module InsightsCloud
2
+ class HitsController < ::ApplicationController
3
+ def index
4
+ host = Host.where(id: host_id_param).first
5
+
6
+ render json: {
7
+ hits: host.insights.hits,
8
+ }, status: :ok
9
+ end
10
+
11
+ private
12
+
13
+ def host_id_param
14
+ params.require(:host_id)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module RhCloudHost
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ has_many(
6
+ :inventory_upload_facts,
7
+ -> { where(fact_name_id: ForemanInventoryUpload::Generators::Queries.fact_names.values) },
8
+ class_name: 'FactValue',
9
+ :foreign_key => :host_id
10
+ )
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ <% content_for(:javascripts) do %>
2
+ <%= webpacked_plugins_js_for :'foreman_rh_cloud' %>
3
+ <% end %>
4
+
5
+ <% content_for(:stylesheets) do %>
6
+ <%= webpacked_plugins_css_for :'foreman_rh_cloud' %>
7
+ <% end %>
8
+
9
+ <div id="host_details_insights_react_container"></div>
10
+ <%= mount_react_component(
11
+ 'InsightsHostDetailsTab',
12
+ '#host_details_insights_react_container',
13
+ { hostID: host.id }.to_json,
14
+ flatten_data: true
15
+ ) %>
@@ -15,6 +15,7 @@ Rails.application.routes.draw do
15
15
  namespace :insights_cloud do
16
16
  resources :tasks, only: [:create]
17
17
  resource :settings, only: [:show, :update]
18
+ get 'hits/:host_id', to: 'hits#index'
18
19
  end
19
20
 
20
21
  namespace :foreman_rh_cloud do
@@ -23,7 +23,7 @@ module ForemanInventoryUpload
23
23
  end
24
24
 
25
25
  def command
26
- "#{rake_prefix}rake foreman_inventory_upload:report:generate"
26
+ "#{rake_prefix}rake rh_cloud_inventory:report:generate"
27
27
  end
28
28
 
29
29
  def env
@@ -8,24 +8,30 @@ module ForemanInventoryUpload
8
8
  def perform(instance_label)
9
9
  klass_name = self.class.name
10
10
  logger.debug("Starting #{klass_name} with label #{instance_label}")
11
- progress_output = ProgressOutput.register(instance_label)
12
- Open3.popen2e(hash_to_s(env), *preprocess_command(command)) do |_stdin, stdout_stderr, wait_thread|
13
- progress_output.status = "Running in pid #{wait_thread.pid}"
11
+ progress_output_for(instance_label) do |progress_output|
12
+ Open3.popen2e(hash_to_s(env), *preprocess_command(command)) do |_stdin, stdout_stderr, wait_thread|
13
+ progress_output.status = "Running in pid #{wait_thread.pid}"
14
14
 
15
- stdout_stderr.each do |out_line|
16
- progress_output.write_line(out_line)
17
- end
15
+ stdout_stderr.each do |out_line|
16
+ progress_output.write_line(out_line)
17
+ end
18
18
 
19
- progress_output.status = wait_thread.value.to_s
19
+ progress_output.status = wait_thread.value.to_s
20
+ end
20
21
  end
21
22
  logger.debug("Finished job #{klass_name} with label #{instance_label}")
22
- ensure
23
- progress_output.close
24
23
  end
25
24
 
26
25
  def command
27
26
  end
28
27
 
28
+ def progress_output_for(instance_label)
29
+ progress_output = ProgressOutput.register(instance_label)
30
+ yield(progress_output)
31
+ ensure
32
+ progress_output.close
33
+ end
34
+
29
35
  def env
30
36
  {}
31
37
  end
@@ -8,15 +8,33 @@ module ForemanInventoryUpload
8
8
  end
9
9
 
10
10
  def perform(filename, organization_id)
11
+ label = UploadReportJob.output_label(organization_id)
11
12
  @filename = filename
12
13
  @organization = Organization.find(organization_id)
13
14
 
15
+ if Setting[:content_disconnected]
16
+ progress_output_for(label) do |progress_output|
17
+ progress_output.write_line('Upload was stopped since disconnected mode setting is enabled for content on this instance.')
18
+ progress_output.status = "Task aborted, exit 1"
19
+ end
20
+ return
21
+ end
22
+
23
+ unless @organization.owner_details&.fetch('upstreamConsumer')&.fetch('idCert')
24
+ logger.info("Skipping organization '#{@organization}', no candlepin certificate defined.")
25
+ progress_output_for(label) do |progress_output|
26
+ progress_output.write_line("Skipping organization #{@organization}, no candlepin certificate defined.")
27
+ progress_output.status = "Task aborted, exit 1"
28
+ end
29
+ return
30
+ end
31
+
14
32
  Tempfile.create([@organization.name, '.pem']) do |cer_file|
15
33
  cer_file.write(rh_credentials[:cert])
16
34
  cer_file.write(rh_credentials[:key])
17
35
  cer_file.flush
18
36
  @cer_path = cer_file.path
19
- super(UploadReportJob.output_label(organization_id))
37
+ super(label)
20
38
  end
21
39
  end
22
40
 
@@ -21,6 +21,9 @@ module ForemanInventoryUpload
21
21
  private
22
22
 
23
23
  def render_report(metadata)
24
+ metadata ||= {}
25
+ metadata['foreman_rh_cloud_version'] = ForemanRhCloud::VERSION
26
+
24
27
  @stream.object do
25
28
  @stream.simple_field('report_id', Foreman.uuid)
26
29
  @stream.simple_field('host_inventory_api_version', '1.0')
@@ -30,23 +30,21 @@ module ForemanInventoryUpload
30
30
  end
31
31
 
32
32
  def self.for_slice(base)
33
- fact_values = FactValue.where(fact_name_id: fact_names.values)
34
33
  base
35
34
  .joins(:subscription_facet)
36
- .eager_load(:fact_values)
37
35
  .preload(
38
36
  :interfaces,
39
37
  :installed_packages,
40
38
  :content_facet,
41
39
  :host_statuses,
40
+ :inventory_upload_facts,
42
41
  subscription_facet: [:pools, :installed_products, :hypervisor_host]
43
42
  )
44
- .merge(fact_values)
45
43
  end
46
44
 
47
45
  def self.for_report(portal_user)
48
46
  org_ids = organizations_for_user(portal_user).pluck(:id)
49
- for_slice(Host.unscoped.where(organization_id: org_ids)).in_batches(of: 1_000)
47
+ for_org(org_ids)
50
48
  end
51
49
 
52
50
  def self.for_org(organization_id)
@@ -66,9 +66,19 @@ module ForemanRhCloud
66
66
  register_global_js_file 'subscriptions_extension'
67
67
 
68
68
  register_custom_status(InventorySync::InventoryStatus)
69
+
70
+ extend_page 'hosts/show' do |context|
71
+ context.add_pagelet :main_tabs,
72
+ partial: 'hosts/insights_tab',
73
+ name: _('Insights'),
74
+ onlyif: proc { |host| host.insights }
75
+ end
69
76
  end
70
77
 
71
78
  ::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
79
+
80
+ ::Host::Managed.include RhCloudHost
81
+ ::Host::Base.include RhCloudHost
72
82
  end
73
83
 
74
84
  initializer "foreman_rh_cloud.set_dynflow.config.on_init", :before => :finisher_hook do |_app|
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '2.0.10'.freeze
2
+ VERSION = '2.0.11'.freeze
3
3
  end
@@ -0,0 +1,15 @@
1
+ namespace :rh_cloud_insights do
2
+ desc "Synchronize Insights inventory"
3
+ task sync: :environment do
4
+ if ! ENV['organization_id'].nil?
5
+ organizations = [ Organization.where(:id => ENV['organization_id']).first ]
6
+ else
7
+ organizations = Organization.all
8
+ end
9
+
10
+ organizations.each do |organization|
11
+ InventorySync::Async::InventoryFullSync.perform_now(organization)
12
+ puts "Synchronized inventory for organization '#{organization.name}'"
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  require 'tempfile'
2
2
 
3
- namespace :foreman_inventory_upload do
3
+ namespace :rh_cloud_inventory do
4
4
  namespace :report do
5
5
  desc 'Generate inventory report to be sent to Red Hat cloud'
6
6
  task generate: :environment do
@@ -26,4 +26,10 @@ namespace :foreman_inventory_upload do
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ desc "Synchronize Insights hosts hits"
31
+ task sync: :environment do
32
+ InsightsCloud::Async::InsightsFullSync.perform_now()
33
+ puts "Synchronized Insights hosts hits data"
34
+ end
29
35
  end
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "0.0.1",
3
+ "version": "2.0.11",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "lint": "tfm-lint --plugin -d /webpack",
8
+ "lint:spelling": "eslint ./",
8
9
  "test": "tfm-test --plugin",
9
10
  "test:watch": "tfm-test --plugin --watchAll",
10
11
  "test:current": "tfm-test --plugin --watch",
@@ -32,6 +33,7 @@
32
33
  "@theforeman/eslint-plugin-foreman": "^4.0.2",
33
34
  "babel-eslint": "^10.0.0",
34
35
  "eslint": "^6.7.2",
36
+ "eslint-plugin-spellcheck": "^0.0.17",
35
37
  "prettier": "^1.13.5",
36
38
  "raf": "^3.4.0",
37
39
  "stylelint": "^9.3.0",
@@ -0,0 +1,34 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class UploadReportJobTest < ActiveJob::TestCase
4
+ include FolderIsolation
5
+
6
+ test 'returns aborted state when disconnected' do
7
+ organization = FactoryBot.create(:organization)
8
+ Organization.any_instance.stubs(:owner_details).returns(
9
+ 'upstreamConsumer' => {
10
+ 'idCert' => 'TEST_CERT',
11
+ }
12
+ )
13
+ FactoryBot.create(:setting, :name => 'content_disconnected', :value => true)
14
+
15
+ ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
16
+
17
+ label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
18
+ progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
19
+ assert_match(/Upload was stopped/, progress_output.full_output)
20
+ assert_match(/exit 1/, progress_output.status)
21
+ end
22
+
23
+ test 'returns aborted state when no certificate defined on organization' do
24
+ organization = FactoryBot.create(:organization)
25
+ Organization.any_instance.expects(:owner_details).returns(nil)
26
+
27
+ ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
28
+
29
+ label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
30
+ progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
31
+ assert_match(/Skipping organization/, progress_output.full_output)
32
+ assert_match(/exit 1/, progress_output.status)
33
+ end
34
+ end
@@ -13,6 +13,8 @@ class MetadataGeneratorTest < ActiveSupport::TestCase
13
13
 
14
14
  assert_not_nil actual['report_id']
15
15
  assert_equal 'Satellite', actual['source']
16
+ assert_not_nil (actual_metadata = actual['source_metadata'])
17
+ assert_equal ForemanRhCloud::VERSION, actual_metadata['foreman_rh_cloud_version']
16
18
  assert_equal({}, actual['report_slices'])
17
19
  end
18
20
 
@@ -9,6 +9,7 @@ class ReportGeneratorTest < ActiveSupport::TestCase
9
9
 
10
10
  @host = FactoryBot.create(
11
11
  :host,
12
+ :redhat,
12
13
  :with_subscription,
13
14
  :with_content,
14
15
  content_view: cv.first,
@@ -264,6 +265,22 @@ class ReportGeneratorTest < ActiveSupport::TestCase
264
265
  assert_equal 1, generator.hosts_count
265
266
  end
266
267
 
268
+ test 'include also hosts with non-redhat OS' do
269
+ os = @host.operatingsystem
270
+ os.name = 'Centos'
271
+ os.save!
272
+
273
+ # make a_host last
274
+ batch = ForemanInventoryUpload::Generators::Queries.for_org(@host.organization_id).first
275
+ generator = create_generator(batch)
276
+
277
+ json_str = generator.render
278
+ actual = JSON.parse(json_str.join("\n"))
279
+
280
+ assert_equal 'slice_123', actual['report_slice_id']
281
+ assert_equal 1, generator.hosts_count
282
+ end
283
+
267
284
  test 'shows system_memory_bytes in bytes' do
268
285
  FactoryBot.create(:fact_value, fact_name: fact_names['memory::memtotal'], value: '1', host: @host)
269
286
 
@@ -1,5 +1,8 @@
1
1
  import Immutable from 'seamless-immutable';
2
- import { LAYOUT_CHANGE_ORG } from 'foremanReact/components/Layout/LayoutConstants';
2
+ import {
3
+ LAYOUT_CHANGE_ORG,
4
+ LAYOUT_INITIALIZE,
5
+ } from 'foremanReact/components/Layout/LayoutConstants';
3
6
  import {
4
7
  INVENTORY_FILTER_UPDATE,
5
8
  INVENTORY_FILTER_CLEAR,
@@ -12,7 +15,7 @@ const initialState = Immutable({
12
15
 
13
16
  export default (
14
17
  state = initialState,
15
- { type, payload: { filterTerm, org } = {} }
18
+ { type, payload: { filterTerm, org, organization } = {} }
16
19
  ) => {
17
20
  switch (type) {
18
21
  case INVENTORY_FILTER_UPDATE:
@@ -30,6 +33,14 @@ export default (
30
33
  filterTerm: term,
31
34
  });
32
35
  }
36
+ case LAYOUT_INITIALIZE: {
37
+ // Layout action changed in Jul 20 2020 - https://github.com/theforeman/foreman/commit/e4c39a7d8f8b50ba45ef63e46f6f6914b69f247a
38
+ const { title } = organization; // org was renamed
39
+ const term = title === ANY_ORGANIZATION ? '' : title;
40
+ return state.merge({
41
+ filterTerm: term,
42
+ });
43
+ }
33
44
  default:
34
45
  return state;
35
46
  }
@@ -1,5 +1,8 @@
1
1
  import { testReducerSnapshotWithFixtures } from '@theforeman/test';
2
- import { LAYOUT_CHANGE_ORG } from 'foremanReact/components/Layout/LayoutConstants';
2
+ import {
3
+ LAYOUT_CHANGE_ORG,
4
+ LAYOUT_INITIALIZE,
5
+ } from 'foremanReact/components/Layout/LayoutConstants';
3
6
  import reducer from '../InventoryFilterReducer';
4
7
  import { filterTerm, org } from '../InventoryFilter.fixtures';
5
8
  import {
@@ -29,6 +32,12 @@ const fixtures = {
29
32
  payload: { org },
30
33
  },
31
34
  },
35
+ 'should handle LAYOUT_INITIALIZE': {
36
+ action: {
37
+ type: LAYOUT_INITIALIZE,
38
+ payload: { organization: org },
39
+ },
40
+ },
32
41
  };
33
42
 
34
43
  describe('AccountList reducer', () =>