diff options
Diffstat (limited to 'cloudinit/sources/DataSourceCloudStack.py')
-rw-r--r-- | cloudinit/sources/DataSourceCloudStack.py | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py index 2654df53..1335b63d 100644 --- a/cloudinit/sources/DataSourceCloudStack.py +++ b/cloudinit/sources/DataSourceCloudStack.py @@ -3,10 +3,12 @@ # Copyright (C) 2012 Canonical Ltd. # Copyright (C) 2012 Cosmin Luta # Copyright (C) 2012 Yahoo! Inc. +# Copyright (C) 2012 Gerard Dethier # # Author: Cosmin Luta <q4break@gmail.com> # Author: Scott Moser <scott.moser@canonical.com> # Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Gerard Dethier <g.dethier@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as @@ -20,9 +22,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from socket import inet_ntoa -from struct import pack - import os import time @@ -31,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__) @@ -40,24 +41,12 @@ class DataSourceCloudStack(sources.DataSource): sources.DataSource.__init__(self, sys_cfg, distro, paths) self.seed_dir = os.path.join(paths.seed_dir, 'cs') # Cloudstack has its metadata/userdata URLs located at - # http://<default-gateway-ip>/latest/ + # http://<virtual-router-ip>/latest/ self.api_ver = 'latest' - gw_addr = self.get_default_gateway() - if not gw_addr: - raise RuntimeError("No default gateway found!") - self.metadata_address = "http://%s/" % (gw_addr) - - def get_default_gateway(self): - """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 + vr_addr = get_vr_address() + if not vr_addr: + raise RuntimeError("No virtual router found!") + self.metadata_address = "http://%s/" % (vr_addr) def __str__(self): return util.obj_name(self) @@ -90,7 +79,7 @@ class DataSourceCloudStack(sources.DataSource): (max_wait, timeout) = self._get_url_settings() - urls = [self.metadata_address] + urls = [self.metadata_address + "/latest/meta-data/instance-id"] start_time = time.time() url = uhelp.wait_for_url(urls=urls, max_wait=max_wait, timeout=timeout, status_cb=LOG.warn) @@ -115,8 +104,14 @@ class DataSourceCloudStack(sources.DataSource): if not self.wait_for_metadata_service(): return False start_time = time.time() - self.userdata_raw = ec2_utils.get_instance_userdata(self.metadata_address, self.api_ver) - self.metadata = ec2_utils.get_instance_metadata(self.metadata_address, self.api_ver) + md_addr = self.metadata_address + ssl_details = util.fetch_ssl_details(self.paths) + self.userdata_raw = ec2_utils.get_instance_userdata(self.api_ver, + md_addr, + ssl_details) + self.metadata = ec2_utils.get_instance_metadata(self.api_ver, + md_addr, + ssl_details) LOG.debug("Crawl of metadata service took %s seconds", int(time.time() - start_time)) return True @@ -133,6 +128,72 @@ 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 leases + # see http://bit.ly/T76eKC for documentation on the virtual router. + # 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 datasources = [ (DataSourceCloudStack, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)), |