foreman_rh_cloud 10.0.4 → 10.0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8215c5bc0f5e21d7c4ee1b09ee2a38a44bc17d36c95606d77e8ee2cffc10d2e
4
- data.tar.gz: f42e8b38e3f996cf29973a776ec03083aaa8db1fb58639690f7a50048c531260
3
+ metadata.gz: bcf5c802bcf566375518a4f83d5a5fae3ec98c5554e89dea57af748af526f998
4
+ data.tar.gz: 1c8d77163d1cac3161813bf9aab5f70f3a8496ce9351a5e2a4d071aaecfb1ad6
5
5
  SHA512:
6
- metadata.gz: bd2acf961ce05b7043013b695dccaab5d764d526b23aef83adc85373a0699fdc9a161bbd65c621d5fffc9139f254e88b6e6e53e2da9e5da6ade0330523c85f0b
7
- data.tar.gz: 380d55213867c915d707f52470f6ec3aca269c3f2aa7bfc1aa2ba2db7659806c3c17824675fe5c9b2ef62df9704f0fb09f0cc2738bab17ea5339edd7c832dbad
6
+ metadata.gz: 807e09c7f560217178221cf3a2c7eda52aee500ea50fe18d56b86f53cffee23d0d7ca50e6b4bd174a7b3c038273158a41cb6c5d60339fd121e5d0c06e0010788
7
+ data.tar.gz: ad3a808a270922e52e25778f9101db3a358fbe99b0ded5f01fab67c5d1a398cc7c997ed816f909b528af579a47f44f5b97a9a6c5621d4fa97d59dc8f43851a3c
data/README.md CHANGED
@@ -15,7 +15,7 @@ for how to install Foreman plugins
15
15
 
16
16
  #### Inventory upload
17
17
 
18
- In UI: Configure -> Inventory Upload -> Restart
18
+ In UI: Insights -> Inventory Upload -> select the organization -> Generate and upload report
19
19
 
20
20
  From command-line:
21
21
 
@@ -38,7 +38,7 @@ From command-line:
38
38
 
39
39
  #### Fetch hosts remediation data
40
40
 
41
- In UI: Configure -> Insights -> Sync now
41
+ In UI: Insights -> Recommendations -> Sync recommendations (under the vertical ellipsis)
42
42
 
43
43
  From command-line:
44
44
 
@@ -46,7 +46,7 @@ From command-line:
46
46
 
47
47
  #### Synchronize inventory status
48
48
 
49
- In UI: Configure -> Inventory Upload -> Sync inventory status
49
+ In UI: Insights -> Inventory Upload -> Sync all inventory status
50
50
 
51
51
  From command-line:
52
52
 
@@ -16,27 +16,41 @@ module InsightsCloud::Api
16
16
  # The method that "proxies" requests over to Cloud
17
17
  def forward_request
18
18
  certs = candlepin_id_cert @organization
19
- @cloud_response = ::ForemanRhCloud::CloudRequestForwarder.new.forward_request(request, controller_name, @branch_id, certs)
19
+ begin
20
+ @cloud_response = ::ForemanRhCloud::CloudRequestForwarder.new.forward_request(request, controller_name, @branch_id, certs)
21
+ rescue RestClient::Exceptions::Timeout => e
22
+ response_obj = e.response.presence || e.exception
23
+ return render json: { message: response_obj.to_s, error: response_obj.to_s }, status: :gateway_timeout
24
+ rescue RestClient::Unauthorized => e
25
+ logger.warn("Forwarding request auth error: #{e}")
26
+ message = 'Authentication to the Insights Service failed.'
27
+ return render json: { message: message, error: message }, status: :unauthorized
28
+ rescue RestClient::NotModified => e
29
+ logger.info("Forwarding request not modified: #{e}")
30
+ message = 'Cloud request not modified'
31
+ return render json: { message: message, error: message }, status: :not_modified
32
+ rescue RestClient::ExceptionWithResponse => e
33
+ response_obj = e.response.presence || e.exception
34
+ code = response_obj.try(:code) || response_obj.try(:http_code) || 500
35
+ message = 'Cloud request failed'
20
36
 
21
- if @cloud_response.code == 401
22
37
  return render json: {
23
- :message => 'Authentication to the Insights Service failed.',
38
+ :message => message,
39
+ :error => response_obj.to_s,
24
40
  :headers => {},
25
- }, status: :bad_gateway
26
- end
27
-
28
- if @cloud_response.code >= 300
29
- return render json: {
30
- :message => 'Cloud request failed',
31
- :headers => {},
32
- :response => @cloud_response,
33
- }, status: @cloud_response.code
41
+ :response => response_obj,
42
+ }, status: code
43
+ rescue StandardError => e
44
+ # Catch any other exceptions here, such as Errno::ECONNREFUSED
45
+ logger.warn("Cloud request failed with exception: #{e}")
46
+ return render json: { error: e.to_s }, status: :bad_gateway
34
47
  end
