]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Move Unix domain socket helpers to a common place
authorAssaf Muller <amuller@redhat.com>
Thu, 12 Mar 2015 23:50:24 +0000 (19:50 -0400)
committerAssaf Muller <amuller@redhat.com>
Mon, 16 Mar 2015 15:18:03 +0000 (11:18 -0400)
As part of the all consuming report-ha-router-master, a new
per router neutron-keepalived-state-change daemon will alert
the L3 agent on every keepalived state change. Since it will
use the Unix domain socket helpers, and they're currently
located in metadata related places, this patch moves them
to a common location.

Also, the UnixDomainHTTPConnection connection string
may now be overridden.

Partially-Implements: blueprint report-ha-router-master
Change-Id: Ib2cde90059f4e089064b2def2838e9bcf9af30de

neutron/agent/linux/utils.py
neutron/agent/metadata/agent.py
neutron/agent/metadata/namespace_proxy.py
neutron/tests/functional/agent/test_l3_agent.py
neutron/tests/unit/agent/linux/test_utils.py
neutron/tests/unit/test_metadata_agent.py
neutron/tests/unit/test_metadata_namespace_proxy.py

index 3795522f00b751e12a75ff69775c60a9d6bde89b..c5aa4c7e0a89460f3949d614e6be8a808bcc8655 100644 (file)
@@ -15,6 +15,7 @@
 
 import fcntl
 import glob
+import httplib
 import os
 import shlex
 import socket
@@ -27,6 +28,7 @@ from eventlet.green import subprocess
 from eventlet import greenthread
 from oslo_config import cfg
 from oslo_log import log as logging
+from oslo_log import loggers
 from oslo_rootwrap import client
 from oslo_utils import excutils
 
@@ -34,6 +36,7 @@ from neutron.agent.common import config
 from neutron.common import constants
 from neutron.common import utils
 from neutron.i18n import _LE
+from neutron import wsgi
 
 
 LOG = logging.getLogger(__name__)
@@ -316,3 +319,64 @@ def wait_until_true(predicate, timeout=60, sleep=1, exception=None):
     with eventlet.timeout.Timeout(timeout, exception):
         while not predicate():
             eventlet.sleep(sleep)
+
+
+def ensure_directory_exists_without_file(path):
+    dirname = os.path.dirname(path)
+    if os.path.isdir(dirname):
+        try:
+            os.unlink(path)
+        except OSError:
+            with excutils.save_and_reraise_exception() as ctxt:
+                if not os.path.exists(path):
+                    ctxt.reraise = False
+    else:
+        ensure_dir(dirname)
+
+
+class UnixDomainHTTPConnection(httplib.HTTPConnection):
+    """Connection class for HTTP over UNIX domain socket."""
+    def __init__(self, host, port=None, strict=None, timeout=None,
+                 proxy_info=None):
+        httplib.HTTPConnection.__init__(self, host, port, strict)
+        self.timeout = timeout
+        self.socket_path = cfg.CONF.metadata_proxy_socket
+
+    def connect(self):
+        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        if self.timeout:
+            self.sock.settimeout(self.timeout)
+        self.sock.connect(self.socket_path)
+
+
+class UnixDomainHttpProtocol(eventlet.wsgi.HttpProtocol):
+    def __init__(self, request, client_address, server):
+        if client_address == '':
+            client_address = ('<local>', 0)
+        # base class is old-style, so super does not work properly
+        eventlet.wsgi.HttpProtocol.__init__(self, request, client_address,
+                                            server)
+
+
+class UnixDomainWSGIServer(wsgi.Server):
+    def __init__(self, name):
+        self._socket = None
+        self._launcher = None
+        self._server = None
+        super(UnixDomainWSGIServer, self).__init__(name)
+
+    def start(self, application, file_socket, workers, backlog):
+        self._socket = eventlet.listen(file_socket,
+                                       family=socket.AF_UNIX,
+                                       backlog=backlog)
+
+        self._launch(application, workers=workers)
+
+    def _run(self, application, socket):
+        """Start a WSGI service in a new green thread."""
+        logger = logging.getLogger('eventlet.wsgi.server')
+        eventlet.wsgi.server(socket,
+                             application,
+                             max_size=self.num_threads,
+                             protocol=UnixDomainHttpProtocol,
+                             log=loggers.WritableLogger(logger))
index 44ea9b062e2a2a3e3c9b26ea15b4c41359f9a109..062acbaa004826001e4919efa535ec789f6efd06 100644 (file)
 
 import hashlib
 import hmac
-import os
-import socket
 
-import eventlet
 import httplib2
 from neutronclient.v2_0 import client
 from oslo_config import cfg
 from oslo_log import log as logging
-from oslo_log import loggers
 import oslo_messaging
-from oslo_utils import excutils
 import six.moves.urllib.parse as urlparse
 import webob
 
