summaryrefslogblamecommitdiffstats
path: root/config-db/slxconfig
blob: 5c58ba82e3e6dc2fcc26aed3926e0615f3fc2b51 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       

                                                                               
 

                                                                    
 

                                                                         
 

                                                                               
           
             


                 


                                                                          











                                                                  

                               

                    
                      
                          
                      
                   
 
                                               

           

                               



                                                                       

                             



                                                                           
 






                             

                                         
 
                               
                            

                                   
                               

                                   






                                        

                                      
                                  


                                      
                                        
                           

                               
                                        
                           
 



                                       
                               
                                        
                           

                               
                                            
                              

                                 

                                         

                                 

                                         

                                 

                                         

                                 

                                             
 
                                    

                                        
                                    


                                        




                                                                 
                                     
                                     
                                        


                                   
                                      




                                     
                                        

                                              

 
                         
 

                     




                                   
                                                          












                                                                                                      

 


                            
                                                           






                                                            
                                                           
                                                                    
                                                                    
                                                                                        



                                                

              
                                                                   
         
               



               
                                     

                     





                                                             



                                
                                                                                  
































                                                                                      

                           
                                                   
                                                          





               
                                     

                     





                                                             



                         


                                                                      

                     

                                                                                          



                                                                             


                                                                              





               
                                     

                     





                                                             



                                
                                                                                     




                                                                                         




                                                                                      


                                                           





                  
                                     

                     
 







                                                             
                                                               




                 



                                                                                 
 

                                                             
 
                     
                                
                     
                                                                                  



                                                                                      
                           


                                                            
          
               

 
                 
 

                                                                                 
 



                                                                       
 

                         
                     


                                                                      
                  
                     

                                                                                          



                                                                             


                                                                              
          
               

 
                 
 



                                                                                 
 

                                                             
 
                     
                                
                     



                                                                                     
                                                                                  
                                              
                                                                                      

                           


                                                                    
          
               

 
                    
 



                                                                                    
 

                                                             
 
                                        

                                                                          
               

 























































                                                                                                

                       
                                                 




                                                                             

                                                                                 
                                    
                                                                       
                                          

                      
                                            







                                                                                     


                                              
                                  

                                                                            





                                                                                                  
         
 
                                                                       
                                                                                 
                                     
         




                                                                                            

                                                            






                                                                                  
                         
                                                                         


                                            
         
               

 

                       
                                                 

                                   
                                                                             

         

                                                                                 
                                              
                                                                       
                                          
 



                                                     

                                                       
         
                                                                              
                               

                                                                             
         
                                                 

                      
                                            







                                                                                             
                                              

              


                                                                                


                                                                                     

         
                                                                       
                                                                                 
                                     
         

                                        
 






                                                                      
 






                                                                      

                                                                            
                                    
 



                                                                            
                                                            






                                                                                  
                         
                                                                         


                                            
         
               

 
                          
 
                                                 

                                   


                                                                                             

         

                                                                                 
                                                                     
                                                                       
 
                                                                              

                                                                                 
                                     

         
                      
                                            







                                                                                     

                                              

                                                                               





                                                                                     





                                                                               

                                                                                           





                                                                                  
         
 











                                                                                                  

         
                                                               
                                                                                 
                         
                                                                             


                                                
         
               

 

                          
                                                 

                                   


                                                                                            

         

                                                                                 
                                                                     
                                                                       
 
                                                                              

                                                                                 
                                     

         
                      
                                            







                                                                                             

                                              

                                                                               





                                                                                     





                                                                               


                                                                                         





                                                                                     
         




                                                                                         
                                                               
                                                                                 
                         
                                                                             


                                                
         
               
 
 

                            
                                                 
 
                                   


                                                                                            
         
 
                                                                   

                                                                              

                                                                                 
                                     
         

                                                                  

                                                


                                                                                       
               
 
 

                            
                                                 
 
                                   


                                                                                            
         
 
                                                                   

                                                                              

                                                                                 
                                     
         

                                                                  

                                                


                                                                                       
               
 
 
              

                                                                               
                         
 
                                    
 





                                      

           
                                                                        
 
               
 

                                              
              





                                                      
              
 
       
 
                                                                       
 
                                  
 
                                                                  
 
                                              
 
                                  
 







                                                                      
                                                                
 
                                                       
 
                                                                
 
                                                       
 
                                            
 
                            
 
                                            
 
                            
 
                                            
 
                            
 
                                                 
 
                               
 
                                            
 
                                   
 
                                            

                                   
 












                                                                   
                                                     


                                                                       
     
 
                  
 


                                                                              
 
              
 
       
 
                       


                                      
                      


                                 
                          


                                                       
                          




                             

               

                                                                 


                                      
 
                                      
 
                                      
 
                                         
 
                                                          
 
                                           
 
                          
 
                                               
 


                               
 
                                                   
 

       
                                                
 


                                                               
 
                                                                           



                                                                 
 



                                                                
 

     
                          
 

       
                                                                    
 


                                                               
 
                                                                      



                                                                    
 



                                                               
 
                                                            
                                           
 

     
                        
 

       
                                                                         
 

                                                              
 
                                                                       
 

                                                          
 
                                                                          
 

                                                       
 

     
                        
 

       
                                                                  
 

                                                            
 
                                                                     
 

                                                            
 
                                                                        
 

                                                         
 

     
                                 
 
       
 
                                                      
 
                                                      
 
                                              
 

     








                                                                   


                                                                 



                                                                     
                                                     




                                                                          
    
