Skip to content

Commit

Permalink
Fixes #36693 - Add new host status for RHEL lifecycle (#10706)
Browse files Browse the repository at this point in the history
* Fixes #36693 - Add new host status for RHEL lifecycle
* Refs #36693 - Update errata and RHEL lifecycle status during applicability calculation
  • Loading branch information
jeremylenz authored Sep 1, 2023
1 parent ea06f3d commit d442ec1
Show file tree
Hide file tree
Showing 11 changed files with 473 additions and 5 deletions.
26 changes: 26 additions & 0 deletions app/models/katello/concerns/host_managed_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def remote_execution_proxies(provider, *_rest)
delegate :content_source_id, :single_content_view, :single_lifecycle_environment, :default_environment?, :single_content_view_environment?, :multi_content_view_environment?, :kickstart_repository_id, :bound_repositories,
:installable_errata, :installable_rpms, to: :content_facet, allow_nil: true

delegate :rhel_eos_schedule_index, to: :operatingsystem, allow_nil: true

has_many :content_view_environment_content_facets, through: :content_facet, class_name: 'Katello::ContentViewEnvironmentContentFacet'
has_many :content_view_environments, through: :content_view_environment_content_facets
has_many :content_views, through: :content_view_environments
Expand Down Expand Up @@ -481,6 +483,30 @@ def purpose_addons_status_label(options = {})
@purpose_addons_status_label ||= get_status(::Katello::PurposeAddonsStatus).to_label(options)
end

def rhel_lifecycle_status
@rhel_lifecycle_status ||= get_status(::Katello::RhelLifecycleStatus).status
end

def rhel_lifecycle_status_label
@rhel_lifecycle_status_label ||= get_status(::Katello::RhelLifecycleStatus).to_label
end

def full_support_end_date
::Katello::RhelLifecycleStatus.full_support_end_dates[rhel_eos_schedule_index]
end

def maintenance_support_end_date
::Katello::RhelLifecycleStatus.maintenance_support_end_dates[rhel_eos_schedule_index]
end

def extended_support_end_date
::Katello::RhelLifecycleStatus.extended_support_end_dates[rhel_eos_schedule_index]
end

def end_of_support_date
::Katello::RhelLifecycleStatus.eos_date(eos_schedule_index: rhel_eos_schedule_index)
end

def traces_status
@traces_status ||= get_status(::Katello::TraceStatus).status
end
Expand Down
17 changes: 17 additions & 0 deletions app/models/katello/concerns/operatingsystem_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,23 @@ def set_atomic_attributes
def atomic?
name.match(/.*atomic.*/i)
end

def rhel_eos_schedule_index(arch_name: nil)
return nil unless name == "RedHat" # using name and not title so we get specifically RHEL, not rebuilds
return "RHEL#{major}" unless major == "7"
case arch_name
when "x86_64", nil
"RHEL7"
when "ppc64le"
"RHEL7 (POWER9)"
when "aarch64"
"RHEL7 (ARM)"
when "s390x"
"RHEL7 (System z (Structure A))"
else
"RHEL#{major}"
end
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module SubscriptionFacetHostExtensions
has_one :purpose_usage_status_object, :class_name => 'Katello::PurposeUsageStatus', :foreign_key => 'host_id', :dependent => :destroy
has_one :purpose_addons_status_object, :class_name => 'Katello::PurposeAddonsStatus', :foreign_key => 'host_id', :dependent => :destroy
has_one :purpose_status_object, :class_name => 'Katello::PurposeStatus', :foreign_key => 'host_id', :dependent => :destroy
has_one :rhel_lifecycle_status_object, :class_name => 'Katello::RhelLifecycleStatus', :foreign_key => 'host_id', :dependent => :destroy
has_one :hypervisor_host, :through => :subscription_facet

scoped_search :on => :status, :relation => :subscription_status_object, :rename => :subscription_status,
Expand All @@ -41,6 +42,7 @@ module SubscriptionFacetHostExtensions
scoped_search on: :status, relation: :purpose_usage_status_object, rename: :usage_status, complete_value: purpose_status_map
scoped_search on: :status, relation: :purpose_addons_status_object, rename: :addons_status, complete_value: purpose_status_map
scoped_search on: :status, relation: :purpose_status_object, rename: :purpose_status, complete_value: purpose_status_map
scoped_search on: :status, relation: :rhel_lifecycle_status_object, rename: :rhel_lifecycle_status, complete_value: rhel_lifecycle_status_map

