diff --git a/dhcpd/config.sls b/dhcpd/config.sls index 47261cd..eb81984 100644 --- a/dhcpd/config.sls +++ b/dhcpd/config.sls @@ -1,4 +1,7 @@ -{% from "dhcpd/map.jinja" import dhcpd with context %} +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} + +{% from tplroot ~ "/map.jinja" import dhcpd with context %} include: - dhcpd @@ -27,6 +30,8 @@ dhcpd.conf: - mode: 644 - watch_in: - service: dhcpd + - context: + dhcpd: {{ dhcpd | json }} {% if dhcpd.service_config is defined %} @@ -45,5 +50,7 @@ service_config: - mode: 644 - watch_in: - service: dhcpd + - context: + dhcpd: {{ dhcpd | json }} {% endif %} diff --git a/dhcpd/files/dhcpd.conf b/dhcpd/files/dhcpd.conf index a75180f..85e4b65 100644 --- a/dhcpd/files/dhcpd.conf +++ b/dhcpd/files/dhcpd.conf @@ -3,95 +3,88 @@ # SaltStack-generated configuration file for ISC dhcpd # -{%- set customized = {} %} {%- set types_to_quote = ['string', 'text'] %} {%- set quote = '' %} {%- set dquote = '"' %} -{% if salt['pillar.get']('dhcpd:customized_options', False) -%} -{%- set customized = salt['pillar.get']('dhcpd:customized_options', {}) %} + # Customized dhcp options - {%- for name, data in customized.items() %} +{%- for name, data in dhcpd.customized_options.items() %} option {{ name|replace('_', '-') }} code {{ data.code }} = {{ data.type }}; - {%- endfor %} -{% endif -%} +{%- endfor %} # option definitions common to all supported networks... -{% if salt['pillar.get']('dhcpd:domain_name', False) -%} -option domain-name "{{ salt['pillar.get']('dhcpd:domain_name') }}"; +{% if dhcpd.domain_name -%} +option domain-name "{{ dhcpd.domain_name }}"; {% endif -%} -{% if salt['pillar.get']('dhcpd:domain_name_servers', False) -%} +{% if dhcpd.domain_name_servers -%} option domain-name-servers - {%- for dns_server in salt['pillar.get']('dhcpd:domain_name_servers') %} {{ dns_server }} + {%- for dns_server in dhcpd.domain_name_servers %} {{ dns_server }} {%- if not loop.last %},{% else %};{% endif %} {%- endfor %} {% endif -%} -{% if salt['pillar.get']('dhcpd:subnet_mask', False) -%} -option subnet-mask {{ salt['pillar.get']('dhcpd:subnet_mask') }}; +{% if dhcpd.subnet_mask -%} +option subnet-mask {{ dhcpd.subnet_mask }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:routers', False) -%} +{% if dhcpd.routers -%} option routers - {%- for router in salt['pillar.get']('dhcpd:routers') %} {{ router }} + {%- for router in dhcpd.routers %} {{ router }} {%- if not loop.last %},{% else %};{% endif %} {%- endfor %} {% endif -%} -{% if salt['pillar.get']('dhcpd:domain_search', False) -%} -option domain-search {{ dquote }}{{ '" , "'.join(salt['pillar.get']('dhcpd:domain_search', [])) }}{{ dquote }}; +{% if dhcpd.domain_search -%} +option domain-search {{ dquote }}{{ dhcpd.domain_search | join( '" , "' ) }}{{ dquote }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:default_lease_time', False) -%} -default-lease-time {{ salt['pillar.get']('dhcpd:default_lease_time') }}; +{% if dhcpd.default_lease_time -%} +default-lease-time {{ dhcpd.default_lease_time }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:max_lease_time', False) -%} -max-lease-time {{ salt['pillar.get']('dhcpd:max_lease_time') }}; +{% if dhcpd.max_lease_time -%} +max-lease-time {{ dhcpd.max_lease_time }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:one_lease_per_client', False) -%} -one-lease-per-client {{ salt['pillar.get']('dhcpd:one_lease_per_client') }}; +{% if dhcpd.one_lease_per_client -%} +one-lease-per-client {{ dhcpd.one_lease_per_client }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:get_lease_hostnames', False) -%} -get-lease-hostnames {{ salt['pillar.get']('dhcpd:get_lease_hostnames') }}; +{% if dhcpd.get_lease_hostnames -%} +get-lease-hostnames {{ dhcpd.get_lease_hostnames }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:server_identifier') -%} -server-identifier {{ salt['pillar.get']('dhcpd:server_identifier') }}; +{% if dhcpd.server_identifier -%} +server-identifier {{ dhcpd.server_identifier }}; {% endif -%} -{% if salt['pillar.get']('dhcpd:server_name') -%} -server-name {{ dquote }}{{ salt['pillar.get']('dhcpd:server_name') }}{{ dquote }}; +{% if dhcpd.server_name -%} +server-name {{ dquote }}{{ dhcpd.server_name }}{{ dquote }}; {% endif -%} -{%- if salt['pillar.get']('dhcpd:use_host_decl_names', False) %} +{%- if dhcpd.use_host_decl_names %} use-host-decl-names on; {%- else %} #use-host-decl-names off; {%- endif %} -{%- if salt['pillar.get']('dhcpd:allow', False) %} - {%- set allow = salt['pillar.get']('dhcpd:allow') %} - {%- if allow is iterable and allow is not string %} - {%- for item in allow %}allow {{ item }};{%- endfor %} - {%- else %}allow {{ allow }}; +{%- if dhcpd.allow %} + {%- if dhcpd.allow is iterable and dhcpd.allow is not string %} + {%- for item in dhcpd.allow %}allow {{ item }};{%- endfor %} + {%- else %}allow {{ dhcpd.allow }}; {%- endif %} {%- endif %} -{%- if salt['pillar.get']('dhcpd:deny', False) %} - {%- set deny = salt['pillar.get']('dhcpd:deny') %} - {%- if deny is iterable and deny is not string %} - {%- for item in deny %} -deny {{ item }}; -{%- endfor %} - {%- else %}deny {{ deny }}; +{%- if dhcpd.deny %} + {%- if dhcpd.deny is iterable and dhcpd.deny is not string %} + {%- for item in dhcpd.deny %}deny {{ item }};{%- endfor %} + {%- else %}deny {{ dhcpd.deny }}; {%- endif %} {%- endif %} # Use this to enble / disable dynamic dns updates globally. -{%- if salt['pillar.get']('dhcpd:ddns_update_style', False) %} -ddns-update-style {{ salt['pillar.get']('dhcpd:ddns_update_style') }}; +{%- if dhcpd.ddns_update_style %} +ddns-update-style {{ dhcpd.ddns_update_style }}; {%- else %} #ddns-update-style none; {%- endif %} -{%- if salt['pillar.get']('dhcpd:ddns_domainname', '') %} -ddns-domainname "{{ salt['pillar.get']('dhcpd:ddns_domainname') }}"; +{%- if dhcpd.ddns_domainname %} +ddns-domainname "{{ dhcpd.ddns_domainname }}"; {%- endif %} -{%- if salt['pillar.get']('dhcpd:update_static_leases', False) %} +{%- if dhcpd.update_static_leases %} update-static-leases on; {%- else %} #update-static-leases off; @@ -99,7 +92,7 @@ update-static-leases on; # If this DHCP server is the official DHCP server for the local # network, the authoritative directive should be uncommented. -{%- if salt['pillar.get']('dhcpd:authoritative', False) %} +{%- if dhcpd.authoritative %} authoritative; {%- else %} #authoritative; @@ -107,18 +100,18 @@ authoritative; # Use this to send dhcp log messages to a different log file (you also # have to hack syslog.conf to complete the redirection). -{%- if salt['pillar.get']('dhcpd:log_facility', False) %} -log-facility {{ salt['pillar.get']('dhcpd:log_facility') }}; +{%- if dhcpd.log_facility %} +log-facility {{ dhcpd.log_facility }}; {%- endif %} -{%- for option in customized.keys() %} - {%- if option in salt['pillar.get']('dhcpd') %} - {%- if customized[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} -option {{ option|replace('_', '-') }} {{ quote }}{{ salt['pillar.get']('dhcpd:' ~ option) }}{{ quote }}; +{%- for option in dhcpd.customized_options.keys() %} + {%- if option in dhcpd %} + {%- if dhcpd.customized_options[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} +option {{ option|replace('_', '-') }} {{ quote }}{{ dhcpd.get(option) }}{{ quote }}; {%- endif %} {%- endfor %} -{%- for class, config in salt['pillar.get']('dhcpd:classes', {}).items() %} +{%- for class, config in dhcpd.classes.items() %} {%- if 'comment' in config %} {%- for line in config.comment.splitlines() %} # {{ line }} @@ -128,16 +121,16 @@ class "{{ class }}" { {%- if 'match' in config %} match {{ config.match }}; {%- endif %} - {%- for option in customized.keys() %} + {%- for option in dhcpd.customized_options.keys() %} {%- if option in config %} - {%- if customized[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} + {%- if dhcpd.customized_options[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} option {{ option|replace('_', '-') }} {{ quote }}{{ config.get(option) }}{{ quote }}; {%- endif %} {%- endfor %} } {%- endfor %} -{%- for failover_peer, config in salt['pillar.get']('dhcpd:failover_peers', {}).items() %} +{%- for failover_peer, config in dhcpd.failover_peers.items() %} {%- if 'comment' in config %} {%- for line in config.comment.splitlines() %} # {{ line }} @@ -193,7 +186,7 @@ failover peer "{{ failover_peer }}" { } {%- endfor %} -{%- for key, config in salt['pillar.get']('dhcpd:keys', {}).items() %} +{%- for key, config in dhcpd.get('keys', {}).items() %} key {{ key }} { {%- if 'algorithm' in config %} algorithm {{ config.algorithm }}; @@ -204,7 +197,7 @@ key {{ key }} { } {%- endfor %} -{%- for zone, config in salt['pillar.get']('dhcpd:zones', {}).items() %} +{%- for zone, config in dhcpd.get('zones', {}).items() %} zone {{ zone }} { {%- if 'primary' in config %} primary {{ config.primary }}; @@ -215,28 +208,26 @@ zone {{ zone }} { } {%- endfor %} -{%- for subnet, config in salt['pillar.get']('dhcpd:subnets', {}).items() %} +{%- for subnet, config in dhcpd.subnets.items() %} {%- include 'dhcpd/files/subnet.jinja' with context %} {%- endfor %} -{% for host, config in salt['pillar.get']('dhcpd:hosts', {}).items() %} +{% for host, config in dhcpd.hosts.items() %} {%- include 'dhcpd/files/host.jinja' with context %} {% endfor %} -{%- for shared_network, config in salt['pillar.get']('dhcpd:shared_networks', {}).items() %} - {%- if 'comment' in config %} - {%- for line in config.comment.splitlines() %} +{%- for shared_network, sn_config in dhcpd.shared_networks.items() %} + {%- if 'comment' in sn_config %} + {%- for line in sn_config.comment.splitlines() %} # {{ line }} {%- endfor %} {%- endif %} shared-network {{ shared_network }} { - {%- for subnet, config in salt['pillar.get']( - 'dhcpd:shared_networks:{0}:subnets'.format(shared_network), {}).items() %} + {%- for subnet, config in sn_config.get('subnets', {}).items() %} {%- filter indent(width=2) %} {% include 'dhcpd/files/subnet.jinja' with context %} {%- endfilter %} {%- endfor %} - {%- for pool in salt['pillar.get']( - 'dhcpd:shared_networks:{0}:pools'.format(shared_network), []) %} + {%- for pool in sn_config.get( 'pools', [] ) %} pool { {%- if 'allow' in pool %} allow {{ pool.allow }}; @@ -248,9 +239,9 @@ shared-network {{ shared_network }} { {%- endif %} } {%- endfor %} - {%- for option in customized.keys() %} - {%- if option in config %} - {%- if customized[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} + {%- for option in dhcpd.customized_options.keys() %} + {%- if option in sn_config %} + {%- if dhcpd.customized_options[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} option {{ option|replace('_', '-') }} {{ quote }}{{ config.get(option) }}{{ quote }}; {%- endif %} {%- endfor %} diff --git a/dhcpd/files/host.jinja b/dhcpd/files/host.jinja index 291694f..c6049b7 100644 --- a/dhcpd/files/host.jinja +++ b/dhcpd/files/host.jinja @@ -40,9 +40,9 @@ host {{ host }} { {%- if 'host_name' in config %} option host-name "{{ config.host_name }}"; {%- endif %} - {%- for option in customized.keys() %} + {%- for option in dhcpd.customized_options.keys() %} {%- if option in config %} - {%- if customized[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} + {%- if dhcpd.customized_options[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} option {{ option|replace('_', '-') }} {{ quote }}{{ config.get(option) }}{{ quote }}; {%- endif %} {%- endfor %} diff --git a/dhcpd/files/service_config.Debian b/dhcpd/files/service_config.Debian index 6419d9a..d561897 100644 --- a/dhcpd/files/service_config.Debian +++ b/dhcpd/files/service_config.Debian @@ -12,4 +12,4 @@ # On what interfaces should the DHCP server (dhcpd) serve DHCP requests? # Separate multiple interfaces with spaces, e.g. "eth0 eth1". -INTERFACES="{{ ' '.join(salt['pillar.get']('dhcpd:listen_interfaces', [])) }}" +INTERFACES="{{ dhcpd.listen_interfaces | join(' ') }}" diff --git a/dhcpd/files/service_config.FreeBSD b/dhcpd/files/service_config.FreeBSD index ca7c762..8b56b40 100644 --- a/dhcpd/files/service_config.FreeBSD +++ b/dhcpd/files/service_config.FreeBSD @@ -1,3 +1,3 @@ # SaltStack-generated demon configuration file for ISC dhcpd -dhcpd_ifaces="{{ ' '.join(salt['pillar.get']('dhcpd:listen_interfaces', [])) }}" +dhcpd_ifaces="{{ dhcpd.listen_interfaces | join(' ') }}" diff --git a/dhcpd/files/service_config.Gentoo b/dhcpd/files/service_config.Gentoo index 23f699a..159063c 100644 --- a/dhcpd/files/service_config.Gentoo +++ b/dhcpd/files/service_config.Gentoo @@ -22,7 +22,7 @@ # Configure which interface or interfaces to for dhcpd to listen on. # List all interfaces space separated. If this is not specified then # we listen on all interfaces. -DHCPD_IFACE="{{ ' '.join(salt['pillar.get']('dhcpd:listen_interfaces', [])) }}" +DHCPD_IFACE="{{ dhcpd.listen_interfaces | join(' ') }}" # Insert any other dhcpd options - see the man page for a full list. # DHCPD_OPTS="" diff --git a/dhcpd/files/service_config.RedHat b/dhcpd/files/service_config.RedHat index 236682c..fcd6f90 100644 --- a/dhcpd/files/service_config.RedHat +++ b/dhcpd/files/service_config.RedHat @@ -1,3 +1,3 @@ [Service] ExecStart= -ExecStart=/usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid {{ ' '.join(salt['pillar.get']('dhcpd:listen_interfaces', [])) }} +ExecStart=/usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid {{ dhcpd.listen_interfaces | join(' ') }} diff --git a/dhcpd/files/subnet.jinja b/dhcpd/files/subnet.jinja index 79c09de..2731fdc 100644 --- a/dhcpd/files/subnet.jinja +++ b/dhcpd/files/subnet.jinja @@ -64,13 +64,13 @@ subnet {{ subnet }} netmask {{ config.netmask }} { {%- if not loop.last %},{% else %};{% endif %} {%- endfor %} {%- endif %} -{%- for option in customized.keys() %} +{%- for option in dhcpd.customized_options.keys() %} {%- if option in config %} - {%- if customized[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} + {%- if dhcpd.customized_options[option]['type'] in types_to_quote %} {% set quote = dquote %} {%- endif %} option {{ option|replace('_', '-') }} {{ quote }}{{ config.get(option) }}{{ quote }}; {%- endif %} {%- endfor %} -{%- for pool in salt['pillar.get']('dhcpd:subnets:{0}:pools'.format(subnet), []) %} +{%- for pool in config.get( 'pools', [] ) %} pool { {%- if 'failover_peer' in pool %} failover peer "{{ pool['failover_peer'] }}"; @@ -88,7 +88,7 @@ subnet {{ subnet }} netmask {{ config.netmask }} { {%- endif %} } {%- endfor %} -{%- for host, config in salt['pillar.get']('dhcpd:subnets:{0}:hosts'.format(subnet), {}).items() %} +{%- for host, config in config.get('hosts', {}).items() %} {%- filter indent(width=2) %} {% include 'dhcpd/files/host.jinja' with context %} {%- endfilter %} diff --git a/dhcpd/map.jinja b/dhcpd/map.jinja index 0bc3c2e..e7c66b3 100644 --- a/dhcpd/map.jinja +++ b/dhcpd/map.jinja @@ -13,7 +13,7 @@ {#- Retrieve the config dict only once #} {%- set _config = salt['config.get'](tplroot, default={}) %} -{%- set config = salt['grains.filter_by']( +{%- set defaults = salt['grains.filter_by']( default_settings, default=tplroot, merge=salt['grains.filter_by']( @@ -39,4 +39,11 @@ ) %} +{%- set config = salt['grains.filter_by']( + {'defaults': defaults}, + default='defaults', + merge=_config + ) +%} + {%- set dhcpd = config %} diff --git a/test/integration/default/controls/config_spec.rb b/test/integration/default/controls/config_spec.rb index 60f51ab..ccd91c3 100644 --- a/test/integration/default/controls/config_spec.rb +++ b/test/integration/default/controls/config_spec.rb @@ -71,6 +71,7 @@ # Customized dhcp options option auto-proxy-config code 252 = string; + # option definitions common to all supported networks... option domain-name "example.org"; option domain-name-servers ns1.example.org, ns2.example.org; @@ -144,16 +145,6 @@ class "foo" { } - # Hosts which require special configuration options can be listed in - # host statements. If no address is specified, the address will be - # allocated dynamically (if possible), but the host-specific information - # will still come from the host declaration. - host passacaglia { - hardware ethernet 0:0:c0:5d:bd:95; - filename "vmunix.passacaglia"; - server-name "toccata.fugue.com"; - } - # Fixed IP addresses can also be specified for hosts. These addresses # should not also be listed as being available for dynamic assignment. # Hosts for which fixed IP addresses have been specified can boot using @@ -174,15 +165,25 @@ class "foo" { option host-name "joe"; } + # Hosts which require special configuration options can be listed in + # host statements. If no address is specified, the address will be + # allocated dynamically (if possible), but the host-specific information + # will still come from the host declaration. + host passacaglia { + hardware ethernet 0:0:c0:5d:bd:95; + filename "vmunix.passacaglia"; + server-name "toccata.fugue.com"; + } + shared-network 224-29 { - #{spurious_whitespace} - subnet 10.17.224.0 netmask 255.255.255.0 { - option routers rtr-224.example.org; - } #{spurious_whitespace} subnet 10.0.29.0 netmask 255.255.255.0 { option routers rtr-29.example.org; } + #{spurious_whitespace} + subnet 10.17.224.0 netmask 255.255.255.0 { + option routers rtr-224.example.org; + } pool { allow members of "foo"; range 10.17.224.10 10.17.224.250; diff --git a/test/integration/default/controls/yaml_dump_spec.rb b/test/integration/default/controls/yaml_dump_spec.rb index 6e11d3e..0bfd497 100644 --- a/test/integration/default/controls/yaml_dump_spec.rb +++ b/test/integration/default/controls/yaml_dump_spec.rb @@ -8,26 +8,94 @@ allow: [] arch: #{arch} authoritative: false - classes: {} + classes: + foo: + comment: 'You can declare a class of clients and then do address allocation + + based on that. The example below shows a case where all clients + + in a certain class get addresses on the 10.17.224/24 subnet, and all + + other clients get addresses on the 10.0.29/24 subnet. + + ' + match: if substring (option vendor-class-identifier, 0, 4) = "SUNW" COMMON common02 = <<~COMMON.chomp - customized_options: {} + customized_options: + auto_proxy_config: + code: 252 + type: string ddns_domainname: '' ddns_update_style: '' - default_lease_time: 0 + default_lease_time: 600 deny: [] - domain_name: '' - domain_name_servers: [] + domain_name: example.org + domain_name_servers: + - ns1.example.org + - ns2.example.org domain_search: [] COMMON common03 = <<~COMMON.chomp - failover_peers: {} + failover_peers: + dhcp-failover: + primary: true + address: 10.152.187.5 + port: 647 + peer_address: 10.152.187.6 + peer_port: 647 + split: 128 + mclt: 3600 get_lease_hostnames: '' - hosts: {} + hosts: + fantasia: + comment: 'Fixed IP addresses can also be specified for hosts. These addresses + + should not also be listed as being available for dynamic assignment. + + Hosts for which fixed IP addresses have been specified can boot using + + BOOTP or DHCP. Hosts for which no fixed address is specified can only + + be booted with DHCP, unless there is an address range on the subnet + + to which a BOOTP client is connected which has the dynamic-bootp flag + + set. + + ' + hardware: ethernet 08:00:07:26:c0:a5 + fixed_address: fantasia.fugue.com + joe: + comment: 'The hostname for a host can be passed in the DHCP response. Using the + + host_name key sets option host-name in the dhcpd configuration. + + ' + hardware: ethernet 08:00:2b:4c:29:32 + fixed_address: joe.fugue.com + host_name: joe + passacaglia: + comment: 'Hosts which require special configuration options can be listed in + + host statements. If no address is specified, the address will be + + allocated dynamically (if possible), but the host-specific information + + will still come from the host declaration. + + ' + hardware: ethernet 0:0:c0:5d:bd:95 + filename: vmunix.passacaglia + server_name: toccata.fugue.com keys: {} - listen_interfaces: [] - log_facility: '' - max_lease_time: 0 + listen_interfaces: + - em1 + - em2 + log_facility: local7 + lookup: + enable: false + max_lease_time: 7200 one_lease_per_client: '' COMMON common04 = <<~COMMON.chomp @@ -38,9 +106,81 @@ server_name: '' COMMON common06 = <<~COMMON.chomp - shared_networks: {} + shared_networks: + 224-29: + subnets: + 10.17.224.0: + netmask: 255.255.255.0 + routers: rtr-224.example.org + 10.0.29.0: + netmask: 255.255.255.0 + routers: rtr-29.example.org + pools: + - allow: members of "foo" + range: + - 10.17.224.10 + - 10.17.224.250 + - deny: members of "foo" + range: + - 10.0.29.10 + - 10.0.29.230 subnet_mask: '' - subnets: {} + subnets: + 10.152.187.0: + comment: 'No service will be given on this subnet, but declaring it helps the + + DHCP server to understand the network topology. + + ' + netmask: 255.255.255.0 + pools: + - failover_peer: dhcp-failover + range: + - 10.152.187.1 + - 10.152.187.254 + 10.254.239.0: + comment: This is a very basic subnet declaration. + netmask: 255.255.255.224 + range: + - 10.254.239.10 + - 10.254.239.20 + routers: + - rtr-239-0-1.example.org + - rtr-239-0-2.example.org + 10.254.239.32: + comment: 'This declaration allows BOOTP clients to get dynamic addresses, + + which we don''t really recommend. + + ' + netmask: 255.255.255.224 + dynamic_bootp: true + range: + - 10.254.239.40 + - 10.254.239.60 + broadcast_address: 10.254.239.31 + routers: rtr-239-32-1.example.org + 10.5.5.0: + comment: A slightly different configuration for an internal subnet. + netmask: 255.255.255.224 + range: + - 10.5.5.26 + - 10.5.5.30 + domain_name_servers: + - ns1.internal.example.org + domain_name: internal.example.org + routers: + - 10.5.5.1 + broadcast_address: 10.5.5.31 + default_lease_time: 600 + max_lease_time: 7200 + hosts: + jake: + comment: 'Hosts can be specified for subnets, taking subnets defaults + + ' + hardware: ethernet 08:00:a7:26:c0:a9 + fixed_address: 10.5.5.27 update_static_leases: false use_host_decl_names: false zones: {}