Skip to content

Commit 55cc3b4

Browse files
committed
(MODULES-2764) Enclose IPv6 addresses in square brackets
The apache module does enclose IPv6 addresses in square brackets as apache recommends Apache 2.2: https://httpd.apache.org/docs/2.2/en/bind.html https://httpd.apache.org/docs/2.2/en/mod/core.html#virtualhost https://httpd.apache.org/docs/2.2/en/mod/core.html#namevirtualhost Apache 2.4: https://httpd.apache.org/docs/2.4/en/bind.html https://httpd.apache.org/docs/2.4/en/mod/core.html#virtualhost added some tests for the custom function enclose_ipv6
1 parent 0e9b153 commit 55cc3b4

5 files changed

Lines changed: 192 additions & 10 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#
2+
# enclose_ipv6.rb
3+
#
4+
5+
module Puppet::Parser::Functions
6+
newfunction(:enclose_ipv6, :type => :rvalue, :doc => <<-EOS
7+
Takes an array of ip addresses and encloses the ipv6 addresses with square brackets.
8+
EOS
9+
) do |arguments|
10+
11+
require 'ipaddr'
12+
13+
if (arguments.size != 1) then
14+
raise(Puppet::ParseError, "enclose_ipv6(): Wrong number of arguments "+
15+
"given #{arguments.size} for 1")
16+
end
17+
unless arguments[0].is_a?(String) or arguments[0].is_a?(Array) then
18+
raise(Puppet::ParseError, "enclose_ipv6(): Wrong argument type "+
19+
"given #{arguments[0].class} expected String or Array")
20+
end
21+
22+
input = [arguments[0]].flatten.compact
23+
result = []
24+
25+
input.each do |val|
26+
begin
27+
ip = IPAddr.new(val)
28+
rescue ArgumentError
29+
raise(Puppet::ParseError, "enclose_ipv6(): Wrong argument "+
30+
"given #{val} is not an ip address.")
31+
end
32+
val = "[#{ip.to_s}]" if ip.ipv6?
33+
result = [result,val]
34+
end
35+
36+
return result.flatten.compact
37+
end
38+
end

manifests/vhost.pp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,13 @@
344344
}
345345