35
48
 
36
49
  # Append redhat-specific headers
37
50
  @cloud_response.headers.each do |key, value|
38
51
  assign_header(response, @cloud_response, key, false) if key.to_s.start_with?('x_rh_')
39
52
  end
53
+
40
54
  # Append general headers
41
55
  assign_header(response, @cloud_response, :x_resource_count, true)
42
56
  headers[Rack::ETAG] = @cloud_response.headers[:etag]
@@ -46,8 +60,8 @@ module InsightsCloud::Api
46
60
  # content type
47
61
  send_data @cloud_response, disposition: @cloud_response.headers[:content_disposition], type: @cloud_response.headers[:content_type]
48
62
  elsif @cloud_response.headers[:content_type] =~ /zip/
49
- # if there is no Content-Disposition, but the content type is binary according the content type,
50
- # forward the request as binry too
63
+ # If there is no Content-Disposition, but the content type is binary according to Content-Type, send the raw data
64
+ # with proper content type
51
65
  send_data @cloud_response, type: @cloud_response.headers[:content_type]
52
66
  else
53
67
  render json: @cloud_response, status: @cloud_response.code
@@ -13,9 +13,15 @@ module ForemanRhCloud
13
13
  logger.debug("Response headers for request url #{final_params[:url]} are: #{response.headers}")
14
14
 
15
15
  response
16
- rescue RestClient::Exception => ex
17
- logger.debug("Failed response with code #{ex.http_code} headers for request url #{final_params[:url]} are: #{ex.http_headers} and body: #{ex.http_body}")
18
- raise ex
16
+ rescue RestClient::Exceptions::Timeout => ex
17
+ logger.debug("Timeout exception raised for request url #{final_params[:url]}: #{ex}")
18
+ raise
19
+ rescue RestClient::ExceptionWithResponse => ex
20
+ logger.debug("Response headers for request url #{final_params[:url]} with status code #{ex.http_code} are: #{ex.http_headers} and body: #{ex.http_body}")
21
+ raise
22
+ rescue StandardError => ex
23
+ logger.debug("Exception raised for request url #{final_params[:url]}: #{ex}")
24
+ raise
19
25
  end
20
26
  end
21
27
  end
@@ -17,8 +17,6 @@ module ForemanRhCloud
17
17
  logger.debug("Sending request to: #{request_opts[:url]}")
18
18
 
19
19
  execute_cloud_request(request_opts)
20
- rescue RestClient::Exception => error_response
21
- error_response.response
22
20
  end
23
21
 
24
22
  def prepare_request_opts(original_request, forward_payload, forward_params, certs)
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '10.0.4'.freeze
2
+ VERSION = '10.0.6'.freeze
3
3
  end
@@ -9,10 +9,11 @@ module InsightsCloud
9
9
 
10
10
  def plan(organizations)
11
11
  organizations = organizations.select do |organization|
12
- if cert_auth_available?(organization)
12
+ checker = ::Katello::UpstreamConnectionChecker.new(organization)
13
+ if cert_auth_available?(organization) && !organization.manifest_expired? && checker.can_connect?
13
14
  true
14
15
  else
15
- logger.debug("Certificate is not available for org: #{organization.name}, skipping insights sync")
16
+ logger.info("A manifest is not available for org: #{organization.name}, or it has expired, or been deleted. skipping insights sync")
16
17
  false
17
18
  end
18
19
  end
@@ -20,19 +21,23 @@ module InsightsCloud
20
21
  sequence do
21
22
  # This can be turned off when we enable automatic status syncs
22
23
  # This step will query cloud inventory to retrieve inventory uuids for each host
23
- plan_hosts_sync(organizations)
24
- plan_self(organization_ids: organizations.map(&:id))
25
- concurrence do
26
- plan_rules_sync(organizations)
27
- plan_notifications
24
+ valid_organizations = organizations.reject(&:manifest_expired?)
25
+ if valid_organizations.any?
26
+ plan_hosts_sync(organizations)
27
+ plan_self(organization_ids: organizations.map(&:id))
28
+ concurrence do
29
+ plan_rules_sync(organizations)
30
+ plan_notifications
31
+ end
28
32
  end
29
33
  end
30
34
  end
31
35
 
32
36
  def try_execute
33
37
  organizations.each do |organization|
