Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #36693 - Add new host status for RHEL lifecycle #10706

Merged
merged 13 commits into from
Sep 1, 2023
Merged
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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to assume all RHEL OSes use "RedHat" as the name? Or do some use "RHEL" ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems they are all RedHat for RHEL 9, 8 and 7.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chris1984 do you happen to know what the strings are for RHEL6 and RHEL5? 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeremylenz Should be good to go with 6 too:

irb(main):004:0> Operatingsystem.second
=> #<Redhat id: 6, major: "6", name: "RedHat", minor: "10", nameindicator: nil, created_at: "2023-09-01 13:51:18.161260000 +0000", updated_at: "2023-09-01 13:51:18.161260000 +0000", release_name: nil, type: "Redhat", description: nil, password_hash: [FILTERED], title: "RedHat 6.10">

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

narrator voice They were not good to go.

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
jeremylenz marked this conversation as resolved.
Show resolved Hide resolved
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' => {
jeremylenz marked this conversation as resolved.
Show resolved Hide resolved
'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
jeremylenz marked this conversation as resolved.
Show resolved Hide resolved
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
jeremylenz marked this conversation as resolved.
Show resolved Hide resolved

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
Loading