-from neutron.agent.linux import utils as linux_utils
+from neutron.agent.linux import utils as agent_utils
 from neutron.agent import rpc as agent_rpc
 from neutron.common import constants as n_const
 from neutron.common import rpc as n_rpc
@@ -38,7 +33,6 @@ from neutron import context
 from neutron.i18n import _LE, _LW
 from neutron.openstack.common.cache import cache
 from neutron.openstack.common import loopingcall
-from neutron import wsgi
 
 LOG = logging.getLogger(__name__)
 
@@ -266,55 +260,12 @@ class MetadataProxyHandler(object):
                         hashlib.sha256).hexdigest()
 
 
-class UnixDomainHttpProtocol(eventlet.wsgi.HttpProtocol):
-    def __init__(self, request, client_address, server):
-        if client_address == '':
-            client_address = ('<local>', 0)
-        # base class is old-style, so super does not work properly
-        eventlet.wsgi.HttpProtocol.__init__(self, request, client_address,
-                                            server)
-
-
-class UnixDomainWSGIServer(wsgi.Server):
-    def __init__(self, name):
-        self._socket = None
-        self._launcher = None
-        self._server = None
-        super(UnixDomainWSGIServer, self).__init__(name)
-
-    def start(self, application, file_socket, workers, backlog):
-        self._socket = eventlet.listen(file_socket,
-                                       family=socket.AF_UNIX,
-                                       backlog=backlog)
-
-        self._launch(application, workers=workers)
-
-    def _run(self, application, socket):
-        """Start a WSGI service in a new green thread."""
-        logger = logging.getLogger('eventlet.wsgi.server')
-        eventlet.wsgi.server(socket,
-                             application,
-                             max_size=self.num_threads,
-                             protocol=UnixDomainHttpProtocol,
-                             log=loggers.WritableLogger(logger))
-
-
 class UnixDomainMetadataProxy(object):
 
     def __init__(self, conf):
         self.conf = conf
-
-        dirname = os.path.dirname(cfg.CONF.metadata_proxy_socket)
-        if os.path.isdir(dirname):
-            try:
-                os.unlink(cfg.CONF.metadata_proxy_socket)
-            except OSError:
-                with excutils.save_and_reraise_exception() as ctxt:
-                    if not os.path.exists(cfg.CONF.metadata_proxy_socket):
-                        ctxt.reraise = False
-        else:
-            linux_utils.ensure_dir(dirname)
-
+        agent_utils.ensure_directory_exists_without_file(
+            cfg.CONF.metadata_proxy_socket)
         self._init_state_reporting()
 
     def _init_state_reporting(self):
@@ -355,7 +306,7 @@ class UnixDomainMetadataProxy(object):
         self.agent_state.pop('start_flag', None)
 
     def run(self):
