diff --git a/app/controllers/api/v2/insights_advisor/insights_advisor_controller.rb b/app/controllers/api/v2/insights_advisor/insights_advisor_controller.rb new file mode 100644 index 00000000..b3c80374 --- /dev/null +++ b/app/controllers/api/v2/insights_advisor/insights_advisor_controller.rb @@ -0,0 +1,23 @@ +module Api + module V2 + module InsightsAdvisor + class InsightsAdvisorController < ::Api::V2::BaseController + include ::Api::Version2 + + api :GET, "insights_advisor/host_details", N_('Fetch Insights-related host details') + param :host_uuids, Array, required: true, desc: N_('List of host UUIDs') + def host_details + uuids = params.require(:host_uuids) + @hosts = ::Host.joins(:insights).where(:insights => { :uuid => uuids }) + if @hosts.empty? + render json: { error: 'No hosts found for the given UUIDs' }, status: :not_found + else + respond_to do |format| + format.json { render 'api/v2/insights_advisor/host_details' } + end + end + end + end + end + end +end diff --git a/app/models/concerns/rh_cloud_host.rb b/app/models/concerns/rh_cloud_host.rb index e776ae84..4436f59f 100644 --- a/app/models/concerns/rh_cloud_host.rb +++ b/app/models/concerns/rh_cloud_host.rb @@ -21,5 +21,10 @@ module RhCloudHost scoped_search :relation => :inventory_sync_status_object, :on => :status, :rename => :insights_inventory_sync_status, :complete_value => { :disconnect => ::InventorySync::InventoryStatus::DISCONNECT, :sync => ::InventorySync::InventoryStatus::SYNC } + scoped_search :relation => :insights, :on => :uuid, :only_explicit => true, :rename => :insights_uuid + + def insights_facet + insights + end end end diff --git a/app/views/api/v2/hosts/insights/base.rabl b/app/views/api/v2/hosts/insights/base.rabl new file mode 100644 index 00000000..2afff2b0 --- /dev/null +++ b/app/views/api/v2/hosts/insights/base.rabl @@ -0,0 +1,5 @@ +attributes :uuid + +node :insights_hit_details do |facet| + facet&.host&.facts('insights::hit_details')&.values&.first +end diff --git a/app/views/api/v2/hosts/insights/insights.rabl b/app/views/api/v2/hosts/insights/insights.rabl new file mode 100644 index 00000000..645bb595 --- /dev/null +++ b/app/views/api/v2/hosts/insights/insights.rabl @@ -0,0 +1,3 @@ +node :insights_attributes do + partial 'api/v2/hosts/insights/base', object: @object&.insights_facet +end diff --git a/app/views/api/v2/insights_advisor/host_details.json.rabl b/app/views/api/v2/insights_advisor/host_details.json.rabl new file mode 100644 index 00000000..24a94809 --- /dev/null +++ b/app/views/api/v2/insights_advisor/host_details.json.rabl @@ -0,0 +1,9 @@ +collection @hosts + +attributes :name +node :insights_uuid do |host| + host.insights_facet&.uuid +end +node :insights_hit_details do |host| + host&.facts('insights::hit_details')&.values&.first +end diff --git a/config/routes.rb b/config/routes.rb index 1c7aaa77..97dfe12a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -65,6 +65,11 @@ post 'cloud_request', to: 'cloud_request#update' end + + namespace 'insights_advisor' do + get 'host_details', to: 'insights_advisor#host_details' + # post 'upload_hits', to: 'insights_advisor#upload_hits' + end end end end diff --git a/lib/foreman_rh_cloud/engine.rb b/lib/foreman_rh_cloud/engine.rb index 69d3a57a..51f6fd99 100644 --- a/lib/foreman_rh_cloud/engine.rb +++ b/lib/foreman_rh_cloud/engine.rb @@ -112,6 +112,7 @@ def self.register_scheduled_task(task_class, cronline) register_facet InsightsFacet, :insights do configure_host do + api_view :list => 'api/v2/hosts/insights/insights' set_dependent_action :destroy end end @@ -151,6 +152,12 @@ def self.register_scheduled_task(task_class, cronline) end end + initializer "foreman_rh_cloud.add_rabl_view_path" do + Rabl.configure do |config| + config.view_paths << ForemanRhCloud::Engine.root.join('app', 'views') + end + end + initializer 'foreman_rh_cloud.register_scheduled_tasks', :before => :finisher_hook do |_app| # skip database manipulations while tables do not exist, like in migrations # skip object creation when admin user is not present, for example in test DB diff --git a/test/controllers/insights_cloud/api/insights_advisor_controller_test.rb b/test/controllers/insights_cloud/api/insights_advisor_controller_test.rb new file mode 100644 index 00000000..fa6b4ed6 --- /dev/null +++ b/test/controllers/insights_cloud/api/insights_advisor_controller_test.rb @@ -0,0 +1,31 @@ +require 'test_plugin_helper' + +module InsightsCloud + module Api + class InsightsAdvisorControllerTest < ActionController::TestCase + tests ::Api::V2::InsightsAdvisor::InsightsAdvisorController + + setup do + @test_org = FactoryBot.create(:organization) + @host1 = FactoryBot.create(:host, :with_insights_hits, organization: @test_org, hostname: 'insightshost1') + @host2 = FactoryBot.create(:host, :with_insights_hits, organization: @test_org, hostname: 'insightshost2') + @host3 = FactoryBot.create(:host, organization: @test_org) + end + + test 'shows hosts with uuids' do + uuids = [@host1.insights.uuid, @host2.insights.uuid] + get :host_details, params: { organization_id: @test_org.id, host_uuids: uuids } + assert_response :success + assert_template 'api/v2/insights_advisor/host_details' + assert_equal @test_org.hosts.joins(:insights).where(:insights => { :uuid => uuids }).count, assigns(:hosts).count + refute_equal @test_org.hosts.count, assigns(:hosts).count + end + + test 'shows error when no hosts found' do + get :host_details, params: { organization_id: @test_org.id, host_uuids: ['nonexistentuuid'] } + assert_response :not_found + assert_equal 'No hosts found for the given UUIDs', JSON.parse(response.body)['error'] + end + end + end +end diff --git a/test/factories/insights_factories.rb b/test/factories/insights_factories.rb index e9bf730c..725aa25d 100644 --- a/test/factories/insights_factories.rb +++ b/test/factories/insights_factories.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :insights_facet do - # sequence(:uuid) { |n| "uuid-#{n}" } + sequence(:uuid) { |n| "uuid-#{n}" } trait :with_hits do hits do