34
- unless cert_auth_available?(organization)
35
- logger.debug("Certificate is not available for org: #{organization.name}, skipping insights sync")
38
+ checker = ::Katello::UpstreamConnectionChecker.new(organization)
39
+ if !cert_auth_available?(organization) && organization.manifest_expired && !checker.can_connect?
40
+ logger.info("A manifest is not available for org: #{organization.name}, or it has expired, or been deleted. skipping insights sync")
36
41
  next
37
42
  end
38
43
 
@@ -13,7 +13,11 @@ module InsightsCloud
13
13
  InsightsResolution.delete_all
14
14
  rule_ids = relevant_rules
15
15
  Organization.all.each do |organization|
16
- next if !cert_auth_available?(organization) || organization.manifest_expired?
16
+ checker = ::Katello::UpstreamConnectionChecker.new(organization)
17
+ if !cert_auth_available?(organization) || organization.manifest_expired? || !checker.can_connect?
18
+ logger.info("A manifest is not available for org: #{organization.name}, or it has expired, or been deleted. skipping resolutions sync")
19
+ next
20
+ end
17
21
  api_response = query_insights_resolutions(rule_ids, organization) unless rule_ids.empty?
18
22
  written_rules = write_resolutions(api_response) if api_response
19
23
  rule_ids -= Array(written_rules)
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "10.0.4",
3
+ "version": "10.0.6",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,4 +1,5 @@
1
1
  require 'test_plugin_helper'
2
+ require 'rest-client'
2
3
 
3
4
  module InsightsCloud::Api
4
5
  class MachineTelemetriesControllerTest < ActionController::TestCase
@@ -33,6 +34,18 @@ module InsightsCloud::Api
33
34
  assert_equal @body, @response.body
34
35
  end
35
36
 
37
+ test "should handle timeout from cloud" do
38
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.
39
+ stubs(:forward_request).
40
+ raises(RestClient::Exceptions::OpenTimeout.new("Timed out connecting to server"))
41
+
42
+ get :forward_request, params: { "path" => "platform/module-update-router/v1/channel" }
43
+ request_response = JSON.parse(@response.body)
44
+ # I can't get @response.status to take a nil value so I'm not asserting for that
45
+
46
+ assert_equal 'Timed out connecting to server', request_response['error']
47
+ end
48
+
36
49
  test "should respond with the same content type" do
37
50
  net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
38
51
  net_http_resp.add_field 'Set-Cookie', 'Monster'
@@ -83,13 +96,46 @@ module InsightsCloud::Api
83
96
  assert_equal net_http_resp[:content_type], @response.headers['Content-Type']
84
97
  end
85
98
 
99
+ test "should handle StandardError" do
100
+ error_message = "Connection refused"
101
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:execute_cloud_request).raises(Errno::ECONNREFUSED.new)
102
+
103
+ get :forward_request, params: { "path" => "platform/module-update-router/v1/channel" }
104
+ assert_equal 502, @response.status
105
+ body = JSON.parse(@response.body)
106
+ assert_equal error_message, body['error']
107
+ end
108
+
109
+ test "should handle 304 cloud" do
110
+ net_http_resp = Net::HTTPResponse.new(1.0, 304, "Not Modified")
111
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
112
+
113
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::NotModified.new(res))
114
+
115
+ get :forward_request, params: { "path" => "platform/module-update-router/v1/channel" }
116
+ assert_equal 304, @response.status
117
+ assert_equal 'Cloud request not modified', JSON.parse(@response.body)['message']
118
+ end
119
+
120
+ test "should handle RestClient::Exceptions::Timeout" do
121
+ timeout_message = "execution expired"
122
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::Exceptions::Timeout.new(timeout_message))
123
+
124
+ get :forward_request, params: { "path" => "platform/module-update-router/v1/channel" }
125
+ assert_equal 504, @response.status
126
+ body = JSON.parse(@response.body)
127
+ assert_equal timeout_message, body['message']
128
+ assert_equal timeout_message, body['error']
129
+ end
130
+
86
131
  test "should handle failed authentication to cloud" do
87
132
  net_http_resp = Net::HTTPResponse.new(1.0, 401, "Unauthorized")
88
133
  res = RestClient::Response.create(@body, net_http_resp, @http_req)
89
- ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:forward_request).returns(res)
134
+
135
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::Unauthorized.new(res))
90
136
 
91
137
  get :forward_request, params: { "path" => "platform/module-update-router/v1/channel" }
92
- assert_equal 502, @response.status
138
+ assert_equal 401, @response.status
93
139
  assert_equal 'Authentication to the Insights Service failed.', JSON.parse(@response.body)['message']
