theforeman/foreman

View on GitHub
app/services/foreman_ansible/operating_system_parser.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true

module ForemanAnsible
  # Methods to parse facts related to the OS
  module OperatingSystemParser
    def operatingsystem
      args = { :name => os_name, :major => os_major, :minor => os_minor }
      args[:release_name] = os_release_name if os_name == 'Debian' || os_name == 'Ubuntu'
      # for Ansible, the CentOS Stream can be identified by missing minor version only
      args[:name] = "CentOS_Stream" if os_name == 'CentOS' && os_minor.blank?
      return @local_os if local_os(args).present?
      return @new_os if new_os(args).present?
      logger.debug do
        'Ansible facts parser: No OS could be created with '\
        "os_name='#{os_name}' os_major='#{os_major}' "\
        "os_minor='#{os_minor}': "\
        "#{@new_os.errors if @new_os.present?}"
      end
      nil
    end

    def local_os(args)
      @local_os = Operatingsystem.where(args).first
    end

    def new_os(args)
      return @new_os if @new_os.present?
      @new_os = Operatingsystem.new(args.merge(:description => os_description))
      @new_os if @new_os.valid? && @new_os.save
    end

    def debian_os_major_sid
      release = if facts[:ansible_distribution_major_version] == 'n/a'
                  facts[:ansible_distribution_release]
                else
                  facts[:ansible_distribution_major_version]
                end
      case release
      when /bookworm/i
        '12'
      when /trixie/i
        '13'
      when /forky/i
        '14'
      end
    end

    def os_release_name
      return '' if os_name != 'Debian' && os_name != 'Ubuntu'
      facts[:ansible_distribution_release]
    end

    def os_major
      if os_name == 'Debian' &&
          (facts[:ansible_distribution_major_version][%r{/sid}i] ||
           facts[:ansible_distribution_major_version] == 'n/a')
        debian_os_major_sid
      else
        facts[:ansible_distribution_major_version] ||
            facts[:ansible_lsb] && facts[:ansible_lsb]['major_release'] ||
            (facts[:version].split('R')[0] if os_name == 'junos')
      end
    end

    def os_release
      facts[:ansible_distribution_version] ||
          facts[:ansible_lsb] && facts[:ansible_lsb]['release']
    end

    def os_minor
      if os_name == 'Ubuntu'
        _, _, minor = os_release&.split('.', 3)
      else
        _, minor = os_release&.split('.', 2) ||
          (facts[:version].split('R') if os_name == 'junos')
      end
      # Until Foreman supports os.minor as something that's not a number,
      # we should remove the extra dots in the version. E.g:
      # '6.1.7601.65536' becomes '6.1.760165536'
      if facts[:ansible_os_family] == 'Windows'
        minor, patch = minor.split('.', 2)
        patch.tr!('.', '')
        minor = "#{minor}.#{patch}"
      end
      minor || ''
    end

    def os_name
      if facts[:ansible_os_family] == 'Windows'
        windows_os_name.tr(" \n\t", '')
      else
        # RHEL 7 is marked as either RedHatEnterpriseServer or RedHatEnterpriseWorkstation, RHEL 8 is lsb id is RedHatEnterprise
        # but we always consider it just RHEL on this level, workstation is differentiated below
        distribution = facts[:ansible_lsb].try(:[], 'id') || facts[:ansible_distribution]

        case distribution
        when 'RedHatEnterprise', 'RedHatEnterpriseServer'
          distribution = 'RedHat'
        when 'RedHatEnterpriseWorkstation'
          distribution = 'RedHat_Workstation'
        end

        distribution
      end
    end

    def os_description
      if facts[:ansible_os_family] == 'Windows'
        windows_os_name
      else
        facts[:ansible_lsb] && facts[:ansible_lsb]['description']
      end
    end

    def windows_os_name
      (facts[:ansible_os_name] || facts[:ansible_distribution] || 'Microsoft Windows').strip
    end
  end
end