From c13e5631307f48236be9155aea76fc9951741020 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Wed, 23 Jul 2008 18:27:33 +0000 Subject: implemented plugin dependency handling: * installing a plugin into a vendor-OS is now only possible when required plugins are already installed * removing a plugin from a vendor-OS is now only possible when now plugins that depend on this one are still installed * the config-demuxer will check the plugin depedency hierarchy and bail if any plugin is missing * when several plugins are being auto-installed (e.g. when copying all plugins from the '<<>>' vendor-OS) the order of the plugins is adjusted to comply with the dependency hierarchy * declared one single dependency: vmchooser depends on vmware (please shout if that is incorrect) git-svn-id: http://svn.openslx.org/svn/openslx/openslx/trunk@1936 95ad53e4-c205-0410-b2fa-d234c58c8868 --- config-db/slxconfig-demuxer | 19 ++++- installer/OpenSLX/OSSetup/Engine.pm | 25 ++++++- os-plugins/OpenSLX/OSPlugin/Base.pm | 47 +++++++++++++ os-plugins/OpenSLX/OSPlugin/Engine.pm | 82 ++++++++++++++++++++++ .../vmchooser/OpenSLX/OSPlugin/vmchooser.pm | 1 + os-plugins/slxos-plugin | 8 ++- 6 files changed, 178 insertions(+), 4 deletions(-) diff --git a/config-db/slxconfig-demuxer b/config-db/slxconfig-demuxer index c435d7d4..b6662ff1 100755 --- a/config-db/slxconfig-demuxer +++ b/config-db/slxconfig-demuxer @@ -51,6 +51,7 @@ use OpenSLX::Basics; use OpenSLX::ConfigDB qw(:support); use OpenSLX::ConfigFolder; use OpenSLX::MakeInitRamFS::Engine; +use OpenSLX::OSPlugin::Roster; use OpenSLX::ScopedResource; use OpenSLX::Utils; @@ -586,8 +587,24 @@ sub writePluginConfigurationsForSystem # skip inactive plugins next unless $attrs->{"${pluginName}::active"}; - push @activePlugins, $pluginName; + + my $plugin = OpenSLX::OSPlugin::Roster->getPlugin($pluginName); + my $requiredPlugins = $plugin->getInfo()->{required} || []; + my @missingPlugins + = grep { + my $required = $_; + ! grep { + $_->{plugin_name} eq $required + } @{$info->{'installed-plugins'}}; + } + @$requiredPlugins; + if (@missingPlugins) { + die _tr( + 'the plugin "%s" requires the following plugins to be installed: "%s"!', + $pluginName, join(',', @missingPlugins) + ); + } next if $option{dryRun}; diff --git a/installer/OpenSLX/OSSetup/Engine.pm b/installer/OpenSLX/OSSetup/Engine.pm index 66c03c85..31a3eb28 100644 --- a/installer/OpenSLX/OSSetup/Engine.pm +++ b/installer/OpenSLX/OSSetup/Engine.pm @@ -1699,7 +1699,7 @@ sub _installPlugins } return if ! @$plugins; - + require OpenSLX::OSPlugin::Engine; vlog( 0, @@ -1707,7 +1707,11 @@ sub _installPlugins ? _tr("reinstalling plugins...\n") : _tr("installing default plugins...\n") ); - for my $pluginInfo (@$plugins) { + 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)); @@ -1721,6 +1725,23 @@ sub _installPlugins 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 ################################################################################ diff --git a/os-plugins/OpenSLX/OSPlugin/Base.pm b/os-plugins/OpenSLX/OSPlugin/Base.pm index 2b6075f5..734a74f5 100644 --- a/os-plugins/OpenSLX/OSPlugin/Base.pm +++ b/os-plugins/OpenSLX/OSPlugin/Base.pm @@ -61,6 +61,7 @@ implementation, please drop a mail to: ot@openslx.com, or join the IRC-channel =cut use OpenSLX::Basics; +use OpenSLX::OSPlugin::Roster; =head1 PLUGIN API @@ -122,6 +123,13 @@ 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 + +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 @@ -209,6 +217,23 @@ sub checkStage3AttrValues 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 @@ -439,6 +464,28 @@ sub setupPluginInInitramfs 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/os-plugins/OpenSLX/OSPlugin/Engine.pm b/os-plugins/OpenSLX/OSPlugin/Engine.pm index 3f73a97a..ae76c9e0 100644 --- a/os-plugins/OpenSLX/OSPlugin/Engine.pm +++ b/os-plugins/OpenSLX/OSPlugin/Engine.pm @@ -23,6 +23,7 @@ use File::Path; use Storable; use OpenSLX::Basics; +use OpenSLX::OSPlugin::Roster; use OpenSLX::OSSetup::Engine; use OpenSLX::ScopedResource; use OpenSLX::Utils; @@ -146,6 +147,8 @@ Invokes the plugin's installer method while chrooted into that vendor-OS. sub installPlugin { my $self = shift; + + $self->_checkIfRequiredPluginsAreInstalled(); if ($self->{'vendor-os-name'} ne '<<>>') { @@ -209,6 +212,8 @@ sub removePlugin { my $self = shift; + $self->_checkIfPluginIsRequiredByOthers(); + if ($self->{'vendor-os-name'} ne '<<>>') { mkpath([ $self->{'plugin-repo-path'}, $self->{'plugin-temp-path'} ]); @@ -638,6 +643,83 @@ sub _addInstalledPluginToDB 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 $vendorOS = $openslxDB->fetchVendorOSByFilter( { + name => $self->{'vendor-os-name'}, + } ); + if (!$vendorOS) { + die _tr( + 'unable to find vendor-OS "%s" in DB!', $self->{'vendor-os-name'} + ); + } + my @installedPlugins = $openslxDB->fetchInstalledPlugins($vendorOS->{id}); + $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 $vendorOS = $openslxDB->fetchVendorOSByFilter( { + name => $self->{'vendor-os-name'}, + } ); + if (!$vendorOS) { + die _tr( + 'unable to find vendor-OS "%s" in DB!', $self->{'vendor-os-name'} + ); + } + my @installedPlugins = $openslxDB->fetchInstalledPlugins($vendorOS->{id}); + $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; diff --git a/os-plugins/plugins/vmchooser/OpenSLX/OSPlugin/vmchooser.pm b/os-plugins/plugins/vmchooser/OpenSLX/OSPlugin/vmchooser.pm index 052a8694..8010dc24 100644 --- a/os-plugins/plugins/vmchooser/OpenSLX/OSPlugin/vmchooser.pm +++ b/os-plugins/plugins/vmchooser/OpenSLX/OSPlugin/vmchooser.pm @@ -42,6 +42,7 @@ sub getInfo based on xml-files, which tell about available images. End-of-Here precedence => 50, + required => [ qw( vmware ) ], }; } diff --git a/os-plugins/slxos-plugin b/os-plugins/slxos-plugin index 2b87e814..7d85bf68 100755 --- a/os-plugins/slxos-plugin +++ b/os-plugins/slxos-plugin @@ -109,7 +109,13 @@ if ($action =~ m[^list-at]i) { my $fill = ' ' x 12; chomp(my $descr = $pluginInfo->{$_}->{description} || ''); $descr =~ s{\n}{\n$fill}igms; - "\n\t$_\n\t $descr\n"; + my $pluginStr = "$_"; + my $required = $pluginInfo->{$_}->{required} || []; + if (@$required) { + $pluginStr + .= _tr(' (requires: %s)', join(',', @$required)); + } + "\n\t$pluginStr\n\t $descr\n"; } else { "\t$_\n"; -- cgit v1.2.3-55-g7522