aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Pinson <raphael.pinson@camptocamp.com>2013-04-12 10:38:14 +0200
committerRaphaël Pinson <raphael.pinson@camptocamp.com>2013-04-12 10:38:14 +0200
commitf4e7bdf477586e34e47a972172c15809ac92fe3c (patch)
tree98a5610e9d0b65b39f0705c0745f12f381d13a6b
parent0689631b833d5683bdef5885de5893450f4928ca (diff)
downloadpuppet-dhcp-f4e7bdf477586e34e47a972172c15809ac92fe3c.tar.gz
puppet-dhcp-f4e7bdf477586e34e47a972172c15809ac92fe3c.tar.bz2
Improve template host.conf.erb with validations and add spec for dhcp::hosts
-rw-r--r--manifests/hosts.pp26
-rw-r--r--spec/defines/dhcp_hosts_spec.rb411
-rw-r--r--templates/host.conf.erb32
3 files changed, 451 insertions, 18 deletions
diff --git a/manifests/hosts.pp b/manifests/hosts.pp
index 426d661..f8e5faf 100644
--- a/manifests/hosts.pp
+++ b/manifests/hosts.pp
@@ -1,4 +1,4 @@
-# = Definition: dhcp::hosts
+# Definition: dhcp::hosts
#
# Creates a dhcp configuration for given hosts
#
@@ -38,15 +38,27 @@
define dhcp::hosts (
$hash_data,
$subnet,
- $global_options = false,
- $template = 'dhcp/host.conf.erb',
+ $ensure = present,
+ $global_options = [],
+ $template = "${module_name}/host.conf.erb",
) {
include ::dhcp::params
- concat::fragment {"dhcp.host.${name}":
- target => "${dhcp::params::config_dir}/hosts.d/${subnet}.conf",
- content => template($template),
- notify => Service['dhcpd'],
+ validate_string($ensure)
+ validate_re($ensure, ['present', 'absent'],
+ "\$ensure must be either 'present' or 'absent', got '${ensure}'")
+ validate_hash($hash_data)
+ validate_string($subnet)
+ validate_re($subnet, '^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$')
+ validate_array($global_options)
+ validate_string($template)
+
+ if ($ensure == 'present') {
+ concat::fragment {"dhcp.host.${name}":
+ target => "${dhcp::params::config_dir}/hosts.d/${subnet}.conf",
+ content => template($template),
+ notify => Service['dhcpd'],
+ }
}
}
diff --git a/spec/defines/dhcp_hosts_spec.rb b/spec/defines/dhcp_hosts_spec.rb
new file mode 100644
index 0000000..658be20
--- /dev/null
+++ b/spec/defines/dhcp_hosts_spec.rb
@@ -0,0 +1,411 @@
+require 'spec_helper'
+
+describe 'dhcp::hosts' do
+ let (:title) { 'My hosts' }
+ let (:facts) { {
+ :operatingsystem => 'Debian',
+ :osfamily => 'Debian',
+ :lsbdistcodename => 'squeeze',
+ } }
+
+ context 'when passing wrong value for ensure' do
+ let (:params) { {
+ :hash_data => {},
+ :subnet => '1.2.3.4',
+ :ensure => 'running'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /\$ensure must be either 'present' or 'absent', got 'running'/)
+ end
+ end
+
+ context 'when hash_data is not passed' do
+ let (:params) { {
+ :subnet => '1.2.3.4',
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /Must pass hash_data to Dhcp::Hosts/)
+ end
+ end
+
+ context 'when passing wrong type for hash_data' do
+ let (:params) { {
+ :hash_data => 'foo',
+ :subnet => '1.2.3.4',
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"foo" is not a Hash\./)
+ end
+ end
+
+ context 'when subnet is not passed' do
+ let (:params) { {
+ :hash_data => {},
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /Must pass subnet to Dhcp::Hosts/)
+ end
+ end
+
+ context 'when passing wrong type for subnet' do
+ let (:params) { {
+ :hash_data => {},
+ :subnet => true
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not a string\./)
+ end
+ end
+
+ context 'when passing wrong value for subnet' do
+ let (:params) { {
+ :hash_data => {},
+ :subnet => 'foo'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"foo" does not match/)
+ end
+ end
+
+ context 'when passing wrong type for global_options' do
+ let (:params) { {
+ :hash_data => {},
+ :subnet => '1.2.3.4',
+ :global_options => 'foo'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"foo" is not an Array\./)
+ end
+ end
+
+ context 'when passing wrong type for template' do
+ let (:params) { {
+ :hash_data => {},
+ :subnet => '1.2.3.4',
+ :template => true
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not a string\./)
+ end
+ end
+
+ context 'when passing one entry in hash_data' do
+ context 'when passing wrong type for an host data' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => true,
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not a Hash/)
+ end
+ end
+
+ context 'when interfaces is not passed' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /Missing interfaces hash for host 'host1'/)
+ end
+ end
+
+ context 'when passing wrong value for an interface' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth 0' => '00:11:22:33:44:55',
+ },
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"eth 0" does not match/)
+ end
+ end
+
+ context 'when passing wrong type for a mac address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => true,
+ },
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not a string\./)
+ end
+ end
+
+ context 'when passing wrong value for a mac address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => 'my mac',
+ },
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"my mac" does not match/)
+ end
+ end
+
+ context 'when passing wrong type for fixed_address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ 'fixed_address' => true,
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not a string/)
+ end
+ end
+
+ context 'when passing wrong value for fixed_address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ 'fixed_address' => 'my wrong value',
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"my wrong value" does not match/)
+ end
+ end
+
+ context 'when not passing fixed_address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with(
+ :content => /fixed-address host1;/
+ ) }
+ end
+
+ context 'when not passing options' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ },
+ },
+ :subnet => '1.2.3.4',
+ :global_options => ['foo', 'bar'],
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with(
+ :content => /foo;\nbar;\n/
+ ) }
+ end
+
+ context 'when overriding options' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ 'options' => ['baz'],
+ },
+ },
+ :subnet => '1.2.3.4',
+ :global_options => ['foo', 'bar'],
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with(
+ :content => /baz;\n/
+ ) }
+ end
+
+ context 'when passing wrong type for options' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ 'options' => true,
+ },
+ },
+ :subnet => '1.2.3.4',
+ :global_options => ['foo', 'bar'],
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /true is not an Array\./)
+ end
+ end
+
+ context 'when passing wrong value for fixed_address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ 'fixed_address' => 'my wrong value',
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it 'should fail' do
+ expect {
+ should contain_concat__fragment('dhcp.host.My hosts')
+ }.to raise_error(Puppet::Error, /"my wrong value" does not match/)
+ end
+ end
+
+ context 'when not passing fixed_address' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with(
+ :content => /fixed-address host1;/
+ ) }
+ end
+
+ context 'when not passing options' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ },
+ },
+ },
+ :subnet => '1.2.3.4',
+ :global_options => ['foo', 'bar'],
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with(
+ :content => /foo;\nbar;\n/
+ ) }
+ end
+
+ context 'when passing two hosts' do
+ let (:params) { {
+ :hash_data => {
+ 'host1' => {
+ 'interfaces' => {
+ 'eth0' => '00:11:22:33:44:55',
+ 'wlan0' => '00:aa:bb:44:55:ff',
+ },
+ },
+ 'host2' => {
+ 'interfaces' => {
+ 'eth1' => '00:11:af:33:44:55',
+ },
+ 'fixed_address' => 'foo.example.com',
+ 'options' => ['opt1'],
+ },
+ },
+ :subnet => '1.2.3.4'
+ } }
+
+ it { should contain_concat__fragment('dhcp.host.My hosts').with_content(
+ /host host1-eth0 \{\n hardware ethernet 00:11:22:33:44:55;\n fixed-address host1;\n\}/).with_content(
+ /host host1-wlan0 \{\n hardware ethernet 00:aa:bb:44:55:ff;\n fixed-address host1;\n\}/).with_content(
+ /host host2-eth1 \{\n hardware ethernet 00:11:af:33:44:55;\n fixed-address foo\.example\.com;\n opt1;\n\}/)
+ }
+ end
+ end
+
+ context 'when passing two entries in hash_data' do
+ end
+
+ context 'when passing global_options' do
+ end
+
+ context 'when overriding template' do
+ end
+end
diff --git a/templates/host.conf.erb b/templates/host.conf.erb
index e6a7073..398d798 100644
--- a/templates/host.conf.erb
+++ b/templates/host.conf.erb
@@ -1,16 +1,26 @@
-<%- @hash_data.sort.each do |host, datas| -%>
-<%- datas.fetch('interfaces').sort.each do |if_name, if_mac| -%>
+<%- @hash_data.sort.each do |host, data|
+ scope.function_validate_hash([data]) -%>
+<%-
+ raise Puppet::ParseError, "Missing interfaces hash for host '#{host}'" unless data.has_key? 'interfaces'
+ data.fetch('interfaces').sort.each do |if_name, if_mac|
+ scope.function_validate_re([if_name, '^\S+$'])
+ scope.function_validate_string([if_mac])
+ scope.function_validate_re([if_mac, '^[a-f0-9:.]+$'])
+ -%>
host <%= host %>-<%= if_name %> {
hardware ethernet <%= if_mac %>;
-<% if datas.fetch('fixed_address', false) -%>
- fixed-address <%= datas.fetch('fixed_address') %>;
-<% else -%>
- fixed-address <%= host %>;
-<% end -%>
-<% if datas.fetch('option', false) -%>
- <%= datas.fetch('option') %>
-<% elsif @global_options -%>
- <%= @global_options %>
+<%
+ fixed_address = data.fetch('fixed_address', nil) || host
+ scope.function_validate_string([fixed_address])
+ scope.function_validate_re([fixed_address, '^\S+$'])
+ -%>
+ fixed-address <%= fixed_address %>;
+<%
+ options = data.fetch('options', nil) || @global_options
+ scope.function_validate_array([options])
+ unless options.empty?
+ -%>
+ <%= options.join(";\n") %>;
<% end -%>
}
<% end -%>