94
140
  end
95
141
 
@@ -65,6 +65,8 @@ class InsightsFullSyncTest < ActiveSupport::TestCase
65
65
  end
66
66
 
67
67
  test 'Hits data is replaced with data from cloud' do
68
+ Organization.any_instance.stubs(:manifest_expired?).returns(false)
69
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
68
70
  InsightsCloud::Async::InsightsFullSync.any_instance.expects(:query_insights_hits).returns(@hits)
69
71
 
70
72
  InsightsCloud::Async::InsightsFullSync.any_instance.expects(:plan_hosts_sync)
@@ -79,7 +81,31 @@ class InsightsFullSyncTest < ActiveSupport::TestCase
79
81
  assert_equal 1, @host2.insights.hits.count
80
82
  end
81
83
 
84
+ test 'Manifest is expired do not run task steps' do
85
+ Organization.any_instance.stubs(:manifest_expired?).returns(true)
86
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
87
+
88
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:query_insights_hits).never
89
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:plan_hosts_sync).never
90
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:plan_self).never
91
+
92
+ ForemanTasks.sync_task(InsightsCloud::Async::InsightsFullSync, [@host1.organization])
93
+ end
94
+
95
+ test 'Manifest is deleted do not run task steps' do
96
+ Organization.any_instance.stubs(:manifest_expired?).returns(false)
97
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(false)
98
+
99
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:query_insights_hits).never
100
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:plan_hosts_sync).never
101
+ InsightsCloud::Async::InsightsFullSync.any_instance.expects(:plan_self).never
102
+
103
+ ForemanTasks.sync_task(InsightsCloud::Async::InsightsFullSync, [@host1.organization])
104
+ end
105
+
82
106
  test 'Hits counters are reset correctly' do
107
+ Organization.any_instance.stubs(:manifest_expired?).returns(false)
108
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
83
109
  InsightsCloud::Async::InsightsFullSync.any_instance.expects(:query_insights_hits).returns(@hits).twice
84
110
 
85
111
  InsightsCloud::Async::InsightsFullSync.any_instance.stubs(:plan_hosts_sync)
@@ -97,6 +123,8 @@ class InsightsFullSyncTest < ActiveSupport::TestCase
97
123
  end
98
124
 
99
125
  test 'Hits ignoring non-existent hosts' do
126
+ Organization.any_instance.stubs(:manifest_expired?).returns(false)
127
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
100
128
  hits_json = <<-HITS_JSON
101
129
  [
102
130
  {
@@ -73,6 +73,7 @@ class InsightsResolutionsSyncTest < ActiveSupport::TestCase
73
73
  end
74
74
 
75
75
  test 'Resolutions data is replaced with data from cloud' do
76
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
76
77
  InsightsCloud::Async::InsightsResolutionsSync.any_instance.stubs(:query_insights_resolutions).returns(@resolutions)
77
78
 
78
79
  ForemanTasks.sync_task(InsightsCloud::Async::InsightsResolutionsSync)
@@ -82,7 +83,28 @@ class InsightsResolutionsSyncTest < ActiveSupport::TestCase
82
83
  assert_equal 2, @rule.resolutions.count
83
84
  end
84
85
 
86
+ test 'Manifest is deleted do not run task steps' do
87
+ Organization.any_instance.stubs(:manifest_expired?).returns(false)
88
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(false)
89
+ InsightsCloud::Async::InsightsResolutionsSync.any_instance.expects(:query_insights_resolutions).never
90
+
91
+ ForemanTasks.sync_task(InsightsCloud::Async::InsightsResolutionsSync)
92
+
93
+ assert_equal 0, InsightsResolution.all.count
94
+ end
95
+
96
+ test 'Manifest is expired do not run task steps' do
97
+ Organization.any_instance.stubs(:manifest_expired?).returns(true)
98
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
99
+ InsightsCloud::Async::InsightsResolutionsSync.any_instance.expects(:query_insights_resolutions).never
100
+
101
+ ForemanTasks.sync_task(InsightsCloud::Async::InsightsResolutionsSync)
102
+
103
+ assert_equal 0, InsightsResolution.all.count
104
+ end
105
+
85
106
  test 'Skips pinging the cloud if no rule ids were found' do
107
+ Katello::UpstreamConnectionChecker.any_instance.stubs(:can_connect?).returns(true)
86
108
  InsightsCloud::Async::InsightsResolutionsSync.any_instance.expects(:query_insights_resolutions).never
87
109
  InsightsRule.all.delete_all
88
110
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.0.4
4
+ version: 10.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-04 00:00:00.000000000 Z
11
+ date: 2025-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: foreman_ansible