#! /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 10
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 $clientConfigPath = "$openslxConfig{'private-path'}/config";
if (!-d $clientConfigPath) {
die _tr("Unable to access client-config-path '%s'!", $clientConfigPath);
}
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-path'}/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 = "$clientConfigPath/default";
if (-d $defaultConfigPath) {
system("cp -r $defaultConfigPath/* $targetPath");
}
# now pour system-specific configuration on top (if any):
my $systemConfigPath = "$clientConfigPath/$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";
my $pxeConfigPath = "$exportPath/pxe/pxelinux.cfg";
if (!-e "$pxePath/pxelinux.0") {
my $pxelinux0Path
= "$openslxConfig{'share-path'}/tftpboot/pxelinux.0";
system(qq[cp -a "$pxelinux0Path" $pxePath/]);
}
if (!-e "$pxePath/menu.c32") {
my $menuc32Path
= "$openslxConfig{'share-path'}/tftpboot/menu.c32";
system(qq[cp -a "$menuc32Path" $pxePath/]);
}
my @clients = fetchClientsByFilter($openslxDB);
foreach my $client (@clients) {
my $externalClientID = externalIDForClient($client);
my $pxeFile = "$pxeConfigPath/$externalClientID";
my $clientAppend = $client->{kernel_params};
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) {
my @infos = aggregatedSystemFileInfosOfSystem($openslxDB, $system);
foreach my $info (@infos) {
my $extSysID = externalIDForSystem($info);
my $append = $system->{kernel_params};
$append .= " initrd=$extSysID/initialramfs";
$append .= " $clientAppend";
$append .= " rootfs=nfs:///srv/openslx/nfsroot/suse-10.0";
print PXE "LABEL openslx-$extSysID\n";
# print PXE "\tMENU DEFAULT\n";
print PXE "\tMENU LABEL ^$info->{label}\n";
print PXE "\tKERNEL $extSysID/kernel\n";
print PXE "\tAPPEND $append\n";
print PXE "\tIPAPPEND 1\n";
}
}
close(PXE);
}
}
sub generateInitalRamFS
{
my $setup = shift;
my $vendorOS = shift;
my $pxeSysPath = shift;
vlog 1, _tr('generating initialramfs %s/initialramfs', $pxeSysPath);
my $cmd = "$openslxConfig{'bin-path'}/slxmkramfs ";
if ($setup->{ramfs_use_glibc}) {
$cmd .= '-g ';
}
if ($setup->{ramfs_use_busybox}) {
$cmd .= '-b ';
}
my $debugLevel = $setup->{ramfs_debug_level};
if ($debugLevel) {
$cmd .= qq[-d $debugLevel ];
}
if (length($setup->{ramfs_nicmods}) > 0) {
$cmd .= qq[-n "$setup->{ramfs_nicmods}" ];
}
if (length($setup->{ramfs_fsmods}) > 0) {
$cmd .= qq[-f "$setup->{ramfs_fsmods}" ];
}
my $rootPath
= "$openslxConfig{'private-path'}/stage1/$vendorOS->{path}";
$cmd .= "-i $pxeSysPath/initialramfs -r $rootPath";
$ENV{'SLX_PRIVATE_PATH'} = $openslxConfig{'private-path'};
$ENV{'SLX_PUBLIC_PATH'} = $openslxConfig{'public-path'};
$ENV{'SLX_SHARE_PATH'} = $openslxConfig{'share-path'};
vlog 2, _tr('executing %s', $cmd);
system($cmd) unless $dryRun;
}
sub writeSystemPXEFiles
{
my $system = shift;
my $pxePath = "$exportPath/pxe";
my $vendorOS = fetchVendorOSesByID($openslxDB, $system->{vendor_os_id});
my @infos = aggregatedSystemFileInfosOfSystem($openslxDB, $system);
foreach my $info (@infos) {
my $kernelFile = $info->{'kernel-file'};
my $extSysID = externalIDForSystem($info);
my $pxeSysPath = "$pxePath/$extSysID";
if (-e $pxeSysPath) {
die _tr('PXE-system %s already exists!', $pxeSysPath);
}
mkdir $pxeSysPath;
vlog 1, _tr('copying kernel %s to %s/kernel', $kernelFile, $pxeSysPath);
system(qq[cp -a "$kernelFile" $pxeSysPath/kernel]) unless $dryRun;
generateInitalRamFS($info, $vendorOS, $pxeSysPath);
}
}
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();
}