From c843acb4f603018615fe62cbb07f3f4936840cd9 Mon Sep 17 00:00:00 2001 From: Dazhao Date: Mon, 20 Jan 2014 15:32:45 +0800 Subject: [PATCH] Make sure use IPv6 sockets for ceilometer in IPv6 environment In IPv6 management network environment, ceilometer command will throw 'Address family for hostname not support' when use WSGI simple server. The root cause is python TCPServer implementation is hard-coded to use IPv4, even in IPv6 environments. Python community want to fix it in Python3.5, so we need to make a workaround for it. Change-Id: I3260a346a095b0f3e57093c18b1920dffe5ac55d Closes-Bug: #1269243 --- ceilometer/api/app.py | 19 +++++++++++++- ceilometer/tests/api/test_app.py | 44 ++++++++++++++++++++++++++++++++ requirements.txt | 1 + 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 ceilometer/tests/api/test_app.py diff --git a/ceilometer/api/app.py b/ceilometer/api/app.py index 896ed7916..9dedac545 100644 --- a/ceilometer/api/app.py +++ b/ceilometer/api/app.py @@ -18,8 +18,10 @@ import logging import os +import socket from wsgiref import simple_server +import netaddr from oslo.config import cfg import pecan @@ -106,6 +108,20 @@ class VersionSelectorApplication(object): return self.v2(environ, start_response) +def get_server_cls(host): + """Return an appropriate WSGI server class base on provided host + + :param host: The listen host for the ceilometer API server. + """ + server_cls = simple_server.WSGIServer + if netaddr.valid_ipv6(host): + # NOTE(dzyu) make sure use IPv6 sockets if host is in IPv6 pattern + if getattr(server_cls, 'address_family') == socket.AF_INET: + class server_cls(server_cls): + address_family = socket.AF_INET6 + return server_cls + + def start(): service.prepare_service() @@ -114,7 +130,8 @@ def start(): # Create the WSGI server and start it host, port = cfg.CONF.api.host, cfg.CONF.api.port - srv = simple_server.make_server(host, port, root) + server_cls = get_server_cls(host) + srv = simple_server.make_server(host, port, root, server_cls) LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.info(_("Configuration:")) diff --git a/ceilometer/tests/api/test_app.py b/ceilometer/tests/api/test_app.py new file mode 100644 index 000000000..b7d9b5eb1 --- /dev/null +++ b/ceilometer/tests/api/test_app.py @@ -0,0 +1,44 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2014 IBM Corp. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 socket + +from oslo.config import cfg + +from ceilometer.api import app +from ceilometer.openstack.common.fixture import config +from ceilometer.tests import base + + +class TestApp(base.BaseTestCase): + + def setUp(self): + super(TestApp, self).setUp() + self.CONF = self.useFixture(config.Config()).conf + + def test_WSGI_address_family(self): + self.CONF.set_override('host', '::', group='api') + server_cls = app.get_server_cls(cfg.CONF.api.host) + self.assertEqual(server_cls.address_family, socket.AF_INET6) + + self.CONF.set_override('host', '127.0.0.1', group='api') + server_cls = app.get_server_cls(cfg.CONF.api.host) + self.assertEqual(server_cls.address_family, socket.AF_INET) + + self.CONF.set_override('host', 'ddddd', group='api') + server_cls = app.get_server_cls(cfg.CONF.api.host) + self.assertEqual(server_cls.address_family, socket.AF_INET) diff --git a/requirements.txt b/requirements.txt index 7b6c237fc..162e994be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,7 @@ kombu>=2.4.8 lockfile>=0.8 lxml>=2.3 msgpack-python +netaddr>=0.7.6 oslo.config>=1.2.0 oslo.vmware pbr>=0.6,<1.0