Repurpose CloudConnectorAnnounceTask for daily Sources registration#1214
Open
jeremylenz wants to merge 10 commits into
Open
Repurpose CloudConnectorAnnounceTask for daily Sources registration#1214jeremylenz wants to merge 10 commits into
jeremylenz wants to merge 10 commits into
Conversation
9 tasks
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- CloudConnectorAnnounceTask#run logs a per-org info line for every organization skipped due to missing manifest; if you expect many orgs this could be noisy, so consider summarizing skipped orgs at the end (similar to
output[:status]) instead of logging each one individually. - The warning about
allow_auto_inventory_uploadbeing disabled in CloudConnectorAnnounceTask#plan will be emitted on every daily run while the setting is off; if that’s an expected long-term configuration for some deployments, consider downgrading to info or adding a guard so the warning is not continuously repeated.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- CloudConnectorAnnounceTask#run logs a per-org info line for every organization skipped due to missing manifest; if you expect many orgs this could be noisy, so consider summarizing skipped orgs at the end (similar to `output[:status]`) instead of logging each one individually.
- The warning about `allow_auto_inventory_upload` being disabled in CloudConnectorAnnounceTask#plan will be emitted on every daily run while the setting is off; if that’s an expected long-term configuration for some deployments, consider downgrading to info or adding a guard so the warning is not continuously repeated.
## Individual Comments
### Comment 1
<location path="lib/insights_cloud/async/cloud_connector_announce_task.rb" line_range="33-46" />
<code_context>
end
- def finalize
+ def run
+ announced = []
+ skipped = []
+ failed = []
+
Organization.unscoped.each do |org|
+ unless cert_auth_available?(org)
+ logger.info("Skipping Sources announcement for organization #{org.name}: no manifest available")
+ skipped << org.name
+ next
+ end
+
presence = ForemanRhCloud::CloudPresence.new(org, logger)
</code_context>
<issue_to_address>
**suggestion:** Exception handling in `run` drops stack traces, which can complicate debugging
In the `rescue StandardError => ex` block, only `"Failed to announce...: #{ex}"` is logged, so the backtrace is lost. Please also log `ex.full_message` or `ex.message` together with `ex.backtrace.join("\n")` (possibly at debug level or in a separate line) so failures remain diagnosable in production.
```suggestion
Organization.unscoped.each do |org|
unless cert_auth_available?(org)
logger.info("Skipping Sources announcement for organization #{org.name}: no manifest available")
skipped << org.name
next
end
presence = ForemanRhCloud::CloudPresence.new(org, logger)
presence.announce_to_sources
announced << org.name
rescue StandardError => ex
logger.warn("Failed to announce to Sources for organization #{org.name}: #{ex}")
logger.debug(
"Sources announcement error details for organization #{org.name}: " \
"#{ex.class}: #{ex.message}\n#{Array(ex.backtrace).join("\n")}"
)
failed << org.name
end
```
</issue_to_address>
### Comment 2
<location path="test/jobs/cloud_connector_announce_task_test.rb" line_range="11-20" />
<code_context>
+ ForemanRhCloud.unstub(:with_iop_smart_proxy?)
+ end
+
+ test 'announces to sources for all organizations when rhc_instance_id is set' do
+ Setting[:rhc_instance_id] = 'test-rhc-id'
+
+ InsightsCloud::Async::CloudConnectorAnnounceTask.any_instance
+ .stubs(:cert_auth_available?).returns(true)
- @job_invocation = generate_job_invocation(:ansible_configure_cloud_connector)
+ ForemanRhCloud::CloudPresence.any_instance
+ .expects(:announce_to_sources)
+ .times(Organization.unscoped.count)
- # reset connector feature ID cache
- InsightsCloud::Async::CloudConnectorAnnounceTask.instance_variable_set(:@connector_feature_id, nil)
+ action = create_and_plan_action(InsightsCloud::Async::CloudConnectorAnnounceTask)
+ run_action(action)
end
</code_context>
<issue_to_address>
**suggestion (testing):** Add assertions for the task output status to cover the new reporting behavior in `run`
The new `output[:status]` summary (with announced/skipped/failed orgs) isn’t validated by the tests. Please add at least one test that inspects `action.output[:status]` after `run_action(action)` and covers cases like:
- all orgs announced (only `Announced:` present)
- orgs skipped for missing manifest (`Skipped (no manifest):` present)
- orgs failing (`Failed:` present)
This will exercise the new reporting behavior and guard against regressions in the status formatting and content.
Suggested implementation:
```ruby
test 'announces to sources for all organizations when rhc_instance_id is set' do
Setting[:rhc_instance_id] = 'test-rhc-id'
InsightsCloud::Async::CloudConnectorAnnounceTask.any_instance
.stubs(:cert_auth_available?).returns(true)
ForemanRhCloud::CloudPresence.any_instance
.expects(:announce_to_sources)
.times(Organization.unscoped.count)
action = create_and_plan_action(InsightsCloud::Async::CloudConnectorAnnounceTask)
run_action(action)
# Validate reporting in action output
assert_equal true, action.output[:success]
assert_includes action.output[:status], 'Announced:'
refute_includes action.output[:status], 'Skipped (no manifest):'
refute_includes action.output[:status], 'Failed:'
end
```
To fully match the review suggestion, you can add two more tests that exercise the “skipped (no manifest)” and “failed” paths by:
1. Creating organizations that will trigger those branches in `run` (e.g. by stubbing/mocking the parts of `CloudConnectorAnnounceTask` / `CloudPresence` that decide an org is skipped vs failed).
2. Running `run_action(action)` and asserting that `action.output[:status]` includes the respective `Skipped (no manifest):` and `Failed:` fragments (and that the other fragments are absent or have the expected counts).
The exact stubs/exceptions depend on how the implementation distinguishes skipped vs failed orgs in your codebase.
</issue_to_address>
### Comment 3
<location path="test/jobs/cloud_connector_announce_task_test.rb" line_range="59-22" />
<code_context>
- def read_jsonl(jsonl)
- jsonl.lines.map { |l| JSON.parse(l) }
+ test 'skips organizations without a manifest' do
+ Setting[:rhc_instance_id] = 'test-rhc-id'
+
+ InsightsCloud::Async::CloudConnectorAnnounceTask.any_instance
+ .stubs(:cert_auth_available?).returns(false)
+
+ ForemanRhCloud::CloudPresence.any_instance
+ .expects(:announce_to_sources)
+ .never
+
+ action = create_and_plan_action(InsightsCloud::Async::CloudConnectorAnnounceTask)
+ run_action(action)
+ end
+
</code_context>
<issue_to_address>
**suggestion (testing):** Consider a test that covers behavior when automatic inventory upload is disabled
The `plan` method now warns when `Setting[:allow_auto_inventory_upload]` is false while `rhc_instance_id` is set, but still calls `plan_self`. Current tests don’t distinguish between the true/false cases for `allow_auto_inventory_upload`. Please add a test that sets `Setting[:rhc_instance_id]` with `Setting[:allow_auto_inventory_upload] = false` and verifies the task still runs (e.g., `run_action(action)` leads to `announce_to_sources` being called). This guards against future changes that might skip the task when auto-upload is disabled.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
d130135 to
1b9de5a
Compare
Collaborator
|
Recommend adding something like what the flow used to look like and what changes after your PR What This PR Does:
After (New Flow - Fixed):
|
05a3462 to
463b152
Compare
parthaa
reviewed
Jun 12, 2026
With cloud connector setup moving to foremanctl, the old REX-triggered Sources registration flow no longer fires. This converts CloudConnectorAnnounceTask from a REX subscription into a daily recurring task that checks if rhc_instance_id is set and registers with Red Hat Sources for each organization with a valid manifest. Also adds POST /api/v2/rh_cloud/announce_to_sources for immediate registration during foremanctl deploy, and removes the old REX-based cloud connector flow (CloudConnector service, enable_cloud_connector endpoints, ansible_configure_cloud_connector feature). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Downgrade allow_auto_inventory_upload message to debug (avoids noisy daily logs for deployments that intentionally disable auto upload) - Remove per-org skip logging, rely on output[:status] summary instead - Log backtrace at debug level on per-org failures for diagnosability - Add output[:status] assertions to tests - Add test for allow_auto_inventory_upload=false (task still runs) - Fix rubocop indentation offenses Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Include error details in output[:status] for failed orgs - Call error! when any org fails so task shows as warning, not success - Downgrade allow_auto_inventory_upload message to debug - Remove per-org skip logging, rely on output[:status] summary instead - Log backtrace at debug level on per-org failures - Add output[:status] assertions to tests - Add test for allow_auto_inventory_upload=false (task still runs) - Fix rubocop indentation offenses Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Sources API returns 400 if an RHC connection already exists for the given rhc_id. Query for an existing connection first and skip the POST if one is found, following the same pattern used by satellite_instance_source for source get-or-create. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use DelayedStart to add a random 0-3 hour delay when running as a daily scheduled task, preventing all Satellites from hitting the Sources API simultaneously at midnight. The API endpoint passes immediate=true to skip the delay during foremanctl deploys. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
If a cloud-initiated remediation job was created for an org in the past 24 hours, the cloud connector pipeline is proven working for that org. Skip the Sources API call and report the org as "Already registered" instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show "Already registered (recent cloud remediation)" when skipping due to recent jobs, vs "Already registered" when the Sources API confirmed the connection exists. Also adds a test for the recent cloud remediation skip path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1d6018a to
f38fbf6
Compare
jeremylenz
commented
Jun 15, 2026
Remove "Satellite" from API endpoint description since this also applies to Foreman. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
job_invocations table has no timestamps. Use foreman_tasks_tasks.started_at via the :task association instead of job_invocations.created_at. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace references to the old UI button / REX job setup with the foremanctl deploy flow and daily CloudConnectorAnnounceTask. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR addresses SAT-45966 / SAT-44641 by repurposing the CloudConnectorAnnounceTask from a REX subscription into a daily recurring task with an API endpoint for immediate registration.
Before (Old Flow — Broken with foremanctl)
ansible_configure_cloud_connector)CloudConnectorAnnounceTaskfires (subscribed toRunHostsJob)CloudPresence.announce_to_sourcesWith cloud connector setup moving to foremanctl, the REX job never runs, so
CloudConnectorAnnounceTasknever fires and Sources registration never happens.After (New Flow — Fixed)
foremanctl deploy --add-feature cloud-connectorPOST /api/v2/rh_cloud/announce_to_sourcesafter settingrhc_instance_idChanges
CloudConnectorAnnounceTaskfrom a REX subscription to a dailyRecurringAction+ one-shot API triggerPOST /api/v2/rh_cloud/announce_to_sourcesendpoint for immediate registration during foremanctl deployrhc_connection_exists?check inCloudPresenceto avoid duplicate connection errors (Sources API returns 400)CloudConnectorservice class,enable_cloud_connectorendpoints,ansible_configure_cloud_connectorREX featureTest plan
POST /api/v2/rh_cloud/announce_to_sourcestriggers immediate registration (no delay)rhc_instance_idis not set, in IoP mode, or org has no manifest🤖 Generated with Claude Code