summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--cloudinit/sources/DataSourceCloudStack.py82
2 files changed, 68 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 9534be26..18e25725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,8 +11,10 @@
- support omnibus installer for chef [Anatoliy Dobrosynets]
- fix bug where cloud-config in user-data could not modify system_info
settings (LP: #1090482)
- - fix CloudStack DataSource to use Virtual Router as found in
- /var/lib/dhcpclient rather than default gateway (LP: #1089989)
+ - fix CloudStack DataSource to use Virtual Router as described by
+ CloudStack documentation if it is available by searching through dhclient
+ lease files. If it is not available, then fall back to the default
+ gateway. (LP: #1089989)
- fix redaction of password field in log (LP: #1096417)
- fix to cloud-config user setup. Previously, lock_passwd was broken and
all accounts would be locked unless 'system' was given (LP: #1096423).
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py
index 82e1e130..275caf0d 100644
--- a/cloudinit/sources/DataSourceCloudStack.py
+++ b/cloudinit/sources/DataSourceCloudStack.py
@@ -30,6 +30,8 @@ from cloudinit import log as logging
from cloudinit import sources
from cloudinit import url_helper as uhelp
from cloudinit import util
+from socket import inet_ntoa
+from struct import pack
LOG = logging.getLogger(__name__)
@@ -122,26 +124,70 @@ class DataSourceCloudStack(sources.DataSource):
return self.metadata['availability-zone']
+def get_default_gateway():
+ # Returns the default gateway ip address in the dotted format.
+ lines = util.load_file("/proc/net/route").splitlines()
+ for line in lines:
+ items = line.split("\t")
+ if items[1] == "00000000":
+ # Found the default route, get the gateway
+ gw = inet_ntoa(pack("<L", int(items[2], 16)))
+ LOG.debug("Found default route, gateway is %s", gw)
+ return gw
+ return None
+
+
+def get_dhclient_d():
+ # find lease files directory
+ supported_dirs = ["/var/lib/dhclient", "/var/lib/dhcp"]
+ for d in supported_dirs:
+ if os.path.exists(d):
+ LOG.debug("Using %s lease directory", d)
+ return d
+ return None
+
+
+def get_latest_lease():
+ # find latest lease file
+ lease_d = get_dhclient_d()
+ if not lease_d:
+ return None
+ lease_files = os.listdir(lease_d)
+ latest_mtime = -1
+ latest_file = None
+ for file_name in lease_files:
+ if file_name.endswith(".lease") or file_name.endswith(".leases"):
+ abs_path = os.path.join(lease_d, file_name)
+ mtime = os.path.getmtime(abs_path)
+ if mtime > latest_mtime:
+ latest_mtime = mtime
+ latest_file = abs_path
+ return latest_file
+
+
def get_vr_address():
- # get the address of the virtual router via dhcp responses
+ # Get the address of the virtual router via dhcp leases
# see http://bit.ly/T76eKC for documentation on the virtual router.
- dhclient_d = "/var/lib/dhclient"
- addresses = set()
- dhclient_files = os.listdir(dhclient_d)
- for file_name in dhclient_files:
- if file_name.endswith(".lease") or file_name.endswith(".leases"):
- with open(os.path.join(dhclient_d, file_name), "r") as fd:
- for line in fd:
- if "dhcp-server-identifier" in line:
- words = line.strip(" ;\r\n").split(" ")
- if len(words) > 2:
- dhcp = words[2]
- LOG.debug("Found DHCP identifier %s", dhcp)
- addresses.add(dhcp)
- if len(addresses) != 1:
- # No unique virtual router found
- return None
- return addresses.pop()
+ # If no virtual router is detected, fallback on default gateway.
+ lease_file = get_latest_lease()
+ if not lease_file:
+ LOG.debug("No lease file found, using default gateway")
+ return get_default_gateway()
+
+ latest_address = None
+ with open(lease_file, "r") as fd:
+ for line in fd:
+ if "dhcp-server-identifier" in line:
+ words = line.strip(" ;\r\n").split(" ")
+ if len(words) > 2:
+ dhcp = words[2]
+ LOG.debug("Found DHCP identifier %s", dhcp)
+ latest_address = dhcp
+ if not latest_address:
+ # No virtual router found, fallback on default gateway
+ LOG.debug("No DHCP found, using default gateway")
+ return get_default_gateway()
+ return latest_address
# Used to match classes to dependencies