You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2788 lines
93 KiB
2788 lines
93 KiB
#!/usr/bin/perl |
|
# |
|
# This manages the DHCP, PXE, tftp daemons, kickstart files and and the install sources on Striker |
|
# dashboards. Collectively, this provides the ability for other machines in the Anvil! to be built or rebuilt |
|
# without access to the Internet. |
|
# |
|
# The initial configuration and the ability to get updates does check for an Internet connection. |
|
# Alternatively, /mnt/files/ will be checked for a |
|
# |
|
# Examples; |
|
# - Call with '--enable' to enable the install target. |
|
# - Call with '--disable' to disable the install target. |
|
# - Call with '--refresh' to check for updates from upstream repositories. |
|
# |
|
# Exit codes; |
|
# 0 = Normal exit. |
|
# 1 = Alteeve repo not installed and not installable. |
|
# 2 = BCN IP not found, unable to configure yet. |
|
# 3 = Failed to write or update a configuration file. |
|
# 4 = Not a striker dashboard (or isn't yet). |
|
# 5 = Not running as the 'root' user. |
|
# 6 = The 'comps,xml' file provided by anvil-striker-extra was not found. |
|
# 7 = A package failed to download to our repo |
|
# 8 = No database connection available. |
|
# 9 = The system isn't configured yet. |
|
# 10 = Failed to start dhcpd. |
|
# 11 = Failed to stop dhcpd. |
|
# 12 = Failed to rename the /var/www/html/rhel8 to ./centos8 |
|
# |
|
# Switchs |
|
# |
|
# --check - Normally, '--status' will exit after checking to see if it's running or not. This switch |
|
# tells it to proceed with a check of the configuration (and possibly update the RPM repo) |
|
# after reporting the status. |
|
# --disable - Disable the "Install Manifest" feature. |
|
# --enable - Enable the "Install Manifest" feature. |
|
# --force - This is the same as '--refresh', forcing the update of the RPM repo. |
|
# --job-uuid - If set, the UUID passed will be read and updated as the update runs. |
|
# --no-refresh - If a refresh of the RPM repository would have been called, this switch will prevent it from |
|
# happening. |
|
# --refresh - This tells this run to refresh the RPM repository, regardless of whether it would have run |
|
# otherwise. |
|
# --status - This checks to see if dhcpd is running or not, then exits (effectively checking if the |
|
# "Install Target" feature is running). |
|
# |
|
# |
|
# TODO: |
|
# - Support building the install target by mounting the ISO and checking /mnt/shared/incoming for needed |
|
# files. We can dump the files into a temporary directory, createrepo it, then use the same logic as we use |
|
# for internet loads. We can use '/mnt/shared/incoming' for handling updated RPMs to updating air-gapped |
|
# systems, too. |
|
|
|
use strict; |
|
use warnings; |
|
use Anvil::Tools; |
|
|
|
# Disable buffering |
|
$| = 1; |
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; |
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; |
|
if (($running_directory =~ /^\./) && ($ENV{PWD})) |
|
{ |
|
$running_directory =~ s/^\./$ENV{PWD}/; |
|
} |
|
|
|
my $anvil = Anvil::Tools->new(); |
|
$anvil->Log->level({set => 2}); |
|
$anvil->Log->secure({set => 1}); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); |
|
|
|
# Read switches |
|
$anvil->data->{switches}{check} = 0; |
|
$anvil->data->{switches}{disable} = ""; |
|
$anvil->data->{switches}{enable} = ""; |
|
$anvil->data->{switches}{force} = ""; |
|
$anvil->data->{switches}{'job-uuid'} = ""; |
|
$anvil->data->{switches}{'no-refresh'} = 0; |
|
$anvil->data->{switches}{refresh} = 0; |
|
$anvil->data->{switches}{status} = ""; |
|
$anvil->Get->switches(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
'switches::check' => $anvil->data->{switches}{check}, |
|
'switches::disable' => $anvil->data->{switches}{disable}, |
|
'switches::enable' => $anvil->data->{switches}{enable}, |
|
'switches::force' => $anvil->data->{switches}{force}, |
|
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'}, |
|
'switches::no-refresh' => $anvil->data->{switches}{'no-refresh'}, |
|
'switches::refresh' => $anvil->data->{switches}{refresh}, |
|
'switches::status' => $anvil->data->{switches}{status}, |
|
}}); |
|
|
|
# Make sure we're running as 'root' |
|
# $< == real UID, $> == effective UID |
|
if (($< != 0) && ($> != 0)) |
|
{ |
|
# Not root |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0005"}); |
|
$anvil->nice_exit({exit_code => 5}); |
|
} |
|
|
|
# If the user just wants a status, check and exit. |
|
if ($anvil->data->{switches}{status}) |
|
{ |
|
my $dhcpd_running = $anvil->System->check_daemon({daemon => $anvil->data->{sys}{daemon}{dhcpd}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dhcpd_running => $dhcpd_running }}); |
|
if ($dhcpd_running) |
|
{ |
|
print $anvil->Words->string({key => "message_0123"})."\n"; |
|
print "status=1\n"; |
|
if (not $anvil->data->{switches}{check}) |
|
{ |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0124"})."\n"; |
|
print "status=0\n"; |
|
if (not $anvil->data->{switches}{check}) |
|
{ |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
} |
|
|
|
# Connect to the database(s). |
|
$anvil->Database->connect; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); |
|
if (not $anvil->data->{sys}{database}{connections}) |
|
{ |
|
# No databases, exit. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0003"}); |
|
$anvil->nice_exit({exit_code => 8}); |
|
} |
|
update_progress($anvil, 0, "clear"); |
|
update_progress($anvil, 1, "log_0239,!!job-uuid!".$anvil->data->{switches}{'job-uuid'}."!!"); |
|
|
|
# If we're being asked to disable, just do so and exit. |
|
if ($anvil->data->{switches}{disable}) |
|
{ |
|
my $exit_code = 0; |
|
my $job_message = "message_0125"; |
|
my $return_code = $anvil->System->stop_daemon({daemon => $anvil->data->{sys}{daemon}{dhcpd}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); |
|
if ($return_code) |
|
{ |
|
# non-0 means something went wrong. |
|
$job_message = "message_0126"; |
|
$exit_code = 8; |
|
print $anvil->Words->string({key => "error_0047", variables => { rc => $return_code }})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "error_0048", variables => { rc => $return_code }}); |
|
} |
|
else |
|
{ |
|
# Success! |
|
print $anvil->Words->string({key => "message_0122"})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "message_0122"}); |
|
} |
|
|
|
# Record the new state |
|
$anvil->Database->insert_or_update_variables({ |
|
variable_name => "install-target::enabled", |
|
variable_source_uuid => $anvil->Get->host_uuid, |
|
variable_source_table => "hosts", |
|
variable_value => "disabled", |
|
variable_default => "unavailable", |
|
variable_description => "striker_0110", |
|
variable_section => "system", |
|
}); |
|
|
|
### NOTE: There is no complex job processing here. If we've been asked to enable or disable, it only |
|
### takes a second to do it. |
|
update_progress($anvil, 100, $job_message); |
|
|
|
$anvil->nice_exit({exit_code => $exit_code}); |
|
} |
|
|
|
# Exit if we're not configured yet |
|
my $configured = $anvil->System->check_if_configured; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }}); |
|
if (not $configured) |
|
{ |
|
print $anvil->Words->string({key => "error_0046"})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "error_0046"}); |
|
|
|
update_progress($anvil, 100, "log_0240,!!job-uuid!".$anvil->data->{switches}{'job-uuid'}."!!"); |
|
$anvil->nice_exit({exit_code => 9}); |
|
} |
|
|
|
# Figure out what this machine is. |
|
load_os_info($anvil); |
|
|
|
# If this isn't a Striker dashboard, exit. |
|
if ($anvil->Get->host_type ne "striker") |
|
{ |
|
print $anvil->Words->string({key => "error_0044"})."\n"; |
|
update_progress($anvil, 100, "error_0044"); |
|
$anvil->nice_exit({exit_code => 4}); |
|
} |
|
|
|
# Calling with 'refresh' takes time, so we only do it when asked. |
|
print $anvil->Words->string({key => "message_0102"})."\n"; |
|
load_packages($anvil); |
|
|
|
# Setup PXE/tftp/dhcpd config. |
|
setup_boot_environment($anvil); |
|
|
|
# Store the RPMs in repo directory. |
|
update_install_source($anvil); |
|
|
|
# If we've been asked to enable or disable the install target, do so now. |
|
if ($anvil->data->{switches}{enable}) |
|
{ |
|
my $exit_code = 0; |
|
my $job_message = "message_0127"; |
|
my $return_code = $anvil->System->start_daemon({debug => 2, daemon => $anvil->data->{sys}{daemon}{dhcpd}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { return_code => $return_code }}); |
|
if ($return_code) |
|
{ |
|
# non-0 means something went wrong. |
|
$exit_code = 8; |
|
$job_message = "message_0128"; |
|
print $anvil->Words->string({key => "error_0047", variables => { rc => $return_code }})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "error_0047", variables => { rc => $return_code }}); |
|
} |
|
else |
|
{ |
|
# Success! |
|
print $anvil->Words->string({key => "message_0121"})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "message_0121"}); |
|
} |
|
|
|
# Record the new state |
|
$anvil->Database->insert_or_update_variables({ |
|
variable_name => "install-target::enabled", |
|
variable_source_uuid => $anvil->Get->host_uuid, |
|
variable_source_table => "hosts", |
|
variable_value => "enabled", |
|
variable_default => "unavailable", |
|
variable_description => "striker_0110", |
|
variable_section => "system", |
|
}); |
|
|
|
### NOTE: There is no complex job processing here. If we've been asked to enable or disable, it only |
|
### takes a second to do it. |
|
update_progress($anvil, 90, $job_message); |
|
|
|
if ($exit_code) |
|
{ |
|
update_progress($anvil, 100, ""); |
|
$anvil->nice_exit({exit_code => $exit_code}); |
|
} |
|
} |
|
|
|
# We're done |
|
print $anvil->Words->string({key => "message_0025"})."\n"; |
|
update_progress($anvil, 100, "message_0025"); |
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
|
|
############################################################################################################# |
|
# Private functions. # |
|
############################################################################################################# |
|
|
|
# This loads the OS info into hashes strings and templates will use later. |
|
sub load_os_info |
|
{ |
|
my ($anvil) = @_; |
|
|
|
my ($os_type, $os_arch) = $anvil->Get->os_type(); |
|
$anvil->data->{host_os}{os_type} = $os_type; |
|
$anvil->data->{host_os}{os_arch} = $os_arch; |
|
$anvil->data->{host_os}{version} = ($os_type =~ /(\d+)$/)[0]; |
|
$anvil->data->{host_os}{os_name} = ""; |
|
if ($os_type =~ /^rhel/) |
|
{ |
|
$anvil->data->{host_os}{os_name} = "RHEL ".$anvil->data->{host_os}{version}; |
|
} |
|
elsif ($os_type =~ /^centos/) |
|
{ |
|
$anvil->data->{host_os}{os_name} = "CentOS ".$anvil->data->{host_os}{version}; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"host_os::os_arch" => $anvil->data->{host_os}{os_arch}, |
|
"host_os::os_name" => $anvil->data->{host_os}{os_name}, |
|
"host_os::os_type" => $anvil->data->{host_os}{os_type}, |
|
"host_os::version" => $anvil->data->{host_os}{version}, |
|
}}); |
|
|
|
return(0); |
|
} |
|
|
|
# If this is being called as a job, this will allow the progress to be updated. |
|
sub update_progress |
|
{ |
|
my ($anvil, $progress, $message) = @_; |
|
|
|
if (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
return(0); |
|
} |
|
|
|
$anvil->Job->update_progress({ |
|
progress => $progress, |
|
message => $message, |
|
job_uuid => $anvil->data->{switches}{'job-uuid'}, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub check_refresh |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# If '--no-refresh' is passed, don't refresh |
|
if ($anvil->data->{switches}{'no-refresh'}) |
|
{ |
|
return(0); |
|
update_progress($anvil, 90, ""); |
|
} |
|
|
|
# Setup the packages directory |
|
$anvil->data->{path}{directories}{packages} = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "path::directories::packages" => $anvil->data->{path}{directories}{packages} }}); |
|
|
|
# Default to 'no' |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"switches::refresh" => $anvil->data->{switches}{refresh}, |
|
"switches::force" => $anvil->data->{switches}{force}, |
|
}}); |
|
|
|
# If refresh isn't set, we're out. |
|
if (not $anvil->data->{switches}{refresh}) |
|
{ |
|
return(0); |
|
} |
|
|
|
# It it's forced, the user is insisting on it. |
|
if ($anvil->data->{switches}{force}) |
|
{ |
|
return(0); |
|
} |
|
|
|
# If it's been disabled in anvil.conf, exit. |
|
$anvil->data->{'install-manifest'}{'refresh-packages'} = 1 if not defined $anvil->data->{'install-manifest'}{'refresh-packages'}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "install-manifest::refresh-packages" => $anvil->data->{'install-manifest'}{'refresh-packages'} }}); |
|
if (not $anvil->data->{'install-manifest'}{'refresh-packages'}) |
|
{ |
|
# We're out. |
|
$anvil->data->{switches}{refresh} = 0; |
|
print $anvil->Words->string({key => "log_0235"})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0235"}); |
|
return(0); |
|
} |
|
|
|
# If the Packages directory doesn't exist, we'll need to refresh. |
|
if (not -e $anvil->data->{path}{directories}{packages}) |
|
{ |
|
# Source isn't configured, set it up |
|
$anvil->data->{switches}{refresh} = 1; |
|
print $anvil->Words->string({key => "log_0237"})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0237"}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "switches::refresh" => $anvil->data->{switches}{refresh} }}); |
|
return(0); |
|
} |
|
|
|
# See when the last time we refreshed the local package cache |
|
my ($unixtime, $variable_uuid, $modified_date) = $anvil->Database->read_variable({ |
|
variable_name => "install-target::refreshed", |
|
variable_source_uuid => $anvil->Get->host_uuid, |
|
variable_source_table => "hosts", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
unixtime => $unixtime, |
|
variable_uuid => $variable_uuid, |
|
modified_date => $modified_date, |
|
}}); |
|
|
|
if (($unixtime eq "") or ($unixtime =~ /\D/)) |
|
{ |
|
$unixtime = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { unixtime => $unixtime }}); |
|
} |
|
|
|
### TODO: Allow the user to set a "refresh time" that will wait until the local time is after a |
|
### certain time before refreshing. Also, allow the user to disable auto-refresh entirely. |
|
# If the database variable 'install-target::refresh' is not set, or is more than 24 hours old, |
|
# refresh. |
|
$anvil->data->{'install-manifest'}{'refresh-period'} = 86400 if not defined $anvil->data->{'install-manifest'}{'refresh-period'}; |
|
$anvil->data->{'install-manifest'}{'refresh-period'} =~ s/,//g; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
'install-manifest::refresh-period' => $anvil->data->{'install-manifest'}{'refresh-period'}, |
|
}}); |
|
if ($anvil->data->{'install-manifest'}{'refresh-period'} =~ /\D/) |
|
{ |
|
$anvil->data->{'install-manifest'}{'refresh-period'} = 86400; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
'install-manifest::refresh-period' => $anvil->data->{'install-manifest'}{'refresh-period'}, |
|
}}); |
|
} |
|
my $time_now = time; |
|
my $next_scan = $unixtime + $anvil->data->{'install-manifest'}{'refresh-period'}; |
|
my $difference = ($next_scan - $time_now); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
's1:time_now' => $time_now, |
|
's2:next_scan' => $next_scan, |
|
's3:difference' => $difference, |
|
}}); |
|
if ((not $variable_uuid) or ($unixtime !~ /^\d+/) or ($difference < 0)) |
|
{ |
|
# It's been long enough (or it's the first time), refresh. |
|
$anvil->data->{switches}{refresh} = 1; |
|
my $variables = { seconds => $anvil->Convert->add_commas({number => $anvil->data->{'install-manifest'}{'refresh-period'}}) }; |
|
print $anvil->Words->string({key => "log_0238", variables => $variables})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0238", variables => $variables}); |
|
return(0); |
|
} |
|
elsif ($difference > 0) |
|
{ |
|
# Log when the next scan will happen |
|
$anvil->data->{switches}{refresh} = 0; |
|
my $variables = { next_refresh => $anvil->Convert->add_commas({number => $difference}) }; |
|
print $anvil->Words->string({key => "log_0236", variables => $variables})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0236", variables => $variables}); |
|
} |
|
|
|
# If the refresh fails, we'll update the last unixtime to be 24 hours from now, so that we can try |
|
# again. We intentionally ignore 'install-manifest::refresh-period', that's only used when the |
|
# refresh succeeded. |
|
if ($unixtime =~ /^\d+$/) |
|
{ |
|
$anvil->data->{sys}{retry_time} = $unixtime + 86400; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::retry_time" => $anvil->data->{sys}{retry_time} }}); |
|
} |
|
else |
|
{ |
|
# No previous time, so start with the current time |
|
$anvil->data->{sys}{retry_time} = time; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::retry_time" => $anvil->data->{sys}{retry_time} }}); |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
sub setup_boot_environment |
|
{ |
|
my ($anvil) = @_; |
|
|
|
### TODO: We don't yet support UEFI, though we will need to soon. Note that the 'shim.efi' and |
|
### 'grubx64.efi' files should be added to 'anvil-striker-extras'. We'll also need to create |
|
### '/var/lib/tftpboot/pxelinux/uefi' as well. |
|
### We;re going to need the '.treeinfo' as well in anvil-striker-extra |
|
### - https://docs.fedoraproject.org/en-US/fedora/f28/install-guide/advanced/Network_based_Installations/ |
|
# Get my BCN IP and active OS. |
|
$anvil->Network->get_ips(); |
|
my $bcn_interface = ""; |
|
my $local_host = $anvil->Get->short_host_name(); |
|
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface => $interface }}); |
|
next if $interface !~ /^bcn/; |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "network::local::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip} }}); |
|
if ($anvil->Validate->ipv4({ip => $anvil->data->{network}{$local_host}{interface}{$interface}{ip} })) |
|
{ |
|
$bcn_interface = $interface; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bcn_interface => $bcn_interface }}); |
|
} |
|
last if $bcn_interface; |
|
} |
|
|
|
if (not $bcn_interface) |
|
{ |
|
# Can't set this up yet. |
|
print $anvil->Words->string({key => "error_0042"})."\n"; |
|
update_progress($anvil, 100, "error_0042"); |
|
$anvil->nice_exit({exit_code => 2}); |
|
} |
|
|
|
my $bcn_ip = $anvil->data->{network}{$local_host}{interface}{$bcn_interface}{ip}; |
|
my $bcn_subnet_mask = $anvil->data->{network}{$local_host}{interface}{$bcn_interface}{subnet_mask}; |
|
my $bcn_network = $anvil->Network->get_network({ip => $bcn_ip, subnet_mask => $bcn_subnet_mask}); |
|
my $dns = $anvil->data->{network}{$local_host}{interface}{$bcn_interface}{dns} ? $anvil->data->{network}{$local_host}{interface}{$bcn_interface}{dns} : $anvil->data->{defaults}{network}{dns}; |
|
my $domain = "localdomain"; |
|
my $base_url = "http://".$bcn_ip."/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}; |
|
if ($anvil->Get->host_name =~ /\./) |
|
{ |
|
$domain = $anvil->Get->host_name; |
|
$domain =~ s/^.*?\.//; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
bcn_interface => $bcn_interface, |
|
bcn_ip => $bcn_ip, |
|
bcn_subnet_mask => $bcn_subnet_mask, |
|
bcn_network => $bcn_network, |
|
dns => $dns, |
|
domain => $domain, |
|
base_url => $base_url, |
|
}}); |
|
|
|
### NOTE: The DNS range is a bit tricky, so for now, we'll assume that the BCN is always a /16 |
|
### network. Someday this might change, and if so, we'll need to make this a lot smarter. |
|
my $striker_number = ($anvil->Get->short_host_name =~ /striker(\d+)/)[0]; |
|
$striker_number = 1 if not $striker_number; |
|
$striker_number =~ s/^0//; |
|
my $third_octet = (10 * $striker_number) + 4; |
|
$third_octet = 254 if $third_octet > 254; |
|
my $first_part = ($bcn_network =~ /^(\d+\.\d+)\./)[0].".".$third_octet; |
|
my $range = $first_part.".10 ".$first_part.".250"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
's1:striker_number' => $striker_number, |
|
's2:third_octet' => $third_octet, |
|
's3:first_part' => $first_part, |
|
's4:range' => $range, |
|
}}); |
|
|
|
### DHCP server config |
|
my $dhcpd_conf_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "dhcpd_conf", variables => { |
|
dns => $dns, |
|
domain => $domain, |
|
network => $bcn_network, |
|
range => $range, |
|
router => $bcn_ip, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dhcpd_conf_body => $dhcpd_conf_body }}); |
|
|
|
# Return code if '1' means the file was changed, '2' indicates it didn't change. '0' means something |
|
# went wrong. |
|
my $dhcpd_conf_success = $anvil->Storage->update_file({ |
|
body => $dhcpd_conf_body, |
|
file => $anvil->data->{path}{configs}{'dhcpd.conf'}, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dhcpd_conf_success => $dhcpd_conf_success }}); |
|
if (not $dhcpd_conf_success) |
|
{ |
|
# Failed. |
|
print $anvil->Words->string({key => "error_0043", variables => { file => $anvil->data->{path}{configs}{'dhcpd.conf'} }})."\n"; |
|
update_progress($anvil, 100, "error_0043"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
elsif ($dhcpd_conf_success eq "1") |
|
{ |
|
# Restart dhcpd. |
|
print $anvil->Words->string({key => "message_0095", variables => { |
|
daemon => "dhcpd", |
|
file => $anvil->data->{path}{configs}{'dhcpd.conf'}, |
|
}})."\n"; |
|
update_progress($anvil, 10, "message_0095,!!daemon!dhcpd!!,!!file!".$anvil->data->{path}{configs}{'dhcpd.conf'}."!!"); |
|
$anvil->System->restart_daemon({daemon => $anvil->data->{sys}{daemon}{dhcpd}}); |
|
} |
|
elsif ($dhcpd_conf_success eq "2") |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{'dhcpd.conf'} }})."\n"; |
|
update_progress($anvil, 10, "message_0096,!!file!".$anvil->data->{path}{configs}{'dhcpd.conf'}."!!"); |
|
} |
|
|
|
### PXE BIOS 'default' file. |
|
my $bios_default_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "tftp_bios", variables => { base_url => $base_url }}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bios_default_body => $bios_default_body }}); |
|
|
|
# Return code if '1' means the file was changed, '2' indicates it didn't change. '0' means something |
|
# went wrong. |
|
my $bios_default_success = $anvil->Storage->update_file({ |
|
body => $bios_default_body, |
|
file => $anvil->data->{path}{configs}{pxe_default}, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bios_default_success => $bios_default_success }}); |
|
if (not $bios_default_success) |
|
{ |
|
# Failed. |
|
print $anvil->Words->string({key => "error_0043", variables => { file => $anvil->data->{path}{configs}{pxe_default} }})."\n"; |
|
update_progress($anvil, 100, "error_0043,!!file!".$anvil->data->{path}{configs}{pxe_default}."!!"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
elsif ($dhcpd_conf_success eq "1") |
|
{ |
|
# Updated |
|
print $anvil->Words->string({key => "message_0097", variables => { file => $anvil->data->{path}{configs}{pxe_default} }})."\n"; |
|
} |
|
elsif ($dhcpd_conf_success eq "2") |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{pxe_default} }})."\n"; |
|
} |
|
|
|
### PXE UEFI 'uefi' file. |
|
my $uefi_default_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "tftp_uefi", variables => { base_url => $base_url }}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uefi_default_body => $uefi_default_body }}); |
|
|
|
# Return code if '1' means the file was changed, '2' indicates it didn't change. '0' means something |
|
# went wrong. |
|
my $uefi_default_success = $anvil->Storage->update_file({ |
|
body => $uefi_default_body, |
|
file => $anvil->data->{path}{configs}{pxe_uefi}, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uefi_default_success => $uefi_default_success }}); |
|
if (not $uefi_default_success) |
|
{ |
|
# Failed. |
|
print $anvil->Words->string({key => "error_0043", variables => { file => $anvil->data->{path}{configs}{pxe_uefi} }})."\n"; |
|
update_progress($anvil, 100, "error_0043,!!file!".$anvil->data->{path}{configs}{pxe_uefi}."!!"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
elsif ($dhcpd_conf_success eq "1") |
|
{ |
|
# Updated |
|
print $anvil->Words->string({key => "message_0097", variables => { file => $anvil->data->{path}{configs}{pxe_uefi} }})."\n"; |
|
} |
|
elsif ($dhcpd_conf_success eq "2") |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{pxe_uefi} }})."\n"; |
|
} |
|
|
|
### TODO: Add repos for all known strikers |
|
# Build the repository file body. |
|
my $repo_file = "/etc/yum.repos.d/".$anvil->Get->short_host_name.".repo"; |
|
my $repo_body = "[".$anvil->Get->short_host_name."-repo]\n"; |
|
$repo_body .= "name=".$anvil->Get->host_name." #!string!message_0153!#\n"; |
|
# Add the IPs. |
|
$anvil->Network->get_ips({}); |
|
my $first_line = 1; |
|
foreach my $in_iface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) |
|
{ |
|
my $ip = $anvil->data->{network}{$local_host}{interface}{$in_iface}{ip}; |
|
if ($ip) |
|
{ |
|
my $prefix = $first_line ? "baseurl=" : " "; |
|
$first_line = 0; |
|
$repo_body .= $prefix."http://".$ip."/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/\n"; |
|
} |
|
} |
|
$repo_body .= "enabled=1\n"; |
|
$repo_body .= "gpgcheck=0\n"; |
|
$repo_body .= "skip_if_unavailable=1\n"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
repo_file => $repo_file, |
|
repo_body => $repo_body, |
|
}}); |
|
|
|
### Generate kickstart files. |
|
my $progress = 10; |
|
foreach my $type ("striker", "node", "dr") |
|
{ |
|
$progress += 2; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type, progress => $progress }}); |
|
|
|
my $say_type = "#!string!message_0115!#"; |
|
if ($type eq "node") |
|
{ |
|
$say_type = "#!string!message_0116!#"; |
|
} |
|
elsif ($type eq "dr") |
|
{ |
|
$say_type = "#!string!message_0117!#"; |
|
} |
|
my $kickstart_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "kickstart", variables => { |
|
type => $type, |
|
say_type => $say_type, |
|
host_name => "new-".$type.".".$domain, |
|
os => $anvil->data->{host_os}{os_type}, |
|
url => $base_url."/os/", |
|
keyboard => $anvil->data->{kickstart}{keyboard} ? $anvil->data->{kickstart}{keyboard} : $anvil->data->{defaults}{kickstart}{keyboard}, |
|
timezone => $anvil->data->{kickstart}{timezone} ? $anvil->data->{kickstart}{timezone} : $anvil->data->{defaults}{kickstart}{timezone}, |
|
password => $anvil->data->{kickstart}{password} ? $anvil->data->{kickstart}{password} : $anvil->data->{defaults}{kickstart}{password}, |
|
repo_file => $repo_file, |
|
repo_body => $repo_body, |
|
debug => 0, # This isn't the same as the rest of our code, just '1' or '0'. |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { kickstart_body => $kickstart_body }}); |
|
|
|
# Return code if '1' means the file was changed, '2' indicates it didn't change. '0' means |
|
# something went wrong. |
|
my $kickstart_file = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/kickstart/".$type.".ks"; |
|
my $kickstart_success = $anvil->Storage->update_file({ |
|
body => $kickstart_body, |
|
file => $kickstart_file, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { kickstart_success => $kickstart_success }}); |
|
if (not $kickstart_success) |
|
{ |
|
# Failed. |
|
print $anvil->Words->string({key => "error_0043", variables => { file => $kickstart_file }})."\n"; |
|
update_progress($anvil, 100, "error_0043,!!file!".$kickstart_file."!!"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
elsif ($kickstart_success eq "1") |
|
{ |
|
# Updated |
|
$anvil->Storage->change_mode({path => $kickstart_file, mode => "0664"}); |
|
$anvil->Storage->change_owner({path => $kickstart_file, user => "apache", group => "apache" }); |
|
|
|
print $anvil->Words->string({key => "message_0097", variables => { file => $kickstart_file }})."\n"; |
|
update_progress($anvil, $progress, "message_0097,!!file!".$kickstart_file."!!"); |
|
} |
|
elsif ($kickstart_success eq "2") |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $kickstart_file }})."\n"; |
|
update_progress($anvil, $progress, "message_0096,!!file!".$kickstart_file."!!"); |
|
} |
|
# progress is '16' as it leaves this loop |
|
} |
|
|
|
# Configure apache to show hidden (dot) files. |
|
my $old_autoindex_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'autoindex.conf'}}); |
|
my $new_autoindex_conf = ""; |
|
my $update_autoindex_conf = 0; |
|
$progress = 18; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { old_autoindex_conf => $old_autoindex_conf }}); |
|
foreach my $line (split/\n/, $old_autoindex_conf) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); |
|
if (($line =~ /^IndexIgnore /) && ($line =~ / \.\?\?\* /)) |
|
{ |
|
$line =~ s/ \.\?\?\* / /; |
|
$update_autoindex_conf = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"<< line" => $line, |
|
update_autoindex_conf => $update_autoindex_conf, |
|
}}); |
|
} |
|
if (($line =~ /^IndexOptions /) && ($line !~ / NameWidth=/)) |
|
{ |
|
# Allow long file names to show without being truncated |
|
$line .= " NameWidth=*"; |
|
$update_autoindex_conf = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"<< line" => $line, |
|
update_autoindex_conf => $update_autoindex_conf, |
|
}}); |
|
} |
|
if (($line =~ /^IndexOptions /) && ($line !~ / FoldersFirst/)) |
|
{ |
|
# Sort folders before files |
|
$line .= " FoldersFirst"; |
|
$update_autoindex_conf = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"<< line" => $line, |
|
update_autoindex_conf => $update_autoindex_conf, |
|
}}); |
|
} |
|
if (($line =~ /^IndexOptions /) && ($line !~ / IgnoreCase/)) |
|
{ |
|
# Sort filenames without putting capitalized first letters at the start of the list. |
|
$line .= " IgnoreCase"; |
|
$update_autoindex_conf = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
"<< line" => $line, |
|
update_autoindex_conf => $update_autoindex_conf, |
|
}}); |
|
} |
|
$new_autoindex_conf .= $line."\n"; |
|
} |
|
if ($update_autoindex_conf) |
|
{ |
|
# Update and reload apache |
|
$anvil->Storage->backup({debug => 2, file => $anvil->data->{path}{configs}{'autoindex.conf'}}); |
|
my $return = $anvil->Storage->write_file({ |
|
debug => 2, |
|
body => $new_autoindex_conf, |
|
file => $anvil->data->{path}{configs}{'autoindex.conf'}, |
|
overwrite => 1, |
|
mode => "0644", |
|
user => "root", |
|
group => "root" |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }}); |
|
|
|
if ($return) |
|
{ |
|
# Something went wrong. |
|
print $anvil->Words->string({key => "log_0233", variables => { file => $anvil->data->{path}{configs}{'autoindex.conf'}, 'return' => $return }})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0233", variables => { file => $anvil->data->{path}{configs}{'autoindex.conf'}, 'return' => $return }}); |
|
update_progress($anvil, "100", "log_0233,!!file!".$anvil->data->{path}{configs}{'autoindex.conf'}."!!,!!return!".$return."!!"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
|
|
print $anvil->Words->string({key => "message_0095", variables => { daemon => "httpd", file => $anvil->data->{path}{configs}{'autoindex.conf'} }})."\n"; |
|
$anvil->System->reload_daemon({daemon => $anvil->data->{sys}{daemon}{httpd}}); |
|
update_progress($anvil, $progress, "message_0095,!!daemon!httpd!!,!!file!".$anvil->data->{path}{configs}{'autoindex.conf'}."!!"); |
|
} |
|
else |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{'autoindex.conf'} }})."\n"; |
|
update_progress($anvil, $progress, "message_0096,!!file!".$anvil->data->{path}{configs}{'autoindex.conf'}."!!"); |
|
} |
|
|
|
# Update dnf to save downloaded files for later repo building efficiency and to skip upstream repos |
|
# that aren't available at a given time. |
|
my $keepcache_seen = 0; |
|
my $skip_seen = 0; |
|
my $old_dnf_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'dnf.conf'}}); |
|
my $new_dnf_conf = ""; |
|
$progress = 20; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { old_dnf_conf => $old_dnf_conf }}); |
|
foreach my $line (split/\n/, $old_dnf_conf) |
|
{ |
|
### NOTE: We don't examin the value on purpose. If the user changes these, we'll respect it. |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); |
|
if ($line =~ /^keepcache=/) |
|
{ |
|
$keepcache_seen = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { keepcache_seen => $keepcache_seen }}); |
|
} |
|
elsif ($line =~ /^skip_if_unavailable=/) |
|
{ |
|
$skip_seen = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { skip_seen => $skip_seen }}); |
|
} |
|
$new_dnf_conf .= $line."\n"; |
|
} |
|
|
|
if ((not $keepcache_seen) or (not $skip_seen)) |
|
{ |
|
# Update needed. |
|
if (not $keepcache_seen) |
|
{ |
|
$new_dnf_conf .= "keepcache=1\n"; |
|
} |
|
if (not $skip_seen) |
|
{ |
|
$new_dnf_conf .= "skip_if_unavailable=1\n"; |
|
} |
|
$anvil->Storage->backup({debug => 2, file => $anvil->data->{path}{configs}{'dnf.conf'}}); |
|
my $return = $anvil->Storage->write_file({ |
|
debug => 2, |
|
body => $new_dnf_conf, |
|
file => $anvil->data->{path}{configs}{'dnf.conf'}, |
|
overwrite => 1, |
|
mode => "0644", |
|
user => "root", |
|
group => "root" |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }}); |
|
|
|
if ($return) |
|
{ |
|
# Something went wrong. |
|
print $anvil->Words->string({key => "log_0233", variables => { file => $anvil->data->{path}{configs}{'dnf.conf'}, 'return' => $return }})."\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0233", variables => { file => $anvil->data->{path}{configs}{'dnf.conf'}, 'return' => $return }}); |
|
update_progress($anvil, 100, "log_0233,!!file!".$anvil->data->{path}{configs}{'dnf.conf'}."!!,!!return!".$return."!!"); |
|
$anvil->nice_exit({exit_code => 3}); |
|
} |
|
print $anvil->Words->string({key => "message_0097", variables => { file => $anvil->data->{path}{configs}{'dnf.conf'} }})."\n"; |
|
update_progress($anvil, $progress, "message_0097,!!file!".$anvil->data->{path}{configs}{'dnf.conf'}."!!"); |
|
} |
|
else |
|
{ |
|
# Update not needed. |
|
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{'dnf.conf'} }})."\n"; |
|
update_progress($anvil, $progress, "message_0096,!!file!".$anvil->data->{path}{configs}{'dnf.conf'}."!!"); |
|
} |
|
|
|
### Check that daemons are enabled/disabled. |
|
### NOTE: We don't manage dhcpd. We leave it off, but if the user enabled it, respect that. |
|
# Make sure tftp is enabled. |
|
$progress = 22; |
|
if (-e $anvil->data->{path}{systemd}{tftp_enabled_symlink}) |
|
{ |
|
print $anvil->Words->string({key => "message_0099", variables => { daemon => $anvil->data->{sys}{daemon}{tftp} }})."\n"; |
|
update_progress($anvil, $progress, "message_0099,!!daemon!".$anvil->data->{sys}{daemon}{tftp}."!!"); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0098", variables => { daemon => $anvil->data->{sys}{daemon}{tftp} }})."\n"; |
|
update_progress($anvil, $progress, "message_0098,!!daemon!".$anvil->data->{sys}{daemon}{tftp}."!!"); |
|
$anvil->System->enable_daemon({daemon => $anvil->data->{sys}{daemon}{tftp}}); |
|
$anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{tftp}}); |
|
} |
|
$progress = 24; |
|
if (-e $anvil->data->{path}{systemd}{httpd_enabled_symlink}) |
|
{ |
|
print $anvil->Words->string({key => "message_0099", variables => { daemon => $anvil->data->{sys}{daemon}{httpd} }})."\n"; |
|
update_progress($anvil, $progress, "message_0099,!!daemon!".$anvil->data->{sys}{daemon}{httpd}."!!"); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0098", variables => { daemon => $anvil->data->{sys}{daemon}{httpd} }})."\n"; |
|
update_progress($anvil, $progress, "message_0098,!!daemon!".$anvil->data->{sys}{daemon}{httpd}."!!"); |
|
$anvil->System->enable_daemon({daemon => $anvil->data->{sys}{daemon}{httpd}}); |
|
$anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{httpd}}); |
|
} |
|
|
|
# Make sure the syslinux files needed for creating the PXE boot menu are in place. |
|
$progress = 26; |
|
if (not -e $anvil->data->{path}{directories}{tftpboot}."/vesamenu.c32") |
|
{ |
|
# Copy the syslinux files |
|
print $anvil->Words->string({key => "message_0100"})."\n"; |
|
update_progress($anvil, $progress, "message_0100"); |
|
$anvil->Storage->rsync({ |
|
debug => 3, |
|
source => $anvil->data->{path}{directories}{syslinux}."/*", |
|
destination => $anvil->data->{path}{directories}{tftpboot}."/", |
|
}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0101"})."\n"; |
|
update_progress($anvil, $progress, "message_0101"); |
|
} |
|
|
|
### TODO: Add UEFI |
|
# Copy the background splash image for the PXE boot images. |
|
my $bios_splash = $anvil->data->{path}{directories}{skins}."/".$anvil->Template->skin."/images/bios-splash.jpg"; |
|
if (-e $bios_splash) |
|
{ |
|
# We don't bother checking if this needs to be updated because rsync can figure it out more |
|
# efficiently. |
|
$anvil->Storage->rsync({ |
|
debug => 3, |
|
source => $bios_splash, |
|
destination => $anvil->data->{path}{directories}{tftpboot}."/splash.jpg", |
|
}); |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
### NOTE: This will probably be removed... |
|
sub check_alteeve_repo |
|
{ |
|
my ($anvil) = @_; |
|
|
|
my $repo_url = ""; |
|
my $repo_file = ""; |
|
### NOTE: This adds 'b' for the beta repo |
|
if (1) |
|
{ |
|
### TODO: Remove this and the check when the signed el8 repo is ready |
|
$repo_file = "/etc/yum.repos.d/alteeve-el".$anvil->data->{host_os}{version}.".repo"; |
|
$repo_url = "https://alteeve.com/an-repo/el".$anvil->data->{host_os}{version}."b/alteeve-el".$anvil->data->{host_os}{version}."b-repo-latest.noarch.rpm"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
repo_file => $repo_file, |
|
repo_url => $repo_url, |
|
}}); |
|
} |
|
else |
|
{ |
|
### TODO: Update this when rhel8 is out |
|
$repo_file = "/etc/yum.repos.d/alteeve-el".$anvil->data->{host_os}{version}."b.repo"; |
|
$repo_url = "https://alteeve.com/an-repo/el".$anvil->data->{host_os}{version}."/alteeve-el".$anvil->data->{host_os}{version}."-repo-latest.noarch.rpm"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
repo_file => $repo_file, |
|
repo_url => $repo_url, |
|
}}); |
|
} |
|
|
|
# If the repo file doesn't exist, try to install it. |
|
if (not -e $repo_file) |
|
{ |
|
# Install the repo |
|
my ($handle, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{rpm}." -Uvh ".$repo_url }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { handle => $handle, return_code => $return_code }}); |
|
} |
|
|
|
# If it still doesn't exist, we're done. |
|
if (not -e $repo_file) |
|
{ |
|
# Die |
|
print $anvil->Words->string({key => "error_0041"})."\n"; |
|
update_progress($anvil, 100, "error_0041"); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
# This uses yumdownloader to push the files into '/var/www/html/<os_name>/<arch>/os |
|
sub update_install_source |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# Job progress is at '26' coming into here |
|
|
|
# Should we refresh the local repo? |
|
check_refresh($anvil); |
|
if (not $anvil->data->{switches}{refresh}) |
|
{ |
|
return(0); |
|
update_progress($anvil, 90, ""); |
|
} |
|
|
|
# Test if there is internet access. |
|
my $domain = "redhat.com"; |
|
if ($anvil->data->{host_os}{os_type} =~ /^centos/) |
|
{ |
|
$domain = "mirrorlist.centos.org"; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { domain => $domain }}); |
|
|
|
$anvil->data->{sys}{internet} = $anvil->Network->check_internet({domains => [$domain]}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::internet" => $anvil->data->{sys}{internet} }}); |
|
|
|
# Loop through each letter directory |
|
if (not $anvil->data->{sys}{internet}) |
|
{ |
|
# No internet. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0031", variables => { domain => $domain }}); |
|
update_progress($anvil, 50, "warning_0031,!!domain!".$domain."!!"); |
|
} |
|
else |
|
{ |
|
# Clear the dnf cache |
|
my $success = 1; |
|
my $progress = 30; |
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{dnf}." clean expire-cache" }); |
|
my $packages = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages/*"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
|
print $anvil->Words->string({key => "message_0077", variables => { directory => $packages }})."\n"; |
|
update_progress($anvil, $progress, "message_0077,!!directory!".$packages."!!"); |
|
|
|
# If this host is not a RHEL host, add the HA packages to the main packages. If it is RHEL, |
|
# we'll pull the packages from a node. |
|
if ($anvil->data->{host_os}{os_type} ne "rhel8") |
|
{ |
|
foreach my $letter (sort {$a cmp $b} keys %{$anvil->data->{ha_packages}}) |
|
{ |
|
foreach my $package (sort {$a cmp $b} @{$anvil->data->{packages}{$letter}}) |
|
{ |
|
# Push the package onto the normal array. |
|
push @{$anvil->data->{packages}{$letter}}, $package; |
|
} |
|
} |
|
delete $anvil->data->{ha_packages}; |
|
} |
|
|
|
foreach my $letter (sort {$a cmp $b} keys %{$anvil->data->{packages}}) |
|
{ |
|
$progress += 2; |
|
$progress = 90 if $progress > 90; |
|
my $download_path = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages/".$letter; |
|
my $array_size = @{$anvil->data->{packages}{$letter}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
letter => $letter, |
|
download_path => $download_path, |
|
array_size => $array_size, |
|
progress => $progress, |
|
}}); |
|
if (not -e $download_path) |
|
{ |
|
$anvil->Storage->make_directory({debug => 2, directory => $download_path, mode => "0775"}); |
|
} |
|
my $say_packages = $anvil->Convert->add_commas({number => $array_size}); |
|
print $anvil->Words->string({key => "message_0120", variables => { |
|
directory => $download_path, |
|
packages => $say_packages, |
|
}})."\n"; |
|
update_progress($anvil, $progress, "message_0120,!!directory!".$download_path."!!,!!packages!".$say_packages."!!"); |
|
|
|
my $packages = ""; |
|
my $shell_call = $anvil->data->{path}{exe}{dnf}." download --destdir ".$download_path." "; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); |
|
foreach my $package (sort {$a cmp $b} @{$anvil->data->{packages}{$letter}}) |
|
{ |
|
# Append the package to the active shell call. |
|
$packages .= $package." "; |
|
} |
|
$packages =~ s/ $//; |
|
$shell_call .= " ".$packages."; 2>&1 ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); |
|
|
|
# Now call the command in the background, then we'll track the output. |
|
my $stdout_file = "/tmp/".$THIS_FILE."_update_install_source.stdout"; |
|
if (-e $stdout_file) |
|
{ |
|
unlink $stdout_file; |
|
} |
|
my ($handle, undef) = $anvil->System->call({ |
|
debug => 2, |
|
shell_call => $shell_call, |
|
background => 1, |
|
stdout_file => $stdout_file, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { handle => $handle }}); |
|
|
|
# Now we'll loop, printing output, until the handle dies. |
|
my $alive = 1; |
|
my $last_stdout_line = 0; |
|
my $error_out = ""; |
|
my $return_code = 255; |
|
while($alive) |
|
{ |
|
# Are we still alive? |
|
$alive = $handle->poll(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { alive => $alive }}); |
|
|
|
# Sleep (even if we're dead now, we want to give a second for the stdout file to be updated |
|
# before processing it). |
|
sleep 1; |
|
|
|
# print any new STDOUT lines |
|
my $stdout = $anvil->Storage->read_file({force_read => 1, file => $stdout_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { stdout => $stdout }}); |
|
|
|
my $this_stdout_line = 0; |
|
foreach my $line (split/\n/, $stdout) |
|
{ |
|
$this_stdout_line++; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
's1:this_stdout_line' => $this_stdout_line, |
|
's2:last_stdout_line' => $last_stdout_line, |
|
's3:line' => $line, |
|
}}); |
|
if ($this_stdout_line > $last_stdout_line) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); |
|
print $anvil->Words->string({key => "message_0078", variables => { line => $line }})."\n"; |
|
|
|
# In some cases, a bad local RPM can cause download failures. This |
|
# checks for and removes them. It can take a few runs to clear out a |
|
# set of bad files, but it will clear out eventually. |
|
if ($line =~ / (.*?.rpm): Interrupted by header callback/i) |
|
{ |
|
my $rpm_name = $1; |
|
my $rpm_path = $download_path."/".$rpm_name; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { |
|
rpm_name => $rpm_name, |
|
rpm_path => $rpm_path, |
|
}}); |
|
|
|
if (-e $rpm_path) |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0469", variables => { rpm_path => $rpm_path }}); |
|
unlink $rpm_path; |
|
|
|
$error_out .= $anvil->Words->string({key => "log_0469", variables => { rpm_path => $rpm_path }})."\n"; |
|
} |
|
} |
|
|
|
$last_stdout_line = $this_stdout_line; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { last_stdout_line => $last_stdout_line }}); |
|
|
|
# A none-zero return code indicates, likely, that a package failed to download. |
|
if ($line =~ /^return_code:(\d+)$/) |
|
{ |
|
$return_code = $1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); |
|
|
|
if ($return_code) |
|
{ |
|
# Something went wrong. |
|
$error_out .= $anvil->Words->string({key => "error_0063", variables => { packages => $packages, return_code => $return_code }})."\n"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { error_out => $error_out }}); |
|
} |
|
} |
|
if ($line =~ /^Error: /) |
|
{ |
|
$error_out .= $line."\n"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { error_out => $error_out }}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { error_out => $error_out }}); |
|
if ($error_out) |
|
{ |
|
# Bump the last successful time by 24 hours. |
|
$anvil->Database->insert_or_update_variables({ |
|
variable_name => "install-target::refreshed", |
|
variable_value => $anvil->data->{sys}{retry_time}, |
|
variable_default => "", |
|
variable_description => "striker_0106", |
|
variable_section => "system", |
|
variable_source_uuid => $anvil->Get->host_uuid, |
|
variable_source_table => "hosts", |
|
}); |
|
|
|
# Something went wrong, exit. |
|
print $anvil->Words->string({key => "error_0045", variables => { error => $error_out }})."\n"; |
|
update_progress($anvil, 100, "error_0045,!!error!".$error_out."!!"); |
|
$anvil->nice_exit({exit_code => 7}); |
|
} |
|
# Progress is '82' leaving this loop |
|
} |
|
|
|
# If this is a RHEL host, we'll now look for a node to download HA packages from. |
|
if ($anvil->data->{host_os}{os_type} eq "rhel8") |
|
{ |
|
# Try to find a node to download the RPMs on. |
|
update_progress($anvil, ++$progress, "message_0184"); |
|
my $use_node_name = ""; |
|
my $use_node_ip = ""; |
|
my $use_password = ""; |
|
my $local_short_host_name = $anvil->Get->short_host_name; |
|
$anvil->Network->load_ips({ |
|
debug => 3, |
|
host => $local_short_host_name, |
|
}); |
|
|
|
my $query = " |
|
SELECT |
|
a.host_uuid, |
|
a.host_name, |
|
b.anvil_password |
|
FROM |
|
hosts a, |
|
anvils b |
|
WHERE |
|
a.host_type = 'node' |
|
AND |
|
( |
|
a.host_uuid = b.anvil_node1_host_uuid |
|
OR |
|
a.host_uuid = b.anvil_node2_host_uuid |
|
) |
|
ORDER BY |
|
a.host_name ASC |
|
;"; |
|
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
my $count = @{$results}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
results => $results, |
|
count => $count, |
|
}}); |
|
foreach my $row (@{$results}) |
|
{ |
|
my $host_uuid = $row->[0]; |
|
my $host_name = $row->[1]; |
|
my $anvil_password = $row->[2]; |
|
my $short_host_name = $host_name; |
|
$short_host_name =~ s/\..*$//; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
host_uuid => $host_uuid, |
|
host_name => $host_name, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
short_host_name => $short_host_name, |
|
}}); |
|
$anvil->Network->load_ips({ |
|
debug => 3, |
|
host_uuid => $host_uuid, |
|
host => $short_host_name, |
|
}); |
|
|
|
my $access = 0; |
|
my ($match) = $anvil->Network->find_matches({ |
|
debug => 3, |
|
first => $local_short_host_name, |
|
second => $short_host_name, |
|
}); |
|
|
|
my $keys = keys %{$match}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'keys' => $keys }}); |
|
if ($keys) |
|
{ |
|
foreach my $interface (sort {$a cmp $b} keys %{$match->{$short_host_name}}) |
|
{ |
|
my $remote_ip = $match->{$short_host_name}{$interface}{ip}; |
|
my ($pinged, $average_time) = $anvil->Network->ping({ |
|
ping => $remote_ip, |
|
count => 1, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
remote_ip => $remote_ip, |
|
pinged => $pinged, |
|
average_time => $average_time, |
|
}}); |
|
if ($pinged) |
|
{ |
|
my $access = $anvil->Remote->test_access({ |
|
target => $remote_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); |
|
if ($access) |
|
{ |
|
my $internet = $anvil->Network->check_internet({ |
|
debug => 3, |
|
target => $remote_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { internet => $internet }}); |
|
if ($internet) |
|
{ |
|
my ($os_type, $os_arch) = $anvil->Get->os_type({ |
|
debug => 3, |
|
target => $remote_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
os_type => $os_type, |
|
os_arch => $os_arch, |
|
}}); |
|
if (($anvil->data->{host_os}{os_type} eq $os_type) && ($os_arch eq $anvil->data->{host_os}{os_arch})) |
|
{ |
|
update_progress($anvil, ++$progress, "message_0185,!!node!".$host_name."!!"); |
|
$use_node_name = $host_name; |
|
$use_node_ip = $remote_ip; |
|
$use_password = $anvil_password; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
use_node_name => $use_node_name, |
|
use_node_ip => $use_node_ip, |
|
use_password => $anvil->Log->is_secure($use_password), |
|
}}); |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_node_ip => $use_node_ip }}); |
|
if ($use_node_ip) |
|
{ |
|
foreach my $letter (sort {$a cmp $b} keys %{$anvil->data->{ha_packages}}) |
|
{ |
|
my $download_path = "/tmp/Packages/".$letter; |
|
my $local_path = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages/".$letter; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
letter => $letter, |
|
download_path => $download_path, |
|
local_path => $local_path, |
|
}}); |
|
|
|
# This is the directory we'll download the packages to on the node. |
|
$anvil->Storage->make_directory({ |
|
debug => 3, |
|
directory => $download_path, |
|
target => $use_node_ip, |
|
password => $use_password, |
|
mode => "0775", |
|
}); |
|
|
|
my $packages = ""; |
|
my $shell_call = $anvil->data->{path}{exe}{dnf}." download --destdir ".$download_path." "; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); |
|
foreach my $package (sort {$a cmp $b} @{$anvil->data->{ha_packages}{$letter}}) |
|
{ |
|
# Append the package to the active shell call. |
|
$packages .= $package." "; |
|
} |
|
$packages =~ s/ $//; |
|
$shell_call .= " ".$packages; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); |
|
|
|
# None of the HA packages are large os it's not worth trying to monitor the downlaods |
|
# in real time. As such, we'll make a standard remote call. |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
debug => 3, |
|
target => $use_node_ip, |
|
password => $use_password, |
|
shell_call => $shell_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
error => $error, |
|
return_code => $return_code, |
|
}}); |
|
|
|
if (not $return_code) |
|
{ |
|
# Success! Copy the files. |
|
my $failed = $anvil->Storage->rsync({ |
|
debug => 3, |
|
source => "root\@".$use_node_ip.":".$download_path."/*", |
|
destination => $local_path."/", |
|
password => $use_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); |
|
if (not $failed) |
|
{ |
|
update_progress($anvil, ++$progress, "message_0187,!!letter!".$letter."!!"); |
|
} |
|
} |
|
} |
|
update_progress($anvil, ++$progress, "message_0188"); |
|
} |
|
else |
|
{ |
|
# No nodes found. |
|
update_progress($anvil, ++$progress, "message_0186"); |
|
} |
|
} |
|
|
|
} |
|
|
|
# Create the repodata |
|
print $anvil->Words->string({key => "message_0118"})."\n"; |
|
my $repo_path = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os"; |
|
my $repo_data_path = $repo_path."/repodata"; |
|
my $comps_xml = $repo_path."/comps.xml"; |
|
my $modules_yaml = $repo_path."/modules.yaml"; |
|
my $target_comps = $repo_data_path."/comps.xml"; |
|
if (not -e $comps_xml) |
|
{ |
|
# We can't install properly without the comps.xml file, it provides grouping needed by the |
|
# guest OS install. |
|
print $anvil->Words->string({key => "message_0119", variables => { comps_xml => $comps_xml }})."\n"; |
|
update_progress($anvil, 100, "message_0119,!!comps_xml!".$comps_xml."!!"); |
|
$anvil->nice_exit({exit_code => 6}); |
|
} |
|
$anvil->Storage->copy_file({ |
|
debug => 2, |
|
source_file => $comps_xml, |
|
target_file => $target_comps, |
|
overwrite => 1, |
|
}); |
|
if (not -e $target_comps) |
|
{ |
|
# Something appears to have happened and it failed to copy. |
|
print $anvil->Words->string({key => "message_0129", variables => { comps_xml => $comps_xml, target_comps => $target_comps }})."\n"; |
|
update_progress($anvil, 100, "message_0129,!!comps_xml!".$comps_xml."!!,!!target_comps!".$target_comps."!!"); |
|
$anvil->nice_exit({exit_code => 6}); |
|
} |
|
update_progress($anvil, 85, ""); |
|
|
|
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{createrepo_c}." -g ".$comps_xml." ".$repo_path }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
|
print $anvil->Words->string({key => "message_0130"})."\n"; |
|
update_progress($anvil, 90, "message_0130"); |
|
|
|
### NOTE: This doesn't work for libssh2 yet (haven't figured out how to add it to 'modules.yaml' |
|
### sourced from RHEL 8.1 ISO yet). Once that's fixed, remove 'module_hotfixes=1' from |
|
### Striker->get_local_repo(). |
|
$output = ""; |
|
($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{modifyrepo_c}." --mdtype=modules ".$modules_yaml." ".$repo_data_path }); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
|
print $anvil->Words->string({key => "message_0159"})."\n"; |
|
update_progress($anvil, 95, "message_0159"); |
|
|
|
# Update the refresh time to now. |
|
$anvil->Database->insert_or_update_variables({ |
|
debug => 2, |
|
variable_name => "install-target::refreshed", |
|
variable_value => time, |
|
variable_default => "", |
|
variable_description => "striker_0106", |
|
variable_section => "system", |
|
variable_source_uuid => $anvil->Get->host_uuid, |
|
variable_source_table => "hosts", |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
# |
|
sub load_packages |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# Read in any packages the user wants us to add. |
|
$anvil->data->{packages}{users} = []; |
|
if ((exists $anvil->data->{striker}{repo}{'extra-packages'}) && ($anvil->data->{striker}{repo}{'extra-packages'})) |
|
{ |
|
foreach my $package (split/,/, $anvil->data->{striker}{repo}{'extra-packages'}) |
|
{ |
|
$package =~ s/^\s+//; |
|
$package =~ s/\s+$//; |
|
next if $package eq ""; |
|
push @{$anvil->data->{packages}{users}}, $package |
|
} |
|
} |
|
|
|
### NOTE: If/when we support other archs, removing '.x86_64/.noarch' would cause all available archs |
|
### to be downloaded (including .ix86, which would waste space...). Decide if it's best to |
|
### explicitely declare archs vs using space/bandwidth to just grab all available. |
|
# This is the list of packages we need to download. |
|
$anvil->data->{packages} = { |
|
a => [ |
|
"abattis-cantarell-fonts.noarch", |
|
"accountsservice-libs.x86_64", |
|
"accountsservice.x86_64", |
|
"acl.x86_64", |
|
"adwaita-cursor-theme.noarch", |
|
"adwaita-gtk2-theme.x86_64", |
|
"adwaita-icon-theme.noarch", |
|
"alsa-lib.x86_64", |
|
"alteeve-el8-repo.noarch", |
|
"annobin.x86_64", |
|
"anvil-core.noarch", |
|
"anvil-dr.noarch", |
|
"anvil-node.noarch", |
|
"anvil-striker-extra.noarch", |
|
"anvil-striker.noarch", |
|
"apr-util-bdb.x86_64", |
|
"apr-util-openssl.x86_64", |
|
"apr-util.x86_64", |
|
"apr.x86_64", |
|
"aspell.x86_64", |
|
"at-spi2-atk.x86_64", |
|
"at-spi2-core.x86_64", |
|
"atk.x86_64", |
|
"audit-libs.x86_64", |
|
"audit.x86_64", |
|
"augeas-libs.x86_64", |
|
"authselect-libs.x86_64", |
|
"authselect.x86_64", |
|
"autogen-libopts.x86_64", |
|
"avahi-glib.x86_64", |
|
"avahi-libs.x86_64", |
|
], |
|
b => [ |
|
"basesystem.noarch", |
|
"bash-completion.noarch", |
|
"bash.x86_64", |
|
"binutils.x86_64", |
|
"bind-export-libs.x86_64", |
|
"bind-libs-lite.x86_64", |
|
"bind-libs.x86_64", |
|
"bind-license.noarch", |
|
"bind-utils.x86_64", |
|
"bluez-libs.x86_64", |
|
"bluez-obexd.x86_64", |
|
"bluez.x86_64", |
|
"bolt.x86_64", |
|
"boost-atomic.x86_64", |
|
"boost-chrono.x86_64", |
|
"boost-date-time.x86_64", |
|
"boost-iostreams.x86_64", |
|
"boost-program-options.x86_64", |
|
"boost-random.x86_64", |
|
"boost-regex.x86_64", |
|
"boost-system.x86_64", |
|
"boost-thread.x86_64", |
|
"bpg-dejavu-sans-fonts.noarch", |
|
"brotli.x86_64", |
|
"bubblewrap.x86_64", |
|
"bzip2-libs.x86_64", |
|
"bzip2.x86_64", |
|
], |
|
c => [ |
|
"c-ares.x86_64", |
|
"ca-certificates.noarch", |
|
"cairo-gobject.x86_64", |
|
"cairo.x86_64", |
|
"celt051.x86_64", |
|
"checkpolicy.x86_64", |
|
"cheese-libs.x86_64", |
|
"chkconfig.x86_64", |
|
"chrony.x86_64", |
|
"cifs-utils.x86_64", |
|
"clutter-gst3.x86_64", |
|
"clutter-gtk.x86_64", |
|
"clutter.x86_64", |
|
"cockpit-bridge.x86_64", |
|
"cockpit-dashboard.noarch", |
|
"cockpit-machines.noarch", |
|
"cockpit-packagekit.noarch", |
|
"cockpit-system.noarch", |
|
"cockpit-ws.x86_64", |
|
"cockpit.x86_64", |
|
"cogl.x86_64", |
|
"color-filesystem.noarch", |
|
"colord-gtk.x86_64", |
|
"colord-libs.x86_64", |
|
"colord.x86_64", |
|
"coreutils-common.x86_64", |
|
"coreutils.x86_64", |
|
"cpio.x86_64", |
|
"cpp.x86_64", |
|
"cracklib-dicts.x86_64", |
|
"cracklib.x86_64", |
|
"createrepo_c-libs.x86_64", |
|
"createrepo_c.x86_64", |
|
"cronie-anacron.x86_64", |
|
"cronie.x86_64", |
|
"crontabs.noarch", |
|
"crypto-policies.noarch", |
|
"crypto-policies-scripts.noarch", |
|
"cryptsetup-libs.x86_64", |
|
"cups-libs.x86_64", |
|
"cups-pk-helper.x86_64", |
|
"curl.x86_64", |
|
"cyrus-sasl-gssapi.x86_64", |
|
"cyrus-sasl-lib.x86_64", |
|
"cyrus-sasl-md5.x86_64", |
|
"cyrus-sasl-plain.x86_64", |
|
"cyrus-sasl.x86_64", |
|
], |
|
d => [ |
|
"dbus-common.noarch", |
|
"dbus-daemon.x86_64", |
|
"dbus-glib.x86_64", |
|
"dbus-libs.x86_64", |
|
"dbus-tools.x86_64", |
|
"dbus-x11.x86_64", |
|
"dbus.x86_64", |
|
"dconf.x86_64", |
|
"dejavu-fonts-common.noarch", |
|
"dejavu-sans-fonts.noarch", |
|
"dejavu-sans-mono-fonts.noarch", |
|
"dejavu-serif-fonts.noarch", |
|
"desktop-file-utils.x86_64", |
|
"device-mapper-event-libs.x86_64", |
|
"device-mapper-event.x86_64", |
|
"device-mapper-libs.x86_64", |
|
"device-mapper-multipath-libs.x86_64", |
|
"device-mapper-multipath.x86_64", |
|
"device-mapper-persistent-data.x86_64", |
|
"device-mapper.x86_64", |
|
"dhcp-client.x86_64", |
|
"dhcp-common.noarch", |
|
"dhcp-libs.x86_64", |
|
"dhcp-server.x86_64", |
|
"diffutils.x86_64", |
|
"dmidecode.x86_64", |
|
"dnf-data.noarch", |
|
"dnf-plugin-subscription-manager.x86_64", |
|
"dnf-plugins-core.noarch", |
|
"dnf.noarch", |
|
"dnsmasq.x86_64", |
|
"dosfstools.x86_64", |
|
"dracut-config-rescue.x86_64", |
|
"dracut-network.x86_64", |
|
"dracut-squash.x86_64", |
|
"dracut.x86_64", |
|
"drbd90-utils.x86_64", |
|
"drpm.x86_64", |
|
"dwz.x86_64", |
|
], |
|
e => [ |
|
"e2fsprogs-libs.x86_64", |
|
"e2fsprogs.x86_64", |
|
"edk2-ovmf.noarch", |
|
"efi-srpm-macros.noarch", |
|
"elfutils.x86_64", |
|
"elfutils-default-yama-scope.noarch", |
|
"elfutils-libelf.x86_64", |
|
"elfutils-libelf-devel.x86_64", |
|
"elfutils-libs.x86_64", |
|
"emacs-filesystem.noarch", |
|
"enchant.x86_64", |
|
"enchant2.x86_64 ", |
|
"ethtool.x86_64", |
|
"evolution-data-server-langpacks.noarch", |
|
"evolution-data-server.x86_64", |
|
"expat.x86_64", |
|
"expect.x86_64", |
|
], |
|
f => [ |
|
"fence-agents-all.x86_64", |
|
"fence-agents-amt-ws.noarch", |
|
"fence-agents-apc-snmp.noarch", |
|
"fence-agents-apc.noarch", |
|
"fence-agents-bladecenter.noarch", |
|
"fence-agents-brocade.noarch", |
|
"fence-agents-cisco-mds.noarch", |
|
"fence-agents-cisco-ucs.noarch", |
|
"fence-agents-common.noarch", |
|
"fence-agents-compute.noarch", |
|
"fence-agents-drac5.noarch", |
|
"fence-agents-eaton-snmp.noarch", |
|
"fence-agents-emerson.noarch", |
|
"fence-agents-eps.noarch", |
|
"fence-agents-heuristics-ping.noarch", |
|
"fence-agents-hpblade.noarch", |
|
"fence-agents-ibmblade.noarch", |
|
"fence-agents-ifmib.noarch", |
|
"fence-agents-ilo-moonshot.noarch", |
|
"fence-agents-ilo-mp.noarch", |
|
"fence-agents-ilo-ssh.noarch", |
|
"fence-agents-ilo2.noarch", |
|
"fence-agents-intelmodular.noarch", |
|
"fence-agents-ipdu.noarch", |
|
"fence-agents-ipmilan.noarch", |
|
"fence-agents-kdump.x86_64", |
|
"fence-agents-mpath.noarch", |
|
"fence-agents-redfish.x86_64", |
|
"fence-agents-rhevm.noarch", |
|
"fence-agents-rsa.noarch", |
|
"fence-agents-rsb.noarch", |
|
"fence-agents-sbd.noarch", |
|
"fence-agents-scsi.noarch", |
|
"fence-agents-virsh.noarch", |
|
"fence-agents-vmware-rest.noarch", |
|
"fence-agents-vmware-soap.noarch", |
|
"fence-agents-wti.noarch", |
|
"fence-virt.x86_64", |
|
"file-libs.x86_64", |
|
"file.x86_64", |
|
"filesystem.x86_64", |
|
"findutils.x86_64", |
|
"fipscheck-lib.x86_64", |
|
"fipscheck.x86_64", |
|
"firefox.x86_64", |
|
"firewalld-filesystem.noarch", |
|
"firewalld.noarch", |
|
"flac-libs.x86_64", |
|
"flatpak.x86_64", |
|
"fontconfig.x86_64", |
|
"fontpackages-filesystem.noarch", |
|
"freeipmi.x86_64", |
|
"freetype.x86_64", |
|
"fribidi.x86_64", |
|
"fuse.x86_64", |
|
"fuse-libs.x86_64", |
|
], |
|
g => [ |
|
"gawk.x86_64", |
|
"GConf2.x86_64", |
|
"gc.x86_64", |
|
"gcc.x86_64", |
|
"gcr.x86_64", |
|
"gdb-headless.x86_64", |
|
"gdbm-libs.x86_64", |
|
"gdbm.x86_64", |
|
"gdisk.x86_64", |
|
"gdk-pixbuf2-modules.x86_64", |
|
"gdk-pixbuf2.x86_64", |
|
"gdm.x86_64", |
|
"genisoimage.x86_64", |
|
"geoclue2-libs.x86_64", |
|
"geoclue2.x86_64", |
|
"geocode-glib.x86_64", |
|
"geolite2-city.noarch", |
|
"geolite2-country.noarch", |
|
"gettext-libs.x86_64", |
|
"gettext.x86_64", |
|
"ghc-srpm-macros.noarch", |
|
"gjs.x86_64", |
|
"glib-networking.x86_64", |
|
"glib2.x86_64", |
|
"glibc-common.x86_64", |
|
"glibc-devel.x86_64", |
|
"glibc-langpack-en.x86_64", |
|
"glibc.x86_64", |
|
"glibc-devel.x86_64", |
|
"glibc-headers.x86_64", |
|
"glusterfs.x86_64", |
|
"glusterfs-api.x86_64", |
|
"glusterfs-cli.x86_64", |
|
"glusterfs-client-xlators.x86_64", |
|
"glusterfs-libs.x86_64", |
|
"glx-utils.x86_64", |
|
"gmp.x86_64", |
|
"gnome-bluetooth-libs.x86_64", |
|
"gnome-bluetooth.x86_64", |
|
"gnome-control-center-filesystem.noarch", |
|
"gnome-control-center.x86_64", |
|
"gnome-desktop3.x86_64", |
|
"gnome-keyring-pam.x86_64", |
|
"gnome-keyring.x86_64", |
|
"gnome-online-accounts.x86_64", |
|
"gnome-session-wayland-session.x86_64", |
|
"gnome-session-xsession.x86_64", |
|
"gnome-session.x86_64", |
|
"gnome-settings-daemon.x86_64", |
|
"gnome-shell.x86_64", |
|
"gnome-terminal.x86_64", |
|
"gnome-themes-standard.x86_64", |
|
"gnupg2-smime.x86_64", |
|
"gnupg2.x86_64", |
|
"gnutls-dane.x86_64", |
|
"gnutls-utils.x86_64", |
|
"gnutls.x86_64", |
|
"go-srpm-macros.noarch", |
|
"gobject-introspection.x86_64", |
|
"gpgme.x86_64", |
|
"gpm-libs.x86_64", |
|
"gpm.x86_64", |
|
"graphite2.x86_64", |
|
"grep.x86_64", |
|
"grilo.x86_64", |
|
"groff-base.x86_64", |
|
"grub2-common.noarch", |
|
"grub2-pc-modules.noarch", |
|
"grub2-pc.x86_64", |
|
"grub2-tools-extra.x86_64", |
|
"grub2-tools-minimal.x86_64", |
|
"grub2-tools.x86_64", |
|
"grubby.x86_64", |
|
"gsettings-desktop-schemas.x86_64", |
|
"gsm.x86_64", |
|
"gssproxy.x86_64", |
|
"gstreamer1-plugins-base.x86_64", |
|
"gstreamer1.x86_64", |
|
"gtksourceview3.x86_64", |
|
"gtk-update-icon-cache.x86_64", |
|
"gtk-vnc2.x86_64", |
|
"gtk2.x86_64", |
|
"gtk3.x86_64", |
|
"guile.x86_64", |
|
"gvfs.x86_64", |
|
"gvfs-client.x86_64", |
|
"gvnc.x86_64", |
|
"gzip.x86_64", |
|
], |
|
h => [ |
|
"hardlink.x86_64", |
|
"harfbuzz-icu.x86_64", |
|
"harfbuzz.x86_64", |
|
"hdparm.x86_64", |
|
"hicolor-icon-theme.noarch", |
|
"hostname.x86_64", |
|
"htop.x86_64", |
|
"httpd-filesystem.noarch", |
|
"httpd-tools.x86_64", |
|
"httpd.x86_64", |
|
"hunspell-en-GB.noarch", |
|
"hunspell-en-US.noarch", |
|
"hunspell-en.noarch", |
|
"hunspell.x86_64", |
|
"hwdata.noarch", |
|
"hyphen.x86_64", |
|
], |
|
i => [ |
|
"ibus-gtk2.x86_64", |
|
"ibus-gtk3.x86_64", |
|
"ibus-libs.x86_64", |
|
"ibus-setup.noarch", |
|
"ibus.x86_64", |
|
"iio-sensor-proxy.x86_64", |
|
"ima-evm-utils.x86_64", |
|
"info.x86_64", |
|
"initscripts.x86_64", |
|
"ipcalc.x86_64", |
|
"ipmitool.x86_64", |
|
"iproute-tc.x86_64", |
|
"iproute.x86_64", |
|
"iprutils.x86_64", |
|
"ipset-libs.x86_64", |
|
"ipset.x86_64", |
|
"iptables-ebtables.x86_64", |
|
"iptables-libs.x86_64", |
|
"iptables.x86_64", |
|
"iputils.x86_64", |
|
"ipxe-roms-qemu.noarch", |
|
"irqbalance.x86_64", |
|
"iscsi-initiator-utils-iscsiuio.x86_64", |
|
"iscsi-initiator-utils.x86_64", |
|
"isns-utils-libs.x86_64", |
|
"isl.x86_64", |
|
"iso-codes.noarch", |
|
"iwl100-firmware.noarch", |
|
"iwl1000-firmware.noarch", |
|
"iwl105-firmware.noarch", |
|
"iwl135-firmware.noarch", |
|
"iwl2000-firmware.noarch", |
|
"iwl2030-firmware.noarch", |
|
"iwl3160-firmware.noarch", |
|
"iwl3945-firmware.noarch", |
|
"iwl4965-firmware.noarch", |
|
"iwl5000-firmware.noarch", |
|
"iwl5150-firmware.noarch", |
|
"iwl6000-firmware.noarch", |
|
"iwl6000g2a-firmware.noarch", |
|
"iwl6050-firmware.noarch", |
|
"iwl7260-firmware.noarch", |
|
], |
|
j => [ |
|
"jansson.x86_64", |
|
"jasper-libs.x86_64", |
|
"jbigkit-libs.x86_64", |
|
"json-c.x86_64", |
|
"json-glib.x86_64", |
|
], |
|
k => [ |
|
"kbd-legacy.noarch", |
|
"kbd-misc.noarch", |
|
"kbd.x86_64", |
|
"kernel-core.x86_64", |
|
"kernel-doc.noarch", |
|
"kernel-devel.x86_64", |
|
"kernel-headers.x86_64", |
|
"kernel-modules.x86_64", |
|
"kernel-tools-libs.x86_64", |
|
"kernel-tools.x86_64", |
|
"kernel.x86_64", |
|
"kexec-tools.x86_64", |
|
"keyutils-libs.x86_64", |
|
"keyutils.x86_64", |
|
"kmod-drbd90.x86_64", |
|
"kmod-libs.x86_64", |
|
"kmod.x86_64", |
|
"kpartx.x86_64", |
|
"krb5-libs.x86_64", |
|
], |
|
l => [ |
|
"langpacks-en.noarch", |
|
"lcms2.x86_64", |
|
"less.x86_64", |
|
"libICE.x86_64", |
|
"libSM.x86_64", |
|
"libX11-common.noarch", |
|
"libX11-xcb.x86_64", |
|
"libX11.x86_64", |
|
"libXau.x86_64", |
|
"libXcomposite.x86_64", |
|
"libXcursor.x86_64", |
|
"libXdamage.x86_64", |
|
"libXdmcp.x86_64", |
|
"libXext.x86_64", |
|
"libXfixes.x86_64", |
|
"libXfont2.x86_64", |
|
"libXft.x86_64", |
|
"libXi.x86_64", |
|
"libXinerama.x86_64", |
|
"libXmu.x86_64", |
|
"libXrandr.x86_64", |
|
"libXrender.x86_64", |
|
"libXt.x86_64", |
|
"libXtst.x86_64", |
|
"libXv.x86_64", |
|
"libXxf86misc.x86_64", |
|
"libXxf86vm.x86_64", |
|
"libacl.x86_64", |
|
"libaio.x86_64", |
|
"libappstream-glib.x86_64", |
|
"libarchive.x86_64", |
|
"libassuan.x86_64", |
|
"libasyncns.x86_64", |
|
"libatasmart.x86_64", |
|
"libatomic_ops.x86_64", |
|
"libattr.x86_64", |
|
"libbabeltrace.x86_64", |
|
"libbasicobjects.x86_64", |
|
"libblkid.x86_64", |
|
"libbytesize.x86_64", |
|
"libbluray.x86_64", |
|
"libcacard.x86_64", |
|
"libcanberra-gtk3.x86_64", |
|
"libcanberra.x86_64", |
|
"libcap-ng.x86_64", |
|
"libcap.x86_64", |
|
"libcdio.x86_64", |
|
"libcdio-paranoia.x86_64", |
|
"libcgroup.x86_64", |
|
"libblockdev.x86_64", |
|
"libblockdev-crypto.x86_64", |
|
"libblockdev-fs.x86_64", |
|
"libblockdev-loop.x86_64", |
|
"libblockdev-mdraid.x86_64", |
|
"libblockdev-part.x86_64", |
|
"libblockdev-swap.x86_64", |
|
"libblockdev-utils.x86_64", |
|
"libcollection.x86_64", |
|
"libcom_err.x86_64", |
|
"libcomps.x86_64", |
|
"libcroco.x86_64", |
|
"libcurl.x86_64", |
|
"libdaemon.x86_64", |
|
"libdatrie.x86_64", |
|
"libdb-utils.x86_64", |
|
"libdb.x86_64", |
|
"libdhash.x86_64", |
|
"libdnf.x86_64", |
|
"libdrm.x86_64", |
|
"libedit.x86_64", |
|
"libepoxy.x86_64", |
|
"liberation-fonts-common.noarch", |
|
"liberation-sans-fonts.noarch", |
|
"libestr.x86_64", |
|
"libevdev.x86_64", |
|
"libevent.x86_64", |
|
"libfastjson.x86_64", |
|
"libfdisk.x86_64", |
|
"libffi.x86_64", |
|
"libfontenc.x86_64", |
|
"libgcc.x86_64", |
|
"libgcrypt.x86_64", |
|
"libgdata.x86_64", |
|
"libglvnd-egl.x86_64", |
|
"libglvnd-gles.x86_64", |
|
"libglvnd-glx.x86_64", |
|
"libglvnd.x86_64", |
|
"libgnomekbd.x86_64", |
|
"libgomp.x86_64", |
|
"libgpg-error.x86_64", |
|
"libgtop2.x86_64", |
|
"libgudev.x86_64", |
|
"libgusb.x86_64", |
|
"libgweather.x86_64", |
|
"libibumad.x86_64", |
|
"libibverbs.x86_64", |
|
"libical.x86_64", |
|
"libicu.x86_64", |
|
"libidn2.x86_64", |
|
"libimobiledevice.x86_64", |
|
"libini_config.x86_64", |
|
"libinput.x86_64", |
|
"libipt.x86_64", |
|
"libiscsi.x86_64", |
|
"libjpeg-turbo.x86_64", |
|
"libkcapi-hmaccalc.x86_64", |
|
"libkcapi.x86_64", |
|
"libksba.x86_64", |
|
"libldb.x86_64", |
|
"libmaxminddb.x86_64", |
|
"libmcpp.x86_64", |
|
"libmetalink.x86_64", |
|
"libmnl.x86_64", |
|
"libmodman.x86_64", |
|
"libmodulemd.x86_64", |
|
"libmodulemd1.x86_64", |
|
"libmount.x86_64", |
|
"libmpc.x86_64", |
|
"libndp.x86_64", |
|
"libnetfilter_conntrack.x86_64", |
|
"libnfnetlink.x86_64", |
|
"libnfsidmap.x86_64", |
|
"libnftnl.x86_64", |
|
"libnghttp2.x86_64", |
|
"libnl3-cli.x86_64", |
|
"libnl3.x86_64", |
|
"libnma.x86_64", |
|
"libnotify.x86_64", |
|
"libnsl2.x86_64", |
|
"liboauth.x86_64", |
|
"libogg.x86_64", |
|
"libosinfo.x86_64", |
|
"libpath_utils.x86_64", |
|
"libpcap.x86_64", |
|
"libpciaccess.x86_64", |
|
"libpipeline.x86_64", |
|
"libpkgconf.x86_64", |
|
"libplist.x86_64", |
|
"libpmem.x86_64", |
|
"libpng.x86_64", |
|
"libpq.x86_64", |
|
"libproxy.x86_64", |
|
"libpsl.x86_64", |
|
"libpwquality.x86_64", |
|
"libqb.x86_64", |
|
"libquvi-scripts.noarch", |
|
"libquvi.x86_64", |
|
"librados2.x86_64", |
|
"librbd1.x86_64", |
|
"librdmacm.x86_64", |
|
"libref_array.x86_64", |
|
"librepo.x86_64", |
|
"libreport-filesystem.x86_64", |
|
"librhsm.x86_64", |
|
"librsvg2.x86_64", |
|
"libseccomp.x86_64", |
|
"libsecret.x86_64", |
|
"libselinux-utils.x86_64", |
|
"libselinux.x86_64", |
|
"libsemanage.x86_64", |
|
"libsepol.x86_64", |
|
"libsigsegv.x86_64", |
|
"libsmartcols.x86_64", |
|
"libsmbclient.x86_64", |
|
"libsndfile.x86_64", |
|
"libsolv.x86_64", |
|
"libsoup.x86_64", |
|
"libss.x86_64", |
|
"libssh.x86_64", |
|
"libssh-config.noarch", |
|
"libssh2.x86_64", |
|
"libsss_autofs.x86_64", |
|
"libsss_certmap.x86_64", |
|
"libsss_idmap.x86_64", |
|
"libsss_nss_idmap.x86_64", |
|
"libsss_sudo.x86_64", |
|
"libstdc++.x86_64", |
|
"libstemmer.x86_64", |
|
"libsysfs.x86_64", |
|
"libtalloc.x86_64", |
|
"libtasn1.x86_64", |
|
"libtdb.x86_64", |
|
"libteam.x86_64", |
|
"libtevent.x86_64", |
|
"libthai.x86_64", |
|
"libtheora.x86_64", |
|
"libtiff.x86_64", |
|
"libtirpc.x86_64", |
|
"libtool-ltdl.x86_64", |
|
"libudisks2.x86_64", |
|
"libunistring.x86_64", |
|
"libusal.x86_64", |
|
"libusbmuxd.x86_64", |
|
"libusbx.x86_64", |
|
"libuser.x86_64", |
|
"libutempter.x86_64", |
|
"libuuid.x86_64", |
|
"libverto-libevent.x86_64", |
|
"libverto.x86_64", |
|
"libvirt-bash-completion.x86_64", |
|
"libvirt-client.x86_64", |
|
"libvirt-daemon-config-network.x86_64", |
|
"libvirt-daemon-config-nwfilter.x86_64", |
|
"libvirt-daemon-driver-interface.x86_64", |
|
"libvirt-daemon-driver-network.x86_64", |
|
"libvirt-daemon-driver-nodedev.x86_64", |
|
"libvirt-daemon-driver-nwfilter.x86_64", |
|
"libvirt-daemon-driver-qemu.x86_64", |
|
"libvirt-daemon-driver-secret.x86_64", |
|
"libvirt-daemon-driver-storage.x86_64", |
|
"libvirt-daemon-driver-storage-core.x86_64", |
|
"libvirt-daemon-driver-storage-disk.x86_64", |
|
"libvirt-daemon-driver-storage-gluster.x86_64", |
|
"libvirt-daemon-driver-storage-iscsi.x86_64", |
|
"libvirt-daemon-driver-storage-iscsi-direct.x86_64", |
|
"libvirt-daemon-driver-storage-logical.x86_64", |
|
"libvirt-daemon-driver-storage-mpath.x86_64", |
|
"libvirt-daemon-driver-storage-rbd.x86_64", |
|
"libvirt-daemon-driver-storage-scsi.x86_64", |
|
"libvirt-daemon-kvm.x86_64", |
|
"libvirt-daemon.x86_64", |
|
"libvirt-docs.x86_64", |
|
"libvirt-glib.x86_64", |
|
"libvirt-libs.x86_64", |
|
"libvirt.x86_64", |
|
"libvisual.x86_64", |
|
"libvorbis.x86_64", |
|
"libwacom-data.noarch", |
|
"libwacom.x86_64", |
|
"libwayland-client.x86_64", |
|
"libwayland-cursor.x86_64", |
|
"libwayland-egl.x86_64", |
|
"libwayland-server.x86_64", |
|
"libwbclient.x86_64", |
|
"libwebp.x86_64", |
|
"libwsman1.x86_64", |
|
"libxcb.x86_64", |
|
"libxcrypt.x86_64", |
|
"libxcrypt-devel.x86_64", |
|
"libxkbcommon-x11.x86_64", |
|
"libxkbcommon.x86_64", |
|
"libxkbfile.x86_64", |
|
"libxklavier.x86_64", |
|
"libxml2.x86_64", |
|
"libxshmfence.x86_64", |
|
"libxslt.x86_64", |
|
"libyaml.x86_64", |
|
"libzstd.x86_64", |
|
"linux-firmware.noarch", |
|
"linuxconsoletools.x86_64", |
|
"llvm-libs.x86_64", |
|
"logrotate.x86_64", |
|
"lshw.x86_64", |
|
"lsscsi.x86_64", |
|
"lua-expat.x86_64", |
|
"lua-json.noarch", |
|
"lua-libs.x86_64", |
|
"lua-lpeg.x86_64", |
|
"lua-socket.x86_64", |
|
"lua.x86_64", |
|
"lvm2-libs.x86_64", |
|
"lvm2.x86_64", |
|
"lz4-libs.x86_64", |
|
"lzo.x86_64", |
|
"lzop.x86_64", |
|
], |
|
'm' => [ |
|
"mailcap.noarch", |
|
"mailx.x86_64", |
|
"make.x86_64", |
|
"man-db.x86_64", |
|
"mcpp.x86_64", |
|
"mdadm.x86_64", |
|
"mesa-dri-drivers.x86_64", |
|
"mesa-filesystem.x86_64", |
|
"mesa-libEGL.x86_64", |
|
"mesa-libGL.x86_64", |
|
"mesa-libgbm.x86_64", |
|
"mesa-libglapi.x86_64", |
|
"microcode_ctl.x86_64", |
|
"mlocate.x86_64", |
|
"mobile-broadband-provider-info.noarch", |
|
"mod_http2.x86_64", |
|
"ModemManager-glib.x86_64", |
|
"mozilla-filesystem.x86_64", |
|
"mozjs52.x86_64", |
|
"mozjs60.x86_64", |
|
"mpfr.x86_64", |
|
"mtdev.x86_64", |
|
"mtools.x86_64", |
|
"mutter.x86_64", |
|
], |
|
n => [ |
|
"ncurses-base.noarch", |
|
"ncurses-libs.x86_64", |
|
"ncurses.x86_64", |
|
"net-snmp-libs.x86_64", |
|
"net-snmp-utils.x86_64", |
|
"net-tools.x86_64", |
|
"netcf-libs.x86_64", |
|
"nettle.x86_64", |
|
"NetworkManager-libnm.x86_64", |
|
"NetworkManager-team.x86_64", |
|
"NetworkManager-tui.x86_64", |
|
"NetworkManager-wifi.x86_64", |
|
"NetworkManager.x86_64", |
|
"newt.x86_64", |
|
"nfs-utils.x86_64", |
|
"nftables.x86_64", |
|
"nm-connection-editor.x86_64", |
|
"nmap-ncat.x86_64", |
|
"nmap.x86_64", |
|
"npth.x86_64", |
|
"nspr.x86_64", |
|
"nss.x86_64", |
|
"nss-softokn-freebl.x86_64", |
|
"nss-softokn.x86_64", |
|
"nss-sysinit.x86_64", |
|
"nss-util.x86_64", |
|
"numactl-libs.x86_64", |
|
"numad.x86_64", |
|
"nvme-cli.x86_64", |
|
], |
|
o => [ |
|
"ocaml-srpm-macros.noarch", |
|
"openblas-srpm-macros.noarch", |
|
"openldap.x86_64", |
|
"openssh-clients.x86_64", |
|
"openssh-server.x86_64", |
|
"openssh.x86_64", |
|
"openssl-libs.x86_64", |
|
"openssl-pkcs11.x86_64", |
|
"openssl.x86_64", |
|
"openwsman-python3.x86_64", |
|
"opus.x86_64", |
|
"orc.x86_64", |
|
"os-prober.x86_64", |
|
"osinfo-db-tools.x86_64", |
|
"osinfo-db.noarch", |
|
"overpass-fonts.noarch", |
|
], |
|
p => [ |
|
"p11-kit-trust.x86_64", |
|
"p11-kit.x86_64", |
|
"PackageKit-glib.x86_64", |
|
"PackageKit.x86_64", |
|
"pam.x86_64", |
|
"pango.x86_64", |
|
"parted.x86_64", |
|
"passwd.x86_64", |
|
"patch.x86_64", |
|
"pciutils-libs.x86_64", |
|
"pciutils.x86_64", |
|
"pcre.x86_64", |
|
"pcre2.x86_64", |
|
"perl-aliased.noarch", |
|
"perl-Algorithm-C3.noarch", |
|
"perl-Algorithm-Diff.noarch", |
|
"perl-Authen-SASL.noarch", |
|
"perl-B-Hooks-EndOfScope.noarch", |
|
"perl-CGI.noarch", |
|
"perl-Capture-Tiny.noarch", |
|
"perl-Carp.noarch", |
|
"perl-Class-C3.noarch", |
|
"perl-Class-Data-Inheritable.noarch", |
|
"perl-Class-Method-Modifiers.noarch", |
|
"perl-Compress-Raw-Bzip2.x86_64", |
|
"perl-Compress-Raw-Zlib.x86_64", |
|
"perl-Convert-ASN1.noarch", |
|
"perl-Curses.x86_64", |
|
"perl-Curses-UI.noarch", |
|
"perl-DBD-Pg.x86_64", |
|
"perl-DBI.x86_64", |
|
"perl-Data-Dump.noarch", |
|
"perl-Data-Dumper.x86_64", |
|
"perl-Data-Dumper-Concise.noarch", |
|
"perl-Data-OptList.noarch", |
|
"perl-Date-Manip.noarch", |
|
"perl-Data-Validate-Domain.noarch", |
|
"perl-Data-Validate-IP.noarch", |
|
"perl-Devel-ArgNames.noarch", |
|
"perl-Devel-Caller.x86_64", |
|
"perl-Devel-GlobalDestruction.noarch", |
|
"perl-Devel-LexAlias.x86_64", |
|
"perl-Devel-StackTrace.noarch", |
|
"perl-Digest-HMAC.noarch", |
|
"perl-Digest-MD5.x86_64", |
|
"perl-Digest-SHA.x86_64", |
|
"perl-Digest-SHA1.x86_64", |
|
"perl-Digest.noarch", |
|
"perl-Dist-CheckConflicts.noarch", |
|
"perl-Email-Date-Format.noarch", |
|
"perl-Email-Find.noarch", |
|
"perl-Email-Valid.noarch", |
|
"perl-Encode-Locale.noarch", |
|
"perl-Encode.x86_64", |
|
"perl-Errno.x86_64", |
|
"perl-Eval-Closure.noarch", |
|
"perl-Eval-WithLexicals.noarch", |
|
"perl-Exception-Class.noarch", |
|
"perl-Exporter.noarch", |
|
"perl-Exporter-Declare.noarch", |
|
"perl-File-BaseDir", |
|
"perl-File-DesktopEntry", |
|
"perl-File-Listing.noarch", |
|
"perl-File-MimeInfo.noarch", |
|
"perl-File-Path.noarch", |
|
"perl-File-Temp.noarch", |
|
"perl-Filter.x86_64", |
|
"perl-Filter-Simple.noarch", |
|
"perl-Future.noarch", |
|
"perl-Getopt-Long.noarch", |
|
"perl-GSSAPI.x86_64", |
|
"perl-HTML-FromText.noarch", |
|
"perl-HTML-Parser.x86_64", |
|
"perl-HTML-Strip.x86_64", |
|
"perl-HTML-Tagset.noarch", |
|
"perl-HTTP-Cookies.noarch", |
|
"perl-HTTP-Date.noarch", |
|
"perl-HTTP-Message.noarch", |
|
"perl-HTTP-Negotiate.noarch", |
|
"perl-HTTP-Tiny.noarch", |
|
"perl-Import-Into.noarch", |
|
"perl-IO.x86_64", |
|
"perl-IO-Compress.noarch", |
|
"perl-IO-HTML.noarch", |
|
"perl-IO-Socket-IP.noarch", |
|
"perl-IO-Socket-SSL.noarch", |
|
"perl-IO-Tty.x86_64", |
|
"perl-IPC-SysV.x86_64", |
|
"perl-JSON.noarch", |
|
"perl-JSON-PP.noarch", |
|
"perl-LDAP.noarch", |
|
"perl-LWP-MediaTypes.noarch", |
|
"perl-Log-Contextual.noarch", |
|
"perl-Log-Dispatch-FileRotate.noarch", |
|
"perl-Log-Dispatch.noarch", |
|
"perl-Log-Journald.x86_64", |
|
"perl-Log-Log4perl.noarch", |
|
"perl-Meta-Builder.noarch", |
|
"perl-MIME-Base64.x86_64", |
|
"perl-MIME-Lite.noarch", |
|
"perl-MIME-Types.noarch", |
|
"perl-MRO-Compat.noarch", |
|
"perl-Mail-Sender.noarch", |
|
"perl-Mail-Sendmail.noarch", |
|
"perl-MailTools.noarch", |
|
"perl-Math-BigInt.noarch", |
|
"perl-Math-Complex.noarch", |
|
"perl-Module-Implementation.noarch", |
|
"perl-Module-Runtime.noarch", |
|
"perl-Moo.noarch", |
|
"perl-Mozilla-CA.noarch", |
|
"perl-NTLM.noarch", |
|
"perl-Net-Domain-TLD.noarch", |
|
"perl-Net-HTTP.noarch", |
|
"perl-Net-Netmask.noarch", |
|
"perl-Net-OpenSSH.noarch", |
|
"perl-Net-SMTP-SSL.noarch", |
|
"perl-Net-SSH2.x86_64", |
|
"perl-Net-SSLeay.x86_64", |
|
"perl-NetAddr-IP.x86_64", |
|
"perl-Object-Remote.noarch", |
|
"perl-Package-Generator.noarch", |
|
"perl-Package-Stash-XS.x86_64", |
|
"perl-Package-Stash.noarch", |
|
"perl-PadWalker.x86_64", |
|
"perl-Params-Util.x86_64", |
|
"perl-Params-Validate.x86_64", |
|
"perl-Params-ValidationCompiler.noarch", |
|
"perl-PathTools.x86_64", |
|
"perl-Pod-Escapes.noarch", |
|
"perl-Pod-Perldoc.noarch", |
|
"perl-Pod-Simple.noarch", |
|
"perl-Pod-Usage.noarch", |
|
"perl-Proc-Simple.noarch", |
|
"perl-Ref-Util-XS.x86_64", |
|
"perl-Ref-Util.noarch", |
|
"perl-Mail-RFC822-Address.noarch", |
|
"perl-Role-Tiny.noarch", |
|
"perl-Scalar-List-Utils.x86_64", |
|
"perl-SelfLoader.noarch", |
|
"perl-Socket.x86_64", |
|
"perl-Socket6.x86_64", |
|
"perl-Specio.noarch", |
|
"perl-srpm-macros.noarch", |
|
"perl-Storable.x86_64", |
|
"perl-strictures.noarch", |
|
"perl-String-ShellQuote.noarch", |
|
"perl-Sub-Exporter-Progressive.noarch", |
|
"perl-Sub-Exporter.noarch", |
|
"perl-Sub-Identify.x86_64", |
|
"perl-Sub-Install.noarch", |
|
"perl-Sub-Quote.noarch", |
|
"perl-Sys-Syslog.x86_64", |
|
"perl-Sys-Virt.x86_64", |
|
"perl-Term-ANSIColor.noarch", |
|
"perl-Term-Cap.noarch", |
|
"perl-Text-Balanced.noarch", |
|
"perl-TermReadKey.x86_64", |
|
"perl-Test-Simple.noarch", |
|
"perl-Text-Diff.noarch", |
|
"perl-Text-ParseWords.noarch", |
|
"perl-Text-Soundex.x86_64", |
|
"perl-Text-Tabs+Wrap.noarch", |
|
"perl-Text-Unidecode.noarch", |
|
"perl-Time-HiRes.x86_64", |
|
"perl-Time-Local.noarch", |
|
"perl-TimeDate.noarch", |
|
"perl-Try-Tiny.noarch", |
|
"perl-URI.noarch", |
|
"perl-UUID-Tiny.noarch", |
|
"perl-Unicode-Normalize.x86_64", |
|
"perl-Variable-Magic.x86_64", |
|
"perl-WWW-RobotRules.noarch", |
|
"perl-XML-LibXML.x86_64", |
|
"perl-XML-NamespaceSupport.noarch", |
|
"perl-XML-Parser.x86_64", |
|
"perl-XML-SAX-Base.noarch", |
|
"perl-XML-SAX.noarch", |
|
"perl-XML-Simple.noarch", |
|
"perl-constant.noarch", |
|
"perl-interpreter.x86_64", |
|
"perl-libnet.noarch", |
|
"perl-libs.x86_64", |
|
"perl-libwww-perl.noarch", |
|
"perl-macros.x86_64", |
|
"perl-namespace-autoclean.noarch", |
|
"perl-namespace-clean.noarch", |
|
"perl-parent.noarch", |
|
"perl-podlators.noarch", |
|
"perl-threads-shared.x86_64", |
|
"perl-threads.x86_64", |
|
"perl-version.x86_64", |
|
"perltidy.noarch", |
|
"pigz.x86_64", |
|
"pinentry-gtk.x86_64", |
|
"pinentry.x86_64", |
|
"pipewire-libs.x86_64", |
|
"pipewire.x86_64", |
|
"pixman.x86_64", |
|
"pkgconf-m4.noarch", |
|
"pkgconf-pkg-config.x86_64", |
|
"pkgconf.x86_64", |
|
"platform-python.x86_64", |
|
"platform-python-pip.noarch", |
|
"platform-python-setuptools.noarch", |
|
"plymouth-core-libs.x86_64", |
|
"plymouth-scripts.x86_64", |
|
"plymouth.x86_64", |
|
"policycoreutils-python-utils.noarch", |
|
"policycoreutils.x86_64", |
|
"polkit-libs.x86_64", |
|
"polkit-pkla-compat.x86_64", |
|
"polkit.x86_64", |
|
"popt.x86_64", |
|
"postfix.x86_64", |
|
"postgresql-contrib.x86_64", |
|
"postgresql-plperl.x86_64", |
|
"postgresql-server.x86_64", |
|
"postgresql.x86_64", |
|
"prefixdevname.x86_64", |
|
"procps-ng.x86_64", |
|
"psmisc.x86_64", |
|
"publicsuffix-list-dafsa.noarch", |
|
"pulseaudio-libs-glib2.x86_64", |
|
"pulseaudio-libs.x86_64", |
|
"pulseaudio-module-bluetooth.x86_64", |
|
"pulseaudio.x86_64", |
|
"python-srpm-macros.noarch", |
|
"python3-asn1crypto.noarch", |
|
"python3-audit.x86_64", |
|
"python3-argcomplete.noarch", |
|
"python3-bind.noarch", |
|
"python3-cairo.x86_64", |
|
"python3-cffi.x86_64", |
|
"python3-chardet.noarch", |
|
"python3-configobj.noarch", |
|
"python3-cryptography.x86_64", |
|
"python3-dateutil.noarch", |
|
"python3-dbus.x86_64", |
|
"python3-decorator.noarch", |
|
"python3-dmidecode.x86_64", |
|
"python3-dnf-plugins-core.noarch", |
|
"python3-dnf.noarch", |
|
"python3-ethtool.x86_64", |
|
"python3-firewall.noarch", |
|
"python3-gobject-base.x86_64", |
|
"python3-gobject.x86_64", |
|
"python3-gpg.x86_64", |
|
"python3-hawkey.x86_64", |
|
"python3-html5lib.noarch", |
|
"python3-idna.noarch", |
|
"python3-iniparse.noarch", |
|
"python3-inotify.noarch", |
|
"python3-libcomps.x86_64", |
|
"python3-libdnf.x86_64", |
|
"python3-librepo.x86_64", |
|
"python3-libs.x86_64", |
|
"python3-libselinux.x86_64", |
|
"python3-libsemanage.x86_64", |
|
"python3-libvirt.x86_64", |
|
"python3-libxml2.x86_64", |
|
"python3-linux-procfs.noarch", |
|
"python3-lxml.x86_64", |
|
"python3-nftables.x86_64", |
|
"python3-perf.x86_64", |
|
"python3-pexpect.noarch", |
|
"python3-pip.noarch", |
|
"python3-pip-wheel.noarch", |
|
"python3-ply.noarch", |
|
"python3-policycoreutils.noarch", |
|
"python3-ptyprocess.noarch", |
|
"python3-pyOpenSSL.noarch", |
|
"python3-pycparser.noarch", |
|
"python3-pycurl.x86_64", |
|
"python3-pyparsing.noarch", |
|
"python3-pysocks.noarch", |
|
"python3-pyudev.noarch", |
|
"python3-pyyaml.x86_64", |
|
"python3-requests.noarch", |
|
"python3-rpm.x86_64", |
|
"python3-rpm-macros.noarch", |
|
"python3-schedutils.x86_64", |
|
"python3-setools.x86_64", |
|
"python3-setuptools.noarch", |
|
"python3-setuptools-wheel.noarch", |
|
"python3-six.noarch", |
|
"python3-slip-dbus.noarch", |
|
"python3-slip.noarch", |
|
"python3-subscription-manager-rhsm.x86_64", |
|
"python3-suds.noarch", |
|
"python3-syspurpose.x86_64", |
|
"python3-systemd.x86_64", |
|
"python3-unbound.x86_64", |
|
"python3-urllib3.noarch", |
|
"python3-webencodings.noarch", |
|
"python36.x86_64", |
|
], |
|
'q' => [ |
|
"qemu-guest-agent.x86_64", |
|
"qemu-img.x86_64", |
|
"qemu-kvm.x86_64", |
|
"qemu-kvm-block-curl.x86_64", |
|
"qemu-kvm-block-gluster.x86_64", |
|
"qemu-kvm-block-iscsi.x86_64", |
|
"qemu-kvm-block-rbd.x86_64", |
|
"qemu-kvm-block-ssh.x86_64", |
|
"qemu-kvm-common.x86_64", |
|
"qemu-kvm-core.x86_64", |
|
"qemu-kvm.x86_64", |
|
"qt5-srpm-macros.noarch", |
|
"quota-nls.noarch", |
|
"quota.x86_64", |
|
], |
|
r => [ |
|
"radvd.x86_64", |
|
"rdma-core.x86_64", |
|
"readline.x86_64", |
|
"redhat-rpm-config.noarch", |
|
"rest.x86_64", |
|
"rootfiles.noarch", |
|
"rpcbind.x86_64", |
|
"rpm-build.x86_64", |
|
"rpm-build-libs.x86_64", |
|
"rpmdevtools.noarch", |
|
"rpm-libs.x86_64", |
|
"rpm-plugin-selinux.x86_64", |
|
"rpm-plugin-systemd-inhibit.x86_64", |
|
"rpm.x86_64", |
|
"rsync.x86_64", |
|
"rsyslog.x86_64", |
|
"rtkit.x86_64", |
|
"ruby-irb.noarch", |
|
"ruby-libs.x86_64", |
|
"ruby.x86_64", |
|
"rubygem-bigdecimal.x86_64", |
|
"rubygem-did_you_mean.noarch", |
|
"rubygem-io-console.x86_64", |
|
"rubygem-json.x86_64", |
|
"rubygem-openssl.x86_64", |
|
"rubygem-psych.x86_64", |
|
"rubygem-rdoc.noarch", |
|
"rubygems.noarch", |
|
"rust-srpm-macros.noarch", |
|
], |
|
's' => [ |
|
"samba-client-libs.x86_64", |
|
"samba-common-libs.x86_64", |
|
"samba-common.noarch", |
|
"sbc.x86_64", |
|
"sbd.x86_64", |
|
"screen.x86_64", |
|
"SDL.x86_64", |
|
"seabios-bin.noarch", |
|
"seavgabios-bin.noarch", |
|
"sed.x86_64", |
|
"selinux-policy-targeted.noarch", |
|
"selinux-policy.noarch", |
|
"setroubleshoot-plugins.noarch", |
|
"setroubleshoot-server.x86_64", |
|
"setup.noarch", |
|
"sg3_utils-libs.x86_64", |
|
"sg3_utils.x86_64", |
|
"sgabios-bin.noarch", |
|
"shadow-utils.x86_64", |
|
"shared-mime-info.x86_64", |
|
"slang.x86_64", |
|
"smartmontools.x86_64", |
|
"snappy.x86_64", |
|
"sound-theme-freedesktop.noarch", |
|
"speexdsp.x86_64", |
|
"spice-glib.x86_64", |
|
"spice-gtk3.x86_64", |
|
"spice-server.x86_64", |
|
"sqlite-libs.x86_64", |
|
"squashfs-tools.x86_64", |
|
"sscg.x86_64", |
|
"sssd-client.x86_64", |
|
"sssd-common.x86_64", |
|
"sssd-kcm.x86_64", |
|
"sssd-nfs-idmap.x86_64", |
|
"startup-notification.x86_64", |
|
"subscription-manager-cockpit.noarch", |
|
"subscription-manager-rhsm-certificates.x86_64", |
|
"subscription-manager.x86_64", |
|
"sudo.x86_64", |
|
"switcheroo-control.x86_64", |
|
"syslinux-nonlinux.noarch", |
|
"syslinux.x86_64", |
|
"systemd-container.x86_64", |
|
"systemd-libs.x86_64", |
|
"systemd-pam.x86_64", |
|
"systemd-udev.x86_64", |
|
"systemd.x86_64", |
|
], |
|
t => [ |
|
"tar.x86_64", |
|
"tcl.x86_64", |
|
"teamd.x86_64", |
|
"telnet.x86_64", |
|
"tftp-server.x86_64", |
|
"timedatex.x86_64", |
|
"tmux.x86_64", |
|
"totem-pl-parser.x86_64", |
|
"trousers-lib.x86_64", |
|
"trousers.x86_64", |
|
"tuned.noarch", |
|
"tzdata.noarch", |
|
], |
|
u => [ |
|
"udisks2.x86_64", |
|
"unbound-libs.x86_64", |
|
"unzip.x86_64", |
|
"upower.x86_64", |
|
"usbredir.x86_64", |
|
"usbutils.x86_64", |
|
"usermode.x86_64", |
|
"userspace-rcu.x86_64", |
|
"util-linux.x86_64", |
|
"uuid.x86_64", |
|
], |
|
v => [ |
|
"vim-common.x86_64", |
|
"vim-enhanced.x86_64", |
|
"vim-filesystem.noarch", |
|
"vim-minimal.x86_64", |
|
"vino.x86_64", |
|
"virt-install.noarch", |
|
"virt-manager-common.noarch", |
|
"virt-manager.noarch", |
|
"virt-top.x86_64", |
|
"virt-what.x86_64", |
|
"volume_key-libs.x86_64", |
|
"vte-profile.x86_64", |
|
"vte291.x86_64", |
|
], |
|
w => [ |
|
"webkit2gtk3.x86_64", |
|
"webkit2gtk3-jsc.x86_64", |
|
"webrtc-audio-processing.x86_64", |
|
"wget.x86_64", |
|
"which.x86_64", |
|
"woff2.x86_64", |
|
"wpa_supplicant.x86_64", |
|
], |
|
x => [ |
|
"xcb-util.x86_64", |
|
"xdg-desktop-portal.x86_64", |
|
"xdg-desktop-portal-gtk.x86_64", |
|
"xfsprogs.x86_64", |
|
"xkeyboard-config.noarch", |
|
"xml-common.noarch", |
|
"xorg-x11-server-Xwayland.x86_64", |
|
"xorg-x11-server-common.x86_64", |
|
"xorg-x11-server-utils.x86_64", |
|
"xorg-x11-xauth.x86_64", |
|
"xorg-x11-xinit.x86_64", |
|
"xorg-x11-xkb-utils.x86_64", |
|
"xz-libs.x86_64", |
|
"xz.x86_64", |
|
], |
|
'y' => [ |
|
"yajl.x86_64", |
|
"yum.noarch", |
|
"yum-utils.noarch", |
|
"zenity.x86_64", |
|
], |
|
z => [ |
|
"zlib.x86_64", |
|
"zlib-devel.x86_64", |
|
"zstd.x86_64", |
|
], |
|
}; |
|
|
|
# These packages can't be downloaded on RHEL Striker dashboads as they usually are not entitled to |
|
$anvil->data->{ha_packages} = { |
|
c => [ |
|
"clufter-bin.x86_64", |
|
"clufter-common.noarch", |
|
"corosync.x86_64", |
|
"corosynclib.x86_64", |
|
], |
|
l => [ |
|
"libknet1.x86_64", |
|
"libknet1-compress-bzip2-plugin.x86_64", |
|
"libknet1-compress-lz4-plugin.x86_64", |
|
"libknet1-compress-lzma-plugin.x86_64", |
|
"libknet1-compress-lzo2-plugin.x86_64", |
|
"libknet1-compress-plugins-all.x86_64", |
|
"libknet1-compress-zlib-plugin.x86_64", |
|
"libknet1-crypto-nss-plugin.x86_64", |
|
"libknet1-crypto-openssl-plugin.x86_64", |
|
"libknet1-crypto-plugins-all.x86_64", |
|
"libknet1-plugins-all.x86_64", |
|
"libnozzle1.x86_64", |
|
], |
|
p => [ |
|
"pacemaker.x86_64", |
|
"pacemaker-cli.x86_64", |
|
"pacemaker-cluster-libs.x86_64", |
|
"pacemaker-libs.x86_64", |
|
"pacemaker-schemas.noarch", |
|
"pcs.x86_64", |
|
"python3-clufter.noarch", |
|
], |
|
r => [ |
|
"resource-agents.x86_64", |
|
], |
|
}; |
|
|
|
|
|
my ($os_type, $os_arch) = $anvil->Get->os_type(); |
|
if ($os_type eq "rhel8") |
|
{ |
|
push @{$anvil->data->{packages}{r}}, "redhat-backgrounds.noarch"; |
|
push @{$anvil->data->{packages}{r}}, "redhat-indexhtml.noarch"; |
|
push @{$anvil->data->{packages}{r}}, "redhat-logos-httpd.noarch"; |
|
push @{$anvil->data->{packages}{r}}, "redhat-logos.x86_64"; |
|
push @{$anvil->data->{packages}{r}}, "redhat-release.x86_64"; |
|
} |
|
elsif ($os_type eq "centos8") |
|
{ |
|
push @{$anvil->data->{packages}{c}}, "centos-backgrounds.noarch"; |
|
push @{$anvil->data->{packages}{c}}, "centos-gpg-keys.noarch"; |
|
push @{$anvil->data->{packages}{c}}, "centos-indexhtml.noarch"; |
|
push @{$anvil->data->{packages}{c}}, "centos-logos-httpd.noarch"; |
|
push @{$anvil->data->{packages}{c}}, "centos-logos.x86_64"; |
|
push @{$anvil->data->{packages}{c}}, "centos-linux-release.noarch"; |
|
|
|
# While we're here, we will need to rename /var/www/html/rhel8 to /var/www/html/rhel8, as |
|
# 'centos8' and '/var/lib/tftpboot/rhel8' as 'centos8', as is used by anvil-striker-extra. |
|
foreach my $directory ("html", "tftpboot") |
|
{ |
|
my $source = $anvil->data->{path}{directories}{$directory}."/rhel8"; |
|
my $target = $anvil->data->{path}{directories}{$directory}."/centos8"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
directory => $directory, |
|
source => $source, |
|
target => $target, |
|
}}); |
|
|
|
if ((-e $anvil->data->{path}{directories}{$directory}."/rhel8") && (not -e $anvil->data->{path}{directories}{$directory}."/centos8")) |
|
{ |
|
my $shell_call = $anvil->data->{path}{exe}{mv}." ".$source." ".$target; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); |
|
|
|
my ($handle, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { handle => $handle, return_code => $return_code }}); |
|
if (-e $anvil->data->{path}{directories}{$directory}."/centos8") |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0475", variables => { |
|
source => $source, |
|
target => $target, |
|
}}); |
|
} |
|
else |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0116", variables => { |
|
source => $source, |
|
target => $target, |
|
}}); |
|
$anvil->nice_exit({exit_code => 12}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
update_progress($anvil, 5, "log_0241"); |
|
|
|
return(0); |
|
}
|
|
|