Commit fe45718f authored by Mihai Petracovici's avatar Mihai Petracovici
Browse files

Add Support for Custom Remote Server Configuration

    * New Attribute: node['rsyslog']['custom_remote']
        * Array of Hashes for custom config
    * Update README for new attribute
    * Added test cases for new feature
    * Rubocop fixes
parent 6fa1bbee
......@@ -50,6 +50,16 @@ suites:
attributes:
rsyslog:
server_ip: 10.0.0.50
custom_remote:
- server: 10.0.0.45
logs: auth.*,mail.*
port: 555
protocol: udp
- server: 10.1.1.33
logs: authpriv.*,cron.*,daemon.*
port: 654
protocol: tcp
remote_template: RSYSLOG_SyslogProtocol23Format
- name: server
run_list:
- recipe[rsyslog_test::server]
......
......@@ -31,7 +31,7 @@ See `attributes/default.rb` for default values.
* `node['rsyslog']['protocol']` - Specify whether to use `udp` or `tcp` for remote loghost. Default is `tcp`. To use both specify both in a string e.g. 'udptcp'.
* `node['rsyslog']['bind']` - Specify the address to which the server should be listening; only use with `node['rsyslog']['protocol'] = 'udp'` because the feature does not work with the `tcp` protocol ([more info](http://www.rsyslog.com/doc/master/configuration/modules/imtcp.html#caveats-known-bugs)).
* `node['rsyslog']['port']` - Specify the port which rsyslog should connect to a remote loghost.
* `node['rsyslog']['remote_logs']` - Specify wether to send all logs to a remote server (client option). Default is `true`.
* `node['rsyslog']['remote_logs']` - Specify whether to send all logs to a remote server (client option). Default is `true`.
* `node['rsyslog']['per_host_dir']` - "PerHost" directories for template statements in `35-server-per-host.conf`. Default value is the previous cookbook version's value, to preserve compatibility. See __server__ recipe below.
* `node['rsyslog']['priv_seperation']` - Whether to use privilege separation or not.
* `node['rsyslog']['priv_user']` - User to run as when using privilege separation. Defult is `node['rsyslog']['user']`
......@@ -48,6 +48,7 @@ See `attributes/default.rb` for default values.
* `node['rsyslog']['default_log_dir']` - log directory used in `50-default.conf` template, defaults to `/var/log`
* `node['rsyslog']['default_facility_logs']` - Hash containing log facilities and destinations used in `50-default.conf` template.
* `node['rsyslog']['default_file_template']` - The name of a pre-defined log format template (ie - RSYSLOG_FileFormat), used for local log files.
* `node['rsyslog']['default_remote_template']` - The name of a pre-defined log format template (ie - RSYSLOG_FileFormat), used for sending to remote servers.
* `node['rsyslog']['rate_limit_interval']` - Value of the $SystemLogRateLimitInterval configuration directive in `/etc/rsyslog.conf`. Default is nil, leaving it to the platform default.
* `node['rsyslog']['rate_limit_burst']` - Value of the $SystemLogRateLimitBurst configuration directive in `/etc/rsyslog.conf`. Default is nil, leaving it to the platform default.
* `node['rsyslog']['action_queue_max_disk_space']` - Max amount of disk space the disk-assisted queue is allowed to use ([more info](http://www.rsyslog.com/doc/queues.html)).
......@@ -58,6 +59,7 @@ See `attributes/default.rb` for default values.
* `node['rsyslog']['tls_auth_mode']` - Value for `$InputTCPServerStreamDriverAuthMode`/`$ActionSendStreamDriverAuthMode`, determines whether client certs are validated. Defaults to `anon` (no validation).
* `node['rsyslog']['use_local_ipv4']` - Whether or not to make use the remote local IPv4 address on cloud systems when searching for servers (where available). Default is 'false'.
* `node['rsyslog']['allow_non_local']` - Whether or not to allow non-local messages. If 'false', incoming messages are only allowed from 127.0.0.1. Default is 'false'.
* `node['rsyslog']['custom_remote']` - Array of hashes for configuring custom remote server targets
* `node['rsyslog']['additional_directives']` - Hash of additional directives and their values to place in the main rsyslog config file
Recipes
......@@ -70,6 +72,26 @@ Includes `recipe[rsyslog]`.
Uses `node['rsyslog']['server_ip']` or Chef search (in that precedence order) to determine the remote syslog server's IP address. If search is used, the search query will look for the first `ipaddress` returned from the criteria specified in `node['rsyslog']['server_search']`.
You can use `node['rsyslog']['custom_config']` to define custom entries for sending logs to remote servers.
Available attributes:
```
'server': Ip/hostname of remote syslog server (Required)
'port': Port to send logs to
'logs': Syslog log facilities to send (auth, authpriv, daemon, etc)
'protocol': Can be tcp or udp
'remote_template': Rsyslog template used for the messages
```
Example:
```ruby
node['rsyslog']['custom_remote'] = [{ 'server' => '10.10.4.4', 'port' => '567', 'logs' => 'auth.*,mail.*', 'protocol' => 'udp', 'remote_template' => 'RSYSLOG_SyslogProtocol23Format'},
{ 'server' => '10.0.0.3', 'port' => '555', 'logs' => 'authpriv,daemon.*' } ]
```
The server key is required; if other keys are left out, the default global values will be used (eg `node['rsyslog']['port']` will be used if 'port' is omitted)
If the node itself is a rsyslog server ie it has `rsyslog.server` set to true then the configuration is skipped.
If the node had an `/etc/rsyslog.d/35-server-per-host.conf` file previously configured, this file gets removed to prevent duplicate logging.
......
......@@ -49,6 +49,7 @@ default['rsyslog']['tls_key_file'] = nil
default['rsyslog']['tls_auth_mode'] = 'anon'
default['rsyslog']['use_local_ipv4'] = false
default['rsyslog']['allow_non_local'] = false
default['rsyslog']['custom_remote'] = [{}]
default['rsyslog']['additional_directives'] = {}
# The most likely platform-specific attributes
......
module RsyslogCookbook
# helpers for the various service providers on Ubuntu systems
module Helpers
def declare_rsyslog_service
if 'ubuntu' == node['platform']
if Chef::VersionConstraint.new('>= 15.04').include?(node['platform_version'])
service_provider = Chef::Provider::Service::Systemd
elsif Chef::VersionConstraint.new('>= 12.04').include?(node['platform_version'])
service_provider = Chef::Provider::Service::Upstart
else
service_provider = nil
end
end
service 'rsyslog' do
service_name node['rsyslog']['service_name']
supports :restart => true, :status => true
action [:enable, :start]
provider service_provider
end
end
end
module RsyslogCookbook
# helpers for the various service providers on Ubuntu systems
module Helpers
def declare_rsyslog_service
if 'ubuntu' == node['platform']
if Chef::VersionConstraint.new('>= 15.04').include?(node['platform_version'])
service_provider = Chef::Provider::Service::Systemd
elsif Chef::VersionConstraint.new('>= 12.04').include?(node['platform_version'])
service_provider = Chef::Provider::Service::Upstart
else
service_provider = nil
end
end
service 'rsyslog' do
service_name node['rsyslog']['service_name']
supports :restart => true, :status => true
action [:enable, :start]
provider service_provider
end
end
end
end
......@@ -33,7 +33,7 @@ end
# normal Chef, we leverage the search query.
if Chef::Config[:solo] && !chef_solo_search_installed?
if node['rsyslog']['server_ip']
rsyslog_servers = Array(node['rsyslog']['server_ip'])
server_ips = Array(node['rsyslog']['server_ip'])
else
Chef::Application.fatal!("Chef Solo does not support search. You must set node['rsyslog']['server_ip'] or use the chef-solo-search cookbook!")
end
......@@ -47,7 +47,22 @@ else
end
ipaddress
end
rsyslog_servers = Array(node['rsyslog']['server_ip']) + Array(results)
server_ips = Array(node['rsyslog']['server_ip']) + Array(results)
end
rsyslog_servers = []
server_ips.each do |ip|
rsyslog_servers << { 'server' => ip, 'port' => node['rsyslog']['port'], 'logs' => node['rsyslog']['logs_to_forward'], 'protocol' => node['rsyslog']['protocol'], 'remote_template' => node['rsyslog']['default_remote_template'] }
end
unless node['rsyslog']['custom_remote'].first.empty?
node['rsyslog']['custom_remote'].each do |server|
if server['server'].nil?
Chef::Application.fatal!('Found a custom_remote server with no IP. Check your custom_remote attribute definition!')
end
end
rsyslog_servers += node['rsyslog']['custom_remote']
end
if rsyslog_servers.empty?
......
......@@ -15,10 +15,12 @@ describe 'rsyslog::client' do
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '12.04') do |node|
node.set['rsyslog']['server_ip'] = server_ip
node.set['rsyslog']['custom_remote'] = custom_remote
end.converge(described_recipe)
end
let(:server_ip) { "10.#{rand(1..9)}.#{rand(1..9)}.50" }
let(:custom_remote) { [{ 'server' => '10.0.0.1', 'port' => 555, 'protocol' => 'tcp', 'logs' => 'auth.*,mail.*', 'remote_template' => 'RSYSLOG_SyslogProtocol23Format' }] }
let(:service_resource) { 'service[rsyslog]' }
it 'includes the default recipe' do
......@@ -29,7 +31,10 @@ describe 'rsyslog::client' do
let(:template) { chef_run.template('/etc/rsyslog.d/49-remote.conf') }
it 'creates the template' do
expect(chef_run).to render_file(template.path).with_content("*.* @@#{server_ip}:514")
expect(chef_run).to render_file(template.path).with_content { |content|
expect(content).to include("*.* @@#{server_ip}:514")
expect(content).to include("#{custom_remote.first['logs']} @@#{custom_remote.first['server']}:#{custom_remote.first['port']};#{custom_remote.first['remote_template']}")
}
end
it 'is owned by root:root' do
......@@ -49,13 +54,17 @@ describe 'rsyslog::client' do
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'smartos', version: 'joyent_20130111T180733Z') do |node|
node.set['rsyslog']['server_ip'] = server_ip
node.set['rsyslog']['custom_remote'] = custom_remote
end.converge(described_recipe)
end
let(:template) { chef_run.template('/opt/local/etc/rsyslog.d/49-remote.conf') }
it 'creates the template' do
expect(chef_run).to render_file(template.path).with_content("*.* @@#{server_ip}:514")
expect(chef_run).to render_file(template.path).with_content { |content|
expect(content).to include("*.* @@#{server_ip}:514")
expect(content).to include("#{custom_remote.first['logs']} @@#{custom_remote.first['server']}:#{custom_remote.first['port']};#{custom_remote.first['remote_template']}")
}
end
it 'is owned by root:root' do
......
......@@ -129,7 +129,7 @@ describe 'rsyslog::default' do
let(:modules) { %w(imuxsock imklog) }
it 'creates the template' do
expect(chef_run).to render_file(template.path).with_content('rsyslog configuration file - Generated by Chef')
expect(chef_run).to render_file(template.path).with_content('Config generated by Chef - manual edits will be overwritten')
end
it 'is owned by root:root' do
......@@ -160,7 +160,7 @@ describe 'rsyslog::default' do
let(:modules) { %w(immark imsolaris imtcp imudp) }
it 'creates the template' do
expect(chef_run).to render_file(template.path).with_content('rsyslog configuration file - Generated by Chef')
expect(chef_run).to render_file(template.path).with_content('Config generated by Chef - manual edits will be overwritten')
end
it 'is owned by root:root' do
......@@ -188,7 +188,7 @@ describe 'rsyslog::default' do
let(:template) { chef_run.template('/etc/rsyslog.d/50-default.conf') }
it 'creates the template' do
expect(chef_run).to render_file(template.path).with_content('*.emerg *')
expect(chef_run).to render_file(template.path).with_content('*.emerg :omusrmsg:*')
end
it 'is owned by root:root' do
......
......@@ -25,8 +25,8 @@ describe 'rsyslog::server' do
end
it 'is owned by root:root' do
expect(directory.owner).to eq('root')
expect(directory.group).to eq('root')
expect(directory.owner).to eq('syslog')
expect(directory.group).to eq('adm')
end
it 'has 0755 permissions' do
......
......@@ -19,10 +19,12 @@ $ActionSendStreamDriverAuthMode <%= node['rsyslog']['tls_auth_mode'] %>
<% end -%>
<% @servers.each do |server| -%>
<% case node['rsyslog']['protocol'] -%>
<% when "tcp" -%>
<%= node['rsyslog']['logs_to_forward'] %> @@<%= server %>:<%= node['rsyslog']['port'] %><%= node["rsyslog"]["default_remote_template"] ? ';' + node["rsyslog"]["default_remote_template"] : nil %>
<% when "udp" -%>
<%= node['rsyslog']['logs_to_forward'] %> @<%= server %>:<%= node['rsyslog']['port'] %><%= node["rsyslog"]["default_remote_template"] ? ';' + node["rsyslog"]["default_remote_template"] : nil %>
<% case server['protocol'] -%>
<% when "tcp" -%>
<%= server['logs'] ? server['logs'] : node['rsyslog']['logs_to_forward'] %> @@<%= server['server'] %>:<%= server['port'] ? server['port'] : node['rsyslog']['port'] %><%= server['remote_template'] ? ';' + server['remote_template'] : nil %>
<% when "udp" -%>
<%= server['logs'] ? server['logs'] : node['rsyslog']['logs_to_forward'] %> @<%= server['server'] %>:<%= server['port'] ? server['port'] : node['rsyslog']['port'] %><%= server['remote_template'] ? ';' + server['remote_template'] : nil %>
<% else -%>
<%= server['logs'] ? server['logs'] : node['rsyslog']['logs_to_forward'] %><%= node['rsyslog']['protocol'] == "tcp" ? " @@" : " @" %><%= server['server'] %>:<%= server['port'] ? server['port'] : node['rsyslog']['port'] %><%= server['remote_template'] ? ';' + server['remote_template'] : nil %>
<% end -%>
<% end -%>
require 'fileutils'
unless Dir.exists?("#{node['rsyslog']['config_prefix']}/rsyslog.d")
FileUtils.mkdir("#{node['rsyslog']['config_prefix']}/rsyslog.d")
end
FileUtils.touch("#{node['rsyslog']['config_prefix']}/rsyslog.d/server.conf")
include_recipe 'rsyslog::client'
......@@ -3,5 +3,9 @@
}
@test "the config points to the remote server" {
grep "@10.0.0.50:514" /etc/rsyslog.d/49-remote.conf
grep "@@10.0.0.50:514" /etc/rsyslog.d/49-remote.conf
}
@test "Custom config is generated" {
egrep 'auth\.\*,mail\.\* @10.0.0.45:555' /etc/rsyslog.d/49-remote.conf && egrep 'authpriv\.\*,cron\.\*,daemon\.\* @@10.1.1.33:654' /etc/rsyslog.d/49-remote.conf
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment