| - one-lease-per-client: "true" | |
| | |
+---------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:: | This is large dictionary that gets parsed out into individual dhcpd config files. Each top-level key (``front`` and ``ipmi`` in the example) will get its own dhcp conf file created. The example shown to the left is our actual ``dhcp_subnets`` dictionary. |
+|:: | This is a large dictionary that gets parsed out into individual dhcpd config files. Each top-level key (``front`` and ``ipmi`` in the example) will get its own dhcp conf file created. The example shown to the left is our actual ``dhcp_subnets`` dictionary. |
| | |
| dhcp_subnets: | |
-| front: | Under each subnet, ``cidr``, ``ipvar``, and ``macvar`` are required. ``ipvar`` and ``macvar`` tell the Jinja2 template which IP address and MAC address should be used for each host in each subnet config file. |
+| front: | Under each subnet, ``version``, ``cidr``, ``ipvar``, and ``macvar`` are required. ``ipvar`` and ``macvar`` tell the Jinja2 template which IP address and MAC address should be used for each host in each subnet config file. |
+| version: '4' | |
| cidr: 172.21.0.0/20 | |
| ipvar: ip | Here's a line from our Ansible inventory host file |
| macvar: mac | |
-| domain_name: front.sepia.ceph.com | ``smithi001.front.sepia.ceph.com mac=0C:C4:7A:BD:15:E8 ip=172.21.15.1 ipmi=172.21.47.1 bmc=0C:C4:7A:6E:21:A7`` |
+| domain_name: front.sepia.ceph.com | ``smithi001.front.sepia.ceph.com mac=0C:C4:7A:BD:15:E8 ip=172.21.15.1 ipmi=172.21.47.1 bmc=0C:C4:7A:6E:21:A7 ipv6=2620:52:3:3:ec4:7aff:febd:15e8`` |
| domain_search: | |
-| - front.sepia.ceph.com | This will result in a static IP entry for smithi001-front with IP 172.21.15.1 and MAC 0C:C4:7A:BD:15:E8 in ``dhcpd.front.conf`` and a smithi001-ipmi entry with IP 172.21.47.1 with MAC 0C:C4:7A:6E:21:A7 in ``dhcpd.ipmi.conf``. |
+| - front.sepia.ceph.com | This will result in: |
| - sepia.ceph.com | |
-| domain_name_server: | The ``next_server`` and ``filename`` values can be overridden by ansible group or host. See below. |
-| - 172.21.0.1 | |
-| - 172.21.0.2 | All the other keys are optional. |
+| domain_name_server: | - a static IP entry for smithi001-front with IP 172.21.15.1 and MAC 0C:C4:7A:BD:15:E8 in ``dhcpd.front.conf`` |
+| - 172.21.0.1 | - a smithi001-ipmi entry with IP 172.21.47.1 with MAC 0C:C4:7A:6E:21:A7 in ``dhcpd.ipmi.conf`` |
+| - 172.21.0.2 | - a smithi001-front-ipv6 entry with IP 2620:52:3:3:ec4:7aff:febd:15e8 with MAC 0C:C4:7A:BD:15:E8 in ``dhcpd.front-ipv6.conf`` |
| routers: 172.21.15.254 | |
-| next_server: 172.21.0.11 | |
+| next_server: 172.21.0.11 | The ``next_server`` and ``filename`` values can be overridden by ansible group or host. See below. |
| filename: "/pxelinux.0" | |
-| classes: | |
+| classes: | All the other keys are optional. |
| virtual: "match if substring(hardware, 0, 4) = 01:52:54:00" | |
| lxc: "match if substring(hardware, 0, 4) = 01:52:54:ff" | |
| pools: | |
| lxc: | |
| range: 172.21.14.1 172.21.14.200 | |
| ipmi: | |
+| version: '4' | |
| cidr: 172.21.32.0/20 | |
| ipvar: ipmi | |
| macvar: bmc | |
| range: 172.21.43.1 172.21.43.100 | |
| next_server: 172.21.0.11 | |
| filename: "/pxelinux.0" | |
+| front-ipv6: | |
+| version: '6' | |
+| cidr: 2620:52:3:3::/64 | |
+| ipvar: ipv6 | |
+| macvar: mac | |
+| domain_name: front.sepia.ceph.com | |
+| domain_search: | |
+| - front.sepia.ceph.com | |
+| - sepia.ceph.com | |
+| routers: 2620:52:3:3:ffff:ffff:ffff:fffe/64 | |
+| next_server: 2620:52:3:3:225:90ff:fee3:d94a | |
+| filename: "/pxelinux.0" | |
| | |
+---------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Optional Variables** |
+---------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``dhcp_option_hostname: False`` | Should this host get ``option host-name "{{ ansible_host }}";`` defined in its host declaration? Defaults to False. Override in secrets repo per host/group. |
+---------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``enable_ipv6: False`` | Configure dhcpd6? Defaults to False. Override in secrets repo per host/group. Must set ``version: 6`` for IPv6 subnets in ``dhcp_subnets`` dictionary. |
++---------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
.. _docs: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable
.. _dhcpd: https://linux.die.net/man/8/dhcpd
--- /dev/null
+---
+enable_ipv6: false
--- /dev/null
+---
+- name: Install/update packages
+ yum:
+ name: dhcp
+ state: latest
+ register: dhcp_yum_transaction
+ tags: packages
+
+- name: Check for firewalld
+ command: firewall-cmd --state
+ register: firewalld_state
+ ignore_errors: true
+
+- name: Check for iptables
+ command: systemctl status iptables
+ register: iptables_state
+ ignore_errors: true
+
+- name: Make sure firewalld is running
+ service:
+ name: firewalld
+ state: started
+ enabled: yes
+ when:
+ - not ansible_check_mode
+ - iptables_state.rc != 0
+ - not (firewalld_state.msg is defined and "'No such file or directory' in firewalld_state.msg")
+
+- name: Configure firewalld
+ firewalld:
+ service: dhcp
+ state: enabled
+ permanent: true
+ immediate: yes
+ when:
+ - not ansible_check_mode
+ - iptables_state.rc != 0
+ - not (firewalld_state.msg is defined and "'No such file or directory' in firewalld_state.msg")
+
+- name: Write global dhcpd.conf
+ template:
+ src: dhcpd.conf.j2
+ dest: /etc/dhcp/dhcpd.conf
+ backup: yes
+ register: dhcp_global_config
+
+# NOTE: This will write the IPv6 configs too just to avoid iterating over `dhcp_subnets: {}` twice.
+# ipv6.yml will configure and restart the dhcpd6 service
+- name: Write each subnet config
+ template:
+ src: dhcpd.subnet.conf.j2
+ dest: "/etc/dhcp/dhcpd.{{ item }}.conf"
+ backup: yes
+ with_items: "{{ dhcp_subnets }}"
+ register: dhcp_subnet_config
+
+- name: Test new config
+ command: dhcpd -t -cf /etc/dhcp/dhcpd.conf
+ register: dhcpd_config_test_result
+ when:
+ - not ansible_check_mode
+ - (dhcp_global_config is changed or dhcp_subnet_config is changed)
+
+- name: Restart dhcpd
+ service:
+ name: dhcpd
+ state: restarted
+ when:
+ - not ansible_check_mode
+ - (dhcp_global_config is changed or dhcp_subnet_config is changed)
+ - dhcpd_config_test_result is defined
+ - dhcpd_config_test_result.rc == 0
--- /dev/null
+---
+- name: Write global dhcpd6.conf
+ template:
+ src: dhcpd6.conf.j2
+ dest: /etc/dhcp/dhcpd6.conf
+ backup: yes
+ register: dhcp6_global_config
+
+- name: Test new config
+ command: dhcpd -t -6 -cf /etc/dhcp/dhcpd6.conf
+ register: dhcpd6_config_test_result
+ when:
+ - not ansible_check_mode
+ - (dhcp6_global_config is changed or dhcp_subnet_config is changed)
+
+- name: Restart dhcpd6
+ service:
+ name: dhcpd6
+ state: restarted
+ when:
+ - not ansible_check_mode
+ - dhcp6_global_config is defined
+ - dhcp_subnet_config is defined
+ - (dhcp6_global_config is changed or dhcp_subnet_config is changed)
+ - dhcpd6_config_test_result is defined
+ - dhcpd6_config_test_result.rc == 0
---
-- name: Install/update packages
- yum:
- name: dhcp
- state: latest
- register: dhcp_yum_transaction
+- name: Run IPv4 DHCP server tasks
+ include_tasks: ipv4.yml
-- name: Check for firewalld
- command: firewall-cmd --state
- register: firewalld_state
- ignore_errors: true
-
-- name: Check for iptables
- command: systemctl status iptables
- register: iptables_state
- ignore_errors: true
-
-- name: Make sure firewalld is running
- service:
- name: firewalld
- state: started
- enabled: yes
- when:
- - iptables_state.rc != 0
- - not (firewalld_state.msg is defined and "'No such file or directory' in firewalld_state.msg")
-
-- name: Configure firewalld
- firewalld:
- service: dhcp
- state: enabled
- permanent: true
- immediate: yes
- when:
- - iptables_state.rc != 0
- - not (firewalld_state.msg is defined and "'No such file or directory' in firewalld_state.msg")
-
-- name: Write global dhcpd.conf
- template:
- src: dhcpd.conf.j2
- dest: /etc/dhcp/dhcpd.conf
- backup: yes
- register: dhcp_global_config
-
-- name: Write each subnet config
- template:
- src: dhcpd.subnet.conf.j2
- dest: "/etc/dhcp/dhcpd.{{ item }}.conf"
- backup: yes
- with_items: "{{ dhcp_subnets }}"
- register: dhcp_subnet_config
-
-- name: Test new config
- command: dhcpd -t -cf /etc/dhcp/dhcpd.conf
- register: dhcpd_config_test_result
- when: dhcp_global_config is changed or dhcp_subnet_config is changed
-
-- name: Restart dhcpd
- service:
- name: dhcpd
- state: restarted
- when:
- - (dhcp_global_config is changed or dhcp_subnet_config is changed)
- - dhcpd_config_test_result is defined
- - dhcpd_config_test_result.rc == 0
+- name: Run IPv6 DHCP server tasks
+ include_tasks: ipv6.yml
+ when: enable_ipv6|bool
{% endfor %}
{% for key, value in dhcp_subnets.items() %}
+{% if value.version == "4" %}
include "/etc/dhcp/dhcpd.{{ key }}.conf";
+{% endif %}
{% endfor %}
{% for subnet, subnet_item in dhcp_subnets.items() %}
{% if subnet == item %}
+{% if subnet_item.version == "6" %}{% set is_six = "6" %}
+subnet6 {{ subnet_item.cidr }} {
+{% else %}{% set is_six = "" %}
subnet {{ subnet_item.cidr | ipaddr('network') }} netmask {{ subnet_item.cidr | ipaddr('netmask') }} {
+{% endif %}
{% if subnet_item.domain_name is defined -%}
option domain-name "{{ subnet_item.domain_name }}";
{% endif -%}
{% if subnet_item.domain_name_servers is defined -%}
option domain-name-servers {{ subnet_item.domain_name_servers|join(', ') }};
{% endif -%}
- {% if subnet_item.routers is defined -%}
+ {% if subnet_item.routers is defined and not subnet_item.version == "6" -%}
option routers {{ subnet_item.routers }};
{% endif -%}
- {% if subnet_item.next_server is defined -%}
+ {% if subnet_item.next_server is defined and not subnet_item.version == "6" -%}
next-server {{ subnet_item.next_server }};
{% endif -%}
- {% if subnet_item.filename is defined -%}
+ {% if subnet_item.filename is defined and not subnet_item.version == "6" -%}
filename "{{ subnet_item.filename }}";
{% endif %}
{%- endif -%}
{% for host in groups['all'] | sort | unique -%}
- {% if hostvars[host][subnet_item.macvar] is defined -%}
+ {% if hostvars[host][subnet_item.macvar] is defined and hostvars[host][subnet_item.ipvar] is defined -%}
{% if hostvars[host][subnet_item.ipvar] | ipaddr(subnet_item.cidr) | ipaddr('bool') -%}
host {{ host.split('.')[0] }}-{{ subnet }} {
{% if hostvars[host]['dhcp_next_server'] is defined -%}
option domain-name-servers {{ hostvars[host]['domain_name_servers']|join(', ') }};
{% endif -%}
hardware ethernet {{ hostvars[host][subnet_item.macvar] }};
- fixed-address {{ hostvars[host][subnet_item.ipvar] }};
+ fixed-address{{ is_six }} {{ hostvars[host][subnet_item.ipvar] }};
{% if hostvars[host]['dhcp_option_hostname'] is defined and hostvars[host]['dhcp_option_hostname'] == true %}
option host-name "{{ host.split('.')[0] }}";
{% endif -%}
--- /dev/null
+{% for item in dhcp_global_options %}
+{% for key, value in item.items() %}
+{{ key }} {{ value }};
+{% endfor %}
+{% endfor %}
+
+{% for key, value in dhcp_subnets.items() %}
+{% if value.version == "6" %}
+include "/etc/dhcp/dhcpd.{{ key }}.conf";
+{% endif %}
+{% endfor %}