scoped_search :on => :release_version, :relation => :subscription_facet, :complete_value => true, :only_explicit => true
scoped_search :on => :autoheal, :relation => :subscription_facet, :complete_value => true, :only_explicit => true
Expand Down Expand Up @@ -100,6 +102,10 @@ def purpose_status_map
::Katello::PurposeStatus.status_map
end

def rhel_lifecycle_status_map
::Katello::RhelLifecycleStatus.status_map
end

def find_by_purpose_addon(_key, operator, value)
conditions = sanitize_sql_for_conditions(["#{Katello::PurposeAddon.table_name}.name #{operator} ?", value_to_sql(operator, value)])
hosts = ::Host::Managed.joins(:purpose_addons).where(conditions)
Expand Down
2 changes: 1 addition & 1 deletion app/models/katello/host/content_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def calculate_and_import_applicability
::Katello::Applicability::ApplicableContentHelper.new(self, ::Katello::Erratum, bound_repos).calculate_and_import
::Katello::Applicability::ApplicableContentHelper.new(self, ::Katello::ModuleStream, bound_repos).calculate_and_import
update_applicability_counts
self.update_errata_status
self.host&.refresh_statuses([::Katello::ErrataStatus, ::Katello::RhelLifecycleStatus])
end

def update_applicability_counts
Expand Down
206 changes: 206 additions & 0 deletions app/models/katello/rhel_lifecycle_status.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
module Katello
class RhelLifecycleStatus < HostStatus::Status
UNKNOWN = 0
FULL_SUPPORT = 1
MAINTENANCE_SUPPORT = 2
APPROACHING_END_OF_MAINTENANCE = 3
EXTENDED_SUPPORT = 4
APPROACHING_END_OF_SUPPORT = 5
SUPPORT_ENDED = 6

def self.end_of_day(date)
DateTime.parse(date.to_s).end_of_day.utc
end

RHEL_EOS_SCHEDULE = { # dates that each support category ends
'RHEL9' => {
'full_support' => end_of_day('2027-05-31'),
'maintenance_support' => end_of_day('2032-05-31'),
'extended_support' => end_of_day('2035-05-31')
},
'RHEL8' => {
'full_support' => end_of_day('2024-05-31'),
'maintenance_support' => end_of_day('2029-05-31'),
'extended_support' => end_of_day('2032-05-31')
},
'RHEL7' => {
'full_support' => end_of_day('2019-08-06'),
'maintenance_support' => end_of_day('2024-06-30'),
'extended_support' => end_of_day('2028-06-30')
},
'RHEL7 (System z (Structure A))' => {
'full_support' => end_of_day('2019-08-06'),
'maintenance_support' => end_of_day('2021-05-31')
},
'RHEL7 (ARM)' => {
'full_support' => end_of_day('2019-08-06'),
'maintenance_support' => end_of_day('2020-11-30')
},
'RHEL7 (POWER9)' => {
'full_support' => end_of_day('2019-08-06'),
'maintenance_support' => end_of_day('2021-05-31')
},
'RHEL6' => {
'full_support' => end_of_day('2016-05-10'),
'maintenance_support' => end_of_day('2020-11-30'),
'extended_support' => end_of_day('2024-06-30')
},
'RHEL5' => {
'full_support' => end_of_day('2013-01-08'),
'maintenance_support' => end_of_day('2017-03-31'),
'extended_support' => end_of_day('2020-11-30')
}
}.freeze

EOS_WARNING_THRESHOLD = 1.year

def self.status_map
map = {
full_support: FULL_SUPPORT,
maintenance_support: MAINTENANCE_SUPPORT,
approaching_end_of_maintenance: APPROACHING_END_OF_MAINTENANCE,
extended_support: EXTENDED_SUPPORT,
approaching_end_of_support: APPROACHING_END_OF_SUPPORT,
support_ended: SUPPORT_ENDED
}

map.default = UNKNOWN
map
end

