]> gitweb.fluxo.info Git - puppet-dhcp.git/commitdiff
Improve template host.conf.erb with validations and add spec for dhcp::hosts
authorRaphaël Pinson <raphael.pinson@camptocamp.com>
Fri, 12 Apr 2013 08:38:14 +0000 (10:38 +0200)
committerRaphaël Pinson <raphael.pinson@camptocamp.com>
Fri, 12 Apr 2013 08:38:14 +0000 (10:38 +0200)
manifests/hosts.pp
spec/defines/dhcp_hosts_spec.rb [new file with mode: 0644]
templates/host.conf.erb

index 426d661a0fc7ebc540f97b04cc7fa40b8ec1fbec..f8e5faf024e538f6663dcebaf02993d1787cf096 100644 (file)
@@ -1,4 +1,4 @@
-# Definition: dhcp::hosts
+# Definition: dhcp::hosts
 #
 # Creates a dhcp configuration for given hosts
 #
 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 (file)
index 0000000..658be20
--- /dev/null
@@ -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
index e6a7073f6146bab8d8c0e1c88c28e6444e10b1e0..398d7983dd2c8db0d58849034d5eb5ee016f2181 100644 (file)
@@ -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 -%>