summaryrefslogblamecommitdiffstats
path: root/boot-env/OpenSLX/BootEnvironment/PXE.pm
blob: 3b96796ae0c04722aeed7b4ece65b9ae94903970 (plain) (tree)
1
                                         
























                                                                               









                                                                            

                                                  








                                                       






                                 



                                                       



                                                          
                                                                      
                                                          

                                                  
                               
                                      









                                                                            
                                   




                                                                           
                                                           

                              
                                        







                                                                                      
                                                            
                                                               

                                                               
                                                          
                                                                       
                                           
                                       


                                                          







                                                                     











                                                                           

                                                                        









                                                              





                                                                
                       

                                                                         
 
                           

                                                   
                                                      
                                                 




                              

     


















                                                                                
 
                                       
            






                                                                       

                       



                                                 
                                                       
                                                                       

         






                                                
                                                 


















                                                                              




                                           













                                                                 


                                                                            








                                                
  
# Copyright (c) 2008..2009 - OpenSLX GmbH
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# BootEnvironment::PXE.pm
#    - provides PXE-specific implementation of the BootEnvironment API.
# -----------------------------------------------------------------------------
package OpenSLX::BootEnvironment::PXE;

use strict;
use warnings;

use base qw(OpenSLX::BootEnvironment::Base);

use File::Basename;
use File::Path;

use OpenSLX::Basics;
use OpenSLX::Utils;

sub initialize
{
    my $self   = shift;
    my $params = shift;
    
    return if !$self->SUPER::initialize($params);

    $self->{'original-path'} = "$openslxConfig{'public-path'}/tftpboot";
    $self->{'target-path'}   = "$openslxConfig{'public-path'}/tftpboot.new";

    $self->{'requires-default-client-config'} = 1;

    if (!$self->{'dry-run'}) {
        mkpath([$self->{'original-path'}]);
        rmtree($self->{'target-path'});
        mkpath("$self->{'target-path'}/client-config");
    }

    return 1;
}

sub writeBootloaderMenuFor
{
    my $self             = shift;
    my $client           = shift;
    my $externalClientID = shift;
    my $systemInfos      = shift;

    $self->_prepareBootloaderConfigFolder() 
        unless $self->{preparedBootloaderConfigFolder};

    my $pxePath       = $self->{'target-path'};
    my $pxeConfigPath = "$pxePath/pxelinux.cfg";

    my $pxeConfig    = $self->_getTemplate();
    my $pxeFile      = "$pxeConfigPath/$externalClientID";
    my $clientAppend = $client->{attrs}->{kernel_params_client} || '';
    my $bootURI      = $client->{attrs}->{boot_uri} || '';
    vlog(1, _tr("writing PXE-file %s", $pxeFile));

    # set label for each system
    foreach my $info (@$systemInfos) {
        my $label = $info->{label} || '';
        if (!length($label) || $label eq $info->{name}) {
            if ($info->{name} =~ m{^(.+)::(.+)$}) {
                my $system = $1;
                my $exportType = $2;
                $label = $system . ' ' x (40-length($system)) . $exportType;
            } else {
                $label = $info->{name};
            }
        }
        $info->{pxeLabel} = $label;
    }
    my $slxLabels = '';
    foreach my $info (sort { $a->{label} cmp $b->{label} } @$systemInfos) {
        my $vendorOSName = $info->{'vendor-os'}->{name};
        my $kernelName   = basename($info->{'kernel-file'});
        my $append       = $info->{attrs}->{kernel_params};
        my $pxePrefix    = '';
        my $tftpPrefix   = '';
        $info->{'pxe_prefix_ip'} ||= '';
        
        # pxe_prefix_ip set and looks like a ip
        if ($info->{'pxe_prefix_ip'} =~ m/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
        	$pxePrefix = "$info->{'pxe_prefix_ip'}::";
        	$tftpPrefix = "tftp://$info->{'pxe_prefix_ip'}" if ! length($bootURI);
        }
        
        $append .= " initrd=$pxePrefix$vendorOSName/$info->{'initramfs-name'}";
        $append .= " file=$bootURI"     if length($bootURI);
        $append .= " file=$tftpPrefix"  if length($tftpPrefix);
        $append .= " $clientAppend";
        $slxLabels .= "LABEL openslx-$info->{'external-id'}\n";
        $slxLabels .= "\tMENU LABEL ^$info->{pxeLabel}\n";
        $slxLabels .= "\tKERNEL $pxePrefix$vendorOSName/$kernelName\n";
        $slxLabels .= "\tAPPEND $append\n";
        $slxLabels .= "\tIPAPPEND 3\n";
        my $helpText = $info->{description} || '';
        if (length($helpText)) {
            # make sure that text matches the given margin
            my $menuMargin;
            while ($pxeConfig =~ m{^\s*MENU MARGIN (\S+?)\s*$}gims) {
                chomp($menuMargin = $1);
            }
            my $margin
                = defined $menuMargin
                    ? "$menuMargin"
                    : "0";
            my $marginAsText = ' ' x $margin;
            $helpText =~ s{^}{$marginAsText}gms;
            $slxLabels .= "\tTEXT HELP\n$helpText\n\tENDTEXT\n";
        }
    }
    # now add the slx-labels (inline or appended) and write the config file
    if (!($pxeConfig =~ s{\@\@\@SLX_LABELS\@\@\@}{$slxLabels})) {
        $pxeConfig .= $slxLabels;
    }

    # PXE uses 'cp850' (codepage 850) but our string is in utf-8, we have
    # to convert in order to avoid showing gibberish on the client side...
    spitFile($pxeFile, $pxeConfig, { 'io-layer' => 'encoding(cp850)' } )
        unless $self->{'dry-run'};

    return 1;
}

