Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make configurable. Add some tests.

  • Loading branch information...
commit efd6cd6ec66092898c54b08c835cc5845e98daf7 1 parent 0c5bb94
@chrisroberts chrisroberts authored
View
6 .gitignore
@@ -0,0 +1,6 @@
+.*
+!.gitignore
+.bundle
+.cache
+.kitchen
+bin
View
3  Gemfile
@@ -0,0 +1,3 @@
+source :rubygems
+
+gem 'test-kitchen'
View
115 Gemfile.lock
@@ -0,0 +1,115 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ archive-tar-minitar (0.5.2)
+ bunny (0.7.9)
+ chef (10.14.2)
+ bunny (>= 0.6.0, < 0.8.0)
+ erubis
+ highline (>= 1.6.9)
+ json (>= 1.4.4, <= 1.6.1)
+ mixlib-authentication (>= 1.3.0)
+ mixlib-cli (>= 1.1.0)
+ mixlib-config (>= 1.1.2)
+ mixlib-log (>= 1.3.0)
+ mixlib-shellout
+ moneta
+ net-ssh (~> 2.2.2)
+ net-ssh-multi (~> 1.1.0)
+ ohai (>= 0.6.0)
+ rest-client (>= 1.0.4, < 1.7.0)
+ treetop (~> 1.4.9)
+ uuidtools
+ yajl-ruby (~> 1.1)
+ childprocess (0.3.5)
+ ffi (~> 1.0, >= 1.0.6)
+ coderay (1.0.7)
+ erubis (2.7.0)
+ ffi (1.1.5)
+ foodcritic (1.6.1)
+ erubis
+ gherkin (~> 2.11.1)
+ gist (~> 3.1.0)
+ nokogiri (= 1.5.0)
+ pry (~> 0.9.8.4)
+ rak (~> 1.4)
+ treetop (~> 1.4.10)
+ yajl-ruby (~> 1.1.0)
+ gherkin (2.11.2)
+ json (>= 1.4.6)
+ gist (3.1.0)
+ hashr (0.0.22)
+ highline (1.6.15)
+ i18n (0.6.1)
+ ipaddress (0.8.0)
+ json (1.5.4)
+ librarian (0.0.24)
+ archive-tar-minitar (>= 0.5.2)
+ chef (>= 0.10)
+ highline
+ thor (~> 0.15)
+ log4r (1.1.10)
+ method_source (0.7.1)
+ mime-types (1.19)
+ mixlib-authentication (1.3.0)
+ mixlib-log
+ mixlib-cli (1.2.2)
+ mixlib-config (1.1.2)
+ mixlib-log (1.4.1)
+ mixlib-shellout (1.1.0)
+ moneta (0.6.0)
+ net-scp (1.0.4)
+ net-ssh (>= 1.99.1)
+ net-ssh (2.2.2)
+ net-ssh-gateway (1.1.0)
+ net-ssh (>= 1.99.1)
+ net-ssh-multi (1.1)
+ net-ssh (>= 2.1.4)
+ net-ssh-gateway (>= 0.99.0)
+ nokogiri (1.5.0)
+ ohai (6.14.0)
+ ipaddress
+ mixlib-cli
+ mixlib-config
+ mixlib-log
+ systemu
+ yajl-ruby
+ polyglot (0.3.3)
+ pry (0.9.8.4)
+ coderay (~> 1.0.5)
+ method_source (~> 0.7.1)
+ slop (>= 2.4.4, < 3)
+ rak (1.4)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ slop (2.4.4)
+ systemu (2.5.2)
+ test-kitchen (0.5.5)
+ foodcritic (~> 1.4)
+ hashr (~> 0.0.20)
+ highline (>= 1.6.9)
+ librarian (~> 0.0.20)
+ mixlib-cli (~> 1.2.2)
+ vagrant (~> 1.0.2)
+ yajl-ruby (~> 1.1.0)
+ thor (0.16.0)
+ treetop (1.4.10)
+ polyglot
+ polyglot (>= 0.3.1)
+ uuidtools (2.1.3)
+ vagrant (1.0.4)
+ archive-tar-minitar (= 0.5.2)
+ childprocess (~> 0.3.1)
+ erubis (~> 2.7.0)
+ i18n (~> 0.6.0)
+ json (~> 1.5.1)
+ log4r (~> 1.1.9)
+ net-scp (~> 1.0.4)
+ net-ssh (~> 2.2.2)
+ yajl-ruby (1.1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ test-kitchen
View
138 README.md
@@ -1,13 +1,145 @@
Description
===========
-Installs keepalived and pushes the configuration file out.
+Installs keepalived and generates the configuration file.
Usage
=====
-Modify the sample template to suit your environment and configuration
-requirements.
+### Configuration settings
+
+* `node[:keepalived][:shared_address] = true` # If keepalived is using a shared address
+
+### Global settings
+
+* `node[:keepalived][:global][:notification_emails] = 'admin@example.com'` # notification emails
+* `node[:keepalived][:global][:notification_email_from] = "keepalived@#{node.domain}" # from address
+* `node[:keepalived][:global][:smtp_server] = '127.0.0.1'` # smtp server address
+* `node[:keepalived][:global][:smtp_connect_timeout] = 30` # smtp connection timeout
+* `node[:keepalived][:global][:router_id] = 'DEFAULT_ROUT_ID'` # router ID
+* `node[:keepalived][:global][:router_ids] = {}` # mapped router ID (see example below)
+
+The `router_ids` allow for defining different IDs based on node name within a
+single role. This allows for a role structured like so:
+
+```ruby
+override_attributes(
+ :keepalived => {
+ :global => {
+ :router_ids => {
+ 'node1' => 'MASTER_NODE',
+ 'node2' => 'BACKUP_NODE'
+ }
+ }
+ }
+)
+```
+### Check Scripts
+
+* `node[:keepalived][:check_scripts] = {}` # define available check scripts
+
+Multiple check scripts can be defined. The key will provide the name of the
+check script within the configuration file. The value should be a hash with
+the keys: `script`, `interval` and `weight` defined. For example, a simple
+HAProxy check script:
+
+```ruby
+node[:keepalived][:check_scripts][:chk_haproxy] = {
+ :script => 'killall -0 haproxy',
+ :interval => 2,
+ :weight => 2
+}
+```
+
+### Instance defaults
+
+These are fallback values instance blocks can default to if non have been
+explicitly defined:
+
+* `node[:keepalived][:instance_defaults][:state] = 'MASTER'` # default state
+* `node[:keepalived][:instance_defaults][:priority] = 100` # default priority
+* `node[:keepalived][:instance_defaults][:virtual_router_id] = 'DEFAULT_VIRT_ROUT_ID'` # default virtual router ID
+
+## Instances
+
+* `node[:keepalived][:instances] = {}`
+
+Multiple instances can be defined. The key will be used to define the instance
+name. The value will be a hash used to describe the instance. Attributes used
+within the instance hash:
+
+* `:ip_addresses => '127.0.0.1'` # IP address(es) used by this instance
+* `:interface => 'eth0'` # Network interface used
+* `:states => {}` # Node name mapped states
+* `:virtual_router_ids => {}` # Node name mapped virtual router IDs
+* `:priorities => {}` # Node name mapped priorities
+* `:track_script => 'check_name'` # Name of check script in use for instance
+* `:nopreempt => false` # Do not preempt
+* `:advert_int => 1` # Set advert_int
+* `:authentication_type => nil` # Enable authentication (:pass or :ah)
+* `:authentication_pass => 'secret'`# Password used for authentication
+
+### Full role based example
+
+```ruby
+override_attributes(
+ :keepalived => {
+ :shared_address => true,
+ :check_scripts => {
+ :chk_haproxy => {
+ :script => 'killall -0 haproxy',
+ :interval => 2,
+ :weight => 2
+ }
+ },
+ :instances => {
+ :vi_1 => {
+ :ip_addresses => '192.168.0.2',
+ :interface => 'eth0',
+ :state => 'MASTER',
+ :states => {
+ 'master.domain' => :master,
+ 'backup.domain' => :backup
+ },
+ :virtual_router_ids => {
+ 'master.domain' => 'SERVICE_MASTER',
+ 'backup.domain' => 'SERVICE_BACKUP'
+ },
+ :priorities => {
+ 'master.domain' => 101,
+ 'backup.domain' => 100
+ },
+ :track_script => 'chk_haproxy',
+ :nopreempt => false,
+ :advert_int => 1,
+ :authentication_type => :pass,
+ :authentication_pass => 'secret'
+ }
+ }
+ }
+)
+```
+
+### Recipe based example:
+
+```ruby
+include_recipe 'keepalived'
+
+node[:keepalived][:check_scripts][:chk_init] = {
+ :script => 'killall -0 init',
+ :interval => 2,
+ :weight => 2
+}
+node[:keepalived][:instances][:vi_1] = {
+ :ip_addresses => '10.0.2.254',
+ :interface => 'eth0',
+ :track_script => 'chk_init',
+ :nopreempt => false,
+ :advert_int => 1,
+ :authentication_type => nil, # :pass or :ah
+ :authentication_pass => 'secret'
+}
+```
License and Author
==================
View
12 attributes/default.rb
@@ -0,0 +1,12 @@
+default[:keepalived][:shared_address] = false
+default[:keepalived][:global][:notification_emails] = 'admin@example.com'
+default[:keepalived][:global][:notification_email_from] = "keepalived@#{node.domain || 'example.com'}"
+default[:keepalived][:global][:smtp_server] = '127.0.0.1'
+default[:keepalived][:global][:smtp_connect_timeout] = 30
+default[:keepalived][:global][:router_id] = 'DEFAULT_ROUT_ID'
+default[:keepalived][:global][:router_ids] = {} # node name based mapping
+default[:keepalived][:check_scripts] = {}
+default[:keepalived][:instance_defaults][:state] = 'MASTER'
+default[:keepalived][:instance_defaults][:priority] = 100
+default[:keepalived][:instance_defaults][:virtual_router_id] = 10
+default[:keepalived][:instances] = {}
View
19 recipes/default.rb
@@ -21,9 +21,15 @@
action :install
end
-service "keepalived" do
- supports :restart => true
- action [:enable, :start]
+if(node[:keepalived][:shared_address])
+ file '/etc/sysctl.d/60-ip-nonlocal-bind.conf' do
+ mode 0644
+ content "net.ipv4.ip_nonlocal_bind=1\n"
+ end
+
+ service 'procps' do
+ action :start
+ end
end
template "/etc/keepalived/keepalived.conf" do
@@ -31,5 +37,10 @@
owner "root"
group "root"
mode 0644
- notifies :restart, resources(:service => "keepalived")
+end
+
+service "keepalived" do
+ supports :restart => true
+ action [:enable, :start]
+ subscribes :restart, resources(:template => "/etc/keepalived/keepalived.conf"), :delayed
end
View
91 templates/default/keepalived.conf.erb
@@ -1,48 +1,57 @@
-! Sample Configuration File for keepalived
+! Configuration File for keepalived
! Generated by Chef.
-
global_defs {
- notification_email {
- acassen
- }
- notification_email_from root@<%= node[:domain] %>
- smtp_server 192.168.200.1
- smtp_connect_timeout 30
- router_id LVS_DEVEL
+ notification_email {
+ <% Array(node[:keepalived][:global][:notification_emails]).each do |email| %>
+ <%= email %>
+ <% end %>
+ }
+ notification_email_from <%= node[:keepalived][:global][:notification_email_from] %>
+ smtp_server <%= node[:keepalived][:global][:smtp_server] %>
+ smtp_connect_timeout <%= node[:keepalived][:global][:smtp_connect_timeout] %>
+ router_id <%= node[:keepalived][:global][:router_ids][node.name] || node[:keepalived][:global][:router_id] %>
}
-vrrp_instance VI_1 {
- interface eth0
- virtual_router_id 50
- nopreempt
- priority 100
- advert_int 1
- virtual_ipaddress {
- 192.168.200.11
- 192.168.200.12
- 192.168.200.13
- }
+<% node[:keepalived][:check_scripts].each_pair do |name, script| %>
+vrrp_script <%= name %> {
+ script "<%= script[:script] %>"
+ interval <%= script[:interval] %>
+ weight <%= script[:weight] %>
}
+<% end %>
-virtual_server 10.10.10.2 1358 {
- delay_loop 6
- lb_algo rr
- lb_kind NAT
- persistence_timeout 50
- protocol TCP
-
- sorry_server 192.168.200.200 1358
-
- real_server 192.168.200.2 1358 {
- weight 1
- HTTP_GET {
- url {
- path /canary
- digest 640205b7b0fc66c1ea91c463fac6334d
- }
- connect_timeout 3
- nb_get_retry 3
- delay_before_retry 3
- }
- }
+<% node[:keepalived][:instances].each_pair do |name, instance| -%>
+<%
+ instance[:states] ||= {}
+ instance[:priorities] ||= {}
+ instance[:virtual_router_ids] ||= {}
+-%>
+vrrp_instance <%= name.upcase %> {
+ interface <%= instance[:interface] %>
+ virtual_router_id <%= instance[:virtual_router_ids][node.name] || node[:keepalived][:instance_defaults][:virtual_router_id] %>
+ <% if instance[:nopreempt] -%>
+ nopreempt
+ <% end -%>
+ state <%= instance[:states][node.name] || node[:keepalived][:instance_defaults][:state] %>
+ priority <%= instance[:priorities][node.name] || node[:keepalived][:instance_defaults][:priority] %>
+ <% if instance[:advert_int] -%>
+ advert_int <%= instance[:advert_int] %>
+ <% end -%>
+ <% if instance[:auth_type] -%>
+ authentication {
+ auth_type <%= instance[:auth_type].to_s.upcase %>
+ auth_pass <%= instance[:auth_pass] %>
+ }
+ <% end -%>
+ virtual_ipaddress {
+ <% Array(instance[:ip_addresses]).each do |address| %>
+ <%= address %>
+ <% end %>
+ }
+ <% if instance[:track_script] %>
+ track_script {
+ <%= instance[:track_script] %>
+ }
+ <% end %>
}
+<% end -%>
View
6 test/kitchen/Kitchenfile
@@ -0,0 +1,6 @@
+cookbook "keepalived" do
+ lint :ignore => %w(FC001)
+ runtimes []
+ configuration "default"
+ configuration "configured"
+end
View
39 test/kitchen/cookbooks/keepalived_test/files/default/tests/minitest/configured_test.rb
@@ -0,0 +1,39 @@
+require_relative './helpers.rb'
+
+describe_recipe 'keepalived_test::configured' do
+
+ include KeepalivedHelpers
+
+ describe 'configured keepalived' do
+ it 'should create a keepalived configuration file' do
+ file('/etc/keepalived/keepalived.conf').must_exist
+ end
+
+ it 'should enable and start the daemon' do
+ service('keepalived').must_be_running
+ service('keepalived').must_be_enabled
+ end
+
+ it 'should provide configuration to allow nonlocal ip binds' do
+ file('/etc/sysctl.d/60-ip-nonlocal-bind.conf').must_match(
+ %r{net\.ipv4\.ip_nonlocal_bind=1}
+ )
+ end
+
+ it 'should allow nonlocal ip binds' do
+ assert_equal(
+ 1, `sysctl net.ipv4.ip_nonlocal_bind`.strip.split('=').last.strip.to_i,
+ 'System is not configured to allow non-local binds'
+ )
+ end
+
+ it 'should have virtual address bound' do
+ sleep(5) # give keepalived some time to get setup
+ refute_nil(
+ `ip addr sh eth0`.split("\n").detect{|l| l.include?('10.0.2.254')},
+ 'Expected bound virtual IP address not found'
+ )
+ end
+
+ end
+end
View
19 test/kitchen/cookbooks/keepalived_test/files/default/tests/minitest/default_test.rb
@@ -0,0 +1,19 @@
+require_relative './helpers.rb'
+
+describe_recipe 'keepalived_test::default' do
+
+ include KeepalivedHelpers
+
+ describe 'keepalived' do
+
+ it 'should create a keepalived configuration file' do
+ file('/etc/keepalived/keepalived.conf').must_exist
+ end
+
+ it 'should start keepalived daemon' do
+ service('keepalived').must_be_enabled
+ service('keepalived').must_be_running
+ end
+
+ end
+end
View
7 test/kitchen/cookbooks/keepalived_test/files/default/tests/minitest/helpers.rb
@@ -0,0 +1,7 @@
+require 'minitest/spec'
+
+module KeepalivedHelpers
+ include MiniTest::Chef::Assertions
+ include MiniTest::Chef::Context
+ include MiniTest::Chef::Resources
+end
View
1  test/kitchen/cookbooks/keepalived_test/metadata.rb
@@ -0,0 +1 @@
+depends 'keepalived'
View
22 test/kitchen/cookbooks/keepalived_test/recipes/configured.rb
@@ -0,0 +1,22 @@
+node[:keepalived][:shared_address] = true
+node[:keepalived][:global][:notification_emails] = 'admin@example.com'
+node[:keepalived][:global][:notification_email_from] = "keepalived@example.com"
+node[:keepalived][:global][:smtp_server] = '127.0.0.1'
+node[:keepalived][:global][:smtp_connect_timeout] = 30
+node[:keepalived][:global][:router_id] = 'DEFAULT_ROUT_ID'
+node[:keepalived][:check_scripts][:chk_init] = {
+ :script => 'killall -0 init',
+ :interval => 2,
+ :weight => 2
+}
+node[:keepalived][:instances][:vi_1] = {
+ :ip_addresses => '10.0.2.254',
+ :interface => 'eth0',
+ :track_script => 'chk_init',
+ :nopreempt => false,
+ :advert_int => 1,
+ :authentication_type => nil, # :pass or :ah
+ :authentication_pass => 'secret'
+}
+
+include_recipe 'keepalived'
View
1  test/kitchen/cookbooks/keepalived_test/recipes/default.rb
@@ -0,0 +1 @@
+# Do nothing special
Please sign in to comment.
Something went wrong with that request. Please try again.