# Copyright (c) 2008 - 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::Preboot.pm # - provides general preboot implementation of the BootEnvironment API. # ----------------------------------------------------------------------------- package OpenSLX::BootEnvironment::PBS; use strict; use warnings; use base qw(OpenSLX::BootEnvironment::Base); use OpenSLX::MakeInitRamFS::Engine::PBS; use Clone qw(clone); use File::Basename; use File::Path; use Data::Dumper; use JSON; use HTTP::Request::Common; use LWP::UserAgent; use OpenSLX::Basics; use OpenSLX::ConfigDB qw(:support); use OpenSLX::Utils; sub initialize { my $self = shift; my $params = shift; return if !$self->SUPER::initialize($params); $self->{'original-path'} = "$openslxConfig{'public-path'}/pbs"; $self->{'target-path'} = "$openslxConfig{'public-path'}/pbs.new"; $self->{'requires-default-client-config'} = 0; # we do not need a default.tgz since there's always an explicit client 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 || []; my $prebootSystemInfo = clone($self->_pickSystemWithNewestKernel($systemInfos)); vlog( 0, _tr( "\nsend preboot information for client '%s' to pbs (%s)\n". " (image templates provided based of %s) ...", $client->{name}, $client->{attrs}->{preboot_server}, $prebootSystemInfo->{name} ) ); $self->_createPrebootStuff($client, $prebootSystemInfo); my $kernel = "$self->{'target-path'}/imagebase/vmlinuz"; my $initramfs = "$self->{'target-path'}/imagebase/initramfs"; my $kernel_md5 = qx/md5sum $kernel | awk '{print \$1}'/; my $initramfs_md5 = qx/md5sum $initramfs | awk '{print \$1}'/; my $data_json = to_json({ 'slxinfo' => qx/slxversion/, 'kernel' => basename($prebootSystemInfo->{'kernel-file'}), 'kernel_md5' => trim($kernel_md5), 'initramfs_md5' => trim($initramfs_md5), 'systems' => $systemInfos }); my $ua = LWP::UserAgent->new; my $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/sync', [data => $data_json]); if ($res->is_success) { my $resData = from_json($res->content); if ($resData->{'getKernel'} eq 'fresh') { $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/addkernel', ['kernel' => basename($prebootSystemInfo->{'kernel-file'}), 'kernelFile' => ["$self->{'target-path'}/imagebase/vmlinuz"], 'initramfsFile' => ["$self->{'target-path'}/imagebase/initramfs"], ], 'Content_Type' => 'form-data' ); print Dumper($res->content); } else { if ($resData->{'getKernel'} eq 'update') { $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/updatekernel', ['kernel' => basename($prebootSystemInfo->{'kernel-file'}), 'kernelFile' => ["$self->{'target-path'}/imagebase/vmlinuz"], ], 'Content_Type' => 'form-data' ); print Dumper($res->content); } else { # do nothing } if ($resData->{'getInitramfs'} eq 'update') { $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/updateinitramfs', ['kernel' => basename($prebootSystemInfo->{'kernel-file'}), 'initramfsFile' => ["$self->{'target-path'}/imagebase/initramfs"], ], 'Content_Type' => 'form-data' ); print Dumper($res->content); } else { # do nothing } } } else { vlog(0, 'communication with pbs failed.. please check and rerun..'); } return 1; } sub _createPrebootStuff { my $self = shift; my $client = shift; my $info = shift; my $prebootClass = instantiateClass( "OpenSLX::BootEnvironment::Preboot::Base" ); my $imagebase = "$self->{'target-path'}/imagebase"; $prebootClass->initialize($self); $client->{attrs}->{boot_uri} = $client->{attrs}->{preboot_server}; mkpath("$imagebase"); $self->_makePBSInitRamFS($info, "$imagebase/initramfs", $client); my $kernelFile = $info->{'kernel-file'}; my $kernelName = basename($kernelFile); slxsystem(qq{cp -p "$kernelFile" "$imagebase/vmlinuz"}) unless $self->{'dry-run'}; return 1; } sub _pickSystemWithNewestKernel { my $self = shift; my $systemInfos = shift; my $systemWithNewestKernel; my $newestKernelFileSortKey = ''; foreach my $system (@$systemInfos) { next unless $system->{'kernel-file'} =~ m{ (?:vmlinuz|x86)-(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?-(\d+(?:\.\d+)?) }x; my $sortKey = sprintf("%02d.%02d.%02d.%02d-%2.1f", $1, $2, $3, $4||0, $5); if ($newestKernelFileSortKey lt $sortKey) { $systemWithNewestKernel = $system; $newestKernelFileSortKey = $sortKey; } } if (!defined $systemWithNewestKernel) { die _tr("unable to pick a system to be used for preboot!"); } return $systemWithNewestKernel; } sub _makePBSInitRamFS { my $self = shift; my $info = shift; my $initramfs = shift; my $client = shift; my $vendorOS = $info->{'vendor-os'}; my $kernelFile = basename(followLink($info->{'kernel-file'})); my $attrs = clone($info->{attrs} || {}); my $bootURI = $client->{attrs}->{boot_uri}; if (!$bootURI) { die _tr("client $client->{name} needs an URI in attribute 'boot_uri' to be used for preboot!"); } chomp(my $slxVersion = qx{slxversion}); my $params = { 'attrs' => $attrs, 'export-name' => undef, 'export-uri' => undef, 'initramfs' => $initramfs, 'kernel-params' => [ split ' ', ($info->{attrs}->{kernel_params} || '') ], 'kernel-version' => $kernelFile =~ m[-(.+)$] ? $1 : '', 'plugins' => '', 'root-path' => "$openslxConfig{'private-path'}/stage1/$vendorOS->{name}", 'slx-version' => $slxVersion, 'system-name' => $info->{name}, 'preboot-id' => $client->{name}, 'boot-uri' => $bootURI, }; # TODO: make debug-level an explicit attribute, it's used in many places! my $kernelParams = $info->{attrs}->{kernel_params} || ''; if ($kernelParams =~ m{debug(?:=(\d+))?}) { my $debugLevel = defined $1 ? $1 : '1'; $params->{'debug-level'} = $debugLevel; } my $makeInitRamFSEngine = OpenSLX::MakeInitRamFS::Engine::PBS->new($params); $makeInitRamFSEngine->execute($self->{'dry-run'}); # copy back kernel-params, as they might have been changed (by plugins) $info->{attrs}->{kernel_params} = join ' ', $makeInitRamFSEngine->kernelParams(); return; } 1;