Skip to content

Refactor local advisor engine config with SmartProxy-based detection #1049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

nofaralfasi
Copy link
Contributor

@nofaralfasi nofaralfasi commented Jul 30, 2025

What are the changes introduced in this pull request?

Replace configuration-based IoP detection with SmartProxy feature detection. The system now automatically detects Insights on Premise mode by checking for SmartProxy instances with the 'Insights' feature instead of relying on environment variables and settings.

Considerations taken when implementing this change?

The main goal was to preserve backward compatibility while moving from static environment variable configuration to dynamic detection based on SmartProxy settings. Instead of relying on manually set ENV vars, the system now determines IoP mode by querying the SmartProxy, which improves accuracy and makes it easier to maintain.
There's a small trade-off in performance (a DB query instead of reading a cached variable), but it removes the need for operational ENV management. Renaming the API field from use_local_advisor_engine to use_iop_mode makes the purpose clearer.

I'm still considering whether to keep the with_local_advisor_engine? method and mark it as deprecated, mainly to ensure older code paths continue to work during the transition.

What are the testing steps for this pull request?

To Do

Summary by Sourcery

Introduce SmartProxy-based detection for Insights On-Prem and refactor plugin registration while renaming the legacy use_local_advisor_engine flag to use_iop_mode

New Features:

  • Detect Insights On-Prem mode dynamically by querying SmartProxy features via with_insights_smartproxy?
  • Register Foreman plugin using Foreman::Plugin.register DSL to define Insights settings, permissions, roles, menus, facets, and page extensions

Enhancements:

  • Rename configuration, API, and UI flags from use_local_advisor_engine to use_iop_mode across the codebase
  • Replace ENV-based on-prem URL and proxy logic with SmartProxy-provided URL and feature detection
  • Update route definitions and service logic to conditionally enable features based on SmartProxy detection

Tests:

  • Update tests to stub with_insights_smartproxy? and verify updated status messages and behavior

Summary by Sourcery

Replace static local advisor engine configuration with dynamic SmartProxy-based detection for Insights on-premise and rename related flags to use_iop_mode.

Enhancements:

  • Introduce with_insights_smartproxy? to detect the Insights feature via SmartProxy and add insights_smartproxy accessor.
  • Refactor code, routes, services, views, and React components to use SmartProxy detection instead of ENV-based with_local_advisor_engine? checks.
  • Rename API field, configuration flags, RABL nodes, and front-end props from use_local_advisor_engine to use_iop_mode for clarity.

Tests:

  • Update tests to stub with_insights_smartproxy? and assert the new use_iop_mode flag and updated status messages.

Copy link

sourcery-ai bot commented Jul 30, 2025

Reviewer's Guide

This PR refactors the Insights On-Premise (IoP) detection from static ENV and setting flags to dynamic SmartProxy feature checks, renames the legacy use_local_advisor_engine flag to use_iop_mode across the stack, and propagates these changes through services, jobs, routes, views, plugin registration, and tests to preserve backward compatibility while removing manual ENV management.

ER diagram for SmartProxy and Insights On-Premise detection

