#!/usr/bin/env ruby

# -------------------------------------------------------------------------------
# Copyright 2025 Open Text.
#
# The only warranties for products and services of Open Text and its
# affiliates and licensors (“Open Text”) are as may be set forth in the
# express warranty statements accompanying such products and services.
# Nothing herein should be construed as constituting an additional
# warranty. Open Text shall not be liable for technical or editorial
# errors or omissions contained herein. The information contained herein
# is subject to change without notice.
#
# Except as specifically indicated otherwise, this document contains
# confidential information and a valid license is required for possession,
# use or copying. If this work is provided to the U.S. Government,
# consistent with FAR 12.211 and 12.212, Commercial Computer Software,
# Computer Software Documentation, and Technical Data for Commercial Items
# are licensed to the U.S. Government under vendor's standard commercial
# license.
# -------------------------------------------------------------------------------

# (c) Copyright 2021 Micro Focus or one of its affiliates
#
# The only warranties for products and services of Micro Focus and its affiliates and licensors
# (Micro Focus) are as may be set forth in the express warranty statements accompanying such
# products and services. Nothing herein should be construed as constituting an additional
# warranty. Micro Focus shall not be liable for technical or editorial errors or omissions contained
# herein. The information contained herein is subject to change without notice.

require 'json'
require 'open3'
require 'rexml/document'

include REXML

@oes_versions = [11, "11\.1", "11\.2", "11\.3", 2015, "2015\.1", 2018, "2018\.1", "2018\.2", "2018\.3", 2023, "23\.4", "24\.4"]

@command_dictionary = {
  'Architecture' => 'uname -m',
  'Virtualization' => 'hostnamectl status | grep Virtualization',
  'Virtualization Type' => "lscpu | grep 'Virtualization type'",
  'Hypervisor Vendor' => "lscpu | grep 'Hypervisor vendor'",
  'CPU' => "lscpu | grep '^CPU(s)'",
  'RAM' => 'grep MemTotal /proc/meminfo',
  'SECURE BOOT' => 'grep SECURE_BOOT /etc/sysconfig/bootloader',
  'Patch Needed' => "zypper pchk  | grep 'patches needed'"
}

@data_dictionary = {
  'OESService' => 'Install'
}

@sysconfig_file_names = {
  'LUM' => 'lum',
  'eDirectory' => 'edir',
  'CIFS' => 'NvlCifs',
  'iPrint' => 'iprnt',
  'DHCP' => 'NvlDhcp',
  'ncs' => 'ncs',
  'NSS' => 'nss',
  'NSSAD' => 'nssad',
  'dsfw' => 'xad',
  'DNS' => 'NvlDns',
  'NCPSERVER' => 'ncpsrvr',
  'OES-LDAP' => 'oes-ldap',
  'SCHEMA-TOOL' => 'schematool',
  'SMS' => 'sms',
  'COMMON' => 'cmmn',
  'UMC' => 'umc',
  'OES-DB' => 'oes-db'
}

@script_errors = []

# To collect system information like timestamp, memory, architecture
def collect_system_info
  time_stamp = Time.now.to_i
  @data_dictionary['timestamp'] = time_stamp

  @command_dictionary.each do |key, value|
    new_value = execute_command("#{value}")
    if new_value.eql?('Error')
      @script_errors << "Skipping #{key} as an error occurred."
    else
      new_value = parse_output(new_value)
      @data_dictionary["#{key}"] = new_value
    end
  end

  patterns_installed

  registration_check

  service_configured

  check_oes_upgrade

  retrieve_proxy_user

  write_to_json
end

# TO collect data on what all patterns are installed in server
def patterns_installed
  patterns = []

  cmd1 = 'zypper --xmlout -q patterns -i > /tmp/installed_patterns.xml'
  cmd2 = 'rm /tmp/installed_patterns.xml'

  retval = execute_command("#{cmd1}")

  if retval.eql?('Error')
    @script_errors << 'Skipping Installed Patterns as an error occurred.'
  else
    begin
      xmlfile = File.new('/tmp/installed_patterns.xml')
      xmldoc = Document.new(xmlfile)

      xmldoc.elements.each('stream/pattern-list/pattern') do |e|
        patterns << e.attributes['name']
      end
    rescue StandardError => e
      @script_errors << "Skipping Installed Patterns as an exception occurred during parsing the data. Exception is '#{e}' ."
      return nil
    end
  end

  @data_dictionary['Installed Patterns'] = patterns
  execute_command("#{cmd2}")
end

# For collecting the registration status of server
def registration_check
  reg_value = ''
  reg_file = '/var/lib/suseRegister/registration-status.xml'

  begin
    if File.file?(reg_file) && !File.zero?(reg_file)
      xmlfile = File.new(reg_file)
      xmldoc = Document.new(xmlfile)
      root = xmldoc.root
      reg_value = root.elements['productstatus/subscription/'].attributes['status']
    else
      reg_value = 'Not Registered'
    end
  rescue NoMethodError => e
    reg_value = 'Not Registered'
  rescue StandardError => e
    @script_errors << "Skipping Registration Status as an exception occurred during parsing the data. Exception is '#{e}' ."
    return nil
  end

  @data_dictionary['Registaration Status'] = reg_value
end

