Matt Fischer a5da52ec52 Keystone hooks support
This code moves all deps to an external class so that Keystone can be
installed with mechanisms besides packages (like venv or docker). This
also cleans-up the dependency tree by removing false or confusing
dependencies.

Change-Id: If69cd7cba267f75faad51fdbc80a58b24d2095d8
Co-Author: Clayton O'Neill <clayton.oneill@twcable.com>
2016-03-15 20:11:25 -06:00

344 lines
11 KiB
Puppet

#
# Class to serve keystone with apache mod_wsgi in place of keystone service
#
# Serving keystone from apache is the recommended way to go for production
# systems as the current keystone implementation is not multi-processor aware,
# thus limiting the performance for concurrent accesses.
#
# See the following URIs for reference:
# https://etherpad.openstack.org/havana-keystone-performance
# http://adam.younglogic.com/2012/03/keystone-should-move-to-apache-httpd/
#
# When using this class you should disable your keystone service.
#
# == Parameters
#
# [*servername*]
# The servername for the virtualhost.
# Optional. Defaults to $::fqdn
#
# [*public_port*]
# The public port.
# Optional. Defaults to 5000
#
# [*admin_port*]
# The admin port.
# Optional. Defaults to 35357
#
# [*bind_host*]
# The host/ip address Apache will listen on.
# Optional. Defaults to undef (listen on all ip addresses).
#
# [*admin_bind_host*]
# The host/ip address Apache will listen on for admin API connections.
# Optional. Defaults to undef or bind_host if only that setting is used.
#
# [*public_path*]
# The prefix for the public endpoint.
# Optional. Defaults to '/'
#
# [*admin_path*]
# The prefix for the admin endpoint.
# Optional. Defaults to '/'
#
# [*ssl*]
# Use ssl ? (boolean)
# Optional. Defaults to true
#
# [*workers*]
# Number of WSGI workers to spawn.
# Optional. Defaults to 1
#
# [*ssl_cert*]
# (optional) Path to SSL certificate
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_key*]
# (optional) Path to SSL key
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_chain*]
# (optional) SSL chain
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_ca*]
# (optional) Path to SSL certificate authority
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_crl_path*]
# (optional) Path to SSL certificate revocation list
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_crl*]
# (optional) SSL certificate revocation list name
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_certs_dir*]
# apache::vhost ssl parameters.
# Optional. Default to apache::vhost 'ssl_*' defaults.
#
# [*priority*]
# (optional) The priority for the vhost.
# Defaults to '10'
#
# [*threads*]
# (optional) The number of threads for the vhost.
# Defaults to $::processorcount
#
# [*wsgi_script_ensure*]
# (optional) File ensure parameter for wsgi scripts.
# Defaults to 'file'.
#
# [*wsgi_script_source*]
# (optional) Wsgi script source.
# Defaults to undef.
#
# [*wsgi_application_group*]
# (optional) The application group of the WSGI script.
# Defaults to '%{GLOBAL}'
#
# [*wsgi_pass_authorization*]
# (optional) Whether HTTP authorisation headers are passed through to a WSGI
# script when the equivalent HTTP request headers are present.
# Defaults to 'On'
#
# [*access_log_format*]
# The log format for the virtualhost.
# Optional. Defaults to false.
#
# [*headers*]
# (optional) Headers for the vhost.
# Defaults to undef.
#
# [*vhost_custom_fragment*]
# (optional) Passes a string of custom configuration
# directives to be placed at the end of the vhost configuration.
# Defaults to undef.
#
# [*wsgi_chunked_request*]
# (optional) apache::vhost wsgi_chunked_request parameter.
# Defaults to undef
#
# == Dependencies
#
# requires Class['apache'] & Class['keystone']
#
# == Examples
#
# include apache
#
# class { 'keystone::wsgi::apache': }
#
# == Note about ports & paths
#
# When using same port for both endpoints (443 anyone ?), you *MUST* use two
# different public_path & admin_path !
#
# == Authors
#
# Francois Charlier <francois.charlier@enovance.com>
#
# == Copyright
#
# Copyright 2013 eNovance <licensing@enovance.com>
#
class keystone::wsgi::apache (
$servername = $::fqdn,
$public_port = 5000,
$admin_port = 35357,
$bind_host = undef,
$admin_bind_host = undef,
$public_path = '/',
$admin_path = '/',
$ssl = true,
$workers = 1,
$ssl_cert = undef,
$ssl_key = undef,
$ssl_chain = undef,
$ssl_ca = undef,
$ssl_crl_path = undef,
$ssl_crl = undef,
$ssl_certs_dir = undef,
$threads = $::processorcount,
$priority = '10',
$wsgi_script_ensure = 'file',
$wsgi_script_source = undef,
$wsgi_application_group = '%{GLOBAL}',
$wsgi_pass_authorization = 'On',
$wsgi_chunked_request = undef,
$access_log_format = false,
$headers = undef,
$vhost_custom_fragment = undef,
) {
include ::keystone::deps
include ::keystone::params
include ::apache
include ::apache::mod::wsgi
if $ssl {
include ::apache::mod::ssl
}
# The httpd package is untagged, but needs to have ordering enforced,
# so handle it here rather than in the deps class.
Anchor['keystone::install::begin']
-> Package['httpd']
-> Anchor['keystone::install::end']
# Configure apache during the config phase
Anchor['keystone::config::begin']
-> Apache::Vhost<||>
~> Anchor['keystone::config::end']
# Start the service during the service phase
Anchor['keystone::service::begin']
-> Service['httpd']
-> Anchor['keystone::service::end']
# Notify the service when config changes
Anchor['keystone::config::end']
~> Service['httpd']
## Sanitize parameters
# Ensure there's no trailing '/' except if this is also the only character
$public_path_real = regsubst($public_path, '(^/.*)/$', '\1')
# Ensure there's no trailing '/' except if this is also the only character
$admin_path_real = regsubst($admin_path, '(^/.*)/$', '\1')
if $public_port == $admin_port and $public_path_real == $admin_path_real {
fail('When using the same port for public & private endpoints, public_path and admin_path should be different.')
}
file { $::keystone::params::keystone_wsgi_script_path:
ensure => directory,
owner => 'keystone',
group => 'keystone',
require => Anchor['keystone::install::end'],
}
$wsgi_files = {
'keystone_wsgi_admin' => {
'path' => "${::keystone::params::keystone_wsgi_script_path}/admin",
},
'keystone_wsgi_main' => {
'path' => "${::keystone::params::keystone_wsgi_script_path}/main",
},
}
$wsgi_file_defaults = {
'ensure' => $wsgi_script_ensure,
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0644',
'require' => File[$::keystone::params::keystone_wsgi_script_path],
}
$wsgi_script_source_real = $wsgi_script_source ? {
default => $wsgi_script_source,
undef => $::keystone::params::keystone_wsgi_script_source,
}
case $wsgi_script_ensure {
'link': { $wsgi_file_source = { 'target' => $wsgi_script_source_real } }
default: { $wsgi_file_source = { 'source' => $wsgi_script_source_real } }
}
create_resources('file', $wsgi_files, merge($wsgi_file_defaults, $wsgi_file_source))
$wsgi_daemon_process_options_main = {
user => 'keystone',
group => 'keystone',
processes => $workers,
threads => $threads,
display-name => 'keystone-main',
}
$wsgi_daemon_process_options_admin = {
user => 'keystone',
group => 'keystone',
processes => $workers,
threads => $threads,
display-name => 'keystone-admin',
}
$wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"])
$wsgi_script_aliases_admin = hash([$admin_path_real, "${::keystone::params::keystone_wsgi_script_path}/admin"])
if $public_port == $admin_port {
$wsgi_script_aliases_main_real = merge($wsgi_script_aliases_main, $wsgi_script_aliases_admin)
} else {
$wsgi_script_aliases_main_real = $wsgi_script_aliases_main
}
if $admin_bind_host {
$real_admin_bind_host = $admin_bind_host
} else {
# backwards compat before we had admin_bind_host
$real_admin_bind_host = $bind_host
}
::apache::vhost { 'keystone_wsgi_main':
ensure => 'present',
servername => $servername,
ip => $bind_host,
port => $public_port,
docroot => $::keystone::params::keystone_wsgi_script_path,
docroot_owner => 'keystone',
docroot_group => 'keystone',
priority => $priority,
ssl => $ssl,
ssl_cert => $ssl_cert,
ssl_key => $ssl_key,
ssl_chain => $ssl_chain,
ssl_ca => $ssl_ca,
ssl_crl_path => $ssl_crl_path,
ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir,
wsgi_daemon_process => 'keystone_main',
wsgi_daemon_process_options => $wsgi_daemon_process_options_main,
wsgi_process_group => 'keystone_main',
wsgi_script_aliases => $wsgi_script_aliases_main_real,
wsgi_application_group => $wsgi_application_group,
wsgi_pass_authorization => $wsgi_pass_authorization,
headers => $headers,
custom_fragment => $vhost_custom_fragment,
wsgi_chunked_request => $wsgi_chunked_request,
require => File['keystone_wsgi_main'],
access_log_format => $access_log_format,
}
if $public_port != $admin_port {
::apache::vhost { 'keystone_wsgi_admin':
ensure => 'present',
servername => $servername,
ip => $real_admin_bind_host,
port => $admin_port,
docroot => $::keystone::params::keystone_wsgi_script_path,
docroot_owner => 'keystone',
docroot_group => 'keystone',
priority => $priority,
ssl => $ssl,
ssl_cert => $ssl_cert,
ssl_key => $ssl_key,
ssl_chain => $ssl_chain,
ssl_ca => $ssl_ca,
ssl_crl_path => $ssl_crl_path,
ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir,
wsgi_daemon_process => 'keystone_admin',
wsgi_daemon_process_options => $wsgi_daemon_process_options_admin,
wsgi_process_group => 'keystone_admin',
wsgi_script_aliases => $wsgi_script_aliases_admin,
wsgi_application_group => $wsgi_application_group,
wsgi_pass_authorization => $wsgi_pass_authorization,
headers => $headers,
custom_fragment => $vhost_custom_fragment,
wsgi_chunked_request => $wsgi_chunked_request,
require => File['keystone_wsgi_admin'],
access_log_format => $access_log_format,
}
}
}