def self.approaching_end_of_category(eos_schedule_index:)
RHEL_EOS_SCHEDULE[eos_schedule_index].select { |_k, v| (Time.now.utc..Time.now.utc + EOS_WARNING_THRESHOLD).cover?(v) }
end

def self.to_status(rhel_eos_schedule_index: nil)
release = rhel_eos_schedule_index
return UNKNOWN unless release.present? && RHEL_EOS_SCHEDULE.key?(release)
approach = approaching_end_of_category(eos_schedule_index: release)
if approach.present?
case approach.keys.first
when last_support_category(eos_schedule_index: release)
return APPROACHING_END_OF_SUPPORT
when 'maintenance_support'
return APPROACHING_END_OF_MAINTENANCE
end
end

full_support_end_date = RHEL_EOS_SCHEDULE[release]['full_support']
maintenance_support_end_date = RHEL_EOS_SCHEDULE[release]['maintenance_support']
extended_support_end_date = RHEL_EOS_SCHEDULE[release]['extended_support']

case
when Date.today <= full_support_end_date
return FULL_SUPPORT
when Date.today <= maintenance_support_end_date
return MAINTENANCE_SUPPORT
when extended_support_end_date.present? && Date.today <= extended_support_end_date
return EXTENDED_SUPPORT
else
return SUPPORT_ENDED
end
end

def self.status_name
N_('RHEL lifecycle')
end

def self.humanized_name
'rhel_lifecycle'
end

# {"RHEL9"=>2035-05-31 23:59:59.999999999 UTC,
# "RHEL8"=>2032-05-31 23:59:59.999999999 UTC, ... }
def self.schedule_slice(support_category)
{}.merge(*RHEL_EOS_SCHEDULE.keys.map do |release|
{ release => RHEL_EOS_SCHEDULE[release]&.[](support_category) }
end)
end

def self.full_support_end_dates
schedule_slice('full_support')
end

def self.maintenance_support_end_dates
schedule_slice('maintenance_support')
end

def self.extended_support_end_dates
schedule_slice('extended_support')
end

def self.last_support_category(eos_schedule_index:)
RHEL_EOS_SCHEDULE[eos_schedule_index].keys.last
end

def self.eos_date(eos_schedule_index: nil)
return nil unless eos_schedule_index
RHEL_EOS_SCHEDULE[eos_schedule_index]&.[]('extended_support') ||
RHEL_EOS_SCHEDULE[eos_schedule_index]&.[]('maintenance_support')
end

def self.to_label(status, eos_date: nil, maintenance_support_end_date: nil)
case status
when FULL_SUPPORT
N_('Full support')
when MAINTENANCE_SUPPORT
N_('Maintenance support')
when APPROACHING_END_OF_MAINTENANCE
if maintenance_support_end_date.present?
N_('Approaching end of maintenance support (%s)') % maintenance_support_end_date.strftime('%Y-%m-%d')
else
N_('Approaching end of maintenance support')
end
when EXTENDED_SUPPORT
N_('Extended support')
when APPROACHING_END_OF_SUPPORT
if eos_date.present?
N_('Approaching end of support (%s)') % eos_date.strftime('%Y-%m-%d')
else
N_('Approaching end of support')
end
when SUPPORT_ENDED
N_('Support ended')
else
N_('Unknown')
end
end

def to_label(_options = {})
self.class.to_label(status, eos_date: eos_date, maintenance_support_end_date: maintenance_support_end_date)
end

def eos_date
self.class.eos_date(eos_schedule_index: rhel_eos_schedule_index)
end

def maintenance_support_end_date
self.class.maintenance_support_end_dates[rhel_eos_schedule_index]
end

def rhel_eos_schedule_index
host&.operatingsystem&.rhel_eos_schedule_index(arch_name: host&.arch&.name)
end

def to_global(_options = {})
if [FULL_SUPPORT, MAINTENANCE_SUPPORT, EXTENDED_SUPPORT].include?(status)
::HostStatus::Global::OK
elsif [APPROACHING_END_OF_SUPPORT, APPROACHING_END_OF_MAINTENANCE].include?(status)
::HostStatus::Global::WARN
elsif [SUPPORT_ENDED].include?(status)
::HostStatus::Global::ERROR
else
::HostStatus::Global::OK
end
end

