###
### Copyright 2000-2007 University of Illinois Board of Trustees
### All rights reserved.
###
### Apache.pm - apache module for psgconf
###
### Campus Information Technologies and Educational Services
### University of Illinois at Urbana-Champaign
###
package PSGConf::Control::Apache;
use strict;
use PSGConf::Action::CopyFile;
use PSGConf::Action::ChGrp;
use PSGConf::Action::ChMod;
use PSGConf::Action::ChOwn;
use PSGConf::Action::CreateFile;
use PSGConf::Action::GenerateFile::httpd_conf;
use PSGConf::Action::GenerateFile::mime_types;
use PSGConf::Action::GenerateFile::EnvFile;
use PSGConf::Action::MkDir;
use PSGConf::Action::svcs::addpg;
use PSGConf::Action::svcs::import;
use PSGConf::Action::svcs::setprop;
use PSGConf::Action::RestartDaemon;
use PSGConf::Action::RunCommand;
use PSGConf::Data::Boolean;
use PSGConf::Data::List;
use PSGConf::Data::Hash;
use PSGConf::Data::String;
use PSGConf::Data::Table;
use PSGConf::Control::Packages qw(_add_pkgs);
use PSGConf::Util;
###############################################################################
### utility functions
###############################################################################
### canonify Apache host:port strings
### (server_name arg is used for default IP address if specified;
### otherwise, use hostname)
sub _canonify_www_addrs
{
my ($addr, $server_name, $psgconf) = @_;
my ($host, $port, @addrs);
($host, $port) = split(/:/, $addr);
if ($host =~ m/^([0-9\.]{1,3}\.){3}[0-9\.]{1,3}$/)
{
### don't modify if specified by IP address
@addrs = ($host);
}
else
{
### convert hostname to IP addresses
@addrs = get_addrs($psgconf, $host)
if ($host ne '');
### if DNS lookup fails or if no host is specified
@addrs = get_addrs($psgconf, $server_name)
if (!@addrs && $server_name ne '');
### if no server_name is specified or DNS lookup fails
@addrs = get_addrs($psgconf, $psgconf->data_obj('hostname')->get())
if (!@addrs);
}
### add port
$port = '80'
if (!defined($port));
@addrs = map { "$_:$port" } @addrs;
return @addrs;
}
###############################################################################
### policy methods
###############################################################################
### check stuff that depends on www_enable
sub _policy_check_enable
{
my ($self, $psgconf) = @_;
if ($psgconf->data_obj('www_enable')->equals('false'))
{
$psgconf->data_obj('www_vh_ssl')->unset();
$psgconf->data_obj('www_auto_start')->set('false');
}
}
### check stuff that depends on www_vh_ssl
sub _policy_check_ssl
{
my ($self, $psgconf) = @_;
if (!$psgconf->data_obj('www_vh_ssl')->count()) {
$psgconf->data_obj('www_ssl_start_reminder')->set('false');
### Remove the ssl module as well
$psgconf->data_obj('www_modules')->delete_row({0 => 'ssl'});
}
}
### initialize default server names
sub _policy_default_server_names
{
my ($self, $psgconf) = @_;
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$psgconf->data_obj('www_ssl_server_name')->set(
$psgconf->data_obj('hostname')->get()
) if ($psgconf->data_obj('www_vh_ssl')->count() &&
! defined $psgconf->data_obj('www_ssl_server_name')->get());
}
### initialize default vhosts
sub _policy_default_vhosts
{
my ($self, $psgconf) = @_;
return
if ($psgconf->data_obj('www_enable')->equals('false'));
if (defined $psgconf->data_obj('www_server_name')->get()
&& !defined $psgconf->data_obj('www_virtual_hosts')->find('http'))
{
$psgconf->data_obj('www_virtual_hosts')->insert(
{ 'http' => [ $psgconf->data_obj('www_server_name')->get() ] }
);
}
if (defined $psgconf->data_obj('www_ssl_server_name')->get()
&& !defined $psgconf->data_obj('www_virtual_hosts')->find('https'))
{
$psgconf->data_obj('www_virtual_hosts')->insert(
{ 'https' => [ $psgconf->data_obj('www_ssl_server_name')->get(), ':443' ] }
);
$psgconf->data_obj('www_vh_ssl')->insert(
{ 'https' => undef }
);
}
}
sub _policy_canonify_www_log_dir
{
my ($self, $psgconf) = @_;
my ($syslog);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
### set logfile location
$psgconf->data_obj('www_log_dir')->set('httpd')
if (!defined $psgconf->data_obj('www_log_dir')->get());
$psgconf->data_obj('www_log_dir')->prepend(
$psgconf->data_obj('log_dir')->get() . '/'
) if (! $psgconf->data_obj('www_log_dir')->match('^/'));
### If we are logging to syslog, then add the
### appropiate syslog.conf entry
if ( $psgconf->data_obj('www_log_syslog')->equals('true') ) {
if ( $psgconf->data_obj('syslog_enable')->equals('true') ) {
### If we have the format syslog:NAME, grab name to
### put into the syslog.conf file. By default Apache
### uses local7, so assume that if :NAME is missing.
$psgconf->data_obj('syslog')->insert( {
$psgconf->data_obj('www_log_dir')->get() . '/error_log'
=> $psgconf->data_obj('www_log_fac')->get()
. '.' . $psgconf->data_obj('www_log_level')->get()
} );
}
}
}
### set default pidfile location
sub _policy_default_pidfile
{
my ($self, $psgconf) = @_;
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$psgconf->data_obj('www_global_options')->insert(
{ 'PidFile' => $psgconf->data_obj('pidfile_dir')->get() . '/httpd.pid' }
) if (!defined $psgconf->data_obj('www_global_options')->find('PidFile'));
}
### convert vhost addresses to IP-addr:port
sub _policy_default_vhost_addrs
{
my ($self, $psgconf) = @_;
my ($www_virtual_hosts);
my ($vhost, $lref, $idx, @addrs);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$www_virtual_hosts = $psgconf->data_obj('www_virtual_hosts')->get();
foreach $vhost (keys %$www_virtual_hosts)
{
$www_virtual_hosts->{$vhost} = [ $psgconf->data_obj('hostname')->get() ]
if (! defined($www_virtual_hosts->{$vhost}));
$lref = $www_virtual_hosts->{$vhost};
if (@$lref < 2)
{
push(@$lref, _canonify_www_addrs(undef, $lref->[0],
$psgconf));
}
else
{
for ($idx = 1; $idx < @$lref; $idx++)
{
@addrs = _canonify_www_addrs($lref->[$idx],
$lref->[0],
$psgconf);
splice(@$lref, $idx, 1, @addrs);
}
}
}
}
### set default listen addresses based on vhost addrs
sub _policy_default_listen_addrs
{
my ($self, $psgconf) = @_;
my ($www_listen_addrs, $www_virtual_hosts);
my ($vhost, $lref);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$www_virtual_hosts = $psgconf->data_obj('www_virtual_hosts')->get();
$www_listen_addrs = $psgconf->data_obj('www_listen_addrs')->get();
if (! %$www_listen_addrs)
{
foreach $vhost (keys %$www_virtual_hosts)
{
$lref = $www_virtual_hosts->{$vhost};
map { $www_listen_addrs->{$_} = undef; }
@$lref[1..$#$lref];
}
}
}
sub _policy_canonify_modules
{
my ($self, $psgconf) = @_;
my ($mod);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
foreach $mod (@{$psgconf->data_obj('www_modules')->get()})
{
next
if ($mod->[0] eq '');
### set default module path
$mod->[1] = 'mod_' . $mod->[0] . '.so'
if (!defined($mod->[1]) || $mod->[1] eq '');
$mod->[1] = $psgconf->data_obj('www_module_dir')->get() . '/' . $mod->[1]
if (substr($mod->[1], 0, 1) ne '/');
### verify that module exists
warn "\n\t!!!Apache module $mod->[1] does not exist\n"
if (! -e $mod->[1]);
### set default add name
$mod->[2] = 'mod_' . $mod->[0] . '.c'
if (!defined($mod->[2]) || $mod->[2] eq '');
}
}
### determine absolute paths for vhost access logs
sub _policy_canonify_vhost_access_logs
{
my ($self, $psgconf) = @_;
my ($www_log_dir, $www_virtual_hosts, $access_logs, $vhost);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$www_virtual_hosts = $psgconf->data_obj('www_virtual_hosts')->get();
$www_log_dir = $psgconf->data_obj('www_log_dir')->get();
$access_logs = $psgconf->data_obj('www_vh_access_log')->get();
foreach $vhost (keys %$access_logs)
{
$access_logs->{$vhost} = $www_log_dir
. '/'
. $access_logs->{$vhost}
if (substr($access_logs->{$vhost}, 0, 1) ne '/');
}
}
### determine absolute path for document root locations
sub _policy_canonify_vhost_doc_roots
{
my ($self, $psgconf) = @_;
my ($www_server_dir, $www_virtual_hosts, $doc_roots, $vhost);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$www_server_dir = $psgconf->data_obj('www_server_dir')->get();
$www_virtual_hosts = $psgconf->data_obj('www_virtual_hosts')->get();
$doc_roots = $psgconf->data_obj('www_vh_document_root')->get();
foreach $vhost (keys %$doc_roots)
{
$doc_roots->{$vhost} = $www_server_dir
. '/'
. $doc_roots->{$vhost}
if (substr($doc_roots->{$vhost}, 0, 1) ne '/');
}
}
### remove non-existant vhosts from www_vh_* data objs
sub _policy_validate_vhost_data
{
my ($self, $psgconf) = @_;
my ($vhost, $directive);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
foreach $directive ( 'www_vh_document_root',
'www_vh_access_log',
'www_vh_ssl',
'www_vh_config'
)
{
foreach $vhost (keys %{$psgconf->data_obj($directive)->get()})
{
$psgconf->data_obj($directive)->delete($vhost)
if (!$psgconf->data_obj('www_virtual_hosts')->exists($vhost));
}
}
}
### set up RC script
sub _policy_add_rc_scripts
{
my ($self, $psgconf) = @_;
my ($start_cmd, $sendmail_path);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
if ($psgconf->data_obj('www_ssl_start_reminder')->equals('true'))
{
$sendmail_path = $psgconf->data_obj('sendmail_path')->get();
$start_cmd = <<PCA_EOF;
echo "NOTE: SSL web server must be manually restarted!";
$sendmail_path -t -oem <<EOF
From: root
To: root
Subject: HTTPS SERVER REMINDER
HTTPS web server must be manually restarted!
EOF
PCA_EOF
}
else
{
$start_cmd = $psgconf->data_obj('www_apachectl_path')->get() . ' start';
$start_cmd .= 'ssl'
if ($psgconf->data_obj('www_vh_ssl')->count());
}
if ($psgconf->data_obj('platform')->match('solaris10')) {
if ($psgconf->data_obj('www_use_apache2')->equals('true')) {
$psgconf->data_obj('rc_scripts')->insert(
{'apache2' => { 'state' => 'enable' }}
);
} else {
$psgconf->data_obj('rc_scripts')->insert(
{'apache' => { 'state' => 'enable' }}
);
}
} else {
$psgconf->data_obj('rc_scripts')->insert(
{'httpd' => {
'state' => 'enable',
'start_cmd' => $start_cmd,
'stop_cmd' => $psgconf->data_obj('www_apachectl_path')->get() . ' stop'
}
}
);
}
}
### create httpd user
sub _policy_add_user
{
my ($self, $psgconf) = @_;
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$psgconf->data_obj('group_info')->insert(
{ $psgconf->data_obj('www_group_name')->get() => {} }
) if (!defined $psgconf->data_obj('group_info')->find(
$psgconf->data_obj('www_group_name')->get()));
$psgconf->data_obj('user_info')->insert(
{ $psgconf->data_obj('www_user_name')->get() => {
'group' => $psgconf->data_obj('www_group_name')->get(),
'passwd' => $psgconf->data_obj('passwd_token')->get(),
'home' => $psgconf->data_obj('www_config_dir')->get(),
'gecos' => 'Apache Webserver',
'shell' => '/bin/false'
}
}
) if (!defined $psgconf->data_obj('user_info')->find($psgconf->data_obj('www_user_name')->get()));
}
### setup webmaster aliases
sub _policy_add_sendmail_aliases
{
my ($self, $psgconf) = @_;
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$psgconf->data_obj('sendmail_aliases')->insert(
{ $psgconf->data_obj('www_user_name')->get() => 'root' }
) if (!defined $psgconf->data_obj('sendmail_aliases')->find($psgconf->data_obj('www_user_name')->get()));
$psgconf->data_obj('sendmail_aliases')->insert(
{ $psgconf->data_obj('www_admin_alias')->get() => 'root' }
) if (!defined $psgconf->data_obj('sendmail_aliases')->find($psgconf->data_obj('www_admin_alias')->get()));
}
### request apache and openssl packages
sub _policy_add_packages
{
my ($self, $psgconf) = @_;
$self->_add_pkgs($psgconf);
$self->{enable} = 'www_vh_ssl';
$self->{packages} = 'openssl_packages';
$self->_add_pkgs($psgconf);
}
### set default www_name_vhost_addrs
sub _policy_default_name_vhost_addrs
{
my ($self, $psgconf) = @_;
my ($www_virtual_hosts, $lref, $vhost, $name_vhost_addrs, %addrs);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$name_vhost_addrs = $psgconf->data_obj('www_name_vhost_addrs')->get();
$www_virtual_hosts = $psgconf->data_obj('www_virtual_hosts')->get();
return
if (%$name_vhost_addrs);
### add addresses of all virtual hosts
foreach $vhost (keys %$www_virtual_hosts)
{
$lref = $www_virtual_hosts->{$vhost};
map { $addrs{$_}++; } @$lref[1..$#$lref];
}
### warn if trying to use name-based vhosting for SSL vhost
foreach $vhost (keys %$www_virtual_hosts)
{
$lref = $www_virtual_hosts->{$vhost};
map {
warn "\n\t!!!SSL virtual host "
. "\"$vhost\" cannot share listen "
. "address \"$_\"\n"
if ( $psgconf->data_obj('www_vh_ssl')->exists($vhost)
&& ($addrs{$_} > 1));
} @$lref[1..$#$lref];
}
### those addresses serving more than one vhost are name-based
map {
$name_vhost_addrs->{$_} = undef
if ($addrs{$_} > 1);
} keys %addrs;
}
#
# Check to see if svc.confd needs to be stopped & restarted before
# importing the apache2 .xml config.
#
sub _kill_svc_configd
{
my ($psgconf) = @_;
my ($ret);
# a return of 1 means that the FMRI doesn't exist, so svc.configd needs
# to be killed so we can import the http-apache2 xml file
$ret = PSGConf::Util::RunCommand('/usr/bin/svcs http > /dev/null', 1);
return $ret;
}
###############################################################################
### decide() method
###############################################################################
sub decide
{
my ($self, $psgconf) = @_;
my ($www_config_dir, $www_server_dir, @logs, $uid, $gid);
return
if ($psgconf->data_obj('www_enable')->equals('false'));
$www_config_dir = $psgconf->data_obj('www_config_dir')->get();
$www_server_dir = $psgconf->data_obj('www_server_dir')->get();
$uid = ( defined $psgconf->data_obj('user_info')->find($psgconf->data_obj('www_user_name')->get()))?
$psgconf->data_obj('user_info')->find($psgconf->data_obj('www_user_name')->get())->{'uid'}:
-1;
$gid = ( defined $psgconf->data_obj('user_info')->find($psgconf->data_obj('www_user_name')->get()))?
$psgconf->data_obj('user_info')->find($psgconf->data_obj('www_user_name')->get())->{'gid'}:
-1;
$psgconf->data_obj('www_mime_dir')->set($www_config_dir)
if ( ! defined $psgconf->data_obj('www_mime_dir')->get() );
@logs = (
$psgconf->data_obj('www_log_dir')->get() . '/access_log'
);
push @logs, $psgconf->data_obj('www_log_dir')->get() . '/error_log'
if ($psgconf->data_obj('www_log_syslog')->equals('false'));
push @logs, $psgconf->data_obj('www_log_dir')->get() . '/suexec'
if ( -f $psgconf->data_obj('www_log_dir')->get() . '/suexec' );
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') );
### set up config and content trees
$psgconf->register_actions(
PSGConf::Action::MkDir->new(
name => $www_server_dir
),
PSGConf::Action::MkDir->new(
name => $psgconf->data_obj('www_document_dir')->get()
),
(map {
PSGConf::Action::MkDir->new(
name => $_
)
} (sort values %{$psgconf->data_obj('www_vh_document_root')->get()})),
PSGConf::Action::MkDir->new(
name => $psgconf->data_obj('www_log_dir')->get(),
uid => $uid,
gid => $gid,
mode => 0755
),
(map {
if ( ! -f $_ ) {
PSGConf::Action::CreateFile->new(
name => $_,
mode => 0644,
uid => $uid,
gid => $gid
);
} else {
PSGConf::Action::ChMod->new(
name => $_,
mode => 0644
),
PSGConf::Action::ChOwn->new(
name => $_,
uid => $uid
),
PSGConf::Action::ChGrp->new(
name => $_,
gid => $gid
);
}
} @logs),
PSGConf::Action::MkDir->new(
name => $www_config_dir,
uid => $uid,
gid => $gid,
mode => 0755
),
($psgconf->data_obj('www_vh_ssl')->count()
? (PSGConf::Action::MkDir->new(
name => $www_config_dir . '/ssl.key',
mode => 0700
),
PSGConf::Action::MkDir->new(
name => $www_config_dir . '/ssl.csr'
),
PSGConf::Action::MkDir->new(
name => $www_config_dir . '/ssl.crt'
)
)
: ()
),
PSGConf::Action::GenerateFile::httpd_conf->new(
name => "$www_config_dir/httpd.conf",
description => 'Apache httpd configuration',
use_apache2 => $psgconf->data_obj('www_use_apache2')->equals('true'),
pidfile_dir => $psgconf->data_obj('pidfile_dir')->get(),
icons_dir => $psgconf->data_obj('www_icons_dir')->get(),
server_dir => $psgconf->data_obj('www_server_dir')->get(),
document_dir => $psgconf->data_obj('www_document_dir')->get(),
default_allowoverride => $psgconf->data_obj('www_default_allowoverride')->get(),
config_dir => $psgconf->data_obj('www_config_dir')->get(),
mime_dir => $psgconf->data_obj('www_mime_dir')->get(),
user_name => $psgconf->data_obj('www_user_name')->get(),
group_name => $psgconf->data_obj('www_group_name')->get(),
log_level => $psgconf->data_obj('www_log_level')->get(),
ssl_log_level => $psgconf->data_obj('www_ssl_log_level')->get(),
ssl_cipher_suite => $psgconf->data_obj('www_ssl_cipher_suite')->get(),
log_dir => $psgconf->data_obj('www_log_dir')->get(),
log_syslog => $psgconf->data_obj('www_log_syslog')->get(),
log_fac => $psgconf->data_obj('www_log_fac')->get(),
global_options => $psgconf->data_obj('www_global_options')->get(),
listen_addrs => $psgconf->data_obj('www_listen_addrs')->get(),
virtual_hosts => $psgconf->data_obj('www_virtual_hosts')->get(),
vh_ssl => $psgconf->data_obj('www_vh_ssl')->get(),
global_config => $psgconf->data_obj('www_global_config')->get(),
modules => $psgconf->data_obj('www_modules')->get(),
module_dir => $psgconf->data_obj('www_module_dir')->get(),
main_server_name => $psgconf->data_obj('hostname')->get(),
main_server_options => $psgconf->data_obj('www_main_server_options')->get(),
main_server_config => $psgconf->data_obj('www_main_server_config')->get(),
main_admin_alias => $psgconf->data_obj('www_admin_alias')->get(),
vh_document_root => $psgconf->data_obj('www_vh_document_root')->get(),
vh_access_log => $psgconf->data_obj('www_vh_access_log')->get(),
vh_config => $psgconf->data_obj('www_vh_config')->get(),
name_vhost_addrs => $psgconf->data_obj('www_name_vhost_addrs')->get()
),
PSGConf::Action::CopyFile->new(
name => "$www_config_dir/magic",
copy_from => 'magic'
),
PSGConf::Action::GenerateFile::mime_types->new(
name => $psgconf->data_obj('www_mime_dir')->get() . '/mime.types',
description => 'Apache MIME types file',
types => $psgconf->data_obj('www_mime_types')->get()
)
);
###
### Since the apache2 import does not work correctly,
### it was recommended to HUP svc.configd instead.
###
$psgconf->register_actions(
PSGConf::Action::RunCommand->new(
name => 'Kill svc.configd',
command => '/usr/bin/pkill svc.configd',
check_func => \&_kill_svc_configd
),
PSGConf::Action::RunCommand->new(
name => 'sleep for 10 seconds',
command => '/usr/bin/sleep 10',
check_func => \&_kill_svc_configd
),
PSGConf::Action::svcs::import->new(
name => 'Import Apache2 SMF configurations',
FMRI => 'svc:/network/http:apache2',
manifest => '/var/svc/manifest/network/http-apache2.xml'
),
### FIXME: The following is a hack to fix the problem
### (Sun Bug ID #6270245) where apache2 starts before
### the filesystem is mounted RW when you are using SVM
### to mirror the boot disks.
PSGConf::Action::svcs::addpg->new(
name => 'Adding filesystem-local dependency',
FMRI => 'svc:/network/http:apache2',
group => 'filesystem-local',
type => 'dependency',
refresh => 0
),
PSGConf::Action::svcs::setprop->new(
name => 'set entities property',
FMRI => 'svc:/network/http:apache2',
property => 'filesystem-local/entities',
value => 'fmri: svc:/system/filesystem/local:default',
refresh => 0
),
PSGConf::Action::svcs::setprop->new(
name => 'set grouping property',
FMRI => 'svc:/network/http:apache2',
property => 'filesystem-local/grouping',
value => 'astring: require_all',
refresh => 0
),
PSGConf::Action::svcs::setprop->new(
name => 'set restart_on property',
FMRI => 'svc:/network/http:apache2',
property => 'filesystem-local/restart_on',
value => 'astring: none',
refresh => 0
),
PSGConf::Action::svcs::setprop->new(
name => 'set type property',
FMRI => 'svc:/network/http:apache2',
property => 'filesystem-local/type',
value => 'astring: service',
refresh => 1
)
) if ( $psgconf->data_obj('www_use_apache2')->equals('true') &&
$psgconf->data_obj('platform')->match('solaris10') );
$psgconf->register_actions(
PSGConf::Action::svcs::setprop->new(
name => 'enable Apache2 SSL',
FMRI => 'svc:/network/http:apache2',
property => 'httpd/ssl',
value => 'true',
refresh => 0
)
) if (defined $psgconf->data_obj('www_ssl_server_name')->get() &&
$psgconf->data_obj('www_use_apache2')->equals('true') &&
$psgconf->data_obj('platform')->match('solaris10') );
$psgconf->register_actions(
PSGConf::Action::RunCommand->new(
name => 'Restart Apache',
command => $psgconf->data_obj('www_apachectl_path')->get() . ' graceful',
filename => [ "$www_config_dir/httpd.conf" ]
)
) if ($psgconf->{'restart_daemons'});
$psgconf->register_actions(
PSGConf::Action::GenerateFile::EnvFile->new(
name => '/etc/sysconfig/httpd',
description => 'Apache startup options',
quote_values => 1,
vars => {
OPTIONS => ($psgconf->data_obj('www_vh_ssl')->count())? '-DSSL': ''
}
)
) if ($psgconf->data_obj('platform')->match('(-rhel-)|(-rhl-)|(-fc-)'));
}
###############################################################################
### Constructor
###############################################################################
sub new
{
my ($class, $psgconf) = @_;
my ($self);
$self = {};
bless($self, $class);
### So that _add_pkgs knows which directives to look at
$self->{name} = 'www';
$self->{enable} = $self->{name} . '_enable';
$self->{packages} = $self->{name} . '_packages';
$psgconf->register_data(
'www_apachectl_path' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/usr/local/sbin/apachectl'
),
'www_auto_start' => PSGConf::Data::Boolean->new(
value => 'false'
),
'www_packages' => PSGConf::Data::List->new(),
'openssl_packages' => PSGConf::Data::List->new(),
'www_config_dir' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/usr/local/etc/apache'
),
'www_mime_dir' => PSGConf::Data::String->new(
'value_abspath' => 1
),
'www_enable' => PSGConf::Data::Boolean->new(
value => 'false'
),
'www_use_apache2' => PSGConf::Data::Boolean->new(
value => 'false'
),
'www_default_allowoverride' => PSGConf::Data::String->new(
value => 'None'
),
'www_global_config' => PSGConf::Data::String->new(),
'www_global_options' => PSGConf::Data::Hash->new(),
'www_icons_dir' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/usr/local/share/apache/icons'
),
'www_listen_addrs' => PSGConf::Data::Hash->new(
value_optional => 1
),
'www_name_vhost_addrs' => PSGConf::Data::Hash->new(
value_optional => 1
),
'www_log_dir' => PSGConf::Data::String->new(),
'www_log_syslog' => PSGConf::Data::Boolean->new(
value => 'false'
),
'www_log_fac' => PSGConf::Data::String->new(
value => 'local7'
),
'www_log_level' => PSGConf::Data::String->new(
value => 'warn'
),
'www_ssl_log_level' => PSGConf::Data::String->new(
value => 'info'
),
'www_user_name' => PSGConf::Data::String->new(
value => 'httpd'
),
'www_group_name' => PSGConf::Data::String->new(
value => 'httpd'
),
'www_admin_alias' => PSGConf::Data::String->new(
value => 'webmaster'
),
'www_main_server_config'
=> PSGConf::Data::String->new(),
'www_main_server_options'
=> PSGConf::Data::Hash->new(),
'www_mime_types' => PSGConf::Data::Hash->new(
value_optional => 1,
value_type => 'HASH'
),
'www_modules' => PSGConf::Data::Table->new(),
'www_module_dir' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/usr/local/libexec'
),
'www_server_name' => PSGConf::Data::String->new(),
'www_server_dir' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/services/www'
),
'www_document_dir' => PSGConf::Data::String->new(
'value_abspath' => 1,
value => '/services/www/htdocs'
),
'www_ssl_server_name' => PSGConf::Data::String->new(),
'www_ssl_cipher_suite' => PSGConf::Data::String->new(
value => 'ALL:!ADH:!EXP56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL'
),
'www_ssl_start_reminder'
=> PSGConf::Data::Boolean->new(
value => 'false'
),
'www_virtual_hosts' => PSGConf::Data::Hash->new(
value_type => 'ARRAY',
value_optional => 1
),
'www_vh_config' => PSGConf::Data::Hash->new(),
'www_vh_document_root' => PSGConf::Data::Hash->new(),
'www_vh_access_log' => PSGConf::Data::Hash->new(),
'www_vh_ssl' => PSGConf::Data::Hash->new(
value_optional => 1
)
);
$psgconf->register_policy($self,
apache_check_enable
=> '_policy_check_enable',
apache_check_ssl
=> '_policy_check_ssl',
apache_canonify_modules
=> '_policy_canonify_modules',
apache_default_server_names
=> '_policy_default_server_names',
apache_default_vhosts
=> '_policy_default_vhosts',
apache_default_vhost_addrs
=> '_policy_default_vhost_addrs',
apache_default_listen_addrs
=> '_policy_default_listen_addrs',
apache_default_pidfile
=> '_policy_default_pidfile',
apache_validate_vhost_data
=> '_policy_validate_vhost_data',
apache_default_name_vhost_addrs
=> '_policy_default_name_vhost_addrs',
apache_canonify_www_log_dir
=> '_policy_canonify_www_log_dir',
apache_canonify_vhost_access_logs
=> '_policy_canonify_vhost_access_logs',
apache_canonify_vhost_doc_roots
=> '_policy_canonify_vhost_doc_roots',
apache_add_rc_scripts
=> '_policy_add_rc_scripts',
apache_add_user
=> '_policy_add_user',
apache_add_sendmail_aliases
=> '_policy_add_sendmail_aliases',
apache_add_packages
=> '_policy_add_packages'
);
return $self;
}
###############################################################################
### documentation
###############################################################################
1;
__END__
=head1 NAME
PSGConf::Control::Apache - psgconf control class for Apache
=head1 SYNOPSIS
In F<psgconf_modules>:
Control PSGConf::Control::Apache
=head1 DESCRIPTION
The B<PSGConf::Control::Apache> module provides a B<psgconf> control object
for configuring the Apache webserver. 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<www_apachectl_path>
A B<PSGConf::Data::String> object containing the absolute path to the
I<apachectl> command. The default is F</usr/local/sbin/apachectl>.
=item I<www_auto_start>
A B<PSGConf::Data::Boolean> object indicating whether Apache should be
started automatically at boot time.
=item I<www_packages>
A B<PSGConf::Data::List> object listing what apache packages to install.
=item I<openssl_packages>
A B<PSGConf::Data::List> object listing what openssl packages to install.
=item I<www_config_dir>
A B<PSGConf::Data::String> object containing the absolute path to the
Apache configuration directory. The default is
F</usr/local/etc/apache>.
=item I<www_mime_dir>
A B<PSGConf::Data::String> object containing the absolute path to the
directory the mime.types file resides in. The default is
I<www_config_dir> directive value.
=item I<www_enable>
A B<PSGConf::Data::Boolean> object indicating whether Apache should be
configured.
=item I<www_use_apache2>
A B<PSGConf::Data::Boolean> object indicating whether Apache2 syntax
should be used in the config file.
=item I<www_default_allowoverride>
A B<PSGConf::Data::String> object containing the default value for
AllowOverride that gets put into the virtual host DocumentRoot as
well as the global DocumentRoot sections. Defaults to C<None>.
=item I<www_global_config>
A B<PSGConf::Data::String> object containing global configuration
directives for F<httpd.conf>.
=item I<www_global_options>
A B<PSGConf::Data::Hash> object containing global configuration options
(and the corresponding values) for F<httpd.conf>.
=item I<www_icons_dir>
A B<PSGConf::Data::String> object containing the absolute path to the
Apache icons directory. The default is F</usr/local/share/apache/icons>.
=item I<www_listen_addrs>
A B<PSGConf::Data::Hash> object whose keys are the addresses and ports
to bind to. Each key is a string of the form C<hostname>, C<address>,
C<hostname:port>, or C<address:port>. If C<:port> is not specified, it
defaults to port 80.
=item I<www_user_name>
A B<PSGConf::Data::String> object containing the name of the login
to run the httpd process as. The default is B<httpd>.
=item I<www_group_name>
A B<PSGConf::Data::String> object containing the name of the group
to run the httpd process as. The default is B<httpd>.
=item I<www_log_dir>
A B<PSGConf::Data::String> object containing the path to the Apache
log directory. If not an absolute path, it will be located under the
directory specified by the I<log_dir> data object (which is provided by
the B<PSGConf::Control::Core> module).
=item I<www_log_syslog>
A B<PSGConf::Data::Boolean> object telling apache to use the C<syslog(1)>
facility to do the logging. The default is no to.
=item I<www_log_fac>
A B<PSGConf::Data::String> object containing the syslog facility to log to.
Defaults to I<local7>.
=item I<www_log_level>
A B<PSGConf::Data::String> object containing the verbosity of the logs.
The default is B<warn>.
=item I<www_ssl_log_level>
A B<PSGConf::Data::String> object containing the verbosity of the logs.
The default is B<info>.
=item I<www_main_server_config>
A B<PSGConf::Data::String> object containing configuration directives
for the main virtual host.
=item I<www_main_server_options>
A B<PSGConf::Data::Hash> object containing configuration options
(and the corresponding values) for the main virtual host.
=item I<www_admin_alias>
A B<PSGConf::Data::String> object containing the name of the email
alias to send problems to. The default is B<webmaster>.
=item I<www_mime_types>
A B<PSGConf::Data::Hash> object containing MIME types (e.g.,
C<application/postscript>) to an anonymous hash whose keys are the list
of file extensions used for that MIME type.
=item I<www_modules>
A B<PSGConf::Data::Table> object containing the list of Apache modules to
load. Each row in the table consists of the following fields: module
name, filename (if different from F<mod_MODULENAME.so>), argument to
C<AddModule> directive (if different from F<mod_MODULENAME.c>), and
conditional value (i.e., set to C<SSL> to wrap the C<LoadModule> and
C<AddModule> directives in a C<E<lt>IfModule SSLE<gt>> block).
=item I<www_module_dir>
A B<PSGConf::Data::String> object that contains the absolute path to the
Apache modules. The default is F</usr/local/libexec>.
=item I<www_name_vhost_addrs>
A B<PSGConf::Data::Hash> object whose keys are the address/port pairs
for which name-based virtual hosting should be used.
=item I<www_server_name>
A B<PSGConf::Data::String> object containing the server name of the
C<http> virtual host. (This is the same as creating an C<http> entry
in the I<www_virtual_hosts> object.)
=item I<www_server_dir>
A B<PSGConf::Data::String> object that contains the absolute path to the
Apache content tree. The default is F</services/www>.
=item I<www_document_dir>
A B<PSGConf::Data::String> object that contains the absolute path to the
Apache DocumentRoot tree. The default is F</services/www/htdocs>.
=item I<www_ssl_server_name>
A B<PSGConf::Data::String> object containing the server name of the
C<https> virtual host. (This is the same as creating an C<https> entry
in the I<www_virtual_hosts> and I<www_vh_ssl> objects.)
=item I<www_ssl_cipher_suite>
A B<PSGConf::Data::String> object containing the codes for the
C<httpd.conf> directive I<SSLCipherSuite>. Defaults to
I<ALL:!ADH:!EXP56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL>
=item I<www_ssl_start_reminder>
A B<PSGConf::Data::Boolean> object that indicates whether the boot
script should print and email a reminder that Apache needs to be started
manually.
=item I<www_virtual_hosts>
A B<PSGConf::Data::Hash> object that contains virtual host definitions.
The hash key is the label for the virtual host, and the value is a reference
to a list containing the server name followed by zero or more addresses.
The addresses are strings of the form C<hostname>, C<address>,
C<hostname:port>, C<address:port>, or just C<:port>. If C<:port> is
not specified, it defaults to port 80. If no hostname or address is
specified, it defaults to the IP address of the server name.
=item I<www_vh_config>
A B<PSGConf::Data::Hash> object that contains a configuration directives
for each virtual host. The hash key is the name of the virtual host,
and the value is the text that should be placed within the virtual host
block.
=item I<www_vh_document_root>
A B<PSGConf::Data::Hash> object that contains the document root for each
virtual host. The hash key is the name of the virtual host, and the
value is the document root directory. If not an absolute path, the
directory will be located in the directory specified by the
I<www_server_dir> data object.
=item I<www_vh_access_log>
A B<PSGConf::Data::Hash> object that contains the access log name for
each virtual host. The hash key is the name of the virtual host, and
the value is the name of the log file. If not an absolute path, the file
will be placed in the directory specified by the I<www_log_dir> data
object.
=item I<www_vh_ssl>
A B<PSGConf::Data::Hash> object whose keys are the names of virtual
hosts which serve HTTPS requests.
=back
In addition, the constructor registers the following policy methods:
=over 4
=item I<apache_check_enable>
If I<www_enable> is not set, unsets I<www_vh_ssl> and I<www_auto_start>.
=item I<apache_check_ssl>
If I<www_vh_ssl> is not set, unset I<www_ssl_start_reminder>.
=item I<apache_default_server_names>
If I<www_enable> is set, updates I<www_server_name> and
I<www_ssl_server_name> from I<hostname> if they are not set.
=item I<apache_default_vhosts>
If I<www_enable> is set, updates I<www_virtual_hosts> and I<www_vh_ssl>
based on I<www_server_name> and I<www_ssl_server_name>.
=item I<apache_canonify_www_log_dir>
If the value of the I<www_log_dir> data object is not an absolute path,
prepends the value of the I<log_dir> data object (supplied by the
B<PSGConf::Control::Core> module).
=item I<apache_default_pidfile>
If the I<www_global_options> object does not have an entry for
C<PidFile>, set it to F<I<pidfile_dir>/httpd.pid>. (The I<pidfile_dir>
data object is provided by the B<PSGConf::Control::Core> module.)
=item I<apache_default_vhost_addrs>
Canonifies information for each entry in I<www_virtual_hosts>.
If no server name is specified, set it to I<hostname>. If no addresses
are specified, add the IP address of our primary network interface; if
no port is specified, set it to 80.
=item I<apache_default_listen_addrs>
If I<www_listen_addrs> is not set, add the addresses of every virtual
host.
=item I<apache_canonify_modules>
For each entry in I<www_modules>, if the module path is not set, set it
to F</usr/local/libexec/mod_MODULENAME.so>. If the module add name is
not set, set it to C<mod_MODULENAME.c>.
=item I<apache_canonify_vhost_access_logs>
For each value in I<www_vh_access_log> that is not an absolute path,
prepends the value of the I<www_log_dir> data object.
=item I<apache_canonify_vhost_doc_roots>
For each value in I<www_vh_document_root> that is not an absolute path,
prepends the value of the I<www_server_dir> data object.
=item I<apache_validate_vhost_data>
Deletes entries in I<www_vh_access_log>, I<www_vh_document_root>,
I<www_vh_ssl>, and I<www_vh_config> for virtual hosts that are not listed
in I<www_virtual_hosts>.
=item I<apache_add_rc_scripts>
Requests an RC script for Apache using the I<rc_scripts> data object,
which is supplied by the B<PSGConf::Control::InitScripts> module.
=item I<apache_add_user>
Adds a user and group named C<httpd> to the I<user_info> and
I<group_info> data objects, supplied by the B<PSGConf::Control::Users>
module.
=item I<apache_add_sendmail_aliases>
If mail aliases for C<httpd> and C<webmaster> do not exist, make them
point to C<root>. This is done using the I<sendmail_aliases> data
object, which is provided by the B<PSGConf::Control::sendmail> module.
=item I<apache_add_packages>
Request the C<apache> package be installed. If I<www_vh_ssl> is set,
also request the C<openssl> package. Packages are requested using the
B<pkg_install_list> data object, which is provided by the
B<PSGConf::Control::Packages> module.
=item I<apache_default_name_vhost_addrs>
If I<www_name_vhost_addrs> is not set, add all addresses/port pairs that
are used by more than one virtual host.
=back
=item decide()
Instantiates and registers action objects, as follows:
=over 4
=item *
Registers a B<PSGConf::Action::MkDir> action object to create the
I<www_server_dir> directory.
=item *
Registers a B<PSGConf::Action::MkDir> action object to create the
F<I<www_server_dir>/htdocs> directory, which is the document root for
the main server.
=item *
Registers a B<PSGConf::Action::MkDir> action object to create the
document root for each virtual host.
=item *
Registers a B<PSGConf::Action::MkDir> action object to create the
I<www_log_dir> directory. This directory will be owned by user and
group I<httpd>.
=item *
Registers a B<PSGConf::Action::MkDir> action object to create the
I<www_config_dir> directory.
=item *
If the I<www_vh_ssl> object has any entries, registers
a B<PSGConf::Action::MkDir> action object to create the
F<I<www_config_dir>/ssl.key> directory.
=item *
If the I<www_vh_ssl> object has any entries, registers
a B<PSGConf::Action::MkDir> action object to create the
F<I<www_config_dir>/ssl.csr> directory.
=item *
If the I<www_vh_ssl> object has any entries, registers
a B<PSGConf::Action::MkDir> action object to create the
F<I<www_config_dir>/ssl.crt> directory.
=item *
Registers a B<PSGConf::Action::GenerateFile::httpd_conf> object to
generate the F<I<www_config_dir>/httpd.conf> file.
=item *
Registers a B<PSGConf::Action::GenerateFile::mime_types> object to
generate the F<I<www_config_dir>/mime.types> file.
=item *
Registers a B<PSGConf::Action::CopyFile> action object to install the
F<magic> file in I<www_config_dir>.
=back
=back
=head1 BUGS
Instead of distributing canned versions of the F<magic> file, it should
be generated dynamically from config data.
Some F<httpd.conf> data is still hard-coded. This should be made more
flexible.
=head1 SEE ALSO
L<perl>
httpd(8)
apachectl(8)
L<PSGConf>
L<PSGConf::Action::CopyFile>
L<PSGConf::Action::ChGrp>
L<PSGConf::Action::ChMod>
L<PSGConf::Action::ChOwn>
L<PSGConf::Action::CreateFile>
L<PSGConf::Action::GenerateFile::EnvFile>
L<PSGConf::Action::GenerateFile::httpd_conf>
L<PSGConf::Action::GenerateFile::mime_types>
L<PSGConf::Action::MkDir>
L<PSGConf::Action::RunCommand>
L<PSGConf::Action::svcs::import>
L<PSGConf::Action::svcs::setprop>
L<PSGConf::Control::Core>
L<PSGConf::Control::InitScripts>
L<PSGConf::Control::Packages>
L<PSGConf::Control::sendmail>
L<PSGConf::Control::Users>
L<PSGConf::Data::Boolean>
L<PSGConf::Data::Hash>
L<PSGConf::Data::String>
L<PSGConf::Data::Table>
L<PSGConf::Util>
L<psgconf-intro>
=cut
syntax highlighted by Code2HTML, v. 0.9.1