#!/usr/bin/perl -wT # # vim:set ts=4: # vim:set shiftwidth=4: =pod =head1 NAME ldap2apache.accounting - create hosts in accounting databse =head1 SYNOPSIS ldap2apache.accounting [-vcnd] =head1 DESCRIPTION ldap2apache.accounting reads the configuration from LDAP and creates the hosts in the accounting database. =head1 OPTIONS =over =item -v Be verbose. =item -c Create table =item -n Do not commit but rollback at end of transaction =item -d Delete records in database but not in ldap =back =head1 AUTHOR Peter Palfrader Epp@3node.com =head1 FILES /etc/3node/ldap2apache =head1 SEE ALSO Dokumentation fuer Webhosting. =cut use strict; use DBI; use XML::Parser; use XML::Dumper; use Net::LDAP; use Getopt::Long; $ENV{'PATH'} = '/bin:/usr/bin'; delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; my $PROGNAME = $0; my $CONFIG; { my $parser = new XML::Parser(Style => 'Tree'); my $tree = $parser->parsefile('/etc/3node/ldap2apache.accounting'); my $dump = new XML::Dumper; $CONFIG = $dump->xml2pl($tree); } Getopt::Long::config('bundling'); if (!GetOptions ( 'v' => \$CONFIG->{'verbose'}, 'c' => \$CONFIG->{'create'}, 'n' => \$CONFIG->{'notreally'}, 'd' => \$CONFIG->{'delete'}, )) { die ("Usage: $PROGNAME [-vcnd]\n"); }; if ($CONFIG->{'help'}) { print ("Usage: $PROGNAME [-vcnd]\n"); exit 0; }; my %VirtualHosts; print STDERR "Connectiong to ldap\n" if $CONFIG->{'verbose'}; my $ldap = Net::LDAP->new($CONFIG->{'ldapserver'}) or die ("$PROGNAME: Cannot create LDAP object: $@"); my $code; if ($CONFIG->{'binddn'} ne '') { $code = $ldap->bind( dn => $CONFIG->{'binddn'}, password => $CONFIG->{'bindpw'}); } else { $code = $ldap->bind(); }; die "$PROGNAME: can't connect to ldap server '$CONFIG->{'ldapserver'}': ".$code->error."\n" if ($code->code); $code = $ldap->search( filter => "(objectclass=$CONFIG->{'webvhost_objectclass'})", base => $CONFIG->{'basedn'}, timelimit => $CONFIG->{'timeout'} ); if ($code->code) { warn "$PROGNAME: Problem to search '(objectclass=$CONFIG->{'webvhost_objectclass'})' in $CONFIG->{'basedn'}: ".$code->error."\n"; next; }; my @vhosts = $code->entries; for my $entry (@vhosts) { my $dn = $entry->dn(); my ($clientname) = ( $dn =~ /ou=vhosts\s*,\s*o=(.*)\s*,\s*ou=hosting/ ); $VirtualHosts{ $entry->get_value('tnWebVHostServerName') } = $clientname; }; print STDERR "Unbinding from ldap\n" if $CONFIG->{'verbose'}; $ldap->unbind; my $TABLE = $CONFIG->{'dbtable'}; print STDERR "Connectiong to database\n" if $CONFIG->{'verbose'}; my $dbh = DBI->connect( "dbi:Pg:dbname=".$CONFIG->{'dbname'}. ";host=".$CONFIG->{'dbhost'}, $CONFIG->{'dbuser'}, $CONFIG->{'dbpasswd'}, { RaiseError => 1, AutoCommit => 0 } ); if ($CONFIG->{'create'}) { print STDERR "Creating table\n" if $CONFIG->{'verbose'}; $dbh->do( "CREATE TABLE $TABLE ( ref integer PRIMARY KEY, bytesin bigint DEFAULT 0, bytesout bigint DEFAULT 0, host character varying(256), client character varying(256) )") or die $dbh->errstr; }; my $query = $dbh->prepare("SELECT ref, client FROM $TABLE WHERE host=?"); my $insert = $dbh->prepare("INSERT INTO $TABLE (ref, host, client) VALUES ( (SELECT coalesce(max(ref),0)+1 FROM $TABLE) , ?, ?)"); for my $hostname (keys %VirtualHosts) { $query->execute( $hostname ); my $hr = $query->fetchrow_hashref; unless ($hr) { print STDERR "Host $hostname needs inserting\n" if $CONFIG->{'verbose'}; $insert->execute ($hostname, $VirtualHosts{$hostname} ); } else { if ($hr->{'client'} ne $VirtualHosts{$hostname}) { warn ("Client mismatch for host '$hostname': '".$hr->{'client'}."' vs '".$VirtualHosts{$hostname}."'\n"); } else { print STDERR "Host $hostname is in database and has the right client '$VirtualHosts{$hostname}'\n" if $CONFIG->{'verbose'}; }; }; }; $query->finish(); $insert->finish(); $query = $dbh->prepare("SELECT ref, host FROM $TABLE"); $query->execute(); my $delete = $dbh->prepare("DELETE FROM $TABLE WHERE ref = ?"); while (my $hashref = $query->fetchrow_hashref() ) { my $host = $hashref->{'host'}; unless (defined $VirtualHosts{$host}) { print "$host is in database but not in ldap\n"; if ($CONFIG->{'delete'}) { print STDERR "Deleting $host\n" if $CONFIG->{'verbose'}; $delete->execute($hashref->{'ref'}); }; }; }; $query->finish(); $delete->finish(); if ($CONFIG->{'notreally'}) { print STDERR "Doing Rollback\n" if $CONFIG->{'verbose'}; $dbh->rollback; } else { print STDERR "Commiting\n" if $CONFIG->{'verbose'}; $dbh->commit; }; print STDERR "Disconnecting\n" if $CONFIG->{'verbose'}; $dbh->disconnect;