#! /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 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::ConfigFolder;
use OpenSLX::DBSchema;
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) {
	$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-s]i) {
	addSystemToConfigDB(@ARGV);
}
elsif ($action =~ m[^add-c]i) {
	addClientToConfigDB(@ARGV);
}
elsif ($action =~ m[^change-v]i) {
	changeVendorOSInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-e]i) {
	changeExportInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-s]i) {
	changeSystemInConfigDB(@ARGV);
}
elsif ($action =~ m[^change-c]i) {
	changeClientInConfigDB(@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-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-cli]i) {
	removeClientFromConfigDB(@ARGV);
}
elsif ($action =~ m[^remove-sys]i) {
	removeSystemFromConfigDB(@ARGV);
}
else {
	vlog(0, _tr(unshiftHereDoc(<<'	END-OF-HERE'), $0));
		You need to specify exactly one of these actions:
			add-client
			add-system
			change-client
			change-export
			change-system
			change-vendor-os
			list-client
			list-export
			list-system
			list-vendor-os
			remove-client
			remove-system
			search-client
			search-export
			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 (!grep { $_ eq $key } @$allowedKeys) {
			die _tr("unknown attribute '%s' specified for %s\n", $key, $table);
		}
		$dataHash{$key} = $value;
	}
	return \%dataHash;
}

sub dumpElements
{
	my $objName = shift;
	my $nameClause = shift || sub { "\t$_->{name}\n" };

	if ($verbose) {
		foreach my $elem (@_) {
			print "$objName '$elem->{name}':\n";
			print join(
				'',
				map {
					my $spc = ' ' x 25;
					my $val = $elem->{$_} || '';
					$val =~ s[\n][\n\t$spc   ]g;
					"\t$_" . substr($spc, length($_)) . " = $val\n";
				}
				sort keys %$elem
			);
		}
	}
	else {
		print join('', sort map { $nameClause->($_); } @_);
	}
	return;
}

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');
			$_;
		}
		sort { $a->{name} cmp $b->{name} } 
		$openslxDB->fetchClientByFilter(\%nameSpec)
	);
	return;
}

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(
		'groups', undef,
		map {
			my @sysIDs = $openslxDB->fetchSystemIDsOfGroup($_->{id});
			$_->{systems} 
				=	join "\n", map { $_->{name} }
					sort { $a->{name} cmp $b->{name} }
					$openslxDB->fetchSystemByID(\@sysIDs, 'name');
			$_;
		}
		sort { $a->{name} cmp $b->{name} } 
		$openslxDB->fetchGroupByFilter(\%nameSpec)
	);
	return;
}

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;
}

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})";
			}
			$_;
		}
		sort { $a->{name} cmp $b->{name} }
		$openslxDB->fetchSystemByFilter(\%nameSpec)
	);
	return;
}

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;
}

