Configure but don't connect to DB in init_db()
This allows us to start up QP even if e.g. Redis is down
This commit is contained in:
parent
f7558f346d
commit
4c9bcc0ee4
@ -180,15 +180,23 @@ sub flush {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub dir {
|
sub dir {
|
||||||
my ( $self, @candidate_dirs ) = @_;
|
my ( $self, @arg ) = @_;
|
||||||
return $self->{dir} if $self->{dir} and ! @candidate_dirs;
|
return $self->{dir} if $self->{dir} and ! @arg;
|
||||||
push @candidate_dirs, ( $self->qphome . '/var/db', $self->qphome . '/config' );
|
for my $d ( $self->candidate_dirs(@arg) ) {
|
||||||
for my $d ( @candidate_dirs ) {
|
|
||||||
next if ! $self->validate_dir($d);
|
next if ! $self->validate_dir($d);
|
||||||
return $self->{dir} = $d; # first match wins
|
return $self->{dir} = $d; # first match wins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub candidate_dirs {
|
||||||
|
my ( $self, @arg ) = @_;
|
||||||
|
return @{ $self->{candidate_dirs} } if $self->{candidate_dirs} && ! @arg;
|
||||||
|
$self->{candidate_dirs} = \@arg if @arg;
|
||||||
|
push @{ $self->{candidate_dirs} },
|
||||||
|
$self->qphome . '/var/db', $self->qphome . '/config';
|
||||||
|
return @{ $self->{candidate_dirs} };
|
||||||
|
}
|
||||||
|
|
||||||
sub validate_dir {
|
sub validate_dir {
|
||||||
my ( $self, $d ) = @_;
|
my ( $self, $d ) = @_;
|
||||||
return 0 if ! $d;
|
return 0 if ! $d;
|
||||||
|
@ -347,10 +347,16 @@ sub _register_standard_hooks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub db_args {
|
||||||
|
my ( $self, %arg ) = @_;
|
||||||
|
$self->{db_args} = \%arg if %arg;
|
||||||
|
$self->{db_args}{name} ||= $self->plugin_name;
|
||||||
|
return %{ $self->{db_args} };
|
||||||
|
}
|
||||||
|
|
||||||
sub db {
|
sub db {
|
||||||
my ( $self, %arg ) = @_;
|
my ( $self, %arg ) = @_;
|
||||||
$arg{name} ||= $self->plugin_name;
|
return $self->{db} ||= Qpsmtpd::DB->new( $self->db_args(%arg) );
|
||||||
return $self->{db} ||= Qpsmtpd::DB->new(%arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -211,7 +211,7 @@ sub register {
|
|||||||
$config->{reject} = $config->{mode} =~ /testonly|off/i ? 0 : 1;
|
$config->{reject} = $config->{mode} =~ /testonly|off/i ? 0 : 1;
|
||||||
}
|
}
|
||||||
$self->{_args} = $config;
|
$self->{_args} = $config;
|
||||||
$self->init_db() or return;
|
$self->init_db();
|
||||||
$self->register_hooks();
|
$self->register_hooks();
|
||||||
$self->prune_db();
|
$self->prune_db();
|
||||||
if ($self->{_args}{upgrade}) {
|
if ($self->{_args}{upgrade}) {
|
||||||
@ -233,22 +233,20 @@ sub register_hooks {
|
|||||||
|
|
||||||
sub init_db {
|
sub init_db {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
return $self->init_redis if $self->{_args}{redis};
|
if ( $self->{_args}{redis} ) {
|
||||||
return $self->init_dbm;
|
$self->init_redis;
|
||||||
|
} else {
|
||||||
|
$self->init_dbm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub init_redis {
|
sub init_redis {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
eval {
|
$self->db_args(
|
||||||
$self->db(
|
name => 'greylist',
|
||||||
name => 'greylist',
|
class => 'Qpsmtpd::DB::Redis',
|
||||||
class => 'Qpsmtpd::DB::Redis',
|
server => $self->parse_redis_server,
|
||||||
server => $self->parse_redis_server,
|
);
|
||||||
) or die 'Unknown error';
|
|
||||||
};
|
|
||||||
return 1 if ! $@;
|
|
||||||
$self->log(LOGCRIT, "Unable to connect to redis, GREYLISTING DISABLED: $@");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parse_redis_server {
|
sub parse_redis_server {
|
||||||
@ -263,19 +261,18 @@ sub init_dbm {
|
|||||||
$self->db(
|
$self->db(
|
||||||
name => 'greylist',
|
name => 'greylist',
|
||||||
class => 'Qpsmtpd::DB::File::DBM'
|
class => 'Qpsmtpd::DB::File::DBM'
|
||||||
) or return 0;
|
);
|
||||||
my $cdir = $self->{_args}{db_dir};
|
my $cdir = $self->{_args}{db_dir};
|
||||||
$cdir = $1 if $cdir and $cdir =~ m{^([-a-zA-Z0-9./_]+)$};
|
$cdir = $1 if $cdir and $cdir =~ m{^([-a-zA-Z0-9./_]+)$};
|
||||||
# greylisting-specific hints for where to store the greylist DB
|
# greylisting-specific hints for where to store the greylist DB
|
||||||
my $db_dir = $self->db->dir( $cdir, '/var/lib/qpsmtpd/greylisting' );
|
my $db_dir = $self->db->dir( $cdir, '/var/lib/qpsmtpd/greylisting' );
|
||||||
$self->db->nfs_locking( $self->{_args}{nfslock} );
|
$self->db->nfs_locking( $self->{_args}{nfslock} );
|
||||||
|
|
||||||
# Work around old DBM filename
|
# Work around old DBM filename
|
||||||
return 1 if -f "$db_dir/greylist.dbm";
|
|
||||||
my $oldname = 'denysoft_greylist';
|
my $oldname = 'denysoft_greylist';
|
||||||
return 1 if ! -f "$db_dir/$oldname.dbm";
|
if ( ! -f "$db_dir/greylist.dbm" && -f "$db_dir/$oldname.dbm" ) {
|
||||||
$self->db->name($oldname);
|
$self->db->name($oldname);
|
||||||
return 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_exclude_files {
|
sub load_exclude_files {
|
||||||
|
@ -333,19 +333,26 @@ sub rc {
|
|||||||
sub test_init_redis {
|
sub test_init_redis {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
delete $self->{db};
|
delete $self->{db};
|
||||||
$self->{_args}{redis} = 'bogusserverasdfqwerty.:6379';
|
$self->{_args}{redis} = 'testredis';
|
||||||
ok( ! $self->init_redis, 'init_redis() fails on bogus server' );
|
$self->init_db;
|
||||||
eval { Qpsmtpd::DB::Redis->new };
|
is( keyvals($self->db_args),
|
||||||
return if $@;
|
'class=Qpsmtpd::DB::Redis;name=greylist;server=testredis:6379',
|
||||||
$self->{_args}{redis} = 'localhost';
|
'init_redis() sets redis args' );
|
||||||
ok( $self->init_redis, 'init_redis() succeeds when redis is up' );
|
}
|
||||||
|
|
||||||
|
sub keyvals {
|
||||||
|
my ( %h ) = @_;
|
||||||
|
return join ";", map { "$_=$h{$_}" } sort keys %h;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub test_init_dbm {
|
sub test_init_dbm {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
delete $self->{db};
|
delete $self->{db};
|
||||||
delete $self->{_args}{redis};
|
delete $self->{_args}{redis};
|
||||||
ok( $self->init_db, 'init_db() works for DBM' );
|
$self->init_db;
|
||||||
|
is( $self->db->name, 'greylist', 'init_dbm() sets correct db name' );
|
||||||
|
is( $self->db->path, 't/config/greylist.dbm', 'init_dbm() sets correct path' );
|
||||||
|
is( ref $self->db, 'Qpsmtpd::DB::File::DBM', 'init_dbm() gives DBM object' );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub test_parse_redis_server {
|
sub test_parse_redis_server {
|
||||||
|
@ -19,6 +19,7 @@ __get_keys();
|
|||||||
__size();
|
__size();
|
||||||
__flush();
|
__flush();
|
||||||
__qphome();
|
__qphome();
|
||||||
|
__candidate_dirs();
|
||||||
__validate_dir();
|
__validate_dir();
|
||||||
__dir();
|
__dir();
|
||||||
__untie_gotcha();
|
__untie_gotcha();
|
||||||
@ -108,6 +109,15 @@ sub __qphome {
|
|||||||
is( $db->qphome, 't', 'qphome()' );
|
is( $db->qphome, 't', 'qphome()' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub __candidate_dirs {
|
||||||
|
is( join('|', $db->candidate_dirs), 't/var/db|t/config',
|
||||||
|
'candidate_dirs() default ' );
|
||||||
|
is( join('|', $db->candidate_dirs('foo')), 'foo|t/var/db|t/config',
|
||||||
|
'candidate_dirs() passed args plus defaults' );
|
||||||
|
is( join('|', $db->candidate_dirs), 'foo|t/var/db|t/config',
|
||||||
|
'candidate_dirs() cached values' );
|
||||||
|
}
|
||||||
|
|
||||||
sub __validate_dir {
|
sub __validate_dir {
|
||||||
is( $db->validate_dir(), 0, 'validate_dir(): false on no input' );
|
is( $db->validate_dir(), 0, 'validate_dir(): false on no input' );
|
||||||
is( $db->validate_dir(undef), 0, 'validate_dir(): false on undef' );
|
is( $db->validate_dir(undef), 0, 'validate_dir(): false on undef' );
|
||||||
|
@ -9,11 +9,33 @@ use Test::Qpsmtpd;
|
|||||||
|
|
||||||
use_ok('Qpsmtpd::Plugin');
|
use_ok('Qpsmtpd::Plugin');
|
||||||
|
|
||||||
|
__db_args();
|
||||||
__db();
|
__db();
|
||||||
__register_hook();
|
__register_hook();
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
||||||
|
sub __db_args {
|
||||||
|
my $plugin = FakePlugin->new;
|
||||||
|
is( keyvals($plugin->db_args),
|
||||||
|
'name=___MockHook___',
|
||||||
|
'default db args populated' );
|
||||||
|
is( keyvals($plugin->db_args( arg1 => 1 )),
|
||||||
|
'arg1=1;name=___MockHook___',
|
||||||
|
'passed args in addition to defaults' );
|
||||||
|
is( keyvals($plugin->db_args( name => 'bob', arg2 => 2 )),
|
||||||
|
'arg2=2;name=bob',
|
||||||
|
'passed args override defaults' );
|
||||||
|
is( keyvals($plugin->db_args),
|
||||||
|
'arg2=2;name=bob',
|
||||||
|
'get previous args' );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub keyvals {
|
||||||
|
my ( %h ) = @_;
|
||||||
|
return join ";", map { "$_=$h{$_}" } sort keys %h;
|
||||||
|
}
|
||||||
|
|
||||||
sub __db {
|
sub __db {
|
||||||
my $plugin = FakePlugin->new;
|
my $plugin = FakePlugin->new;
|
||||||
my $db = $plugin->db( class => 'FakeDB', name => 'testfoo' );
|
my $db = $plugin->db( class => 'FakeDB', name => 'testfoo' );
|
||||||
|
Loading…
Reference in New Issue
Block a user