foreman_rh_cloud 2.0.10 → 2.0.11

Sign up to get free protection for your applications and to get access to all the features.
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', () =>