diff --git a/.fixtures.yml b/.fixtures.yml index a3f4dbbb..d5ce9483 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,6 +1,8 @@ fixtures: repositories: + apache: git://github.com/puppetlabs/puppetlabs-apache.git aviator: git://github.com/aimonb/puppet_aviator.git + concat: git://github.com/puppetlabs/puppetlabs-concat.git mysql: git://github.com/puppetlabs/puppetlabs-mysql.git postgresql: git://github.com/puppetlabs/puppetlabs-postgresql.git stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git diff --git a/manifests/wsgi/apache.pp b/manifests/wsgi/apache.pp new file mode 100644 index 00000000..469484aa --- /dev/null +++ b/manifests/wsgi/apache.pp @@ -0,0 +1,189 @@ +# +# Copyright (C) 2014 eNovance SAS <licensing@enovance.com> +# +# Author: Emilien Macchi <emilien.macchi@enovance.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: openstacklib::wsgi::apache +# +# Serve a service with apache mod_wsgi +# When using this class you should disable your service. +# +# == Parameters +# +# [*service_name*] +# (optional) Name of the service to run. +# Example: nova-api +# Defaults to $name +# +# [*servername*] +# (optional) The servername for the virtualhost. +# Defaults to $::fqdn +# +# [*bind_host*] +# (optional) The host/ip address Apache will listen on. +# Defaults to undef (listen on all ip addresses). +# +# [*bind_port*] +# (optional) The port to listen. +# Defaults to undef +# +# [*group*] +# (optional) Group with permissions on the script +# Defaults to undef +# +# [*path*] +# (optional) The prefix for the endpoint. +# Defaults to '/' +# +# [*priority*] +# (optional) The priority for the vhost. +# Defaults to '10' +# +# [*ssl*] +# (optional) Use ssl ? (boolean) +# Defaults to false +# +# [*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*] +# (optional) Path to SSL certificate directory +# Default to apache::vhost 'ssl_*' defaults. +# +# [*threads*] +# (optional) The number of threads for the vhost. +# Defaults to $::processorcount +# +# [*user*] +# (optional) User with permissions on the script +# Defaults to undef +# +# [*workers*] +# (optional) The number of workers for the vhost. +# Defaults to '1' +# +# [*wsgi_script_path*] +# (optional) The path of the WSGI script. +# Defaults to undef +# +# [*wsgi_script_script*] +# (optional) The source of the WSGI script. +# Defaults to undef +# +define openstacklib::wsgi::apache ( + $service_name = $name, + $bind_host = undef, + $bind_port = undef, + $group = undef, + $path = '/', + $priority = '10', + $servername = $::fqdn, + $ssl = false, + $ssl_ca = undef, + $ssl_cert = undef, + $ssl_certs_dir = undef, + $ssl_chain = undef, + $ssl_crl = undef, + $ssl_crl_path = undef, + $ssl_key = undef, + $threads = $::processorcount, + $user = undef, + $workers = 1, + $wsgi_script_path = undef, + $wsgi_script_source = undef, +) { + + include ::apache + include ::apache::mod::wsgi + if $ssl { + include ::apache::mod::ssl + } + + # Ensure there's no trailing '/' except if this is also the only character + $path_real = regsubst($path, '(^/.*)/$', '\1') + + if !defined(File[$wsgi_script_path]) { + file { $wsgi_script_path: + ensure => directory, + owner => $user, + group => $group, + require => Package['httpd'], + } + } + + file { "${service_name}_wsgi": + ensure => file, + path => "${wsgi_script_path}/${service_name}_wsgi", + source => $wsgi_script_source, + owner => $user, + group => $group, + mode => '0644', + require => File[$wsgi_script_path], + } + + $wsgi_daemon_process_options = { + owner => $user, + group => $group, + processes => $workers, + threads => $threads, + } + $wsgi_script_aliases = hash([$path_real,$wsgi_script_path]) + + ::apache::vhost { "${service_name}_wsgi": + ensure => 'present', + servername => $servername, + ip => $bind_host, + port => $bind_port, + docroot => $wsgi_script_path, + docroot_owner => $user, + docroot_group => $group, + 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 => $service_name, + wsgi_daemon_process_options => $wsgi_daemon_process_options, + wsgi_process_group => $service_name, + wsgi_script_aliases => $wsgi_script_aliases, + require => File["${service_name}_wsgi"], + } + +} diff --git a/metadata.json b/metadata.json index ae6e3279..1b8a8322 100644 --- a/metadata.json +++ b/metadata.json @@ -32,6 +32,7 @@ "description": "Puppet module library to expose common functionality between OpenStack modules.", "dependencies": [ { "name": "aimonb/aviator", "version_requirement": ">=0.4.2 <1.0.0" }, + { "name": "puppetlabs/apache", "version_requirement": ">=1.0.0 <2.0.0" }, { "name": "puppetlabs/mysql", "version_requirement": ">=2.2.0 <3.0.0" }, { "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" }, { "name": "puppetlabs/rabbitmq", "version_requirement": ">=2.0.2 <4.0.0" }, diff --git a/spec/defines/openstacklib_wsgi_apache_spec.rb b/spec/defines/openstacklib_wsgi_apache_spec.rb new file mode 100644 index 00000000..bc3522d1 --- /dev/null +++ b/spec/defines/openstacklib_wsgi_apache_spec.rb @@ -0,0 +1,120 @@ +# +# Copyright (C) 2014 eNovance SAS <licensing@enovance.com> +# +# Author: Emilien Macchi <emilien.macchi@enovance.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +require 'spec_helper' + +describe 'openstacklib::wsgi::apache' do + + let (:title) { 'keystone' } + + let :global_facts do + { + :processorcount => 42, + :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' + } + end + + let :params do + { + :bind_port => 5000, + :group => 'keystone', + :ssl => true, + :user => 'keystone', + :wsgi_script_path => '/var/www/cgi-bin/keystone', + :wsgi_script_source => '/usr/share/keystone/keystone.wsgi' + } + end + + shared_examples_for 'apache serving a service with mod_wsgi' do + it { should contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) } + it { should contain_class('apache') } + it { should contain_class('apache::mod::wsgi') } + + describe 'with default parameters' do + + it { should contain_file('/var/www/cgi-bin/keystone').with( + 'ensure' => 'directory', + 'owner' => 'keystone', + 'group' => 'keystone', + 'require' => 'Package[httpd]' + )} + + it { should contain_file('keystone_wsgi').with( + 'ensure' => 'file', + 'path' => '/var/www/cgi-bin/keystone/keystone_wsgi', + 'source' => '/usr/share/keystone/keystone.wsgi', + 'owner' => 'keystone', + 'group' => 'keystone', + 'mode' => '0644', + )} + + it { should contain_apache__vhost('keystone_wsgi').with( + 'servername' => 'some.host.tld', + 'ip' => nil, + 'port' => '5000', + 'docroot' => '/var/www/cgi-bin/keystone', + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'true', + 'wsgi_daemon_process' => 'keystone', + 'wsgi_process_group' => 'keystone', + 'wsgi_script_aliases' => { '/' => "/var/www/cgi-bin/keystone" }, + 'require' => 'File[keystone_wsgi]' + )} + it { should contain_file("#{platform_parameters[:httpd_ports_file]}") } + end + + end + + context 'on RedHat platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7.0' + }) + end + + let :platform_parameters do + { + :httpd_service_name => 'httpd', + :httpd_ports_file => '/etc/httpd/conf/ports.conf', + } + end + + it_configures 'apache serving a service with mod_wsgi' + end + + context 'on Debian platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '7.0' + }) + end + + let :platform_parameters do + { + :httpd_service_name => 'apache2', + :httpd_ports_file => '/etc/apache2/ports.conf', + } + end + + it_configures 'apache serving a service with mod_wsgi' + end +end diff --git a/spec/shared_examples.rb b/spec/shared_examples.rb new file mode 100644 index 00000000..d92156a3 --- /dev/null +++ b/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ecd609ae..4f919c0f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,13 @@ require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' require 'vcr' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end + VCR.configure do |c| c.cassette_library_dir = 'spec/fixtures/vcr' c.hook_into :faraday