diff --git a/README.md b/README.md index d145b36c5..65d5bc360 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,20 @@ nginx::resource::server { 'www.puppetlabs.com': ```puppet nginx::resource::upstream { 'puppet_rack_app': - members => [ - 'localhost:3000', - 'localhost:3001', - 'localhost:3002', - ], + members => { + 'localhost:3000': + server => 'localhost' + port => 3000 + weight => 1 + 'localhost:3001': + server => 'localhost' + port => 3001 + weight => 1 + 'localhost:3002': + server => 'localhost' + port => 3002 + weight => 2 + }, } nginx::resource::server { 'rack.puppetlabs.com': @@ -85,6 +94,38 @@ nginx::resource::mailhost { 'domain1.example': } ``` +### Convert upstream members from Array to Hash + +The datatype Array for members of a nginx::resource::upstream is replaced by a Hash. The following configuration is no longer valid: + +```puppet +nginx::resource::upstream { 'puppet_rack_app': + members => [ + 'localhost:3000', + 'localhost:3001', + 'localhost:3002', + ], +} +``` + +From now on, the configuration must look like this: + +```puppet +nginx::resource::upstream { 'puppet_rack_app': + members => { + 'localhost:3000': + server => 'localhost' + port => 3000 + 'localhost:3001': + server => 'localhost' + port => 3001 + 'localhost:3002': + server => 'localhost' + port => 3002 + }, +} +``` + ## SSL configuration By default, creating a server resource will only create a HTTP server. To also @@ -137,9 +178,15 @@ nginx::nginx_upstreams: 'puppet_rack_app': ensure: present members: - - localhost:3000 - - localhost:3001 - - localhost:3002 + 'localhost:3000': + server: 'localhost' + port: 3000 + 'localhost:3001': + server: 'localhost' + port: 3001 + 'localhost:3002': + server: 'localhost' + port: 3002 nginx::nginx_servers: 'www.puppetlabs.com': www_root: '/var/www/www.puppetlabs.com' @@ -185,9 +232,15 @@ nginx::nginx_upstreams: 'syslog': upstream_context: 'stream' members: - - '10.0.0.1:514' - - '10.0.0.2:514' - - '10.0.0.3:514' + '10.0.0.1:514' + server: '10.0.0.1' + port: '514' + '10.0.0.2:514' + server: '10.0.0.2' + port: '514' + '10.0.0.3:514' + server: '10.0.0.3' + port: '514' ``` ## Nginx with precompiled Passenger diff --git a/manifests/init.pp b/manifests/init.pp index c33d4f55a..0b65a47fb 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -171,6 +171,7 @@ $nginx_mailhosts_defaults = {}, $nginx_streamhosts = {}, $nginx_upstreams = {}, + Nginx::UpstreamMemberDefaults $nginx_upstream_defaults = {}, $nginx_servers = {}, $nginx_servers_defaults = {}, Boolean $purge_passenger_repo = true, @@ -182,7 +183,7 @@ contain 'nginx::config' contain 'nginx::service' - create_resources('nginx::resource::upstream', $nginx_upstreams) + create_resources('nginx::resource::upstream', $nginx_upstreams, $nginx_upstream_defaults) create_resources('nginx::resource::server', $nginx_servers, $nginx_servers_defaults) create_resources('nginx::resource::location', $nginx_locations, $nginx_locations_defaults) create_resources('nginx::resource::mailhost', $nginx_mailhosts, $nginx_mailhosts_defaults) diff --git a/manifests/resource/upstream.pp b/manifests/resource/upstream.pp index 28c61123f..d3665b2d0 100644 --- a/manifests/resource/upstream.pp +++ b/manifests/resource/upstream.pp @@ -3,13 +3,28 @@ # This definition creates a new upstream proxy entry for NGINX # # Parameters: -# [*members*] - Array of member URIs for NGINX to connect to. Must follow valid NGINX syntax. -# If omitted, individual members should be defined with nginx::resource::upstream::member # [*ensure*] - Enables or disables the specified location (present|absent) -# [*upstream_cfg_append*] - Hash of custom directives to put after other directives in upstream -# [*upstream_cfg_prepend*] - It expects a hash with custom directives to put before anything else inside upstream -# [*upstream_fail_timeout*] - Set the fail_timeout for the upstream. Default is 10 seconds - As that is what Nginx does normally. -# [*upstream_max_fails*] - Set the max_fails for the upstream. Default is to use nginx default value which is 1. +# [*context*] - Set the type of this upstream (http|stream). +# [*members*] - Hash of member URIs for NGINX to connect to. Must follow valid NGINX syntax. +# If omitted, individual members should be defined with nginx::resource::upstream::member +# [*members_tag*] - Restrict collecting the exported members for this upstream with a tag. +# [*member_defaults*] - Specify default settings added to each member of this upstream. +# [*hash*] - Activate the hash load balancing method (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#hash). +# [*ip_hash*] - Activate ip_hash for this upstream (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash). +# [*keepalive*] - Set the maximum number of idle keepalive connections (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive). +# [*keepalive_requests*] - Sets the maximum number of requests that can be served through one keepalive connection (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_requests). +# [*keepalive_timeout*] - Sets a timeout during which an idle keepalive connection to an upstream server will stay open (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_timeout). +# [*least_conn*] - Activate the least_conn load balancing method (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_conn). +# [*least_time*] - Activate the least_time load balancing method (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_time). +# [*ntlm*] - Allow NTLM authentication (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ntlm). +# [*queue_max*] - Set the maximum number of queued requests (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#queue). +# [*queue_timeout*] - Set the timeout for the queue (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#queue). +# [*random*] - Activate the random load balancing method (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#random). +# [*statefile*] - Specifies a file that keeps the state of the dynamically configurable group (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#state). +# [*sticky*] - Enables session affinity (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#sticky). +# [*zone*] - Defines the name and optional the size of the shared memory zone (https://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone). +# [*cfg_append*] - Hash of custom directives to put after other directives in upstream +# [*cfg_prepend*] - It expects a hash with custom directives to put before anything else inside upstream # # Actions: # @@ -18,82 +33,121 @@ # Sample Usage: # nginx::resource::upstream { 'proxypass': # ensure => present, -# members => [ -# 'localhost:3000', -# 'localhost:3001', -# 'localhost:3002', -# ], +# members => { +# 'localhost:3001' => { +# server => 'localhost', +# port => 3000, +# }, +# 'localhost:3002' => { +# server => 'localhost', +# port => 3002, +# }, +# 'localhost:3003' => { +# server => 'localhost', +# port => 3003, +# }, +# }, # } # # Custom config example to use ip_hash, and 20 keepalive connections # create a hash with any extra custom config you want. -# $my_config = { -# 'ip_hash' => '', -# 'keepalive' => '20', -# } # nginx::resource::upstream { 'proxypass': -# ensure => present, -# members => [ -# 'localhost:3000', -# 'localhost:3001', -# 'localhost:3002', -# ], -# upstream_cfg_prepend => $my_config, +# ensure => present, +# members => { +# 'localhost:3001' => { +# server => 'localhost', +# port => 3000, +# }, +# 'localhost:3002' => { +# server => 'localhost', +# port => 3002, +# }, +# 'localhost:3003' => { +# server => 'localhost', +# port => 3003, +# }, +# }, +# ip_hash => true, +# keepalive => 20, # } +# define nginx::resource::upstream ( - Optional[Array] $members = undef, - $members_tag = undef, - Enum['present', 'absent'] $ensure = 'present', - Optional[Hash] $upstream_cfg_append = undef, - Optional[Hash] $upstream_cfg_prepend = undef, - $upstream_fail_timeout = '10s', - $upstream_max_fails = undef, - Enum['http', 'stream'] $upstream_context = 'http', + Enum['present', 'absent'] $ensure = 'present', + Enum['http', 'stream'] $context = 'http', + Nginx::UpstreamMembers $members = {}, + Optional[String[1]] $members_tag = undef, + Nginx::UpstreamMemberDefaults $member_defaults = {}, + Optional[String[1]] $hash = undef, + Boolean $ip_hash = false, + Optional[Integer[1]] $keepalive = undef, + Optional[Integer[1]] $keepalive_requests = undef, + Optional[Nginx::Time] $keepalive_timeout = undef, + Boolean $least_conn = false, + Optional[Nginx::UpstreamLeastTime] $least_time = undef, + Boolean $ntlm = false, + Optional[Integer] $queue_max = undef, + Optional[Nginx::Time] $queue_timeout = undef, + Optional[String[1]] $random = undef, + Optional[Stdlib::Unixpath] $statefile = undef, + Optional[Nginx::UpstreamSticky] $sticky = undef, + Optional[Nginx::UpstreamZone] $zone = undef, + Nginx::UpstreamCustomParameters $cfg_append = {}, + Nginx::UpstreamCustomParameters $cfg_prepend = {}, ) { if ! defined(Class['nginx']) { fail('You must include the nginx base class before using any defined resources') } - $root_group = $nginx::root_group - - $ensure_real = $ensure ? { - 'absent' => absent, - default => present, + if $least_time { + if $context == 'http' and ! ($least_time =~ Nginx::UpstreamLeastTimeHttp) { + fail('The parameter "least_time" does not match the datatype "Nginx::UpstreamLeastTimeHttp"') + } + if $context == 'stream' and ! ($least_time =~ Nginx::UpstreamLeastTimeStream) { + fail('The parameter "least_time" does not match the datatype "Nginx::UpstreamLeastTimeStream"') + } } - $conf_dir_real = $upstream_context ? { - 'stream' => 'conf.stream.d', - default => 'conf.d', + $conf_dir = $context ? { + 'stream' => "${nginx::config::conf_dir}/conf.stream.d", + default => "${nginx::config::conf_dir}/conf.d", } - $conf_dir = "${nginx::config::conf_dir}/${conf_dir_real}" - Concat { owner => 'root', - group => $root_group, + group => $nginx::root_group, mode => '0644', } - concat { "${nginx::conf_dir}/${conf_dir_real}/${name}-upstream.conf": - ensure => $ensure_real, + concat { "${conf_dir}/${name}-upstream.conf": + ensure => $ensure, notify => Class['::nginx::service'], require => File[$conf_dir], } - # Uses: $name, $upstream_cfg_prepend concat::fragment { "${name}_upstream_header": - target => "${nginx::conf_dir}/${conf_dir_real}/${name}-upstream.conf", + target => "${conf_dir}/${name}-upstream.conf", order => '10', - content => template('nginx/upstream/upstream_header.erb'), + content => epp('nginx/upstream/upstream_header.epp', { + cfg_prepend => $cfg_prepend, + name => $name, + }), } if $members != undef { - # Uses: $members, $upstream_fail_timeout - concat::fragment { "${name}_upstream_members": - target => "${nginx::conf_dir}/${conf_dir_real}/${name}-upstream.conf", - order => '50', - content => template('nginx/upstream/upstream_members.erb'), + $members.each |$member,$values| { + $member_values = merge($member_defaults,$values,{'upstream' => $name,'context' => $context}) + + if $context == 'stream' and $member_values['route'] { + fail('The parameter "route" is not available for upstreams with context "stream"') + } + if $context == 'stream' and $member_values['state'] and $member_values['state'] == 'drain' { + fail('The state "drain" is not available for upstreams with context "stream"') + } + + nginx::resource::upstream::member { $member: + * => $member_values, + } } } else { # Collect exported members: @@ -105,8 +159,24 @@ } concat::fragment { "${name}_upstream_footer": - target => "${nginx::conf_dir}/${conf_dir_real}/${name}-upstream.conf", + target => "${conf_dir}/${name}-upstream.conf", order => '90', - content => template('nginx/upstream/upstream_footer.erb'), + content => epp('nginx/upstream/upstream_footer.epp', { + cfg_append => $cfg_append, + hash => $hash, + ip_hash => $ip_hash, + keepalive => $keepalive, + keepalive_requests => $keepalive_requests, + keepalive_timeout => $keepalive_timeout, + least_conn => $least_conn, + least_time => $least_time, + ntlm => $ntlm, + queue_max => $queue_max, + queue_timeout => $queue_timeout, + random => $random, + statefile => $statefile, + sticky => $sticky, + zone => $zone, + }), } } diff --git a/manifests/resource/upstream/member.pp b/manifests/resource/upstream/member.pp index 7ce6ea5a9..075f564a1 100644 --- a/manifests/resource/upstream/member.pp +++ b/manifests/resource/upstream/member.pp @@ -9,46 +9,95 @@ # # # Parameters: -# [*ensure*] - Enables or disables the specified member (present|absent) -# [*upstream*] - The name of the upstream resource -# [*server*] - Hostname or IP of the upstream member server -# [*port*] - Port of the listening service on the upstream member -# [*upstream_fail_timeout*] - Set the fail_timeout for the upstream. Default is 10 seconds -# +# [*upstream*] - The name of the upstream resource +# [*ensure*] - Enables or disables the specified member (present|absent) +# [*context*] - Set the type of this upstream (http|stream). +# [*server*] - Hostname or IP of the upstream member server +# [*port*] - Port of the listening service on the upstream member +# [*weight*] - Set the weight for this upstream member +# [*max_conns*] - Set the max_conns for this upstream member +# [*max_fails*] - Set the max_fails for this upstream member +# [*fail_timeout*] - Set the fail_timeout for this upstream member +# [*backup*] - Activate backup for this upstream member +# [*resolve*] - Activate resolve for this upstream member +# [*route*] - Set the route for this upstream member +# [*service*] - Set the service for this upstream member +# [*slow_start*] - Set the slow_start for this upstream member +# [*state*] - Set the state for this upstream member +# [*params_prepend*] - prepend a parameter for this upstream member +# [*params_append*] - append a paremeter for this upstream member +# [*comment*] - Add a comment for this upstream member # # Examples: # # Exporting the resource on a upstream member server: # # @@nginx::resource::upstream::member { $trusted['certname']: -# ensure => present, -# upstream => 'proxypass', -# server => $facts['networking']['ip'], -# port => 3000, +# ensure => present, +# upstream => 'proxypass', +# server => $facts['networking']['ip'], +# port => 3000, # } # # # Collecting the resource on the NGINX server: # # nginx::resource::upstream { 'proxypass': -# ensure => present, +# ensure => present, # } # define nginx::resource::upstream::member ( - $upstream, - $server, - Enum['present', 'absent'] $ensure = 'present', - Integer $port = 80, - $upstream_fail_timeout = '10s', + String[1] $upstream, + Enum['present', 'absent'] $ensure = 'present', + Enum['http', 'stream'] $context = 'http', + Optional[Nginx::UpstreamMemberServer] $server = $name, + Stdlib::Port $port = 80, + Optional[Integer[1]] $weight = undef, + Optional[Integer[1]] $max_conns = undef, + Optional[Integer[1]] $max_fails = undef, + Optional[Nginx::Time] $fail_timeout = undef, + Boolean $backup = false, + Boolean $resolve = false, + Optional[String[1]] $route = undef, + Optional[String[1]] $service = undef, + Optional[Nginx::Time] $slow_start = undef, + Optional[Enum['drain','down']] $state = undef, + Optional[String[1]] $params_prepend = undef, + Optional[String[1]] $params_append = undef, + Optional[String[1]] $comment = undef, ) { if ! defined(Class['nginx']) { fail('You must include the nginx base class before using any defined resources') } - # Uses: $server, $port, $upstream_fail_timeout + $conf_dir = $context ? { + 'stream' => "${nginx::config::conf_dir}/conf.stream.d", + default => "${nginx::config::conf_dir}/conf.d", + } + + $_server = ($server =~ Pattern[/^unix:\/([^\/\0]+\/*)*$/]) ? { + true => $server, + false => "${server}:${port}", + } + concat::fragment { "${upstream}_upstream_member_${name}": - target => "${nginx::conf_dir}/conf.d/${upstream}-upstream.conf", + target => "${conf_dir}/${upstream}-upstream.conf", order => 40, - content => template('nginx/upstream/upstream_member.erb'), + content => epp('nginx/upstream/upstream_member.epp', { + _server => $_server, + backup => $backup, + comment => $comment, + fail_timeout => $fail_timeout, + max_conns => $max_conns, + max_fails => $max_fails, + params_append => $params_append, + params_prepend => $params_prepend, + resolve => $resolve, + route => $route, + service => $service, + slow_start => $slow_start, + state => $state, + weight => $weight, + }), } } diff --git a/spec/acceptance/nginx_proxy_spec.rb b/spec/acceptance/nginx_proxy_spec.rb index 839f854bc..9a80269a3 100644 --- a/spec/acceptance/nginx_proxy_spec.rb +++ b/spec/acceptance/nginx_proxy_spec.rb @@ -6,11 +6,20 @@ class { 'nginx': } nginx::resource::upstream { 'puppet_rack_app': ensure => present, - members => [ - 'localhost:3000', - 'localhost:3001', - 'localhost:3002', - ], + members => { + 'localhost:3000' => { + server => 'localhost', + port => 3000, + }, + 'localhost:3001' => { + server => 'localhost', + port => 3001, + }, + 'localhost:3002' => { + server => 'localhost', + port => 3002, + }, + }, } nginx::resource::server { 'rack.puppetlabs.com': ensure => present, @@ -23,10 +32,10 @@ class { 'nginx': } describe file('/etc/nginx/conf.d/puppet_rack_app-upstream.conf') do it { is_expected.to be_file } - it { is_expected.to contain 'server localhost:3000' } - it { is_expected.to contain 'server localhost:3001' } - it { is_expected.to contain 'server localhost:3002' } - it { is_expected.not_to contain 'server localhost:3003' } + it { is_expected.to contain 'server localhost:3000' } + it { is_expected.to contain 'server localhost:3001' } + it { is_expected.to contain 'server localhost:3002' } + it { is_expected.not_to contain 'server localhost:3003' } end describe file('/etc/nginx/sites-available/rack.puppetlabs.com.conf') do diff --git a/spec/acceptance/nginx_upstream_spec.rb b/spec/acceptance/nginx_upstream_spec.rb new file mode 100644 index 000000000..c4c6b35a7 --- /dev/null +++ b/spec/acceptance/nginx_upstream_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper_acceptance' + +describe 'nginx::resource::upstream define:' do + it 'runs successfully' do + pp = " + class { 'nginx': } + nginx::resource::upstream { 'production': + ensure => present, + ip_hash => true, + keepalive => 16, + member_defaults => { + max_conns => 20, + max_fails => 20, + fail_timeout => '20s', + }, + members => { + 'appserver_01' => { + server => '10.10.10.1', + port => 80, + weight => 2, + max_conns => 10, + max_fails => 10, + fail_timeout => '10s', + comment => 'Appserver 01', + }, + 'appserver_02' => { + server => '10.10.10.2', + port => 80, + weight => 3, + max_conns => 15, + max_fails => 15, + fail_timeout => '15s', + comment => 'Appserver 02', + }, + 'appserver_03' => { + server => '10.10.10.3', + port => 80, + backup => true, + comment => 'Appserver 03', + }, + }, + zone => 'production 64k', + } + nginx::resource::upstream { 'socket': + ensure => present, + member_defaults => { + max_conns => 20, + max_fails => 20, + fail_timeout => '20s', + }, + members => { + 'socket_01' => { + server => 'unix:/var/run/socket_01.sock', + }, + 'socket_02' => { + server => 'unix:/var/run/socket_02.sock', + }, + }, + zone => 'socket 64k', + } + + nginx::resource::server { 'www.puppetlabs.com': + ensure => present, + proxy => 'http://production', + } + nginx::resource::server { 'socket.puppetlabs.com': + ensure => present, + proxy => 'http://socket', + } + " + apply_manifest(pp, catch_failures: true) + end + + describe file('/etc/nginx/conf.d/production-upstream.conf') do + it { is_expected.to be_file } + it { is_expected.to contain '# MANAGED BY PUPPET' } + it { is_expected.to contain 'upstream production {' } + it { is_expected.to contain ' server 10.10.10.1:80 weight=2 max_conns=10 max_fails=10 fail_timeout=10s; # Appserver 01' } + it { is_expected.to contain ' server 10.10.10.2:80 weight=3 max_conns=15 max_fails=15 fail_timeout=15s; # Appserver 02' } + it { is_expected.to contain ' server 10.10.10.3:80 max_conns=20 max_fails=20 fail_timeout=20s backup; # Appserver 03' } + it { is_expected.to contain ' ip_hash;' } + it { is_expected.to contain ' zone production 64k;' } + it { is_expected.to contain ' keepalive 16;' } + end + describe file('/etc/nginx/sites-available/www.puppetlabs.com.conf') do + it { is_expected.to be_file } + it { is_expected.to contain '# MANAGED BY PUPPET' } + it { is_expected.to contain ' proxy_pass http://production;' } + end + + describe file('/etc/nginx/conf.d/socket-upstream.conf') do + it { is_expected.to be_file } + it { is_expected.to contain '# MANAGED BY PUPPET' } + it { is_expected.to contain 'upstream socket {' } + it { is_expected.to contain ' server unix:/var/run/socket_01.sock max_conns=20 max_fails=20 fail_timeout=20s;' } + it { is_expected.to contain ' server unix:/var/run/socket_02.sock max_conns=20 max_fails=20 fail_timeout=20s;' } + it { is_expected.to contain ' zone socket 64k;' } + end + describe file('/etc/nginx/sites-available/socket.puppetlabs.com.conf') do + it { is_expected.to be_file } + it { is_expected.to contain '# MANAGED BY PUPPET' } + it { is_expected.to contain ' proxy_pass http://socket;' } + end + + describe service('nginx') do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end + + describe port(80) do + it { is_expected.to be_listening } + end +end diff --git a/spec/classes/nginx_spec.rb b/spec/classes/nginx_spec.rb index b55f7eabb..53697e84f 100644 --- a/spec/classes/nginx_spec.rb +++ b/spec/classes/nginx_spec.rb @@ -9,7 +9,7 @@ let :params do { - nginx_upstreams: { 'upstream1' => { 'members' => ['localhost:3000'] } }, + nginx_upstreams: { 'upstream1' => { 'members' => { 'localhost' => { 'port' => 3000 } } } }, nginx_servers: { 'test2.local' => { 'www_root' => '/' } }, nginx_servers_defaults: { 'listen_options' => 'default_server' }, nginx_locations: { 'test2.local' => { 'server' => 'test2.local', 'www_root' => '/' } }, diff --git a/spec/defines/resource_upstream_spec.rb b/spec/defines/resource_upstream_spec.rb index 314b93029..454a71508 100644 --- a/spec/defines/resource_upstream_spec.rb +++ b/spec/defines/resource_upstream_spec.rb @@ -12,7 +12,21 @@ let :default_params do { - members: ['test'] + http: { + context: 'http', + members: { 'member-http' => {} } + }, + stream: { + context: 'stream', + members: { 'member-stream' => {} } + } + } + end + + let :conf_d_pathes do + { + http: '/etc/nginx/conf.d', + stream: '/etc/nginx/conf.stream.d' } end @@ -23,117 +37,445 @@ end describe 'os-independent items' do - describe 'basic assumptions' do - let(:params) { default_params } + ## + ## check that http is the default + ## + describe 'basic assumptions for default upstreams' do + let(:params) { default_params[:http] } - it { is_expected.to contain_concat("/etc/nginx/conf.d/#{title}-upstream.conf").that_requires('File[/etc/nginx/conf.d]') } - it { is_expected.to contain_concat__fragment("#{title}_upstream_header").with_content(%r{upstream #{title}}) } + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("/etc/nginx/conf.d/#{title}-upstream.conf"). + that_requires('File[/etc/nginx/conf.d]') + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content(%r{upstream #{title}}). + with( + 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", + 'order' => 10 + ) + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{params[:members].keys[0]}"). + with( + 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", + 'order' => 40 + ) + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with( + 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", + 'order' => 90 + ). + with_content("}\n") + } + end - it do - is_expected.to contain_concat__fragment("#{title}_upstream_header").with( - 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", - 'order' => 10 - ) - end + ## + ## check http and stream upstreams + ## + %w[http stream].each do |upstreamcontext| + describe "basic assumptions for #{upstreamcontext} upstreams" do + let(:params) { default_params[upstreamcontext.to_sym] } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } - it do - is_expected.to contain_concat__fragment("#{title}_upstream_members").with( - 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", - 'order' => 50 - ) + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + that_requires("File[#{conf_d_path}]") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content(%r{upstream #{title}}). + with( + 'target' => "#{conf_d_path}/#{title}-upstream.conf", + 'order' => 10 + ) + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{params[:members].keys[0]}"). + with( + 'target' => "#{conf_d_path}/#{title}-upstream.conf", + 'order' => 40 + ) + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with( + 'target' => "#{conf_d_path}/#{title}-upstream.conf", + 'order' => 90 + ). + with_content("}\n") + } end - it do - is_expected.to contain_concat__fragment("#{title}_upstream_footer").with( - 'target' => "/etc/nginx/conf.d/#{title}-upstream.conf", - 'order' => 90 - ).with_content("}\n") - end - end + ## + ## check the upstream template + ## + describe 'upstream.conf template content' do + ## + ## check the default + ## + context "when only a server is specified in a #{upstreamcontext} upstream" do + let(:params) { default_params[upstreamcontext.to_sym] } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } - describe 'upstream.conf template content' do - [ - { - title: 'should contain ordered prepended directives', - attr: 'upstream_cfg_prepend', - fragment: 'header', - value: { - 'test3' => 'test value 3', - 'test6' => { 'subkey1' => %w[subvalue1 subvalue2] }, - 'keepalive' => 'keepalive 1', - 'test2' => 'test value 2', - 'test5' => { 'subkey1' => 'subvalue1' }, - 'test4' => ['test value 1', 'test value 2'] - }, - match: [ - ' test2 test value 2;', - ' test3 test value 3;', - ' test4 test value 1;', - ' test4 test value 2;', - ' test5 subkey1 subvalue1;', - ' test6 subkey1 subvalue1;', - ' test6 subkey1 subvalue2;', - ' keepalive keepalive 1;' - ] - }, - { - title: 'should set server', - attr: 'members', - fragment: 'members', - value: %w[test3 test1 test2], - match: [ - ' server test3 fail_timeout=10s;', - ' server test1 fail_timeout=10s;', - ' server test2 fail_timeout=10s;' - ] - }, - { - title: 'should contain ordered appended directives', - attr: 'upstream_cfg_append', - fragment: 'footer', - value: { - 'test3' => 'test value 3', - 'test6' => { 'subkey1' => %w[subvalue1 subvalue2] }, - 'keepalive' => 'keepalive 1', - 'test2' => 'test value 2', - 'test5' => { 'subkey1' => 'subvalue1' }, - 'test4' => ['test value 1', 'test value 2'] - }, - match: [ - ' test2 test value 2;', - ' test3 test value 3;', - ' test4 test value 1;', - ' test4 test value 2;', - ' test5 subkey1 subvalue1;', - ' test6 subkey1 subvalue1;', - ' test6 subkey1 subvalue2;', - ' keepalive keepalive 1;' - ] - } - ].each do |param| - context "when #{param[:attr]} is #{param[:value]}" do - let(:params) { default_params.merge(param[:attr].to_sym => param[:value]) } - - it { is_expected.to contain_concat("/etc/nginx/conf.d/#{title}-upstream.conf").with_mode('0644') } - it { is_expected.to contain_concat__fragment("#{title}_upstream_#{param[:fragment]}") } - it param[:title] do - lines = catalogue.resource('concat::fragment', "#{title}_upstream_#{param[:fragment]}").send(:parameters)[:content].split("\n") - expect(lines & Array(param[:match])).to eq(Array(param[:match])) - Array(param[:notmatch]).each do |item| - is_expected.to contain_concat__fragment("#{title}_upstream_#{param[:fragment]}").without_content(item) + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + with_mode('0644') + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content("# MANAGED BY PUPPET\nupstream #{title} {\n") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{params[:members].keys[0]}"). + with_content(" server #{params[:members].keys[0]}:80;\n") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content("}\n") + } + end + + ## + ## check the upstream parameters + ## + [ + { + value: { hash: '$remote_addr consistent' }, + match: 'hash $remote_addr consistent' + }, + { + value: { keepalive: 20 }, + match: 'keepalive 20' + }, + { + value: { keepalive_requests: 20 }, + match: 'keepalive_requests 20' + }, + { + value: { keepalive_timeout: '20s' }, + match: 'keepalive_timeout 20s' + }, + { + value: { least_conn: true }, + match: 'least_conn' + }, + { + value: { least_conn: false }, + match: false + }, + { + value: { least_time: 'last_byte inflight' }, + match: 'least_time last_byte inflight' + }, + { + value: { least_time: 'header inflight' }, + match: 'least_time header inflight', + fails: { stream: 'The parameter "least_time" does not match the datatype "Nginx::UpstreamLeastTimeStream"' } + }, + { + value: { least_time: 'first_byte inflight' }, + match: 'least_time first_byte inflight', + fails: { http: 'The parameter "least_time" does not match the datatype "Nginx::UpstreamLeastTimeHttp"' } + }, + { + value: { ntlm: true }, + match: 'ntlm' + }, + { + value: { ntlm: false }, + match: false + }, + { + value: { queue_max: 20 }, + match: 'queue 20' + }, + { + value: { queue_max: 20, queue_timeout: '20s' }, + match: 'queue 20 timeout=20s' + }, + { + value: { random: 'two least_conn' }, + match: 'random two least_conn' + }, + { + value: { statefile: '/var/lib/nginx/state/servers.conf' }, + match: 'state /var/lib/nginx/state/servers.conf' + }, + { + value: { sticky: { cookie: { name: 'srv_id', expires: '1h', domain: '.example.com', httponly: true, secure: true, path: '/' } } }, + match: 'sticky cookie name=srv_id expires=1h domain=.example.com httponly secure path=/' + }, + { + value: { sticky: { route: '$route_cookie $route_uri' } }, + match: 'sticky route $route_cookie $route_uri' + }, + { + value: { sticky: { learn: { create: '$upstream_cookie_examplecookie', lookup: '$cookie_examplecookie', zone: 'client_sessions:1m' } } }, + match: 'sticky learn create=$upstream_cookie_examplecookie lookup=$cookie_examplecookie zone=client_sessions:1m' + }, + { + value: { zone: 'frontend 1M' }, + match: 'zone frontend 1M' + }, + { + value: { zone: 'backend 64k' }, + match: 'zone backend 64k' + } + ].each do |upstream_parameter| + context "when #{upstream_parameter[:value].keys[0]} is set to #{upstream_parameter[:value]} in #{upstreamcontext} upstream" do + let(:params) { default_params[upstreamcontext.to_sym].merge(upstream_parameter[:value]) } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } + + if upstream_parameter.key?(:fails) && upstream_parameter[:fails].key?(upstreamcontext.to_sym) + it { + is_expected.to raise_error(Puppet::Error, %r{#{upstream_parameter[:fails][upstreamcontext.to_sym]}}) + } + next + end + + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + with_mode('0644') + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content("# MANAGED BY PUPPET\nupstream #{title} {\n") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{params[:members].keys[0]}"). + with_content(" server #{params[:members].keys[0]}:80;\n") + } + + if upstream_parameter[:match] != false + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content(" #{upstream_parameter[:match]};\n}\n") + } + else + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content("}\n") + } end end end - end - context 'when ensure => absent' do - let :params do - default_params.merge( - ensure: 'absent' - ) + ## + ## check the upstream member parameters + ## + [ + { + value: { unix: { server: 'unix:/tmp/backend3' } }, + match: 'unix:/tmp/backend3;' + }, + { + value: { member1: {} }, + match: 'member1:80;' + }, + { + value: { member1: { server: '127.0.0.1' } }, + match: '127.0.0.1:80;' + }, + { + value: { member1: { server: '127.0.0.1', port: 8080 } }, + match: '127.0.0.1:8080;' + }, + { + value: { member1: { weight: 20 } }, + match: 'member1:80 weight=20;' + }, + { + value: { member1: { max_conns: 20 } }, + match: 'member1:80 max_conns=20;' + }, + { + value: { member1: { max_fails: 20 } }, + match: 'member1:80 max_fails=20;' + }, + { + value: { member1: { fail_timeout: '20s' } }, + match: 'member1:80 fail_timeout=20s;' + }, + { + value: { member1: { backup: true } }, + match: 'member1:80 backup;' + }, + { + value: { member1: { backup: false } }, + match: 'member1:80;' + }, + { + value: { member1: { resolve: true } }, + match: 'member1:80 resolve;' + }, + { + value: { member1: { resolve: false } }, + match: 'member1:80;' + }, + { + value: { member1: { route: 'a' } }, + match: 'member1:80 route=a;', + fails: { stream: 'The parameter "route" is not available for upstreams with context "stream"' } + }, + { + value: { member1: { service: 'member1.backend' } }, + match: 'member1:80 service=member1.backend;' + }, + { + value: { member1: { slow_start: '20s' } }, + match: 'member1:80 slow_start=20s;' + }, + { + value: { member1: { state: 'drain' } }, + match: 'member1:80 drain;', + fails: { stream: 'The state "drain" is not available for upstreams with context "stream"' } + }, + { + value: { member1: { state: 'down' } }, + match: 'member1:80 down;' + }, + { + value: { member1: { params_prepend: 'member=1', weight: 20 } }, + match: 'member1:80 member=1 weight=20;' + }, + { + value: { member1: { params_append: 'member=1', weight: 20 } }, + match: 'member1:80 weight=20 member=1;' + }, + { + value: { member1: { comment: 'member1' } }, + match: 'member1:80; # member1' + } + ].each do |upstream_member_parameter| + context "when members is set to #{upstream_member_parameter[:value]}" do + let(:params) { default_params[upstreamcontext.to_sym].merge(members: upstream_member_parameter[:value]) } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } + + if upstream_member_parameter.key?(:fails) && upstream_member_parameter[:fails].key?(upstreamcontext.to_sym) + it { + is_expected.to raise_error(Puppet::Error, %r{#{upstream_member_parameter[:fails][upstreamcontext.to_sym]}}) + } + next + end + + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + with_mode('0644') + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content("# MANAGED BY PUPPET\nupstream #{title} {\n") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{upstream_member_parameter[:value].keys[0]}"). + with_content(" server #{upstream_member_parameter[:match]}\n") + } + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content("}\n") + } + end end - it { is_expected.to contain_concat("/etc/nginx/conf.d/#{title}-upstream.conf").with_ensure('absent') } + ## + ## check cfg_prepend and cfg_append + ## + [ + { + parameter: 'cfg_prepend', + values: { + 'k2' => 'v2', + 'k5' => { 'k51' => %w[v51 v52] }, + 'k1' => 'v2', + 'k4' => { 'k41' => 'v41' }, + 'k3' => %w[v31 v32] + }, + match: " k2 v2;\n k5 k51 v51;\n k5 k51 v52;\n k1 v2;\n k4 k41 v41;\n k3 v31;\n k3 v32;\n", + fragment: 'header' + }, + { + parameter: 'cfg_append', + values: { + 'k2' => 'v2', + 'k5' => { 'k51' => %w[v51 v52] }, + 'k1' => 'v2', + 'k4' => { 'k41' => 'v41' }, + 'k3' => %w[v31 v32] + }, + match: " k2 v2;\n k5 k51 v51;\n k5 k51 v52;\n k1 v2;\n k4 k41 v41;\n k3 v31;\n k3 v32;\n", + fragment: 'footer' + } + ].each do |upstream_cfg_extension| + context "when #{upstream_cfg_extension[:parameter]} is set to #{upstream_cfg_extension[:values]} in #{upstreamcontext} upstream" do + let(:params) { default_params[upstreamcontext.to_sym].merge(upstream_cfg_extension[:parameter].to_sym => upstream_cfg_extension[:values]) } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } + + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + with_mode('0644') + } + if upstream_cfg_extension[:fragment] == 'header' + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content("# MANAGED BY PUPPET\nupstream #{title} {\n#{upstream_cfg_extension[:match]}") + } + else + it { + is_expected.to contain_concat__fragment("#{title}_upstream_header"). + with_content("# MANAGED BY PUPPET\nupstream #{title} {\n") + } + end + it { + is_expected.to contain_concat__fragment("#{title}_upstream_member_#{params[:members].keys[0]}"). + with_content(" server #{params[:members].keys[0]}:80;\n") + } + if upstream_cfg_extension[:fragment] == 'footer' + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content("#{upstream_cfg_extension[:match]}}\n") + } + else + it { + is_expected.to contain_concat__fragment("#{title}_upstream_footer"). + with_content("}\n") + } + end + end + end + + context 'when ensure => absent' do + let(:params) { default_params[upstreamcontext.to_sym].merge(ensure: 'absent') } + let(:conf_d_path) { conf_d_pathes[upstreamcontext.to_sym] } + + it { + is_expected.to compile.with_all_deps + } + it { + is_expected.to contain_concat("#{conf_d_path}/#{title}-upstream.conf"). + with_ensure('absent') + } + end end end end diff --git a/spec/type_aliases/size.rb b/spec/type_aliases/size.rb new file mode 100644 index 000000000..fc5ed1be4 --- /dev/null +++ b/spec/type_aliases/size.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'Nginx::Size' do + it { is_expected.to allow_value('1024k') } + it { is_expected.to allow_value('1024K') } + it { is_expected.to allow_value('1m') } + it { is_expected.to allow_value('1M') } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value(1) } + it { is_expected.not_to allow_value(1024) } + it { is_expected.not_to allow_value('') } + it { is_expected.not_to allow_value('0.1k') } + it { is_expected.not_to allow_value('0.1K') } + it { is_expected.not_to allow_value('0.1m') } + it { is_expected.not_to allow_value('0.1M') } + it { is_expected.not_to allow_value('1g') } + it { is_expected.not_to allow_value('1G') } +end diff --git a/spec/type_aliases/time.rb b/spec/type_aliases/time.rb new file mode 100644 index 000000000..e768f4f1d --- /dev/null +++ b/spec/type_aliases/time.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'Nginx::Time' do + it { is_expected.to allow_value('10ms') } + it { is_expected.to allow_value('10s') } + it { is_expected.to allow_value('10m') } + it { is_expected.to allow_value('10h') } + it { is_expected.to allow_value('1d') } + it { is_expected.to allow_value('1M') } + it { is_expected.to allow_value('1y') } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value(1) } + it { is_expected.not_to allow_value(10) } + it { is_expected.not_to allow_value('') } + it { is_expected.not_to allow_value('10S') } + it { is_expected.not_to allow_value('10.0s') } + it { is_expected.not_to allow_value('10,0s') } +end diff --git a/spec/type_aliases/upstreamcustomparameters.rb b/spec/type_aliases/upstreamcustomparameters.rb new file mode 100644 index 000000000..9b194b7c0 --- /dev/null +++ b/spec/type_aliases/upstreamcustomparameters.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe 'Nginx::UpstreamCustomParameters' do + it { is_expected.to allow_value('key' => 'value') } + it { is_expected.to allow_value('key' => 20) } + it { is_expected.to allow_value('key' => %w[value1 value2]) } + it { is_expected.to allow_value('key' => %w[20 21]) } + it { is_expected.to allow_value('key' => %w[value1 20]) } + it { is_expected.to allow_value('key' => { 'subkey' => 'value' }) } + it { is_expected.to allow_value('key' => { 'subkey' => 20 }) } + it { is_expected.to allow_value('key' => { 'subkey' => %w[subvalue1 subvalue2] }) } + it { is_expected.to allow_value('key' => { 'subkey' => %w[20 21] }) } + it { is_expected.to allow_value('key' => { 'subkey' => %w[subvalue1 20] }) } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value(20 => 'value') } + it { is_expected.not_to allow_value('key' => '') } + it { is_expected.not_to allow_value('key' => { '' => 'value' }) } + it { is_expected.not_to allow_value('key' => { 20 => 'value' }) } + it { is_expected.not_to allow_value('key' => { 'subkey' => { 'subsubkey' => 'value' } }) } + it { is_expected.not_to allow_value('key' => { 'subkey' => { 'subsubkey' => 20 } }) } + it { is_expected.not_to allow_value('key' => { 'subkey' => { 'subsubkey' => %w[subvalue1 subvalue2] } }) } + it { is_expected.not_to allow_value('key' => { 'subkey' => { 'subsubkey' => %w[20 21] } }) } + it { is_expected.not_to allow_value('key' => { 'subkey' => { 'subsubkey' => %w[subvalue1 20] } }) } +end diff --git a/spec/type_aliases/upstreammemberserver.rb b/spec/type_aliases/upstreammemberserver.rb new file mode 100644 index 000000000..599f2d94f --- /dev/null +++ b/spec/type_aliases/upstreammemberserver.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe 'Nginx::UpstreamMemberServer' do + it { is_expected.to allow_value('10.10.10.10') } + it { is_expected.to allow_value('backend.example.com') } + it { is_expected.to allow_value('unix:/tmp/backend') } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value('') } + it { is_expected.not_to allow_value(1) } + it { is_expected.not_to allow_value('10.10.10.10:80') } + it { is_expected.not_to allow_value('backend.example.com:80') } + it { is_expected.not_to allow_value('unix:/tmp/backend:80') } + it { is_expected.not_to allow_value('linux:/tmp/backend') } +end diff --git a/spec/type_aliases/upstreamstickyzone.rb b/spec/type_aliases/upstreamstickyzone.rb new file mode 100644 index 000000000..e8008d638 --- /dev/null +++ b/spec/type_aliases/upstreamstickyzone.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe 'Nginx::UpstreamStickyZone' do + it { is_expected.to allow_value('live:64k') } + it { is_expected.to allow_value('live:64K') } + it { is_expected.to allow_value('stage:1m') } + it { is_expected.to allow_value('stage:1M') } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value(1) } + it { is_expected.not_to allow_value(1024) } + it { is_expected.not_to allow_value('live') } + it { is_expected.not_to allow_value('stage:') } + it { is_expected.not_to allow_value('live:64') } + it { is_expected.not_to allow_value('live 64') } + it { is_expected.not_to allow_value('stage:64.0') } + it { is_expected.not_to allow_value('stage 64.0') } + it { is_expected.not_to allow_value('live:1g') } + it { is_expected.not_to allow_value('live 1g') } + it { is_expected.not_to allow_value('stage:1G') } + it { is_expected.not_to allow_value('stage 1G') } + it { is_expected.not_to allow_value('live:1.0G') } + it { is_expected.not_to allow_value('live 1.0G') } + it { is_expected.not_to allow_value('stage:1.0M') } + it { is_expected.not_to allow_value('stage 1.0M') } + it { is_expected.not_to allow_value('live 1024k') } + it { is_expected.not_to allow_value('stage 1M') } +end diff --git a/spec/type_aliases/upstreamzone.rb b/spec/type_aliases/upstreamzone.rb new file mode 100644 index 000000000..0d3201d5c --- /dev/null +++ b/spec/type_aliases/upstreamzone.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'Nginx::UpstreamZone' do + it { is_expected.to compile.with_all_deps } + it { is_expected.to allow_value('live 64k') } + it { is_expected.to allow_value('live 64K') } + it { is_expected.to allow_value('stage 1m') } + it { is_expected.to allow_value('stage 1M') } + + it { is_expected.not_to allow_value(:undef) } + it { is_expected.not_to allow_value(1) } + it { is_expected.not_to allow_value(1024) } + it { is_expected.not_to allow_value('live') } + it { is_expected.not_to allow_value('stage:') } + it { is_expected.not_to allow_value('live:64') } + it { is_expected.not_to allow_value('live 64') } + it { is_expected.not_to allow_value('stage:64.0') } + it { is_expected.not_to allow_value('stage 64.0') } + it { is_expected.not_to allow_value('live:1g') } + it { is_expected.not_to allow_value('live 1g') } + it { is_expected.not_to allow_value('stage:1G') } + it { is_expected.not_to allow_value('stage 1G') } + it { is_expected.not_to allow_value('live:1.0G') } + it { is_expected.not_to allow_value('live 1.0G') } + it { is_expected.not_to allow_value('stage:1.0M') } + it { is_expected.not_to allow_value('stage 1.0M') } + it { is_expected.not_to allow_value('live:1024k') } + it { is_expected.not_to allow_value('stage:1M') } +end diff --git a/templates/upstream/upstream_footer.epp b/templates/upstream/upstream_footer.epp new file mode 100644 index 000000000..9c09dd4e5 --- /dev/null +++ b/templates/upstream/upstream_footer.epp @@ -0,0 +1,85 @@ +<%- | Hash $cfg_append = {}, + Optional[String[1]] $hash = undef, + Boolean $ip_hash = false, + Optional[Integer[1]] $keepalive = undef, + Optional[Integer[1]] $keepalive_requests = undef, + Optional[Nginx::Time] $keepalive_timeout = undef, + Boolean $least_conn = false, + Optional[Nginx::UpstreamLeastTime] $least_time = undef, + Boolean $ntlm = false, + Optional[Integer] $queue_max = undef, + Optional[Nginx::Time] $queue_timeout = undef, + Optional[String[1]] $random = undef, + Optional[Stdlib::Unixpath] $statefile = undef, + Optional[Nginx::UpstreamSticky] $sticky = undef, + Optional[Nginx::UpstreamZone] $zone = undef, +| -%> +<% if $hash { -%> + hash <%= $hash %>; +<% } -%> +<% if $ip_hash { -%> + ip_hash; +<% } -%> +<% if $least_conn { -%> + least_conn; +<% } -%> +<% if $least_time { -%> + least_time <%= $least_time %>; +<% } -%> +<% if $ntlm { -%> + ntlm; +<% } -%> +<% if $random { -%> + random <%= $random %>; +<% } -%> +<% if $statefile { -%> + state <%= $statefile %>; +<% } -%> +<% if $sticky { -%> + <%- $sticky.each |$type,$values| { -%> + <%- if $type != 'route' { -%> + sticky <%= $type %><% $values.each |$key,$value| { %> <%= $key %><% if $value != true { %>=<%= $value %><% } %><% } %>; + <%- } else { -%> + sticky <%= $type %> <%= $values %>; + <%- } -%> + <%- } -%> +<% } -%> +<% if $zone { -%> + zone <%= $zone %>; +<% } -%> +<% if $keepalive { -%> + keepalive <%= $keepalive %>; +<% } -%> +<% if $keepalive_requests { -%> + keepalive_requests <%= $keepalive_requests %>; +<% } -%> +<% if $keepalive_timeout { -%> + keepalive_timeout <%= $keepalive_timeout %>; +<% } -%> +<% if $queue_max { -%> + queue <%= $queue_max %><% if $queue_timeout { %> timeout=<%= $queue_timeout %><% } %>; +<% } -%> +<% if $cfg_append { -%> + <%- $cfg_append.each |$key,$value| { -%> + <%- if $value =~ Hash { -%> + <%- $value.each |$subkey,$subvalue| { -%> + <%- if $subvalue =~ Array { -%> + <%- Array($subvalue).each |$asubvalue| { -%> + <%= $key %> <%= $subkey %> <%= $asubvalue %>; + <%- } -%> + <%- } else { -%> + <%= $key %> <%= $subkey %> <%= $subvalue %>; + <%- } -%> + <%- } -%> + <%- } else { -%> + <%- if $value =~ Array { -%> + <%- $value.each |$asubvalue| { -%> + <%= $key %> <%= $asubvalue %>; + <%- } -%> + <%- } else { -%> + <%= $key %> <%= $value %>; + <%- } -%> + <%- } -%> + <%- } -%> +<% } -%> +} diff --git a/templates/upstream/upstream_footer.erb b/templates/upstream/upstream_footer.erb deleted file mode 100644 index 33b0bcd30..000000000 --- a/templates/upstream/upstream_footer.erb +++ /dev/null @@ -1,21 +0,0 @@ -<% if @upstream_cfg_append %> -<%# Slightly less obtuse way to sort but put keepalive at end -%> -<% - @upstream_cfg_append = Hash[@upstream_cfg_append.sort] - @upstream_cfg_append['keepalive'] = @upstream_cfg_append.delete('keepalive') --%> - <%- @upstream_cfg_append.each do |key,value| -%> - <%- if value.is_a?(Hash) -%> - <%- value.each do |subkey,subvalue| -%> - <%- Array(subvalue).each do |asubvalue| -%> - <%= key %> <%= subkey %> <%= asubvalue %>; - <%- end -%> - <%- end -%> - <%- else -%> - <%- Array(value).each do |asubvalue| -%> - <%= key %> <%= asubvalue %>; - <%- end -%> - <%- end -%> - <%- end -%> -<% end -%> -} diff --git a/templates/upstream/upstream_header.epp b/templates/upstream/upstream_header.epp new file mode 100644 index 000000000..133baf3a8 --- /dev/null +++ b/templates/upstream/upstream_header.epp @@ -0,0 +1,28 @@ +<%- | Hash $cfg_prepend = {}, + String[1] $name, +| -%> +# MANAGED BY PUPPET +upstream <%= $name %> { +<% if $cfg_prepend { -%> + <%- $cfg_prepend.each |$key,$value| { -%> + <%- if $value =~ Hash { -%> + <%- $value.each |$subkey,$subvalue| { -%> + <%- if $subvalue =~ Array { -%> + <%- Array($subvalue).each |$asubvalue| { -%> + <%= $key %> <%= $subkey %> <%= $asubvalue %>; + <%- } -%> + <%- } else { -%> + <%= $key %> <%= $subkey %> <%= $subvalue %>; + <%- } -%> + <%- } -%> + <%- } else { -%> + <%- if $value =~ Array { -%> + <%- $value.each |$asubvalue| { -%> + <%= $key %> <%= $asubvalue %>; + <%- } -%> + <%- } else { -%> + <%= $key %> <%= $value %>; + <%- } -%> + <%- } -%> + <%- } -%> +<% } -%> diff --git a/templates/upstream/upstream_header.erb b/templates/upstream/upstream_header.erb deleted file mode 100644 index 7aed428d2..000000000 --- a/templates/upstream/upstream_header.erb +++ /dev/null @@ -1,22 +0,0 @@ -# MANAGED BY PUPPET -upstream <%= @name %> { -<% if @upstream_cfg_prepend -%> -<%# Slightly less obtuse way to sort but put keepalive at end -%> -<% - @upstream_cfg_prepend = Hash[@upstream_cfg_prepend.sort] - @upstream_cfg_prepend['keepalive'] = @upstream_cfg_prepend.delete('keepalive') --%> - <%- @upstream_cfg_prepend.each do |key,value| -%> - <%- if value.is_a?(Hash) -%> - <%- value.each do |subkey,subvalue| -%> - <%- Array(subvalue).each do |asubvalue| -%> - <%= key %> <%= subkey %> <%= asubvalue %>; - <%- end -%> - <%- end -%> - <%- else -%> - <%- Array(value).each do |asubvalue| -%> - <%= key %> <%= asubvalue %>; - <%- end -%> - <%- end -%> - <%- end -%> -<% end -%> diff --git a/templates/upstream/upstream_member.epp b/templates/upstream/upstream_member.epp new file mode 100644 index 000000000..4bfed2db7 --- /dev/null +++ b/templates/upstream/upstream_member.epp @@ -0,0 +1,28 @@ +<%- | $_server, + Boolean $backup = false, + Optional[String[1]] $comment = undef, + Optional[Nginx::Time] $fail_timeout = undef, + Optional[Integer[1]] $max_conns = undef, + Optional[Integer[1]] $max_fails = undef, + Optional[String[1]] $params_append = undef, + Optional[String[1]] $params_prepend = undef, + Boolean $resolve = false, + Optional[String[1]] $route = undef, + Optional[String[1]] $service = undef, + Optional[Nginx::Time] $slow_start = undef, + Optional[Enum['drain','down']] $state = undef, + Optional[Integer[1]] $weight = undef, +| -%> + server <%= $_server -%> +<%- if $params_prepend { %> <%= $params_prepend %><% } -%> +<%- if $state { %> <%= $state %><% } -%> +<%- if $weight { %> weight=<%= $weight %><% } -%> +<%- if $max_conns { %> max_conns=<%= $max_conns %><% } -%> +<%- if $max_fails { %> max_fails=<%= $max_fails %><% } -%> +<%- if $fail_timeout { %> fail_timeout=<%= $fail_timeout %><% } -%> +<%- if $slow_start { %> slow_start=<%= $slow_start %><% } -%> +<%- if $service { %> service=<%= $service %><% } -%> +<%- if $route { %> route=<%= $route %><% } -%> +<%- if $resolve { %> resolve<% } -%> +<%- if $backup { %> backup<% } -%> +<%- if $params_append { %> <%= $params_append %><% } %>;<% if $comment { %> # <%= $comment %><% } %> diff --git a/templates/upstream/upstream_member.erb b/templates/upstream/upstream_member.erb deleted file mode 100644 index 5f44b54ee..000000000 --- a/templates/upstream/upstream_member.erb +++ /dev/null @@ -1 +0,0 @@ - server <%= @server %>:<%= @port %> fail_timeout=<%= @upstream_fail_timeout %><% if @upstream_max_fails -%> max_fails=<%=@upstream_max_fails %><% end %>; diff --git a/templates/upstream/upstream_members.erb b/templates/upstream/upstream_members.erb deleted file mode 100644 index 0f5c30626..000000000 --- a/templates/upstream/upstream_members.erb +++ /dev/null @@ -1,2 +0,0 @@ - <% @members.each do |i| %> - server <%= i %> fail_timeout=<%= @upstream_fail_timeout %><% if @upstream_max_fails -%> max_fails=<%=@upstream_max_fails %><% end %>;<% end %> diff --git a/types/size.pp b/types/size.pp new file mode 100644 index 000000000..580476686 --- /dev/null +++ b/types/size.pp @@ -0,0 +1 @@ +type Nginx::Size = Pattern[/^\d+[k|K|m|M]?$/] diff --git a/types/time.pp b/types/time.pp new file mode 100644 index 000000000..f6c24edc8 --- /dev/null +++ b/types/time.pp @@ -0,0 +1 @@ +type Nginx::Time = Pattern[/^\d+(ms|s|m|h|d|w|M|y)?$/] diff --git a/types/upstreamcustomparameters.pp b/types/upstreamcustomparameters.pp new file mode 100644 index 000000000..2bcd5ec02 --- /dev/null +++ b/types/upstreamcustomparameters.pp @@ -0,0 +1,24 @@ +type Nginx::UpstreamCustomParameters = Hash[String[1], + Variant[ + String[1], + Integer, + Array[ + Variant[ + String[1], + Integer + ] + ], + Hash[String[1], + Variant[ + String[1], + Integer, + Array[ + Variant[ + String[1], + Integer, + ] + ] + ] + ] + ] +] diff --git a/types/upstreamdefaults.pp b/types/upstreamdefaults.pp new file mode 100644 index 000000000..4adf692e7 --- /dev/null +++ b/types/upstreamdefaults.pp @@ -0,0 +1,20 @@ +type Nginx::UpstreamDefaults = Struct[{ + context => Optional[Enum['http', 'stream']], + member_defaults => Optional[Nginx::UpstreamMemberDefaults], + hash => Optional[String], + ip_hash => Optional[Boolean], + keepalive => Optional[Integer[1]], + kepalive_requests => Optional[Integer[1]], + keepalive_timeout => Optional[Nginx::Time], + least_conn => Optional[Boolean], + least_time => Optional[Nginx::UpstreamLeastTime], + ntlm => Optional[Boolean], + queue_max => Optional[Integer], + queue_timeout => Optional[Nginx::Time], + random => Optional[String], + statefile => Optional[Stdlib::Unixpath], + sticky => Optional[Nginx::UpstreamSticky], + zone => Optional[Nginx::UpstreamZone], + cfg_append => Optional[Hash], + cfg_prepend => Optional[Hash], +}] diff --git a/types/upstreamleasttime.pp b/types/upstreamleasttime.pp new file mode 100644 index 000000000..daeab96b8 --- /dev/null +++ b/types/upstreamleasttime.pp @@ -0,0 +1 @@ +type Nginx::UpstreamLeastTime = Variant[Nginx::UpstreamLeastTimeHttp,Nginx::UpstreamLeastTimeStream] diff --git a/types/upstreamleasttimehttp.pp b/types/upstreamleasttimehttp.pp new file mode 100644 index 000000000..5299f4524 --- /dev/null +++ b/types/upstreamleasttimehttp.pp @@ -0,0 +1 @@ +type Nginx::UpstreamLeastTimeHttp = Enum['header','header inflight','last_byte','last_byte inflight'] diff --git a/types/upstreamleasttimestream.pp b/types/upstreamleasttimestream.pp new file mode 100644 index 000000000..35ff9fcfd --- /dev/null +++ b/types/upstreamleasttimestream.pp @@ -0,0 +1 @@ +type Nginx::UpstreamLeastTimeStream = Enum['connect','connect inflight','first_byte','first_byte inflight','last_byte','last_byte inflight'] diff --git a/types/upstreammember.pp b/types/upstreammember.pp new file mode 100644 index 000000000..10dcc42e8 --- /dev/null +++ b/types/upstreammember.pp @@ -0,0 +1,17 @@ +type Nginx::UpstreamMember = Struct[{ + server => Optional[Nginx::UpstreamMemberServer], + port => Optional[Stdlib::Port], + weight => Optional[Integer[1]], + max_conns => Optional[Integer[1]], + max_fails => Optional[Integer[1]], + fail_timeout => Optional[Nginx::Time], + backup => Optional[Boolean], + resolve => Optional[Boolean], + route => Optional[String], + service => Optional[String], + slow_start => Optional[Nginx::Time], + state => Optional[Enum['drain','down']], + params_prepend => Optional[String], + params_append => Optional[String], + comment => Optional[String], +}] diff --git a/types/upstreammemberdefaults.pp b/types/upstreammemberdefaults.pp new file mode 100644 index 000000000..0bb1ce7c1 --- /dev/null +++ b/types/upstreammemberdefaults.pp @@ -0,0 +1,15 @@ +type Nginx::UpstreamMemberDefaults = Struct[{ + port => Optional[Stdlib::Port], + weight => Optional[Integer[1]], + max_conns => Optional[Integer[1]], + max_fails => Optional[Integer[1]], + fail_timeout => Optional[Nginx::Time], + backup => Optional[Boolean], + resolve => Optional[Boolean], + route => Optional[String], + service => Optional[String], + slow_start => Optional[Nginx::Time], + state => Optional[Enum['drain','down']], + params_prepend => Optional[String], + params_append => Optional[String], +}] diff --git a/types/upstreammembers.pp b/types/upstreammembers.pp new file mode 100644 index 000000000..ee6e1448b --- /dev/null +++ b/types/upstreammembers.pp @@ -0,0 +1 @@ +type Nginx::UpstreamMembers = Hash[String,Nginx::UpstreamMember] diff --git a/types/upstreammemberserver.pp b/types/upstreammemberserver.pp new file mode 100644 index 000000000..b5415f17b --- /dev/null +++ b/types/upstreammemberserver.pp @@ -0,0 +1 @@ +type Nginx::UpstreamMemberServer = Variant[Stdlib::Host,Pattern[/^unix:\/([^\/\0]+\/*)[^:]*$/]] diff --git a/types/upstreamsticky.pp b/types/upstreamsticky.pp new file mode 100644 index 000000000..f6a7c5c03 --- /dev/null +++ b/types/upstreamsticky.pp @@ -0,0 +1,28 @@ +type Nginx::UpstreamSticky = Variant[ + Hash[ + Enum['cookie'], + Struct[{ + name => String, + expires => Optional[Variant[Nginx::Time,Enum['max']]], + domain => Optional[String], + httponly => Optional[Boolean], + secure => Optional[Boolean], + path => Optional[String], + }] + ], + Hash[ + Enum['route'], + String + ], + Hash[ + Enum['learn'], + Struct[{ + create => String, + lookup => String, + zone => Nginx::UpstreamStickyZone, + timeout => Optional[Nginx::Time], + header => Optional[Boolean], + sync => Optional[Boolean], + }] + ] +] diff --git a/types/upstreamstickyzone.pp b/types/upstreamstickyzone.pp new file mode 100644 index 000000000..635ccba5f --- /dev/null +++ b/types/upstreamstickyzone.pp @@ -0,0 +1 @@ +type Nginx::UpstreamStickyZone = Pattern[/^[-_\.A-Za-z0-9]*:\d+[k|K|m|M]$/] diff --git a/types/upstreamzone.pp b/types/upstreamzone.pp new file mode 100644 index 000000000..b1cbe57ba --- /dev/null +++ b/types/upstreamzone.pp @@ -0,0 +1 @@ +type Nginx::UpstreamZone = Pattern[/^[-_\.A-Za-z0-9]* \d+[k|K|m|M]$/]