erDiagram
    SMART_PROXY ||--o{ FOREMAN_RH_CLOUD : provides
    SMART_PROXY {
        string url
        string[] features
    }
    FOREMAN_RH_CLOUD {
        bool use_iop_mode
    }
Loading

Class diagram for ForemanRhCloud IoP detection refactor

classDiagram
    class ForemanRhCloud {
        +on_premise_url()
        +env_or_on_premise_url(env_var_name)
        +proxy_setting()
        +proxy_string()
        +marked_foreman_host()
        +legacy_insights_ca()
        +cloud_url_validator()
        +with_insights_smartproxy()?  <<new>>
        +insights_smartproxy  <<new>>
    }
    class SmartProxy {
        +with_features(feature)
        +exists?()
        +first()
        +url
    }
    ForemanRhCloud --> SmartProxy : uses for IoP detection
Loading

Class diagram for AdvisorEngineConfigController API change

classDiagram
    class AdvisorEngineConfigController {
        +show()
    }
    AdvisorEngineConfigController : - use_iop_mode (renamed from use_local_advisor_engine)
    AdvisorEngineConfigController --> ForemanRhCloud : uses with_insights_smartproxy?
Loading

File-Level Changes

Change Details Files
Introduce SmartProxy-based detection and remove static ENV/setting checks
  • Implement with_insights_smartproxy? and insights_smartproxy accessor
  • Replace on_premise_url, proxy_string, legacy_insights_ca and related methods to use SmartProxy detection
  • Drop SETTINGS/ENV-based use_local_advisor_engine check
lib/foreman_rh_cloud.rb
lib/foreman_rh_cloud/engine.rb
Propagate SmartProxy detection across services, jobs, and rake tasks
  • Replace calls to with_local_advisor_engine? with with_insights_smartproxy?
  • Update conditional logic in async jobs and sync classes to plan/skip based on SmartProxy
  • Adjust rake tasks to detect IoP via SmartProxy
app/services/foreman_rh_cloud/cert_auth.rb
app/services/foreman_rh_cloud/cloud_request.rb
app/services/foreman_rh_cloud/cloud_request_forwarder.rb
lib/foreman_inventory_upload/async/generate_all_reports_job.rb
lib/insights_cloud/async/insights_scheduled_sync.rb
lib/inventory_sync/async/inventory_scheduled_sync.rb
lib/inventory_sync/async/inventory_hosts_sync.rb
lib/tasks/rh_cloud_inventory.rake
lib/tasks/insights.rake
Rename use_local_advisor_engine flag to use_iop_mode in API, views, routes and plugin
  • Update API controller response to use_iop_mode
  • Rename JSON and RABL nodes and React props from use_local_advisor_engine to use_iop_mode
  • Adjust route and plugin DSL conditionals to leverage SmartProxy detection
app/controllers/api/v2/rh_cloud/advisor_engine_config_controller.rb
app/views/api/v2/hosts/insights/base.rabl
app/views/api/v2/hosts/insights/single.rabl
webpack/InsightsHostDetailsTab/NewHostDetailsTab.js
webpack/common/Hooks/ConfigHooks.js
config/routes.rb
lib/foreman_rh_cloud/plugin.rb
Update tests to stub and verify SmartProxy detection and renamed flag
  • Stub with_insights_smartproxy? in place of with_local_advisor_engine?
  • Adjust expected status messages and JSON keys to reflect SmartProxy mode
  • Ensure legacy behaviour continues via deprecation handling in tests
test/jobs/inventory_scheduled_sync_test.rb
test/unit/rh_cloud_http_proxy_test.rb
test/controllers/insights_sync/settings_controller_test.rb

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@nofaralfasi nofaralfasi force-pushed the 35683_cu branch 2 times, most recently from a360d46 to 3d4c8ee Compare July 30, 2025 14:30
Comment on lines -8 to -9
port = ENV['ADVISOR_ENGINE_PORT'] || "24443"
ENV['ADVISOR_ENGINE_URL'] || "https://localhost:#{port}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ShimShtein I want to confirm whether it's safe to remove these lines.
I see that this method is still being used here.
Should we keep it as a fallback for default values?
If we do need to keep it, the implementation will have to be updated due to recent changes in the env_or_on_premise_url method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems OK. In on-prem we want the smart-proxy to force-drive the URLs

Replace configuration-based IoP detection with SmartProxy feature detection.
The system now automatically detects Insights on Premise mode by checking
for SmartProxy instances with the 'Insights' feature instead of relying on
environment variables and settings.
@nofaralfasi nofaralfasi marked this pull request as ready for review July 31, 2025 11:06
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @nofaralfasi - I've reviewed your changes - here's some feedback:

  • Consider memoizing the insights_smartproxy lookup to avoid a database query on every with_insights_smartproxy? call and reduce performance overhead.
  • Add handling for the case where multiple SmartProxy instances expose the 'Insights' feature—either warn or fail fast—to prevent ambiguity in which URL is chosen.
  • Provide a deprecated alias for with_local_advisor_engine? to smooth the transition for any code paths or plugins that still rely on the old method name.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider memoizing the insights_smartproxy lookup to avoid a database query on every with_insights_smartproxy? call and reduce performance overhead.
- Add handling for the case where multiple SmartProxy instances expose the 'Insights' feature—either warn or fail fast—to prevent ambiguity in which URL is chosen.
- Provide a deprecated alias for with_local_advisor_engine? to smooth the transition for any code paths or plugins that still rely on the old method name.

## Individual Comments

### Comment 1
<location> `lib/foreman_rh_cloud/engine.rb:128` </location>
<code_context>
+    SmartProxy.with_features('Insights').exists?
+  end
+
+  def self.insights_smartproxy
+    SmartProxy.with_features('Insights').first
   end

</code_context>

<issue_to_address>
Ambiguity if multiple SmartProxies with 'Insights' feature exist.

Currently, the method returns the first matching SmartProxy, which may cause unpredictable results if multiple exist. Consider enforcing uniqueness or raising an error when more than one is found.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +17 to 18
const isLocalAdvisorEngine = advisorEngineConfig?.use_iop_mode;
return isLocalAdvisorEngine;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const isLocalAdvisorEngine = advisorEngineConfig?.use_iop_mode;
return isLocalAdvisorEngine;
return advisorEngineConfig?.use_iop_mode;


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nofaralfasi The AI is right here, I'll leave it up to you if you want to change it.

@@ -23,7 +23,7 @@ def plan
end

def run
output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights Smart Proxy.') if ForemanRhCloud.with_insights_smartproxy?

I think it should be two words

@@ -34,7 +34,7 @@ def plan
end

def run
output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights Smart Proxy.') if ForemanRhCloud.with_insights_smartproxy?

@@ -35,7 +35,7 @@ def plan_org_sync(org)
end

def run
output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights SmartProxy.') if ForemanRhCloud.with_insights_smartproxy?
output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local Insights Smart Proxy.') if ForemanRhCloud.with_insights_smartproxy?

Comment on lines +17 to 18
const isLocalAdvisorEngine = advisorEngineConfig?.use_iop_mode;
return isLocalAdvisorEngine;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nofaralfasi The AI is right here, I'll leave it up to you if you want to change it.

@@ -7,7 +7,7 @@ class AdvisorEngineConfigController < ::Api::V2::BaseController
api :GET, "/rh_cloud/advisor_engine_config", N_("Show if system is configured to use local iop-advisor-engine.")
def show
render json: {
use_local_advisor_engine: ForemanRhCloud.with_local_advisor_engine?,
use_iop_mode: ForemanRhCloud.with_insights_smartproxy?,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we sub iop for insights ?

@ShimShtein @vkrizan I am thinking we should change the smart-proxy feature as well. We have an inconsistency in nomenclature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proxy feature is Insights. We can converge to local_insights_mode WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my point is being missed. I am wanting to remove the use of the word Insights in favor of just using iop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind either. I'm with Shim, that the feature is name Insights, like the opensource counterpart. The "on Prem" can be implied for Foreman/Satellite.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposed change -- RedHatInsights/iop-gateway#17

Copy link
Collaborator

@jeremylenz jeremylenz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking nit below :)

@@ -121,8 +121,12 @@ def self.register_scheduled_task(task_class, cronline)
end
end

def self.with_local_advisor_engine?
SETTINGS.dig(:foreman_rh_cloud, :use_local_advisor_engine) || false
def self.with_insights_smartproxy?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smart Proxy is two words.

Suggested change
def self.with_insights_smartproxy?
def self.with_insights_smart_proxy?

SmartProxy.with_features('Insights').exists?
end

def self.insights_smartproxy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def self.insights_smartproxy
def self.insights_smart_proxy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants