###
###  Copyright 2000-2007 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  PSGConf::Control::logrotate - psgconf control class for controlling log rotation/pruning
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Control::logrotate;

use PSGConf::Action::MkDir;
use PSGConf::Action::GenerateFile::Literal;
use PSGConf::Action::Remove;

use PSGConf::Data::Boolean;
use PSGConf::Data::Hash;


###############################################################################
### policies
###############################################################################

sub _add_files
{
	my ($psgconf, $cmd, $missing, @files) = @_;
	my ($files, $file);

	$files = $psgconf->data_obj('logrotate_files')->get();
	foreach $file ( @files ) {
		if ( ! exists $files->{$file} ) {
			$files->{$file}->{sharedscripts} = undef;
			$files->{$file}->{postrotate} = 
				"\n\t\t" . $cmd . "\n\tendscript"
				if ( defined $cmd );
			$files->{$file}->{missingok} = undef
				if ( defined $missing );
		}
	}
}

sub _policy_add_syslog_files
{
	my ($self, $psgconf) = @_;
	my (@logs);
 
	return
		if ($psgconf->data_obj('syslog_enable')->equals('false')
			|| $psgconf->data_obj('logrotate_enable')->equals('false'));
 
	map {
		push @logs, $_ if ( -f $_ );
	} keys %{$psgconf->data_obj('syslog')->get()};

	&_add_files ($psgconf,
		"/usr/bin/killall -HUP syslogd",
		undef,
		@logs );
}

sub _policy_add_www_files 
{
     my ($self, $psgconf) = @_;
	my (@logs);

	return
		if ($psgconf->data_obj('www_enable')->equals('false')
			|| $psgconf->data_obj('logrotate_enable')->equals('false'));

     @logs = (
          $psgconf->data_obj('www_log_dir')->get() . '/suexec.log',
          $psgconf->data_obj('www_log_dir')->get() . '/error_log',
          $psgconf->data_obj('www_log_dir')->get() . '/access_log'
     );

     map { push @logs, $_; } values %{$psgconf->data_obj('www_vh_access_log')->get()};

     push @logs, $psgconf->data_obj('www_log_dir')->get() . '/ssl_engine_log'
          if ( $psgconf->data_obj('www_vh_ssl')->count() );

     push @logs, $psgconf->data_obj('www_jk_logfile')->get()
          if ( $psgconf->data_obj('www_jk_enable')->equals('true') );

     ###
     ### FIXME: Need to add the bluestem and any other logs not in
     ### the stock psgconf modules.  This really screams to be put
     ### into a method that other Control modules can call from w/i
     ### one of their policies.
     ###

	&_add_files ( $psgconf, 
		$psgconf->data_obj('www_apachectl_path')->get() . " graceful > /dev/null 2>&1", 
		1,
		@logs);
}

sub _policy_add_ftp_files 
{
     my ($self, $psgconf) = @_;

	return
		if ($psgconf->data_obj('anon_ftp_enable')->equals('false')
			|| $psgconf->data_obj('logrotate_enable')->equals('false'));

	if ( $psgconf->data_obj('anon_ftp_use_vsftpd')->equals('true') ) {
		&_add_files ($psgconf, undef, undef, ( $psgconf->data_obj('log_dir')->get() . '/vsftpd.log' ));
	} else {
		&_add_files ($psgconf, undef, undef, ( $psgconf->data_obj('log_dir')->get() . '/xferlog' ));
	}
}

###############################################################################
### contstructor
###############################################################################

sub new {
	my ($class, $psgconf) = @_;
	my ($self);
  
	$self = {};
  
	bless($self, $class);
  
	$self->{name} = 'logrotate';
	$self->{enable} = $self->{name} . '_enable';
	$self->{packages} = $self->{name} . '_packages';

	$psgconf->register_data(
		'logrotate_enable'	=> PSGConf::Data::Boolean->new(
							'value' => 'false'
						),
		'logrotate_options'	=> PSGConf::Data::Hash->new(
							value_optional => 1
						),
		'logrotate_files'	=> PSGConf::Data::Hash->new(
							value_type => 'HASH'
						)
	);

	$psgconf->register_policy($self,
		logrotate_add_syslog_files	=> '_policy_add_syslog_files',
		logrotate_add_ftp_files		=> '_policy_add_ftp_files',
		logrotate_add_www_files		=> '_policy_add_www_files'
	);

	return $self;
}