sub _getTemplate
{
    my $self = shift;
    
    return $self->{'pxe-template'} if $self->{'pxe-template'};
    
    my ($sec, $min, $hour, $day, $mon, $year) = (localtime);
    $mon++;
    $year += 1900;
    my $callDate = sprintf('%04d-%02d-%02d', $year, $mon, $day);
    my $callTime = sprintf('%02d:%02d:%02d', $hour, $min, $sec);
    
    # generate PXE-Menu
    my $pxeTemplate =
        "# generated by slxconfig-demuxer (on $callDate at $callTime)\n";

    # first check for theme
    my $basePath   = $openslxConfig{'base-path'};
    my $configPath = $openslxConfig{'config-path'};
    my $tftpServer = $openslxConfig{'tftp-server-ip'};
    my $pxeTheme   = $openslxConfig{'pxe-theme'};
    if (defined $tftpServer) {
        $tftpServer .= "::"
    }
    else {
        $tftpServer = "";
    }

    # let user stuff in config path win over our stuff in base path
    my $pxeThemePath;
    my $pxeThemeInConfig
        = "$configPath/boot-env/pxe/themes/${pxeTheme}";
    my $pxeThemeInBase
        = "$basePath/share/boot-env/pxe/themes/${pxeTheme}";
    if (-e "$pxeThemeInConfig/theme.conf") {
        $pxeThemePath = $pxeThemeInConfig;
    }
    else {
        if (-e "$pxeThemeInBase/theme.conf") {
            $pxeThemePath = $pxeThemeInBase;
        }
    }
    # include theme specific stuff from above
    if (defined $pxeThemePath) {
        $pxeTemplate .= "\n# theme specific configuration from $pxeThemePath\n";
        $pxeTemplate .= slurpFile("$pxeThemePath/theme.conf");
    }

    # copy background picture if exists
    my $pic;
    if (defined $pxeTheme) {
        while ($pxeTemplate =~ m{^\s*MENU BACKGROUND (\S+?)\s*$}gims) {
            chomp($pic = $1);
        }
        my $picPrefix = $tftpServer;
        $picPrefix .= $pic;
        $pxeTemplate =~ s,$pic,$picPrefix,g;
    }
    if (defined $pic) {
        my $pxeBackground = "$pxeThemePath/$pic";
        # vesamenu.c32 if $pic
        $pxeTemplate .= "\nDEFAULT $tftpServer";
        $pxeTemplate .= "vesamenu.c32\n";
        if (-e $pxeBackground && !$self->{'dry-run'}) {
            slxsystem(qq[cp "$pxeBackground" $self->{'target-path'}/]);
        }
    }
    else {
        # we only need menu.c32 if no $pic
        $pxeTemplate .= "\nDEFAULT $tftpServer";
        $pxeTemplate .= "menu.c32\n";
    }

    # include defaults
    $pxeTemplate .= "\n# static configuration\n";
    $pxeTemplate .= "NOESCAPE 0\n";
    $pxeTemplate .= "PROMPT 0\n";

    # include slxsettings
    $pxeTemplate .= "\n# slxsettings configuration\n";
    $pxeTemplate .= "TIMEOUT $openslxConfig{'pxe-timeout'}\n" || "";
    $pxeTemplate .= "TOTALTIMEOUT $openslxConfig{'pxe-totaltimeout'}\n" || "";
    $pxeTemplate .= "MENU MASTER PASSWD $openslxConfig{'pxe-passwd'}\n" || "";
    $pxeTemplate .= "MENU TITLE $openslxConfig{'pxe-title'}\n" || "";

    # fetch PXE-include, if exists (overwrite existing definitions)
    my $pxeIncludeFile
        = "$openslxConfig{'config-path'}/boot-env/pxe/menu-include";
    if (-e $pxeIncludeFile) {
        $pxeTemplate .= "\n# configuration from include $pxeIncludeFile\n";
        $pxeTemplate .= slurpFile($pxeIncludeFile);
    }

    $pxeTemplate .= "\n# slxsystems:\n";
    $self->{'pxe-template'} = $pxeTemplate;
    
    return $pxeTemplate;
}
   
sub _prepareBootloaderConfigFolder
{
    my $self = shift;
    
    my $basePath      = $openslxConfig{'base-path'};
    my $pxePath       = $self->{'target-path'};
    my $pxeConfigPath = "$pxePath/pxelinux.cfg";

    if (!$self->{'dry-run'}) {
        rmtree($pxeConfigPath);
        mkpath($pxeConfigPath);

        for my $file ('pxelinux.0', 'menu.c32', 'vesamenu.c32') {
            if (!-e "$pxePath/$file") {
                slxsystem(
                    qq[cp -p "$basePath/share/boot-env/pxe/$file" $pxePath/]
                );
            }
        }
    }
    
    $self->{preparedBootloaderConfigFolder} = 1;

    return 1;
}

1;