-        server = UnixDomainWSGIServer('neutron-metadata-agent')
+        server = agent_utils.UnixDomainWSGIServer('neutron-metadata-agent')
         server.start(MetadataProxyHandler(self.conf),
                      self.conf.metadata_proxy_socket,
                      workers=self.conf.metadata_workers,
index be1d32adf7086ef599345ae55ed2ce33beb18f40..032e489fb3620ae8a0989025ea48c2dc9bf24247 100644 (file)
@@ -12,9 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import httplib
-import socket
-
 import httplib2
 from oslo_config import cfg
 from oslo_log import log as logging
@@ -22,6 +19,7 @@ import six.moves.urllib.parse as urlparse
 import webob
 
 from neutron.agent.linux import daemon
+from neutron.agent.linux import utils as agent_utils
 from neutron.common import config
 from neutron.common import exceptions
 from neutron.common import utils
@@ -31,20 +29,6 @@ from neutron import wsgi
 LOG = logging.getLogger(__name__)
 
 
-class UnixDomainHTTPConnection(httplib.HTTPConnection):
-    """Connection class for HTTP over UNIX domain socket."""
-    def __init__(self, host, port=None, strict=None, timeout=None,
-                 proxy_info=None):
-        httplib.HTTPConnection.__init__(self, host, port, strict)
-        self.timeout = timeout
-
-    def connect(self):
-        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        if self.timeout:
-            self.sock.settimeout(self.timeout)
-        self.sock.connect(cfg.CONF.metadata_proxy_socket)
-
-
 class NetworkMetadataProxyHandler(object):
     """Proxy AF_INET metadata request through Unix Domain socket.
 
@@ -98,7 +82,7 @@ class NetworkMetadataProxyHandler(object):
             method=method,
             headers=headers,
             body=body,
-            connection_type=UnixDomainHTTPConnection)
+            connection_type=agent_utils.UnixDomainHTTPConnection)
 
         if resp.status == 200:
             LOG.debug(resp)
index 8e81f9608b89c30e7f26672e0b69bff8be9392b5..331406175373b310b476f0f71ebfb05c19381043 100755 (executable)
@@ -35,7 +35,6 @@ from neutron.agent.linux import external_process
 from neutron.agent.linux import ip_lib
 from neutron.agent.linux import ovs_lib
 from neutron.agent.linux import utils
-from neutron.agent.metadata import agent as metadata_agent
 from neutron.common import config as common_config
 from neutron.common import constants as l3_constants
 from neutron.common import utils as common_utils
@@ -544,7 +543,7 @@ class MetadataFakeProxyHandler(object):
 class MetadataL3AgentTestCase(L3AgentTestFramework):
 
     def _create_metadata_fake_server(self, status):
-        server = metadata_agent.UnixDomainWSGIServer('metadata-fake-server')
+        server = utils.UnixDomainWSGIServer('metadata-fake-server')
         self.addCleanup(server.stop)
         server.start(MetadataFakeProxyHandler(status),
                      self.agent.conf.metadata_proxy_socket,
index 4f374f357b3c4202990db1d0d13e49748f2234c3..c66d48ec6fa01e48ef09f0d17edac9be50118f8e 100644 (file)
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+
 import os
 
 import mock
+import socket
 import testtools
 
 from neutron.agent.linux import utils
@@ -221,3 +223,62 @@ class TestBaseOSUtils(base.BaseTestCase):
         utils.ensure_dir('/the')
         isdir.assert_called_once_with('/the')
         self.assertFalse(makedirs.called)
+
+
+class TestUnixDomainHttpConnection(base.BaseTestCase):
+    def test_connect(self):
+        with mock.patch.object(utils, 'cfg') as cfg:
+            cfg.CONF.metadata_proxy_socket = '/the/path'
+            with mock.patch('socket.socket') as socket_create:
+                conn = utils.UnixDomainHTTPConnection('169.254.169.254',
+                                                      timeout=3)
+                conn.connect()
+
+                socket_create.assert_has_calls([
+                    mock.call(socket.AF_UNIX, socket.SOCK_STREAM),
+                    mock.call().settimeout(3),
+                    mock.call().connect('/the/path')]
+                )
+                self.assertEqual(conn.timeout, 3)
+
+
+class TestUnixDomainHttpProtocol(base.BaseTestCase):
+    def test_init_empty_client(self):
+        u = utils.UnixDomainHttpProtocol(mock.Mock(), '', mock.Mock())
+        self.assertEqual(u.client_address, ('<local>', 0))
+
+    def test_init_with_client(self):
+        u = utils.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock())
+        self.assertEqual(u.client_address, 'foo')
+
+
+class TestUnixDomainWSGIServer(base.BaseTestCase):
+    def setUp(self):
+        super(TestUnixDomainWSGIServer, self).setUp()
+        self.eventlet_p = mock.patch.object(utils, 'eventlet')
+        self.eventlet = self.eventlet_p.start()
+        self.server = utils.UnixDomainWSGIServer('test')
+
+    def test_start(self):
+        mock_app = mock.Mock()
+        with mock.patch.object(self.server, '_launch') as launcher:
+            self.server.start(mock_app, '/the/path', workers=5, backlog=128)
+            self.eventlet.assert_has_calls([
+                mock.call.listen(
+                    '/the/path',
+                    family=socket.AF_UNIX,
+                    backlog=128
+                )]
+            )
+            launcher.assert_called_once_with(mock_app, workers=5)
+
+    def test_run(self):
+        self.server._run('app', 'sock')
+
+        self.eventlet.wsgi.server.assert_called_once_with(
+            'sock',
+            'app',
+            protocol=utils.UnixDomainHttpProtocol,
+            log=mock.ANY,
+            max_size=self.server.num_threads
+        )
index 27a450a751e65ffd35c8f3d4c282e015c3c1eba5..1a314c00e6c61d3956b76b8d40b25886d14a7cfb 100644 (file)
 #    under the License.
 
 import contextlib
-import socket
 
 import mock
 import testtools
 import webob
 
-from neutron.agent.linux import utils as linux_utils
+from neutron.agent.linux import utils as agent_utils
 from neutron.agent.metadata import agent
 from neutron.agent import metadata_agent
 from neutron.common import constants
@@ -511,50 +510,6 @@ class TestMetadataProxyHandlerNoCache(TestMetadataProxyHandlerCache):
             2, self.qclient.return_value.list_ports.call_count)
 
 
-class TestUnixDomainHttpProtocol(base.BaseTestCase):
-    def test_init_empty_client(self):
-        u = agent.UnixDomainHttpProtocol(mock.Mock(), '', mock.Mock())
-        self.assertEqual(u.client_address, ('<local>', 0))
-
-    def test_init_with_client(self):
-        u = agent.UnixDomainHttpProtocol(mock.Mock(), 'foo', mock.Mock())
-        self.assertEqual(u.client_address, 'foo')
-
-
-class TestUnixDomainWSGIServer(base.BaseTestCase):
-    def setUp(self):
-        super(TestUnixDomainWSGIServer, self).setUp()
-        self.eventlet_p = mock.patch.object(agent, 'eventlet')
-        self.eventlet = self.eventlet_p.start()
-        self.server = agent.UnixDomainWSGIServer('test')
-
-    def test_start(self):
-        mock_app = mock.Mock()
-        with mock.patch.object(self.server, '_launch') as launcher:
-            self.server.start(mock_app, '/the/path', workers=5, backlog=128)
-            self.eventlet.assert_has_calls([
-                mock.call.listen(
-                    '/the/path',
-                    family=socket.AF_UNIX,
-                    backlog=128
-                )]
-            )
-            launcher.assert_called_once_with(mock_app, workers=5)
-
-    def test_run(self):
-        with mock.patch.object(agent, 'logging') as logging:
-            self.server._run('app', 'sock')
-
-            self.eventlet.wsgi.server.assert_called_once_with(
-                'sock',
-                'app',
-                protocol=agent.UnixDomainHttpProtocol,
-                log=mock.ANY,
-                max_size=self.server.num_threads
-            )
-            self.assertTrue(len(logging.mock_calls))
-
-
 class TestUnixDomainMetadataProxy(base.BaseTestCase):
     def setUp(self):
         super(TestUnixDomainMetadataProxy, self).setUp()
@@ -567,7 +522,7 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
         self.cfg.CONF.metadata_workers = 0
         self.cfg.CONF.metadata_backlog = 128
 
-    @mock.patch.object(linux_utils, 'ensure_dir')
+    @mock.patch.object(agent_utils, 'ensure_dir')
     def test_init_doesnot_exists(self, ensure_dir):
         agent.UnixDomainMetadataProxy(mock.Mock())
         ensure_dir.assert_called_once_with('/the')
@@ -603,8 +558,8 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
                     unlink.assert_called_once_with('/the/path')
 
     @mock.patch.object(agent, 'MetadataProxyHandler')
-    @mock.patch.object(agent, 'UnixDomainWSGIServer')
-    @mock.patch.object(linux_utils, 'ensure_dir')
+    @mock.patch.object(agent_utils, 'UnixDomainWSGIServer')
+    @mock.patch.object(agent_utils, 'ensure_dir')
     def test_run(self, ensure_dir, server, handler):
         p = agent.UnixDomainMetadataProxy(self.cfg.CONF)
         p.run()
index 4a707a503c6c3c389bd8f8b09c40c205042b564d..ce9c2bca95847a0e47c0b14e9f5cfa1c13ce3fe0 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import socket
-
 import mock
 import testtools
 import webob
 
+from neutron.agent.linux import utils as agent_utils
 from neutron.agent.metadata import namespace_proxy as ns_proxy
 from neutron.common import exceptions
 from neutron.common import utils
@@ -36,24 +35,6 @@ class FakeConf(object):
     metadata_proxy_shared_secret = 'secret'
 
 
-class TestUnixDomainHttpConnection(base.BaseTestCase):
-    def test_connect(self):
-        with mock.patch.object(ns_proxy, 'cfg') as cfg:
-            cfg.CONF.metadata_proxy_socket = '/the/path'
-            with mock.patch('socket.socket') as socket_create:
-                conn = ns_proxy.UnixDomainHTTPConnection('169.254.169.254',
-                                                         timeout=3)
-
-                conn.connect()
-
-                socket_create.assert_has_calls([
-                    mock.call(socket.AF_UNIX, socket.SOCK_STREAM),
-                    mock.call().settimeout(3),
-                    mock.call().connect('/the/path')]
-                )
-                self.assertEqual(conn.timeout, 3)
-
-
 class TestNetworkMetadataProxyHandler(base.BaseTestCase):
     def setUp(self):
         super(TestNetworkMetadataProxyHandler, self).setUp()
@@ -111,7 +92,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Router-ID': 'router_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )
@@ -141,7 +122,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Network-ID': 'network_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )
@@ -171,7 +152,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Network-ID': 'network_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )
@@ -211,7 +192,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Network-ID': 'network_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )
@@ -240,7 +221,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Network-ID': 'network_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )
@@ -267,7 +248,7 @@ class TestNetworkMetadataProxyHandler(base.BaseTestCase):
                         'X-Forwarded-For': '192.168.1.1',
                         'X-Neutron-Network-ID': 'network_id'
                     },
-                    connection_type=ns_proxy.UnixDomainHTTPConnection,
+                    connection_type=agent_utils.UnixDomainHTTPConnection,
                     body=''
                 )]
             )