#! /usr/bin/perl
# -----------------------------------------------------------------------------
# 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/
# -----------------------------------------------------------------------------
use strict;
my $abstract = q[
slxconfig
This script can be used to display or change the OpenSLX configuration
database. You can create systems that use a specific vendor-OS
and you can create clients for these systems, too.
];
use Getopt::Long qw(:config pass_through);
use Pod::Usage;
# add the folder this script lives in and the lib-folder to perl's
# search path for modules:
use FindBin;
use lib "$FindBin::RealBin";
use lib "$FindBin::RealBin/../lib";
use lib "$FindBin::RealBin/../config-db";
# development path to config-db
use OpenSLX::Basics;
use OpenSLX::ConfigDB;
use OpenSLX::DBSchema;
my (
$helpReq,
$manReq,
$verbose,
$versionReq,
);
GetOptions(
'help|?' => \$helpReq,
'man' => \$manReq,
'verbose' => \$verbose,
'version' => \$versionReq,
) or pod2usage(2);
pod2usage(-msg => $abstract, -verbose => 0, -exitval => 1) if $helpReq;
if ($manReq) {
$ENV{LANG} = 'en_EN';
# avoid dubious problem with perldoc in combination with UTF-8 that
# leads to strange dashes and single-quotes being used
pod2usage(-verbose => 2)
}
if ($versionReq) {
system('slxversion');
exit 1;
}
openslxInit();
my $openslxDB = OpenSLX::ConfigDB->new();
$openslxDB->connect();
my $action = shift @ARGV;
if ($action =~ m[^add-system$]i) {
addSystemToConfigDB(@ARGV);
} elsif ($action =~ m[^add-client$]i) {
addClientToConfigDB(@ARGV);
} elsif ($action =~ m[^change-system$]i) {
changeSystemInConfigDB(@ARGV);
} elsif ($action =~ m[^change-client$]i) {
changeClientInConfigDB(@ARGV);
} elsif ($action =~ m[^list-c]) {
print _tr("List of the matching clients:\n");
listClients(@ARGV);
} elsif ($action =~ m[^list-e]) {
print _tr("List of the matching exports:\n");
listExports(@ARGV);
} elsif ($action =~ m[^list-s]) {
print _tr("List of the matching systems:\n");
listSystems(@ARGV);
} elsif ($action =~ m[^list-v]) {
print _tr("List of the matching vendor-OSes:\n");
listVendorOSes(@ARGV);
} elsif ($action =~ m[^remove-client$]i) {
removeClientFromConfigDB(@ARGV);
} elsif ($action =~ m[^remove-system$]i) {
removeSystemFromConfigDB(@ARGV);
} else {
print STDERR _tr("You need to specify exactly one of these actions:
add-client
add-system
change-client
change-system
list-client
list-export
list-system
list-vendoros
remove-client
remove-system
Try '%s --help' for more info.\n", $0);
}
$openslxDB->disconnect();
exit;
sub parseKeyValueArgs
{
my $allowedKeys = shift;
my $table = shift;
my %dataHash;
while (my $param = shift) {
if ($param !~ m[^\s*([\w\-]+)\s*=(.+)$]) {
die _tr("value specification %s has unknown format, expected <key>=<value>\n",
$param);
}
my $key = $1;
my $value = $2;
if (!grep { $_ eq $key } @$allowedKeys) {
die _tr("unknown attribute '%s' specified for %s\n", $key, $table);
}
$dataHash{$1} = $2;
}
return \%dataHash;
}
sub dumpElements
{
my $objName = shift;
if ($verbose) {
foreach my $elem (@_) {
print "$objName '$elem->{name}':\n";
print join(
'',
map {
my $spc = ' 'x25;
my $val = $elem->{$_};
$val =~ s[\n][\n\t$spc ]g;
"\t$_"
.substr($spc, length($_))
." = $val\n";
}
sort keys %$elem
);
}
} else {
print join('', map { "\t$_->{name}\n" } @_);
}
}
sub listClients
{
my @clientKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{client}};
my $clientData = parseKeyValueArgs(\@clientKeys, 'client', @_);
dumpElements(
'client',
map {
my @sysIDs = $openslxDB->aggregatedSystemIDsOfClient($_);
$_->{systems}
= join "\n",
map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByID(\@sysIDs, 'name');
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByFilter($clientData)
);
}
sub listExports
{
my @exportKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{export}};
my $exportData = parseKeyValueArgs(\@exportKeys, 'export', @_);
dumpElements(
'export',
map {
my $vendorOS
= $openslxDB->fetchVendorOSByID($_->{vendor_os_id}, 'name');
if (defined $vendorOS) {
$_->{vendor_os_id} .= " ($vendorOS->{name})";
}
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchExportByFilter($exportData)
);
}
sub listSystems
{
my @systemKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{system}};
my $systemData = parseKeyValueArgs(\@systemKeys, 'system', @_);
dumpElements(
'system',
map {
my @clientIDs = $openslxDB->aggregatedClientIDsOfSystem($_);
$_->{clients}
= join "\n",
map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByID(\@clientIDs, 'name');
my $export = $openslxDB->fetchExportByID($_->{export_id}, 'name');
if (defined $export) {
$_->{export_id} .= " ($export->{name})";
}
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByFilter($systemData)
);
}
sub listVendorOSes
{
my @vendorOSKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{vendor_os}};
my $vendorOSData = parseKeyValueArgs(\@vendorOSKeys, 'vendor_os', @_);
dumpElements('vendor-OS',
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchVendorOSByFilter($vendorOSData));
}
sub addClientToConfigDB
{
my @clientKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{client}};
push @clientKeys, 'systems';
my $clientData = parseKeyValueArgs(\@clientKeys, 'client', @_);
my @systemIDs;
if (exists $clientData->{systems}) {
@systemIDs
= map {
my $system
= $openslxDB->fetchSystemByFilter({ 'name' => $_ });
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split '\s*,\s*', $clientData->{systems};
delete $clientData->{systems};
}
if (!length($clientData->{name})) {
die _tr("you have to specify the name for the new client\n");
}
if (!length($clientData->{mac})) {
die _tr("you have to specify the MAC for the new client\n");
}
if ($clientData->{mac} !~ m[^(?:[[:xdigit:]][[:xdigit:]]:){5}?[[:xdigit:]][[:xdigit:]]$]) {
die _tr("unknown MAC-format given, expected something like '01:02:03:04:05:06'!\n");
}
if (!length($clientData->{boot_type})) {
$clientData->{boot_type} = 'pxe';
}
if ($openslxDB->fetchClientByFilter({ 'name' => $clientData->{name} })) {
die _tr("the client '%s' already exists in the DB, giving up!\n",
$clientData->{name});
}
my $clientID = $openslxDB->addClient([$clientData]);
vlog 0, _tr("client '%s' has been successfully added to DB (ID=%s)\n",
$clientData->{name}, $clientID);
if (defined @systemIDs) {
$openslxDB->addSystemIDsToClient($clientID, \@systemIDs);
}
if ($verbose) {
listClients("id=$clientID");
}
}
sub addSystemToConfigDB
{
my @systemKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{system}};
push @systemKeys, 'clients', 'export';
my $systemData = parseKeyValueArgs(\@systemKeys, 'system', @_);
if (!length($systemData->{export})) {
die _tr("you have to specify the export the new system shall be using\n");
}
my $exportName = $systemData->{export};
delete $systemData->{export};
my $export
= $openslxDB->fetchExportByFilter({ 'name' => $exportName });
if (!defined $export) {
die _tr("export '%s' could not be found in DB, giving up!\n", $exportName);
}
$systemData->{export_id} = $export->{id};
my @clientIDs;
if (exists $systemData->{clients}) {
@clientIDs
= map {
my $client
= $openslxDB->fetchClientByFilter({ 'name' => $_ });
if (!defined $client) {
die _tr("client '%s' doesn't exist in DB, giving up!\n", $_);
}
$client->{id};
}
split '\s*,\s*', $systemData->{clients};
delete $systemData->{clients};
}
if (!length($systemData->{kernel})) {
$systemData->{kernel} = 'vmlinuz';
}
if (!length($systemData->{name})) {
$systemData->{name} = "$exportName-$systemData->{kernel}";
}
if (!length($systemData->{label})) {
$systemData->{label} = "$exportName-$systemData->{kernel}";
}
if (!length($systemData->{ramfs_debug_level})) {
$systemData->{ramfs_debug_level} = '0';
}
if (!length($systemData->{ramfs_use_glibc})) {
$systemData->{ramfs_use_glibc} = '0';
}
if (!length($systemData->{ramfs_use_busybox})) {
$systemData->{ramfs_use_busybox} = '1';
}
if ($openslxDB->fetchSystemByFilter({ 'name' => $systemData->{name} })) {
die _tr("the system '%s' already exists in the DB, giving up!\n",
$systemData->{name});
}
my $systemID = $openslxDB->addSystem([$systemData]);
vlog 0, _tr("system '%s' has been successfully added to DB (ID=%s)\n",
$systemData->{name}, $systemID);
if (defined @clientIDs) {
$openslxDB->addClientIDsToSystem($systemID, \@clientIDs);
}
if ($verbose) {
listSystems("id=$systemID");
}
}
sub changeClientInConfigDB
{
my @clientKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{client}};
push @clientKeys, 'systems', 'add-systems', 'remove-systems';
my $clientData = parseKeyValueArgs(\@clientKeys, 'client', @_);
if (!exists $clientData->{name}) {
die _tr("you have to specify the name for the client you'd like to change!\n");
}
my $client = $openslxDB->fetchClientByFilter({'name' => $clientData->{name}});
if (!defined $client) {
die _tr("the client '%s' doesn't exists in the DB, giving up!\n",
$clientData->{name});
}
my @systemIDs;
if (exists $clientData->{systems}) {
@systemIDs
= map {
my $system
= $openslxDB->fetchSystemByFilter({ 'name' => $_ });
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split ",", $clientData->{systems};
delete $clientData->{systems};
}
if (exists $clientData->{'add-systems'}) {
@systemIDs = $openslxDB->fetchSystemIDsOfClient($client->{id});
push @systemIDs,
map {
my $system
= $openslxDB->fetchSystemByFilter({ 'name' => $_ });
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split ",", $clientData->{'add-systems'};
delete $clientData->{'add-systems'};
}
if (exists $clientData->{'remove-systems'}) {
@systemIDs = $openslxDB->fetchSystemIDsOfClient($client->{id});
foreach my $sysName (split ",", $clientData->{'remove-systems'}) {
my $system
= $openslxDB->fetchSystemByFilter({ 'name' => $sysName });
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $sysName);
}
@systemIDs = grep { $_ != $system->{id} } @systemIDs;
}
delete $clientData->{'remove-systems'};
}
if (length($clientData->{mac})
&& $clientData->{mac} !~ m[^(?:[[:xdigit:]][[:xdigit:]]:){5}?[[:xdigit:]][[:xdigit:]]$]) {
die _tr("unknown MAC-format given, expected something like '01:02:03:04:05:06'!\n");
}
$openslxDB->changeClient($client->{id}, [$clientData]);
vlog 0, _tr("client '%s' has been successfully changed\n",
$clientData->{name});
if (defined @systemIDs) {
$openslxDB->setSystemIDsOfClient($client->{id}, \@systemIDs);
}
if ($verbose) {
listClients("id=$client->{id}");
}
}
sub changeSystemInConfigDB
{
my @systemKeys
= map { (/^(\w+)\W/) ? $1 : $_; }
@{$DbSchema->{tables}->{system}};
push @systemKeys, 'clients', 'add-clients', 'remove-clients';
my $systemData = parseKeyValueArgs(\@systemKeys, 'system', @_);
if (!exists $systemData->{name}) {
die _tr("you have to specify the name of the system you'd like to change!\n");
}
my $system = $openslxDB->fetchSystemByFilter({'name' => $systemData->{name}});
if (!defined $system) {
die _tr("the system '%s' doesn't exists in the DB, giving up!\n",
$systemData->{name});
}
my @clientIDs;
if (exists $systemData->{clients}) {
@clientIDs
= map {
my $client
= $openslxDB->fetchClientByFilter({ 'name' => $_ });
if (!defined $client) {
die _tr("client '%s' doesn't exist in DB, giving up!\n", $_);
}
$client->{id};
}
split ",", $systemData->{clients};
delete $systemData->{clients};
}
if (exists $systemData->{'add-clients'}) {
@clientIDs = $openslxDB->fetchClientIDsOfSystem($system->{id});
push @clientIDs,
map {
my $client
= $openslxDB->fetchClientByFilter({ 'name' => $_ });
if (!defined $client) {
die _tr("client '%s' doesn't exist!\n", $_);
}
$client->{id};
}
split ",", $systemData->{'add-clients'};
delete $systemData->{'add-clients'};
}
if (exists $systemData->{'remove-clients'}) {
@clientIDs = $openslxDB->fetchClientIDsOfSystem($system->{id});
foreach my $clientName (split ",", $systemData->{'remove-clients'}) {
my $client
= $openslxDB->fetchClientByFilter({ 'name' => $clientName });
if (!defined $client) {
die _tr("client '%s' doesn't exist!\n", $clientName);
}
@clientIDs = grep { $_ != $client->{id} } @clientIDs;
}
delete $systemData->{'remove-clients'};
}
$openslxDB->changeSystem($system->{id}, [$systemData]);
vlog 0, _tr("system '%s' has been successfully changed\n",
$systemData->{name});
if (defined @clientIDs) {
$openslxDB->setClientIDsOfSystem($system->{id}, \@clientIDs);
}
if ($verbose) {
listSystems("id=$system->{id}");
}
}
sub removeClientFromConfigDB
{
my $clientData = parseKeyValueArgs(['name'], 'client', @_);
if (!length($clientData->{name})) {
die _tr("you have to specify the name of the client you'd like to remove!\n");
}
my $client = $openslxDB->fetchClientByFilter({'name' => $clientData->{name}});
if (!defined $client) {
die _tr("the client '%s' doesn't exists in the DB, giving up!\n",
$clientData->{name});
}
if ($client->{id} == 0) {
die _tr("you can't remove the default-client!\n");
}
$openslxDB->removeClient($client->{id});
vlog 0, _tr("client '%s' has been successfully removed from DB\n",
$clientData->{name});
}
sub removeSystemFromConfigDB
{
my $systemData = parseKeyValueArgs(['name'], 'system', @_);
if (!length($systemData->{name})) {
die _tr("you have to specify the name of the system you'd like to remove!\n");
}
my $system = $openslxDB->fetchSystemByFilter({'name' => $systemData->{name}});
if (!defined $system) {
die _tr("the system '%s' doesn't exists in the DB, giving up!\n",
$systemData->{name});
}
if ($system->{id} == 0) {
die _tr("you can't remove the default-client!\n");
}
$openslxDB->removeSystem($system->{id});
vlog 0, _tr("system '%s' has been successfully removed from DB\n",
$systemData->{name});
}
__END__
=head1 NAME
slxconfig - OpenSLX-script to configure a vendor-OS for use with
OpenSLX. You can create systems that will use the specified vendor-OS
and you can create clients for that system, too.
=head1 SYNOPSIS
slxconfig [options] <action> <key-value-pairs>
Options:
--help brief help message
--man show full documentation
--verbose be more verbose
--version show version
Actions:
add-client name=<client-name> mac=<client-MAC> [<key-value-pair>] ...
add-system export=<export-name> [<key-value-pair>] ...
change-client name=<client-name> [<key-value-pair>] ...
change-system name=<system-name> [<key-value-pair>] ...
list-clients [<key-value-pair>] ...
list-exports [<key-value-pair>] ...
list-systems [<key-value-pair>] ...
list-vendoroses [<key-value-pair>] ...
remove-client name=<client-name>
remove-system name=<system-name>
=head1 OPTIONS
=over 8
=item B<--help>
Prints a brief help message and exits.
=item B<--man>
Prints the manual page and exits.
=item B<--verbose>
Prints more information during execution of any action.
=item B<--version>
Prints the version and exits.
=back
=head1 EXAMPLES
=head2 Listing existing Clients / Exports / Systems / Vendor-OSes
slxconfig list-client
slxconfig list-export
slxconfig list-system
slxconfig list-vendoros
lists all existing instances of the respective DB-objects.
slxconfig list-client id=3
lists the client with id=3
slxconfig list-export type=nfs
lists the client with id=3
=head2 Adding a new System to an exported Vendor-OS
slxconfig add-system export-name=<export-name> [clients=<client-Names>] [<attribute=value> ...]
adds a new system to the config-DB. The new system will use
the I<export> whose name is given.
If you specify clients (a comma-separated list of client names),
the new system will be used by the given clients.
=head2 Adding a new Client
slxconfig add-client [systems=<system-names>] [<attribute=value> ...]
adds a new client to the config-DB.
If you specify systems (a comma-separated list of system names),
the new client will use the given systems.
=head2 Changing a Client
slxconfig change-client [add-systems=<new system-names>]
[remove-systems=<system-names>]
[<attribute=value> ...]
changes an existing client in the config-DB.
With C<add-systems> you can add new systems to the specified client,
and with C<remove-systems> you can remove systems from it.
Any other attributes specified on the commandline will directly
change the data of the client itself.
=head2 Changing a System
slxconfig change-system [add-clients=<new client-names>]
[remove-clients=<client-names>]
[<attribute=value> ...]
changes an existing system in the config-DB.
With C<add-clients> you can add new clients to the specified system,
and with C<remove-clients> you can remove clients from it.
Any other attributes specified on the commandline will directly
change the data of the system itself.
=head2 Removing a System / Client
slxconfig remove-system name=<system-name>
slxconfig remove-client name=<client-name>
removes the system/client with the given name.
=cut