From 1f758deb82c01741113699a7e6397e0ccdc1a8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20D=C3=A9siles?= <1536672+cdesiles@users.noreply.github.com> Date: Tue, 3 Feb 2026 22:07:40 +0100 Subject: [PATCH] feat: add dhcpd server role --- roles/dhcpd/README.md | 29 +++++++++++++++ roles/dhcpd/defaults/main.yml | 27 ++++++++++++++ roles/dhcpd/handlers/main.yml | 5 +++ roles/dhcpd/tasks/main.yml | 46 ++++++++++++++++++++++++ roles/dhcpd/templates/dhcpd.conf.j2 | 28 +++++++++++++++ roles/dhcpd/templates/isc-dhcp-server.j2 | 5 +++ roles/dhcpd/vars/archlinux.yml | 3 ++ roles/dhcpd/vars/debian.yml | 4 +++ 8 files changed, 147 insertions(+) create mode 100644 roles/dhcpd/README.md create mode 100644 roles/dhcpd/defaults/main.yml create mode 100644 roles/dhcpd/handlers/main.yml create mode 100644 roles/dhcpd/tasks/main.yml create mode 100644 roles/dhcpd/templates/dhcpd.conf.j2 create mode 100644 roles/dhcpd/templates/isc-dhcp-server.j2 create mode 100644 roles/dhcpd/vars/archlinux.yml create mode 100644 roles/dhcpd/vars/debian.yml diff --git a/roles/dhcpd/README.md b/roles/dhcpd/README.md new file mode 100644 index 0000000..984961e --- /dev/null +++ b/roles/dhcpd/README.md @@ -0,0 +1,29 @@ +# dhcpd + +ISC DHCP server role for Arch Linux and Debian/Ubuntu. + +## Requirements + +- `dhcpd_interface` must be defined in inventory + +## Configuration + +See [defaults/main.yml](defaults/main.yml) for all available variables. + +## Example + +```yaml +dhcpd_interface: "lan0" +dhcpd_subnet: "192.168.1.0" +dhcpd_range_start: "192.168.1.20" +dhcpd_range_end: "192.168.1.200" +dhcpd_gateway: "192.168.1.1" +dhcpd_dns_servers: + - "192.168.1.2" +dhcpd_domain_name: "home.lan" + +dhcpd_reservations: + - hostname: printer + mac: "aa:bb:cc:dd:ee:ff" + ip: "192.168.1.10" +``` diff --git a/roles/dhcpd/defaults/main.yml b/roles/dhcpd/defaults/main.yml new file mode 100644 index 0000000..681b00c --- /dev/null +++ b/roles/dhcpd/defaults/main.yml @@ -0,0 +1,27 @@ +# Network configuration +dhcpd_subnet: "192.168.1.0" +dhcpd_netmask: "255.255.255.0" +dhcpd_range_start: "192.168.1.20" +dhcpd_range_end: "192.168.1.200" +dhcpd_gateway: "192.168.1.1" +dhcpd_dns_servers: + - "1.1.1.1" + +# Lease times (in seconds) +dhcpd_default_lease_time: 86400 # 24 hours +dhcpd_max_lease_time: 172800 # 48 hours + +# Interface to listen on (required) +# dhcpd_interface: "lan0" + +# Domain name (optional) +# dhcpd_domain_name: "home.lan" + +# Static reservations +# dhcpd_reservations: +# - hostname: printer +# mac: "aa:bb:cc:dd:ee:ff" +# ip: "192.168.1.10" +# - hostname: nas +# mac: "11:22:33:44:55:66" +# ip: "192.168.1.2" diff --git a/roles/dhcpd/handlers/main.yml b/roles/dhcpd/handlers/main.yml new file mode 100644 index 0000000..e064390 --- /dev/null +++ b/roles/dhcpd/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart dhcpd + ansible.builtin.systemd: + name: "{{ dhcpd_service }}" + state: restarted diff --git a/roles/dhcpd/tasks/main.yml b/roles/dhcpd/tasks/main.yml new file mode 100644 index 0000000..79d2cdd --- /dev/null +++ b/roles/dhcpd/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- name: Validate required variables + ansible.builtin.assert: + that: + - dhcpd_interface is defined + - dhcpd_interface | length > 0 + fail_msg: | + dhcpd_interface is required. + See roles/dhcpd/defaults/main.yml for configuration instructions. + success_msg: "Variable validation passed" + +- name: Load OS-specific variables + ansible.builtin.include_vars: "{{ item }}" + with_first_found: + - "{{ ansible_facts['os_family'] | lower }}.yml" + - "debian.yml" + +- name: Install DHCP server + ansible.builtin.package: + name: "{{ dhcpd_package }}" + state: present + +- name: Deploy DHCP server configuration + ansible.builtin.template: + src: dhcpd.conf.j2 + dest: "{{ dhcpd_config_path }}" + owner: root + group: root + mode: "0644" + notify: Restart dhcpd + +- name: Configure interface for DHCP server (Debian) + ansible.builtin.template: + src: isc-dhcp-server.j2 + dest: "{{ dhcpd_defaults_path }}" + owner: root + group: root + mode: "0644" + when: ansible_facts['os_family'] | lower == 'debian' + notify: Restart dhcpd + +- name: Enable and start DHCP server + ansible.builtin.systemd: + name: "{{ dhcpd_service }}" + enabled: true + state: started diff --git a/roles/dhcpd/templates/dhcpd.conf.j2 b/roles/dhcpd/templates/dhcpd.conf.j2 new file mode 100644 index 0000000..3728cae --- /dev/null +++ b/roles/dhcpd/templates/dhcpd.conf.j2 @@ -0,0 +1,28 @@ +# {{ ansible_managed }} + +# Global options +default-lease-time {{ dhcpd_default_lease_time }}; +max-lease-time {{ dhcpd_max_lease_time }}; + +authoritative; + +{% if dhcpd_domain_name is defined %} +option domain-name "{{ dhcpd_domain_name }}"; +{% endif %} +option domain-name-servers {{ dhcpd_dns_servers | join(', ') }}; + +# Subnet configuration +subnet {{ dhcpd_subnet }} netmask {{ dhcpd_netmask }} { + range {{ dhcpd_range_start }} {{ dhcpd_range_end }}; + option routers {{ dhcpd_gateway }}; +} + +# Static reservations +{% if dhcpd_reservations is defined %} +{% for host in dhcpd_reservations %} +host {{ host.hostname }} { + hardware ethernet {{ host.mac }}; + fixed-address {{ host.ip }}; +} +{% endfor %} +{% endif %} diff --git a/roles/dhcpd/templates/isc-dhcp-server.j2 b/roles/dhcpd/templates/isc-dhcp-server.j2 new file mode 100644 index 0000000..89dfd99 --- /dev/null +++ b/roles/dhcpd/templates/isc-dhcp-server.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} +# Defaults for isc-dhcp-server + +INTERFACESv4="{{ dhcpd_interface }}" +INTERFACESv6="" diff --git a/roles/dhcpd/vars/archlinux.yml b/roles/dhcpd/vars/archlinux.yml new file mode 100644 index 0000000..7c3198e --- /dev/null +++ b/roles/dhcpd/vars/archlinux.yml @@ -0,0 +1,3 @@ +dhcpd_package: dhcp +dhcpd_service: dhcpd4 +dhcpd_config_path: /etc/dhcpd.conf diff --git a/roles/dhcpd/vars/debian.yml b/roles/dhcpd/vars/debian.yml new file mode 100644 index 0000000..9762379 --- /dev/null +++ b/roles/dhcpd/vars/debian.yml @@ -0,0 +1,4 @@ +dhcpd_package: isc-dhcp-server +dhcpd_service: isc-dhcp-server +dhcpd_config_path: /etc/dhcp/dhcpd.conf +dhcpd_defaults_path: /etc/default/isc-dhcp-server