diff --git a/cloudbaseinit/metadata/services/httpservice.py b/cloudbaseinit/metadata/services/httpservice.py index 93ae547b..3cef1786 100644 --- a/cloudbaseinit/metadata/services/httpservice.py +++ b/cloudbaseinit/metadata/services/httpservice.py @@ -16,10 +16,12 @@ import posixpath import urllib2 +import urlparse from cloudbaseinit.metadata.services import base from cloudbaseinit.openstack.common import cfg from cloudbaseinit.openstack.common import log as logging +from cloudbaseinit.osutils import factory as osutils_factory opts = [ cfg.StrOpt('metadata_base_url', default='http://169.254.169.254/', @@ -37,8 +39,38 @@ class HttpService(base.BaseMetadataService): super(HttpService, self).__init__() self._enable_retry = True + def _check_metadata_ip_route(self): + ''' + Workaround for: https://bugs.launchpad.net/quantum/+bug/1174657 + ''' + osutils = osutils_factory.OSUtilsFactory().get_os_utils() + + os_major_version = int(osutils.get_os_version().split('.')[0]) + if os_major_version >= 6: + # 169.254.x.x addresses are not getting routed starting from + # Windows Vista / 2008 + metadata_netloc = urlparse.urlparse(CONF.metadata_base_url).netloc + metadata_host = metadata_netloc.split(':')[0] + + if metadata_host.startswith("169.254."): + if not osutils.check_static_route_exists(metadata_host): + (interface_index, gateway) = osutils.get_default_gateway() + if gateway: + try: + osutils.add_static_route(metadata_host, + "255.255.255.255", + gateway, + interface_index, + 10) + except Exception, ex: + # Ignore it + LOG.exception(ex) + def load(self): super(HttpService, self).load() + + self._check_metadata_ip_route() + try: self.get_meta_data('openstack') return True diff --git a/cloudbaseinit/osutils/base.py b/cloudbaseinit/osutils/base.py index 165309dd..1bf3d7d7 100644 --- a/cloudbaseinit/osutils/base.py +++ b/cloudbaseinit/osutils/base.py @@ -69,3 +69,16 @@ class BaseOSUtils(object): def terminate(self): pass + + def get_default_gateway(self): + pass + + def check_static_route_exists(self, destination): + pass + + def add_static_route(self, destination, mask, next_hop, interface_index, + metric): + pass + + def get_os_version(self): + pass diff --git a/cloudbaseinit/osutils/windows.py b/cloudbaseinit/osutils/windows.py index e00803e0..d96c523b 100644 --- a/cloudbaseinit/osutils/windows.py +++ b/cloudbaseinit/osutils/windows.py @@ -327,3 +327,48 @@ class WindowsUtils(base.BaseOSUtils): # is not enough time.sleep(3) self._stop_service(self._service_name) + + def get_default_gateway(self): + conn = wmi.WMI(moniker='//./root/cimv2') + for net_adapter_config in conn.Win32_NetworkAdapterConfiguration(): + if net_adapter_config.DefaultIPGateway: + return (net_adapter_config.InterfaceIndex, + net_adapter_config.DefaultIPGateway[0]) + return (None, None) + + def check_static_route_exists(self, destination): + conn = wmi.WMI(moniker='//./root/cimv2') + return len(conn.Win32_IP4RouteTable(Destination=destination)) > 0 + + def add_static_route(self, destination, mask, next_hop, interface_index, + metric): + args = ['ROUTE', 'ADD', destination, 'MASK', mask, next_hop] + (out, err, ret_val) = self.execute_process(args) + # Cannot use the return value to determine the outcome + if err: + raise Exception('Unable to add route: %(err)s' % locals()) + + # TODO(alexpilotti): The following code creates the route properly and + # "route print" shows the added route, but routing to the destination + # fails. This option would be preferable compared to spawning a + # "ROUTE ADD" process. + ''' + ROUTE_PROTOCOL_NETMGMT = 3 + ROUTE_TYPE_INDIRECT = 4 + + conn = wmi.WMI(moniker='//./root/cimv2') + + route = conn.Win32_IP4RouteTable.SpawnInstance_() + route.Destination = destination + route.Mask = mask + route.NextHop = next_hop + route.InterfaceIndex = interface_index + route.Metric1 = metric + route.Protocol = self.ROUTE_PROTOCOL_NETMGMT + route.Type = self.ROUTE_TYPE_INDIRECT + route.Put_() + ''' + + def get_os_version(self): + conn = wmi.WMI(moniker='//./root/cimv2') + return conn.Win32_OperatingSystem()[0].Version