From d248f1550daefe0a32ce9213cdd506cdeabfb439 Mon Sep 17 00:00:00 2001 From: Jonathon Turel Date: Tue, 14 Jul 2026 19:41:25 +0000 Subject: [PATCH] Fixes #39308 - Skip Candlepin update when subscription facet is destroyed --- .../subscription_facet_host_extensions.rb | 9 +++++-- app/models/katello/host/subscription_facet.rb | 2 ++ test/factories/content_facet_factory.rb | 24 +++++++++++++++-- .../content_view_environment_factory.rb | 19 +++----------- test/factories/host_factory.rb | 2 +- test/factories/katello_erratum_factory.rb | 5 ++++ test/factories/repository_factory.rb | 2 +- .../concerns/host_managed_extensions_test.rb | 7 +++++ ...subscription_facet_host_extensions_test.rb | 26 +++++++++++++++++++ 9 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 test/factories/katello_erratum_factory.rb create mode 100644 test/models/concerns/subscription_facet_host_extensions_test.rb diff --git a/app/models/katello/concerns/subscription_facet_host_extensions.rb b/app/models/katello/concerns/subscription_facet_host_extensions.rb index a05b083bb95..5e8da700699 100644 --- a/app/models/katello/concerns/subscription_facet_host_extensions.rb +++ b/app/models/katello/concerns/subscription_facet_host_extensions.rb @@ -38,7 +38,7 @@ def update_candlepin_associations(consumer_params = nil) content_facet.cvenvs_changed = false if content_facet content_facet&.save! - if subscription_facet + if subscription_facet && !subscription_facet.destroyed? consumer_params ||= subscription_facet.consumer_attributes host_uuid = consumer_params.dig(:facts, 'dmi.system.uuid') @@ -48,7 +48,12 @@ def update_candlepin_associations(consumer_params = nil) override_value ||= subscription_facet.update_dmi_uuid_override&.value consumer_params[:facts]['dmi.system.uuid'] = override_value end - ::Katello::Resources::Candlepin::Consumer.update(subscription_facet.uuid, consumer_params) + + begin + ::Katello::Resources::Candlepin::Consumer.update(subscription_facet.uuid, consumer_params) + rescue RestClient::Gone, RestClient::NotFound + raise "Unable to update missing or deleted candlepin consumer uuid=#{subscription_facet.uuid} host_id=#{self.id}" + end if consumer_params.try(:[], :facts) ::Katello::Host::SubscriptionFacet.update_facts(self, consumer_params[:facts]) diff --git a/app/models/katello/host/subscription_facet.rb b/app/models/katello/host/subscription_facet.rb index 0dd2c2accc1..d69f8d9553f 100644 --- a/app/models/katello/host/subscription_facet.rb +++ b/app/models/katello/host/subscription_facet.rb @@ -250,6 +250,8 @@ def candlepin_consumer end def backend_update_needed? + return false if self.destroyed? + %w(release_version service_level purpose_role purpose_usage).each do |method| if self.send("#{method}_changed?") Rails.logger.debug("backend_update_needed: subscription facet #{method} changed") diff --git a/test/factories/content_facet_factory.rb b/test/factories/content_facet_factory.rb index 6212d812f55..d30af10d619 100644 --- a/test/factories/content_facet_factory.rb +++ b/test/factories/content_facet_factory.rb @@ -1,5 +1,25 @@ FactoryBot.define do - factory :katello_content_facets, :aliases => [:content_facet], :class => ::Katello::Host::ContentFacet do - # UUID removed - it belongs to subscription_facet, not content_facet + factory :katello_content_facet, :aliases => [:content_facet], :class => ::Katello::Host::ContentFacet do + host { association(:host, content_facet: @instance) } + + trait :with_content_view_environment do + content_view_environments { [association(:katello_content_view_environment)] } + end + + trait :with_content_source do + content_source { association(:smart_proxy, :with_pulp3) } + end + + trait :with_kickstart_repository do + kickstart_repository { association(:katello_repository, :with_product) } + end + + trait :with_applicable_errata do + applicable_errata { [association(:katello_erratum)] } + end + + trait :with_bound_repositories do + bound_repositories { [association(:katello_repository)] } + end end end diff --git a/test/factories/content_view_environment_factory.rb b/test/factories/content_view_environment_factory.rb index 5538aba4681..d68c2ddd6a0 100644 --- a/test/factories/content_view_environment_factory.rb +++ b/test/factories/content_view_environment_factory.rb @@ -5,21 +5,8 @@ # - environment: the lifecycle environment # The content_view will be automatically set from the version - association :content_view_version, :factory => :katello_content_view_version - - after(:build) do |cve, _evaluator| - # Set content_view from the version - if cve.content_view_version && !cve.content_view - cve.content_view = cve.content_view_version.content_view - end - - # Set environment to library if not provided - unless cve.environment - org = cve.content_view&.organization || cve.content_view_version&.content_view&.organization - if org - cve.environment = org.library - end - end - end + content_view_version { association(:katello_content_view_version) } + content_view { content_view_version.content_view } + environment { association(:katello_environment, organization: content_view.organization) } end end diff --git a/test/factories/host_factory.rb b/test/factories/host_factory.rb index aeba94a7eb3..dd2ef8e9e29 100644 --- a/test/factories/host_factory.rb +++ b/test/factories/host_factory.rb @@ -11,7 +11,7 @@ end trait :with_content do - association :content_facet, :factory => :content_facet, :strategy => :build + association :content_facet, host: @instance, :factory => :content_facet, :strategy => :build after(:build) do |host, evaluator| if host.content_facet diff --git a/test/factories/katello_erratum_factory.rb b/test/factories/katello_erratum_factory.rb new file mode 100644 index 00000000000..4f5b493ef2f --- /dev/null +++ b/test/factories/katello_erratum_factory.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :katello_erratum, class: Katello::Erratum do + sequence(:pulp_id) { |n| n } + end +end diff --git a/test/factories/repository_factory.rb b/test/factories/repository_factory.rb index 02f77315761..7c76dc8b5c9 100644 --- a/test/factories/repository_factory.rb +++ b/test/factories/repository_factory.rb @@ -65,7 +65,7 @@ trait :with_product do with_content_view - product { FactoryBot.create(:katello_product, :with_provider, organization: organization) } + product { association(:katello_product, :with_provider, organization: organization) } end trait :deb do diff --git a/test/models/concerns/host_managed_extensions_test.rb b/test/models/concerns/host_managed_extensions_test.rb index c0763d1344f..e55be2758a2 100644 --- a/test/models/concerns/host_managed_extensions_test.rb +++ b/test/models/concerns/host_managed_extensions_test.rb @@ -250,6 +250,13 @@ def test_backend_update_needed? assert subscription_facet.backend_update_needed? end + def test_backend_update_needed_facet_destroyed + host = FactoryBot.build_stubbed(:host, :with_subscription) + host.subscription_facet.expects(:destroyed?).returns(true) + + refute host.subscription_facet.backend_update_needed? + end + def test_host_update_with_overridden_dmi_uuid ::Setting[:host_dmi_uuid_duplicates] = ['duplicate-dmi-uuid'] params = {facts: {'dmi.system.uuid' => 'duplicate-dmi-uuid'}}.with_indifferent_access diff --git a/test/models/concerns/subscription_facet_host_extensions_test.rb b/test/models/concerns/subscription_facet_host_extensions_test.rb new file mode 100644 index 00000000000..bc44feac838 --- /dev/null +++ b/test/models/concerns/subscription_facet_host_extensions_test.rb @@ -0,0 +1,26 @@ +require 'katello_test_helper' + +module Katello + class SubscriptionFacetHostExtensionsTest + class UpdateCandlepinAssociationsTest < ActiveSupport::TestCase + test "doesn't update candlepin if subscription facet was destroyed" do + host = FactoryBot.build_stubbed(:host, :with_content, :with_subscription) + host.content_facet.stubs(:save!) + host.subscription_facet.expects(:destroyed?).once.returns(true) + ::Katello::Resources::Candlepin::Consumer.expects(:update).never + + host.update_candlepin_associations + end + + test "raises RuntimeError if consumer is gone" do + host = FactoryBot.build_stubbed(:host, :with_content, :with_subscription) + ::Katello::Resources::Candlepin::Consumer.expects(:update).raises(RestClient::Gone) + host.content_facet.stubs(:save!) + + assert_raises(RuntimeError, /missing or deleted/) do + host.update_candlepin_associations + end + end + end + end +end