summaryrefslogtreecommitdiffstats
path: root/src/os-plugins/OpenSLX
diff options
context:
space:
mode:
authorSebastian Schmelzer2010-09-02 17:50:49 +0200
committerSebastian Schmelzer2010-09-02 17:50:49 +0200
commit416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5 (patch)
tree4715f7d742fec50931017f38fe6ff0a89d4ceccc /src/os-plugins/OpenSLX
parentFix for the problem reported on the list (sed filter forgotten for the (diff)
downloadcore-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.tar.gz
core-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.tar.xz
core-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.zip
change dir structure
Diffstat (limited to 'src/os-plugins/OpenSLX')
-rw-r--r--src/os-plugins/OpenSLX/OSPlugin/Base.pm631
-rw-r--r--src/os-plugins/OpenSLX/OSPlugin/Engine.pm857
-rw-r--r--src/os-plugins/OpenSLX/OSPlugin/Roster.pm213
3 files changed, 1701 insertions, 0 deletions
diff --git a/src/os-plugins/OpenSLX/OSPlugin/Base.pm b/src/os-plugins/OpenSLX/OSPlugin/Base.pm
new file mode 100644
index 00000000..2af0f04c
--- /dev/null
+++ b/src/os-plugins/OpenSLX/OSPlugin/Base.pm
@@ -0,0 +1,631 @@
+# 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 OSPlugin API.
+# -----------------------------------------------------------------------------
+package OpenSLX::OSPlugin::Base;
+
+use strict;
+use warnings;
+
+our $VERSION = 1.01; # API-version . implementation-version
+
+=head1 NAME
+
+OpenSLX::OSPlugin::Base - the base class for all OpenSLX OS-plugins.
+
+=head1 DESCRIPTION
+
+This class defines the OpenSLX API for OS-plugins.
+
+The general idea behind OS-plugins is to extend any installed vendor-OS with
+a specific features. Each feature is implemented as a separate, small software
+component in order to make them easy to understand and maintain.
+
+Since all of these software components are plugged into the OpenSLX system by
+means of a common API, we call them B<OS-plugin>s.
+
+This API can be separated into different parts:
+
+=over
+
+=item - L</Declarative Interface> (provide info about a plugin)
+
+=item - L</Vendor-OS Interface> (installing or removing a plugin into/from a
+vendor-OS)
+
+=item - L</Initramfs Interface> (integrating a plugin into an initramfs)
+
+=back
+
+=head1 MORE INFO
+
+Please read the user-level introduction on plugins in the OpenSLX-wiki:
+L<http://openslx.org/trac/de/openslx/wiki/PluginKonzept> (in German).
+
+If you'd like to know how a plugin is implemented, please have a look at the
+'example' plugin, which contains some explainations and useful hints.
+
+If you have any questions regarding the concept of OS-plugins and their
+implementation, please drop a mail to: ot@openslx.com, or join the IRC-channel
+'#openslx' (on freenode).
+
+=cut
+
+use Scalar::Util qw( weaken );
+
+use OpenSLX::Basics;
+use OpenSLX::OSPlugin::Roster;
+
+=head1 PLUGIN API
+
+=head2 Declarative Interface
+
+=over
+
+=item new()
+
+Every plugin should provide a new-method and provide it's own name in the
+'name' entry of $self.
+
+Please note that by convention, plugin names are all lowercase!
+
+=cut
+
+sub new
+{
+ confess "Creating OpenSLX::OSPlugin::Base-objects directly makes no sense!";
+}
+
+=item initialize()
+
+Initializes basic context for this plugin (esp. a reference to the OSPlugin
+engine that drives this plugin.
+
+=cut
+
+sub initialize
+{
+ my $self = shift;
+
+ $self->{'os-plugin-engine'} = shift;
+ $self->{'distro'} = shift;
+
+ weaken($self->{'os-plugin-engine'});
+ # avoid circular reference between plugin and its engine
+
+ return;
+}
+
+=item getInfo()
+
+Returns a hash-ref with administrative information about this plugin (what does
+it do and how does it relate to other plugins). Every plugin needs to provide
+this method and return the information about itself.
+
+The returned hash-ref must include at least the following entries:
+
+=over
+
+=item B<description>
+
+Explains the purpose of this plugins.
+
+=item B<precedence>
+
+Specifies the execution precedence of this plugin with respect to all other
+plugins (plugins with lower precedences will be started before the ones with
+a higher precedence).
+
+Valid values range from 0-99. If your plugin does not have any requirements
+in this context, just specify the default value '50'.
+
+=item B<required>
+
+Specifies the list of plugins that are required by this plugin.
+
+Before any plugin can be installed, all other plugins that are required by it
+must have been installed.
+
+=back
+
+=cut
+
+sub getInfo
+{
+ my $self = shift;
+
+ return {
+ # a short (one-liner) description of this plugin
+ description => '',
+ };
+}
+
+=item getAttrInfo()
+
+Returns a hash-ref with information about all attributes supported by this
+specific plugin.
+
+This default configuration will be added as attributes to the default system,
+such that it can be overruled for any specific system by means of B<slxconfig>.
+
+The returned hash-ref must include at least the following entries:
+
+=over
+
+=item B<I<plugin-name>::active>
+
+Indicates whether or not this plugin is active (1 for active, 0 for inactive).
+
+=back
+
+=cut
+
+sub getAttrInfo
+{
+ my $self = shift;
+
+ # This default configuration will be added as attributes to the default
+ # system, such that it can be overruled for any specific system by means
+ # of slxconfig.
+ return {
+ # attribute 'active' is mandatory for all plugins
+ };
+}
+
+=item getDefaultAttrsForVendorOS()
+
+Returns a hash-ref with the default attribute values for the given vendor-OS.
+
+=cut
+
+sub getDefaultAttrsForVendorOS
+{
+ my $self = shift;
+
+ # the default implementation does not change the default values at all:
+ return $self->getAttrInfo();
+}
+
+=item checkStage3AttrValues()
+
+Checks if the stage3 values given in B<$stage3Attrs> are allowed and make sense.
+
+This method returns an array-ref of problems found. If there were no problems,
+this methods returns undef.
+
+Plugins may override this implementation to do checks that for instance look
+at the stage1 vendor-OS-attributes given in B<$vendorOSAttrs>.
+
+N.B.: this method is called while being chrooted into the vendor-OS, so it
+ may invoke all distro methods that expect to be run in this environment,
+ too
+
+=cut
+
+sub checkStage3AttrValues
+{
+ my $self = shift;
+ my $stage3Attrs = shift;
+ my $vendorOSAttrs = shift;
+
+ # this default implementation does no further checks (thus relying on the
+ # attributte regex check that is done in the AttributeRoster)
+ return;
+}
+
+=item dependsOnPlugin()
+
+=cut
+
+sub dependsOnPlugin
+{
+ my $self = shift;
+ my $otherName = shift;
+
+ if (!defined $self->{dependsOn}) {
+ my @dependsOn = $self->_determineAllPluginsWeDependOn();
+ $self->{dependsOn} = \@dependsOn;
+ }
+
+ return grep { $_ eq $otherName } @{$self->{dependsOn}};
+}
+
+=back
+
+=head2 Vendor-OS Interface
+
+=over
+
+=item installationPhase()
+
+In this method, the plugin should install itself into the given vendor-OS.
+
+What "installation" means is up to the plugin. Some plugins may just copy
+a file from the OpenSLX host installation into the vendor-OS, while others may
+need to download files from the internet and/or install packages through the
+vendor-OS' meta packager.
+
+N.B.: This method is invoked while chrooted into the vendor-OS root.
+
+The hash-ref given in B<$info> contains vital information for the installation
+process:
+
+=over
+
+=item C<plugin-repo-path>
+
+The folder where the stage1-plugin should store all files required by the
+corresponding stage3 runlevel script.
+
+=item C<plugin-temp-path>
+
+A temporary playground that will be cleaned up automatically.
+
+=item C<openslx-base-path>
+
+In order to make the OpenSLX files from the host available, the OpenSLX base
+folder (normally /opt/openslx) will be mounted into the chroot.
+So if you have to copy any files from the host, fetch them from this path.
+
+=item C<openslx-config-path>
+
+In order to make the OpenSLX config files from the host available, the OpenSLX
+config folder (normally /etc/opt/openslx) will be mounted into the chroot.
+So if you have to copy any config files from the host, fetch them from this
+path.
+
+=item C<plugin-attrs>
+
+Contains the attributes in effect for the installation of this plugin.
+
+=back
+
+=cut
+
+sub installationPhase
+{
+ my $self = shift;
+ my $info = shift;
+
+ return;
+}
+
+=item removalPhase()
+
+In this method, the plugin should remove itself from the given vendor-OS.
+
+What "removal" means is up to the plugin. Some plugins may just delete
+a file from the vendor-OS, while others may need to uninstall packages through
+the vendor-OS' meta packager.
+
+N.B.: This method is invoked while chrooted into the vendor-OS root.
+
+The hash-ref given in B<$info> contains vital information for the installation
+process:
+
+=over
+
+=item C<plugin-repo-path>
+
+The folder where the stage1-plugin should store all files required by the
+corresponding stage3 runlevel script.
+
+=item C<plugin-temp-path>
+
+A temporary playground that will be cleaned up automatically.
+
+=item C<openslx-base-path>
+
+In order to make the OpenSLX files from the host available, the OpenSLX base
+folder (normally /opt/openslx) will be mounted into the chroot.
+So if you have to copy any files from the host, fetch them from this path.
+
+=item C<openslx-config-path>
+
+In order to make the OpenSLX config files from the host available, the OpenSLX
+config folder (normally /etc/opt/openslx) will be mounted into the chroot.
+So if you have to copy any config files from the host, fetch them from this
+path.
+
+=item C<plugin-attrs>
+
+Contains the attributes in effect for the installation of this plugin.
+
+=back
+
+=cut
+
+sub removalPhase
+{
+ my $self = shift;
+ my $info = shift;
+
+ return;
+}
+
+=item preInstallationPhase()
+
+In this method, any preparations for installation of the plugin into a vendor-OS
+should be executed. As this method is being called immediately before the chroot
+is entered, this is the last/only chance to copy any files into the chroot that
+are required from within (in installationPhase()).
+
+The given parameters are similar to the ones for installationPhase(), except
+that all paths are now relative to the root-fs instead of being relative to the
+chroot (i.e. the paths are ready to be used from outside the chroot):
+
+A "exit 1;" will result in a not installed plugin.
+
+=over
+
+=item C<plugin-repo-path>
+
+The folder where the stage1-plugin should store all files required by the
+corresponding stage3 runlevel script.
+
+=item C<plugin-temp-path>
+
+A temporary playground that will be cleaned up automatically.
+
+If a plugin needs to unpack any archives, these archives should be copied to
+this folder (as it will be cleaned automatically).
+
+=item C<openslx-base-path>
+
+In order to make the OpenSLX files from the host available, the OpenSLX base
+folder (normally /opt/openslx) will be mounted into the chroot.
+So if you have to copy any files from the host, fetch them from this path.
+
+=item C<openslx-config-path>
+
+In order to make the OpenSLX config files from the host available, the OpenSLX
+config folder (normally /etc/opt/openslx) will be mounted into the chroot.
+So if you have to copy any config files from the host, fetch them from this
+path.
+
+=item C<plugin-attrs>
+
+Contains the attributes in effect for the installation of this plugin.
+
+=item C<vendor-os-path>
+
+Contains the path to the vendor-OS into which the plugin will be installed.
+
+=back
+
+=cut
+
+sub preInstallationPhase
+{
+ my $self = shift;
+ my $info = shift;
+
+ return;
+}
+
+=item postRemovalPhase()
+
+In this method, any plugin has the chance to do any necessary cleanup that
+must be executed outside of the chroot.
+
+This method is invoked immediately after leaving the chroot into the vendor-OS
+root, but before the plugin-temp-path has been cleaned up. So if required, any
+files could be copied out of the temp-path somewhere into the root-fs.
+
+The given parameters are similar to the ones for removalPhase(), except that all
+paths are now relative to the root-fs instead of being relative to the chroot
+(i.e. the paths are ready to be used from outside the chroot):
+
+=over
+
+=item C<plugin-repo-path>
+
+The folder where the stage1-plugin should store all files required by the
+corresponding stage3 runlevel script.
+
+=item C<plugin-temp-path>
+
+A temporary playground that will be cleaned up automatically.
+
+=item C<openslx-base-path>
+
+In order to make the OpenSLX files from the host available, the OpenSLX base
+folder (normally /opt/openslx) will be mounted into the chroot.
+So if you have to copy any files from the host, fetch them from this path.
+
+=item C<openslx-config-path>
+
+In order to make the OpenSLX config files from the host available, the OpenSLX
+config folder (normally /etc/opt/openslx) will be mounted into the chroot.
+So if you have to copy any config files from the host, fetch them from this
+path.
+
+=item C<plugin-attrs>
+
+Contains the attributes in effect for the installation of this plugin.
+
+=item C<vendor-os-path>
+
+Contains the path to the vendor-OS from which the plugin has been removed.
+
+=back
+
+=cut
+
+sub postRemovalPhase
+{
+ my $self = shift;
+ my $info = shift;
+
+ return;
+}
+
+=back
+
+=head2 Initramfs Interface
+
+All of the following methods are invoked by the config demuxer when it makes an
+initramfs for a system that has this plugin activated. Through these methods,
+each plugin can integrate itself into that initramfs.
+
+=over
+
+=item suggestAdditionalKernelParams()
+
+Called in order to give the plugin a chance to add any kernel params it
+requires.
+
+In order to do so, the plugin should return a list of additional kernel params
+that it would like to see added.
+
+=cut
+
+sub suggestAdditionalKernelParams
+{
+ my $self = shift;
+ my $makeInitRamFSEngine = shift;
+
+ return;
+}
+
+=item suggestAdditionalKernelModules()
+
+Called in order to give the plugin a chance to add any kernel modules it
+requires.
+
+In order to do so, the plugin should return the names of additional kernel
+modules that it would like to see added.
+
+=cut
+
+sub suggestAdditionalKernelModules
+{
+ my $self = shift;
+ my $makeInitRamFSEngine = shift;
+ my $attrs = shift;
+
+ return;
+}
+
+=item copyRequiredFilesIntoInitramfs()
+
+Called in order to give the plugin a chance to copy all required files from the
+vendor-OS into the initramfs.
+
+N.B.: Only files that are indeed required by the initramfs should be copied
+here, i.e. files that are needed *before* the root-fs has been mounted.
+All other files should be taken from the root-fs instead!
+
+=cut
+
+sub copyRequiredFilesIntoInitramfs
+{
+ my $self = shift;
+ my $targetPath = shift;
+ my $attrs = shift;
+ my $makeInitRamFSEngine = shift;
+
+ return;
+}
+
+=item setupPluginInInitramfs()
+
+Called in order to let the plugin setup all the files it requires in the
+initramfs.
+
+Normally, you don't need to override this method in your own plugin,
+as it is usually enough to override suggestAdditionalKernelParams(),
+suggestAdditionalKernelModules() and maybe copyRequiredFilesIntoInitramfs().
+
+=cut
+
+sub setupPluginInInitramfs
+{
+ my $self = shift;
+ my $attrs = shift;
+ my $makeInitRamFSEngine = shift;
+
+ my $pluginName = $self->{name};
+ my $pluginSrcPath = "$openslxConfig{'base-path'}/lib/plugins";
+ my $buildPath = $makeInitRamFSEngine->{'build-path'};
+ my $pluginInitdPath = "$buildPath/etc/plugin-init.d";
+ my $initHooksPath = "$buildPath/etc/init-hooks";
+
+ # copy runlevel script
+ my $precedence = sprintf('%02d', $self->getInfo()->{precedence});
+ my $scriptName = "$pluginSrcPath/$pluginName/XX_${pluginName}.sh";
+ my $targetName = "$pluginInitdPath/${precedence}_${pluginName}.sh";
+ if (-e $scriptName) {
+ $makeInitRamFSEngine->addCMD("cp $scriptName $targetName");
+ $makeInitRamFSEngine->addCMD("chmod a+x $targetName");
+ }
+
+ # copy init hook scripts, if any
+ if (-d "$pluginSrcPath/$pluginName/init-hooks") {
+ my $hookSrcPath = "$pluginSrcPath/$pluginName/init-hooks";
+ $makeInitRamFSEngine->addCMD(
+ "cp -r $hookSrcPath/* $buildPath/etc/init-hooks/"
+ );
+ }
+
+ # invoke hook methods to suggest additional kernel params ...
+ my @suggestedParams
+ = $self->suggestAdditionalKernelParams($makeInitRamFSEngine);
+ if (@suggestedParams) {
+ my $params = join ' ', @suggestedParams;
+ vlog(1, "plugin $pluginName suggests these kernel params: $params");
+ $makeInitRamFSEngine->addKernelParams(@suggestedParams);
+ }
+
+ # ... and kernel modules
+ my @suggestedModules
+ = $self->suggestAdditionalKernelModules($makeInitRamFSEngine, $attrs);
+ if (@suggestedModules) {
+ my $modules = join(',', @suggestedModules);
+ vlog(1, "plugin $pluginName suggests these kernel modules: $modules");
+ $makeInitRamFSEngine->addKernelModules(@suggestedModules);
+ }
+
+ # invoke hook method to copy any further files that are required in stage3
+ # before the root-fs has been mounted
+ $self->copyRequiredFilesIntoInitramfs(
+ $buildPath, $attrs, $makeInitRamFSEngine
+ );
+
+ return 1;
+}
+
+sub _determineAllPluginsWeDependOn
+{
+ my $self = shift;
+ my $seen = shift || {};
+
+ return if $seen->{$self->{name}};
+ $seen->{$self->{name}} = 1;
+
+ my %dependsOn;
+ if ($self->getInfo()->{required}) {
+ @dependsOn{@{$self->getInfo()->{required}}} = ();
+ }
+
+ foreach my $depName (keys %dependsOn) {
+ my $depPlugin = OpenSLX::OSPlugin::Roster->getPlugin($depName);
+ my @subDeps = $depPlugin->_determineAllPluginsWeDependOn($seen);
+ @dependsOn{@subDeps} = ();
+ }
+
+ return keys %dependsOn;
+}
+
+=back
+
+1;
diff --git a/src/os-plugins/OpenSLX/OSPlugin/Engine.pm b/src/os-plugins/OpenSLX/OSPlugin/Engine.pm
new file mode 100644
index 00000000..25827205
--- /dev/null
+++ b/src/os-plugins/OpenSLX/OSPlugin/Engine.pm
@@ -0,0 +1,857 @@
+# Copyright (c) 2007, 2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# Engine.pm
+# - provides driver engine for the OSPlugin API.
+# -----------------------------------------------------------------------------
+package OpenSLX::OSPlugin::Engine;
+
+use strict;
+use warnings;
+
+our $VERSION = 1.01; # API-version . implementation-version
+
+use Config;
+use File::Basename;
+use File::Path;
+use Storable;
+
+use OpenSLX::Basics;
+use OpenSLX::OSPlugin::Roster;
+use OpenSLX::OSSetup::Engine;
+use OpenSLX::ScopedResource;
+use OpenSLX::Utils;
+
+=head1 NAME
+
+OpenSLX::OSPlugin::Engine - driver class for plugin handling.
+
+=head1 DESCRIPTION
+
+This class works as a driver for the installation/removal of plugins
+into/from a vendor.
+
+Additionally, it provides the OS-Plugin support interface.
+
+=head1 PUBLIC METHODS
+
+=over
+
+=item new()
+
+Trivial constructor
+
+=cut
+
+sub new
+{
+ my $class = shift;
+
+ my $self = {};
+
+ return bless $self, $class;
+}
+
+=item initialize($pluginName, $vendorOSName )
+
+Sets up basic data (I<$pluginName> and I<$vendorOSName>) as well as paths and
+loads plugin.
+
+=cut
+
+sub initialize
+{
+ my $self = shift;
+ my $pluginName = shift;
+ my $vendorOSName = shift;
+ my $givenAttrs = shift || {};
+
+ $self->{'vendor-os-name'} = $vendorOSName;
+
+ $self->{'vendor-os-path'}
+ = "$openslxConfig{'private-path'}/stage1/$vendorOSName";
+ vlog(2, "vendor-OS path is '$self->{'vendor-os-path'}'");
+
+ if ($pluginName) {
+ $self->{'plugin-name'} = $pluginName;
+ $self->{'plugin-path'}
+ = "$openslxConfig{'base-path'}/lib/plugins/$pluginName";
+ vlog(1, "plugin path is '$self->{'plugin-path'}'");
+
+ $self->{'plugin'} = $self->_loadPlugin();
+ return if !$self->{'plugin'};
+
+ $self->{'chrooted-plugin-repo-path'}
+ = "$openslxConfig{'base-path'}/plugin-repo/$self->{'plugin-name'}";
+ $self->{'plugin-repo-path'}
+ = "$self->{'vendor-os-path'}/$self->{'chrooted-plugin-repo-path'}";
+ $self->{'chrooted-plugin-temp-path'}
+ = "/tmp/slx-plugin/$self->{'plugin-name'}";
+ $self->{'plugin-temp-path'}
+ = "$self->{'vendor-os-path'}/$self->{'chrooted-plugin-temp-path'}";
+ $self->{'chrooted-openslx-base-path'} = '/mnt/opt/openslx';
+ $self->{'chrooted-openslx-config-path'} = '/mnt/etc/opt/openslx';
+
+ # merge attributes that were given on cmdline with the ones that
+ # already exist in the DB and finally with the default values
+ $self->{'plugin-attrs'} = { %$givenAttrs };
+ my $defaultAttrs = $self->{plugin}->getDefaultAttrsForVendorOS(
+ $vendorOSName
+ );
+ my $dbAttrs = $self->_fetchInstalledPluginAttrs($vendorOSName);
+ for my $attrName (keys %$defaultAttrs) {
+ next if exists $givenAttrs->{$attrName};
+ $self->{'plugin-attrs'}->{$attrName}
+ = exists $dbAttrs->{$attrName}
+ ? $dbAttrs->{$attrName}
+ : $defaultAttrs->{$attrName}->{default};
+ }
+ $self->{'vendorOS-attrs'} = $dbAttrs;
+ }
+
+ return 1;
+}
+
+=back
+
+=head2 Driver Interface
+
+The following methods are invoked by the slxos-plugin script in order to
+install/remove a plugin into/from a vendor-OS:
+
+=over
+
+=item installPlugin()
+
+Invokes the plugin's installer method while chrooted into that vendor-OS.
+
+=cut
+
+sub installPlugin
+{
+ my $self = shift;
+
+ $self->_checkIfRequiredPluginsAreInstalled();
+
+ # look for unknown attributes
+ my $attrs = $self->{'plugin-attrs'};
+ my $attrInfos = $self->{plugin}->getAttrInfo();
+ my @unknownAttrs = grep { !exists $attrInfos->{$_} } keys %$attrs;
+ if (@unknownAttrs) {
+ die _tr(
+ "The plugin '%s' does not support these attributes:\n\t%s",
+ $self->{'plugin-name'}, join(',', @unknownAttrs)
+ );
+ }
+
+ # check all attr-values against the regex of the attribute (if any)
+ my @attrProblems;
+ foreach my $attr (keys %$attrs) {
+ my $value = $attrs->{$attr};
+ next if !defined $value;
+ my $attrInfo = $attrInfos->{$attr};
+ my $regex = $attrInfo->{content_regex};
+ if ($regex && $value !~ $regex) {
+ push @attrProblems, _tr(
+ "the value '%s' for attribute %s is not allowed.\nAllowed values are: %s",
+ $value, $attr, $attrInfo->{content_descr}
+ );
+ }
+ }
+
+ if (@attrProblems) {
+ my $complaint = join "\n", @attrProblems;
+ die $complaint;
+ }
+
+ if ($self->{'vendor-os-name'} ne '<<<default>>>') {
+
+ # as the attrs may be changed by the plugin during installation, we
+ # have to find a way to pass them back to this process (remember:
+ # installation takes place in a forked process in order to do a chroot).
+ # We simply serialize the attributes into a temp file and deserialize
+ # it in the calling process.
+ my $serializedAttrsFile
+ = "$self->{'plugin-temp-path'}/serialized-attrs";
+ my $chrootedSerializedAttrsFile
+ = "$self->{'chrooted-plugin-temp-path'}/serialized-attrs";
+
+ rmtree([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]);
+ mkpath([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]);
+
+ # invoke plugin and let it prepare the installation
+ $self->{plugin}->preInstallationPhase( {
+ 'plugin-repo-path' => $self->{'plugin-repo-path'},
+ 'plugin-temp-path' => $self->{'plugin-temp-path'},
+ 'openslx-base-path' => $openslxConfig{'base-path'},
+ 'openslx-config-path' => $openslxConfig{'config-path'},
+ 'plugin-attrs' => $self->{'plugin-attrs'},
+ 'vendor-os-path' => $self->{'vendor-os-path'},
+ } );
+
+ # HACK: do a dummy serialization here in order to get Storable
+ # completely loaded (otherwise it will complain in the chroot about
+ # missing modules).
+ store $self->{'plugin-attrs'}, $serializedAttrsFile;
+
+ $self->_callChrootedFunctionForPlugin(
+ sub {
+ # invoke plugin and let it install itself into vendor-OS
+ $self->{plugin}->installationPhase( {
+ 'plugin-repo-path'
+ => $self->{'chrooted-plugin-repo-path'},
+ 'plugin-temp-path'
+ => $self->{'chrooted-plugin-temp-path'},
+ 'openslx-base-path'
+ => $self->{'chrooted-openslx-base-path'},
+ 'openslx-config-path'
+ => $self->{'chrooted-openslx-config-path'},
+ 'plugin-attrs'
+ => $self->{'plugin-attrs'},
+ } );
+
+ # serialize possibly changed attributes (executed inside chroot)
+ store $self->{'plugin-attrs'}, $chrootedSerializedAttrsFile;
+ }
+ );
+
+ # now retrieve (deserialize) the current attributes and store them
+ $self->{'plugin-attrs'} = retrieve $serializedAttrsFile;
+
+ # cleanup temp path
+ rmtree([ $self->{'plugin-temp-path'} ]);
+
+ # now update the vendorOS-attrs and let the plugin itself check the
+ # stage3 attrs
+ $self->{'vendorOS-attrs'} = $self->{'plugin-attrs'};
+ $self->checkStage3AttrValues(
+ $self->{'plugin-attrs'}, \@attrProblems
+ );
+ if (@attrProblems) {
+ my $complaint = join "\n", @attrProblems;
+ die $complaint;
+ }
+ }
+
+ $self->_addInstalledPluginToDB();
+
+ return 1;
+}
+
+=item removePlugin()
+
+Invokes the plugin's removal method while chrooted into that vendor-OS.
+
+=cut
+
+sub removePlugin
+{
+ my $self = shift;
+
+ $self->_checkIfPluginIsRequiredByOthers();
+
+ if ($self->{'vendor-os-name'} ne '<<<default>>>') {
+
+ mkpath([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]);
+
+ $self->_callChrootedFunctionForPlugin(
+ sub {
+ $self->{plugin}->removalPhase( {
+ 'plugin-repo-path'
+ => $self->{'chrooted-plugin-repo-path'},
+ 'plugin-temp-path'
+ => $self->{'chrooted-plugin-temp-path'},
+ 'openslx-base-path'
+ => $self->{'chrooted-openslx-base-path'},
+ 'openslx-config-path'
+ => $self->{'chrooted-openslx-config-path'},
+ 'plugin-attrs'
+ => $self->{'plugin-attrs'},
+ } );
+ }
+ );
+
+ # invoke plugin and let it prepare the installation
+ $self->{plugin}->postRemovalPhase( {
+ 'plugin-repo-path' => $self->{'plugin-repo-path'},
+ 'plugin-temp-path' => $self->{'plugin-temp-path'},
+ 'openslx-base-path' => $openslxConfig{'base-path'},
+ 'openslx-config-path' => $openslxConfig{'config-path'},
+ 'plugin-attrs' => $self->{'plugin-attrs'},
+ 'vendor-os-path' => $self->{'vendor-os-path'},
+ } );
+
+ rmtree([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]);
+ }
+
+ $self->_removeInstalledPluginFromDB();
+
+ return 1;
+}
+
+=item getInstalledPlugins()
+
+Returns the list of names of the plugins that are installed into the current
+vendor-OS.
+
+=cut
+
+sub getInstalledPlugins
+{
+ my $self = shift;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ my @installedPlugins = $openslxDB->fetchInstalledPlugins($vendorOSID);
+ $openslxDB->disconnect();
+
+ return @installedPlugins;
+}
+
+=back
+
+=head2 Support Interface
+
+This is the plugin support interface for OS-plugins, which represents the
+connection between a plugin's implementation and the rest of the OpenSLX system.
+
+Plugin implementations are meant to use this interface in order to find
+out details about the current vendor-OS or download files or install packages.
+
+=over
+
+=item vendorOSName()
+
+Returns the name of the current vendor-OS.
+
+=cut
+
+sub vendorOSName
+{
+ my $self = shift;
+
+ return $self->{'vendor-os-name'};
+}
+
+=item distroName()
+
+Returns the name of the distro that the current vendor-OS is based on.
+
+Each distro name always consists of the distro type, a dash and the
+distro version, like 'suse-10.2' or 'ubuntu-7.04'.
+
+=cut
+
+sub distroName
+{
+ my $self = shift;
+
+ return $self->_osSetupEngine()->distroName();
+}
+
+=item downloadFile($fileURL, $targetPath, $wgetOptions)
+
+Invokes busybox's wget to download a file from the given URL.
+
+=over
+
+=item I<$fileURL>
+
+The URL of the file to download.
+
+=item I<$targetPath> [optional]
+
+The directory where the file should be downloaded into. The default is the
+current plugin's temp directory.
+
+=item I<$wgetOptions> [optional]
+
+Any other options you'd like to pass to wget.
+
+=item I<Return Value>
+
+If the downloaded was successful this method returns C<1>, otherwise it dies.
+
+=back
+
+=cut
+
+sub downloadFile
+{
+ my $self = shift;
+ my $fileURL = shift || return;
+ my $targetPath = shift || $self->{'chrooted-plugin-temp-path'};
+ my $wgetOptions = shift || '';
+
+ my $busybox = $self->_osSetupEngine()->busyboxBinary();
+
+ if (slxsystem("$busybox wget -P $targetPath $wgetOptions $fileURL")) {
+ die _tr('unable to download file "%s"! (%s)', $fileURL, $!);
+ }
+
+ return 1;
+}
+
+=item getInstalledPackages()
+
+Returns the list of names of the packages (as an array) that are already
+installed in the vendor-OS.
+Useful if a plugin wants to find out whether or not it has to
+install additional packages.
+
+=cut
+
+sub getInstalledPackages
+{
+ my $self = shift;
+
+ my $packager = $self->_osSetupEngine()->packager();
+ return if !$packager;
+
+ return $packager->getInstalledPackages();
+}
+
+=item getInstallablePackagesForSelection()
+
+Looks at the selection with the given name and returns the list of names of the
+packages (as one string separated by spaces) that need to be installed in order
+to complete the selection.
+
+=cut
+
+sub getInstallablePackagesForSelection
+{
+ my $self = shift;
+ my $selection = shift;
+
+ return $self->_osSetupEngine()->getInstallablePackagesForSelection(
+ $selection
+ );
+}
+
+=item installPackages($packages)
+
+Installs the given packages into the vendor-OS.
+
+N.B: Since this method uses the meta-packager of the vendor-OS, package
+dependencies will be determined and solved automatically.
+
+=over
+
+=item I<$packages>
+
+Contains a list of package names (separated by spaces) that shall be installed.
+
+=item I<Return Value>
+
+If the packages have been installed successfully this method return 1,
+otherwise it dies.
+
+=back
+
+=cut
+
+sub installPackages
+{
+ my $self = shift;
+ my $packages = shift;
+
+ return if !$packages;
+
+ my $metaPackager = $self->_osSetupEngine()->metaPackager();
+ return if !$metaPackager;
+
+ return $metaPackager->installPackages($packages, 1);
+}
+
+=item removePackages($packages)
+
+Removes the given packages from the vendor-OS.
+
+=over
+
+=item I<$packages> [ARRAY-ref]
+
+Contains a list of package names (separated by spaces) that shall be removed.
+
+=item I<Return Value>
+
+If the packages have been removed successfully this method return 1,
+otherwise it dies.
+
+=back
+
+=cut
+
+sub removePackages
+{
+ my $self = shift;
+ my $packages = shift;
+
+ return if !$packages;
+
+ my $metaPackager = $self->_osSetupEngine()->metaPackager();
+ return if !$metaPackager;
+
+ return $metaPackager->removePackages($packages);
+}
+
+=back
+
+=head2 Driver Interface
+
+The following methods are invoked by the slxos-plugin script in order to
+install/remove a plugin into/from a vendor-OS:
+
+=over
+
+=item checkStage3AttrValues()
+
+Checks if the stage3 values given in B<$stage3Attrs> are allowed and make sense.
+
+This method gets also invoked whenever changes by slxconfig were made (passing
+in only the stage3 attributes the user tried to change) and by the config
+demuxer (passing in all stage3 attributes for the system currently being
+demuxed).
+
+If all values are ok, this method returns 1 - if not, it extends the given
+problems array-ref with the problems that were found (and returns undef).
+
+This method chroots into the vendor-OS and then asks the plugin itself to check
+the attributes.
+
+=cut
+
+sub checkStage3AttrValues
+{
+ my $self = shift;
+ my $stage3Attrs = shift;
+ my $problemsOut = shift;
+
+ # we have to pass any problems back to this process (remember:
+ # installation takes place in a forked process in order to do a chroot).
+ # We simply serialize the problems into a temp file and deserialize
+ # it in the calling process.
+ my $serializedProblemsFile
+ = "$self->{'plugin-temp-path'}/serialized-problems";
+ my $chrootedSerializedProblemsFile
+ = "$self->{'chrooted-plugin-temp-path'}/serialized-problems";
+
+ mkpath([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]);
+
+ # HACK: do a dummy serialization here in order to get Storable
+ # completely loaded (otherwise it will complain in the chroot about
+ # missing modules).
+ store [], $serializedProblemsFile;
+
+ $self->_callChrootedFunctionForPlugin(
+ sub {
+ # let plugin check by itself
+ my $problems = $self->{plugin}->checkStage3AttrValues(
+ $stage3Attrs, $self->{'vendorOS-attrs'}
+ );
+
+ # serialize list of problems (executed inside chroot)
+ store($problems, $chrootedSerializedProblemsFile) if $problems;
+ }
+ );
+
+ # now retrieve (deserialize) the found problems and pass them on
+ my $problems = retrieve $serializedProblemsFile;
+ rmtree([ $self->{'plugin-temp-path'} ]);
+ if ($problems && ref($problems) eq 'ARRAY' && @$problems) {
+ push @$problemsOut, @$problems;
+ return;
+ }
+
+ return 1;
+}
+
+=back
+
+=cut
+
+sub _loadPlugin
+{
+ my $self = shift;
+
+ my $pluginModule = "OpenSLX::OSPlugin::$self->{'plugin-name'}";
+ my $plugin = instantiateClass(
+ $pluginModule, {
+ acceptMissing => 1,
+ pathToClass => $self->{'plugin-path'},
+ }
+ );
+ return if !$plugin;
+
+ # if there's a distro folder, instantiate the most appropriate distro class
+ my $distro;
+ if ($self->{'vendor-os-name'} ne '<<<default>>>'
+ && -d "$self->{'plugin-path'}/OpenSLX/Distro") {
+ my $pluginBasePath = "$openslxConfig{'base-path'}/lib/plugins";
+ my $distroScope = $plugin->{name} . '::OpenSLX::Distro';
+ $distro = loadDistroModule({
+ distroName => $self->distroName(),
+ distroScope => $distroScope,
+ pathToClass => $pluginBasePath,
+ });
+ if (!$distro) {
+ die _tr(
+ 'unable to load any distro module for vendor-OS %s in plugin %s',
+ $self->{'vendor-os-name'}, $plugin->{name}
+ );
+ }
+ $distro->initialize($self);
+ }
+
+ $plugin->initialize($self, $distro);
+
+ return $plugin;
+}
+
+sub _callChrootedFunctionForPlugin
+{
+ my $self = shift;
+ my $function = shift;
+
+ # create os-setup engine here in order to block access to the vendor-OS
+ # via other processes (which could cause problems)
+ my $osSetupEngine = $self->_osSetupEngine();
+
+ my @bindmounts;
+ my @chrootPerlIncludes;
+
+ # setup list of perl modules we want to bind into chroot
+ push @chrootPerlIncludes, "/mnt/opt/openslx/lib";
+
+ push @bindmounts, {
+ 'source' => $Config{privlibexp},
+ 'target' => "$self->{'vendor-os-path'}/mnt/perl/privlibexp"
+ };
+ push @chrootPerlIncludes, "/mnt/perl/privlibexp";
+ push @bindmounts, {
+ 'source' => $Config{archlibexp},
+ 'target' => "$self->{'vendor-os-path'}/mnt/perl/archlibexp"
+ };
+ push @chrootPerlIncludes, "/mnt/perl/archlibexp";
+ push @bindmounts, {
+ 'source' => $Config{vendorlibexp},
+ 'target' => "$self->{'vendor-os-path'}/mnt/perl/vendorlibexp"
+ };
+ push @chrootPerlIncludes, "/mnt/perl/vendorlibexp";
+ push @bindmounts, {
+ 'source' => $Config{vendorarchexp},
+ 'target' => "$self->{'vendor-os-path'}/mnt/perl/vendorarchexp"
+ };
+ push @chrootPerlIncludes, "/mnt/perl/vendorarchexp";
+
+ # prepare openslx bind mounts
+ push @bindmounts, {
+ 'source' => $openslxConfig{'base-path'},
+ 'target' => "$self->{'vendor-os-path'}/mnt/opt/openslx"
+ };
+ push @bindmounts, {
+ 'source' => $openslxConfig{'config-path'},
+ 'target' => "$self->{'vendor-os-path'}/mnt/etc/opt/openslx"
+ };
+
+ # create mountpoints
+ foreach (@bindmounts) {
+ mkpath($_->{'target'});
+ }
+
+ my $pluginSession = OpenSLX::ScopedResource->new({
+ name => 'osplugin::session',
+ acquire => sub {
+ # bind mount perl includes, openslx base and config paths into vendor-OS
+ foreach (@bindmounts) {
+ slxsystem("mount -o bind $_->{'source'} $_->{'target'}") == 0
+ or die _tr(
+ "unable to bind mount '%s' to '%s'! (%s)",
+ $_->{'source'}, $_->{'target'}, $!
+ );
+ }
+
+ # add mounted perl includes to @INC
+ foreach (@chrootPerlIncludes) {
+ unshift @INC, $_;
+ }
+ 1
+ },
+ release => sub {
+ # cleanup @INC again
+ while (my $perlinc = pop(@chrootPerlIncludes)) {
+ if ($INC[0] eq $perlinc) {
+ shift @INC;
+ }
+ }
+
+ # unmount bindmounts
+ foreach (@bindmounts) {
+ slxsystem("umount $_->{'target'}") == 0
+ or die _tr(
+ "unable to umount '%s'! (%s)",
+ $_->{'target'}, $!
+ );
+ }
+ 1
+ },
+ });
+
+ # now let plugin install itself into vendor-OS
+ $osSetupEngine->callChrootedFunctionForVendorOS($function);
+
+ return;
+}
+
+sub _addInstalledPluginToDB
+{
+ my $self = shift;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ $openslxDB->addInstalledPlugin(
+ $vendorOSID, $self->{'plugin-name'}, $self->{'plugin-attrs'}
+ );
+ $openslxDB->disconnect();
+
+ return 1;
+}
+
+sub _checkIfRequiredPluginsAreInstalled
+{
+ my $self = shift;
+
+ my $requiredPlugins = $self->{plugin}->getInfo()->{required} || [];
+ return 1 if !@$requiredPlugins;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ my @installedPlugins = $openslxDB->fetchInstalledPlugins($vendorOSID);
+ $openslxDB->disconnect();
+
+ my @missingPlugins
+ = grep {
+ my $required = $_;
+ ! grep { $_->{plugin_name} eq $required } @installedPlugins;
+ }
+ @$requiredPlugins;
+
+ if (@missingPlugins) {
+ die _tr(
+ 'the plugin "%s" requires the following plugins to be installed first: "%s"!',
+ $self->{'plugin-name'}, join(',', @missingPlugins)
+ );
+ }
+
+ return 1;
+}
+
+sub _checkIfPluginIsRequiredByOthers
+{
+ my $self = shift;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ my @installedPlugins = $openslxDB->fetchInstalledPlugins($vendorOSID);
+ $openslxDB->disconnect();
+
+ my @lockingPlugins
+ = grep {
+ my $installed
+ = OpenSLX::OSPlugin::Roster->getPlugin($_->{plugin_name});
+ my $requiredByInstalled
+ = $installed
+ ? ($installed->getInfo()->{required} || [])
+ : [];
+ grep { $_ eq $self->{'plugin-name'} } @$requiredByInstalled;
+ }
+ @installedPlugins;
+
+ if (@lockingPlugins) {
+ die _tr(
+ 'the plugin "%s" is required by the following plugins: "%s"!',
+ $self->{'plugin-name'},
+ join(',', map { $_->{plugin_name} } @lockingPlugins)
+ );
+ }
+
+ return 1;
+}
+
+sub _fetchInstalledPluginAttrs
+{
+ my $self = shift;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ my $installedPlugin = $openslxDB->fetchInstalledPlugins(
+ $vendorOSID, $self->{'plugin-name'}
+ );
+ $openslxDB->disconnect();
+
+ return {} if !$installedPlugin;
+ return $installedPlugin->{attrs};
+}
+
+sub _removeInstalledPluginFromDB
+{
+ my $self = shift;
+
+ my $openslxDB = instantiateClass("OpenSLX::ConfigDB");
+ $openslxDB->connect();
+ my $vendorOSID = $self->_fetchVendorOSID($openslxDB);
+ $openslxDB->removeInstalledPlugin($vendorOSID, $self->{'plugin-name'});
+ $openslxDB->disconnect();
+
+ return 1;
+}
+
+sub _fetchVendorOSID
+{
+ my $self = shift;
+ my $openslxDB = shift;
+
+ if ($self->{'vendor-os-name'} eq '<<<default>>>') {
+ return 0;
+ }
+
+ my $vendorOS = $openslxDB->fetchVendorOSByFilter( {
+ name => $self->{'vendor-os-name'},
+ } );
+ if (!$vendorOS) {
+ die _tr(
+ 'unable to find vendor-OS "%s" in DB!', $self->{'vendor-os-name'}
+ );
+ }
+
+ return $vendorOS->{id};
+}
+
+sub _osSetupEngine
+{
+ my $self = shift;
+
+ if (!$self->{'ossetup-engine'}) {
+ # create ossetup-engine for given vendor-OS:
+ my $osSetupEngine = OpenSLX::OSSetup::Engine->new;
+ $osSetupEngine->initialize($self->{'vendor-os-name'}, 'plugin');
+ $self->{'ossetup-engine'} = $osSetupEngine;
+ }
+
+ return $self->{'ossetup-engine'};
+}
+
+1;
diff --git a/src/os-plugins/OpenSLX/OSPlugin/Roster.pm b/src/os-plugins/OpenSLX/OSPlugin/Roster.pm
new file mode 100644
index 00000000..7bfed044
--- /dev/null
+++ b/src/os-plugins/OpenSLX/OSPlugin/Roster.pm
@@ -0,0 +1,213 @@
+# 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/
+# -----------------------------------------------------------------------------
+# OSPlugin::Roster.pm
+# - provides information about all available plugins
+# -----------------------------------------------------------------------------
+package OpenSLX::OSPlugin::Roster;
+
+use strict;
+use warnings;
+
+use OpenSLX::Basics;
+use Clone qw(clone);
+
+my %plugins;
+
+=item C<getAvailablePlugins()>
+
+Returns a hash that keys the names of available plugins to their info hash.
+
+=cut
+
+sub getAvailablePlugins
+{
+ my $class = shift;
+
+ $class->_init() if !%plugins;
+
+ my %pluginInfo;
+ foreach my $pluginName (keys %plugins) {
+ $pluginInfo{$pluginName} = $plugins{$pluginName}->getInfo();
+ }
+ return \%pluginInfo;
+}
+
+=item C<getPlugin()>
+
+Returns an instance of the plugin with the given name
+
+=cut
+
+sub getPlugin
+{
+ my $class = shift;
+ my $pluginName = shift;
+
+ $class->_init() if !%plugins;
+
+ my $plugin = $plugins{$pluginName};
+ return if !$plugin;
+
+ return clone($plugin);
+}
+
+=item C<getPluginAttrInfo()>
+
+Returns a hash that contains info about the attributes support by the
+given plugin
+
+=cut
+
+sub getPluginAttrInfo
+{
+ my $class = shift;
+ my $pluginName = shift;
+
+ $class->_init() if !%plugins;
+
+ return if !$plugins{$pluginName};
+
+ return $plugins{$pluginName}->getAttrInfo();
+}
+
+=item C<addAllAttributesToHash()>
+
+Fetches attribute info from all available plugins and adds it to the given
+hash-ref.
+
+If a plugin name has been given, only the attributes of that plugin will be
+added.
+
+=over
+
+=item Return Value
+
+1
+
+=back
+
+=cut
+
+sub addAllAttributesToHash
+{
+ my $class = shift;
+ my $attrInfo = shift;
+ my $pluginName = shift;
+
+ return $class->_addAttributesToHash($attrInfo, $pluginName, sub { 1 } );
+}
+
+=item C<addAllStage1AttributesToHash()>
+
+Fetches attribute info relevant for stage1 (i.e. vendor-OS-attributes)
+from all available plugins and adds it to the given hash-ref.
+
+If a plugin name has been given, only the attributes of that plugin will be
+added.
+
+=over
+
+=item Return Value
+
+1
+
+=back
+
+=cut
+
+sub addAllStage1AttributesToHash
+{
+ my $class = shift;
+ my $attrInfo = shift;
+ my $pluginName = shift;
+
+ return $class->_addAttributesToHash($attrInfo, $pluginName, sub {
+ my $attr = shift;
+ return $attr->{applies_to_vendor_os};
+ } );
+}
+
+=item C<addAllStage3AttributesToHash()>
+
+Fetches attribute info relevant for stage3 (i.e. system- or client-attributes)
+from all available plugins and adds it to the given hash-ref.
+
+If a plugin name has been given, only the attributes of that plugin will be
+added.
+
+=over
+
+=item Return Value
+
+1
+
+=back
+
+=cut
+
+sub addAllStage3AttributesToHash
+{
+ my $class = shift;
+ my $attrInfo = shift;
+ my $pluginName = shift;
+
+ return $class->_addAttributesToHash($attrInfo, $pluginName, sub {
+ my $attr = shift;
+ return $attr->{applies_to_systems} || $attr->{applies_to_clients};
+ } );
+}
+
+sub _addAttributesToHash
+{
+ my $class = shift;
+ my $attrInfo = shift;
+ my $pluginName = shift;
+ my $testFunc = shift;
+
+ $class->_init() if !%plugins;
+
+ foreach my $plugin (values %plugins) {
+ next if $pluginName && $plugin->{name} ne $pluginName;
+ my $pluginAttrInfo = $plugin->getAttrInfo();
+ foreach my $attr (keys %$pluginAttrInfo) {
+ next if !$testFunc->($pluginAttrInfo->{$attr});
+ $attrInfo->{$attr} = clone($pluginAttrInfo->{$attr});
+ }
+ }
+ return 1;
+}
+
+sub _init
+{
+ my $class = shift;
+
+ %plugins = ();
+ my $pluginPath = "$openslxConfig{'base-path'}/lib/plugins";
+ foreach my $modulePath (glob("$pluginPath/*")) {
+ next if $modulePath !~ m{/([^/]+)$};
+ my $pluginName = $1;
+ if (!-e "$modulePath/OpenSLX/OSPlugin/$pluginName.pm") {
+ vlog(
+ 1,
+ "skipped plugin-folder $modulePath as no corresponding perl "
+ . "module could be found."
+ );
+ next;
+ }
+ my $class = "OpenSLX::OSPlugin::$pluginName";
+ vlog(2, "loading plugin $class from path '$modulePath'");
+ my $plugin = instantiateClass($class, { pathToClass => $modulePath });
+ $plugins{$pluginName} = $plugin;
+ }
+ return;
+}
+
+1;