Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: dhcpv4 Module #84

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions molecule/services_dhcpv4/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
- name: converge
hosts: all
become: true
tasks:
- name: Converge - Enable DHCP Server on LAN interface
puzzle.opnsense.services_dhcpv4:
interface: lan
enable: true
range_from: 10.2.0.100
range_to: 10.2.0.200
67 changes: 67 additions & 0 deletions molecule/services_dhcpv4/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
scenario:
name: services_dhcpv4
test_sequence:
# - dependency not relevant unless we have requirements
- destroy
- syntax
- create
- converge
- idempotence
- verify
- destroy

driver:
name: vagrant
parallel: true

platforms:
- name: "22.7"
hostname: false
box: puzzle/opnsense
box_version: "22.7"
memory: 1024
cpus: 2
instance_raw_config_args:
- 'vm.guest = :freebsd'
- 'ssh.sudo_command = "%c"'
- 'ssh.shell = "/bin/sh"'
- name: "23.1"
box: puzzle/opnsense
hostname: false
box_version: "23.1"
memory: 1024
cpus: 2
instance_raw_config_args:
- 'vm.guest = :freebsd'
- 'ssh.sudo_command = "%c"'
- 'ssh.shell = "/bin/sh"'
- name: "23.7"
box: puzzle/opnsense
hostname: false
box_version: "23.7"
memory: 1024
cpus: 2
instance_raw_config_args:
- 'vm.guest = :freebsd'
- 'ssh.sudo_command = "%c"'
- 'ssh.shell = "/bin/sh"'
- name: "24.1"
box: puzzle/opnsense
hostname: false
box_version: "24.1"
memory: 1024
cpus: 2
instance_raw_config_args:
- 'vm.guest = :freebsd'
- 'ssh.sudo_command = "%c"'
- 'ssh.shell = "/bin/sh"'

provisioner:
name: ansible
env:
ANSIBLE_VERBOSITY: 3
verifier:
name: ansible
options:
become: true
6 changes: 6 additions & 0 deletions molecule/services_dhcpv4/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Verify connectivity to server
hosts: all
tasks:
- name: Ping the server
ansible.builtin.ping:
59 changes: 59 additions & 0 deletions plugins/module_utils/module_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@
},
},
},
"services_dhcpv4": {
"enable": "/enable",
"range_from": "/range/from",
"range_to": "/range/to",
# Add other mappings here.
"php_requirements": [
"",
],
"configure_functions": {
"reconfigure_dhcpd": {
"name": "reconfigure_dhcpd",
"configure_params": ["true"],
},
},
},
"interfaces_assignments": {
"interfaces": "interfaces",
# Add other mappings here.
Expand Down Expand Up @@ -278,6 +293,21 @@
},
},
},
"services_dhcpv4": {
"enable": "/enable",
"range_from": "/range/from",
"range_to": "/range/to",
# Add other mappings here.
"php_requirements": [
"",
],
"configure_functions": {
"reconfigure_dhcpd": {
"name": "reconfigure_dhcpd",
"configure_params": ["true"],
},
},
},
},
"23.7": {
"system_settings_general": {
Expand Down Expand Up @@ -403,6 +433,21 @@
},
},
},
"services_dhcpv4": {
"enable": "/enable",
"range_from": "/range/from",
"range_to": "/range/to",
# Add other mappings here.
"php_requirements": [
"",
],
"configure_functions": {
"reconfigure_dhcpd": {
"name": "reconfigure_dhcpd",
"configure_params": ["true"],
},
},
},
},
"24.1": {
"system_settings_general": {
Expand Down Expand Up @@ -527,6 +572,20 @@
"name": "filter_configure",
"configure_params": [],
},
},
"services_dhcpv4": {
"enable": "/enable",
"range_from": "/range/from",
"range_to": "/range/to",
# Add other mappings here.
"php_requirements": [
"",
],
"configure_functions": {
"reconfigure_dhcpd": {
"name": "reconfigure_dhcpd",
"configure_params": ["true"],
},
},
},
},
Expand Down
15 changes: 15 additions & 0 deletions plugins/module_utils/services_dhcpv4_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from ansible_collections.puzzle.opnsense.plugins.module_utils import (
xml_utils,
opnsense_utils,
)
from ansible_collections.puzzle.opnsense.plugins.module_utils.config_utils import (
OPNsenseModuleConfig,
)

class DHCPv4Set(OPNsenseModuleConfig):
def __init__(self, interface, path: str = "/conf/config.xml"):
super().__init__(
module_name="services_dhcpv4",
config_context_names=["services_dhcpv4", "enable", "range_from", "range_to"],
path=interface + path,
)
141 changes: 141 additions & 0 deletions plugins/modules/services_dhcpv4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2024, Lukas Grimm <[email protected]>, Puzzle ITC
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

"""services_dhcpv4 module: Module to configure dhcpv4"""

__metaclass__ = type


# https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html
# fmt: off
DOCUMENTATION = r'''
---
author:
- Lukas Grimm (@ombre8)
module: services_dhcpv4
short_description: Configure DHCP server for specific Interface.
description:
- Module to configure general system settings
options:
interface:
description: "The Interface the DHCP server should be configured on"
type: str
required: true
enable:
description: Wheter the Server is enabled or not
type: bool
default: true
required: false
range_from:
description: Start of the IP Pool
type: str
required: false
range_to:
description: End of the IP Pool
type: str
required: false
'''

EXAMPLES = r'''
---
- name: Enable DHCP Server on LAN interface
puzzle.opnsense.services_dhcpv4:
interface: LAN

- name: Enable DHCP Server on guestwifi interface
puzzle.opnsense.services_dhcpv4:
interface: guestwifi
enable: true
range_from: 192.168.10.100
range_to: 192.168.10.254
'''

RETURN = '''
opnsense_configure_output:
description: A List of the executed OPNsense configure function along with their respective stdout, stderr and rc
returned: always
type: list
sample:
- function: reconfigure_dhcpd
params:
- 'true'
rc: 0
stderr: ''
stderr_lines: []
stdout: ''
stdout_lines: []
'''
# fmt: on

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.puzzle.opnsense.plugins.module_utils.service_dhcpv4_utils import (
DHCPv4Set,
)


def main():
"""
Main function of the services_dhcpv4 module
"""

module_args = {
"interface": {"type": "string", "required": True},
"enable": {"type": "bool", "default": True, "required": False},
"range_from": {"type": "string", "required": False},
"range_to": {"type": "string", "required": False},
}

module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True,
)

result = {
"changed": False,
"invocation": module.params,
"diff": None,
}

interface = module.params.get("interface")
enable = module.params.get("enable")
range_from = module.params.get("range_from")
range_to = module.params.get("range_to")

with DHCPv4Set(
module_name="services_dhcpv4",
config_context_names=["services_dhcpv4"],
interface=interface,
check_mode=module.check_mode,
) as config:
if enable != config.get("enable").text:
config.set(value=str(enable), setting="enable")

if range_from != config.get("range_from").text:
config.set(value=str(range_from), setting="range_from")

if range_to != config.get("range_to").text:
config.set(value=str(range_to), setting="range_to")

if config.changed:
result["diff"] = config.diff
result["changed"] = True

if config.changed and not module.check_mode:
config.save()
result["opnsense_configure_output"] = config.apply_settings()
for cmd_result in result["opnsense_configure_output"]:
if cmd_result["rc"] != 0:
module.fail_json(
msg="Apply of the OPNsense settings failed",
details=cmd_result,
)

# Return results
module.exit_json(**result)


if __name__ == "__main__":
main()