From c55140f8bbd8e8f0e7c112a419027b65d479add6 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Wed, 6 Mar 2024 21:53:46 +0100
Subject: dhcp: T6102: Fix clear DHCP lease op-mode
* Add `clear dhcpv6-server lease`
* Standardize using vyos.opmode
---
op-mode-definitions/clear-dhcp-server-lease.xml.in | 20 -----
op-mode-definitions/dhcp.xml.in | 30 ++++++++
python/vyos/kea.py | 12 +++
src/op_mode/clear_dhcp_lease.py | 88 ----------------------
src/op_mode/dhcp.py | 23 ++++++
5 files changed, 65 insertions(+), 108 deletions(-)
delete mode 100644 op-mode-definitions/clear-dhcp-server-lease.xml.in
delete mode 100755 src/op_mode/clear_dhcp_lease.py
diff --git a/op-mode-definitions/clear-dhcp-server-lease.xml.in b/op-mode-definitions/clear-dhcp-server-lease.xml.in
deleted file mode 100644
index aef0eb22a..000000000
--- a/op-mode-definitions/clear-dhcp-server-lease.xml.in
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
- Clear DHCP server lease
-
-
-
-
- DHCP server lease
-
- sudo ${vyos_op_scripts_dir}/clear_dhcp_lease.py --ip $4
-
-
-
-
-
-
diff --git a/op-mode-definitions/dhcp.xml.in b/op-mode-definitions/dhcp.xml.in
index 0db7471e5..3c42c8e8f 100644
--- a/op-mode-definitions/dhcp.xml.in
+++ b/op-mode-definitions/dhcp.xml.in
@@ -1,5 +1,35 @@
+
+
+
+
+ Clear DHCP server lease
+
+
+
+
+ DHCP server lease
+
+ ${vyos_op_scripts_dir}/dhcp.py clear_dhcp_server_lease --family inet --address $4
+
+
+
+
+
+ Clear DHCPv6 server lease
+
+
+
+
+ DHCPv6 server lease
+
+ ${vyos_op_scripts_dir}/dhcp.py clear_dhcp_server_lease --family inet6 --address $4
+
+
+
+
+
diff --git a/python/vyos/kea.py b/python/vyos/kea.py
index 2328d0b00..5aa91e652 100644
--- a/python/vyos/kea.py
+++ b/python/vyos/kea.py
@@ -328,6 +328,18 @@ def kea_get_leases(inet):
return leases['arguments']['leases']
+def kea_delete_lease(inet, ip_address):
+ ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
+
+ args = {'ip-address': ip_address}
+
+ result = _ctrl_socket_command(ctrl_socket, f'lease{inet}-del', args)
+
+ if result and 'result' in result:
+ return result['result'] == 0
+
+ return False
+
def kea_get_active_config(inet):
ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
diff --git a/src/op_mode/clear_dhcp_lease.py b/src/op_mode/clear_dhcp_lease.py
deleted file mode 100755
index 7d4b47104..000000000
--- a/src/op_mode/clear_dhcp_lease.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2023 VyOS maintainers and contributors
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library. If not, see .
-
-import argparse
-import re
-
-from vyos.configquery import ConfigTreeQuery
-from vyos.kea import kea_parse_leases
-from vyos.utils.io import ask_yes_no
-from vyos.utils.process import call
-from vyos.utils.commit import commit_in_progress
-
-# TODO: Update to use Kea control socket command "lease4-del"
-
-config = ConfigTreeQuery()
-base = ['service', 'dhcp-server']
-lease_file = '/config/dhcp/dhcp4-leases.csv'
-
-
-def del_lease_ip(address):
- """
- Read lease_file and write data to this file
- without specific section "lease ip"
- Delete section "lease x.x.x.x { x;x;x; }"
- """
- with open(lease_file, encoding='utf-8') as f:
- data = f.read().rstrip()
- pattern = rf"^{address},[^\n]+\n"
- # Delete lease for ip block
- data = re.sub(pattern, '', data)
-
- # Write new data to original lease_file
- with open(lease_file, 'w', encoding='utf-8') as f:
- f.write(data)
-
-def is_ip_in_leases(address):
- """
- Return True if address found in the lease file
- """
- leases = kea_parse_leases(lease_file)
- for lease in leases:
- if address == lease['address']:
- return True
- print(f'Address "{address}" not found in "{lease_file}"')
- return False
-
-if not config.exists(base):
- print('DHCP-server not configured!')
- exit(0)
-
-if config.exists(base + ['failover']):
- print('Lease cannot be reset in failover mode!')
- exit(0)
-
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser()
- parser.add_argument('--ip', help='IPv4 address', action='store', required=True)
-
- args = parser.parse_args()
- address = args.ip
-
- if not is_ip_in_leases(address):
- exit(1)
-
- if commit_in_progress():
- print('Cannot clear DHCP lease while a commit is in progress')
- exit(1)
-
- if not ask_yes_no(f'This will restart DHCP server.\nContinue?'):
- exit(1)
- else:
- del_lease_ip(address)
- call('systemctl restart kea-dhcp4-server.service')
diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py
index 1d9ad0e76..d27e1baf7 100755
--- a/src/op_mode/dhcp.py
+++ b/src/op_mode/dhcp.py
@@ -31,6 +31,7 @@ from vyos.configquery import ConfigTreeQuery
from vyos.kea import kea_get_active_config
from vyos.kea import kea_get_leases
from vyos.kea import kea_get_pool_from_subnet_id
+from vyos.kea import kea_delete_lease
from vyos.utils.process import is_systemd_service_running
time_string = "%a %b %d %H:%M:%S %Z %Y"
@@ -360,6 +361,28 @@ def show_server_static_mappings(raw: bool, family: ArgFamily, pool: typing.Optio
else:
return _get_formatted_server_static_mappings(static_mappings, family=family)
+def _lease_valid(inet, address):
+ leases = kea_get_leases(inet)
+ for lease in leases:
+ if address == lease['ip-address']:
+ return True
+ return False
+
+@_verify
+def clear_dhcp_server_lease(family: ArgFamily, address: str):
+ v = 'v6' if family == 'inet6' else ''
+ inet = '6' if family == 'inet6' else '4'
+
+ if not _lease_valid(inet, address):
+ print(f'Lease not found on DHCP{v} server')
+ return None
+
+ if not kea_delete_lease(inet, address):
+ print(f'Failed to clear lease for "{address}"')
+ return None
+
+ print(f'Lease "{address}" has been cleared')
+
def _get_raw_client_leases(family='inet', interface=None):
from time import mktime
from datetime import datetime
--
cgit v1.2.3