#! /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=$info->{'export-uri'} file"; 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(); }