346346
if $ip {
347+
$_ip = enclose_ipv6($ip)
347348
if $port {
348-
$listen_addr_port = suffix(any2array($ip),":${port}")
349-
$nvh_addr_port = suffix(any2array($ip),":${port}")
349+
$listen_addr_port = suffix(any2array($_ip),":${port}")
350+
$nvh_addr_port = suffix(any2array($_ip),":${port}")
350351
} else {
351352
$listen_addr_port = undef
352-
$nvh_addr_port = $ip
353+
$nvh_addr_port = $_ip
353354
if ! $servername and ! $ip_based {
354355
fail("Apache::Vhost[${name}]: must pass 'ip' and/or 'port' parameters for name-based vhosts")
355356
}
@@ -798,7 +799,7 @@
798799
# - $krb_method_k5passwd
799800
# - $krb_authoritative
800801
# - $krb_auth_realms
801-
# - $krb_5keytab
802+
# - $krb_5keytab
802803
# - $krb_local_user_mapping
803804
if $auth_kerb {
804805
concat::fragment { "${name}-auth_kerb":

spec/acceptance/vhost_spec.rb

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,16 @@ class { 'apache':
218218
end
219219

220220
describe file("#{$vhost_dir}/25-example.com.conf") do
221-
it { is_expected.to contain '<VirtualHost 127.0.0.1:80 ::1:80>' }
221+
it { is_expected.to contain '<VirtualHost 127.0.0.1:80 [::1]:80>' }
222222
it { is_expected.to contain "ServerName example.com" }
223223
end
224224

225225
describe file($ports_file) do
226226
it { is_expected.to be_file }
227227
it { is_expected.to contain 'Listen 127.0.0.1:80' }
228-
it { is_expected.to contain 'Listen ::1:80' }
228+
it { is_expected.to contain 'Listen [::1]:80' }
229229
it { is_expected.not_to contain 'NameVirtualHost 127.0.0.1:80' }
230-
it { is_expected.not_to contain 'NameVirtualHost ::1:80' }
230+
it { is_expected.not_to contain 'NameVirtualHost [::1]:80' }
231231
end
232232

233233
it 'should answer to ipv4.example.com' do
@@ -243,6 +243,50 @@ class { 'apache':
243243
end
244244
end
245245

246+
context 'new vhost with IPv6 address on port 80' do
247+
it 'should configure one apache vhost with an ipv6 address' do
248+
pp = <<-EOS
249+
class { 'apache':
250+
default_vhost => false,
251+
}
252+
apache::vhost { 'example.com':
253+
port => '80',
254+
ip => '::1',
255+
ip_based => true,
256+
docroot => '/var/www/html',
257+
}
258+
host { 'ipv6.example.com': ip => '::1', }
259+
file { '/var/www/html/index.html':
260+
ensure => file,
261+
content => "Hello from vhost\\n",
262+
}
263+
EOS
264+
apply_manifest(pp, :catch_failures => true)
265+
end
266+
267+
describe service($service_name) do
268+
it { is_expected.to be_enabled }
269+
it { is_expected.to be_running }
270+
end
271+
272+
describe file("#{$vhost_dir}/25-example.com.conf") do
273+
it { is_expected.to contain '<VirtualHost [::1]:80>' }
274+
it { is_expected.to contain "ServerName example.com" }
275+
end
276+
277+
describe file($ports_file) do
278+
it { is_expected.to be_file }
279+
it { is_expected.to contain 'Listen [::1]:80' }
280+
it { is_expected.not_to contain 'NameVirtualHost [::1]:80' }
281+
end
282+
283+
it 'should answer to ipv6.example.com' do
284+
shell("/usr/bin/curl ipv6.example.com:80", {:acceptable_exit_codes => 0}) do |r|
285+
expect(r.stdout).to eq("Hello from vhost\n")
286+
end
287+
end
288+
end
289+
246290
context 'apache_directories' do
247291
describe 'readme example, adapted' do
248292
it 'should configure a vhost with Files' do

spec/defines/vhost_spec.rb

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,12 +487,46 @@
487487

488488
it { is_expected.to compile }
489489
it { is_expected.to contain_concat__fragment('rspec.example.com-apache-header').with(
490-
:content => /[.\/m]*<VirtualHost 127.0.0.1:80 ::1:80>[.\/m]*$/ ) }
490+
:content => /[.\/m]*<VirtualHost 127.0.0.1:80 \[::1\]:80>[.\/m]*$/ ) }
491491
it { is_expected.to contain_concat__fragment('Listen 127.0.0.1:80') }
492-
it { is_expected.to contain_concat__fragment('Listen ::1:80') }
492+
it { is_expected.to contain_concat__fragment('Listen [::1]:80') }
493493
it { is_expected.to_not contain_concat__fragment('NameVirtualHost 127.0.0.1:80') }
494-
it { is_expected.to_not contain_concat__fragment('NameVirtualHost ::1:80') }
494+
it { is_expected.to_not contain_concat__fragment('NameVirtualHost [::1]:80') }
495495
end
496+
497+
context 'vhost with ipv6 address' do
498+
let :params do
499+
{
500+
'port' => '80',
501+
'ip' => '::1',
502+
'ip_based' => true,
503+
'servername' => 'example.com',
504+
'docroot' => '/var/www/html',
505+
'add_listen' => true,
506+
'ensure' => 'present'
507+
}
508+
end
509+
let :facts do
510+
{
511+
:osfamily => 'RedHat',
512+
:operatingsystemrelease => '7',
513+
:concat_basedir => '/dne',
514+
:operatingsystem => 'RedHat',
515+
:id => 'root',
516+
:kernel => 'Linux',
517+
:path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
518+
:kernelversion => '3.6.2',
519+
:is_pe => false,
520+
}
521+
end
522+
523+
it { is_expected.to compile }
524+
it { is_expected.to contain_concat__fragment('rspec.example.com-apache-header').with(
525+
:content => /[.\/m]*<VirtualHost \[::1\]:80>[.\/m]*$/ ) }
526+
it { is_expected.to contain_concat__fragment('Listen [::1]:80') }
527+
it { is_expected.to_not contain_concat__fragment('NameVirtualHost [::1]:80') }
528+
end
529+
496530
context 'set only aliases' do
497531
let :params do
498532
{
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#! /usr/bin/env ruby -S rspec
2+
require 'spec_helper'
3+
4+
describe "the enclose_ipv6 function" do
5+
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
6+
7+
it "should exist" do
8+
expect(Puppet::Parser::Functions.function("enclose_ipv6")).to eq("function_enclose_ipv6")
9+
end
10+
11+
it "should raise a ParseError if there is less than 1 arguments" do
12+
expect { scope.function_enclose_ipv6([]) }.to( raise_error(Puppet::ParseError) )
13+
end
14+
15+
it "should raise a ParseError if there is more than 1 arguments" do
16+
expect { scope.function_enclose_ipv6(['argument1','argument2']) }.to( raise_error(Puppet::ParseError) )
17+
end
18+
19+
it "should raise a ParseError when given garbage" do
20+
expect { scope.function_enclose_ipv6(['garbage']) }.to( raise_error(Puppet::ParseError) )
21+
end
22+
23+
it "should raise a ParseError when given something else than a string or an array" do
24+
expect { scope.function_enclose_ipv6([['1' => '127.0.0.1']]) }.to( raise_error(Puppet::ParseError) )
25+
end
26+
27+
it "should not raise a ParseError when given a single ip string" do
28+
expect { scope.function_enclose_ipv6(['127.0.0.1']) }.to_not raise_error
29+
end
30+
31+
it "should not raise a ParseError when given an array of ip strings" do
32+
expect { scope.function_enclose_ipv6([['127.0.0.1','fe80::1']]) }.to_not raise_error
33+
end
34+
35+
it "should not raise a ParseError when given differently notations of ip addresses" do
36+
expect { scope.function_enclose_ipv6([['127.0.0.1','fe80::1','[fe80::1]']]) }.to_not raise_error
37+
end
38+
39+
it "should raise a ParseError when given a wrong ipv4 address" do
40+
expect { scope.function_enclose_ipv6(['127..0.0.1']) }.to( raise_error(Puppet::ParseError) )
41+
end
42+
43+
it "should raise a ParseError when given a ipv4 address with square brackets" do
44+
expect { scope.function_enclose_ipv6(['[127.0.0.1]']) }.to( raise_error(Puppet::ParseError) )
45+
end
46+
47+
it "should raise a ParseError when given a wrong ipv6 address" do
48+
expect { scope.function_enclose_ipv6(['fe80:::1']) }.to( raise_error(Puppet::ParseError) )
49+
end
50+
51+
it "should embrace ipv6 adresses within an array of ip addresses" do
52+
result = scope.function_enclose_ipv6([['127.0.0.1','fe80::1','[fe80::1]']])
53+
expect(result).to(eq(['127.0.0.1','[fe80::1]','[fe80::1]']))
54+
end
55+
56+
it "should embrace a single ipv6 adresse" do
57+
result = scope.function_enclose_ipv6(['fe80::1'])
58+
expect(result).to(eq(['[fe80::1]']))
59+
end
60+
61+
it "should not embrace a single ipv4 adresse" do
62+
result = scope.function_enclose_ipv6(['127.0.0.1'])
63+
expect(result).to(eq(['127.0.0.1']))
64+
end
65+
end

0 commit comments

Comments
 (0)