From 7ed0fa3092744a8fe9d0b9ebd2d126e5e07b6285 Mon Sep 17 00:00:00 2001
From: Viacheslav Hletenko <v.gletenko@vyos.io>
Date: Wed, 15 Jun 2022 12:32:07 +0000
Subject: op-mode: T1375: Allow to clear dhcp-server lease

Allow to reset dhcp-leases per ip
Parse file '/config/dhcpd.leases' find match section 'lease x.x.x.x {}'
And remove this section

clear dhcp-server lease 192.0.2.21

(cherry picked from commit a83eecfeee1f925c914a46623dd35f96b48389f8)
---
 src/op_mode/clear_dhcp_lease.py | 73 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100755 src/op_mode/clear_dhcp_lease.py

(limited to 'src/op_mode')

diff --git a/src/op_mode/clear_dhcp_lease.py b/src/op_mode/clear_dhcp_lease.py
new file mode 100755
index 000000000..6ac3d4c1c
--- /dev/null
+++ b/src/op_mode/clear_dhcp_lease.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+
+import argparse
+import re
+
+from isc_dhcp_leases import Lease
+from isc_dhcp_leases import IscDhcpLeases
+
+from vyos.configquery import ConfigTreeQuery
+from vyos.util import ask_yes_no
+from vyos.util import call
+
+
+config = ConfigTreeQuery()
+base = ['service', 'dhcp-server']
+lease_file = '/config/dhcpd.leases'
+
+
+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()
+        lease_config_ip = '{(?P<config>[\s\S]+?)\n}'
+        pattern = rf"lease {address} {lease_config_ip}"
+        # 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 = IscDhcpLeases(lease_file)
+    lease_ips = []
+    for lease in leases.get():
+        lease_ips.append(lease.ip)
+    if address not in lease_ips:
+        print(f'Address "{address}" not found in "{lease_file}"')
+        return False
+    return True
+
+
+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 not ask_yes_no(f'This will restart DHCP server.\nContinue?'):
+        exit(1)
+    else:
+        del_lease_ip(address)
+        call('systemctl restart isc-dhcp-server.service')
-- 
cgit v1.2.3