def to_status
self.class.to_status(rhel_eos_schedule_index: self.host&.operatingsystem&.rhel_eos_schedule_index)
end

# this status is only relevant for RHEL
def relevant?(_options = {})
host&.operatingsystem&.rhel_eos_schedule_index
end
end
end
1 change: 1 addition & 0 deletions app/services/katello/host_status_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class HostStatusManager
Katello::PurposeUsageStatus,
Katello::PurposeAddonsStatus,
Katello::PurposeStatus,
Katello::RhelLifecycleStatus,
Katello::TraceStatus].freeze

PURPOSE_STATUS = [
Expand Down
8 changes: 5 additions & 3 deletions app/services/katello/registration_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,11 @@ def finalize_registration(host)
host.subscription_facet.update_from_consumer_attributes(host.subscription_facet.candlepin_consumer.
consumer_attributes.except(:guestIds, :facts))
host.subscription_facet.save!
host.subscription_facet.update_subscription_status
host.content_facet.update_errata_status
host.refresh_global_status!
host.refresh_statuses([
::Katello::ErrataStatus,
::Katello::SubscriptionStatus,
::Katello::RhelLifecycleStatus
])
end

def set_host_collections(host, activation_keys)
Expand Down
28 changes: 28 additions & 0 deletions test/models/concerns/host_managed_extensions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,34 @@ def test_search_known_traces
end
end

class HostRhelEosSchedulesTest < ActiveSupport::TestCase
let(:host) { FactoryBot.create(:host, :with_subscription) }

def test_full_support_end_dates
host.expects(:rhel_eos_schedule_index).returns('RHEL9')
expected_date = ::Katello::RhelLifecycleStatus.full_support_end_dates['RHEL9']
assert_equal expected_date, host.full_support_end_date
end

def test_maintenance_support_end_dates
host.expects(:rhel_eos_schedule_index).returns('RHEL9')
expected_date = ::Katello::RhelLifecycleStatus.maintenance_support_end_dates['RHEL9']
assert_equal expected_date, host.maintenance_support_end_date
end

def test_extended_support_end_dates
host.expects(:rhel_eos_schedule_index).returns('RHEL9')
expected_date = ::Katello::RhelLifecycleStatus.extended_support_end_dates['RHEL9']
assert_equal expected_date, host.extended_support_end_date
end

def test_end_of_support_dates
host.expects(:rhel_eos_schedule_index).returns('RHEL9')
expected_date = ::Katello::RhelLifecycleStatus.eos_date(eos_schedule_index: 'RHEL9')
assert_equal expected_date, host.end_of_support_date
end
end

class HostManagedExtensionsKickstartTest < ActiveSupport::TestCase
def setup
disable_orchestration # disable foreman orchestration
Expand Down
16 changes: 16 additions & 0 deletions test/models/concerns/operatingsystem_extensions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,21 @@ def test_assign_template_for_atomic
assert_equal "x86_64", os.architectures.first.name
assert_equal "#{::Operatingsystem::REDHAT_ATOMIC_HOST_DISTRO_NAME} 7.3", os.description
end

def test_rhel_eos_schedule_index
os = Operatingsystem.create!(:name => "RedHat", :major => "7", :minor => "3")
assert_equal "RHEL7", os.rhel_eos_schedule_index
assert_equal "RHEL7 (POWER9)", os.rhel_eos_schedule_index(arch_name: "ppc64le")
assert_equal "RHEL7 (ARM)", os.rhel_eos_schedule_index(arch_name: "aarch64")
assert_equal "RHEL7 (System z (Structure A))", os.rhel_eos_schedule_index(arch_name: "s390x")

os = Operatingsystem.create!(:name => "RedHat", :major => "6", :minor => "3")
assert_equal "RHEL6", os.rhel_eos_schedule_index
end

def test_rhel_eos_schedule_index_non_rhel
os = Operatingsystem.create!(:name => "CentOS_Stream", :major => "8", :minor => "3")
assert_nil os.rhel_eos_schedule_index
end
end
end
Loading

0 comments on commit d442ec1

Please sign in to comment.