This is an automated email from the ASF dual-hosted git repository.

harikrishna-patnala pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.20 by this push:
     new 5432a04ae6e Ensure VM IP is removed from VR DHCP records in 
dnsmasq.leases after expunge VM (#13194)
5432a04ae6e is described below

commit 5432a04ae6e053658ae58c12867408cef9d12935
Author: Suresh Kumar Anaparti <[email protected]>
AuthorDate: Mon Aug 17 13:22:46 2026 +0530

    Ensure VM IP is removed from VR DHCP records in dnsmasq.leases after 
expunge VM (#13194)
    
    * Ensure VM IP is removed from VR DHCP records in dnsmasq.leases after 
expunge VM
    
    This also reverts the PR #10183 changes (for #10182), in turn resulting in 
#11877.
    
    * review changes
---
 systemvm/debian/opt/cloud/bin/cs/CsDhcp.py | 67 +++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py 
b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py
index 574a352b5f3..c067fd349e8 100755
--- a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py
+++ b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py
@@ -20,6 +20,9 @@ import os
 from netaddr import *
 from random import randint
 import json
+import fcntl
+import shutil
+import tempfile
 from .CsGuestNetwork import CsGuestNetwork
 from cs.CsDatabag import CsDataBag
 from cs.CsFile import CsFile
@@ -139,7 +142,8 @@ class CsDhcp(CsDataBag):
             # Listen Address
             if self.cl.is_redundant():
                 listen_address.append(gateway)
-            listen_address.append(ip)
+            else:
+                listen_address.append(ip)
             # Add localized "data-server" records in /etc/hosts for VPC routers
             if self.config.is_vpc() or self.config.is_router():
                 self.add_host(gateway, "%s data-server" % 
CsHelper.get_hostname())
@@ -165,15 +169,76 @@ class CsDhcp(CsDataBag):
                 mac = lease[1]
                 ip = lease[2]
                 if mac not in macs_dhcphosts:
+                    logging.info("Releasing DHCP lease for IP: %s, mac: %s", 
ip, mac)
                     cmd = "dhcp_release $(ip route get %s | grep eth | head -1 
| awk '{print $3}') %s %s" % (ip, ip, mac)
                     logging.info(cmd)
                     CsHelper.execute(cmd)
+                    if self.ensure_lease_removed(ip):
+                        logging.info("Lease for %s still existed after 
dhcp_release; removed manually", ip)
                     removed = removed + 1
                     self.del_host(ip)
             logging.info("Deleted %s entries from dnsmasq.leases file" % 
str(removed))
         except Exception as e:
             logging.error("Caught error while trying to delete entries from 
dnsmasq.leases file: %s" % e)
 
+    def lease_exists(self, ip):
+        if not os.path.exists(LEASES):
+            return False
+
+        with open(LEASES, "r") as fp:
+            for line in fp:
+                fields = line.split()
+                if len(fields) >= 3 and fields[2] == ip:
+                    return True
+
+        return False
+
+    def remove_lease(self, ip):
+        if not os.path.exists(LEASES):
+            return False
+
+        removed = False
+
+        with open(LEASES, "r+") as fp:
+            fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
+            lines = fp.readlines()
+
+            fd, tmp_path = tempfile.mkstemp(
+                prefix="dnsmasq.leases.",
+                dir=os.path.dirname(LEASES)
+            )
+
+            try:
+                with os.fdopen(fd, "w") as tmp:
+                    for line in lines:
+                        fields = line.split()
+
+                        if len(fields) >= 3 and fields[2] == ip:
+                            removed = True
+                            continue
+
+                        tmp.write(line)
+
+                if removed:
+                    shutil.move(tmp_path, LEASES)
+
+                    # reload dnsmasq
+                    try:
+                        CsHelper.service("dnsmasq", "reload")
+                    except Exception:
+                        pass
+                else:
+                    os.remove(tmp_path)
+            finally:
+                fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
+
+        return removed
+
+    def ensure_lease_removed(self, ip):
+        if self.lease_exists(ip):
+            return self.remove_lease(ip)
+        return False
+
     def preseed(self):
         self.add_host("127.0.0.1", "localhost")
         self.add_host("127.0.1.1", "%s" % CsHelper.get_hostname())

Reply via email to