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
From 0920121eed97889ff33ef84f04a3730242ccb04b Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Fri, 8 Mar 2024 16:36:25 +0100
Subject: dhcp: T3316: De-duplicate Kea control socket variable
---
python/vyos/kea.py | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/python/vyos/kea.py b/python/vyos/kea.py
index 5aa91e652..89ae7ca81 100644
--- a/python/vyos/kea.py
+++ b/python/vyos/kea.py
@@ -56,6 +56,8 @@ kea6_options = {
'captive_portal': 'v6-captive-portal'
}
+kea_ctrl_socket = '/run/kea/dhcp{inet}-ctrl-socket'
+
def kea_parse_options(config):
options = []
@@ -294,7 +296,9 @@ def kea6_parse_subnet(subnet, config):
return out
-def _ctrl_socket_command(path, command, args=None):
+def _ctrl_socket_command(inet, command, args=None):
+ path = kea_ctrl_socket.format(inet=inet)
+
if not os.path.exists(path):
return None
@@ -319,9 +323,7 @@ def _ctrl_socket_command(path, command, args=None):
return json.loads(result.decode('utf-8'))
def kea_get_leases(inet):
- ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
-
- leases = _ctrl_socket_command(ctrl_socket, f'lease{inet}-get-all')
+ leases = _ctrl_socket_command(inet, f'lease{inet}-get-all')
if not leases or 'result' not in leases or leases['result'] != 0:
return []
@@ -329,11 +331,9 @@ 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)
+ result = _ctrl_socket_command(inet, f'lease{inet}-del', args)
if result and 'result' in result:
return result['result'] == 0
@@ -341,9 +341,7 @@ def kea_delete_lease(inet, ip_address):
return False
def kea_get_active_config(inet):
- ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
-
- config = _ctrl_socket_command(ctrl_socket, 'config-get')
+ config = _ctrl_socket_command(inet, 'config-get')
if not config or 'result' not in config or config['result'] != 0:
return None
--
cgit v1.2.3