###############################################################################
###  decide() method
###
###  create /etc/logrotate.d if it doesn't exist
###
###  generate /etc/logrotate.conf based on options and files
###     specified in psg.conf
###############################################################################

sub decide {
	my ($self, $psgconf) = @_;
	my ($conffile);
	my ($options) = $psgconf->data_obj('logrotate_options')->get();
	my ($files) = $psgconf->data_obj('logrotate_files')->get();
	
	return
		if ($psgconf->data_obj('logrotate_enable')->equals('false'));

	# generate the global options in the /etc/logrotate.conf file
	map {
		$conffile .= "$_ " . $options->{"$_"} . "\n";
	} (keys %$options);

	$conffile .= "include /etc/logrotate.d\n\n\n";

	# generate the file section of /etc/logrotate.conf

	map {
		my ($file, $fileops);
		$file = $_;
		$fileops = $files->{"$file"};

		$conffile .= "$file {\n";

		# the file name is the key to the first hash - 
		# the value is another hash containing options for the file
		map {

			$conffile .= "\t$_ " . $fileops->{"$_"} . "\n";
	    
		} (sort keys %$fileops);

		$conffile .= "}\n\n";
	} (sort keys %$files);
	
	### create /etc/logrotate.conf
	$psgconf->register_actions(
		PSGConf::Action::GenerateFile::Literal->new(
			name		=> '/etc/logrotate.conf',
			content	=> $conffile
		),
		PSGConf::Action::MkDir->new(
			name		=> '/etc/logrotate.d'
		)
	);
	$psgconf->register_actions(
		PSGConf::Action::Remove->new(
			name		=> '/etc/logrotate.d/syslog',
			backup	=> 0
		)
	) if ( $psgconf->data_obj('syslog_enable')->equals('true') );
	$psgconf->register_actions(
		PSGConf::Action::Remove->new(
			name		=> '/etc/logrotate.d/httpd',
			backup	=> 0
		)
	) if ( $psgconf->data_obj('www_enable')->equals('true') );
	$psgconf->register_actions(
		PSGConf::Action::Remove->new(
			name		=> '/etc/logrotate.d/vsftpd.log',
			backup	=> 0
		)
	) if ( $psgconf->data_obj('anon_ftp_enable')->equals('true') &&
		$psgconf->data_obj('anon_ftp_use_vsftpd')->equals('true') );
}

1;

__END__

=head1 NAME

PSGConf::Control::logrotate - psgconf control class for controlling log rotation/pruning

=head1 SYNOPSIS

In F<psgconf_modules>:

  Control PSGConf::Control::logrotate

=head1 DESCRIPTION

The B<PSGConf::Control::logrotate> module provides a B<psgconf> control object
for rotating system logs using the logrotate facility.
It supports the following methods:

=over 4

=item new()

The constructor.  Its parameter is a reference to the B<PSGConf>
object.  It registers the following data objects:

=over 4

=item I<logrotate_enable>

A B<PSGConf::Data::Boolean> object to enable/disable this feature

=item I<logrotate_options>

A B<PSGConf::Data::Hash> object for global logrotate options to be added to the logrotate.conf file:
    logrotate_options { "compress", "rotate" => "14", "daily" }

=item I<logrotate_file>

A B<PSGConf::Data::Hash> object of B<PSGConf::Data::Hash> objects with the key to the main hash being the path to a log file, and the contained has being options for that specific log file:

    logrotate_files { "/var/log/wtmp" => { "daily", "create 0664 root utmp", "rotate 14" } };

=back

The constructor also registers the following policy methods:

=over 4

=item I<logrotate_add_syslog_files>

Requests that the C<syslog> files be rotated.

=item I<logrotate_add_ftp_files>

Requests that the C<anon_ftp> log files be rotated.

=item I<logrotate_add_www_files>

Requests that the C<apache> log files be rotated.

=back

=item decide()

Registers a B<PSGConf::Action::GenerateFile::Literal> Action object to
generate the F</etc/logrotate.conf> file.  It will also remove the
f</etc/logrotate.d/syslog> file if it exists and we are configured
to rotate syslog files.

=back

=head1 SEE ALSO

L<perl>

C<CE<lt>logrotate(8)E<gt>>

L<PSGConf>

L<PSGConf::Action::MkDir>

L<PSGConf::Action::GenerateFile::Literal>

L<PSGConf::Action::Remove>

L<PSGConf::Data::Hash>

L<PSGConf::Data::Boolean>

L<psgconf-intro>

=cut



syntax highlighted by Code2HTML, v. 0.9.1