NAME
SPOPS::LDAP::MultiDatasource -- SPOPS::LDAP functionality but fetching objects from multiple datasources
SYNOPSIS
# In your configuration
my $config = {
datasource => [ 'main', 'secondary', 'tertiary' ],
isa => [ ... 'SPOPS::LDAP::MultiDatasource' ],
};
DESCRIPTION
This class extends SPOPS::LDAP with one purpose: be able to fetch objects from multiple datasources. This can happen when you have got objects dispersed among multiple directories -- for instance, your 'Accounting' department is on one LDAP server and your 'Development' department on another. One class can (more or less -- see below) link the two LDAP servers.
Caveats
The fetch()
method is the only functional method overridden from SPOPS::LDAP
. The fetch_group()
or fetch_iterator()
methods will only use the first datasource in the listing, whatever datasource you pass in with the parameter 'connect_key' or whatever LDAP connection handle you pass in with the parameter 'ldap'. If you want to retrieve objects from multiple datasources using the same filter, use the fetch_group_all()
method.
The fetch_iterator()
method is not supported at all for multiple datasources -- use fetch_group_all()
.
SETUP
There are a number of items to configure and setup to use this class.
SPOPS Configuration
datasource (\@)
If you want to use multiple datasources, you need to specify them. The datasource
key holds an arrayref of datasources in the order you want them searched.
Example:
my $spops = {
class => 'My::Person',
isa => [ 'SPOPS::LDAP::MultiDatasource' ],
datasource => [ 'main', 'accounting', 'development', 'etc' ],
};
The 'etc' datasource will be the last one searched. This would obviously be a performance hit if most of your objects were there.
ldap_base_dn ($ or \%)
First, this should not be a full DN, but rather a partial one that when matched up with a datasource creates a full DN. For example:
my $spops = {
class => 'My::Person',
isa => [ 'SPOPS::LDAP::MultiDatasource' ],
ldap_base_dn => 'ou=People',
};
Second, if you use a scalar for this key you are in effect saying 'use the same partial DN for all my datasources'. But if you are using different partial DNs for different datasources, you need to specify them:
my $spops = {
class => 'My::Person',
isa => [ 'SPOPS::LDAP::MultiDatasource' ],
datasource => [ 'main', 'accounting', 'development', 'etc' ],
ldap_base_dn => { main => 'ou=People',
accounting => 'ou=BeanCounters',
development => 'ou=Geeks',
etc => 'ou=Commoners' },
};
Methods You Must Implement
connection_info( $connect_key )
This method should look at the $connect_key
and return a hashref of information used to connect to the LDAP directory. Keys (hopefully self-explanatory) should be:
host ($)
base_dn ($)
Other keys are optional and can be used in conjunction with a connection/resource manager (example below).
port ($) (optional, default is '389')
bind_dn ($) (optional, will use anonymous bind without)
bind_password ($) (optional, only used if 'bind_dn' specified)
For example:
package My::ConnectionManage;
use strict;
my $connections = {
main => { host => 'localhost',
base_dn => 'dc=MyCompanyEast,dc=com' },
accounting => { host => 'accounting.mycompany.com',
base_dn => 'dc=MyCompanyWest,dc=com' },
development => { host => 'dev.mycompany.com',
base_dn => 'dc=MyCompanyNorth,dc=com' },
etc => { host => 'etc.mycompany.com',
base_dn => 'dc=MyCompanyBranch,dc=com' },
};
sub connection_info {
my ( $class, $connect_key ) = @_;
return \%{ $connections->{ $connect_key } };
}
Then put this class into the 'isa' for your SPOPS class:
my $spops = {
class => 'My::Person',
isa => [ 'My::ConnectionManage', 'SPOPS::LDAP::MultiDatasource' ],
};
global_datasource_handle( $connect_key )
You will need an implementation that deals with multiple configurations. For example:
package My::DSManage;
use strict;
use Net::LDAP;
my %DS = ();
sub global_datasource_handle {
my ( $class, $connect_key ) = @_;
unless ( $connect_key ) {
die "Cannot retrieve handle without connect key!\n";
}
unless ( $DS{ $connect_key } ) {
my $ldap_info = $class->connection_info( $connect_key );
$ldap_info->{port} ||= 389;
my $ldap = Net::LDAP->new( $ldap_info->{host},
port => $ldap_info->{port} );
die "Cannot create LDAP connection!\n" unless ( $ldap );
my ( %bind_params );
if ( $ldap_info->{bind_dn} ) {
$bind_params{dn} = $ldap_info->{bind_dn};
$bind_params{password} = $ldap_info->{bind_password};
}
my $bind_msg = $ldap->bind( %bind_params );
die "Cannot bind! Error: ", $bind_msg->error, "\n" if ( $bind_msg->code );
$DS{ $connect_key } = $ldap;
}
return $DS{ $connect_key };
}
Then put this class into the 'isa' for your SPOPS class:
my $spops = {
class => 'My::Person',
isa => [ 'My::DSManage', 'SPOPS::LDAP::MultiDatasource' ],
};
Someone with a thinking cap on might put the previous two items in the same class :-)
METHODS
fetch( $id, \%params )
Given the normal parameters for fetch()
, tries to retrieve an object matching either the $id
or the 'filter' specified in \%params
from one of the datasources. When it finds an object it is immediately returned.
If you pass in the key 'ldap' in \%params, this functions as the fetch()
does in SPOPS::LDAP
and multiple datasources are not used.
Returns: SPOPS object (if found), or undef.
fetch_group_all( \%params )
Given the normal parameters for fetch_group()
, retrieves all objects matching the parameters from all datasources. Use with caution.
Returns: Arrayref of SPOPS objects.
base_dn( $connect_key )
Returns the full base DN associated with $connect_key
.
get_partial_dn( $connect_key )
Retrieves the partial base DN associated with $connect_key
.
get_connect_key()
If called, returns either the value of the config key 'default_datasource' or the value of the class constant 'DEFAULT_CONNECT_KEY', which is normally 'main'.
BUGS
None known.
TO DO
Test some more.
SEE ALSO
COPYRIGHT
fCopyright (c) 2001 MSN Marketing Service Nordwest, GmbH. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
AUTHORS
Chris Winters <chris@cwinters.com>