Merge pull request #337 from rabbitt/master

add ability to define geo and map mappings
This commit is contained in:
James Fryman 2014-06-16 09:43:15 -05:00
commit 03094eabe5
8 changed files with 449 additions and 0 deletions

View file

@ -83,6 +83,8 @@ class nginx (
$worker_connections = $nginx::params::nx_worker_connections, $worker_connections = $nginx::params::nx_worker_connections,
$worker_processes = $nginx::params::nx_worker_processes, $worker_processes = $nginx::params::nx_worker_processes,
$worker_rlimit_nofile = $nginx::params::nx_worker_rlimit_nofile, $worker_rlimit_nofile = $nginx::params::nx_worker_rlimit_nofile,
$geo_mappings = {},
$string_mappings = {},
) inherits nginx::params { ) inherits nginx::params {
include stdlib include stdlib
@ -159,6 +161,9 @@ class nginx (
validate_string($proxy_headers_hash_bucket_size) validate_string($proxy_headers_hash_bucket_size)
validate_bool($super_user) validate_bool($super_user)
validate_hash($string_mappings)
validate_hash($geo_mappings)
class { 'nginx::package': class { 'nginx::package':
package_name => $package_name, package_name => $package_name,
package_source => $package_source, package_source => $package_source,
@ -221,6 +226,8 @@ class nginx (
create_resources('nginx::resource::vhost', $nginx_vhosts) create_resources('nginx::resource::vhost', $nginx_vhosts)
create_resources('nginx::resource::location', $nginx_locations) create_resources('nginx::resource::location', $nginx_locations)
create_resources('nginx::resource::mailhost', $nginx_mailhosts) create_resources('nginx::resource::mailhost', $nginx_mailhosts)
create_resources('nginx::resource::map', $string_mappings)
create_resources('nginx::resource::geo', $geo_mappings)
# Allow the end user to establish relationships to the "main" class # Allow the end user to establish relationships to the "main" class
# and preserve the relationship to the implementation classes through # and preserve the relationship to the implementation classes through

90
manifests/resource/geo.pp Normal file
View file

@ -0,0 +1,90 @@
# define: nginx::resource::geo
#
# This definition creates a new geo mapping entry for NGINX
#
# Parameters:
# [*networks*] - Hash of geo lookup keys and resultant values
# [*default*] - Sets the resulting value if the source value fails to
# match any of the variants.
# [*ensure*] - Enables or disables the specified location
# [*ranges*] - Indicates that lookup keys (network addresses) are
# specified as ranges.
# [*address*] - Nginx defaults to using $remote_addr for testing.
# This allows you to override that with another variable
# name (automatically prefixed with $)
# [*delete*] - deletes the specified network (see: geo module docs)
# [*proxy_recursive*] - Changes the behavior of address acquisition when
# specifying trusted proxies via 'proxies' directive
# [*proxies*] - Hash of network->value mappings.
# Actions:
#
# Requires:
#
# Sample Usage:
#
# nginx::resource::geo { 'client_network':
# ensure => present,
# ranges => false,
# default => extra,
# proxy_recursive => false,
# proxies => [ '192.168.99.99' ],
# networks => {
# '10.0.0.0/8' => 'intra',
# '172.16.0.0/12' => 'intra',
# '192.168.0.0/16' => 'intra',
# }
# }
#
# Sample Hiera usage:
#
# nginx::geos:
# client_network:
# ensure: present
# ranges: false
# default: 'extra'
# proxy_recursive: false
# proxies:
# - 192.168.99.99
# networks:
# '10.0.0.0/8': 'intra'
# '172.16.0.0/12': 'intra'
# '192.168.0.0/16': 'intra'
define nginx::resource::geo (
$networks,
$default = undef,
$ensure = 'present',
$ranges = false,
$address = undef,
$delete = undef,
$proxies = undef,
$proxy_recursive = undef
) {
validate_hash($networks)
validate_bool($ranges)
validate_re($ensure, '^(present|absent)$',
"Invalid ensure value '${ensure}'. Expected 'present' or 'absent'")
if ($default != undef) { validate_string($default) }
if ($address != undef) { validate_string($address) }
if ($delete != undef) { validate_string($delete) }
if ($proxies != undef) { validate_array($proxies) }
if ($proxy_recursive != undef) { validate_bool($proxy_recursive) }
File {
owner => 'root',
group => 'root',
mode => '0644',
}
file { "${nginx::params::nx_conf_dir}/conf.d/${name}-geo.conf":
ensure => $ensure ? {
'absent' => absent,
default => 'file',
},
content => template('nginx/conf.d/geo.erb'),
notify => Class['nginx::service'],
}
}

74
manifests/resource/map.pp Normal file
View file

@ -0,0 +1,74 @@
# define: nginx::resource::map
#
# This definition creates a new mapping entry for NGINX
#
# Parameters:
# [*ensure*] - Enables or disables the specified location (present|absent)
# [*default*] - Sets the resulting value if the source values fails to
# match any of the variants.
# [*string*] - Source string or variable to provide mapping for
# [*mappings*] - Hash of map lookup keys and resultant values
# [*hostnames*] - Indicates that source values can be hostnames with a
# prefix or suffix mask.
# Actions:
#
# Requires:
#
# Sample Usage:
#
# nginx::resource::map { 'backend_pool':
# ensure => present,
# hostnames => true,
# default => 'ny-pool-1,
# string => '$http_host',
# mappings => {
# '*.nyc.example.com' => 'ny-pool-1',
# '*.sf.example.com' => 'sf-pool-1',
# }
# }
#
# Sample Hiera usage:
#
# nginx::maps:
# client_network:
# ensure: present
# hostnames: true
# default: 'ny-pool-1'
# string: $http_host
# mappings:
# '*.nyc.example.com': 'ny-pool-1'
# '*.sf.example.com': 'sf-pool-1'
define nginx::resource::map (
$string,
$mappings,
$default = undef,
$ensure = 'present',
$hostnames = false
) {
validate_string($string)
validate_re($string, '^.{2,}$',
"Invalid string value [${string}]. Expected a minimum of 2 characters.")
validate_hash($mappings)
validate_bool($hostnames)
validate_re($ensure, '^(present|absent)$',
"Invalid ensure value '${ensure}'. Expected 'present' or 'absent'")
if ($default != undef) { validate_string($default) }
File {
owner => 'root',
group => 'root',
mode => '0644',
}
file { "${nginx::params::nx_conf_dir}/conf.d/${name}-map.conf":
ensure => $ensure ? {
'absent' => absent,
default => 'file',
},
content => template('nginx/conf.d/map.erb'),
notify => Class['nginx::service'],
}
}

View file

@ -194,6 +194,8 @@ define nginx::resource::vhost (
$log_by_lua_file = undef, $log_by_lua_file = undef,
$use_default_location = true, $use_default_location = true,
$rewrite_rules = [], $rewrite_rules = [],
$string_mappings = {},
$geo_mappings = {},
) { ) {
validate_re($ensure, '^(present|absent)$', validate_re($ensure, '^(present|absent)$',
@ -332,6 +334,8 @@ define nginx::resource::vhost (
} }
validate_bool($use_default_location) validate_bool($use_default_location)
validate_array($rewrite_rules) validate_array($rewrite_rules)
validate_hash($string_mappings)
validate_hash($geo_mappings)
# Variables # Variables
$vhost_dir = "${nginx::config::conf_dir}/sites-available" $vhost_dir = "${nginx::config::conf_dir}/sites-available"
@ -555,4 +559,7 @@ define nginx::resource::vhost (
require => Concat[$config_file], require => Concat[$config_file],
notify => Service['nginx'], notify => Service['nginx'],
} }
create_resources('nginx::resource::map', $string_mappings)
create_resources('nginx::resource::geo', $geo_mappings)
} }

View file

@ -0,0 +1,128 @@
require 'spec_helper'
describe 'nginx::resource::geo' do
let :title do
'client_network'
end
let :default_params do
{
:default => 'extra',
:networks => {
'172.16.0.0/12' => 'intra',
'192.168.0.0/16' => 'intra',
'10.0.0.0/8' => 'intra',
},
:proxies => [ '1.2.3.4', '4.3.2.1' ]
}
end
let :facts do
{
:osfamily => 'RedHat',
:operatingsystem => 'CentOS',
}
end
let :pre_condition do
[
'include ::nginx::params',
]
end
describe 'os-independent items' do
describe 'basic assumptions' do
let :params do default_params end
it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with(
{
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'ensure' => 'file',
'content' => /geo \$#{title}/,
}
)}
end
describe "geo.conf template content" do
[
{
:title => 'should set address',
:attr => 'address',
:value => '$remote_addr',
:match => 'geo $remote_addr $client_network {'
},
{
:title => 'should set ranges',
:attr => 'ranges',
:value => true,
:match => ' ranges;'
},
{
:title => 'should set default',
:attr => 'default',
:value => 'extra',
:match => [ ' default extra;' ],
},
{
:title => 'should contain ordered network directives',
:attr => 'networks',
:value => {
'192.168.0.0/16' => 'intra',
'172.16.0.0/12' => 'intra',
'10.0.0.0/8' => 'intra',
},
:match => [
' 10.0.0.0/8 intra;',
' 172.16.0.0/12 intra;',
' 192.168.0.0/16 intra;',
],
},
{
:title => 'should set multiple proxies',
:attr => 'proxies',
:value => [ '1.2.3.4', '4.3.2.1' ],
:match => [
' proxy 1.2.3.4;',
' proxy 4.3.2.1;'
]
},
{
:title => 'should set proxy_recursive',
:attr => 'proxy_recursive',
:value => true,
:match => ' proxy_recursive;'
},
{
:title => 'should set delete',
:attr => 'delete',
:value => '192.168.0.0/16',
:match => ' delete 192.168.0.0/16;'
},
].each do |param|
context "when #{param[:attr]} is #{param[:value]}" do
let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end
it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with_mode('0644') }
it param[:title] do
verify_contents(subject, "/etc/nginx/conf.d/#{title}-geo.conf", Array(param[:match]))
Array(param[:notmatch]).each do |item|
should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").without_content(item)
end
end
end
end
context 'when ensure => absent' do
let :params do default_params.merge(
{
:ensure => 'absent'
}
) end
it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with_ensure('absent') }
end
end
end
end

View file

@ -0,0 +1,101 @@
require 'spec_helper'
describe 'nginx::resource::map' do
let :title do
'backend_pool'
end
let :default_params do
{
:string => '$uri',
:default => 'pool_a',
:mappings => {
'foo' => 'pool_b',
'bar' => 'pool_c',
'baz' => 'pool_d',
},
}
end
let :facts do
{
:osfamily => 'RedHat',
:operatingsystem => 'CentOS',
}
end
let :pre_condition do
[
'include ::nginx::params',
]
end
describe 'os-independent items' do
describe 'basic assumptions' do
let :params do default_params end
it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with(
{
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'ensure' => 'file',
'content' => /map \$uri \$#{title}/,
}
)}
end
describe "map.conf template content" do
[
{
:title => 'should set hostnames',
:attr => 'hostnames',
:value => true,
:match => ' hostnames;'
},
{
:title => 'should set default',
:attr => 'default',
:value => 'pool_a',
:match => [ ' default pool_a;' ],
},
{
:title => 'should contain ordered mappings',
:attr => 'mappings',
:value => {
'foo' => 'pool_b',
'bar' => 'pool_c',
'baz' => 'pool_d',
},
:match => [
' bar pool_c;',
' baz pool_d;',
' foo pool_b;',
],
},
].each do |param|
context "when #{param[:attr]} is #{param[:value]}" do
let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end
it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with_mode('0644') }
it param[:title] do
verify_contents(subject, "/etc/nginx/conf.d/#{title}-map.conf", Array(param[:match]))
Array(param[:notmatch]).each do |item|
should contain_file("/etc/nginx/conf.d/#{title}-map.conf").without_content(item)
end
end
end
end
context 'when ensure => absent' do
let :params do default_params.merge(
{
:ensure => 'absent'
}
) end
it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with_ensure('absent') }
end
end
end
end

