diff --git a/spec/acceptance/itk_spec.rb b/spec/acceptance/itk_spec.rb index 9832ad4d..2283e00b 100644 --- a/spec/acceptance/itk_spec.rb +++ b/spec/acceptance/itk_spec.rb @@ -1,50 +1,50 @@ # frozen_string_literal: true require 'spec_helper_acceptance' case os[:family] when 'debian', 'ubuntu' service_name = 'apache2' variant = :prefork when 'redhat' - unless os[:release] =~ %r{^5} + unless %r{^5}.match?(os[:release]) variant = (os[:release].to_i >= 7) ? :prefork : :itk_only service_name = 'httpd' end when 'freebsd' service_name = 'apache24' variant = :prefork end # IAC-787: The http-itk mod package is not available in any of the standard RHEL/CentOS 8.x repos. Disable this test # on those platforms until we can find a suitable source for this package. describe 'apache::mod::itk class', if: service_name && mod_supported_on_platform?('apache::mod::itk') do describe 'running puppet code' do let(:pp) do case variant when :prefork <<-MANIFEST class { 'apache': mpm_module => 'prefork', } class { 'apache::mod::itk': } MANIFEST when :itk_only <<-MANIFEST class { 'apache': mpm_module => 'itk', } MANIFEST end end it 'behaves idempotently' do idempotent_apply(pp) end end describe service(service_name), skip: 'FM-8483' do it { is_expected.to be_running } it { is_expected.to be_enabled } end end diff --git a/spec/acceptance/vhost_spec.rb b/spec/acceptance/vhost_spec.rb index 2c240b1d..8c0079e8 100644 --- a/spec/acceptance/vhost_spec.rb +++ b/spec/acceptance/vhost_spec.rb @@ -1,1292 +1,1292 @@ # frozen_string_literal: true require 'spec_helper_acceptance' apache_hash = apache_settings_hash describe 'apache::vhost define' do context 'no default vhosts' do pp = <<-MANIFEST class { 'apache': default_vhost => false, default_ssl_vhost => false, service_ensure => stopped, } if ($::osfamily == 'Suse' and $::operatingsystemrelease < '15') { exec { '/usr/bin/gensslcert': require => Class['apache'], } } elsif ($::osfamily == 'Suse' and $::operatingsystemrelease >= '15') { # In SLES 15, if not given a name, gensslcert defaults the name to be the hostname exec { '/usr/bin/gensslcert -n default': require => Class['apache'], } } MANIFEST it 'creates no default vhosts' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/15-default.conf") do it { is_expected.not_to be_file } end describe file("#{apache_hash['vhost_dir']}/15-default-ssl.conf") do it { is_expected.not_to be_file } end end context 'default vhost without ssl' do pp = <<-MANIFEST class { 'apache': } MANIFEST it 'creates a default vhost config' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/15-default.conf") do it { is_expected.to contain '' } end describe file("#{apache_hash['vhost_dir']}/15-default-ssl.conf") do it { is_expected.not_to be_file } end end context 'default vhost with ssl', unless: (os[:family] =~ %r{redhat} && os[:release].to_i == 8) do pp = <<-MANIFEST file { '#{apache_hash['run_dir']}': ensure => 'directory', recurse => true, } class { 'apache': default_ssl_vhost => true, require => File['#{apache_hash['run_dir']}'], } MANIFEST it 'creates default vhost configs' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/15-default.conf") do it { is_expected.to contain '' } end describe file("#{apache_hash['vhost_dir']}/15-default-ssl.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'SSLEngine on' } end end context 'new vhost on port 80' do pp = <<-MANIFEST class { 'apache': } file { '/var/www': ensure => 'directory', recurse => true, } apache::vhost { 'first.example.com': port => '80', docroot => '/var/www/first', require => File['/var/www'], } MANIFEST it 'configures an apache vhost' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-first.example.com.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'ServerName first.example.com' } end end context 'new proxy vhost on port 80' do pp = <<-MANIFEST class { 'apache': } apache::vhost { 'proxy.example.com': port => '80', docroot => '/var/www/proxy', proxy_pass => [ { 'path' => '/foo', 'url' => 'http://backend-foo/'}, ], proxy_preserve_host => true, proxy_error_override => true, } MANIFEST it 'configures an apache proxy vhost' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-proxy.example.com.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'ServerName proxy.example.com' } it { is_expected.to contain 'ProxyPass' } it { is_expected.to contain 'ProxyPreserveHost On' } it { is_expected.to contain 'ProxyErrorOverride On' } it { is_expected.not_to contain 'ProxyAddHeaders' } it { is_expected.not_to contain "" } end end context 'new proxy vhost on port 80' do pp = <<-MANIFEST class { 'apache': } apache::vhost { 'proxy.example.com': port => '80', docroot => '#{apache_hash['doc_root']}/proxy', proxy_pass_match => [ { 'path' => '/foo', 'url' => 'http://backend-foo/'}, ], proxy_preserve_host => true, proxy_error_override => true, } MANIFEST it 'configures an apache proxy vhost' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-proxy.example.com.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'ServerName proxy.example.com' } it { is_expected.to contain 'ProxyPassMatch /foo http://backend-foo/' } it { is_expected.to contain 'ProxyPreserveHost On' } it { is_expected.to contain 'ProxyErrorOverride On' } it { is_expected.not_to contain 'ProxyAddHeaders' } it { is_expected.not_to contain "" } end end context 'new vhost with multiple IP addresses on multiple ports' do pp = <<-MANIFEST class { 'apache': default_vhost => false, } apache::vhost { 'example.com': port => ['80', '8080'], ip => ['127.0.0.1','127.0.0.2'], ip_based => true, docroot => '/var/www/html', } host { 'host1.example.com': ip => '127.0.0.1', } host { 'host2.example.com': ip => '127.0.0.2', } file { '/var/www/html/index.html': ensure => file, content => "Hello from vhost\\n", } MANIFEST it 'configures one apache vhost with 2 ip addresses and 2 ports' do apply_manifest(pp, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end describe file("#{apache_hash['vhost_dir']}/25-example.com.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'ServerName example.com' } end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } it { is_expected.to contain 'Listen 127.0.0.1:80' } it { is_expected.to contain 'Listen 127.0.0.1:8080' } it { is_expected.to contain 'Listen 127.0.0.2:80' } it { is_expected.to contain 'Listen 127.0.0.2:8080' } it { is_expected.not_to contain 'NameVirtualHost 127.0.0.1:80' } it { is_expected.not_to contain 'NameVirtualHost 127.0.0.1:8080' } it { is_expected.not_to contain 'NameVirtualHost 127.0.0.2:80' } it { is_expected.not_to contain 'NameVirtualHost 127.0.0.2:8080' } end it 'answers to host1.example.com port 80' do run_shell('/usr/bin/curl host1.example.com:80', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from vhost\n") end end it 'answers to host1.example.com port 8080' do run_shell('/usr/bin/curl host1.example.com:8080', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from vhost\n") end end it 'answers to host2.example.com port 80' do run_shell('/usr/bin/curl host2.example.com:80', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from vhost\n") end end it 'answers to host2.example.com port 8080' do run_shell('/usr/bin/curl host2.example.com:8080', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from vhost\n") end end end context 'new vhost with IPv6 address on port 80', :ipv6 do pp = <<-MANIFEST class { 'apache': default_vhost => false, } apache::vhost { 'example.com': port => '80', ip => '::1', ip_based => true, docroot => '/var/www/html', } host { 'ipv6.example.com': ip => '::1', } file { '/var/www/html/index.html': ensure => file, content => "Hello from vhost\\n", } MANIFEST it 'configures one apache vhost with an ipv6 address' do apply_manifest(pp, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end describe file("#{apache_hash['vhost_dir']}/25-example.com.conf") do it { is_expected.to contain '' } it { is_expected.to contain 'ServerName example.com' } end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } it { is_expected.to contain 'Listen [::1]:80' } it { is_expected.not_to contain 'NameVirtualHost [::1]:80' } end it 'answers to ipv6.example.com' do run_shell('/usr/bin/curl ipv6.example.com:80', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from vhost\n") end end end context 'apache_directories' do let(:pp) do <<-MANIFEST class { 'apache': } if versioncmp('#{apache_hash['version']}', '2.4') >= 0 { $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'require' => 'all denied', } } else { $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'deny' => 'from all', } } $_directories = [ { 'path' => '/var/www/files', }, $_files_match_directory, ] apache::vhost { 'files.example.net': docroot => '/var/www/files', directories => $_directories, } file { '/var/www/files/index.html': ensure => file, content => "Hello World\\n", } file { '/var/www/files/index.html.bak': ensure => file, content => "Hello World\\n", } host { 'files.example.net': ip => '127.0.0.1', } MANIFEST end describe 'readme example, adapted' do it 'configures a vhost with Files' do apply_manifest(pp, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'answers to files.example.net #stdout' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/index.html').stdout).to eq("Hello World\n") end it 'answers to files.example.net #stderr' do result = run_shell('/usr/bin/curl -sSf files.example.net:80/index.html.bak', expect_failures: true) expect(result.stderr).to match(%r{curl: \(22\) The requested URL returned error: 403}) expect(result.exit_code).to eq 22 end end describe 'other Directory options' do pp_one = <<-MANIFEST class { 'apache': } if versioncmp($apache_version, '2.4') >= 0 { $_files_match_directory = { 'path' => 'private.html$', 'provider' => 'filesmatch', 'require' => 'all denied' } } else { $_files_match_directory = [ { 'path' => 'private.html$', 'provider' => 'filesmatch', 'deny' => 'from all' }, { 'path' => '/bar/bar.html', 'provider' => 'location', allow => [ 'from 127.0.0.1', ] }, ] } $_directories = [ { 'path' => '/var/www/files', }, { 'path' => '/foo/', 'provider' => 'location', 'directoryindex' => 'notindex.html', }, $_files_match_directory, ] apache::vhost { 'files.example.net': docroot => '/var/www/files', directories => $_directories, } file { '/var/www/files/foo': ensure => directory, } file { '/var/www/files/foo/notindex.html': ensure => file, content => "Hello Foo\\n", } file { '/var/www/files/private.html': ensure => file, content => "Hello World\\n", } file { '/var/www/files/bar': ensure => directory, } file { '/var/www/files/bar/bar.html': ensure => file, content => "Hello Bar\\n", } host { 'files.example.net': ip => '127.0.0.1', } MANIFEST it 'configures a vhost with multiple Directory sections' do apply_manifest(pp_one, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'answers to files.example.net #stdout' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/').stdout).to eq("Hello World\n") end it 'answers to files.example.net #stdout foo' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/foo/').stdout).to eq("Hello Foo\n") end it 'answers to files.example.net #stderr' do result = run_shell('/usr/bin/curl -sSf files.example.net:80/private.html', expect_failures: true) expect(result.stderr).to match(%r{curl: \(22\) The requested URL returned error: 403}) expect(result.exit_code).to eq 22 end it 'answers to files.example.net #stdout bar' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/bar/bar.html').stdout).to eq("Hello Bar\n") end end describe 'SetHandler directive' do pp_two = <<-MANIFEST class { 'apache': } apache::mod { 'status': } host { 'files.example.net': ip => '127.0.0.1', } apache::vhost { 'files.example.net': docroot => '/var/www/files', directories => [ { path => '/var/www/files', }, { path => '/server-status', provider => 'location', sethandler => 'server-status', }, ], } file { '/var/www/files/index.html': ensure => file, content => "Hello World\\n", } MANIFEST it 'configures a vhost with a SetHandler directive' do apply_manifest(pp_two, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'answers to files.example.net #stdout' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/index.html').stdout).to eq("Hello World\n") end it 'answers to files.example.net #stdout regex' do expect(run_shell('/usr/bin/curl -sSf files.example.net:80/server-status?auto').stdout).to match(%r{Scoreboard: }) end end describe 'Satisfy and Auth directive', unless: apache_hash['version'] == '2.4' do pp_two = <<-MANIFEST class { 'apache': } host { 'files.example.net': ip => '127.0.0.1', } apache::vhost { 'files.example.net': docroot => '/var/www/files', directories => [ { path => '/var/www/files/foo', auth_type => 'Basic', auth_name => 'Basic Auth', auth_user_file => '/var/www/htpasswd', auth_require => "valid-user", }, { path => '/var/www/files/bar', auth_type => 'Basic', auth_name => 'Basic Auth', auth_user_file => '/var/www/htpasswd', auth_require => 'valid-user', satisfy => 'Any', }, { path => '/var/www/files/baz', allow => 'from 10.10.10.10', auth_type => 'Basic', auth_name => 'Basic Auth', auth_user_file => '/var/www/htpasswd', auth_require => 'valid-user', satisfy => 'Any', }, ], } file { '/var/www/files/foo': ensure => directory, } file { '/var/www/files/bar': ensure => directory, } file { '/var/www/files/baz': ensure => directory, } file { '/var/www/files/foo/index.html': ensure => file, content => "Hello World\\n", } file { '/var/www/files/bar/index.html': ensure => file, content => "Hello World\\n", } file { '/var/www/files/baz/index.html': ensure => file, content => "Hello World\\n", } file { '/var/www/htpasswd': ensure => file, content => "login:IZ7jMcLSx0oQk", # "password" as password } MANIFEST it 'configures a vhost with Satisfy and Auth directive' do apply_manifest(pp_two, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } it 'answers to files.example.net' do result = run_shell('/usr/bin/curl -sSf files.example.net:80/foo/index.html', expect_failures: true) expect(result.stderr).to match(%r{curl: \(22\) The requested URL returned error: 401}) expect(result.exit_code).to eq 22 expect(run_shell('/usr/bin/curl -sSf -u login:password files.example.net:80/foo/index.html').stdout).to eq("Hello World\n") expect(run_shell('/usr/bin/curl -sSf files.example.net:80/bar/index.html').stdout).to eq("Hello World\n") expect(run_shell('/usr/bin/curl -sSf -u login:password files.example.net:80/bar/index.html').stdout).to eq("Hello World\n") result = run_shell('/usr/bin/curl -sSf files.example.net:80/baz/index.html', expect_failures: true) expect(result.stderr).to match(%r{curl: \(22\) The requested URL returned error: 401}) expect(result.exit_code).to eq 22 expect(run_shell('/usr/bin/curl -sSf -u login:password files.example.net:80/baz/index.html').stdout).to eq("Hello World\n") end end end end context 'virtual_docroot hosting separate sites' do pp = <<-MANIFEST class { 'apache': } apache::vhost { 'virt.example.com': vhost_name => '*', serveraliases => '*virt.example.com', port => '80', docroot => '/var/www/virt', virtual_docroot => '/var/www/virt/%1', } host { 'virt.example.com': ip => '127.0.0.1', } host { 'a.virt.example.com': ip => '127.0.0.1', } host { 'b.virt.example.com': ip => '127.0.0.1', } file { [ '/var/www/virt/a', '/var/www/virt/b', ]: ensure => directory, } file { '/var/www/virt/a/index.html': ensure => file, content => "Hello from a.virt\\n", } file { '/var/www/virt/b/index.html': ensure => file, content => "Hello from b.virt\\n", } MANIFEST it 'configures a vhost with VirtualDocumentRoot' do apply_manifest(pp, catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'answers to a.virt.example.com' do run_shell('/usr/bin/curl a.virt.example.com:80', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from a.virt\n") end end it 'answers to b.virt.example.com' do run_shell('/usr/bin/curl b.virt.example.com:80', acceptable_exit_codes: 0) do |r| expect(r.stdout).to eq("Hello from b.virt\n") end end end context 'proxy_pass for alternative vhost' do it 'configures a local vhost and a proxy vhost' do apply_manifest(%( class { 'apache': default_vhost => false, } apache::vhost { 'localhost': docroot => '/var/www/local', ip => '127.0.0.1', port => '8888', } apache::listen { '*:80': } apache::vhost { 'proxy.example.com': docroot => '/var/www', port => '80', add_listen => false, proxy_pass => { 'path' => '/', 'url' => 'http://localhost:8888/subdir/', }, } host { 'proxy.example.com': ip => '127.0.0.1', } file { ['/var/www/local', '/var/www/local/subdir']: ensure => directory, } file { '/var/www/local/subdir/index.html': ensure => file, content => "Hello from localhost\\n", } ), catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'gets a response from the back end #stdout' do run_shell('/usr/bin/curl --max-redirs 0 proxy.example.com:80') do |r| expect(r.stdout).to eq("Hello from localhost\n") end end it 'gets a response from the back end #exit_code' do run_shell('/usr/bin/curl --max-redirs 0 proxy.example.com:80') do |r| expect(r.exit_code).to eq(0) end end end context 'proxy_pass_match for alternative vhost' do it 'configures a local vhost and a proxy vhost' do apply_manifest(%( class { 'apache': default_vhost => false, } apache::vhost { 'localhost': docroot => '/var/www/local', ip => '127.0.0.1', port => '8888', } apache::listen { '*:80': } apache::vhost { 'proxy.example.com': docroot => '/var/www', port => '80', add_listen => false, proxy_pass_match => { 'path' => '/', 'url' => 'http://localhost:8888/subdir/', }, } host { 'proxy.example.com': ip => '127.0.0.1', } file { ['/var/www/local', '/var/www/local/subdir']: ensure => directory, } file { '/var/www/local/subdir/index.html': ensure => file, content => "Hello from localhost\\n", } ), catch_failures: true) end describe service(apache_hash['service_name']), skip: 'FM-8483' do it { is_expected.to be_enabled } it { is_expected.to be_running } end it 'gets a response from the back end #stdout' do run_shell('/usr/bin/curl --max-redirs 0 proxy.example.com:80') do |r| expect(r.stdout).to eq("Hello from localhost\n") end end it 'gets a response from the back end #exit_code' do run_shell('/usr/bin/curl --max-redirs 0 proxy.example.com:80') do |r| expect(r.exit_code).to eq(0) end end end describe 'ip_based' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', ip_based => true, servername => 'test.server', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } it { is_expected.not_to contain 'NameVirtualHost test.server' } end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'ServerName test.server' } end end describe 'ip_based and no servername' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', ip_based => true, servername => '', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } it { is_expected.not_to contain 'NameVirtualHost test.server' } end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.not_to contain 'ServerName' } end end describe 'add_listen' do pp = <<-MANIFEST class { 'apache': default_vhost => false } host { 'testlisten.server': ip => '127.0.0.1' } apache::listen { '81': } apache::vhost { 'testlisten.server': docroot => '/tmp', port => '80', add_listen => false, servername => 'testlisten.server', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } it { is_expected.not_to contain 'Listen 80' } it { is_expected.to contain 'Listen 81' } end end describe 'docroot' do pp = <<-MANIFEST user { 'test_owner': ensure => present, } group { 'test_group': ensure => present, } class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp/test', docroot_owner => 'test_owner', docroot_group => 'test_group', docroot_mode => '0750', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file('/tmp/test') do it { is_expected.to be_directory } it { is_expected.to be_owned_by 'test_owner' } it { is_expected.to be_grouped_into 'test_group' } it { is_expected.to be_mode 750 } end end describe 'default_vhost' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', default_vhost => true, } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file(apache_hash['ports_file']) do it { is_expected.to be_file } end describe file("#{apache_hash['vhost_dir']}/10-test.server.conf") do it { is_expected.to be_file } end end describe 'parameter tests', if: mod_supported_on_platform?('apache::mod::itk') do pp = <<-MANIFEST class { 'apache': } host { 'test.itk': ip => '127.0.0.1' } apache::vhost { 'test.itk': docroot => '/tmp', itk => { user => 'nobody', group => 'nobody' } } host { 'test.custom_fragment': ip => '127.0.0.1' } apache::vhost { 'test.custom_fragment': docroot => '/tmp', custom_fragment => inline_template('#weird test string'), } apache::vhost { 'test.without_priority_prefix': priority => false, docroot => '/tmp' } apache::vhost { 'test.ssl_protocol': docroot => '/tmp', ssl => true, ssl_protocol => ['All', '-SSLv2'], ssl_user_name => 'SSL_CLIENT_S_DN_CN', } apache::vhost { 'test.block': docroot => '/tmp', block => 'scm', } apache::vhost { 'test.setenv_setenvif': docroot => '/tmp', setenv => ['TEST /test'], setenvif => ['Request_URI "\.gif$" object_is_image=gif'] } apache::vhost { 'test.rewrite': docroot => '/tmp', rewrites => [ { comment => 'test', rewrite_cond => '%{HTTP_USER_AGENT} ^Lynx/ [OR]', rewrite_rule => ['^index\.html$ welcome.html'], rewrite_map => ['lc int:tolower'], } ], } apache::vhost { 'test.request_headers': docroot => '/tmp', request_headers => ['append MirrorID "mirror 12"'], } apache::vhost { 'test.redirect': docroot => '/tmp', redirect_source => ['/images'], redirect_dest => ['http://test.server/'], redirect_status => ['permanent'], } apache::vhost { 'test.no_proxy_uris': docroot => '/tmp', proxy_dest => 'http://test2', no_proxy_uris => [ 'http://test2/test' ], } apache::vhost { 'test.proxy': docroot => '/tmp', proxy_dest => 'http://testproxy', } apache::vhost { 'test.scriptaliases': docroot => '/tmp', scriptaliases => [{ alias => '/myscript', path => '/usr/share/myscript', }], } apache::vhost { 'test.aliases': docroot => '/tmp', aliases => [ { alias => '/image' , path => '/ftp/pub/image' } , { scriptalias => '/myscript' , path => '/usr/share/myscript' } ], } apache::vhost { 'test.access_logs': docroot => '/tmp', logroot => '/tmp', access_logs => [ {'file' => 'log1'}, {'file' => 'log2', 'env' => 'admin' }, {'file' => '/var/tmp/log3', 'format' => '%h %l'}, {'syslog' => 'syslog' } ] } apache::vhost { 'test.access_log_env_var': docroot => '/tmp', logroot => '/tmp', access_log_syslog => 'syslog', access_log_env_var => 'admin', } apache::vhost { 'test.access_log_format': docroot => '/tmp', logroot => '/tmp', access_log_syslog => 'syslog', access_log_format => '%h %l', } apache::vhost { 'test.logroot': docroot => '/tmp', logroot => '/tmp', } apache::vhost { 'test.override': docroot => '/tmp', override => ['All'], } apache::vhost { 'test.options': docroot => '/tmp', options => ['Indexes','FollowSymLinks', 'ExecCGI'], } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.itk.conf") do it { is_expected.to be_file } it { is_expected.to contain 'AssignUserId nobody nobody' } end describe file("#{apache_hash['vhost_dir']}/25-test.custom_fragment.conf") do it { is_expected.to be_file } it { is_expected.to contain '#weird test string' } end describe file("#{apache_hash['vhost_dir']}/test.without_priority_prefix.conf") do it { is_expected.to be_file } end describe file("#{apache_hash['vhost_dir']}/25-test.ssl_protocol.conf") do it { is_expected.to be_file } it { is_expected.to contain 'SSLProtocol *All -SSLv2' } it { is_expected.to contain 'SSLUserName *SSL_CLIENT_S_DN_CN' } end describe file("#{apache_hash['vhost_dir']}/25-test.block.conf") do it { is_expected.to be_file } it { is_expected.to contain '' } end describe file("#{apache_hash['vhost_dir']}/25-test.setenv_setenvif.conf") do it { is_expected.to be_file } it { is_expected.to contain 'SetEnv TEST /test' } it { is_expected.to contain 'SetEnvIf Request_URI "\.gif$" object_is_image=gif' } end describe file("#{apache_hash['vhost_dir']}/25-test.rewrite.conf") do it { is_expected.to be_file } it { is_expected.to contain '#test' } it { is_expected.to contain 'RewriteCond %{HTTP_USER_AGENT} ^Lynx/ [OR]' } it { is_expected.to contain 'RewriteRule ^index.html$ welcome.html' } it { is_expected.to contain 'RewriteMap lc int:tolower' } end describe file("#{apache_hash['vhost_dir']}/25-test.request_headers.conf") do it { is_expected.to be_file } it { is_expected.to contain 'append MirrorID "mirror 12"' } end describe file("#{apache_hash['vhost_dir']}/25-test.redirect.conf") do it { is_expected.to be_file } it { is_expected.to contain 'Redirect permanent /images http://test.server/' } end describe file("#{apache_hash['vhost_dir']}/25-test.no_proxy_uris.conf") do it { is_expected.to be_file } it { is_expected.to contain 'ProxyPass http://test2/test !' } it { is_expected.to contain 'ProxyPass / http://test2/' } end describe file("#{apache_hash['vhost_dir']}/25-test.proxy.conf") do it { is_expected.to be_file } it { is_expected.to contain 'ProxyPass / http://testproxy/' } end describe file("#{apache_hash['vhost_dir']}/25-test.scriptaliases.conf") do it { is_expected.to be_file } it { is_expected.to contain 'ScriptAlias /myscript "/usr/share/myscript"' } end describe file("#{apache_hash['vhost_dir']}/25-test.aliases.conf") do it { is_expected.to be_file } it { is_expected.to contain 'Alias /image "/ftp/pub/image"' } it { is_expected.to contain 'ScriptAlias /myscript "/usr/share/myscript"' } end describe file("#{apache_hash['vhost_dir']}/25-test.access_logs.conf") do it { is_expected.to be_file } it { is_expected.to contain 'CustomLog "/tmp/log1" combined' } it { is_expected.to contain 'CustomLog "/tmp/log2" combined env=admin' } it { is_expected.to contain 'CustomLog "/var/tmp/log3" "%h %l"' } it { is_expected.to contain 'CustomLog "syslog" combined' } end describe file("#{apache_hash['vhost_dir']}/25-test.access_log_env_var.conf") do it { is_expected.to be_file } it { is_expected.to contain 'CustomLog "syslog" combined env=admin' } end describe file("#{apache_hash['vhost_dir']}/25-test.access_log_format.conf") do it { is_expected.to be_file } it { is_expected.to contain 'CustomLog "syslog" "%h %l"' } end describe file("#{apache_hash['vhost_dir']}/25-test.logroot.conf") do it { is_expected.to be_file } it { is_expected.to contain ' CustomLog "/tmp' } end describe file("#{apache_hash['vhost_dir']}/25-test.override.conf") do it { is_expected.to be_file } it { is_expected.to contain 'AllowOverride All' } end describe file("#{apache_hash['vhost_dir']}/25-test.options.conf") do it { is_expected.to be_file } it { is_expected.to contain 'Options Indexes FollowSymLinks ExecCGI' } end end context 'when a manifest defines $servername' do describe 'when the $use_servername_for_filenames parameter is set to true' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': use_servername_for_filenames => true, servername => 'test.servername', docroot => '/tmp', logroot => '/tmp', } MANIFEST it 'applies cleanly and DOES NOT print warning about $use_servername_for_filenames usage for test.server vhost' do result = apply_manifest(pp, catch_failures: true) expect(result.stderr).not_to contain %r{ .*Warning\:\sScope\(Apache::Vhost\[test\.server\]\)\:.* It\sis\spossible\sfor\sthe\s\$name\sparameter.* sanitized\s\$servername\sparameter\swhen\snot\sexplicitly\sdefined\. }xm end describe file("#{apache_hash['vhost_dir']}/25-test.servername.conf") do it { is_expected.to be_file } it { is_expected.to contain ' ErrorLog "/tmp/test.servername_error.log' } it { is_expected.to contain ' CustomLog "/tmp/test.servername_access.log' } end end describe 'when the $use_servername_for_filenames parameter is NOT defined' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': servername => 'test.servername', docroot => '/tmp', logroot => '/tmp', } MANIFEST it 'applies cleanly and prints warning about $use_servername_for_filenames usage for test.server vhost' do result = apply_manifest(pp, catch_failures: true) expect(result.stderr).to contain %r{ .*Warning\:\sScope\(Apache::Vhost\[test\.server\]\)\:.* It\sis\spossible\sfor\sthe\s\$name\sparameter.* sanitized\s\$servername\sparameter\swhen\snot\sexplicitly\sdefined\. }xm end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain ' ErrorLog "/tmp/test.server_error.log' } it { is_expected.to contain ' CustomLog "/tmp/test.server_access.log' } end end end ['access', 'error'].each do |logtype| case logtype when 'access' logname = 'CustomLog' when 'error' logname = 'ErrorLog' end describe "#{logtype}_log" do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', logroot => '/tmp', #{logtype}_log => false, } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.not_to contain " #{logname} \"/tmp" } end end describe "#{logtype}_log_pipe" do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', logroot => '/tmp', #{logtype}_log_pipe => '|/bin/sh', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain " #{logname} \"|/bin/sh" } end end describe "#{logtype}_log_syslog" do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', logroot => '/tmp', #{logtype}_log_syslog => 'syslog', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain " #{logname} \"syslog\"" } end end end describe 'actions' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', action => 'php-fastcgi', } MANIFEST it 'applies cleanly' do - pp += "\nclass { 'apache::mod::actions': }" if os[:family] =~ %r{debian|suse|ubuntu|sles} + pp += "\nclass { 'apache::mod::actions': }" if %r{debian|suse|ubuntu|sles}.match?(os[:family]) apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'Action php-fastcgi /cgi-bin virtual' } end end describe 'suphp' do pp = <<-MANIFEST class { 'apache': service_ensure => stopped, } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', suphp_addhandler => '#{apache_hash['suphp_handler']}', suphp_engine => 'on', suphp_configpath => '#{apache_hash['suphp_configpath']}', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain "suPHP_AddHandler #{apache_hash['suphp_handler']}" } it { is_expected.to contain 'suPHP_Engine on' } it { is_expected.to contain "suPHP_ConfigPath \"#{apache_hash['suphp_configpath']}\"" } end end describe 'directory rewrite rules' do pp = <<-MANIFEST class { 'apache': } host { 'test.server': ip => '127.0.0.1' } if ! defined(Class['apache::mod::rewrite']) { include ::apache::mod::rewrite } apache::vhost { 'test.server': docroot => '/tmp', directories => [ { path => '/tmp', rewrites => [ { comment => 'Permalink Rewrites', rewrite_base => '/', }, { rewrite_rule => [ '^index\\.php$ - [L]' ] }, { rewrite_cond => [ '%{REQUEST_FILENAME} !-f', '%{REQUEST_FILENAME} !-d', ], rewrite_rule => [ '. /index.php [L]' ], } ], }, ], } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain '#Permalink Rewrites' } it { is_expected.to contain 'RewriteEngine On' } it { is_expected.to contain 'RewriteBase /' } it { is_expected.to contain 'RewriteRule ^index\.php$ - [L]' } it { is_expected.to contain 'RewriteCond %{REQUEST_FILENAME} !-f' } it { is_expected.to contain 'RewriteCond %{REQUEST_FILENAME} !-d' } it { is_expected.to contain 'RewriteRule . /index.php [L]' } end end describe 'wsgi' do context 'filter on OS', if: mod_supported_on_platform?('apache::mod::wsgi') do pp = <<-MANIFEST class { 'apache': } class { 'apache::mod::wsgi': } host { 'test.server': ip => '127.0.0.1' } apache::vhost { 'test.server': docroot => '/tmp', wsgi_application_group => '%{GLOBAL}', wsgi_daemon_process => { 'wsgi' => { 'python-home' => '/usr' }, 'foo' => {} }, wsgi_daemon_process_options => {processes => '2'}, wsgi_import_script => '/test1', wsgi_import_script_options => { application-group => '%{GLOBAL}', process-group => 'wsgi' }, wsgi_process_group => 'nobody', wsgi_script_aliases => { '/test' => '/test1' }, wsgi_script_aliases_match => { '/test/([^/*])' => '/test1' }, wsgi_pass_authorization => 'On', wsgi_chunked_request => 'On', } MANIFEST it 'import_script applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'WSGIApplicationGroup %{GLOBAL}' } it { is_expected.to contain 'WSGIDaemonProcess foo' } it { is_expected.to contain 'WSGIDaemonProcess wsgi python-home=/usr' } it { is_expected.to contain 'WSGIImportScript /test1 application-group=%{GLOBAL} process-group=wsgi' } it { is_expected.to contain 'WSGIProcessGroup nobody' } it { is_expected.to contain 'WSGIScriptAlias /test "/test1"' } it { is_expected.to contain 'WSGIPassAuthorization On' } it { is_expected.to contain 'WSGIChunkedRequest On' } end end end describe 'additional_includes' do pp = <<-MANIFEST if $::osfamily == 'RedHat' and "$::selinux" == "true" { $semanage_package = $::operatingsystemmajrelease ? { '5' => 'policycoreutils', '8' => 'policycoreutils-python-utils', default => 'policycoreutils-python', } package { $semanage_package: ensure => installed } exec { 'set_apache_defaults': command => 'semanage fcontext -a -t httpd_sys_content_t "/apache_spec(/.*)?"', path => '/bin:/usr/bin/:/sbin:/usr/sbin', require => Package[$semanage_package], } exec { 'restorecon_apache': command => 'restorecon -Rv /apache_spec', path => '/bin:/usr/bin/:/sbin:/usr/sbin', before => Service['httpd'], require => Class['apache'], } } class { 'apache': } host { 'test.server': ip => '127.0.0.1' } file { '/apache_spec': ensure => directory, } file { '/apache_spec/include': ensure => present, content => '#additional_includes' } apache::vhost { 'test.server': docroot => '/apache_spec', additional_includes => '/apache_spec/include', } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: false) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'Include "/apache_spec/include"' } end end describe 'shibboleth parameters', if: (os[:family] == 'debian' && os[:release] != '7') do # Debian 7 is too old for ShibCompatValidUser pp = <<-MANIFEST class { 'apache': } class { 'apache::mod::shib': } apache::vhost { 'test.server': port => '80', docroot => '/var/www/html', shib_compat_valid_user => 'On' } MANIFEST it 'applies cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'ShibCompatValidUser On' } end end # IAC-587: These tests do not currently run successfully on certain RHEL OSs due to dependency issues with the # mod_auth_openidc module. describe 'auth_oidc', if: mod_supported_on_platform?('apache::mod::authnz_ldap') do pp = <<-MANIFEST class { 'apache': } apache::vhost { 'test.server': port => '80', docroot => '/var/www/html', auth_oidc => true, oidc_settings => { 'ProviderMetadataURL' => 'https://login.example.com/.well-known/openid-configuration', 'ClientID' => 'test', 'RedirectURI' => 'https://login.example.com/redirect_uri', 'ProviderTokenEndpointAuth' => 'client_secret_basic', 'RemoteUserClaim' => 'sub', 'ClientSecret' => 'aae053a9-4abf-4824-8956-e94b2af335c8', 'CryptoPassphrase' => '4ad1bb46-9979-450e-ae58-c696967df3cd' } } MANIFEST it 'applys cleanly' do apply_manifest(pp, catch_failures: true) end describe file("#{apache_hash['vhost_dir']}/25-test.server.conf") do it { is_expected.to be_file } it { is_expected.to contain 'OIDCProviderMetadataURL https://login.example.com/.well-known/openid-configuration' } it { is_expected.to contain 'OIDCClientID test' } it { is_expected.to contain 'OIDCRedirectURI https://login.example.com/redirect_uri' } it { is_expected.to contain 'OIDCProviderTokenEndpointAuth client_secret_basic' } it { is_expected.to contain 'OIDCRemoteUserClaim sub' } it { is_expected.to contain 'OIDCClientSecret aae053a9-4abf-4824-8956-e94b2af335c8' } it { is_expected.to contain 'OIDCCryptoPassphrase 4ad1bb46-9979-450e-ae58-c696967df3cd' } end end end diff --git a/spec/spec_helper_acceptance_local.rb b/spec/spec_helper_acceptance_local.rb index 2922671e..c80aa202 100644 --- a/spec/spec_helper_acceptance_local.rb +++ b/spec/spec_helper_acceptance_local.rb @@ -1,194 +1,194 @@ # frozen_string_literal: true require 'singleton' require_relative '../util/apache_mod_platform_support' class LitmusHelper include Singleton include PuppetLitmus end class ApacheModTestFilterHelper include Singleton def initialize_ampc(os) @ampc = ApacheModPlatformCompatibility.new @ampc.generate_supported_platforms_versions @ampc.register_running_platform(os) @ampc.generate_mod_platform_exclusions end def mod_supported_on_platform?(mod) @ampc.mod_supported_on_platform?(mod) end def print_parsing_errors @ampc.print_parsing_errors end end RSpec.configure do |c| # IPv6 is not enabled by default in the new travis-ci Trusty environment (see https://github.com/travis-ci/travis-ci/issues/8891 ) if ENV['CI'] == 'true' c.filter_run_excluding ipv6: true end c.before :suite do # Make sure selinux is disabled so the tests work. - LitmusHelper.instance.run_shell('setenforce 0', expect_failures: true) if os[:family] =~ %r{redhat|oracle} + LitmusHelper.instance.run_shell('setenforce 0', expect_failures: true) if %r{redhat|oracle}.match?(os[:family]) LitmusHelper.instance.run_shell('puppet module install stahnma/epel') pp = <<-PUPPETCODE # needed by tests package { 'curl': ensure => 'latest', } # needed for netstat, for serverspec checks if $::osfamily == 'SLES' or $::osfamily == 'SUSE' { package { 'net-tools-deprecated': ensure => 'latest', } } # needed for ss, for serverspec checks if $::operatingsystem == 'Ubuntu' and $::operatingsystemmajrelease !~ /14.04|16.04/ { package { 'iproute2': ensure => 'latest', } } if $::osfamily == 'RedHat' { if $::operatingsystemmajrelease == '5' or $::operatingsystemmajrelease == '6'{ class { 'epel': epel_baseurl => "http://osmirror.delivery.puppetlabs.net/epel${::operatingsystemmajrelease}-\\$basearch/RPMS.all", epel_mirrorlist => "http://osmirror.delivery.puppetlabs.net/epel${::operatingsystemmajrelease}-\\$basearch/RPMS.all", } } elsif $::operatingsystemmajrelease == '8' { class { 'epel': os_maj_release => "7", epel_baseurl => "http://osmirror.delivery.puppetlabs.net/epel7-\\$basearch/RPMS.all", epel_mirrorlist => "http://osmirror.delivery.puppetlabs.net/epel7-\\$basearch/RPMS.all", } } else { class { 'epel': } } } PUPPETCODE LitmusHelper.instance.apply_manifest(pp) end c.after :suite do ApacheModTestFilterHelper.instance.print_parsing_errors end end def apache_settings_hash osfamily = os[:family] operatingsystemrelease = os[:release].to_f apache = {} case osfamily when 'redhat', 'oracle' apache['confd_dir'] = '/etc/httpd/conf.d' apache['conf_file'] = '/etc/httpd/conf/httpd.conf' apache['ports_file'] = '/etc/httpd/conf/ports.conf' apache['vhost_dir'] = '/etc/httpd/conf.d' apache['vhost'] = '/etc/httpd/conf.d/15-default.conf' apache['run_dir'] = '/var/run/httpd' apache['doc_root'] = '/var/www' apache['service_name'] = 'httpd' apache['package_name'] = 'httpd' apache['error_log'] = 'error_log' apache['suphp_handler'] = 'php5-script' apache['suphp_configpath'] = 'undef' if operatingsystemrelease >= 8 && osfamily == 'redhat' apache['version'] = '2.4' apache['mod_dir'] = '/etc/httpd/conf.modules.d' apache['mod_ssl_dir'] = apache['mod_dir'] elsif operatingsystemrelease >= 7 && osfamily == 'redhat' apache['version'] = '2.4' apache['mod_dir'] = '/etc/httpd/conf.modules.d' apache['mod_ssl_dir'] = apache['confd_dir'] elsif operatingsystemrelease >= 7 && osfamily == 'oracle' apache['version'] = '2.4' apache['mod_dir'] = '/etc/httpd/conf.modules.d' apache['mod_ssl_dir'] = apache['confd_dir'] else apache['version'] = '2.2' apache['mod_dir'] = '/etc/httpd/conf.d' apache['mod_ssl_dir'] = apache['mod_dir'] end when 'debian', 'ubuntu' apache['confd_dir'] = '/etc/apache2/conf.d' apache['mod_dir'] = '/etc/apache2/mods-available' apache['conf_file'] = '/etc/apache2/apache2.conf' apache['ports_file'] = '/etc/apache2/ports.conf' apache['vhost'] = '/etc/apache2/sites-available/15-default.conf' apache['vhost_dir'] = '/etc/apache2/sites-enabled' apache['run_dir'] = '/var/run/apache2' apache['doc_root'] = '/var/www' apache['service_name'] = 'apache2' apache['package_name'] = 'apache2' apache['error_log'] = 'error.log' apache['suphp_handler'] = 'x-httpd-php' apache['suphp_configpath'] = '/etc/php5/apache2' apache['version'] = if osfamily == 'ubuntu' && operatingsystemrelease >= 13.10 '2.4' elsif osfamily == 'debian' && operatingsystemrelease >= 8.0 '2.4' else '2.2' end apache['mod_ssl_dir'] = apache['mod_dir'] when 'freebsd' apache['confd_dir'] = '/usr/local/etc/apache24/Includes' apache['mod_dir'] = '/usr/local/etc/apache24/Modules' apache['conf_file'] = '/usr/local/etc/apache24/httpd.conf' apache['ports_file'] = '/usr/local/etc/apache24/Includes/ports.conf' apache['vhost'] = '/usr/local/etc/apache24/Vhosts/15-default.conf' apache['vhost_dir'] = '/usr/local/etc/apache24/Vhosts' apache['run_dir'] = '/var/run/apache24' apache['doc_root'] = '/var/www' apache['service_name'] = 'apache24' apache['package_name'] = 'apache24' apache['error_log'] = 'http-error.log' apache['version'] = '2.2' apache['mod_ssl_dir'] = apache['mod_dir'] when 'gentoo' apache['confd_dir'] = '/etc/apache2/conf.d' apache['mod_dir'] = '/etc/apache2/modules.d' apache['conf_file'] = '/etc/apache2/httpd.conf' apache['ports_file'] = '/etc/apache2/ports.conf' apache['vhost'] = '/etc/apache2/vhosts.d/15-default.conf' apache['vhost_dir'] = '/etc/apache2/vhosts.d' apache['run_dir'] = '/var/run/apache2' apache['doc_root'] = '/var/www' apache['service_name'] = 'apache2' apache['package_name'] = 'www-servers/apache' apache['error_log'] = 'http-error.log' apache['version'] = '2.4' apache['mod_ssl_dir'] = apache['mod_dir'] when 'suse', 'sles' apache['confd_dir'] = '/etc/apache2/conf.d' apache['mod_dir'] = '/etc/apache2/mods-available' apache['conf_file'] = '/etc/apache2/httpd.conf' apache['ports_file'] = '/etc/apache2/ports.conf' apache['vhost'] = '/etc/apache2/sites-available/15-default.conf' apache['vhost_dir'] = '/etc/apache2/sites-available' apache['run_dir'] = '/var/run/apache2' apache['doc_root'] = '/srv/www' apache['service_name'] = 'apache2' apache['package_name'] = 'apache2' apache['error_log'] = 'error.log' apache['version'] = if operatingsystemrelease < 12 '2.2' else '2.4' end apache['mod_ssl_dir'] = apache['mod_dir'] else raise 'unable to figure out what apache version' end apache end def mod_supported_on_platform?(mod) return false if ENV['DISABLE_MOD_TEST_EXCLUSION'] ApacheModTestFilterHelper.instance.mod_supported_on_platform?(mod) end diff --git a/spec/unit/provider/a2mod/gentoo_spec.rb b/spec/unit/provider/a2mod/gentoo_spec.rb index 48f860b3..53e1c83f 100644 --- a/spec/unit/provider/a2mod/gentoo_spec.rb +++ b/spec/unit/provider/a2mod/gentoo_spec.rb @@ -1,178 +1,178 @@ # frozen_string_literal: true require 'spec_helper' provider_class = Puppet::Type.type(:a2mod).provider(:gentoo) describe provider_class do before :each do provider_class.clear end [:conf_file, :instances, :modules, :initvars, :conf_file, :clear].each do |method| - it "should respond to the class method #{method}" do + it "responds to the class method #{method}" do expect(provider_class).to respond_to(method) end end describe 'when fetching modules' do let(:filetype) do double end it 'returns a sorted array of the defined parameters' do expect(filetype).to receive(:read).and_return(%(APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n)) expect(provider_class).to receive(:filetype) { filetype } expect(provider_class.modules).to eq(['bar', 'baz', 'foo']) end it 'caches the module list' do expect(filetype).to receive(:read).once { %(APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n) } # rubocop:disable Lint/AmbiguousBlockAssociation expect(provider_class).to receive(:filetype).once { filetype } # rubocop:disable Lint/AmbiguousBlockAssociation 2.times { expect(provider_class.modules).to eq(['bar', 'baz', 'foo']) } end it 'normalizes parameters' do expect(filetype).to receive(:read).and_return(%(APACHE2_OPTS="-D FOO -D BAR -D BAR"\n)) expect(provider_class).to receive(:filetype) { filetype } expect(provider_class.modules).to eq(['bar', 'foo']) end end describe 'when prefetching' do it 'matches providers to resources' do provider = instance_double('ssl_provider', name: 'ssl') resource = instance_double('ssl_resource') expect(resource).to receive(:provider=).with(provider) expect(provider_class).to receive(:instances) { [provider] } provider_class.prefetch('ssl' => resource) end end describe 'when flushing' do before :each do @filetype = double allow(@filetype).to receive(:backup) allow(provider_class).to receive(:filetype).at_least(:once) { @filetype } @info = double allow(@info).to receive(:[]).with(:name) { 'info' } allow(@info).to receive(:provider=) @mpm = double allow(@mpm).to receive(:[]).with(:name) { 'mpm' } allow(@mpm).to receive(:provider=) @ssl = double allow(@ssl).to receive(:[]).with(:name) { 'ssl' } allow(@ssl).to receive(:provider=) end it 'adds modules whose ensure is present' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="") } expect(@filetype).to receive(:write).with(%(APACHE2_OPTS="-D INFO")) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) provider_class.flush end it 'removes modules whose ensure is present' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="-D INFO") } expect(@filetype).to receive(:write).with(%(APACHE2_OPTS="")) allow(@info).to receive(:should).with(:ensure) { :absent } allow(@info).to receive(:provider=) provider_class.prefetch('info' => @info) provider_class.flush end it 'does not modify providers without resources' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="-D INFO -D MPM") } expect(@filetype).to receive(:write).with(%(APACHE2_OPTS="-D MPM -D SSL")) allow(@info).to receive(:should).with(:ensure) { :absent } provider_class.prefetch('info' => @info) allow(@ssl).to receive(:should).with(:ensure) { :present } provider_class.prefetch('ssl' => @ssl) provider_class.flush end it 'writes the modules in sorted order' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="") } expect(@filetype).to receive(:write).with(%(APACHE2_OPTS="-D INFO -D MPM -D SSL")) allow(@mpm).to receive(:should).with(:ensure) { :present } provider_class.prefetch('mpm' => @mpm) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) allow(@ssl).to receive(:should).with(:ensure) { :present } provider_class.prefetch('ssl' => @ssl) provider_class.flush end it 'writes the records back once' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="") } expect(@filetype).to receive(:write).once.with(%(APACHE2_OPTS="-D INFO -D SSL")) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) allow(@ssl).to receive(:should).with(:ensure) { :present } provider_class.prefetch('ssl' => @ssl) provider_class.flush end it 'onlies modify the line containing APACHE2_OPTS' do expect(@filetype).to receive(:read).at_least(:once) { %(# Comment\nAPACHE2_OPTS=""\n# Another comment) } expect(@filetype).to receive(:write).once.with(%(# Comment\nAPACHE2_OPTS="-D INFO"\n# Another comment)) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) provider_class.flush end it 'restores any arbitrary arguments' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="-Y -D MPM -X") } expect(@filetype).to receive(:write).once.with(%(APACHE2_OPTS="-Y -X -D INFO -D MPM")) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) provider_class.flush end it 'backups the file once if changes were made' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="") } expect(@filetype).to receive(:write).once.with(%(APACHE2_OPTS="-D INFO -D SSL")) allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) allow(@ssl).to receive(:should).with(:ensure) { :present } provider_class.prefetch('ssl' => @ssl) expect(@filetype).to receive(:backup) provider_class.flush end it 'does not write the file or run backups if no changes were made' do expect(@filetype).to receive(:read).at_least(:once) { %(APACHE2_OPTS="-X -D INFO -D SSL -Y") } expect(@filetype).to receive(:write).never allow(@info).to receive(:should).with(:ensure) { :present } provider_class.prefetch('info' => @info) allow(@ssl).to receive(:should).with(:ensure) { :present } provider_class.prefetch('ssl' => @ssl) expect(@filetype).to receive(:backup).never provider_class.flush end end end diff --git a/spec/util/_resources/test_metadata_json.rb b/spec/util/_resources/test_metadata_json.rb index b03edfcc..bd333b73 100644 --- a/spec/util/_resources/test_metadata_json.rb +++ b/spec/util/_resources/test_metadata_json.rb @@ -1,88 +1,88 @@ # frozen_string_literal: true METADATA_JSON = '{ "name": "puppetlabs-apache", "version": "5.4.0", "author": "puppetlabs", "summary": "Installs, configures, and manages Apache virtual hosts, web services, and modules.", "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-apache", "project_page": "https://github.com/puppetlabs/puppetlabs-apache", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.13.1 < 7.0.0" }, { "name": "puppetlabs/concat", "version_requirement": ">= 2.2.1 < 7.0.0" } ], "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "6", "7", "8" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "6", "7", "8" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "6", "7" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "8", "9", "10" ] }, { "operatingsystem": "SLES", "operatingsystemrelease": [ "11 SP1", "12", "15" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04", "18.04" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 5.5.10 < 7.0.0" } ], "description": "Module for Apache configuration", "pdk-version": "1.17.0", "template-url": "https://github.com/puppetlabs/pdk-templates#main", "template-ref": "heads/main-0-g095317c" -}'.freeze +}' diff --git a/spec/util/apache_mod_platform_support_spec.rb b/spec/util/apache_mod_platform_support_spec.rb index 5d9cd84d..1025a866 100644 --- a/spec/util/apache_mod_platform_support_spec.rb +++ b/spec/util/apache_mod_platform_support_spec.rb @@ -1,181 +1,181 @@ # frozen_string_literal: true require 'rspec' require 'rspec-puppet-facts' require_relative '../../util/apache_mod_platform_support' require_relative '_resources/test_metadata_json' describe ApacheModPlatformCompatibility do foobar_pp = 'foobar.pp' foobar_mod = 'apache::mod::foobar' foobar_class = "class #{foobar_mod}" foobar_linux = 'foobar_linux' expected_compatible_platform_versions = { 'redhat' => [6, 7, 8], 'centos' => [6, 7, 8], 'oraclelinux' => [6, 7], 'scientific' => [6, 7], 'debian' => [8, 9, 10], 'sles' => [11, 12, 15], 'ubuntu' => [14, 16, 18], } context 'when initialized' do describe '#process_line' do ampc = described_class.new it 'returns an empty hash when given garbage line' do expect(ampc.process_line('foobar')).to eq({}) end it 'returns a hash with type: :unsupported_platform_declaration and extracted value' do expect(ampc.process_line('# @note Unsupported platforms: foobar')).to eq(type: :unsupported_platform_declaration, value: 'foobar') end it 'returns a hash with type: :class_declaration and extracted value' do expect(ampc.process_line(foobar_class)).to eq(type: :class_declaration, value: foobar_mod) end end describe '#extract_os_ver_pairs' do ampc = described_class.new it 'handles single OS with single Version' do expect(ampc.extract_os_ver_pairs('Debian: 5')).to eq('debian' => [5]) end it 'handles single OS with multiple Versions' do expect(ampc.extract_os_ver_pairs('Debian: 5, 6, 7')).to eq('debian' => [5, 6, 7]) end it 'handles multiple OSs with multiple Versions' do expect(ampc.extract_os_ver_pairs('Debian: 5, 6, 7; CentOS: 5,6,7')).to eq('debian' => [5, 6, 7], 'centos' => [5, 6, 7]) end it 'handles Versions in \d+\.\d+ format' do expect(ampc.extract_os_ver_pairs('Ubuntu: 14.04, 16.04')).to eq('ubuntu' => [14, 16]) end it 'handles Versions with "SP"' do expect(ampc.extract_os_ver_pairs('SLES: 11 SP1, 12')).to eq('sles' => [11, 12]) end it 'returns an empty Hash when given data in an entirely invalid format' do expect(ampc.extract_os_ver_pairs('foobar')).to eq({}) end it 'returns an empty Hash when given data with incorrect OS/Version group separator' do expect(ampc.extract_os_ver_pairs('Ubuntu#14.04, 16.04')).to eq({}) end it 'returns an empty Hash when given data with incorrect OS + Version separator' do expect(ampc.extract_os_ver_pairs('CentOS:5,6#Debian:5,6')).to eq({}) end it 'returns an empty Hash when given data with incorrect Version separator' do expect(ampc.extract_os_ver_pairs('CentOS:5@6')).to eq({}) end end describe '#register_unsupported_platforms' do ampc = described_class.new it 'registers a valid unsupported platform' do ampc.register_running_platform(family: 'debian', release: '8.11', arch: 'x86_64') expect(ampc).to receive(:valid_os?).with('debian').and_return(true) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'debian' => [8]) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(false) end it 'registers multiple valid unsupported platforms' do expect(ampc).to receive(:valid_os?).with('debian').and_return(true) expect(ampc).to receive(:valid_os?).with('ubuntu').and_return(true) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'debian' => [8]) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'ubuntu' => [14]) ampc.register_running_platform(family: 'debian', release: '8.11', arch: 'x86_64') expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(false) ampc.register_running_platform(family: 'ubuntu', release: '14.04', arch: 'x86_64') expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(false) end it 'registers an :os_parse error when given an invalid platform' do expect(ampc).to receive(:valid_os?).with(foobar_linux).and_return(false) expect(ampc).to receive(:register_error).with(foobar_pp, 1, :os_parse, foobar_linux) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, foobar_linux => [1]) ampc.register_running_platform(family: 'debian', release: '8.11', arch: 'x86_64') end end describe '#generate_supported_platforms_versions' do ampc = described_class.new before(:each) do allow(File).to receive(:read).and_call_original allow(File).to receive(:read).with('../../metadata.json').and_return(METADATA_JSON) ampc.generate_supported_platforms_versions ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, foobar_linux => [1]) end context 'after parsing the metadata.json' do expected_compatible_platform_versions.each do |os, vers| vers.each do |ver| - it "should state #{os} version #{ver} IS a compatible platform" do + it "states #{os} version #{ver} IS a compatible platform" do ampc.register_running_platform(family: os, version: ver) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(true) end end end end end describe '#mod_unsupported_on_platform' do ampc = described_class.new before(:each) do allow(File).to receive(:read).and_call_original allow(File).to receive(:read).with('../../metadata.json').and_return(METADATA_JSON) ampc = described_class.new ampc.generate_supported_platforms_versions end ubuntu_14_04_os = { family: 'ubuntu', release: '14.04' } it 'returns false when running on an OS with all versions incompatible' do ampc.register_running_platform(ubuntu_14_04_os) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'ubuntu' => [0]) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(false) end it 'returns false when running on an OS with one specific version incompatible' do ampc.register_running_platform(ubuntu_14_04_os) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'ubuntu' => [14]) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(false) end it 'returns true when running on an OS with no versions marked as incompatible' do ampc.register_running_platform(ubuntu_14_04_os) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'debian' => [6, 7]) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(true) end it 'returns true when running on an OS version not marked as incompatible' do ampc.register_running_platform(ubuntu_14_04_os) ampc.register_unsupported_platforms(foobar_pp, 1, foobar_mod, 'ubuntu' => [16, 18]) expect(ampc.mod_supported_on_platform?(foobar_mod)).to be(true) end end describe '#print_parsing_errors' do ampc = described_class.new abc_pp = 'abc.pp' abc_pp_error_line = 1 abc_pp_error_type = :tag_parse abc_pp_error_type_msg = 'OS and version information in incorrect format:' abc_pp_error_detail = 'Bad line' def_pp = 'def.pp' def_pp_error_line = 2 def_pp_error_type = :os_parse def_pp_error_type_msg = 'OS name is not present in metadata.json:' def_pp_error_detail = foobar_linux tag_format_help_msg_txt = ['succint', 'warning'] expected_stderr_msg = "The following errors were encountered when trying to parse the 'Unsupported platforms' tag(s) in 'manifests/mod':\n" \ " * #{abc_pp} (line #{abc_pp_error_line}): #{abc_pp_error_type_msg} #{abc_pp_error_detail}\n" \ " * #{def_pp} (line #{def_pp_error_line}): #{def_pp_error_type_msg} #{def_pp_error_detail}\n" \ "#{tag_format_help_msg_txt[0]}\n" \ "#{tag_format_help_msg_txt[1]}\n" context 'given a number of errors were discovered when parsing the manifests' do ampc.register_error(abc_pp, abc_pp_error_line, abc_pp_error_type, abc_pp_error_detail) ampc.register_error(def_pp, def_pp_error_line, def_pp_error_type, def_pp_error_detail) it 'prints the expected warnings to $stderr' do allow(File).to receive(:readlines).with('util/_resources/tag_format_help_msg.txt').and_return(tag_format_help_msg_txt) expect { ampc.print_parsing_errors }.to output(expected_stderr_msg).to_stderr end end end end end diff --git a/util/apache_mod_platform_support.rb b/util/apache_mod_platform_support.rb index f277b30a..320142fb 100644 --- a/util/apache_mod_platform_support.rb +++ b/util/apache_mod_platform_support.rb @@ -1,149 +1,149 @@ # frozen_string_literal: true require 'json' # Helper class to facilitate exclusion of tests that use an Apache MOD on platforms it isn't supported on. # All Apache MOD classes are defined under 'manifests/mod'. The exclusion should be in the format: # # @note Unsupported platforms: OS: ver, ver; OS: ver, ver, ver; OS: all' # class apache::mod::foobar { # ... # # For example: # @note Unsupported platforms: RedHat: 5, 6; Ubuntu: 14.04; SLES: all; Scientific: 11 SP1' # class apache::mod::actions { # apache::mod { 'actions': } # } # # Filtering is then performed during the test using RSpec's filtering, like so: # # describe 'auth_oidc', unless: mod_unsupported_on_platform('apache::mod::auth_openidc') do # ... # it 'applies cleanly', unless: mod_unsupported_on_platform('apache::mod::auth_openidc') do # ... class ApacheModPlatformCompatibility ERROR_MSG = { tag_parse: 'OS and version information in incorrect format:', os_parse: 'OS name is not present in metadata.json:', }.freeze def initialize @os = {} @mapping = {} @manifest_errors = [] @compatible_platform_versions = {} @mod_platform_compatibility_mapping = {} end def register_running_platform(os) @os = { family: os[:family], release: os[:release].to_i } end def generate_supported_platforms_versions metadata = JSON.parse(File.read('metadata.json')) metadata['operatingsystem_support'].each do |os| @compatible_platform_versions[os['operatingsystem'].downcase] = os['operatingsystemrelease'].map(&:to_i) end end # Class to hold the details of an error whilst parsing an unsupported tag class ManifestError attr_reader :manifest, :line_num, :error_type, :error_detail def initialize(manifest, line_num, error_type, error_detail) @manifest = manifest @line_num = line_num @error_type = error_type @error_detail = error_detail end end def print_parsing_errors return if @manifest_errors.empty? $stderr.puts "The following errors were encountered when trying to parse the 'Unsupported platforms' tag(s) in 'manifests/mod':\n" @manifest_errors.each do |manifest_error| $stderr.puts " * #{manifest_error.manifest} (line #{manifest_error.line_num}): #{ERROR_MSG[manifest_error.error_type]} #{manifest_error.error_detail}" end File.readlines('util/_resources/tag_format_help_msg.txt').each do |line| $stderr.puts line end end def valid_os?(os) @compatible_platform_versions.keys.include? os end def register_error(manifest, line_num, error_type, error_detail) @manifest_errors << ManifestError.new(manifest, line_num, error_type, error_detail) end def register_unsupported_platforms(manifest, line_num, mod, platforms_versions) platforms_versions.keys.each do |os| unless valid_os?(os) register_error(manifest, line_num, :os_parse, os) next end if @mod_platform_compatibility_mapping.key? mod @mod_platform_compatibility_mapping[mod].merge!(platforms_versions) else @mod_platform_compatibility_mapping[mod] = platforms_versions end end end def extract_os_ver_pairs(line) platforms_versions = {} os_ver_groups = line.delete(' ').downcase # E.g. "debian:5,6;centos:5;sles:11sp1,12;scientific:all;ubuntu:14.04,16.04" - if %r{^((?:\w+:(?:(?:\d+(?:\.\d+|sp\d+)?|all),?)+;?)+)$}i =~ os_ver_groups + if %r{^((?:\w+:(?:(?:\d+(?:\.\d+|sp\d+)?|all),?)+;?)+)$}i.match?(os_ver_groups) os_ver_groups.split(';').each do |os_vers| os, vers = os_vers.split(':') vers.gsub!(%r{sp\d+}, '') # Remove SP ver as we cannot determine this level of granularity from values from Litmus platforms_versions[os] = vers.split(',').map(&:to_i) # 'all' will be converted to 0 end end platforms_versions end def process_line(line) data = {} - return data unless line =~ %r{@note\sUnsupported\splatforms?:\s?|class\sapache::mod}i + return data unless %r{@note\sUnsupported\splatforms?:\s?|class\sapache::mod}i.match?(line) if (match = %r{@note\sUnsupported\splatforms?:\s?(?.*)$}i.match(line)) data[:type] = :unsupported_platform_declaration data[:value] = match[:os_vers] elsif (match = %r{class\s(?apache::mod::\w+)}i.match(line)) data[:type] = :class_declaration data[:value] = match[:mod] end data end def generate_mod_platform_exclusions Dir.glob('manifests/mod/*.pp').each do |manifest| platforms_versions = [] line_num = 0 File.readlines(manifest).each do |line| line_num += 1 data = process_line(line) next if data.empty? if data[:type] == :unsupported_platform_declaration platforms_versions = extract_os_ver_pairs(data[:value]) register_error(manifest, line_num, :tag_parse, line) if platforms_versions.empty? next elsif data[:type] == :class_declaration register_unsupported_platforms(manifest, line_num, data[:value], platforms_versions) unless platforms_versions.empty? break # Once we detect the class declaration, we can move on end end end end # Called from within the context of a test run, making use of RSpec's filtering, e.g.: # it 'should do some test', if: mod_supported_on_platform('apache::mod::foobar') def mod_supported_on_platform?(mod) return true if @mod_platform_compatibility_mapping.empty? return true unless @mod_platform_compatibility_mapping.key? mod return true unless @mod_platform_compatibility_mapping[mod].key? @os[:family] return false if @mod_platform_compatibility_mapping[mod][@os[:family]] == [0] !@mod_platform_compatibility_mapping[mod][@os[:family]].include? @os[:release] end end