#! /usr/bin/perl
use strict;
# add the folder this script lives in to perl's search path for modules:
use FindBin;
use lib $FindBin::Bin;
use Fcntl qw(:DEFAULT :flock);
use File::Basename;
use Getopt::Long qw(:config pass_through);
use OpenSLX::Basics;
use OpenSLX::ConfigDB qw(:access :aggregation :support);
my $pxeConfigDefaultTemplate = q[# generated by openslx
NOESCAPE 0
PROMPT 0
TIMEOUT 100
DEFAULT menu.c32
IMPLICIT 1
ALLOWOPTIONS 1
MENU TITLE What would you like to do? (use cursor to select)
MENU MASTER PASSWD secret
];
my (
$dryRun,
# dryRun won't touch any file
$systemConfCount,
# number of system configurations written
$clientSystemConfCount,
# number of (system-specific) client configurations written
);
GetOptions(
'dry-run' => \$dryRun
# dry-run doesn't write anything, just prints statistic about what
# would have been written
);
openslxInit();
my $openslxDB = connectConfigDB();
my $configPath = "$openslxConfig{'private-basepath'}/config";
if (!-d $configPath) {
die _tr("Unable to access config-path '%s'!", $configPath);
}
my $tempPath = "$openslxConfig{'temp-basepath'}/oslx-demuxer";
if (!$dryRun) {
mkdir $tempPath;
if (!-d $tempPath) {
die _tr("Unable to create or access temp-path '%s'!", $tempPath);
}
}
my $exportPath = "$openslxConfig{'public-basepath'}/tftpboot";
if (!$dryRun) {
system("rm -rf $exportPath/client-conf/* $exportPath/pxe/*");
system("mkdir -p $exportPath/client-conf $exportPath/pxe/pxelinux.cfg");
if (!-d $exportPath) {
die _tr("Unable to create or access export-path '%s'!", $exportPath);
}
}
my $lockFile = "$exportPath/config-demuxer.lock";
lockScript($lockFile);
writeConfigurations();
my $wr = ($dryRun ? "would have written" : "wrote");
print "$wr $systemConfCount systems and $clientSystemConfCount client-configurations to $exportPath/client-conf\n";
disconnectConfigDB($openslxDB);
system("rm -rf $tempPath") unless $dryRun || length($tempPath) < 12;
unlockScript($lockFile);
exit;
################################################################################
###
################################################################################
sub lockScript
{
my $lockFile = shift;
return if $dryRun;
# use a lock-file to singularize execution of this script:
if (-e $lockFile) {
my $ctime = (stat($lockFile))[10];
my $now = time();
if ($now - $ctime > 15*60) {
# existing lock file is older than 15 minutes, wipe it:
unlink $lockFile;
}
}
sysopen(LOCKFILE, $lockFile, O_RDWR|O_CREAT|O_EXCL)
or die _tr(qq[Lock-file <%s> exists, script is already running.\nPlease remove the logfile and try again if you are sure that no one else is executing this script.], $lockFile);
}
sub unlockScript
{
my $lockFile = shift;
return if $dryRun;
unlink $lockFile;
}
sub writeAttributesToFile
{
my $attrHash = shift;
my $fileName = shift;
return if $dryRun;
open(ATTRS, "> $fileName") or die "unable to write to $fileName";
my @attrs = sort grep { isAttribute($_) } keys %$attrHash;
foreach my $attr (@attrs) {
if (length($attrHash->{$attr}) > 0) {
my $externalAttrName = externalAttrName($attr);
print ATTRS "$externalAttrName = $attrHash->{$attr}\n";
}
}
close(ATTRS);
}
sub copyExternalSystemConfig
{ # copies local configuration extensions of given system from private
# config folder (var/lib/openslx/config/...) into a temporary folder
my $systemName = shift;
my $targetPath = shift;
return if $dryRun;
if ($targetPath !~ m[$tempPath]) {
die _tr("system-error: illegal target-path <%s>!", $targetPath);
}
system("rm -rf $targetPath");
mkdir $targetPath;
# first copy default files...
my $defaultConfigPath = "$configPath/default";
if (-d $defaultConfigPath) {
system("cp -r $defaultConfigPath/* $targetPath");
}
# now pour system-specific configuration on top (if any):
my $systemConfigPath = "$configPath/$systemName";
if (-d $systemConfigPath) {
system("cp -r $systemConfigPath/* $targetPath");
}
}
sub createTarOfPath
{
my $buildPath = shift;
my $tarName = shift;
my $destinationPath = shift;
my $tarFile = "$destinationPath/$tarName";
vlog 1, _tr('creating tar %s', $tarFile);
return if $dryRun;
mkdir $destinationPath;
my $tarCmd = "cd $buildPath && tar czf $tarFile *";
if (system("$tarCmd") != 0) {
die _tr("unable to execute shell-command:\n\t%s \n\t($!)", $tarCmd);
}
}
################################################################################
###
################################################################################
sub writePXEMenus
{
my $pxePath = "$exportPath/pxe/pxelinux.cfg";
if (!-e "$exportPath/pxe/pxelinux.0") {
my $pxelinux0Path
= "$openslxConfig{'shared-basepath'}/tftpboot/pxelinux.0";
system(qq[cp -a "$pxelinux0Path" $exportPath/pxe/]);
}
if (!-e "$exportPath/pxe/menu.c32") {
my $menuc32Path
= "$openslxConfig{'shared-basepath'}/tftpboot/menu.c32";
system(qq[cp -a "$menuc32Path" $exportPath/pxe/]);
}
my @clients = fetchClientsByFilter($openslxDB);
foreach my $client (@clients) {
my $externalClientID = externalIDForClient($client);
my $pxeFile = "$pxePath/$externalClientID";
vlog 1, _tr("writing PXE-file %s", $pxeFile);
open(PXE, "> $pxeFile") or die "unable to write to $pxeFile";
print PXE $pxeConfigDefaultTemplate;
my @systemIDs = aggregatedSystemIDsOfClient($openslxDB, $client);
my @systems = fetchSystemsByID($openslxDB, \@systemIDs);
foreach my $system (@systems) {
print PXE "LABEL openslx-$system->{name}\n";
# print PXE "\tMENU DEFAULT\n";
print PXE "\tMENU LABEL ^$system->{label}\n";
my $kernel = basename($system->{kernel});
print PXE "\tKERNEL $kernel\n";
print PXE "\tAPPEND $system->{kernel_params}\n";
print PXE "\tIPAPPEND 1\n";
}
close(PXE);
}
}
sub writeSystemPXEFiles
{
my $system = shift;
my $pxePath = "$exportPath/pxe";
my @kernelFiles = aggregatedKernelFilesOfSystem($openslxDB, $system);
foreach my $kernelFile (@kernelFiles) {
vlog 1, _tr('copying kernel %s to %s/', $kernelFile, $pxePath);
system(qq[cp -a "$kernelFile" $pxePath/]) unless $dryRun;
}
# foreach my $initramFile (aggregatedInitramFilesOfSystem($openslxDB, $system)) {
# vlog 1, _tr('copying initramfs %s to %s/', $initramFile, $pxePath);
# system(qq[cp -a "$initramFile" $pxePath/]) unless $dryRun;
# }
}
sub writeClientConfigurationsForSystem
{
my $system = shift;
my $buildPath = shift;
my $attrFile = shift;
my @clientIDs = aggregatedClientIDsOfSystem($openslxDB, $system);
my @clients = fetchClientsByID($openslxDB, \@clientIDs);
foreach my $client (@clients) {
vlog 2, _tr("exporting client %d:%s", $client->{id}, $client->{name});
$clientSystemConfCount++;
# merge configurations of client, it's groups, default client and
# system and write the resulting attributes to a configuration file:
mergeDefaultAndGroupAttributesIntoClient($openslxDB, $client);
mergeAttributes($client, $system);
writeAttributesToFile($client, $attrFile);
# create tar containing external system configuration
# and client attribute file:
my $externalClientID = externalIDForClient($client);
my $externalSystemID = externalIDForSystem($system);
createTarOfPath($buildPath, "${externalClientID}.tgz",
"$exportPath/client-conf/$externalSystemID");
}
}
sub writeSystemConfigurations
{
my @systems = fetchSystemsByFilter($openslxDB);
foreach my $system (@systems) {
next unless $system->{id} > 0;
vlog 2, _tr('exporting system %d:%s', $system->{id}, $system->{name});
$systemConfCount++;
my $buildPath = "$tempPath/build";
copyExternalSystemConfig($system->{name}, $buildPath);
my $attrFile = "$buildPath/initramfs/machine-setup";
mergeDefaultAttributesIntoSystem($openslxDB, $system);
writeAttributesToFile($system, $attrFile);
my $externalSystemID = externalIDForSystem($system);
my $systemPath = "$exportPath/client-conf/$externalSystemID";
createTarOfPath($buildPath, "default.tgz", $systemPath);
writeSystemPXEFiles($system);
writeClientConfigurationsForSystem($system, $buildPath, $attrFile);
system("rm -rf $buildPath") unless $dryRun;
}
}
sub writeConfigurations
{
$systemConfCount = $clientSystemConfCount = 0;
writeSystemConfigurations();
writePXEMenus();
}