29
templates/conf.d/geo.erb Normal file
View file

@ -0,0 +1,29 @@
<%
# sorting ip addresses in ascending order is more efficient for nginx - so we need
# to convert them to numbers first via IPAddr
require 'ipaddr'
-%>
geo <%= @address ? "#{@address} " : '' %>$<%= @name %> {
<% if @ranges -%>
ranges;
<% end -%>
<% if @default -%>
default <%= @default %>;
<% end -%>
<% if @delete -%>
delete <%= @delete %>;
<% end -%>
<% if @proxies -%>
<%- [@proxies].flatten.each do |proxy| -%>
proxy <%= proxy %>;
<%- end -%>
<% end -%>
<% if @proxy_recursive && @proxies -%>
proxy_recursive;
<% end -%>
<% if @networks -%>
<%- @networks.sort_by{|k,v| IPAddr.new(k.split('-').first).to_i }.each do |key,value| -%>
<%= key %> <%= value %>;
<%- end -%>
<% end -%>
}

13
templates/conf.d/map.erb Normal file
View file

@ -0,0 +1,13 @@
map <%= @string %> $<%= @name %> {
<% if @hostnames -%>
hostnames;
<% end -%>
<% if @default -%>
default <%= @default %>;
<% end -%>
<% if @mappings -%>
<%- @mappings.sort_by{|k,v| k}.each do |key,value| -%>
<%= key %> <%= value %>;
<%- end -%>
<% end -%>
}