summaryrefslogtreecommitdiff
path: root/ironic_python_agent/agent.py
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@redhat.com>2016-03-17 17:49:36 +0100
committerSam Betts <sam@code-smash.net>2016-03-21 14:21:12 +0000
commit6829d34c150fa1cd41064786e76d41dfccef3ef3 (patch)
tree4adcc814b400607057f8ac1c8b9369187bc513fd /ironic_python_agent/agent.py
parent7a24ba85a9b3204485245030ff92f787a2e87a4e (diff)
downloadironic-python-agent-6829d34c150fa1cd41064786e76d41dfccef3ef3.tar.gz
Bind to interface routable to the ironic host, not a random one
Binding to the first interface that has an IP address is error-prone: there is no guarantee that ironic can reach us via this inteface. It is much safer to detect the interface facing ironic and bind to it. Unused LookupAgentInterfaceError exception is deleted. The TinyIPA build also requires iptables dependency at build time to insert the required kernel modules. Closes-Bug: #1558956 Change-Id: I9586805e6c7f52a50834bc03efeb72d1faa6cb65
Diffstat (limited to 'ironic_python_agent/agent.py')
-rw-r--r--ironic_python_agent/agent.py83
1 files changed, 44 insertions, 39 deletions
diff --git a/ironic_python_agent/agent.py b/ironic_python_agent/agent.py
index 1716edac..75a7e8aa 100644
--- a/ironic_python_agent/agent.py
+++ b/ironic_python_agent/agent.py
@@ -15,11 +15,14 @@
import os
import random
import select
+import socket
import threading
import time
+from oslo_concurrency import processutils
from oslo_log import log
import pkg_resources
+from six.moves.urllib import parse as urlparse
from stevedore import extension
from wsgiref import simple_server
@@ -30,6 +33,7 @@ from ironic_python_agent.extensions import base
from ironic_python_agent import hardware
from ironic_python_agent import inspector
from ironic_python_agent import ironic_api_client
+from ironic_python_agent import utils
LOG = log.getLogger(__name__)
@@ -183,6 +187,21 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
version=self.version
)
+ def _get_route_source(self, dest):
+ """Get the IP address to send packages to destination."""
+ try:
+ out, _err = utils.execute('ip', 'route', 'get', dest)
+ except (EnvironmentError, processutils.ProcessExecutionError) as e:
+ LOG.warning('Cannot get route to host %(dest)s: %(err)s',
+ {'dest': dest, 'err': e})
+ return
+
+ try:
+ return out.strip().split('\n')[0].split('src')[1].strip()
+ except IndexError:
+ LOG.warning('No route to host %(dest)s, route record: %(rec)s',
+ {'dest': dest, 'rec': out})
+
def set_agent_advertise_addr(self):
"""Set advertised IP address for the agent, if not already set.
@@ -190,52 +209,38 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
find a better one. If the agent's network interface is None, replace
that as well.
- :raises: LookupAgentInterfaceError if a valid network interface cannot
- be found.
:raises: LookupAgentIPError if an IP address could not be found
"""
if self.advertise_address[0] is not None:
return
- if self.network_interface is None:
- ifaces = self.get_agent_network_interfaces()
+ found_ip = None
+ if self.network_interface is not None:
+ # TODO(dtantsur): deprecate this
+ found_ip = hardware.dispatch_to_managers('get_ipv4_addr',
+ self.network_interface)
else:
- ifaces = [self.network_interface]
-
- attempts = 0
- while (attempts < self.ip_lookup_attempts):
- for iface in ifaces:
- found_ip = hardware.dispatch_to_managers('get_ipv4_addr',
- iface)
- if found_ip is not None:
- self.advertise_address = (found_ip,
- self.advertise_address[1])
- self.network_interface = iface
- return
- attempts += 1
- time.sleep(self.ip_lookup_sleep)
-
- raise errors.LookupAgentIPError('Agent could not find a valid IP '
- 'address.')
-
- def get_agent_network_interfaces(self):
- """Get a list of all network interfaces available.
-
- Excludes loopback connections.
-
- :returns: list of network interfaces available.
- :raises: LookupAgentInterfaceError if a valid interface could not
- be found.
- """
- iface_list = [iface.serialize()['name'] for iface in
- hardware.dispatch_to_managers('list_network_interfaces')]
- iface_list = [name for name in iface_list if 'lo' not in name]
-
- if len(iface_list) == 0:
- raise errors.LookupAgentInterfaceError('Agent could not find a '
- 'valid network interface.')
+ url = urlparse.urlparse(self.api_url)
+ ironic_host = url.hostname
+ # Try resolving it in case it's not an IP address
+ try:
+ ironic_host = socket.gethostbyname(ironic_host)
+ except socket.gaierror:
+ LOG.debug('Count not resolve %s, maybe no DNS', ironic_host)
+
+ for attempt in range(self.ip_lookup_attempts):
+ found_ip = self._get_route_source(ironic_host)
+ if found_ip:
+ break
+
+ time.sleep(self.ip_lookup_sleep)
+
+ if found_ip:
+ self.advertise_address = (found_ip,
+ self.advertise_address[1])
else:
- return iface_list
+ raise errors.LookupAgentIPError('Agent could not find a valid IP '
+ 'address.')
def get_node_uuid(self):
"""Get UUID for Ironic node.