From 416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5 Mon Sep 17 00:00:00 2001 From: Sebastian Schmelzer Date: Thu, 2 Sep 2010 17:50:49 +0200 Subject: change dir structure --- src/installer/OpenSLX/OSSetup/Distro/Any_Clone.pm | 31 + src/installer/OpenSLX/OSSetup/Distro/Base.pm | 371 ++++ src/installer/OpenSLX/OSSetup/Distro/Debian.pm | 135 ++ src/installer/OpenSLX/OSSetup/Distro/Debian_3_1.pm | 74 + src/installer/OpenSLX/OSSetup/Distro/Fedora.pm | 48 + src/installer/OpenSLX/OSSetup/Distro/Gentoo.pm | 33 + src/installer/OpenSLX/OSSetup/Distro/Scilin.pm | 48 + src/installer/OpenSLX/OSSetup/Distro/Suse.pm | 98 + src/installer/OpenSLX/OSSetup/Distro/Ubuntu.pm | 119 ++ src/installer/OpenSLX/OSSetup/Engine.pm | 1929 ++++++++++++++++++++ src/installer/OpenSLX/OSSetup/MetaPackager/Base.pm | 98 + src/installer/OpenSLX/OSSetup/MetaPackager/apt.pm | 142 ++ .../OpenSLX/OSSetup/MetaPackager/smart.pm | 127 ++ src/installer/OpenSLX/OSSetup/MetaPackager/yum.pm | 117 ++ .../OpenSLX/OSSetup/MetaPackager/zypper.pm | 122 ++ src/installer/OpenSLX/OSSetup/Packager/Base.pm | 98 + src/installer/OpenSLX/OSSetup/Packager/dpkg.pm | 102 ++ src/installer/OpenSLX/OSSetup/Packager/rpm.pm | 89 + 18 files changed, 3781 insertions(+) create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Any_Clone.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Base.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Debian.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Debian_3_1.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Fedora.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Gentoo.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Scilin.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Suse.pm create mode 100644 src/installer/OpenSLX/OSSetup/Distro/Ubuntu.pm create mode 100644 src/installer/OpenSLX/OSSetup/Engine.pm create mode 100644 src/installer/OpenSLX/OSSetup/MetaPackager/Base.pm create mode 100644 src/installer/OpenSLX/OSSetup/MetaPackager/apt.pm create mode 100644 src/installer/OpenSLX/OSSetup/MetaPackager/smart.pm create mode 100644 src/installer/OpenSLX/OSSetup/MetaPackager/yum.pm create mode 100644 src/installer/OpenSLX/OSSetup/MetaPackager/zypper.pm create mode 100644 src/installer/OpenSLX/OSSetup/Packager/Base.pm create mode 100644 src/installer/OpenSLX/OSSetup/Packager/dpkg.pm create mode 100644 src/installer/OpenSLX/OSSetup/Packager/rpm.pm (limited to 'src/installer/OpenSLX/OSSetup') diff --git a/src/installer/OpenSLX/OSSetup/Distro/Any_Clone.pm b/src/installer/OpenSLX/OSSetup/Distro/Any_Clone.pm new file mode 100644 index 00000000..43385a29 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Any_Clone.pm @@ -0,0 +1,31 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Any_Clone.pm +# - provides generic clone-only overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Any_Clone; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/Distro/Base.pm b/src/installer/OpenSLX/OSSetup/Distro/Base.pm new file mode 100644 index 00000000..c356e6d9 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Base.pm @@ -0,0 +1,371 @@ +# Copyright (c) 2006..2010 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Base.pm +# - provides base implementation of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Base; + +use strict; +use warnings; + +our $VERSION = 1.01; # API-version . implementation-version + +use Fcntl qw(:DEFAULT :flock); +use File::Basename; +use File::Path; +use Scalar::Util qw( weaken ); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + confess "Creating OpenSLX::OSSetup::System::Base-objects directly makes no sense!"; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->{'engine'} = $engine; + weaken($self->{'engine'}); + # avoid circular reference between distro and its engine + + if ($engine->{'distro-name'} =~ m[x86_64]) { + # be careful to only try installing 64-bit systems if actually + # running on a 64-bit host, as otherwise we are going to fail later, + # anyway: + my $arch = `uname -m`; + if ($?) { + die _tr("unable to determine architecture of host system (%s)\n", $!); + } + if ($arch !~ m[x86_64]) { + die _tr("you can't install a 64-bit system on a 32-bit host, sorry!\n"); + } + } + + $self->{'stage1a-binaries'} = { + "$openslxConfig{'base-path'}/share/busybox/busybox" => 'bin', + }; + + $self->{'stage1b-faked-files'} = [ + '/etc/mtab', + ]; + + $self->{'stage1c-faked-files'} = [ + ]; + + $self->{'clone-filter'} = " + + /var + - /var/tmp/* + - /var/spool/* + - /var/cache/apt/archives/*.deb + - /var/cache/apt/archives/lock + - /var/cache/apt/archives/partial/* + + /var/cache/apt/archives/partial + - /var/tmp/* + + /var/tmp/apt + - /var/opt/openslx + - /var/lib/vmware + - /var/lib/ntp/* + - /var/run/* + + /var/run/screen + - /var/log/* + + /var/log/apt + - /usr/lib/vmware/modules/* + + /usr + - /tmp/* + + /tmp + - /sys/* + + /sys + + /sbin + - /root/* + + /root + - /proc/* + + /proc + - /opt/openslx + + /opt + - /media/* + + /media + - /mnt/* + + /mnt + + /lib64 + - /lib/ld-uClibc* + + /lib + - /home/* + + /home + - /etc/vmware/* + + /etc/vmware + - /etc/vmware-installer + - /etc/grub* + - /etc/shadow* + - /etc/samba/secrets.tdb + - /etc/resolv.conf.* + - /etc/opt/openslx + + /etc/opt/openslx + - /etc/exports* + - /etc/X11/xorg.* + - /etc/X11/XF86* + + /etc + - /dev/* + + /dev + + /boot + + /bin + - /* + - .svn + - .git + - .*.cmd + - *~ + - *lost+found* + - *.old + - *.bak + "; + + return; +} + +sub fixPrerequiredFiles +{ +} + +sub startSession +{ + my $self = shift; + my $osDir = shift; + + # setup a fixed locale environment to avoid warnings about unset locales + # (like for instance shown by apt-get) + $ENV{LC_ALL} = 'POSIX'; + + # ensure that a couple of important devices exist + my %devInfo = ( + mem => { type => 'c', major => '1', minor => '1' }, + null => { type => 'c', major => '1', minor => '3' }, + zero => { type => 'c', major => '1', minor => '5' }, + random => { type => 'c', major => '1', minor => '8' }, + urandom => { type => 'c', major => '1', minor => '9' }, + kmsg => { type => 'c', major => '1', minor => '11' }, + tty => { type => 'c', major => '5', minor => '0' }, + console => { type => 'c', major => '5', minor => '1' }, + ptmx => { type => 'c', major => '5', minor => '2' }, + ); + if (!-e "$osDir/dev" && !mkpath("$osDir/dev")) { + die _tr("unable to create folder '%s' (%s)\n", "$osDir/dev", $!); + } + foreach my $dev (keys %devInfo) { + my $info = $devInfo{$dev}; + if (!-e "$osDir//dev/$dev") { + if (slxsystem( + "mknod $osDir//dev/$dev $info->{type} $info->{major} $info->{minor}" + )) { + croak(_tr("unable to create dev-node '%s'! (%s)", $dev, $!)); + } + } + } + + # enter chroot jail + chrootInto($osDir); + $ENV{PATH} = join(':', @{$self->getDefaultPathList()}); + + # mount /proc (if we have 'mount' available) + if (qx{which mount 2>/dev/null}) { + if (!-e '/proc' && !mkpath('/proc')) { + die _tr("unable to create folder '%s' (%s)\n", "$osDir/proc", $!); + } + if (slxsystem("mount -t proc proc '/proc'")) { + warn _tr("unable to mount '%s' (%s)\n", "$osDir/proc", $!); + } + if (!-e '/dev/pts' && !mkpath('/dev/pts')) { + die _tr("unable to create folder '%s' (%s)\n", "$osDir/dev/pts", $!); + } + if (slxsystem("mount -t devpts devpts '/dev/pts'")) { + warn _tr("unable to mount '%s' (%s)\n", "$osDir/dev/pts", $!); + } + } + + return 1; +} + +sub finishSession +{ + my $self = shift; + + # umount /proc, /dev/pts (if we have 'umount' available) + if (qx{which umount 2>/dev/null}) { + if (slxsystem("umount /proc")) { + warn _tr("unable to umount '%s' (%s)\n", "/proc", $!); + } + if (slxsystem("umount /dev/pts")) { + warn _tr("unable to umount '%s' (%s)\n", "/dev/pts", $!); + } + } + + return 1; +} + +sub getDefaultPathList +{ + my $self = shift; + + return [ qw( + /sbin + /usr/sbin + /usr/local/sbin + /usr/local/bin + /usr/bin + /bin + /usr/bin/X11 + /usr/X11R6/bin + /opt/kde3/bin + /opt/gnome/bin + ) ]; +} + +sub updateDistroConfig +{ + if (slxsystem("ldconfig")) { + die _tr("unable to run ldconfig (%s)", $!); + } +} + +sub pickKernelFile +{ + my $self = shift; + my $kernelPath = shift; + + my $newestKernelFile; + my $newestKernelFileSortKey = ''; + my $kernelPattern = '{vmlinuz,kernel-genkernel-x86}-*'; + foreach my $kernelFile (glob("$kernelPath/$kernelPattern")) { + next unless $kernelFile =~ 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) { + $newestKernelFile = $kernelFile; + $newestKernelFileSortKey = $sortKey; + } + } + + if (!defined $newestKernelFile) { + die _tr("unable to pick a kernel-file from path '%s'!", $kernelPath); + } + return $newestKernelFile; +} + +sub preSystemInstallationHook +{ +} + +sub postSystemInstallationHook +{ +} + +sub setPasswordForUser +{ + my $self = shift; + my $username = shift; + my $password = shift; + + my $hashedPassword = $self->hashPassword($password); + + my $writePasswordFunction = sub { + # now read, change and write shadow-file in atomic manner: + my $shadowFile = '/etc/shadow'; + if (!-e $shadowFile) { + spitFile( $shadowFile, ''); + } + slxsystem("cp -r $shadowFile $shadowFile~"); + my $shadowFH; + open($shadowFH, '+<', $shadowFile) + or croak _tr("could not open file '%s'! (%s)", $shadowFile, $!); + flock($shadowFH, LOCK_EX) + or croak _tr("could not lock file '%s'! (%s)", $shadowFile, $!); + my $lastChanged = int(time()/24/60/60); + my $newEntry + = "$username:$hashedPassword:$lastChanged:0:99999:7:::"; + my $content = do { local $/; <$shadowFH> }; + if ($content =~ m{^$username:}ims) { + $content =~ s{^$username:.+?$}{$newEntry}ms; + } else { + $content .= "$newEntry\n"; + } + seek($shadowFH, 0, 0) + or croak _tr("could not seek file '%s'! (%s)", $shadowFile, $!); + print $shadowFH $content + or croak _tr("could not write to file '%s'! (%s)", $shadowFile, $!); + close($shadowFH) + or croak _tr("could not close file '%s'! (%s)", $shadowFile, $!); + unlink "$shadowFile~"; + }; + $self->{engine}->callChrootedFunctionForVendorOS($writePasswordFunction); +} + +sub hashPassword +{ + my $self = shift; + my $password = shift; + + my $busyboxBin = $self->{engine}->busyboxBinary(); + my $hashedPassword = qx{$busyboxBin cryptpw -a md5 $password}; + chomp $hashedPassword; + + return $hashedPassword; +} + +1; +################################################################################ + +=pod + +=head1 NAME + +OpenSLX::OSSetup::System::Base - the base class for all OSSetup backends + +=head1 SYNOPSIS + + package OpenSLX::OSSetup::coolnewOS; + + use vars qw(@ISA $VERSION); + @ISA = ('OpenSLX::OSSetup::Base'); + $VERSION = 1.01; + + use coolnewOS; + + sub new + { + my $class = shift; + my $self = {}; + return bless $self, $class; + } + + # override all methods of OpenSLX::OSSetup::Base in order to implement + # a full OS-setup backend + ... + +I> + +=head1 DESCRIPTION + +This class defines the OSSetup interface for the OpenSLX. + +Aim of the OSSetup abstraction is to make it possible to install a large set +of different operating systems transparently. + +... + +=cut diff --git a/src/installer/OpenSLX/OSSetup/Distro/Debian.pm b/src/installer/OpenSLX/OSSetup/Distro/Debian.pm new file mode 100644 index 00000000..bdb9dcc1 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Debian.pm @@ -0,0 +1,135 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Debian.pm +# - provides Debian-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Debian; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->SUPER::initialize($engine); + $self->{'packager-type'} = 'dpkg'; + $self->{'meta-packager-type'} = $ENV{SLX_META_PACKAGER} || 'apt'; + $self->{'stage1c-faked-files'} = []; + return; +} + +sub preSystemInstallationHook +{ + my $self = shift; + + $self->SUPER::preSystemInstallationHook(); + + # create required /dev-entries + my %devInfo = ( + mem => { type => 'c', major => '1', minor => '1' }, + null => { type => 'c', major => '1', minor => '3' }, + zero => { type => 'c', major => '1', minor => '5' }, + random => { type => 'c', major => '1', minor => '8' }, + urandom => { type => 'c', major => '1', minor => '9' }, + kmsg => { type => 'c', major => '1', minor => '11' }, + console => { type => 'c', major => '5', minor => '1' }, + ptmx => { type => 'c', major => '5', minor => '2' }, + ); + foreach my $dev (keys %devInfo) { + my $info = $devInfo{$dev}; + if (!-e "/dev/$dev") { + if (slxsystem( + "mknod /dev/$dev $info->{type} $info->{major} $info->{minor}" + )) { + croak(_tr("unable to create dev-node '%s'! (%s)", $dev, $!)); + } + } + } + foreach my $devDir ('pts', 'shm', '.udevdb', '.udev') { + if (!-e "/dev/$devDir") { + if (slxsystem("mkdir -p /dev/$devDir")) { + croak(_tr("unable to create dev-dir '%s'! (%s)", $devDir, $!)); + } + } + } + + # replace /usr/sbin/invoke-rc.d by a dummy, in order to avoid a whole lot + # of initscripts being started. Wishful thinking: there should be another + # way to stop Debian from doing this, as this is not really very supportive + # of folder-based installations (then again: I may simply be too stupid + # to find out how it is supposed to work ...) + rename('/usr/sbin/invoke-rc.d', '/usr/sbin/_invoke-rc.d'); + spitFile('/usr/sbin/invoke-rc.d', "#! /bin/sh\nexit 0\n"); + chmod 0755, '/usr/sbin/invoke-rc.d'; +} + +sub startSession +{ + my $self = shift; + my $osDir = shift; + + $self->SUPER::startSession($osDir); + + # As in preSystemInstallationHook, we replace /usr/sbin/invoke-rc.d by a + # dummy. + # + # During installation, this might not exist yet, so we better check + if (-e '/usr/sbin/invoke-rc.d') { + rename('/usr/sbin/invoke-rc.d', '/usr/sbin/_invoke-rc.d'); + spitFile('/usr/sbin/invoke-rc.d', "#! /bin/sh\nexit 0\n"); + chmod 0755, '/usr/sbin/invoke-rc.d'; + } +} + +sub finishSession +{ + my $self = shift; + + # restore /usr/sbin/invoke-rc.d + rename('/usr/sbin/_invoke-rc.d', '/usr/sbin/invoke-rc.d'); + + $self->SUPER::finishSession(); +} + +sub setPasswordForUser +{ + my $self = shift; + my $username = shift; + my $password = shift; + + # activate shadow passwords + my $activateShadowFunction = sub { + slxsystem('/sbin/shadowconfig', 'on'); + }; + $self->{engine}->callChrootedFunctionForVendorOS($activateShadowFunction); + + # invoke default behaviour + $self->SUPER::setPasswordForUser($username, $password); +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/Distro/Debian_3_1.pm b/src/installer/OpenSLX/OSSetup/Distro/Debian_3_1.pm new file mode 100644 index 00000000..03c6fdf9 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Debian_3_1.pm @@ -0,0 +1,74 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Debian_3_1.pm +# - provides Debian-3.1-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Debian_3_1; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Debian); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub preSystemInstallationHook +{ + my $self = shift; + + $self->SUPER::preSystemInstallationHook(); + + # when the kernel package is being configured, it insists on trying to + # create an initrd, which neither works nor makes sense in our environment. + # + # in order to circumvent this problem, we manually install initrd-tools + # (which contains mkinitrd) ... + $self->{engine}->{'meta-packager'}->installPackages('initrd-tools'); + # ... and replace /usr/sbin/mkinitrd with a dummy, in order to skip the + # initrd-creation. + rename('/usr/sbin/mkinitrd', '/usr/sbin/_mkinitrd'); + spitFile('/usr/sbin/mkinitrd', "#! /bin/sh\ntouch \$2\n"); + chmod 0755, '/usr/sbin/mkinitrd'; +} + +sub startSession +{ + my $self = shift; + my $osDir = shift; + + $self->SUPER::startSession($osDir); + + # As in preSystemInstallationHook, we replace /usr/sbin/mkinitrd with a + # dummy, in order to skip the initrd-creation. + # + # During installation, this might not exist yet, so we better check + if (-e '/usr/sbin/mkinitrd') { + rename('/usr/sbin/mkinitrd', '/usr/sbin/_mkinitrd'); + spitFile('/usr/sbin/mkinitrd', "#! /bin/sh\ntouch \$2\n"); + chmod 0755, '/usr/sbin/mkinitrd'; + } +} + +sub finishSession +{ + my $self = shift; + + # restore /usr/sbin/mkinitrd + rename('/usr/sbin/_mkinitrd', '/usr/sbin/mkinitrd'); + + $self->SUPER::finishSession(); +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/Distro/Fedora.pm b/src/installer/OpenSLX/OSSetup/Distro/Fedora.pm new file mode 100644 index 00000000..80480340 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Fedora.pm @@ -0,0 +1,48 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Fedora.pm +# - provides Fedora-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Fedora; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->SUPER::initialize($engine); + $self->{'packager-type'} = 'rpm'; + $self->{'meta-packager-type'} = $ENV{SLX_META_PACKAGER} || 'yum'; + $self->{'stage1c-faked-files'} = [ + '/etc/fstab', + '/etc/mtab', + ]; + return; +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/Distro/Gentoo.pm b/src/installer/OpenSLX/OSSetup/Distro/Gentoo.pm new file mode 100644 index 00000000..79fd0e29 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Gentoo.pm @@ -0,0 +1,33 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Gentoo.pm +# - provides Gentoo-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Gentoo; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Distro/Scilin.pm b/src/installer/OpenSLX/OSSetup/Distro/Scilin.pm new file mode 100644 index 00000000..e1ce5fc3 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Scilin.pm @@ -0,0 +1,48 @@ +# Copyright (c) 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Scilin.pm +# - provides Scientific Linux specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Scilin; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->SUPER::initialize($engine); + $self->{'packager-type'} = 'rpm'; + $self->{'meta-packager-type'} = $ENV{SLX_META_PACKAGER} || 'yum'; + $self->{'stage1c-faked-files'} = [ + '/etc/fstab', + '/etc/mtab', + ]; + return; +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Distro/Suse.pm b/src/installer/OpenSLX/OSSetup/Distro/Suse.pm new file mode 100644 index 00000000..8e85e46a --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Suse.pm @@ -0,0 +1,98 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Suse.pm +# - provides SUSE-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Suse; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->SUPER::initialize($engine); + $self->{'packager-type'} = 'rpm'; + + # use 'zypper' as meta-packager from 10.2 onwards and use 'smart' for + # older releases + my $defaultMetaPackager = 'zypper'; + if ($self->{'engine'}->{'distro-name'} =~ m{-([^-]+)$}) { + my $distroVersion = 0.0 + $1; + if ($distroVersion <= 10.2) { + $defaultMetaPackager = 'smart'; + } + } + $self->{'meta-packager-type'} + = $ENV{SLX_META_PACKAGER} || $defaultMetaPackager; + + if ($engine->{'action-type'} eq 'install') { + # Inform SUSE RPMs that we're performing an installation - this is + # only important for installations taking place in stage 1c: + $ENV{YAST_IS_RUNNING} = "instsys"; + } + + return; +} + +sub fixPrerequiredFiles +{ + my $self = shift; + my $stage1cDir = shift; + + chown( + 0, 0, "$stage1cDir/etc/group", "$stage1cDir/etc/passwd", + "$stage1cDir/etc/shadow" + ); + return; +} + +sub updateDistroConfig +{ + my $self = shift; + + # invoke SuSEconfig in order to allow it to update the configuration: + if (slxsystem('SuSEconfig')) { + die _tr("unable to run SuSEconfig (%s)", $!); + } + $self->SUPER::updateDistroConfig(); + return; +} + +sub hashPassword +{ + my $self = shift; + my $password = shift; + + my $busyboxBin = $self->{engine}->busyboxBinary(); + my $hashedPassword = qx{$busyboxBin cryptpw -a blowfish '$password'}; + chomp $hashedPassword; + + return $hashedPassword; +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Distro/Ubuntu.pm b/src/installer/OpenSLX/OSSetup/Distro/Ubuntu.pm new file mode 100644 index 00000000..f0f42487 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Distro/Ubuntu.pm @@ -0,0 +1,119 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# OSSetup/Distro/Ubuntu.pm +# - provides Ubuntu-specific overrides of the OSSetup Distro API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Distro::Ubuntu; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Distro::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + my $self = {}; + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->SUPER::initialize($engine); + $self->{'packager-type'} = 'dpkg'; + $self->{'meta-packager-type'} = $ENV{SLX_META_PACKAGER} || 'apt'; + $self->{'stage1c-faked-files'} = []; + return; +} + +sub preSystemInstallationHook +{ + my $self = shift; + + $self->SUPER::preSystemInstallationHook(); + + # fake required /dev-entries + my %devInfo = ( + mem => { type => 'c', major => '1', minor => '1' }, + null => { type => 'c', major => '1', minor => '3' }, + zero => { type => 'c', major => '1', minor => '5' }, + random => { type => 'c', major => '1', minor => '8' }, + urandom => { type => 'c', major => '1', minor => '9' }, + kmsg => { type => 'c', major => '1', minor => '11' }, + console => { type => 'c', major => '5', minor => '1' }, + ptmx => { type => 'c', major => '5', minor => '2' }, + ); + foreach my $dev (keys %devInfo) { + my $info = $devInfo{$dev}; + if (!-e "/dev/$dev") { + if (slxsystem( + "mknod /dev/$dev $info->{type} $info->{major} $info->{minor}" + )) { + croak(_tr("unable to create dev-node '%s'! (%s)", $dev, $!)); + } + } + } + foreach my $devDir ('pts', 'shm', '.udevdb', '.udev') { + if (!-e "/dev/$devDir") { + if (slxsystem("mkdir -p /dev/$devDir")) { + croak(_tr("unable to create dev-dir '%s'! (%s)", $devDir, $!)); + } + } + } + + # replace /usr/sbin/invoke-rc.d by a dummy, in order to avoid a whole lot + # of initscripts being started. Wishful thinking: there should be another + # way to stop Ubuntu from doing this, as this is not really very supportive + # of folder-based installations (then again: I may simply be too stupid + # to find out how it is supposed to work ...) + rename('/usr/sbin/invoke-rc.d', '/usr/sbin/_invoke-rc.d'); + spitFile('/usr/sbin/invoke-rc.d', "#! /bin/sh\nexit 0\n"); + chmod 0755, '/usr/sbin/invoke-rc.d'; +} + +sub startSession +{ + my $self = shift; + my $osDir = shift; + + $self->SUPER::startSession($osDir); + + # As in preSystemInstallationHook, we replace /usr/sbin/invoke-rc.d by a + # dummy. + # + # During installation, this might not exist yet, so we better check + if (-e '/usr/sbin/invoke-rc.d') { + rename('/usr/sbin/invoke-rc.d', '/usr/sbin/_invoke-rc.d'); + spitFile('/usr/sbin/invoke-rc.d', "#! /bin/sh\nexit 0\n"); + chmod 0755, '/usr/sbin/invoke-rc.d'; + } +} + +sub finishSession +{ + my $self = shift; + + # restore /usr/sbin/invoke-rc.d + rename('/usr/sbin/_invoke-rc.d', '/usr/sbin/invoke-rc.d'); + + $self->SUPER::finishSession(); +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Engine.pm b/src/installer/OpenSLX/OSSetup/Engine.pm new file mode 100644 index 00000000..642a058b --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Engine.pm @@ -0,0 +1,1929 @@ +# Copyright (c) 2006..2010 - 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/ +# ----------------------------------------------------------------------------- +# Engine.pm +# - provides driver engine for the OSSetup API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Engine; + +use strict; +use warnings; + +our (@ISA, @EXPORT, $VERSION); +$VERSION = 1.01; # API-version . implementation-version + +use Exporter; +@ISA = qw(Exporter); + +@EXPORT = qw( + %supportedDistros +); + +use Config::General; +use File::Basename; +use File::Path; +use URI; + +use OpenSLX::Basics; +use OpenSLX::ScopedResource; +use OpenSLX::Syscall; +use OpenSLX::Utils; + +use vars qw(%supportedDistros); + +%supportedDistros = ( + 'debian-3.1' => 'clone,install,update,shell', + 'debian-4.0' => 'clone,install,update,shell', + 'debian-4.0_amd64' => 'clone,install,update,shell', + 'debian-5.0' => 'clone,update,shell', + 'fedora-6' => 'clone,install,update,shell', + 'fedora-6_x86_64' => 'clone,install,update,shell', + 'gentoo-2007.X' => 'clone', + 'suse-10.1' => 'clone,install,update,shell', + 'suse-10.1_x86_64' => 'clone,install,update,shell', + 'suse-10.2' => 'clone,install,update,shell', + 'suse-10.2_x86_64' => 'clone,install,update,shell', + 'suse-10.3' => 'clone,install,update,shell', + 'suse-10.3_x86_64' => 'clone,update,shell', + 'suse-11.0' => 'clone,install,update,shell', + 'suse-11.0_x86_64' => 'clone,update,shell', + 'suse-11.1' => 'clone,install,update,shell', + 'suse-11.1_x86_64' => 'clone,update,shell', + 'suse-11.2' => 'clone,install,update,shell', + 'suse-11.2_x86_64' => 'clone,update,shell', + 'suse-11.3' => 'clone,update,shell', + 'suse-11.3_x86_64' => 'clone,update,shell', + 'scilin-4.7' => 'clone,update,shell', + 'scilin-5.3' => 'clone,update,shell', + 'scilin-5.4_x86_64' => 'clone,update,shell', + 'scilin-5.5_x86_64' => 'clone,update,shell', + 'ubuntu-8.04' => 'clone,install,update,shell', + 'ubuntu-8.04_amd64' => 'clone,update,shell', + 'ubuntu-8.10' => 'clone,install,update,shell', + 'ubuntu-8.10_amd64' => 'clone,update,shell', + 'ubuntu-9.04' => 'clone,install,update,shell', + 'ubuntu-9.04_amd64' => 'clone,update,shell', + 'ubuntu-9.10' => 'clone,install,update,shell', + 'ubuntu-9.10_amd64' => 'clone,update,shell', + 'ubuntu-10.04' => 'clone,install,update,shell', + 'ubuntu-10.04_amd64'=> 'clone,update,shell', +); + +my %localHttpServers; +my $filelisting; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + my $class = shift; + + my $self = {}; + + return bless $self, $class; +} + +sub initialize +{ + my $self = shift; + my $vendorOSName = shift; + my $actionType = shift; + + if ($vendorOSName eq '<<>>') { + die _tr("you can't do that with the default vendor-OS!\n"); + } + if ($vendorOSName !~ m[^([^\-]+\-[^\-]+)(?:\-(.+))?]) { + die _tr( + "Given vendor-OS has unknown format, " . + "expected '-[-]'\n" + ); + } + my $distroName = lc($1); + my $selectionName = $2 || 'default'; + $self->{'vendor-os-name'} = $vendorOSName; + $self->{'action-type'} = $actionType; + $self->{'distro-name'} = $distroName; + $self->{'selection-name'} = $selectionName; + $self->{'clone-source'} = ''; + if (!exists $supportedDistros{$distroName}) { + print _tr("Sorry, distro '%s' is unsupported.\n", $distroName); + print _tr("List of supported distros:\n\t"); + print join("\n\t", sort keys %supportedDistros) . "\n"; + exit 1; + } + my $support = $supportedDistros{$distroName}; + if ($actionType eq 'install' && $support !~ m[install]i) { + print _tr( + "Sorry, distro '%s' can not be installed, only cloned!\n", + $distroName + ); + exit 1; + } + elsif ($actionType eq 'update' && $support !~ m[(update)]i) { + print _tr( + "Sorry, update support for vendor-OS '%s' has not been " . + "implemented!\n", + $distroName + ); + exit 1; + } + elsif ($actionType eq 'shell' && $support !~ m[(shell)]i) { + print _tr( + "Sorry, vendor-OS '%s' has no support for chrooted shells " . + "available!\n", + $distroName + ); + exit 1; + } + + # load module for the requested distro: + my $distro = loadDistroModule({ + distroName => $distroName, + distroScope => 'OpenSLX::OSSetup::Distro', + fallbackName => 'Any_Clone', + }); + if (!$distro) { + die _tr( + 'unable to load any OSSetup::Distro module for vendor-OS %s!', + $vendorOSName + ); + } + + $distro->initialize($self); + $self->{distro} = $distro; + + # protect against parallel executions of writing OpenSLX scripts + $self->{'vendor-os-lock'} = grabLock($vendorOSName); + + if ($actionType =~ m{^(install|update|shell|plugin)}) { + # setup path to distribution-specific info: + my $sharedDistroInfoDir + = "$openslxConfig{'base-path'}/share/distro-info/" . + "$self->{'distro-name'}"; + if (!-d $sharedDistroInfoDir) { + die _tr( + "unable to find shared distro-info in '%s'\n", + $sharedDistroInfoDir + ); + } + $self->{'shared-distro-info-dir'} = $sharedDistroInfoDir; + my $configDistroInfoDir = + "$openslxConfig{'config-path'}/distro-info/$self->{'distro-name'}"; + if (!-d $configDistroInfoDir) { + die _tr( + "unable to find configurable distro-info in '%s'\n", + $configDistroInfoDir + ); + } + $self->{'config-distro-info-dir'} = $configDistroInfoDir; + + my $setupMirrorsIfNecessary = $actionType eq 'install'; + $self->_readDistroInfo($setupMirrorsIfNecessary); + } + + if ($self->{'action-type'} eq 'install' + && !exists $self->{'distro-info'}->{'selection'}->{$selectionName}) + { + die( + _tr( + "selection '%s' is unknown to distro '%s'\n", + $selectionName, $self->{'distro-name'} + ) + . _tr("These selections are available:\n\t") + . join("\n\t", sort keys %{$self->{'distro-info'}->{'selection'}}) + . "\n" + ); + } + + $self->{'vendor-os-path'} + = "$openslxConfig{'private-path'}/stage1/$self->{'vendor-os-name'}"; + vlog(1, "vendor-OS path is '$self->{'vendor-os-path'}'"); + + if ($actionType =~ m{^(install|update|shell|plugin)}) { + $self->_createPackager(); + $self->_createMetaPackager(); + } + + return; +} + +sub installVendorOS +{ + my $self = shift; + my $vendorOSSettings = shift; + + my $installInfoFile = "$self->{'vendor-os-path'}/.openslx-install-info"; + if (-e $installInfoFile) { + die _tr("vendor-OS '%s' already exists, giving up!\n", + $self->{'vendor-os-path'}); + } + $self->_createVendorOSPath(); + + my $httpServers = OpenSLX::ScopedResource->new({ + name => 'local-http-servers', + acquire => sub { $self->_startLocalURLServersAsNeeded(); 1 }, + release => sub { $self->_stopLocalURLServers(); 1 }, + }); + + my $baseSystemFile = "$self->{'vendor-os-path'}/.openslx-base-system"; + if (-e $baseSystemFile) { + vlog(0, _tr("found existing base system, continuing...\n")); + } + else { + # basic setup, stage1a-c: + $self->_setupStage1A(); + callInSubprocess( + sub { + # some tasks that involve a chrooted environment: + $self->_changePersonalityIfNeeded(); + $self->_setupStage1B(); + $self->_setupStage1C(); + } + ); + $self->_stage1C_cleanupBasicVendorOS(); + # just touch the file, in order to indicate a basic system: + slxsystem("touch $baseSystemFile"); + } + callInSubprocess( + sub { + # another task that involves a chrooted environment: + $self->_changePersonalityIfNeeded(); + $self->_setupStage1D(); + } + ); + + # create the install-info file, in order to indicate a proper installation: + spitFile( + $installInfoFile, + "SLX_META_PACKAGER=$self->{distro}->{'meta-packager-type'}\n" + ); + + # base system info file is no longer needed, we have a full system now + slxsystem("rm $baseSystemFile"); + + $self->_applyVendorOSSettings($vendorOSSettings) unless !$vendorOSSettings; + + vlog( + 0, + _tr( + "Vendor-OS '%s' installed succesfully.\n", + $self->{'vendor-os-name'} + ) + ); + + # generate default openslx directories for the client + $self->_generateDefaultDirs(); + + # add the uclibs and tools to the stage1 + $self->_copyUclibcRootfs(); + #callInSubprocess( + # sub { + # $self->_callChrootedFunction({ + # chrootDir => $self->{'vendor-os-path'}, + # function => sub { + # $self->{'distro'}->addUclibLdconfig(); + # }, + # updateConfig => 1, + # }); + #}); + $self->_touchVendorOS(); + $self->addInstalledVendorOSToConfigDB(); + return; +} + +sub cloneVendorOS +{ + my $self = shift; + my $source = shift; + + if (substr($source, -1, 1) ne '/') { + # make sure source path ends with a slash, as otherwise, the + # last folder would be copied (but we only want its contents). + $source .= '/'; + } + + $self->{'clone-source'} = $source; + my $lastCloneSource = ''; + my $cloneInfoFile = "$self->{'vendor-os-path'}/.openslx-clone-info"; + my $isReClone; + if (-e $self->{'vendor-os-path'}) { + my $installInfoFile = "$self->{'vendor-os-path'}/.openslx-install-info"; + if (-e $installInfoFile) { + # oops, given vendor-os has been installed, not cloned, we complain: + croak( + _tr( + "The vendor-OS '%s' exists but it is no clone, refusing " . + "to clobber!\nPlease delete the folder manually, if " . + "that's really what you want...\n", + $self->{'vendor-os-path'} + ) + ); + } + elsif (-e $cloneInfoFile) { + # check if last and current source match: + my $cloneInfo = slurpFile($cloneInfoFile); + if ($cloneInfo =~ m[^source\s*=\s*(.+?)\s*$]ims) { + $lastCloneSource = $1; + } + if ($source ne $lastCloneSource) { + # protect user from confusing sources (still allowed, though): + my $yes = _tr('yes'); + my $no = _tr('no'); + print _tr( + "Last time this vendor-OS was cloned, it has been cloned " . + "from '%s', now you specified a different source: '%s'\n" . + "Would you still like to proceed (%s/%s)?", + $lastCloneSource, $source, $yes, $no + ); + my $answer = ; + exit 5 unless $answer =~ m[^\s*$yes]i; + } + $isReClone = 1; + } + else { + # Neither the install-info nor the clone-info file exists. This + # probably means that the folder has been created by an older + # version of the tools. There's not much we can do, we simply + # trust our user and assume that he knows what he's doing. + } + } + + $self->_createVendorOSPath(); + + $self->_clone_fetchSource($source); + if ($source ne $lastCloneSource) { + spitFile($cloneInfoFile, "source=$source\n"); + } + if ($isReClone) { + vlog( + 0, + _tr( + "Vendor-OS '%s' has been re-cloned succesfully.\n", + $self->{'vendor-os-name'} + ) + ); + } + else { + vlog( + 0, + _tr( + "Vendor-OS '%s' has been cloned succesfully.\n", + $self->{'vendor-os-name'} + ) + ); + } + + # generate default openslx directories for the client + $self->_generateDefaultDirs(); + + # add the uclibs and tools to the stage1 + $self->_copyUclibcRootfs(); + $self->_touchVendorOS(); + $self->addInstalledVendorOSToConfigDB(); + return; +} + +sub updateVendorOS +{ + my $self = shift; + + if (!-e $self->{'vendor-os-path'}) { + die _tr("can't update vendor-OS '%s', since it doesn't exist!\n", + $self->{'vendor-os-path'}); + } + + my $httpServers = OpenSLX::ScopedResource->new({ + name => 'local-http-servers', + acquire => sub { $self->_startLocalURLServersAsNeeded(); 1 }, + release => sub { $self->_stopLocalURLServers(); 1 }, + }); + + callInSubprocess( + sub { + $self->_changePersonalityIfNeeded(); + $self->_updateStage1D(); + } + ); + + $self->_generateDefaultDirs(); + $self->_copyUclibcRootfs(); + $self->_touchVendorOS(); + vlog( + 0, + _tr("Vendor-OS '%s' updated succesfully.\n", $self->{'vendor-os-name'}) + ); + + $self->_installPlugins(); + + return; +} + +sub startChrootedShellForVendorOS +{ + my $self = shift; + + if (!-e $self->{'vendor-os-path'}) { + die _tr( + "can't start chrooted shell for vendor-OS '%s', since it doesn't " . + "exist!\n", + $self->{'vendor-os-path'} + ); + } + + my $httpServers = OpenSLX::ScopedResource->new({ + name => 'local-http-servers', + acquire => sub { $self->_startLocalURLServersAsNeeded(); 1 }, + release => sub { $self->_stopLocalURLServers(); 1 }, + }); + + callInSubprocess( + sub { + $self->_changePersonalityIfNeeded(); + $self->_startChrootedShellInStage1D(); + } + ); + + vlog( + 0, + _tr( + "Chrooted shell for vendor-OS '%s' has been closed.\n", + $self->{'vendor-os-name'} + ) + ); + $self->_touchVendorOS(); + + return; +} + +sub callChrootedFunctionForVendorOS +{ + my $self = shift; + my $function = shift; + my $updateConfig = shift || 0; + + if (!-e $self->{'vendor-os-path'}) { + die _tr( + "can't call chrooted function for vendor-OS '%s', since it " . + "doesn't exist!\n", + $self->{'vendor-os-path'} + ); + } + + # avoid trying to chroot into a 64-bit vendor-OS if the host is only 32-bit: + if (!$self->_hostIs64Bit() && -e "$self->{'vendor-os-path'}/lib64") { + die _tr("you can't use a 64-bit vendor-OS on a 32-bit host, sorry!\n"); + } + + my $httpServers = OpenSLX::ScopedResource->new({ + name => 'local-http-servers', + acquire => sub { $self->_startLocalURLServersAsNeeded(); 1 }, + release => sub { $self->_stopLocalURLServers(); 1 }, + }); + + callInSubprocess( + sub { + $self->_changePersonalityIfNeeded(); + $self->_callChrootedFunction({ + chrootDir => $self->{'vendor-os-path'}, + function => $function, + updateConfig => $updateConfig, + }); + } + ); + + vlog( + 1, + _tr( + "Chrooted function for vendor-OS '%s' has finished.\n", + $self->{'vendor-os-name'} + ) + ); + $self->_touchVendorOS(); + + return 1; +} + +sub removeVendorOS +{ + my $self = shift; + + vlog( + 0, + _tr("removing vendor-OS folder '%s'...", $self->{'vendor-os-path'}) + ); + if (system( + "find $self->{'vendor-os-path'} -xdev -depth -print0 | xargs -0 rm -r" + )) { + vlog( + 0, + _tr("* unable to remove vendor-OS '%s'!", $self->{'vendor-os-path'}) + ); + } + else { + vlog( + 0, + _tr( + "Vendor-OS '%s' removed succesfully.\n", + $self->{'vendor-os-name'} + ) + ); + } + $self->removeVendorOSFromConfigDB(); + return; +} + +sub addInstalledVendorOSToConfigDB +{ + my $self = shift; + + if (!-e $self->{'vendor-os-path'}) { + die _tr( + "can't import vendor-OS '%s', since it doesn't exist!\n", + $self->{'vendor-os-path'} + ); + } + my $openslxDB = instantiateClass("OpenSLX::ConfigDB"); + $openslxDB->connect(); + + my @plugins; + + # insert new vendor-os if it doesn't already exist in DB: + my $vendorOSName = $self->{'vendor-os-name'}; + my $vendorOS = $openslxDB->fetchVendorOSByFilter({'name' => $vendorOSName}); + if (defined $vendorOS) { + if ($vendorOS->{'clone_source'} + && $self->{'clone-source'} ne $vendorOS->{'clone_source'}) { + $openslxDB->changeVendorOS( + $vendorOS->{id}, + { 'clone_source' => $self->{'clone-source'} } + ); + vlog( + 0, + _tr( + "Vendor-OS '%s' has been updated in OpenSLX-database.\n", + $vendorOSName + ) + ); + } + else { + vlog( + 0, + _tr( + "No need to change vendor-OS '%s' in OpenSLX-database.\n", + $vendorOSName + ) + ); + } + # fetch installed plugins of this vendor-OS in order to reinstall them + @plugins = $openslxDB->fetchInstalledPlugins($vendorOS->{id}); + } + else { + my $data = { 'name' => $vendorOSName }; + if (length($self->{'clone-source'})) { + $data->{'clone_source'} = $self->{'clone-source'}; + } + my $id = $openslxDB->addVendorOS($data); + + vlog( + 0, + _tr( + "Vendor-OS '%s' has been added to DB (ID=%s).\n", + $vendorOSName, $id + ) + ); + # fetch plugins from default vendor-OS in order to install those into + # this new one + @plugins = $openslxDB->fetchInstalledPlugins(0); + } + + $openslxDB->disconnect(); + + # now that we have the list of plugins, we (re-)install all of them: + $self->_installPlugins(\@plugins, defined $vendorOS); + + return; +} + +sub removeVendorOSFromConfigDB +{ + my $self = shift; + + my $openslxDB = instantiateClass("OpenSLX::ConfigDB"); + $openslxDB->connect(); + + my $vendorOSName = $self->{'vendor-os-name'}; + my $vendorOS = $openslxDB->fetchVendorOSByFilter({'name' => $vendorOSName}); + if (!defined $vendorOS) { + vlog( + 0, + _tr( + "Vendor-OS '%s' didn't exist in OpenSLX-database.\n", + $vendorOSName + ) + ); + } + else { + # remove all exports (and systems) using this vendor-OS and then + # remove the vendor-OS itself: + my @exports = $openslxDB->fetchExportByFilter( + {'vendor_os_id' => $vendorOS->{id}}); + foreach my $export (@exports) { + my $osExportEngine = instantiateClass("OpenSLX::OSExport::Engine"); + $osExportEngine->initializeFromExisting($export->{name}); + vlog( + 0, + _tr( + "purging export '%s', since it belongs to the vendor-OS " . + "being deleted...", + $export->{name} + ) + ); + $osExportEngine->purgeExport(); + } + + $openslxDB->removeVendorOS($vendorOS->{id}); + vlog( + 0, + _tr("Vendor-OS '%s' has been removed from DB!\n", $vendorOSName) + ); + } + + $openslxDB->disconnect(); + return; +} + +sub pickKernelFile +{ + my $self = shift; + + return $self->{distro}->pickKernelFile(@_); +} + +sub distroName +{ + my $self = shift; + + return $self->{'distro-name'}; +} + +sub metaPackager +{ + my $self = shift; + + return $self->{'meta-packager'}; +} + +sub packager +{ + my $self = shift; + + return $self->{'packager'}; +} + +sub getInstallablePackagesForSelection +{ + my $self = shift; + my $selKey = shift; + + return if !$selKey; + + my $selection = $self->{'distro-info'}->{selection}->{$selKey}; + return if !$selection; + + my @pkgs = split m{\s+}, $selection->{packages}; + my %installedPkgs; + @installedPkgs{ $self->{'packager'}->getInstalledPackages() } = (); + @pkgs = grep { !exists $installedPkgs{$_} } @pkgs; + + return join ' ', @pkgs; +} + +sub busyboxBinary +{ + my $self = shift; + + my $uclibdir = "$openslxConfig{'base-path'}/share/uclib-rootfs"; + + return sprintf( + "LD_LIBRARY_PATH=%s/lib %s/bin/busybox", + $uclibdir, + $uclibdir + ); +} + +################################################################################ +### implementation methods +################################################################################ +sub _readDistroInfo +{ + my $self = shift; + my $setupMirrorsIfNecessary = shift || 0; + + vlog(1, "reading configuration info for $self->{'vendor-os-name'}..."); + + $self->{'distro-info'} = { + 'package-subdir' => '', + 'prereq-packages' => '', + 'bootstrap-packages' => '', + 'metapackager' => {}, + 'repository' => {}, + 'selection' => {}, + 'excludes' => {}, + }; + + # merge user-provided configuration with distro defaults + foreach my $file ( + "$self->{'shared-distro-info-dir'}/settings.default", + "$self->{'config-distro-info-dir'}/settings" + ) { + if (-e $file) { + vlog(2, "reading configuration file $file..."); + my $configObject = Config::General->new( + -AllowMultiOptions => 0, + -AutoTrue => 1, + -ConfigFile => $file, + -LowerCaseNames => 1, + -SplitPolicy => 'equalsign', + ); + my %config = $configObject->getall(); + mergeHash($self->{'distro-info'}, \%config); + } + } + + # fetch mirrors for all repositories (if requested): + foreach my $repoKey (keys %{$self->{'distro-info'}->{repository}}) { + my $repo = $self->{'distro-info'}->{repository}->{$repoKey}; + $repo->{key} = $repoKey; + # if there is local URL, only that is used, otherwise we fetch the + # configured mirrors: + if (!$repo->{'local-url'}) { + $repo->{urls} = $self->_fetchConfiguredMirrorsForRepository( + $repo, $setupMirrorsIfNecessary + ); + } + } + + # expand all selections: + my $seen = {}; + foreach my $selKey (keys %{$self->{'distro-info'}->{selection}}) { + $self->_expandSelection($selKey, $seen); + } + + # dump distro-info, if asked for: + if ($openslxConfig{'log-level'} >= 2) { + my $repository = $self->{'distro-info'}->{repository}; + foreach my $r (sort keys %$repository) { + vlog(2, "repository '$r':"); + foreach my $k (sort keys %{$repository->{$r}}) { + vlog(3, "\t$k = '$repository->{$r}->{$k}'"); + } + } + my $selection = $self->{'distro-info'}->{selection}; + foreach my $s (sort keys %$selection) { + vlog(2, "selection '$s':"); + foreach my $k (sort keys %{$selection->{$s}}) { + vlog(3, "\t$k = '$selection->{$s}->{$k}'"); + } + } + my $excludes = $self->{'distro-info'}->{excludes}; + foreach my $e (sort keys %$excludes) { + vlog(2, "excludes for '$e':"); + foreach my $k (sort keys %{$excludes->{$e}}) { + vlog(3, "\t$k = '$excludes->{$e}->{$k}'"); + } + } + } + return; +} + +sub _fetchConfiguredMirrorsForRepository +{ + my $self = shift; + my $repoInfo = shift; + my $setupMirrorsIfNecessary = shift; + + my $configuredMirrorsFile + = "$self->{'config-distro-info-dir'}/mirrors/$repoInfo->{key}"; + if (!-e $configuredMirrorsFile) { + return '' if !$setupMirrorsIfNecessary; + vlog(0, + _tr( + "repo '%s' has no configured mirrors, let's pick some ...", + $repoInfo->{name} + ) + ); + $self->_configureBestMirrorsForRepository($repoInfo); + } + vlog(2, "reading configured mirrors file '$configuredMirrorsFile'."); + my $configObject = Config::General->new( + -AllowMultiOptions => 0, + -AutoTrue => 1, + -ConfigFile => $configuredMirrorsFile, + -LowerCaseNames => 1, + -SplitPolicy => 'equalsign', + ); + my %config = $configObject->getall(); + + return $config{urls}; +} + +sub _configureBestMirrorsForRepository +{ + my $self = shift; + my $repoInfo = shift; + + my $configuredMirrorsFile + = "$self->{'config-distro-info-dir'}/mirrors/$repoInfo->{key}"; + + if (!-e "$self->{'config-distro-info-dir'}/mirrors") { + mkdir "$self->{'config-distro-info-dir'}/mirrors"; + } + + my $allMirrorsFile + = "$self->{'shared-distro-info-dir'}/mirrors/$repoInfo->{key}"; + my @allMirrors = string2Array(scalar slurpFile($allMirrorsFile)); + + my $mirrorsToTryCount = $openslxConfig{'mirrors-to-try-count'} || 20; + my $mirrorsToUseCount = $openslxConfig{'mirrors-to-use-count'} || 5; + vlog(1, + _tr( + "selecting the '%s' best mirrors (from a set of '%s') for repo " . + "'%s' ...", + $mirrorsToUseCount, $mirrorsToTryCount, $repoInfo->{key} + ) + ); + + # determine own top-level domain: + my $topLevelDomain; + if (defined $openslxConfig{'mirrors-preferred-top-level-domain'}) { + $topLevelDomain + = lc($openslxConfig{'mirrors-preferred-top-level-domain'}); + } + else { + my $FQDN = getFQDN(); + $FQDN =~ m{\.(\w+)$}; + $topLevelDomain = lc($1); + } + + # select up to $mirrorsToTryCount "close" mirrors from the array ... + my @tryMirrors + = grep { + my $uri = URI->new($_); + my $host = $uri->host(); + $host =~ m{\.(\w+)$} && lc($1) eq $topLevelDomain; + } + @allMirrors; + + my $tryList = join("\n\t", @tryMirrors); + vlog(1, + _tr( + "mirrors matching the preferred top level domain ('%s'):\n\t%s\n", + $topLevelDomain, $tryList + ) + ); + + if (@tryMirrors > $mirrorsToTryCount) { + # shrink array to $mirrorsToTryCount elements + vlog(1, _tr("shrinking list to %s mirrors\n", $mirrorsToTryCount)); + $#tryMirrors = $mirrorsToTryCount; + } + elsif (@tryMirrors < $mirrorsToTryCount) { + # we need more mirrors, try adding some others randomly: + vlog(1, + _tr( + "filling list with %s more random mirrors:\n", + $mirrorsToTryCount - @tryMirrors + ) + ); + + # fill @untriedMirrors with the mirrors not already contained + # in @tryMirrors ... + my @untriedMirrors + = grep { + my $mirror = $_; + !grep { $mirror eq $_ } @tryMirrors; + } @allMirrors; + + # ... and pick randomly until we have reached the limit or there are + # no more unused mirrors left + foreach my $count (@tryMirrors..$mirrorsToTryCount-1) { + last if !@untriedMirrors; + my $index = int(rand(scalar @untriedMirrors)); + my $randomMirror = splice(@untriedMirrors, $index, 1); + push @tryMirrors, $randomMirror; + vlog(1, "\t$randomMirror\n"); + } + } + + # just make sure we are not going to try/use more mirros than we have + # available + if ($mirrorsToTryCount > @tryMirrors) { + $mirrorsToTryCount = @tryMirrors; + } + if ($mirrorsToUseCount > $mirrorsToTryCount) { + $mirrorsToUseCount = $mirrorsToTryCount; + } + + # ... fetch a file from all of these mirrors and measure the time taken ... + vlog(0, + _tr( + "testing %s mirrors to determine the fastest %s ...\n", + $mirrorsToTryCount, $mirrorsToUseCount + ) + ); + my %mirrorSpeed; + my $veryGoodSpeedCount = 0; + foreach my $mirror (@tryMirrors) { + if ($veryGoodSpeedCount >= $mirrorsToUseCount) { + # we already have enough mirrors with very good speed, + # it makes no sense to test any others. We simply set the + # time of the remaining mirrors to some large value, so they + # won't get picked: + $mirrorSpeed{$mirror} = 10000; + next; + } + + # test the current mirror and record the result + my $time = $self->_speedTestMirror( + $mirror, $repoInfo->{'file-for-speedtest'} + ); + $mirrorSpeed{$mirror} = $time; + if ($time <= 1) { + $veryGoodSpeedCount++; + } + } + + # ... now select the best (fastest) $mirrorsToUseCount mirrors ... + my @bestMirrors + = ( + sort { + $mirrorSpeed{$a} <=> $mirrorSpeed{$b}; + } + @tryMirrors + )[0..$mirrorsToUseCount-1]; + + vlog(0, + _tr( + "picked these '%s' mirrors for repo '%s':\n\t%s\n", + $mirrorsToUseCount, $repoInfo->{name}, join("\n\t", @bestMirrors) + ) + ); + + # ... and write them into the configuration file: + my $configObject = Config::General->new( + -AllowMultiOptions => 0, + -AutoTrue => 1, + -LowerCaseNames => 1, + -SplitPolicy => 'equalsign', + ); + $configObject->save_file($configuredMirrorsFile, { + 'urls' => join("\n", @bestMirrors), + }); + return; +} + +sub _speedTestMirror +{ + my $self = shift; + my $mirror = shift; + my $file = shift; + + vlog(0, _tr("\ttesting mirror '%s' ...\n", $mirror)); + + # do an explicit DNS-lookup as we do not want to include the time that takes + # in the speedtest + my $uri = URI->new($mirror); + my $hostName = $uri->host(); + if (!gethostbyname($hostName)) { + # unable to resolve host, we pretend it took really long + return 10000; + } + + # now measure the time it takes to download the file + my $wgetCmd = $self->busyboxBinary(); + $wgetCmd .= " wget -q -O - $mirror/$file >/dev/null"; + my $start = time(); + if (slxsystem($wgetCmd)) { + # just return any large number that is unlikely to be selected + return 10000; + } + my $time = time() - $start; + vlog(0, "\tfetched '$file' in $time seconds\n"); + return $time; +} + +sub _expandSelection +{ + my $self = shift; + my $selKey = shift; + my $seen = shift; + + return if $seen->{$selKey}; + $seen->{$selKey} = 1; + + return if !exists $self->{'distro-info'}->{selection}->{$selKey}; + my $selection = $self->{'distro-info'}->{selection}->{$selKey}; + + if ($selection->{base}) { + # add all packages from base selection(s) to the current one: + my $basePackages = ''; + for my $base (split ',', $selection->{base}) { + my $baseSelection = $self->{'distro-info'}->{selection}->{$base} + or die _tr( + 'base-selection "%s" is unknown (referenced in "%s")!', + $base, $selKey + ); + $self->_expandSelection($base, $seen); + $basePackages .= $baseSelection->{packages} || ''; + } + my $packages = $selection->{packages} || ''; + $selection->{packages} = $basePackages . "\n" . $packages; + } + return; +} + +sub _applyVendorOSSettings +{ + my $self = shift; + my $vendorOSSettings = shift; + + if (exists $vendorOSSettings->{'root-password'}) { + # hashes password according to requirements of current distro and + # writes it to /etc/shadow + $self->{distro}->setPasswordForUser( + 'root', $vendorOSSettings->{'root-password'} + ); + } + + return; +} + +sub _createVendorOSPath +{ + my $self = shift; + + if (slxsystem("mkdir -p $self->{'vendor-os-path'}")) { + die _tr("unable to create directory '%s', giving up! (%s)\n", + $self->{'vendor-os-path'}, $!); + } + return; +} + +sub _touchVendorOS +{ + my $self = shift; + + # touch root folder, as we are using this folder to determine the + # 'age' of the vendor-OS when trying to determine whether or not we + # need to re-export this vendor-OS: + slxsystem("touch $self->{'vendor-os-path'}"); + return; +} + +sub _generateDefaultDirs +{ + my $self = shift; + my $targetRoot = shift || $self->{'vendor-os-path'}; + + vlog(0, _tr("Creating default directories ...\n")); + + my $OPENSLX_DEFAULT_DIR = "/opt/openslx"; + my $OPENSLX_DEFAULT_CONFDIR = "/etc/opt/openslx"; + my $OPENSLX_DEFAULT_LOGDIR = "/var/log/openslx"; + my $OPENSLX_DEFAULT_VARDIR = "/var/opt/openslx"; + my $OPENSLX_DEFAULT_BINDIR = "$OPENSLX_DEFAULT_VARDIR/bin"; + my $OPENSLX_DEFAULT_LIBDIR = "$OPENSLX_DEFAULT_VARDIR/lib"; + my $OPENSLX_DEFAULT_VIRTDIR = "/var/lib/virt"; + mkpath("$targetRoot/$OPENSLX_DEFAULT_DIR", 0, 0755); + mkpath("$targetRoot/$OPENSLX_DEFAULT_CONFDIR", 0, 0755); + mkpath("$targetRoot/$OPENSLX_DEFAULT_LOGDIR", 0, 0755); + mkpath("$targetRoot/$OPENSLX_DEFAULT_BINDIR", 0, 0755); + mkpath("$targetRoot/$OPENSLX_DEFAULT_LIBDIR", 0, 0755); + mkpath("$targetRoot/$OPENSLX_DEFAULT_VIRTDIR", 0, 0755); + #system("chmod 0755 $targetRoot/$OPENSLX_DEFAULT_DIR"); + + my $openslxConfig = "# Default OpenSLX directories defined by satge 1\n"; + $openslxConfig .= "# Version 0.2\n\n"; + $openslxConfig .= "OPENSLX_DEFAULT_DIR=$OPENSLX_DEFAULT_DIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_CONFDIR=$OPENSLX_DEFAULT_CONFDIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_LOGDIR=$OPENSLX_DEFAULT_LOGDIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_VARDIR=$OPENSLX_DEFAULT_VARDIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_BINDIR=$OPENSLX_DEFAULT_BINDIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_LIBDIR=$OPENSLX_DEFAULT_LIBDIR\n"; + $openslxConfig .= "OPENSLX_DEFAULT_VIRTDIR=$OPENSLX_DEFAULT_VIRTDIR\n"; + + spitFile("$targetRoot/$OPENSLX_DEFAULT_CONFDIR/openslx.conf", + "$openslxConfig"); + + # add BINDIR to PATH + my $openslxDefaultPath = "PATH=$OPENSLX_DEFAULT_BINDIR:\$PATH\n"; + $openslxDefaultPath .= "export PATH\n"; + spitFile("$targetRoot/etc/profile.d/openslx-binpath.sh", + "$openslxDefaultPath"); +} + +sub _copyUclibcRootfs +{ + my $self = shift; + my $targetRoot = shift || $self->{'vendor-os-path'}; + my $distro = $self->{distro}; + + vlog(0, _tr("copying uclibc-rootfs into vendor-OS ...\n")); + + my $target = "$targetRoot/opt/openslx/uclib-rootfs"; + + if (system("mkdir -p $target")) { + die _tr("unable to create directory '%s', giving up! (%s)\n", + $target, $!); + } + + my $uclibcRootfs = "$openslxConfig{'base-path'}/share/uclib-rootfs"; + my @excludes = qw( + dialog + kexec + libcurses.so* + libncurses.so* + ); + my $exclOpts = join ' ', map { "--exclude $_" } @excludes; + vlog(3, _tr("using exclude-filter:\n%s\n", $exclOpts)); + my $rsyncFH; + my $rsyncCmd + = "rsync -aq --delete-excluded --exclude-from=- $uclibcRootfs/ $target"; + vlog(2, "executing: $rsyncCmd\n"); + # if we're doing a fresh install we need to create /lib, /bin first + mkdir "$targetRoot/lib"; + mkdir "$targetRoot/bin"; + + open($rsyncFH, '|-', $rsyncCmd) + or die _tr("unable to start rsync for source '%s', giving up! (%s)", + $uclibcRootfs, $!); + print $rsyncFH $exclOpts; + close($rsyncFH) + or die _tr("unable to copy to target '%s', giving up! (%s)", + $target, $!); + + # write version of uclibc-rootfs original into a file in order to be + # able to check the up-to-date state later (in the config-demuxer) + slxsystem("slxversion >${target}.version"); + + return; +} + +sub _createPackager +{ + my $self = shift; + + my $packagerClass + = "OpenSLX::OSSetup::Packager::$self->{distro}->{'packager-type'}"; + my $packager = instantiateClass($packagerClass); + $packager->initialize($self); + $self->{'packager'} = $packager; + return; +} + +sub _createMetaPackager +{ + my $self = shift; + + my $metaPackagerType = $self->{distro}->{'meta-packager-type'}; + + my $installInfoFile = "$self->{'vendor-os-path'}/.openslx-install-info"; + if (-e $installInfoFile) { + # activate the meta-packager that was used when installing the os: + my $installInfo = slurpFile($installInfoFile); + if ($installInfo =~ m[SLX_META_PACKAGER=(\w+)]) { + $metaPackagerType = $1; + } + } + + my $metaPackagerClass = "OpenSLX::OSSetup::MetaPackager::$metaPackagerType"; + my $metaPackager = instantiateClass($metaPackagerClass); + $metaPackager->initialize($self); + $self->{'meta-packager'} = $metaPackager; + return; +} + +sub _sortRepositoryURLs +{ + my $self = shift; + my $repoInfo = shift; + + my @URLs + = defined $repoInfo->{'local-url'} + ? $repoInfo->{'local-url'} + : string2Array($repoInfo->{urls}); + if (!@URLs) { + die( + _tr( + "repository '%s' has no URLs defined, " . + "unable to fetch anything!", + $repoInfo->{name}, + ) + ); + } + + return \@URLs; +} + +sub _downloadBaseFiles +{ + my $self = shift; + my $files = shift; + use vars qw(@filelisting); + + my $pkgSubdir = $self->{'distro-info'}->{'package-subdir'}; + my @URLs = @{$self->{'baseURLs'}}; + my $maxTryCount = $openslxConfig{'ossetup-max-try-count'}; + my @possiblefiles; + + my @foundFiles; + foreach my $fileVariantStr (@$files) { + my $tryCount = 0; + next unless $fileVariantStr =~ m[\S]; + my $foundFile; +try_next_url: + my $url = $URLs[$self->{'baseURL-index'}]; + $url .= "/$pkgSubdir" if length($pkgSubdir); + + foreach my $file (split '\s+', $fileVariantStr) { + #substitute given name with real filename including version number + my $basefile = basename($file); + my $basedir = dirname($file)."/"; + @possiblefiles = grep(/^$basefile/,@filelisting); + #selecting always the first occurence + if ($possiblefiles[0]) { + $basefile = $possiblefiles[0]; + } elsif ($basefile =~ /.*\.rpm/) { + vlog(5,"Trying suggested name because of .rpm-ending."); + } else { + die _tr("file <$basefile> not found in list received from" . + "mirror"); + } + vlog(2, "fetching <$basefile>..."); + if (slxsystem("wget", "-c", "-O", "$basefile", + "$url/$basedir$basefile") == 0) { + $foundFile = $basefile; + last; + } + elsif (-e $basefile) { + vlog(0, "removing left-over '$basefile' and trying again..."); + unlink $basefile; + redo; + } + } + if (!defined $foundFile) { + if ($tryCount < $maxTryCount) { + $tryCount++; + $self->{'baseURL-index'} + = ($self->{'baseURL-index'} + 1) % scalar(@URLs); + vlog( + 0, + _tr( + "switching to mirror '%s'.", + $URLs[$self->{'baseURL-index'}] + ) + ); + goto try_next_url; + } + die _tr("unable to fetch '%s' from any source!\n", $fileVariantStr); + } + push @foundFiles, $foundFile; + } + return @foundFiles; +} + +sub _startLocalURLServersAsNeeded +{ + my $self = shift; + + my $port = 5080; + my %portForURL; + foreach my $repoInfo (values %{$self->{'distro-info'}->{repository}}) { + my $localURL = $repoInfo->{'local-url'} || ''; + next if !$localURL; + next if $localURL =~ m[^\w+:]; # anything /w a protcol-spec is non-local + if (!exists $localHttpServers{$localURL}) { + my $pid + = executeInSubprocess( + $self->busyboxBinary(), "httpd", '-p', $port, '-h', '/', + '-f' + ); + vlog(1, + _tr( + "started local HTTP-server for URL '%s' on port '%s'.", + $localURL, $port + ) + ); + $repoInfo->{'local-url'} = "http://localhost:$port$localURL"; + $localHttpServers{$localURL}->{pid} = $pid; + $localHttpServers{$localURL}->{url} = $repoInfo->{'local-url'}; + $port++; + } + else { + $repoInfo->{'local-url'} = $localHttpServers{$localURL}->{url}; + } + } + return; +} + +sub _stopLocalURLServers +{ + my $self = shift; + + while (my ($localURL, $serverInfo) = each %localHttpServers) { + vlog(1, _tr("stopping local HTTP-server for URL '%s'.", $localURL)); + kill TERM => $serverInfo->{pid}; + } +} + +sub _setupStage1A +{ + my $self = shift; + + vlog(1, "setting up stage1a for $self->{'vendor-os-name'}..."); + + # specify individual paths for the respective substages: + $self->{stage1aDir} = "$self->{'vendor-os-path'}/stage1a"; + $self->{stage1bSubdir} = 'slxbootstrap'; + $self->{stage1cSubdir} = 'slxfinal'; + + # we create *all* of the above folders by creating stage1cDir: + my $stage1cDir + = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}/". + "$self->{'stage1cSubdir'}"; + if (slxsystem("mkdir -p $stage1cDir")) { + die _tr("unable to create directory '%s', giving up! (%s)\n", + $stage1cDir, $!); + } + + $self->_stage1A_setupUclibcEnvironment(); + $self->_stage1A_copyPrerequiredFiles(); + $self->_stage1A_copyTrustedPackageKeys(); + $self->_stage1A_createRequiredFiles(); + return; +} + +sub _stage1A_setupUclibcEnvironment +{ + my $self = shift; + $self->_copyUclibcRootfs("$self->{stage1aDir}/$self->{stage1bSubdir}"); + my $source = "$self->{stage1bSubdir}/opt/openslx/uclib-rootfs"; + my $target = "$self->{stage1aDir}"; + slxsystem("ln -sf $source/bin $target/bin"); + slxsystem("ln -sf $source/lib $target/lib"); + slxsystem("ln -sf $source/usr $target/usr"); + $self->_stage1A_setupResolver(); + + return; +} + + +sub _stage1A_setupResolver +{ + my $self = shift; + my $libcFolder = shift; + + #if (!defined $libcFolder) { + # warn _tr("unable to determine libc-target-folder, will use /lib!"); + # $libcFolder = '/lib'; + #} + + copyFile('/etc/resolv.conf', "$self->{stage1aDir}/etc"); + copyFile('/etc/nsswitch.conf', "$self->{stage1aDir}/etc"); + spitFile("$self->{stage1aDir}/etc/hosts", "127.0.0.1 localhost\n"); + #copyFile("$libcFolder/libresolv*", "$self->{stage1aDir}$libcFolder"); + #copyFile("$libcFolder/libnss_dns*", "$self->{stage1aDir}$libcFolder"); + #copyFile("$libcFolder/libnss_files*", "$self->{stage1aDir}$libcFolder"); + + my $stage1cDir + = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}/" . + "$self->{'stage1cSubdir'}"; + copyFile('/etc/resolv.conf', "$stage1cDir/etc"); + return; +} + +sub _stage1A_copyPrerequiredFiles +{ + my $self = shift; + + return unless -d "$self->{'shared-distro-info-dir'}/prereqfiles"; + + vlog(2, "copying folder with pre-required files..."); + my $stage1cDir + = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}/" . + "$self->{'stage1cSubdir'}"; + my $cmd = qq[ + tar -cp -C $self->{'shared-distro-info-dir'}/prereqfiles . \\ + | tar -xp -C $stage1cDir + ]; + if (slxsystem($cmd)) { + die _tr( + "unable to copy folder with pre-required files to folder '%s'" . + "(%s)\n", + $stage1cDir, $! + ); + } + vlog(2, "fix pre-required files..."); + $self->{distro}->fixPrerequiredFiles($stage1cDir); + return; +} + +sub _stage1A_copyTrustedPackageKeys +{ + my $self = shift; + + vlog(2, "copying folder with trusted package keys..."); + my $stage1bDir = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}"; + foreach my $folder ( + $self->{'shared-distro-info-dir'}, $self->{'config-distro-info-dir'} + ) { + next unless -d "$folder/trusted-package-keys"; + my $cmd = qq[ + tar -cp -C $folder trusted-package-keys \\ + | tar -xp -C $stage1bDir + ]; + if (slxsystem($cmd)) { + die _tr( + "unable to copy folder with trusted package keys to folder " . + "'%s' (%s)\n", + "$stage1bDir/trusted-package-keys", $! + ); + } + slxsystem("chmod 444 $stage1bDir/trusted-package-keys/*"); + + # install ultimately trusted keys (from distributor): + my $stage1cDir = "$stage1bDir/$self->{'stage1cSubdir'}"; + my $keyDir = "$self->{'shared-distro-info-dir'}/trusted-package-keys"; + if (-e "$keyDir/pubring.gpg") { + copyFile("$keyDir/pubring.gpg", "$stage1cDir/usr/lib/rpm/gnupg"); + } + } + return; +} + +sub _stage1A_createRequiredFiles +{ + my $self = shift; + + vlog(2, "creating required files..."); + + # fake all files required by stage1b (by creating them empty): + my $stage1bDir = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}"; + foreach my $fake (@{$self->{distro}->{'stage1b-faked-files'}}) { + fakeFile("$stage1bDir/$fake"); + } + + # fake all files required by stage1c (by creating them empty): + my $stage1cDir = "$stage1bDir/$self->{'stage1cSubdir'}"; + foreach my $fake (@{$self->{distro}->{'stage1c-faked-files'}}) { + fakeFile("$stage1cDir/$fake"); + } + + mkdir "$stage1cDir/dev"; + if (!-e "$stage1cDir/dev/null" + && slxsystem("mknod $stage1cDir/dev/null c 1 3")) + { + die _tr( + "unable to create node '%s' (%s)\n", "$stage1cDir/dev/null", $! + ); + } + return; +} + +sub _setupStage1B +{ + my $self = shift; + + vlog(1, "setting up stage1b for $self->{'vendor-os-name'}..."); + $self->_stage1B_chrootAndBootstrap(); + return; +} + +sub _stage1B_chrootAndBootstrap +{ + my $self = shift; + + # give packager a chance to copy required files into stage1a-folder: + $self->{packager}->prepareBootstrap($self->{stage1aDir}); + + $self->_callChrootedFunction({ + chrootDir => $self->{stage1aDir}, + function => sub { + # chdir into slxbootstrap, as we want to drop packages into there: + chdir "/$self->{stage1bSubdir}" + or die _tr( + "unable to chdir into '%s' (%s)\n", + "/$self->{stage1bSubdir}", $! + ); + + # fetch prerequired packages and use them to bootstrap the packager: + $self->{'baseURLs'} = $self->_sortRepositoryURLs( + $self->{'distro-info'}->{repository}->{base} + ); + $self->{'baseURL-index'} = 0; + my @pkgs = + string2Array($self->{'distro-info'}->{'prereq-packages'}); + vlog( + 2, + "downloading these prereq packages:\n\t" . join("\n\t", @pkgs) + ); + my @prereqPkgs = $self->_downloadBaseFiles(\@pkgs); + $self->{'prereq-packages'} = \@prereqPkgs; + $self->{packager}->bootstrap(\@prereqPkgs); + + @pkgs = + string2Array($self->{'distro-info'}->{'bootstrap-packages'}); + push( + @pkgs, + string2Array( + $self->{'distro-info'}->{'metapackager'} + ->{$self->{distro}->{'meta-packager-type'}}->{packages} + ) + ); + vlog( + 2, + "downloading bootstrap packages:\n\t" . join("\n\t", @pkgs) + ); + my @bootstrapPkgs = $self->_downloadBaseFiles(\@pkgs); + $self->{'bootstrap-packages'} = \@bootstrapPkgs; + }, + }); + return; +} + +sub _setupStage1C +{ + my $self = shift; + + vlog(1, "setting up stage1c for $self->{'vendor-os-name'}..."); + $self->_stage1C_chrootAndInstallBasicVendorOS(); + return; +} + +sub _stage1C_chrootAndInstallBasicVendorOS +{ + my $self = shift; + + my $stage1bDir = "/$self->{stage1bSubdir}"; + chrootInto($stage1bDir); + + my $stage1cDir = "/$self->{stage1cSubdir}"; + + # import any additional trusted package keys to rpm-DB: + my $keyDir = "/trusted-package-keys"; + my $keyDirDH; + if (opendir($keyDirDH, $keyDir)) { + my @keyFiles + = map { "$keyDir/$_" } + grep { $_ !~ m[^(\.\.?|pubring.gpg)$] } + readdir($keyDirDH); + closedir($keyDirDH); + $self->{packager}->importTrustedPackageKeys(\@keyFiles, $stage1cDir); + } + + # install bootstrap packages + $self->{packager}->installPackages( + $self->{'bootstrap-packages'}, $stage1cDir + ); + return; +} + +sub _stage1C_cleanupBasicVendorOS +{ + my $self = shift; + + my $stage1cDir + = "$self->{'stage1aDir'}/$self->{'stage1bSubdir'}/" . + "$self->{'stage1cSubdir'}"; + if (slxsystem("mv $stage1cDir/* $self->{'vendor-os-path'}/")) { + die _tr( + "unable to move final setup to '%s' (%s)\n", + $self->{'vendor-os-path'}, $! + ); + } + if (slxsystem("rm -rf $self->{stage1aDir}")) { + die _tr( + "unable to remove temporary folder '%s' (%s)\n", + $self->{stage1aDir}, $! + ); + } + return; +} + +sub _setupStage1D +{ + my $self = shift; + + vlog(1, "setting up stage1d for $self->{'vendor-os-name'}..."); + + $self->_callChrootedFunction({ + chrootDir => $self->{'vendor-os-path'}, + function => sub { + $self->_stage1D_setupPackageSources(); + $self->_stage1D_updateBasicVendorOS(); + $self->{distro}->preSystemInstallationHook(); + my $ok = eval { + $self->_stage1D_installPackageSelection(); + 1; + }; + my $err = $ok ? undef : $@; + $self->{distro}->postSystemInstallationHook(); + die $err if defined $err; + }, + updateConfig => 1, + }); + return; +} + +sub _updateStage1D +{ + my $self = shift; + + vlog(1, "updating $self->{'vendor-os-name'}..."); + + $self->_callChrootedFunction({ + chrootDir => $self->{'vendor-os-path'}, + function => sub { + $self->_stage1D_updateBasicVendorOS(); + }, + updateConfig => 1, + }); + return; +} + +sub _startChrootedShellInStage1D +{ + my $self = shift; + + vlog(0, "starting chrooted shell for $self->{'vendor-os-name'}"); + vlog(0, "---------------------------------------"); + vlog(0, "- please type 'exit' if you are done! -"); + vlog(0, "---------------------------------------"); + + $self->_callChrootedFunction({ + chrootDir => $self->{'vendor-os-path'}, + function => sub { + # will hang until user exits manually: + slxsystem($openslxConfig{'default-shell'}); + }, + updateConfig => 1, + }); + return; +} + +sub _callChrootedFunction +{ + my $self = shift; + my $params = shift; + + checkParams($params, { + 'chrootDir' => '!', + 'function' => '!', + 'updateConfig' => '?', + }); + + my $distro = $self->{distro}; + my $distroSession = OpenSLX::ScopedResource->new({ + name => 'ossetup::distro::session', + acquire => sub { $distro->startSession($params->{chrootDir}); 1 }, + release => sub { $distro->finishSession(); 1 }, + }); + + die $@ if ! eval { + # invoke given function: + $params->{function}->(); + $distro->updateDistroConfig() if $params->{updateConfig}; + 1; + }; + + return; +} + +sub _stage1D_setupPackageSources +{ + my $self = shift; + + vlog(1, "setting up package sources for meta packager..."); + my $selectionName = $self->{'selection-name'}; + my $pkgExcludes + = $self->{'distro-info'}->{excludes}->{$selectionName}->{packages}; + my $excludeList = join ' ', string2Array($pkgExcludes); + $self->{'meta-packager'}->initPackageSources(); + my ($rk, $repo); + while (($rk, $repo) = each %{$self->{'distro-info'}->{repository}}) { + vlog(2, "setting up package source $rk..."); + $self->{'meta-packager'}->setupPackageSource( + $rk, $repo, $excludeList, $self->_sortRepositoryURLs($repo) + ); + } + return; +} + +sub _stage1D_updateBasicVendorOS +{ + my $self = shift; + + vlog(1, "updating basic vendor-os..."); + $self->{'meta-packager'}->updateBasicVendorOS(); + return; +} + +sub _stage1D_installPackageSelection +{ + my $self = shift; + + my $selectionName = $self->{'selection-name'}; + + vlog(1, "installing package selection <$selectionName>..."); + my $selection = $self->{'distro-info'}->{selection}->{$selectionName}; + my @pkgs = string2Array($selection->{packages}); + my @installedPkgs = $self->{'packager'}->getInstalledPackages(); + @pkgs = grep { + my $pkg = $_; + if (grep { $_ eq $pkg; } @installedPkgs) { + vlog(1, "package '$pkg' filtered, it is already installed."); + 0; + } + else { + 1; + } + } @pkgs; + if (!@pkgs) { + vlog( + 0, + _tr( + "No packages listed for selection '%s', nothing to do.", + $selectionName + ) + ); + } + else { + vlog(1, "installing these packages:\n" . join("\n\t", @pkgs)); + $self->{'meta-packager'}->installPackages(join(' ', @pkgs), 1); + } + return; +} + +sub _clone_fetchSource +{ + my $self = shift; + my $source = shift; + + vlog( + 0, + _tr( + "Cloning vendor-OS from '%s' to '%s'...\n", $source, + $self->{'vendor-os-path'} + ) + ); + my $excludeIncludeList = $self->_clone_determineIncludeExcludeList(); + vlog(1, "using exclude-include-filter:\n$excludeIncludeList\n"); + my $additionalRsyncOptions = $ENV{SLX_RSYNC_OPTIONS} || ''; + my $rsyncCmd + = "rsync -av --delete --exclude-from=- $additionalRsyncOptions" + . " $source $self->{'vendor-os-path'}"; + vlog(2, "executing: $rsyncCmd\n"); + my $rsyncFH; + open($rsyncFH, '|-', $rsyncCmd) + or croak( + _tr( + "unable to start rsync for source '%s', giving up! (%s)\n", + $source, $! + ) + ); + print $rsyncFH $excludeIncludeList; + if (!close($rsyncFH)) { + print "rsync-result=", 0+$!, "\n"; + croak _tr( + "unable to clone from source '%s', giving up! (%s)\n", $source, $! + ); + } + return; +} + +sub _clone_determineIncludeExcludeList +{ + my $self = shift; + + my $localFilterFile + = "$openslxConfig{'config-path'}/distro-info/clone-filter"; + my $includeExcludeList + = slurpFile($localFilterFile, { failIfMissing => 0 }); + $includeExcludeList .= $self->{distro}->{'clone-filter'}; + $includeExcludeList =~ s[^\s+][]igms; + + # remove any leading whitespace, as rsync doesn't like it + return $includeExcludeList; +} + +sub _installPlugins +{ + my $self = shift; + my $plugins = shift; + my $isReInstall = shift; + + if (!$plugins) { + $plugins = []; + my $openslxDB = instantiateClass("OpenSLX::ConfigDB"); + $openslxDB->connect(); + # fetch plugins from existing vendor-OS + my $vendorOS = $openslxDB->fetchVendorOSByFilter({ + 'name' => $self->{'vendor-os-name'} + }); + if ($vendorOS) { + push @$plugins, $openslxDB->fetchInstalledPlugins($vendorOS->{id}); + $isReInstall = 1; + } + $openslxDB->disconnect(); + } + + return if ! @$plugins; + + require OpenSLX::OSPlugin::Engine; + vlog( + 0, + $isReInstall + ? _tr("reinstalling plugins...\n") + : _tr("installing default plugins...\n") + ); + for my $pluginInfo ( + sort { + $self->_sortPluginsByDependency($a->{plugin_name}, + $b->{plugin_name}); + } @$plugins + ) { + my $pluginName = $pluginInfo->{plugin_name}; + my $pluginEngine = OpenSLX::OSPlugin::Engine->new(); + vlog(0, _tr("\t%s\n", $pluginName)); + $pluginEngine->initialize( + $pluginName, $self->{'vendor-os-name'}, $pluginInfo->{attrs} + ); + $pluginEngine->installPlugin(); + } + vlog(0, _tr("done with plugins.\n")); + + return; +} + +sub _sortPluginsByDependency +{ + my $self = shift; + my $pluginNameA = shift; + my $pluginNameB = shift; + + my $pluginA = OpenSLX::OSPlugin::Roster->getPlugin($pluginNameA); + if ($pluginA->dependsOnPlugin($pluginNameB)) { + return 1; + } + my $pluginB = OpenSLX::OSPlugin::Roster->getPlugin($pluginNameB); + if ($pluginB->dependsOnPlugin($pluginNameA)) { + return -1; + } + return 0; +} + +################################################################################ +### utility methods +################################################################################ +sub _changePersonalityIfNeeded +{ + my $self = shift; + + my $distroName = $self->{'distro-name'}; + if ($self->_hostIs64Bit() && $distroName !~ m[_64]) { + vlog(2, 'entering 32-bit personality'); + OpenSLX::Syscall->enter32BitPersonality(); + } + return; +} + +sub _hostIs64Bit +{ + my $self = shift; + + $self->{arch} = `uname -m` unless defined $self->{arch}; + return ($self->{arch} =~ m[64]); +} + +1; + +=pod + +=head1 NAME + +OpenSLX::OSSetup::Engine - driver engine for OSSetup API + +=head1 SYNOPSIS + +... + +=cut + diff --git a/src/installer/OpenSLX/OSSetup/MetaPackager/Base.pm b/src/installer/OpenSLX/OSSetup/MetaPackager/Base.pm new file mode 100644 index 00000000..f149d0f5 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/MetaPackager/Base.pm @@ -0,0 +1,98 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# Base.pm +# - provides empty base of the OpenSLX OSSetup::MetaPackager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::MetaPackager::Base; + +use strict; +use warnings; + +our $VERSION = 1.01; # API-version . implementation-version + +use Scalar::Util qw( weaken ); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + confess "Creating OpenSLX::OSSetup::MetaPackager::Base-objects directly makes no sense!"; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->{'engine'} = $engine; + weaken($self->{'engine'}); + # avoid circular reference between meta-packager and its engine + + return; +} + +sub initPackageSources +{ +} + +sub setupPackageSource +{ +} + +sub updateBasicVendorOS +{ +} + +sub installPackages +{ +} + +sub removePackages +{ +} + +1; +################################################################################ + +=pod + +=head1 NAME + +OpenSLX::OSSetup::MetaPackager::Base - the base class for all OSSetup::MetaPackagers + +=head1 SYNOPSIS + + package OpenSLX::OSSetup::MetaPackager::coolnewpkg; + + use vars qw(@ISA $VERSION); + @ISA = ('OpenSLX::OSSetup::MetaPackager::Base'); + $VERSION = 1.01; + + use coolnewpkg; + + sub new + { + my $class = shift; + my $self = {}; + return bless $self, $class; + } + + # override all methods of OpenSLX::OSSetup::MetaPackager::Base in order to + # implement the support for a new meta-packager + ... + +I> + +=cut diff --git a/src/installer/OpenSLX/OSSetup/MetaPackager/apt.pm b/src/installer/OpenSLX/OSSetup/MetaPackager/apt.pm new file mode 100644 index 00000000..ecb87a35 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/MetaPackager/apt.pm @@ -0,0 +1,142 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# apt.pm +# - provides apt-get-specific overrides of the OpenSLX::OSSetup::MetaPackager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::MetaPackager::apt; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::MetaPackager::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'apt', + }; + return bless $self, $class; +} + +sub initPackageSources +{ + my $self = shift; + + $ENV{LC_ALL} = 'POSIX'; + + # remove any existing sources + slxsystem('rm -f /etc/apt/sources.list'); + + # create default timezone if there isn't any + if (!-e '/etc/timezone') { + spitFile('/etc/timezone', "$openslxConfig{'default-timezone'}\n"); + } + + # create kernel config if there isn't any + if (!-e '/etc/kernel-img.conf') { + my $kernelConfig = unshiftHereDoc(<<" END-OF-HERE"); + # Kernel image management overrides + # See kernel-img.conf(5) for details + do_symlinks = yes + relative_links = yes + do_bootloader = no + do_bootfloppy = no + do_initrd = yes + link_in_boot = yes + END-OF-HERE + spitFile('/etc/kernel-img.conf', $kernelConfig); + } + + return 1; +} + +sub setupPackageSource +{ + my $self = shift; + my $repoName = shift; + my $repoInfo = shift; + my $excludeList = shift; + my $repoURLs = shift; + + my $baseURL = shift @$repoURLs; + my $distribution = $repoInfo->{'distribution'}; + my $components = $repoInfo->{'components'}; + + my $sourcesList = "deb $baseURL $distribution $components\n"; + + foreach my $mirrorURL (@$repoURLs) { + $sourcesList .= "deb $mirrorURL $distribution $components\n"; + } + + appendFile('/etc/apt/sources.list', $sourcesList); + + return; +} + +sub installPackages +{ + my $self = shift; + my $packages = shift; + my $doRefresh = shift || 0; + + $packages =~ tr{\n}{ }; + + if ($doRefresh && slxsystem("apt-get -y update")) { + die _tr("unable to update repository info (%s)\n", $!); + } + if ('/var/cache/debconf/slx-defaults.dat') { + $ENV{DEBCONF_DB_FALLBACK} + = "'File{/var/cache/debconf/slx-defaults.dat}'"; + } + $ENV{DEBIAN_FRONTEND} = 'noninteractive'; + if (slxsystem("apt-get -y install $packages")) { + die _tr("unable to install selection (%s)\n", $!); + } + delete $ENV{DEBCONF_DB_FALLBACK}; + delete $ENV{DEBIAN_FRONTEND}; + + return 1; +} + +sub removePackages +{ + my $self = shift; + my $pkgSelection = shift; + + if (slxsystem("apt-get -y remove $pkgSelection")) { + die _tr("unable to remove selection (%s)\n", $!); + } + + return 1; +} + +sub updateBasicVendorOS +{ + my $self = shift; + + if (slxsystem("apt-get -y update")) { + die _tr("unable to update repository info (%s)\n", $!); + } + if (slxsystem("apt-get -y upgrade")) { + die _tr("unable to update this vendor-os (%s)\n", $!); + } + + return 1; +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/MetaPackager/smart.pm b/src/installer/OpenSLX/OSSetup/MetaPackager/smart.pm new file mode 100644 index 00000000..fc178cb7 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/MetaPackager/smart.pm @@ -0,0 +1,127 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# smart.pm +# - provides smart-specific overrides of the OpenSLX::OSSetup::MetaPackager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::MetaPackager::smart; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::MetaPackager::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'smart', + }; + return bless $self, $class; +} + +sub initPackageSources +{ + my $self = shift; + + $ENV{LC_ALL} = 'POSIX'; + + # remove any existing channels + slxsystem("rm -f /etc/smart/channels/*"); + if (slxsystem("smart channel -y --remove-all")) { + die _tr("unable to remove existing channels (%s)\n", $!); + } + return 1; +} + +sub setupPackageSource +{ + my $self = shift; + my $repoName = shift; + my $repoInfo = shift; + my $excludeList = shift; + my $repoURLs = shift; + + my $repoSubdir = ''; + if ($repoInfo->{'repo-subdir'}) { + $repoSubdir = "/$repoInfo->{'repo-subdir'}"; + } + my $baseURL = shift @$repoURLs; + my $repoDescr + = qq[$repoName name="$repoInfo->{name}" baseurl=$baseURL$repoSubdir]; + $repoDescr .= " type=rpm-md"; + if (slxsystem("smart channel -y --add $repoDescr")) { + die _tr("unable to add channel '%s' (%s)\n", $repoName, $!); + } + + my $mirrorDescr; + foreach my $mirrorURL (@$repoURLs) { + $mirrorDescr .= " --add $baseURL$repoSubdir $mirrorURL$repoSubdir"; + } + if (defined $mirrorDescr) { + if (slxsystem("smart mirror $mirrorDescr")) { + die _tr( + "unable to add mirrors for channel '%s' (%s)\n", + $repoName, $! + ); + } + } + return 1; +} + +sub installPackages +{ + my $self = shift; + my $packages = shift; + my $doRefresh = shift || 0; + + $packages =~ tr{\n}{ }; + + if ($doRefresh && slxsystem("smart update")) { + die _tr("unable to update channel info (%s)\n", $!); + } + if (slxsystem("smart install -y $packages")) { + die _tr("unable to install selection (%s)\n", $!); + } + return 1; +} + +sub removePackages +{ + my $self = shift; + my $pkgSelection = shift; + + if (slxsystem("smart remove -y $pkgSelection")) { + die _tr("unable to remove selection (%s)\n", $!); + } + return 1; +} + +sub updateBasicVendorOS +{ + my $self = shift; + + if (slxsystem("smart upgrade -y --update")) { + if ($! == 2) { + # file not found => smart isn't installed + die _tr("unable to update this vendor-os, as it seems to lack an installation of smart!\n"); + } + die _tr("unable to update this vendor-os (%s)\n", $!); + } + return 1; +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/MetaPackager/yum.pm b/src/installer/OpenSLX/OSSetup/MetaPackager/yum.pm new file mode 100644 index 00000000..99a10382 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/MetaPackager/yum.pm @@ -0,0 +1,117 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# yum.pm +# - provides yum-specific overrides of the OpenSLX::OSSetup::MetaPackager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::MetaPackager::yum; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::MetaPackager::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'yum', + }; + return bless $self, $class; +} + +sub initPackageSources +{ + my $self = shift; + + $ENV{LC_ALL} = 'POSIX'; + + slxsystem("rm -f /etc/yum.repos.d/*"); + slxsystem("mkdir -p /etc/yum.repos.d"); + + return 1; +} + +sub setupPackageSource +{ + my $self = shift; + my $repoName = shift; + my $repoInfo = shift; + my $excludeList = shift; + my $repoURLs = shift; + + my $repoSubdir; + if (length($repoInfo->{'repo-subdir'})) { + $repoSubdir = "/$repoInfo->{'repo-subdir'}"; + } + my $baseURL = shift @$repoURLs; + + my $repoDescr + = "[$repoName]\nname=$repoInfo->{name}\nbaseurl=$baseURL$repoSubdir\n"; + vlog(4,"Adding repo <",$repoName,"> with Base-URL <",$baseURL,"> and Repo-SubDir <",$repoSubdir,">"); + foreach my $mirrorURL (@$repoURLs) { + $repoDescr .= " $mirrorURL$repoSubdir\n"; + } + my $repoFile = "/etc/yum.repos.d/$repoName.repo"; + spitFile($repoFile, "$repoDescr\nexclude=$excludeList\n"); + + return 1; +} + +sub installPackages +{ + my $self = shift; + my $packages = shift; + + $packages =~ tr{\n}{ }; + if (slxsystem("mount -t proc proc proc/") != 0){die _tr("unable to mount proc/ for yum \n");}; + if (slxsystem("yum -y install $packages")) { + die _tr("unable to install selection (%s)\n", $!); + } + if(slxsystem("umount proc/") != 0) {_tr("unable to umount proc/")}; + + return 1; +} + +sub removePackages +{ + my $self = shift; + my $pkgSelection = shift; + + if (slxsystem("yum -y remove $pkgSelection")) { + die _tr("unable to remove selection (%s)\n", $!); + } + + return 1; +} + +sub updateBasicVendorOS +{ + my $self = shift; + if (slxsystem("mount -t proc proc proc/") != 0){die _tr("unable to mount proc/ for yum \n");}; + if (slxsystem("yum -y update")) { + if ($! == 2) { + # file not found => yum isn't installed + die _tr("unable to update this vendor-os, as it seems to lack an installation of yum!\n"); + } + if(slxsystem("umount proc/") != 0) {_tr("unable to umount proc/")}; + die _tr("unable to update this vendor-os (%s)\n", $!); + } + if(slxsystem("umount proc/") != 0) {_tr("unable to umount proc/")}; + return 1; +} + +1; \ No newline at end of file diff --git a/src/installer/OpenSLX/OSSetup/MetaPackager/zypper.pm b/src/installer/OpenSLX/OSSetup/MetaPackager/zypper.pm new file mode 100644 index 00000000..4bb22bde --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/MetaPackager/zypper.pm @@ -0,0 +1,122 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# zypper.pm +# - provides zypper-specific overrides of the OpenSLX::OSSetup::MetaPackager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::MetaPackager::zypper; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::MetaPackager::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'zypper', + }; + return bless $self, $class; +} + +sub initPackageSources +{ + my $self = shift; + + $ENV{LC_ALL} = 'POSIX'; + + # remove any existing channels + slxsystem("rm -f /etc/zypp/repos.d/*"); + + return 1; +} + +sub setupPackageSource +{ + my $self = shift; + my $repoName = shift; + my $repoInfo = shift; + my $excludeList = shift; + my $repoURLs = shift; + + my $repoSubdir = ''; + if (defined $repoInfo->{'repo-subdir'} && + length($repoInfo->{'repo-subdir'})) { + $repoSubdir = "/$repoInfo->{'repo-subdir'}"; + } + my $baseURL = shift @$repoURLs; + + if ($baseURL =~ m/non-oss/) { + # skip non-oss repositories, cause zypper can't realy handle them + # correctly; zypper is deacting them with following message: + # "Repository type can't be determined." + return 1; + } + + if (slxsystem("zypper addrepo $baseURL$repoSubdir $repoName")) { + die _tr("unable to add repo '%s' (%s)\n", $repoName, $!); + } + + return 1; +} + +sub installPackages +{ + my $self = shift; + my $packages = shift; + my $doRefresh = shift || 0; + + $packages =~ tr{\n}{ }; + + if ($doRefresh && slxsystem("zypper --non-interactive refresh")) { + die _tr("unable to update repo info (%s)\n", $!); + } + if (slxsystem("zypper --non-interactive install $packages")) { + die _tr("unable to install selection (%s)\n", $!); + } + + return 1; +} + +sub removePackages +{ + my $self = shift; + my $pkgSelection = shift; + + if (slxsystem("zypper --non-interactive remove $pkgSelection")) { + die _tr("unable to remove selection (%s)\n", $!); + } + + return 1; +} + +sub updateBasicVendorOS +{ + my $self = shift; + + if (slxsystem("zypper --non-interactive update")) { + if ($! == 2) { + # file not found => zypper isn't installed + die _tr("unable to update this vendor-os, as it seems to lack an installation of zypper!\n"); + } + die _tr("unable to update this vendor-os (%s)\n", $!); + } + + return 1; +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Packager/Base.pm b/src/installer/OpenSLX/OSSetup/Packager/Base.pm new file mode 100644 index 00000000..af600b8b --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Packager/Base.pm @@ -0,0 +1,98 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# Base.pm +# - provides empty base of the OpenSLX OSSetup::Packager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Packager::Base; + +use strict; +use warnings; + +our $VERSION = 1.01; # API-version . implementation-version + +use Scalar::Util qw( weaken ); + +use OpenSLX::Basics; + +################################################################################ +### interface methods +################################################################################ +sub new +{ + confess "Creating OpenSLX::OSSetup::Packager::Base-objects directly makes no sense!"; +} + +sub initialize +{ + my $self = shift; + my $engine = shift; + + $self->{'engine'} = $engine; + weaken($self->{'engine'}); + # avoid circular reference between packager and its engine + + return; +} + +sub prepareBootstrap +{ +} + +sub bootstrap +{ +} + +sub importTrustedPackageKeys +{ +} + +sub installPackages +{ +} + +sub getInstalledPackages +{ +} + +1; +################################################################################ + +=pod + +=head1 NAME + +OpenSLX::OSSetup::Packager::Base - the base class for all OSSetup::Packagers + +=head1 SYNOPSIS + + package OpenSLX::OSSetup::Packager::coolnewpkg; + + use vars qw(@ISA $VERSION); + @ISA = ('OpenSLX::OSSetup::Packager::Base'); + $VERSION = 1.01; + + use coolnewpkg; + + sub new + { + my $class = shift; + my $self = {}; + return bless $self, $class; + } + + # override all methods of OpenSLX::OSSetup::Packager::Base in order to + # implement the support for a new packager + ... + +I> + +=cut diff --git a/src/installer/OpenSLX/OSSetup/Packager/dpkg.pm b/src/installer/OpenSLX/OSSetup/Packager/dpkg.pm new file mode 100644 index 00000000..94aff9c6 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Packager/dpkg.pm @@ -0,0 +1,102 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# rpm.pm +# - provides rpm-specific overrides of the OpenSLX::OSSetup::Packager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Packager::dpkg; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Packager::Base); + +use OpenSLX::Basics; +use OpenSLX::Utils; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'dpkg', + }; + return bless $self, $class; +} + +sub prepareBootstrap +{ + my $self = shift; + my $stage1aDir = shift; + + copyBinaryWithRequiredLibs({ + 'binary' => '/usr/bin/perl', + 'targetFolder' => "$stage1aDir/usr/bin", + 'libTargetFolder' => $stage1aDir, + }); + +} + +sub bootstrap +{ + my $self = shift; + my $pkgs = shift; + + my $debootstrapPkg = $pkgs->[0]; + chdir '..'; + vlog(2, "unpacking debootstrap ..."); + if (slxsystem("ash", "-c", "ar x slxbootstrap/$debootstrapPkg")) { + die _tr("unable to unarchive package '%s' (%s)", $debootstrapPkg, $!); + } + if (slxsystem("ash", "-c", "tar xzf data.tar.gz")) { + die _tr("unable to untar 'data.tar.gz (%s)", $!); + } + if (slxsystem("ash", "-c", "rm -f debian-binary *.tar.gz")) { + die _tr("unable to cleanup package '%s' (%s)", $debootstrapPkg, $!); + } + my $arch = $self->{engine}->{'distro-info'}->{arch}; + my $releaseName = $self->{engine}->{'distro-info'}->{'release-name'}; + my $baseURL = $self->{engine}->{baseURLs}->[0]; + my $debootstrapCmd = unshiftHereDoc(<<" END-OF-HERE"); + /usr/sbin/debootstrap --arch $arch $releaseName \\ + /slxbootstrap/slxfinal $baseURL + END-OF-HERE + if (slxsystem("ash", "-c", ". $debootstrapCmd")) { + die _tr("unable to run debootstrap (%s)", $!); + } + return; +} + +sub installPackages +{ + my $self = shift; + my $pkgs = shift; + my $finalPath = shift; + + return unless defined $pkgs && @$pkgs; + + if (slxsystem("dpkg", "--root=$finalPath", "--install", @$pkgs)) { + die _tr("error during package-installation (%s)\n", $!); + } + return; +} + +sub getInstalledPackages +{ + my $self = shift; + + my $rpmCmd = 'dpkg-query --showformat "\${package}\n" --show'; + my $pkgList = qx{$rpmCmd}; + return split "\n", $pkgList; +} + +1; diff --git a/src/installer/OpenSLX/OSSetup/Packager/rpm.pm b/src/installer/OpenSLX/OSSetup/Packager/rpm.pm new file mode 100644 index 00000000..8a86a3d2 --- /dev/null +++ b/src/installer/OpenSLX/OSSetup/Packager/rpm.pm @@ -0,0 +1,89 @@ +# Copyright (c) 2006, 2007 - 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/ +# ----------------------------------------------------------------------------- +# rpm.pm +# - provides rpm-specific overrides of the OpenSLX::OSSetup::Packager API. +# ----------------------------------------------------------------------------- +package OpenSLX::OSSetup::Packager::rpm; + +use strict; +use warnings; + +use base qw(OpenSLX::OSSetup::Packager::Base); + +use OpenSLX::Basics; + +################################################################################ +### implementation +################################################################################ +sub new +{ + my $class = shift; + my $self = { + 'name' => 'rpm', + }; + return bless $self, $class; +} + +sub bootstrap +{ + my $self = shift; + my $pkgs = shift; + + foreach my $pkg (@$pkgs) { + vlog(2, "unpacking package $pkg..."); + if (slxsystem("ash", "-c", "rpm2cpio $pkg | cpio -i -d -u")) { + die _tr("unable to unpack package <%s> (%s)", $pkg, $!); + } + } + return; +} + +sub importTrustedPackageKeys +{ + my $self = shift; + my $keyFiles = shift; + my $finalPath = shift; + + return unless defined $keyFiles; + + foreach my $keyFile (@$keyFiles) { + vlog(2, "importing package key $keyFile..."); + if (slxsystem("rpm", "--root=$finalPath", "--import", "$keyFile")) { + die _tr("unable to import package key <%s> (%s)\n", $keyFile, $!); + } + } + return; +} + +sub installPackages +{ + my $self = shift; + my $pkgs = shift; + my $finalPath = shift; + + return unless defined $pkgs && scalar(@$pkgs); + + if (slxsystem("rpm", "--root=$finalPath", "-ivh", @$pkgs)) { + die _tr("error during package-installation (%s)\n", $!); + } + return; +} + +sub getInstalledPackages +{ + my $self = shift; + + my $rpmCmd = 'rpm -qa --queryformat="%{NAME}\n"'; + my $pkgList = `$rpmCmd`; + return split "\n", $pkgList; +} + +1; -- cgit v1.2.3-55-g7522