diff --git a/core/src/main/java/com/cloud/agent/api/routing/DhcpEntryCommand.java b/core/src/main/java/com/cloud/agent/api/routing/DhcpEntryCommand.java index 7fb65fe15cf9..67ca447e3853 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/DhcpEntryCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/DhcpEntryCommand.java @@ -36,6 +36,7 @@ public class DhcpEntryCommand extends NetworkElementCommand { private boolean isDefault; boolean executeInSequence = false; boolean remove; + Long leaseTime; public boolean isRemove() { return remove; @@ -152,4 +153,12 @@ public boolean isDefault() { public void setDefault(boolean isDefault) { this.isDefault = isDefault; } + + public Long getLeaseTime() { + return leaseTime; + } + + public void setLeaseTime(Long leaseTime) { + this.leaseTime = leaseTime; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/DhcpEntryConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/DhcpEntryConfigItem.java index 9c5b657bb4e4..041645046b23 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/DhcpEntryConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/DhcpEntryConfigItem.java @@ -35,7 +35,7 @@ public List generateConfig(final NetworkElementCommand cmd) { final DhcpEntryCommand command = (DhcpEntryCommand) cmd; final VmDhcpConfig vmDhcpConfig = new VmDhcpConfig(command.getVmName(), command.getVmMac(), command.getVmIpAddress(), command.getVmIp6Address(), command.getDuid(), command.getDefaultDns(), - command.getDefaultRouter(), command.getStaticRoutes(), command.isDefault(), command.isRemove()); + command.getDefaultRouter(), command.getStaticRoutes(), command.isDefault(), command.isRemove(), command.getLeaseTime()); return generateConfigItems(vmDhcpConfig); } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/VmDhcpConfig.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/VmDhcpConfig.java index d9cb8b0b2645..1c43cd1823b9 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/VmDhcpConfig.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/VmDhcpConfig.java @@ -29,6 +29,7 @@ public class VmDhcpConfig extends ConfigBase { private String defaultGateway; private String staticRoutes; private boolean defaultEntry; + private Long leaseTime; // Indicate if the entry should be removed when set to true private boolean remove; @@ -39,6 +40,11 @@ public VmDhcpConfig() { public VmDhcpConfig(String hostName, String macAddress, String ipv4Address, String ipv6Address, String ipv6Duid, String dnsAddresses, String defaultGateway, String staticRoutes, boolean defaultEntry, boolean remove) { + this(hostName, macAddress, ipv4Address, ipv6Address, ipv6Duid, dnsAddresses, defaultGateway, staticRoutes, defaultEntry, remove, null); + } + + public VmDhcpConfig(String hostName, String macAddress, String ipv4Address, String ipv6Address, String ipv6Duid, String dnsAddresses, String defaultGateway, + String staticRoutes, boolean defaultEntry, boolean remove, Long leaseTime) { super(VM_DHCP); this.hostName = hostName; this.macAddress = macAddress; @@ -50,6 +56,7 @@ public VmDhcpConfig(String hostName, String macAddress, String ipv4Address, Stri this.staticRoutes = staticRoutes; this.defaultEntry = defaultEntry; this.remove = remove; + this.leaseTime = leaseTime; } public String getHostName() { @@ -132,4 +139,12 @@ public void setDefaultEntry(boolean defaultEntry) { this.defaultEntry = defaultEntry; } + public Long getLeaseTime() { + return leaseTime; + } + + public void setLeaseTime(Long leaseTime) { + this.leaseTime = leaseTime; + } + } diff --git a/scripts/network/exdhcp/dhcpd_edithosts.py b/scripts/network/exdhcp/dhcpd_edithosts.py index 4df996dc0321..a0deae63a50b 100644 --- a/scripts/network/exdhcp/dhcpd_edithosts.py +++ b/scripts/network/exdhcp/dhcpd_edithosts.py @@ -17,18 +17,18 @@ # under the License. -# Usage: dhcpd_edithosts.py mac ip hostname dns gateway nextserver +# Usage: dhcpd_edithosts.py mac ip hostname dns gateway nextserver [leasetime] import sys, os from os.path import exists from time import sleep from os import remove -usage = '''dhcpd_edithosts.py mac ip hostname dns gateway nextserver''' +usage = '''dhcpd_edithosts.py mac ip hostname dns gateway nextserver [leasetime]''' conf_path = "/etc/dhcpd.conf" file_lock = "/etc/dhcpd.conf_locked" sleep_max = 20 -host_entry = 'host %s { hardware ethernet %s; fixed-address %s; option domain-name-servers %s; option domain-name "%s"; option routers %s; default-lease-time infinite; max-lease-time infinite; min-lease-time infinite; filename "pxelinux.0";}' -host_entry1 = 'host %s { hardware ethernet %s; fixed-address %s; option domain-name-servers %s; option domain-name "%s"; option routers %s; default-lease-time infinite; max-lease-time infinite; min-lease-time infinite; next-server %s; filename "pxelinux.0";}' +host_entry = 'host %s { hardware ethernet %s; fixed-address %s; option domain-name-servers %s; option domain-name "%s"; option routers %s; default-lease-time %s; max-lease-time %s; min-lease-time %s; filename "pxelinux.0";}' +host_entry1 = 'host %s { hardware ethernet %s; fixed-address %s; option domain-name-servers %s; option domain-name "%s"; option routers %s; default-lease-time %s; max-lease-time %s; min-lease-time %s; next-server %s; filename "pxelinux.0";}' def lock(): if exists(file_lock): count = 0 @@ -59,10 +59,14 @@ def unlock(): print "Cannot remove file lock at %s" % file_lock return False -def insert_host_entry(mac, ip, hostname, dns, gateway, next_server): +def insert_host_entry(mac, ip, hostname, dns, gateway, next_server, lease_time="infinite"): if lock() == False: return 1 + # Convert 0 to 'infinite' for lease time + if lease_time == "0": + lease_time = "infinite" + cmd = 'sed -i /"fixed-address %s"/d %s' % (ip, conf_path) ret = os.system(cmd) if ret != 0: @@ -78,9 +82,9 @@ def insert_host_entry(mac, ip, hostname, dns, gateway, next_server): return 1 if next_server != "null": - entry = host_entry1 % (hostname, mac, ip, dns, "cloudnine.internal", gateway, next_server) + entry = host_entry1 % (hostname, mac, ip, dns, "cloudnine.internal", gateway, lease_time, lease_time, lease_time, next_server) else: - entry = host_entry % (hostname, mac, ip, dns, "cloudnine.internal", gateway) + entry = host_entry % (hostname, mac, ip, dns, "cloudnine.internal", gateway, lease_time, lease_time, lease_time) cmd = '''echo '%s' >> %s''' % (entry, conf_path) ret = os.system(cmd) if ret != 0: @@ -111,6 +115,7 @@ def insert_host_entry(mac, ip, hostname, dns, gateway, next_server): dns = sys.argv[4] gateway = sys.argv[5] next_server = sys.argv[6] + lease_time = sys.argv[7] if len(sys.argv) > 7 else "infinite" if exists(conf_path) == False: conf_path = "/etc/dhcp/dhcpd.conf" @@ -118,5 +123,5 @@ def insert_host_entry(mac, ip, hostname, dns, gateway, next_server): print "Cannot find dhcpd.conf" sys.exit(1) - ret = insert_host_entry(mac, ip, hostname, dns, gateway, next_server) + ret = insert_host_entry(mac, ip, hostname, dns, gateway, next_server, lease_time) sys.exit(ret) diff --git a/scripts/network/exdhcp/dnsmasq_edithosts.sh b/scripts/network/exdhcp/dnsmasq_edithosts.sh index f0744a9a822b..522250d8622b 100755 --- a/scripts/network/exdhcp/dnsmasq_edithosts.sh +++ b/scripts/network/exdhcp/dnsmasq_edithosts.sh @@ -21,6 +21,7 @@ # $1 : the mac address # $2 : the associated ip address # $3 : the hostname +# $4 : the lease time (optional, defaults to 'infinite') wait_for_dnsmasq () { local _pid=$(pidof dnsmasq) @@ -41,11 +42,17 @@ no_dhcp_release=$? [ ! -f /etc/dhcphosts.txt ] && touch /etc/dhcphosts.txt [ ! -f /var/lib/misc/dnsmasq.leases ] && touch /var/lib/misc/dnsmasq.leases +# Set lease time, default to 'infinite', convert 0 to 'infinite' +lease_time=${4:-infinite} +if [ "$lease_time" = "0" ]; then + lease_time=infinite +fi + sed -i /$1/d /etc/dhcphosts.txt sed -i /$2,/d /etc/dhcphosts.txt sed -i /$3,/d /etc/dhcphosts.txt -echo "$1,$2,$3,infinite" >>/etc/dhcphosts.txt +echo "$1,$2,$3,$lease_time" >>/etc/dhcphosts.txt #release previous dhcp lease if present if [ $no_dhcp_release -eq 0 ] diff --git a/server/src/main/java/com/cloud/configuration/Config.java b/server/src/main/java/com/cloud/configuration/Config.java index abae4d3996cb..518c2168e9c2 100644 --- a/server/src/main/java/com/cloud/configuration/Config.java +++ b/server/src/main/java/com/cloud/configuration/Config.java @@ -351,6 +351,15 @@ public enum Config { ConfigKey.Kind.CSV, null), + DhcpLeaseTimeout( + "Network", + ManagementServer.class, + Integer.class, + "dhcp.lease.timeout", + "0", + "DHCP lease time in seconds for VMs. Use 0 for infinite lease time (default). A non-zero value sets the lease duration in seconds.", + null), + //VPN RemoteAccessVpnPskLength( "Network", diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index b915027e9ab3..78a2be99be5f 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -296,6 +296,11 @@ public void createDhcpEntryCommand(final VirtualRouter router, final UserVm vm, dhcpCommand.setDefault(nic.isDefaultNic()); dhcpCommand.setRemove(remove); + // Set DHCP lease timeout from global config (0 = infinite) + String leaseTimeStr = _configDao.getValue(Config.DhcpLeaseTimeout.key()); + Long leaseTime = (leaseTimeStr != null) ? Long.parseLong(leaseTimeStr) : 0L; + dhcpCommand.setLeaseTime(leaseTime); + dhcpCommand.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); dhcpCommand.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); dhcpCommand.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(nic.getNetworkId(), router.getId())); diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py index e15714af212f..9c048f40540e 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py @@ -199,12 +199,14 @@ def write_hosts(self): def add(self, entry): self.add_host(entry['ipv4_address'], entry['host_name']) - # Lease time set to "infinite" since we properly control all DHCP/DNS config via CloudStack. + # Lease time is configurable via CloudStack global config dhcp.lease.timeout + # 0 = infinite (default), otherwise the value represents seconds # Infinite time helps avoid some edge cases which could cause DHCPNAK being sent to VMs since # (RHEL) system lose routes when they receive DHCPNAK. # When VM is expunged, its active lease and DHCP/DNS config is properly removed from related files in VR, # so the infinite duration of lease does not cause any issues or garbage. - lease = 'infinite' + lease_time = entry.get('lease_time', 0) + lease = 'infinite' if lease_time == 0 else str(lease_time) if entry['default_entry']: self.dhcp_hosts.add("%s,%s,%s,%s" % (entry['mac_address'], diff --git a/systemvm/debian/opt/cloud/bin/edithosts.sh b/systemvm/debian/opt/cloud/bin/edithosts.sh index 6f66331c88e3..976f009c2b12 100755 --- a/systemvm/debian/opt/cloud/bin/edithosts.sh +++ b/systemvm/debian/opt/cloud/bin/edithosts.sh @@ -21,7 +21,7 @@ # edithosts.sh -- edit the dhcphosts file on the routing domain usage() { - printf "Usage: %s: -m -4 -6 -h -d -n -s -u [-N]\n" $(basename $0) >&2 + printf "Usage: %s: -m -4 -6 -h -d -n -s -u -l [-N]\n" $(basename $0) >&2 } mac= @@ -33,8 +33,9 @@ dns= routes= duid= nondefault= +lease_time=infinite -while getopts 'm:4:h:d:n:s:6:u:N' OPTION +while getopts 'm:4:h:d:n:s:6:u:l:N' OPTION do case $OPTION in m) mac="$OPTARG" @@ -53,6 +54,8 @@ do ;; s) routes="$OPTARG" ;; + l) lease_time="$OPTARG" + ;; N) nondefault=1 ;; ?) usage @@ -124,17 +127,21 @@ fi sed -i /$host,/d $DHCP_HOSTS #put in the new entry +# If lease_time is 0, use 'infinite', otherwise use the value +if [ "$lease_time" = "0" ]; then + lease_time=infinite +fi if [ $ipv4 ] then - echo "$mac,$ipv4,$host,infinite" >>$DHCP_HOSTS + echo "$mac,$ipv4,$host,$lease_time" >>$DHCP_HOSTS fi if [ $ipv6 ] then if [ $nondefault ] then - echo "id:$duid,set:nondefault6,[$ipv6],$host,infinite" >>$DHCP_HOSTS + echo "id:$duid,set:nondefault6,[$ipv6],$host,$lease_time" >>$DHCP_HOSTS else - echo "id:$duid,[$ipv6],$host,infinite" >>$DHCP_HOSTS + echo "id:$duid,[$ipv6],$host,$lease_time" >>$DHCP_HOSTS fi fi