sub searchClients
{
	my @clientKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{client}};

	my $clientData = parseKeyValueArgs(\@clientKeys, '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');
			$_;
		}
		sort { $a->{name} cmp $b->{name} }
		$openslxDB->fetchClientByFilter($clientData)
	);
	return;
}

sub searchExports
{
	my @exportKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{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;
}

sub searchSystems
{
	my @systemKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{system}};

	my $systemData = parseKeyValueArgs(\@systemKeys, '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})";
			}
			$_;
			}
			sort { $a->{name} cmp $b->{name} }
			$openslxDB->fetchSystemByFilter($systemData)
	);
	return;
}

sub searchVendorOSes
{
	my @vendorOSKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{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;
}

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 =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{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));
	if ($verbose) {
		listVendorOSes("id=$vendorOS->{id}");
	}
	return;
}

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 =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{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));
	if ($verbose) {
		listExports("id=$export->{id}");
	}
	return;
}

sub addClientToConfigDB
{
	my $clientName = _cleanName(shift || '');

	if (!length($clientName)) {
		die _tr("you have to specify the name for the new client\n");
	}

	my @clientKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{client}};
	push @clientKeys, 'systems';
	my $clientData = parseKeyValueArgs(\@clientKeys, '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;
}

sub addSystemToConfigDB
{
	my $systemName = _cleanName(shift || '');

	if (!length($systemName)) {
		die _tr("you have to specify the name of the new system!\n");
	}

	my @systemKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{system}};
	push @systemKeys, 'clients', 'export';
	my $systemData = parseKeyValueArgs(\@systemKeys, 'system', @_);
	$systemData->{name} = $systemName;

	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);
	}

	if ($systemName =~ m[\bkde\b]) {

		# activate kdm and X if system is based on kde:
		$systemData->{attr_start_xdmcp} = 'kdm'
			unless exists $systemData->{attr_start_xdmcp};
		$systemData->{attr_start_x} = 'yes'
			unless exists $systemData->{attr_start_x};
	}
	if ($systemName =~ m[\bgnome\b]) {

		# activate gdm and X if system is based on GNOME:
		$systemData->{attr_start_xdmcp} = 'gdm'
			unless exists $systemData->{attr_start_xdmcp};
		$systemData->{attr_start_x} = 'yes'
			unless exists $systemData->{attr_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;
}

sub changeClientInConfigDB
{
	my $clientName = _cleanName(shift || '');

	if (!length($clientName)) {
		die _tr(
			"you have to specify the name for the client you'd like to change!\n"
		);
	}

	my @clientKeys =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{client}};
	push @clientKeys, 'systems', 'add-systems', 'remove-systems';
	my $clientData = parseKeyValueArgs(\@clientKeys, '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;
}

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 =
		map { (/^(\w+)\W/) ? $1 : $_; } @{$DbSchema->{tables}->{system}};
	push @systemKeys, 'clients', 'add-clients', 'remove-clients';
	my $systemData = parseKeyValueArgs(\@systemKeys, '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;
}

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;
}

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;
}

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<<     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

=item B<<     change-system <system-name> [<key>=<value> ...] >>

changes the data of an existing system in the config-DB

=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-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-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-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 / Systems / Vendor-OSes

=over 8

=item B<<     slxconfig list-client >>

=item B<<     slxconfig list-export >>

=item B<<     slxconfig list-system >>

=item B<<     slxconfig list-vendor-os >>

lists all existing instances of the respective DB-objects.

=item B<<     slxconfig list-client id=3 >>

lists the client with id=3

=item B<<     slxconfig list-export type=nfs >>

lists the exports of type 'nfs'

=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<<                          attr_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 attr_start_xdmcp=gnome >>

will change the system named 'suse-10.1' such that it will use
the GNOME session manager.

=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 attr_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 System / Client

=over 8

=item B<<     slxconfig remove-system <system-name> >>

=item B<<     slxconfig remove-client <client-name> >>

removes the system/client with the given name.

=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