From aa43cb7db942a975a3b83a41c96fab1cfabf2916 Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 12 Dec 2024 19:29:58 -0500 Subject: [PATCH 1/6] Foreman RH Cloud API Bindings to upload hits Update app/controllers/api/v2/insights_advisor/insights_advisor_controller.rb Co-authored-by: Evgeni Golov Rebased Jeremy's work Make host_uuid not required more --- .../advisor_engine_controller.rb | 71 +++++++++++++++++++ config/routes.rb | 3 +- ...to_rule_id_and_host_id_in_insights_hits.rb | 5 ++ lib/foreman_hits/async/upload.rb | 53 ++++++++++++++ 4 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb create mode 100644 lib/foreman_hits/async/upload.rb diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index 759484ed..26ea0f6c 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -3,6 +3,11 @@ module V2 module AdvisorEngine class AdvisorEngineController < ::Api::V2::BaseController include ::Api::Version2 + include Foreman::Controller::SmartProxyAuth + include ::Foreman::Controller::FilterParameters + + filter_parameters :payload + add_smart_proxy_filters [:host_details, :upload_hits] api :GET, "/advisor_engine/host_details", N_('Fetch Insights-related host details') param :host_uuids, Array, required: true, desc: N_('List of host UUIDs') @@ -17,6 +22,72 @@ def host_details end end end + + api :PATCH, "/advisor_engine/upload_hits", N_("Upload from insights advisor") + param :host_name, String, required: true + param :host_uuid, String + + param :payload, Hash, :desc => N_("On prem payload including resolutions, rules, hits") do + param :resolutions, Array, :desc => N_("upload resolutions related to the hits") do + param :rule_id, String, :desc => N_("rule id"), :required => true + param :description, String, :desc => N_("resolution description") + param :needs_reboot, :bool, :desc => N_("need reboot") + param :resolution_risk, String, :desc => N_("resolution risk") + param :resolution_type, String, :desc => N_("type") + end + + param :rules, Array, :desc => N_("upload rules related to the hits") do + param :rule_id, String, :desc => N_("rule id"), :required => true + param :description, String, :desc => N_("rule description") + param :category_name, String, :desc => N_("category name") + param :impact_name, String, :desc => N_("impact name") + param :summary, String, :desc => N_("summary") + param :generic, String, :desc => N_("generic") + param :reason, String, :desc => N_("reason") + param :total_risk, :number, :desc => N_("total risk") + param :reboot_required, :bool, :desc => N_("reboot required") + param :more_info, String, :desc => N_("more info") + param :rating, :number, :desc => N_("rating") + end + + param :hits, Array, :desc => N_("upload hits information") do + param :rule_id, String, :desc => N_("rule id"), :required => true + param :title, String, :desc => N_("rule title") + param :solution_url, String, :desc => N_("solution url") + param :total_risk, :number, :desc => N_("total risk") + param :likelihood, :number, :desc => N_("likelihood number") + param :publish_date, String, :desc => N_("publish date (YYYY-MM-DD)") + param :results_url, String, :desc => N_("result url") + end + param :details, String, :desc => N_("upload hits details json") + end + + def upload_hits + host = Host.find_by(name: params.require(:host_name)) + payload = payload_params.to_h + task = ForemanTasks.async_task(ForemanHits::Async::Upload, host, params[:host_uuid], payload) + render json: { + task: task, + }, status: :ok + end + + def payload_params + params.require(:payload).permit( + :details, + { + resolutions: [ + :rule_id, :description, :needs_reboot, :resolution_risk, :resolution_type + ], + rules: [ + :rule_id, :description, :category_name, :impact_name, :summary, :generic, + :reason, :total_risk, :reboot_required, :more_info, :rating + ], + hits: [ + :rule_id, :title, :solution_url, :total_risk, :likelihood, :publish_date, :results_url + ], + } + ) + end end end end diff --git a/config/routes.rb b/config/routes.rb index d495c95f..3c46b21b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,13 +62,12 @@ namespace 'rh_cloud' do post 'enable_connector', to: 'inventory#enable_cloud_connector' - post 'cloud_request', to: 'cloud_request#update' end namespace 'advisor_engine' do get 'host_details', to: 'advisor_engine#host_details' - # post 'upload_hits', to: 'advisor_engine#upload_hits' + patch 'upload_hits', to: 'advisor_engine#upload_hits' end end end diff --git a/db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb b/db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb new file mode 100644 index 00000000..74887690 --- /dev/null +++ b/db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb @@ -0,0 +1,5 @@ +class AddUniqueIndexToRuleIdAndHostIdInInsightsHits < ActiveRecord::Migration[7.0] + def change + add_index :insights_hits, [:rule_id, :host_id], unique: true, name: 'index_insight_hits_on_rule_id_and_host_id' + end +end diff --git a/lib/foreman_hits/async/upload.rb b/lib/foreman_hits/async/upload.rb new file mode 100644 index 00000000..a00d9ff9 --- /dev/null +++ b/lib/foreman_hits/async/upload.rb @@ -0,0 +1,53 @@ +module ForemanHits + module Async + class Upload < ::Actions::EntryAction + def plan(host, uuid, payload = {}) + plan_self(host_id: host.id, uuid: uuid, payload: payload) + end + + def run + host = Host.find(input[:host_id]) + payload = input[:payload] + update_facets(host, input[:uuid]) + update_hits(host, payload) + update_rules_and_resolutions(payload) + update_details(host, payload) + end + + def update_facets(host, uuid) + facet = InsightsFacet.find_or_create_by(host_id: host.id) + facet.update!(uuid: uuid) if uuid.present? + host.reload + end + + def update_hits(host, payload) + facet = host.insights + facet.hits.delete_all + hits = payload[:hits] + # rubocop:disable Rails/SkipsModelValidations + facet.hits.insert_all(hits) + # rubocop:enable Rails/SkipsModelValidations + InsightsFacet.reset_counters(facet.id, :hits_count) + end + + def update_rules_and_resolutions(payload) + # rubocop:disable Rails/SkipsModelValidations + ::InsightsRule.upsert_all(payload[:rules], unique_by: :rule_id) + rules = payload[:rules].map { |rule| rule[:rule_id] } + ::InsightsResolution.where(rule_id: rules).delete_all + ::InsightsResolution.insert_all(payload[:resolutions]) + # rubocop:enable Rails/SkipsModelValidations + end + + def update_details(host, payload) + fact_name = FactName.where(name: "insights::hit_details", short_name: 'insights_details').first_or_create + fact_value = host.fact_values.where(fact_name: fact_name).first_or_create + fact_value.update(value: payload[:details]) + end + + def rescue_strategy_for_self + Dynflow::Action::Rescue::Fail + end + end + end +end From 83f298c2b903563cadbbd19b64c3e71f148bb25b Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 16 Jan 2025 17:00:13 -0500 Subject: [PATCH 2/6] Update app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb Co-authored-by: Jeremy Lenz --- .../api/v2/advisor_engine/advisor_engine_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index 26ea0f6c..022f6361 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -23,7 +23,7 @@ def host_details end end - api :PATCH, "/advisor_engine/upload_hits", N_("Upload from insights advisor") + api :PATCH, "/advisor_engine/upload_hits", N_("Upload hits from foreman-advisor-engine") param :host_name, String, required: true param :host_uuid, String From aec50558445e371b844cbd2a250724aef3029200 Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 16 Jan 2025 17:00:29 -0500 Subject: [PATCH 3/6] Update app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb Co-authored-by: Jeremy Lenz --- .../api/v2/advisor_engine/advisor_engine_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index 022f6361..ff5ce2b5 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -27,7 +27,7 @@ def host_details param :host_name, String, required: true param :host_uuid, String - param :payload, Hash, :desc => N_("On prem payload including resolutions, rules, hits") do + param :payload, Hash, :desc => N_("iop payload including resolutions, rules, hits") do param :resolutions, Array, :desc => N_("upload resolutions related to the hits") do param :rule_id, String, :desc => N_("rule id"), :required => true param :description, String, :desc => N_("resolution description") From 3285190d790c303d941085ce2904ce88a43535fd Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 16 Jan 2025 17:00:42 -0500 Subject: [PATCH 4/6] Update app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb Co-authored-by: Jeremy Lenz --- .../api/v2/advisor_engine/advisor_engine_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index ff5ce2b5..d43878e4 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -31,7 +31,7 @@ def host_details param :resolutions, Array, :desc => N_("upload resolutions related to the hits") do param :rule_id, String, :desc => N_("rule id"), :required => true param :description, String, :desc => N_("resolution description") - param :needs_reboot, :bool, :desc => N_("need reboot") + param :needs_reboot, :bool, :desc => N_("Whether the resolution requires reboot") param :resolution_risk, String, :desc => N_("resolution risk") param :resolution_type, String, :desc => N_("type") end From 1181fd405b2ed53dcb6e964b6eebe1bfae9265fe Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 16 Jan 2025 17:00:50 -0500 Subject: [PATCH 5/6] Update app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb Co-authored-by: Jeremy Lenz --- .../api/v2/advisor_engine/advisor_engine_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index d43878e4..345a5b00 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -36,7 +36,7 @@ def host_details param :resolution_type, String, :desc => N_("type") end - param :rules, Array, :desc => N_("upload rules related to the hits") do + param :rules, Array, :desc => N_("Upload rules related to the hits") do param :rule_id, String, :desc => N_("rule id"), :required => true param :description, String, :desc => N_("rule description") param :category_name, String, :desc => N_("category name") From 8d5eade86693db619dd7dbb12a551c644ceae56e Mon Sep 17 00:00:00 2001 From: Partha Aji Date: Thu, 16 Jan 2025 17:00:57 -0500 Subject: [PATCH 6/6] Update app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb Co-authored-by: Jeremy Lenz --- .../api/v2/advisor_engine/advisor_engine_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb index 345a5b00..b0f806e7 100644 --- a/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +++ b/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb @@ -50,7 +50,7 @@ def host_details param :rating, :number, :desc => N_("rating") end - param :hits, Array, :desc => N_("upload hits information") do + param :hits, Array, :desc => N_("Upload hits information") do param :rule_id, String, :desc => N_("rule id"), :required => true param :title, String, :desc => N_("rule title") param :solution_url, String, :desc => N_("solution url")