#! /usr/bin/perl -CLADS
# -----------------------------------------------------------------------------
# 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;
use warnings;
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 List::Util qw(max);
use Pod::Usage;
use Storable qw(dclone);
# 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::AttributeRoster;
use OpenSLX::Basics;
use OpenSLX::ConfigDB;
use OpenSLX::ConfigFolder;
use OpenSLX::Utils;
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) {
# avoid dubious problem with perldoc in combination with UTF-8 that
# leads to strange dashes and single-quotes being used
$ENV{LC_MESSAGES} = 'POSIX';
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-c]i) {
addClientToConfigDB(@ARGV);
}
elsif ($action =~ m[^add-g]i) {
addGroupToConfigDB(@ARGV);
}
elsif ($action =~ m[^add-s]i) {
addSystemToConfigDB(@ARGV);
}
elsif ($action =~ m[^change-v]i) {
changeVendorOSInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-e]i) {
changeExportInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-g]i) {
changeGroupInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-s]i) {
changeSystemInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-c]i) {
changeClientInConfigDB(@ARGV);
}
elsif ($action =~ m[^list-a]) {
print _tr("List of known attributes:\n");
listAttributes(@ARGV);
}
elsif ($action =~ m[^list-c]) {
print _tr("List of clients:\n");
listClients(@ARGV);
}
elsif ($action =~ m[^list-e]) {
print _tr("List of exports:\n");
listExports(@ARGV);
}
elsif ($action =~ m[^list-g]) {
print _tr("List of groups:\n");
listGroups(@ARGV);
}
elsif ($action =~ m[^list-s]) {
print _tr("List of systems:\n");
listSystems(@ARGV);
}
elsif ($action =~ m[^list-v]) {
print _tr("List of vendor-OSes:\n");
listVendorOSes(@ARGV);
}
elsif ($action =~ m[^search-c]) {
print _tr("Matching clients:\n");
searchClients(@ARGV);
}
elsif ($action =~ m[^search-e]) {
print _tr("Matching exports:\n");
searchExports(@ARGV);
}
elsif ($action =~ m[^search-g]) {
print _tr("Matching groups:\n");
searchGroups(@ARGV);
}
elsif ($action =~ m[^search-s]) {
print _tr("Matching systems:\n");
searchSystems(@ARGV);
}
elsif ($action =~ m[^search-v]) {
print _tr("Matching vendor-OSes:\n");
searchVendorOSes(@ARGV);
}
elsif ($action =~ m[^remove-c]i) {
removeClientFromConfigDB(@ARGV);
}
elsif ($action =~ m[^remove-g]i) {
removeGroupFromConfigDB(@ARGV);
}
elsif ($action =~ m[^remove-s]i) {
removeSystemFromConfigDB(@ARGV);
}
else {
vlog(0, _tr(unshiftHereDoc(<<' END-OF-HERE'), $0));
You need to specify exactly one of these actions:
add-client
add-group
add-system
change-client
change-export
change-group
change-system
change-vendor-os
list-attributes
list-client
list-export
list-group
list-system
list-vendor-os
remove-client
remove-group
remove-system
search-client
search-export
search-group
search-system
search-vendor-os
Try '%s --help' for more info.
END-OF-HERE
}
$openslxDB->disconnect();
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 = lc($1);
my $value = $2;
if ($value eq '-') {
$value = undef;
}
if (!grep { $_ eq $key } @$allowedKeys) {
die _tr("unknown key '%s' specified for %s\n", $key, $table);
}
$dataHash{$key} = $value;
}
return \%dataHash;
}
sub parseKeyValueArgsWithAttrs
{
my $allowedKeys = shift;
my $allowedAttrKeys = shift;
my $table = shift;
my (%dataHash, %attrHash);
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 = lc($1);
my $value = $2;
if ($value eq '-') {
$value = undef;
}
if (grep { $_ eq $key } @$allowedKeys) {
$dataHash{$key} = $value;
} elsif (grep { $_ eq $key } @$allowedAttrKeys) {
$attrHash{$key} = $value;
} else {
die _tr("unknown key '%s' specified for %s\n", $key, $table);
}
}
if (wantarray) {
return (\%dataHash, \%attrHash);
}
else {
if (%attrHash) {
$dataHash{attrs} = \%attrHash;
}
return \%dataHash;
}
}
sub mergeNonExistingAttributes
{
my $target = shift;
my $source = shift;
my $sourceAttrs = $source->{attrs} || {};
$target->{attrs} ||= {};
my $targetAttrs = $target->{attrs};
foreach my $key (keys %$sourceAttrs) {
next if exists $targetAttrs->{$key};
$targetAttrs->{$key} = $sourceAttrs->{$key};
}
return 1;
}
sub dumpElements
{
my $objName = shift;
my $nameClause = shift || sub { "\t$_->{name}\n" };
if ($verbose) {
my $ind = ' ' x 4;
foreach my $elem (@_) {
print "$objName '$elem->{name}':\n";
my $spcLen = max map { length($_) } keys %$elem;
print join(
'',
map {
my $elemVal = defined $elem->{$_} ? $elem->{$_} : '-';
if (ref($elemVal) eq 'HASH') {
my $spcLen
= max(map { length($_) } keys %$elemVal) || 0;
my $spc = ' ' x $spcLen;
my $subLines = join(
"\n",
map {
my $spc = ' ' x $spcLen;
my $val = $elemVal->{$_} || '';
$val =~ s[\n][\n$ind$spc ]g;
"$ind$_" . substr($spc, length($_)) . " = $val";
}
sort keys %$elemVal
);
$subLines ||= "$ind<none>";
" $_:\n$subLines\n";
} else {
my $spc = ' ' x $spcLen;
$elemVal =~ s[\n][\n$ind$spc ]g;
"$ind$_" . substr($spc, length($_)) . " = $elemVal\n";
}
}
sort {
my $refCmp = ref($elem->{$a}) cmp ref($elem->{$b});
return $refCmp ? $refCmp : $a cmp $b;
}
grep {
$_ ne 'name';
}
keys %$elem
);
}
}
else {
print join('', sort map { $nameClause->($_); } @_);
}
return 1;
}
sub listAttributes
{
my $name = shift;
# always set verbose in order to give descriptive info
$verbose = 1;
my $attrInfo = OpenSLX::AttributeRoster->getAttrInfo($name);
if (!defined $attrInfo) {
die _tr('attribute "%s" is unknown!', $name);
}
dumpElements(
'attribute', undef,
map {
my $attr = dclone($attrInfo->{$_});
$attr->{name} = $_;
$attr;
}
sort keys %$attrInfo
);
return 1;
}
sub listClients
{
my $name = _cleanName(shift);
my %nameSpec;
# set verbose mode if any params have been passed in:
if (defined $name) {
$verbose = 1;
$nameSpec{name} = $name;
}
dumpElements(
'client', undef,
map {
my @sysIDs = $openslxDB->fetchSystemIDsOfClient($_->{id});
$_->{systems}
= join "\n",
map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByID(\@sysIDs, 'name');
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByFilter(\%nameSpec)
);
return 1;
}
sub listGroups
{
my $name = _cleanName(shift);
my %nameSpec;
# set verbose mode if any params have been passed in:
if (defined $name) {
$verbose = 1;
$nameSpec{name} = $name;
}
dumpElements(
'group', undef,
map {
my @systemIDs = $openslxDB->fetchSystemIDsOfGroup($_->{id});
$_->{systems}
= join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByID(\@systemIDs, 'name');
my @clientIDs = $openslxDB->fetchClientIDsOfGroup($_->{id});
$_->{clients}
= join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByID(\@clientIDs, 'name');
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchGroupByFilter(\%nameSpec)
);
return 1;
}
sub listExports
{
my $name = _cleanName(shift);
my %nameSpec;
# set verbose mode if any params have been passed in:
if (defined $name) {
$verbose = 1;
$nameSpec{name} = $name;
}
dumpElements(
'export',
sub {
"\t$_->{name}"
. substr(' ' x 30, length($_->{name}))
. "($_->{type})\n";
},
map {
my $vendorOS =
$openslxDB->fetchVendorOSByID($_->{vendor_os_id}, 'name');
if (defined $vendorOS) {
$_->{vendor_os_id} .= " ($vendorOS->{name})";
}
$_;
}
sort { $a->{name} eq $b->{name} || $a->{type} cmp $b->{type} }
$openslxDB->fetchExportByFilter(\%nameSpec)
);
return 1;
}
sub listSystems
{
my $name = _cleanName(shift);
my %nameSpec;
# set verbose mode if any params have been passed in:
if (defined $name) {
$verbose = 1;
$nameSpec{name} = $name;
}
dumpElements(
'system', undef,
map {
my @clientIDs = $openslxDB->fetchClientIDsOfSystem($_->{id});
$_->{clients}
= join "\n",
map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByID(\@clientIDs, 'name');
my $export = $openslxDB->fetchExportByID($_->{export_id});
if (defined $export) {
$_->{export_id} = "$export->{name} ($export->{type})";
}
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByFilter(\%nameSpec)
);
return 1;
}
sub listVendorOSes
{
my $name = _cleanName(shift);
my %nameSpec;
# set verbose mode if any params have been passed in:
if (defined $name) {
$verbose = 1;
$nameSpec{name} = $name;
}
dumpElements('vendor-OS', undef,
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchVendorOSByFilter(\%nameSpec));
return 1;
}
sub searchClients
{
my @clientKeys = $openslxDB->getColumnsOfTable('client');
my @clientAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my ($clientData, $clientAttrs) = parseKeyValueArgsWithAttrs(
\@clientKeys, \@clientAttrKeys, 'client', @_
);
# set verbose mode if any params have been passed in:
$verbose = 1 if %$clientData;
dumpElements(
'client', undef,
map {
my @sysIDs = $openslxDB->fetchSystemIDsOfClient($_->{id});
$_->{systems}
= join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByID(\@sysIDs, 'name');
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByFilter($clientData, undef, $clientAttrs)
);
return 1;
}
sub searchGroups
{
my @groupKeys = $openslxDB->getColumnsOfTable('groups');
my @groupAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my ($groupData, $groupAttrs) = parseKeyValueArgsWithAttrs(
\@groupKeys, \@groupAttrKeys, 'group', @_
);
# set verbose mode if any params have been passed in:
$verbose = 1 if %$groupData;
dumpElements(
'group', undef,
map {
my @systemIDs = $openslxDB->fetchSystemIDsOfGroup($_->{id});
$_->{systems}
= join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByID(\@systemIDs, 'name');
my @clientIDs = $openslxDB->fetchClientIDsOfGroup($_->{id});
$_->{clients}
= join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByID(\@clientIDs, 'name');
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchGroupByFilter($groupData, undef, $groupAttrs)
);
return 1;
}
sub searchExports
{
my @exportKeys = $openslxDB->getColumnsOfTable('export');
my $exportData = parseKeyValueArgs(\@exportKeys, 'export', @_);
# set verbose mode if any params have been passed in:
$verbose = 1 if %$exportData;
dumpElements(
'export',
sub {
"\t$_->{name}"
. substr(' ' x 30, length($_->{name}))
. "($_->{type})\n";
},
map {
my $vendorOS =
$openslxDB->fetchVendorOSByID($_->{vendor_os_id}, 'name');
if (defined $vendorOS) {
$_->{vendor_os_id} .= " ($vendorOS->{name})";
}
$_;
}
sort { $a->{name} eq $b->{name} || $a->{type} cmp $b->{type} }
$openslxDB->fetchExportByFilter($exportData)
);
return 1;
}
sub searchSystems
{
my @systemKeys = $openslxDB->getColumnsOfTable('system');
my @systemAttrKeys = OpenSLX::AttributeRoster->getSystemAttrs();
my ($systemData, $systemAttrs) = parseKeyValueArgsWithAttrs(
\@systemKeys, \@systemAttrKeys, 'system', @_
);
# set verbose mode if any params have been passed in:
$verbose = 1 if %$systemData;
dumpElements(
'system', undef,
map {
my @clientIDs = $openslxDB->fetchClientIDsOfSystem($_->{id});
$_->{clients} = join "\n", map { $_->{name} }
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchClientByID(\@clientIDs, 'name');
my $export = $openslxDB->fetchExportByID($_->{export_id});
if (defined $export) {
$_->{export_id} = "$export->{name} ($export->{type})";
}
# rename attrs to ATTRIBUTES for display
$_->{ATTRIBUTES} = $_->{attrs};
delete $_->{attrs};
$_;
}
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchSystemByFilter($systemData, undef, $systemAttrs)
);
return 1;
}
sub searchVendorOSes
{
my @vendorOSKeys = $openslxDB->getColumnsOfTable('vendor_os');
my $vendorOSData = parseKeyValueArgs(\@vendorOSKeys, 'vendor_os', @_);
# set verbose mode if any params have been passed in:
$verbose = 1 if %$vendorOSData;
dumpElements(
'vendor-OS', undef,
sort { $a->{name} cmp $b->{name} }
$openslxDB->fetchVendorOSByFilter($vendorOSData)
);
return 1;
}
sub changeVendorOSInConfigDB
{
my $vendorOSName = _cleanName(shift || '');
if (!length($vendorOSName)) {
die _tr(
"you have to specify the name for the vendor-OS you'd like to change!\n"
);
}
my @keys = $openslxDB->getColumnsOfTable('vendor_os');
my $vendorOSData = parseKeyValueArgs(\@keys, 'vendor_os', @_);
my $vendorOS = $openslxDB->fetchVendorOSByFilter({'name' => $vendorOSName});
if (!defined $vendorOS) {
die _tr("the vendor-OS '%s' doesn't exists in the DB, giving up!\n",
$vendorOSName);
}
$openslxDB->changeVendorOS($vendorOS->{id}, [$vendorOSData]);
vlog(
0, _tr("vendor-OS '%s' has been successfully changed\n", $vendorOSName)
);
listVendorOSes("id=$vendorOS->{id}") if $verbose;
return 1;
}
sub changeExportInConfigDB
{
my $exportName = _cleanName(shift || '');
if (!length($exportName)) {
die _tr(
"you have to specify the name for the export you'd like to change!\n"
);
}
my @exportKeys = $openslxDB->getColumnsOfTable('export');
my $exportData = parseKeyValueArgs(\@exportKeys, 'export', @_);
my $export = $openslxDB->fetchExportByFilter({'name' => $exportName});
if (!defined $export) {
die _tr("the export '%s' doesn't exists in the DB, giving up!\n",
$exportName);
}
$openslxDB->changeExport($export->{id}, [$exportData]);
vlog(0, _tr("export '%s' has been successfully changed\n", $exportName));
listExports("id=$export->{id}") if $verbose;
return 1;
}
sub addClientToConfigDB
{
my $clientName = _cleanName(shift || '');
if (!length($clientName)) {
die _tr("you have to specify the name for the new client\n");
}
my @clientKeys = $openslxDB->getColumnsOfTable('client');
push @clientKeys, 'systems';
my @clientAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my $clientData = parseKeyValueArgsWithAttrs(
\@clientKeys, \@clientAttrKeys, 'client', @_
);
$clientData->{name} = $clientName;
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 (!$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 ($openslxDB->fetchClientByFilter({'name' => $clientName})) {
die _tr("the client '%s' already exists in the DB, giving up!\n",
$clientName);
}
if ($openslxDB->fetchClientByFilter({'mac' => $clientData->{mac}})) {
die _tr(
"a client with the MAC '%s' already exists in the DB, giving up!\n",
$clientData->{mac}
);
}
my $clientID = $openslxDB->addClient([$clientData]);
vlog(
0,
_tr(
"client '%s' has been successfully added to DB (ID=%s)\n",
$clientName, $clientID
)
);
if (@systemIDs) {
$openslxDB->addSystemIDsToClient($clientID, \@systemIDs);
}
if ($verbose) {
listClients("id=$clientID");
}
return 1;
}
sub addGroupToConfigDB
{
my $groupName = _cleanName(shift || '');
if (!length($groupName)) {
die _tr("you have to specify the name for the new group\n");
}
my @groupKeys = $openslxDB->getColumnsOfTable('groups');
push @groupKeys, 'systems', 'clients';
my @groupAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my $groupData = parseKeyValueArgsWithAttrs(
\@groupKeys, \@groupAttrKeys, 'group', @_
);
$groupData->{name} = $groupName;
my @systemIDs;
if (exists $groupData->{systems}) {
@systemIDs = map {
my $system = $openslxDB->fetchSystemByFilter({'name' => $_});
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split '\s*,\s*', $groupData->{systems};
delete $groupData->{systems};
}
my @clientIDs;
if (exists $groupData->{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*', $groupData->{clients};
delete $groupData->{clients};
}
if (!defined $groupData->{priority} || !length($groupData->{priority})) {
$groupData->{priority} = 50;
vlog(0, _tr("priority of new group has been set to default (50)."));
}
if ($openslxDB->fetchGroupByFilter({'name' => $groupName})) {
die _tr("the group '%s' already exists in the DB, giving up!\n",
$groupName);
}
my $groupID = $openslxDB->addGroup([$groupData]);
vlog(
0,
_tr(
"group '%s' has been successfully added to DB (ID=%s)\n",
$groupName, $groupID
)
);
if (@systemIDs) {
$openslxDB->addSystemIDsToGroup($groupID, \@systemIDs);
}
if (@clientIDs) {
$openslxDB->addClientIDsToGroup($groupID, \@clientIDs);
}
if ($verbose) {
listGroups("id=$groupID");
}
return 1;
}
sub addSystemToConfigDB
{
my $systemName = _cleanName(shift || '');
if (!length($systemName)) {
die _tr("you have to specify the name of the new system!\n");
}
my @systemKeys = $openslxDB->getColumnsOfTable('system');
push @systemKeys, 'clients', 'export';
my @systemAttrKeys = OpenSLX::AttributeRoster->getSystemAttrs();
my $systemData = parseKeyValueArgsWithAttrs(
\@systemKeys, \@systemAttrKeys, 'system', @_
);
$systemData->{name} = $systemName;
$systemData->{attrs} ||= {};
my $exportName = $systemData->{export} || '';
delete $systemData->{export};
if (!length($exportName)) {
$exportName = $systemName;
# try falling back to given system name
}
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};
}
else {
# no clients given, so we add this system to the default client,
# which will make this system bootable by *all* clients (unless
# they are configured otherwise).
my $defaultClient =
$openslxDB->fetchClientByFilter({'name' => '<<<default>>>'});
push @clientIDs, $defaultClient->{id};
}
if ($openslxDB->fetchSystemByFilter({'name' => $systemName})) {
die _tr("the system '%s' already exists in the DB, giving up!\n",
$systemName);
}
# activate kdm and X if system is based on kde:
if ($systemName =~ m[\bkde\b]) {
$systemData->{attrs}->{start_xdmcp} = 'kdm'
unless exists $systemData->{attrs}->{start_xdmcp};
$systemData->{attrs}->{start_x} = 'yes'
unless exists $systemData->{attrs}->{start_x};
}
# activate gdm and X if system is based on GNOME:
if ($systemName =~ m[\bgnome\b]) {
$systemData->{attrs}->{start_xdmcp} = 'gdm'
unless exists $systemData->{attrs}->{start_xdmcp};
$systemData->{attrs}->{start_x} = 'yes'
unless exists $systemData->{attrs}->{start_x};
}
my $systemConfigPath =
"$openslxConfig{'private-path'}/config/$systemName/default";
if (!-e $systemConfigPath) {
# create the default (empty) config folders for this system:
createConfigFolderForSystem($systemName);
}
my $systemID = $openslxDB->addSystem([$systemData]);
vlog(
0,
_tr(
"system '%s' has been successfully added to DB (ID=%s)\n",
$systemName, $systemID
)
);
if (@clientIDs) {
$openslxDB->addClientIDsToSystem($systemID, \@clientIDs);
}
if ($verbose) {
listSystems("id=$systemID");
}
return 1;
}
sub changeClientInConfigDB
{
my $clientName = _cleanName(shift || '');
if (!length($clientName)) {
die _tr(
"you have to specify the name of the client you'd like to change!\n"
);
}
my @clientKeys = $openslxDB->getColumnsOfTable('client');
push @clientKeys, 'systems', 'add-systems', 'remove-systems';
my @clientAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my $clientData = parseKeyValueArgsWithAttrs(
\@clientKeys, \@clientAttrKeys, 'client', @_
);
my $client = $openslxDB->fetchClientByFilter({'name' => $clientName});
if (!defined $client) {
die _tr("the client '%s' doesn't exists in the DB, giving up!\n",
$clientName);
}
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 ($clientData->{name} && $client->{name} eq '<<<default>>>') {
die _tr(
"you can't rename the default client - no changes were made!\n");
}
if ( $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", $clientName));
if (@systemIDs) {
$openslxDB->setSystemIDsOfClient($client->{id}, \@systemIDs);
}
if ($verbose) {
listClients("id=$client->{id}");
}
return 1;
}
sub changeGroupInConfigDB
{
my $groupName = _cleanName(shift || '');
if (!length($groupName)) {
die _tr(
"you have to specify the name of the group you'd like to change!\n"
);
}
my @groupKeys = $openslxDB->getColumnsOfTable('group');
push @groupKeys, qw(
systems add-systems remove-systems clients add-clients remove-clients
);
my @groupAttrKeys = OpenSLX::AttributeRoster->getClientAttrs();
my $groupData = parseKeyValueArgsWithAttrs(
\@groupKeys, \@groupAttrKeys, 'group', @_
);
my $group = $openslxDB->fetchGroupByFilter({'name' => $groupName});
if (!defined $group) {
die _tr("the group '%s' doesn't exists in the DB, giving up!\n",
$groupName);
}
mergeNonExistingAttributes($groupData, $group);
my (@systemIDs, @clientIDs);
if (exists $groupData->{systems}) {
@systemIDs = map {
my $system = $openslxDB->fetchSystemByFilter({'name' => $_});
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split ",", $groupData->{systems};
delete $groupData->{systems};
}
if (exists $groupData->{'add-systems'}) {
@systemIDs = $openslxDB->fetchSystemIDsOfGroup($group->{id});
push @systemIDs, map {
my $system = $openslxDB->fetchSystemByFilter({'name' => $_});
if (!defined $system) {
die _tr("system '%s' doesn't exist!\n", $_);
}
$system->{id};
}
split ",", $groupData->{'add-systems'};
delete $groupData->{'add-systems'};
}
if (exists $groupData->{'remove-systems'}) {
@systemIDs = $openslxDB->fetchSystemIDsOfGroup($group->{id});
foreach my $sysName (split ',', $groupData->{'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 $groupData->{'remove-systems'};
}
if (exists $groupData->{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 ",", $groupData->{clients};
delete $groupData->{clients};
}
if (exists $groupData->{'add-clients'}) {
@clientIDs = $openslxDB->fetchClientIDsOfGroup($group->{id});
push @clientIDs, map {
my $client = $openslxDB->fetchClientByFilter({'name' => $_});
if (!defined $client) {
die _tr("client '%s' doesn't exist!\n", $_);
}
$client->{id};
}
split ",", $groupData->{'add-clients'};
delete $groupData->{'add-clients'};
}
if (exists $groupData->{'remove-clients'}) {
@clientIDs = $openslxDB->fetchClientIDsOfGroup($group->{id});
foreach my $clientName (split ",", $groupData->{'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 $groupData->{'remove-clients'};
}
if (defined $groupData->{priority} && $groupData->{priority} !~ m{^\d+$}) {
die _tr("unknown priority-format given, expected an integer!\n");
}
$openslxDB->changeGroup($group->{id}, [$groupData]);
vlog(0, _tr("group '%s' has been successfully changed\n", $groupName));
if (@systemIDs) {
$openslxDB->setSystemIDsOfGroup($group->{id}, \@systemIDs);
}
if (@clientIDs) {
$openslxDB->setClientIDsOfGroup($group->{id}, \@clientIDs);
}
if ($verbose) {
listGroups("id=$group->{id}");
}
return 1;
}
sub changeSystemInConfigDB
{
my $systemName = _cleanName(shift || '');
if (!length($systemName)) {
die _tr(
"you have to specify the name of the system you'd like to change!\n"
);
}
my @systemKeys = $openslxDB->getColumnsOfTable('system');
push @systemKeys, 'clients', 'add-clients', 'remove-clients';
my @systemAttrKeys = OpenSLX::AttributeRoster->getSystemAttrs();
my $systemData = parseKeyValueArgsWithAttrs(
\@systemKeys, \@systemAttrKeys, 'system', @_
);
my $system = $openslxDB->fetchSystemByFilter({'name' => $systemName});
if (!defined $system) {
die _tr("the system '%s' doesn't exists in the DB, giving up!\n",
$systemName);
}
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'};
}
if ($systemData->{name} && $system->{name} eq '<<<default>>>') {
die _tr(
"you can't rename the default system - no changes were made!\n");
}
$openslxDB->changeSystem($system->{id}, [$systemData]);
vlog(0, _tr("system '%s' has been successfully changed\n", $systemName));
if (@clientIDs) {
$openslxDB->setClientIDsOfSystem($system->{id}, \@clientIDs);
}
if ($verbose) {
listSystems("id=$system->{id}");
}
return 1;
}
sub removeClientFromConfigDB
{
my $clientName = _cleanName(shift || '');
if (!length($clientName)) {
die _tr(
"you have to specify the name of the client you'd like to remove!\n"
);
}
my $clientData = parseKeyValueArgs(['name'], 'client', @_);
my $client = $openslxDB->fetchClientByFilter({'name' => $clientName});
if (!defined $client) {
die _tr("the client '%s' doesn't exists in the DB, giving up!\n",
$clientName);
}
if ($client->{name} eq '<<<default>>>') {
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", $clientName)
);
return 1;
}
sub removeGroupFromConfigDB
{
my $groupName = _cleanName(shift || '');
if (!length($groupName)) {
die _tr(
"you have to specify the name of the group you'd like to remove!\n"
);
}
my $groupData = parseKeyValueArgs(['name'], 'group', @_);
my $group = $openslxDB->fetchGroupByFilter({'name' => $groupName});
if (!defined $group) {
die _tr("the group '%s' doesn't exists in the DB, giving up!\n",
$groupName);
}
$openslxDB->removeGroup($group->{id});
vlog(0,
_tr("group '%s' has been successfully removed from DB\n", $groupName)
);
return 1;
}
sub removeSystemFromConfigDB
{
my $systemName = _cleanName(shift || '');
if (!length($systemName)) {
die _tr(
"you have to specify the name of the system you'd like to remove!\n"
);
}
my $systemData = parseKeyValueArgs(['name'], 'system', @_);
my $system = $openslxDB->fetchSystemByFilter({'name' => $systemName});
if (!defined $system) {
die _tr("the system '%s' doesn't exists in the DB, giving up!\n",
$systemName);
}
if ($system->{name} eq '<<<default>>>') {
die _tr("you can't remove the default system!\n");
}
$openslxDB->removeSystem($system->{id});
vlog(0,
_tr("system '%s' has been successfully removed from DB\n", $systemName)
);
return 1;
}
sub _cleanName
{ # removes 'name=""' constructs from the name, as it is rather tempting
# for the user to type that ... (and we'd like to play along with DWIM)
my $name = shift;
return unless defined $name;
if ($name =~ m[^name=(.+)$]) {
return $1;
}
return $name;
}
=head1 NAME
slxconfig - OpenSLX-script to view & change the configurational database
=head1 SYNOPSIS
slxconfig [options] <action> <key-value-pairs>
=head3 Options
--help brief help message
--man show full documentation
--verbose be more verbose
--version show version
=head3 Actions
=over 8
=item B<< add-client <client-name> mac=<MAC> [<key>=<value> ...] >>
adds a new client to the config-DB
=item B<< add-system <system-name> [export=<export-name>] \ >>
=item B<< <key>=<value> ...] >>
adds a new system to the config-DB
=item B<< add-group <group-name> [priority=<Number>] [<key>=<value> ...] >>
adds a new group to the config-DB
=item B<< change-vendor-os <vendor-os-name> [<key>=<value> ...] >>
changes the data of an existing vendor-OS in the config-DB.
=item B<< change-export <export-name> [<key>=<value> ...] >>
changes the data of an existing export in the config-DB
=item B<< change-client <client-name> [<key>=<value> ...] >>
changes the data of an existing client in the config-DB
Note: you can use the special value '-' to unset a key (mostly useful
for attributes).
=item B<< change-group <group-name> [<key>=<value> ...] >>
changes the data of an existing group in the config-DB
Note: you can use the special value '-' to unset a key (mostly useful
for attributes).
=item B<< change-system <system-name> [<key>=<value> ...] >>
changes the data of an existing system in the config-DB
Note: you can use the special value '-' to unset a key (mostly useful
for attributes).
=item B<< list-attributes [<attr-name>] >>
lists all attributes or the one with the given name
=item B<< list-client [<client-name>] >>
lists client with given name
=item B<< list-export [<export-name>] >>
lists export with given name
=item B<< list-group [<group-name>] >>
lists group with given name
=item B<< list-system [<system-name>] >>
lists system with given name
=item B<< list-vendor-os [<vendorOS-name>] >>
lists vendor-OS with given name
=item B<< remove-client <client-name> >>
removes a client from the config-DB
=item B<< remove-group <group-name> >>
removes a group from the config-DB
=item B<< remove-system <system-name> >>
removes a system from the config-DB
=item B<< search-client [<key>=<value> ...] >>
shows all clients in config-DB (optionally matching given criteria)
=item B<< search-export [<key>=<value> ...] >>
shows all exports in config-DB (optionally matching given criteria)
=item B<< search-group [<key>=<value> ...] >>
shows all groups in config-DB (optionally matching given criteria)
=item B<< search-system [<key>=<value> ...] >>
shows all systems in config-DB (optionally matching given
criteria)
=item B<< search-vendor-os [<key>=<value> ...] >>
shows all vendor-OSes in config-DB (optionally matching given criteria)
=back
=head1 DESCRIPTION
B<slxconfig> can be used to view the contents of the configurational database.
Additionally, you can add systems as well as clients and change their specific
boot configuration.
=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
=head3 Listing existing Clients / Exports / Groups / Systems / Vendor-OSes
=over 8
=item B<< slxconfig list-client >>
=item B<< slxconfig list-export >>
=item B<< slxconfig list-group >>
=item B<< slxconfig list-system >>
=item B<< slxconfig list-vendor-os >>
lists all existing instances of the respective DB-objects.
=back
=head3 Listing known attributes
=over 8
=item B<< slxconfig list-attr >>
lists all known attributes (--verbose will give details).
=back
=head3 Adding a new System to an exported Vendor-OS
=over 8
=item B<< slxconfig add-system debian-4.0 >>
adds a new system named 'debian-4.0' to the config-DB that will
use the export of the same name. No client will be associated
with this system, yet.
=item B<< slxconfig add-system suse-10.1 export-name=suse-10.1-kde \ >>
=item B<< clients=PC131,PC132,PC133 \ >>
=item B<< label="Linux Desktop" >>
adds a new system name 'suse-10.1' to the config-DB that will
use the export named 'suse-10.1-kde'. The system will be labeled
'Linux Desktop' and the clients 'PC131, 'PC132' and 'PC133' are
associated with this system (so they can boot it).
=back
=head3 Adding a new Client
=over 8
=item B<< slxconfig add-client vmware-1 mac=01:02:03:04:05:06 >>
adds a new client named 'vmware-1', being identified by the MAC
'01:02:03:04:05:06' to the config-DB. No system will be
associated with this client, yet (so it can't boot anything).
=item B<< slxconfig add-client vmware-1 mac=01:02:03:04:05:06 \ >>
=item B<< systems=suse-10.1,debian-4.0 \ >>
=item B<< start_x=no >>
adds a new client named 'vmware-1', being identified by the MAC
'01:02:03:04:05:06' to the config-DB. The systems 'suse-10.1' &
'Debian-4.0' will be associated with this client (so it will
offer these systems for booting).
During boot, the X-server will not be started by this client
(so the systems will stay in console mode).
=back
=head3 Changing a System
=over 8
=item B<< slxconfig change-system suse-10.1 start_xdmcp=gnome vmware=- >>
will change the system named 'suse-10.1' such that it will use
the GNOME session manager. The attribute vmware is set to undefined (such that
it will be inherited from the default system)
=item B<< slxconfig change-system suse-10.1 add-clients=vmware-1 >>
will associate the client 'vmware-1' with the system named
'suse-10.1'.
=item B<< slxconfig change-system suse-10.1 remove-clients=vmware-1 >>
will remove the client 'vmware-1' from the system named
'suse-10.1'.
=back
=head3 Changing a Client
=over 8
=item B<< slxconfig change-client PC131 start_snmp=yes >>
will change the client named 'PC131' such that it will start
the SNMP daemon on all systems that it boots.
=item B<< slxconfig change-client PC131 add-systems=Debian-4.0 >>
will associate the system 'Debian-4.0' with the client named
'PC131'.
=item B<< slxconfig change-client PC131 remove-systems=Debian-4.0 >>
will remove the system 'Debian-4.0' from the client named
'PC131'.
=back
=head3 Removing a Client / Group / System
=over 8
=item B<< slxconfig remove-client <client-name> >>
=item B<< slxconfig remove-group <group-name> >>
=item B<< slxconfig remove-system <system-name> >>
removes the client/group/system with the given name.
=back
=head3 Searching for Clients / Exports / Groups / Systems / Vendor-OSes
=over 8
=item B<< slxconfig search-client mac='01:02:03:04:05:06' >>
displays all clients with the MAC '01:02:03:04:05:06' (should be only one)
=item B<< slxconfig search-export type=nfs >>
displays the exports of type 'nfs'
=item B<< slxconfig list-group priority=50 >>
displays the groups that have the default priority (50)
=back
=head1 SEE ALSO
slxsettings, slxos-setup, slxos-export, slxconfig-demuxer
=head1 GENERAL OPENSLX OPTIONS
Being a part of OpenSLX, this script supports several other options
which can be used to overrule the OpenSLX settings:
--db-name=<string> name of database
--db-spec=<string> full DBI-specification of database
--db-type=<string> type of database to connect to
--locale=<string> locale to use for translations
--logfile=<string> file to write logging output to
--private-path=<string> path to private data
--public-path=<string> path to public (client-accesible) data
--temp-path=<string> path to temporary data
--verbose-level=<int> level of logging verbosity (0-3)
Please refer to the C<slxsettings>-manpage for a more detailed description
of these options.
=cut