# For collecting what all oes services are configured
# Only collect those services which are configured (value is yes)
def service_configured
  configured = []
  oes_release = execute_command('grep -r DISPLAY_RELEASE /etc/novell-release')

  if oes_release.eql?('Error')
    @script_errors << 'Skipping SERVICE_CONFIGURED as an error occurred during fetching the status.'
    return nil
  end

  oes_release = parse_output(oes_release)
  @data_dictionary['OES VERSION'] = oes_release

  oes_release = oes_release.split('.').first if oes_release.include? '.'

  @sysconfig_file_names.each do |key, value|
    sys_path = '/etc/sysconfig/novell/'

    sys_path += value
    if key.eql?('COMMON')
      std_out = execute_command("grep -r SERVICES_CONFIGURED #{sys_path}")
    else
      std_out = execute_command("grep -r SERVICE_CONFIGURED #{sys_path}")
    end

    if std_out.eql?('Error')
      @script_errors << "Skipping #{key} as an error occurred during fetching SERVICE_CONFIGURED data."
    else
      std_out = parse_output(std_out)
      configured << key if std_out.eql?('yes')
    end
  end

  @data_dictionary['SERVICE_CONFIGURED'] = configured
end

# To check system is upgraded or freshly installed
def check_oes_upgrade
  upgrade_check = ''
  count = 0
  if File.file?('/root/.suse_register.log')
    @oes_versions.each do |f|
      output = execute_command("grep -c 'product version=\"#{f}\"' /root/.suse_register.log")
        count += 1 unless output.eql?('Error')
    end
    upgrade_check = if count > 0
                      'System is upgraded.'
                    else
                      'System is freshly installed.'
                    end
  elsif File.directory?('/var/adm/backup/system-upgrade/')
    upgrade_check = 'System is upgraded.'
  else
    upgrade_check = 'System is freshly installed.'
  end

  @data_dictionary['Upgrade Status'] = upgrade_check
end

#To check the common and service proxy configured in the server
def retrieve_proxy_user
  service_proxy = []
  common_proxy = []
  common_proxy_value = ''
  if @data_dictionary.fetch('SERVICE_CONFIGURED').include?('eDirectory')
    pxylist_file = '/var/opt/novell/log/proxymgmt/pxylist.txt'
    output = execute_command('/opt/novell/proxymgmt/bin/retrieve_proxy_list.sh')
    if output.eql?('Error')
      @script_errors << 'Skipping Proxy User as an error occurred during executing retrieve_proxy_list script.'
      return nil
    else
      if File.file?(pxylist_file)
        file = File.open(pxylist_file)
        file_data = file.readlines.map(&:chomp)
        file.close
        if file_data.any? { |val| val.include?('Error in retrieving credentials') }
          @script_errors << 'Skipping Proxy User as an error occurred during retrieving credentials.'
          return nil
        else
          file_data.each_with_index do |val, index|
            next if index == 0

            val_first = val.split(':').first.strip
            val_last = val.split(':').last.strip
            common_proxy_value = val_last if val_first.eql?('Common Proxy')
            next if val_first.eql?('Common Proxy')

            if common_proxy_value.eql?(val_last)
              common_proxy << val_first
            elsif !val_last.strip.empty?
              service_proxy << val_first
            end
          end
          @data_dictionary['Common Proxy User'] = common_proxy
          @data_dictionary['Service Proxy User'] = service_proxy
        end
      end
    end
  else
    @script_errors << 'Skipping Proxy User detection since eDirectory is not configured on this OES Server.'
  end
end

# For executing command
def execute_command(cmd)
  begin
    stdout, stderr, status = Open3.capture3("#{cmd}")
  rescue
    return 'Error'
  end

  if status.success?
    return stdout
  else
    return 'Error'
  end
end

# For parsing the output genrated after executing the command
def parse_output(output)
  if output.include? ':'
    output = output.split(':').last
  elsif output.include? '='
    output = output.split('=').last
  end

  output = output.strip
  output = output.gsub(/\A"|"\Z/, '')
  return output
end

# For writing the final hash (which is @data_dictionary) to json file
def write_to_json
  file_path = '/var/opt/novell/telemetry/data/'
  file_name = @data_dictionary.fetch('OESService')

  Dir.glob('/var/opt/novell/telemetry/data/Install_*.json').each { |file| File.delete(file)}

  @data_dictionary['SCRIPT_ERROR'] = @script_errors if @script_errors.size > 0

  file_name = if @data_dictionary.has_key?('timestamp')
                file_name + "_#{@data_dictionary.fetch('timestamp')}.json"
              else
                file_name += '.json'
              end

  file_path += file_name

  begin
    File.open(file_path, 'w') do |f|
      f.write(JSON.pretty_generate(@data_dictionary))
    end
  rescue StandardError => e
    puts e
    exit 1
  end
end

def read_telemetry_participation
  begin
    # Checking systemctl is not in initializing or starting stage because of bug OCTCR52A47512
    stdout, stderr, status = Open3.capture3('systemctl is-system-running')
    if !status.success?
      stdout = stdout.strip
      if stdout.eql?('initializing') || stdout.eql?('starting')
        puts 'Cannot Execute the script as the system is not fully up and running'
        exit 0
      end
    end

    telemetry_value = File.read('/etc/opt/novell/telemetry/config/telemetry.json')
    telemetry_hash = JSON.parse(telemetry_value)
    if telemetry_hash.has_key?('opt-in') && telemetry_hash.fetch('opt-in').eql?('yes')
      collect_system_info
    else
      puts 'Cannot Execute the script as telemetry opt-in value is not yes'
      exit 0
    end
  rescue StandardError => e
    puts e
    exit 2
  end
end

read_telemetry_participation
