Bug #37543
closedCV promote fails with undefined method `get_status' for nil:NilClass when deleting a Host in the CV during Finalize phase of the Promote task
Description
Description of problem:
When promoting a CV to a LE (maybe also during other scenarios, not sure now), the task can fail during Finalize step Actions::Katello::ContentView::PromoteToEnvironment .
The reason is in code:
/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/content_view.rb new line 437:
~~~
def update_host_statuses(environment)
update errata applicability counts for all hosts in the CV & LE
Location.no_taxonomy_scope do
User.as_anonymous_admin do
::Katello::Host::ContentFacet.in_content_views_and_environments(
content_views: [self],
lifecycle_environments: [environment]
).each do |facet|
facet.update_applicability_counts
facet.update_errata_status
end
end
end
end
~~~
where:
1) ContentFacet list is generated
2) for each facet, applicability is being recalculated
3) some Host for such a facet is deleted
4) the facet for the deleted Host is being recalculated
Then, the 4) fails with backtrace:
NoMethodError
undefined method `get_status' for nil:NilClass
—
"/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/host/content_facet.rb:331:in
`update_errata_status'"
"/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/content_view.rb:438:in
`block (3 levels) in update_host_statuses'"
"/usr/share/gems/gems/activerecord-6.1.7.4/lib/active_record/relation/delegation.rb:88:in
`each'"
"/usr/share/gems/gems/activerecord-6.1.7.4/lib/active_record/relation/delegation.rb:88:in
`each'"
"/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/content_view.rb:436:in
`block (2 levels) in update_host_statuses'"
"/usr/share/foreman/app/models/concerns/foreman/thread_session.rb:108:in `as'"
"/usr/share/foreman/app/models/concerns/foreman/thread_session.rb:114:in `as_anonymous_admin'"
"/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/content_view.rb:432:in
`block in update_host_statuses'"
"/usr/share/foreman/app/models/taxonomy.rb:73:in `block in no_taxonomy_scope'"
"/usr/share/foreman/app/models/taxonomy.rb:80:in `block (2 levels) in as_taxonomy'"
"/usr/share/foreman/app/models/concerns/foreman/thread_session.rb:195:in `as_location'"
"/usr/share/foreman/app/models/taxonomy.rb:79:in `block in as_taxonomy'"
"/usr/share/foreman/app/models/concerns/foreman/thread_session.rb:154:in `as_org'"
"/usr/share/foreman/app/models/taxonomy.rb:78:in `as_taxonomy'"
"/usr/share/foreman/app/models/taxonomy.rb:72:in `no_taxonomy_scope'"
"/usr/share/gems/gems/katello-4.9.0.25/app/models/katello/content_view.rb:431:in
`update_host_statuses'"
"/usr/share/gems/gems/katello-4.9.0.25/app/lib/actions/katello/content_view/promote_to_environment.rb:49:in
`finalize'"
Because we call "host.get_status(::Katello::ErrataStatus).refresh!" for a removed Host.
Version-Release number of selected component (if applicable):
Applicable to any version, I think
How reproducible:
100%
Steps to Reproduce:
1. Have Foreman with a bigger CV (promoted to non-Library LE) and many Hosts associated to the CV/LE. To populate fake Hosts, you can run below script in a loop:
~~~
domain=YOUR.HOST.DOMAIN
ak=YOUR.ACTIVATION.KEY
org=YOUR.ORGANIZATION
uuid=$(uuidgen)
short=$(hostname -s)
echo "{\"dmi.system.uuid\": \"${uuid}\"}" > /etc/rhsm/facts/uuid.facts
hostnamectl set-hostname ${short}.${uuid%%-*}.${domain}
subscription-manager clean
subscription-manager register --activationkey ${ak} --org ${org}
~~~
(a few hundreds of Hosts is sufficient)
2. Create a new version of the CV and promote it to the LE associated with the Hosts.
3. During the promote, regularly delete some Hosts - you must catch the time when Finalize phase is running.
One can mimic 2. even for already promoted CV/LE by running (customize own CV id and LE id):
(within foreman-rake console)
::Katello::ContentView.find(54).update_host_statuses(Katello::KTEnvironment.find(2))
(once you run this, delete a Host)
Actual results:
2. fails in Actions::Katello::ContentView::PromoteToEnvironment step in Finalize phase with above backtrace.
Optionally, foreman-rake mimicking reproducer fails with:
irb(main):138:0> ::Katello::ContentView.find(54).update_host_statuses(Katello::KTEnvironment.find(2))
Traceback (most recent call last):
16: from lib/tasks/console.rake:5:in `block in <top (required)>'
15: from (irb):138
14: from katello (4.9.0.25) app/models/katello/content_view.rb:431:in `update_host_statuses'
13: from app/models/taxonomy.rb:72:in `no_taxonomy_scope'
12: from app/models/taxonomy.rb:78:in `as_taxonomy'
11: from app/models/concerns/foreman/thread_session.rb:154:in `as_org'
10: from app/models/taxonomy.rb:79:in `block in as_taxonomy'
9: from app/models/concerns/foreman/thread_session.rb:195:in `as_location'
8: from app/models/taxonomy.rb:80:in `block (2 levels) in as_taxonomy'
7: from app/models/taxonomy.rb:73:in `block in no_taxonomy_scope'
6: from katello (4.9.0.25) app/models/katello/content_view.rb:432:in `block in update_host_statuses'
5: from app/models/concerns/foreman/thread_session.rb:114:in `as_anonymous_admin'
4: from app/models/concerns/foreman/thread_session.rb:108:in `as'
3: from katello (4.9.0.25) app/models/katello/content_view.rb:436:in `block (2 levels) in update_host_statuses'
2: from katello (4.9.0.25) app/models/katello/content_view.rb:439:in `block (3 levels) in update_host_statuses'
1: from katello (4.9.0.25) app/models/katello/host/content_facet.rb:331:in `update_errata_status'
NoMethodError (undefined method `get_status' for nil:NilClass)
irb(main):139:0>
Expected results:
No such exception.
Additional info:
Potential fix: add "if content.host" twice:
def update_host_statuses(environment)
update errata applicability counts for all hosts in the CV & LE
Location.no_taxonomy_scope do
User.as_anonymous_admin do
::Katello::Host::ContentFacet.in_content_views_and_environments(
content_views: [self],
lifecycle_environments: [environment]
).each do |facet|
facet.update_applicability_counts if facet.host # here it is optional
facet.update_errata_status if facet.host # here it is crucial
end
end
end
end