summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.zuul.yaml62
-rw-r--r--README.rst2
-rw-r--r--glance/common/wsgi.py31
-rw-r--r--glance/domain/__init__.py8
-rw-r--r--glance/tests/functional/__init__.py4
-rw-r--r--glance/tests/functional/v2/test_images.py31
-rw-r--r--glance/tests/unit/api/test_common.py2
-rw-r--r--glance/tests/unit/common/test_utils.py2
-rw-r--r--glance/tests/unit/common/test_wsgi.py62
-rw-r--r--glance/tests/utils.py25
-rw-r--r--lower-constraints.txt2
-rw-r--r--releasenotes/notes/use-webob-1.8.1-5c3cd1b1382f063e.yaml12
-rw-r--r--releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po21
-rw-r--r--requirements.txt4
-rw-r--r--tox.ini14
15 files changed, 181 insertions, 101 deletions
diff --git a/.zuul.yaml b/.zuul.yaml
index 8ec164acd..5d4d325c2 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -26,6 +26,7 @@
- job:
name: glance-tox-oslo-tips-base
parent: tox
+ abstract: true
description: Abstract job for Glance vs. oslo libraries
# NOTE(rosmaita): only need functional test jobs, oslo is
# already running periodic jobs using our unit tests
@@ -65,6 +66,7 @@
- job:
name: glance-tox-keystone-tips-base
parent: tox
+ abstract: true
description: Abstract job for Glance vs. keystone
required-projects:
- name: openstack/keystoneauth
@@ -106,6 +108,7 @@
- job:
name: glance-tox-glance_store-tips-base
parent: tox
+ abstract: true
description: Abstract job for Glance vs. glance_store
required-projects:
- name: openstack/glance_store
@@ -145,6 +148,7 @@
- job:
name: glance-tox-cursive-tips-base
parent: tox
+ abstract: true
description: Abstract job for Glance vs. cursive and related libs
required-projects:
- name: openstack/cursive
@@ -265,7 +269,7 @@
- ^releasenotes/.*$
- ^setup.cfg$
- ^tox.ini$
- - legacy-tempest-dsvm-neutron-pg-full:
+ - tempest-pg-full:
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
@@ -274,7 +278,7 @@
- ^releasenotes/.*$
- ^setup.cfg$
- ^tox.ini$
- - legacy-tempest-dsvm-neutron-full-opensuse-423:
+ - tempest-full-py3-opensuse150:
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
@@ -285,17 +289,43 @@
- ^tox.ini$
periodic:
jobs:
- - glance-tox-functional-oslo-tips
- - glance-tox-functional-py35-oslo-tips
- - glance-tox-py27-keystone-tips
- - glance-tox-py35-keystone-tips
- - glance-tox-functional-keystone-tips
- - glance-tox-functional-py35-keystone-tips
- - glance-tox-py27-glance_store-tips
- - glance-tox-py35-glance_store-tips
- - glance-tox-functional-glance_store-tips
- - glance-tox-functional-py35-glance_store-tips
- - glance-tox-py27-cursive-tips
- - glance-tox-py35-cursive-tips
- - glance-tox-functional-cursive-tips
- - glance-tox-functional-py35-cursive-tips
+ # NOTE(rosmaita): we only want the "tips" jobs to be run against
+ # master, hence the 'branches' qualifiers below. Without them, when
+ # a stable branch is cut, the tests would be run against the stable
+ # branch as well, which is pointless because these libraries are
+ # frozen (more or less) in the stable branches.
+ #
+ # The "tips" jobs can be removed from the stable branch .zuul.yaml
+ # files if someone is so inclined, but that would require manual
+ # maintenance, so we do not do it by default. Another option is
+ # to define these jobs in the openstack-infra/project-config repo.
+ # That would make us less agile in adjusting these tests, so we
+ # aren't doing that either.
+ - glance-tox-functional-oslo-tips:
+ branches: master
+ - glance-tox-functional-py35-oslo-tips:
+ branches: master
+ - glance-tox-py27-keystone-tips:
+ branches: master
+ - glance-tox-py35-keystone-tips:
+ branches: master
+ - glance-tox-functional-keystone-tips:
+ branches: master
+ - glance-tox-functional-py35-keystone-tips:
+ branches: master
+ - glance-tox-py27-glance_store-tips:
+ branches: master
+ - glance-tox-py35-glance_store-tips:
+ branches: master
+ - glance-tox-functional-glance_store-tips:
+ branches: master
+ - glance-tox-functional-py35-glance_store-tips:
+ branches: master
+ - glance-tox-py27-cursive-tips:
+ branches: master
+ - glance-tox-py35-cursive-tips:
+ branches: master
+ - glance-tox-functional-cursive-tips:
+ branches: master
+ - glance-tox-functional-py35-cursive-tips:
+ branches: master
diff --git a/README.rst b/README.rst
index 7c9bc115a..c267df725 100644
--- a/README.rst
+++ b/README.rst
@@ -71,7 +71,7 @@ Release notes
To learn more about Glance's new features, optimizations, and changes
between versions, consult the release notes online at:
-* `Release Notes <https://docs.openstack.org/releasenotes/glance/>`_
+* `Release Notes <https://docs.openstack.org/releasenotes/glance/>`__
Other Information
-----------------
diff --git a/glance/common/wsgi.py b/glance/common/wsgi.py
index bc0bb084f..7ccd76a2f 100644
--- a/glance/common/wsgi.py
+++ b/glance/common/wsgi.py
@@ -53,12 +53,6 @@ from glance import i18n
from glance.i18n import _, _LE, _LI, _LW
-try:
- from webob.acceptparse import AcceptLanguageValidHeader # noqa
- USING_WEBOB_1_8 = True
-except ImportError:
- USING_WEBOB_1_8 = False
-
bind_opts = [
cfg.HostAddressOpt('bind_host',
default='0.0.0.0',
@@ -1033,8 +1027,10 @@ class Request(webob.Request):
def best_match_content_type(self):
"""Determine the requested response content-type."""
supported = ('application/json',)
- bm = self.accept.best_match(supported)
- return bm or 'application/json'
+ best_matches = self.accept.acceptable_offers(supported)
+ if not best_matches:
+ return 'application/json'
+ return best_matches[0][0]
def get_content_type(self, allowed_content_types):
"""Determine content type of the request body."""
@@ -1048,18 +1044,7 @@ class Request(webob.Request):
else:
return content_type
- def _best_match_language_1_7(self):
- """Determines best available locale from the Accept-Language header.
-
- :returns: the best language match or None if the 'Accept-Language'
- header was not available in the request.
- """
- if not self.accept_language:
- return None
- langs = i18n.get_available_languages('glance')
- return self.accept_language.best_match(langs)
-
- def _best_match_language_1_8(self):
+ def best_match_language(self):
"""Determines best available locale from the Accept-Language header.
:returns: the best language match or None if the 'Accept-Language'
@@ -1076,12 +1061,6 @@ class Request(webob.Request):
best_match = None
return best_match
- def best_match_language(self):
- if USING_WEBOB_1_8:
- return self._best_match_language_1_8()
- else:
- return self._best_match_language_1_7()
-
def get_range_from_request(self, image_size):
"""Return the `Range` in a request."""
diff --git a/glance/domain/__init__.py b/glance/domain/__init__.py
index 7feb1edfb..0bb6a2964 100644
--- a/glance/domain/__init__.py
+++ b/glance/domain/__init__.py
@@ -300,9 +300,9 @@ class ExtraProperties(collections.MutableMapping, dict):
def __eq__(self, other):
if isinstance(other, ExtraProperties):
- return dict(self).__eq__(dict(other))
+ return dict.__eq__(self, dict(other))
elif isinstance(other, dict):
- return dict(self).__eq__(other)
+ return dict.__eq__(self, other)
else:
return False
@@ -310,10 +310,10 @@ class ExtraProperties(collections.MutableMapping, dict):
return not self.__eq__(other)
def __len__(self):
- return dict(self).__len__()
+ return dict.__len__(self)
def keys(self):
- return dict(self).keys()
+ return dict.keys(self)
class ImageMembership(object):
diff --git a/glance/tests/functional/__init__.py b/glance/tests/functional/__init__.py
index d6ac835dd..ac42b1da2 100644
--- a/glance/tests/functional/__init__.py
+++ b/glance/tests/functional/__init__.py
@@ -364,6 +364,8 @@ store_type_preference = %(store_type_location_strategy_preference)s
[glance_store]
filesystem_store_datadir=%(image_dir)s
default_store = %(default_store)s
+[import_filtering_opts]
+allowed_ports = []
"""
self.paste_conf_base = """[pipeline:glance-api]
pipeline =
@@ -549,6 +551,8 @@ default_backend = %(default_backend)s
filesystem_store_datadir=%(image_dir_backend_1)s
[file2]
filesystem_store_datadir=%(image_dir_backend_2)s
+[import_filtering_opts]
+allowed_ports = []
"""
self.paste_conf_base = """[pipeline:glance-api]
pipeline =
diff --git a/glance/tests/functional/v2/test_images.py b/glance/tests/functional/v2/test_images.py
index eb584365b..7d6d93398 100644
--- a/glance/tests/functional/v2/test_images.py
+++ b/glance/tests/functional/v2/test_images.py
@@ -341,8 +341,11 @@ class TestImages(functional.FunctionalTest):
'content-type': 'application/json',
'X-Roles': 'admin',
})
- image_data_uri = ('https://www.openstack.org/assets/openstack-logo/'
- '2016R/OpenStack-Logo-Horizontal.eps.zip')
+
+ # Start http server locally
+ pid, port = test_utils.start_standalone_http_server()
+
+ image_data_uri = 'http://localhost:%s/' % port
data = jsonutils.dumps({'method': {
'name': 'web-download',
'uri': image_data_uri
@@ -369,6 +372,9 @@ class TestImages(functional.FunctionalTest):
os_hash_value=expect_h,
status='active')
+ # kill the local http server
+ os.kill(pid, signal.SIGKILL)
+
# Deleting image should work
path = self._url('/v2/images/%s' % image_id)
response = requests.delete(path, headers=self._headers())
@@ -4901,8 +4907,11 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
'content-type': 'application/json',
'X-Roles': 'admin',
})
- image_data_uri = ('https://www.openstack.org/assets/openstack-logo/'
- '2016R/OpenStack-Logo-Horizontal.eps.zip')
+
+ # Start http server locally
+ pid, port = test_utils.start_standalone_http_server()
+
+ image_data_uri = 'http://localhost:%s/' % port
data = jsonutils.dumps({'method': {
'name': 'web-download',
'uri': image_data_uri
@@ -4928,6 +4937,9 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
checksum=expect_c,
os_hash_value=expect_h,
status='active')
+
+ # kill the local http server
+ os.kill(pid, signal.SIGKILL)
# Ensure image is created in default backend
path = self._url('/v2/images/%s' % image_id)
response = requests.get(path, headers=self._headers())
@@ -5055,8 +5067,11 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
'X-Roles': 'admin',
'X-Image-Meta-Store': 'file2'
})
- image_data_uri = ('https://www.openstack.org/assets/openstack-logo/'
- '2016R/OpenStack-Logo-Horizontal.eps.zip')
+
+ # Start http server locally
+ pid, port = test_utils.start_standalone_http_server()
+
+ image_data_uri = 'http://localhost:%s/' % port
data = jsonutils.dumps({'method': {
'name': 'web-download',
'uri': image_data_uri
@@ -5082,6 +5097,10 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
checksum=expect_c,
os_hash_value=expect_h,
status='active')
+
+ # kill the local http server
+ os.kill(pid, signal.SIGKILL)
+
# Ensure image is created in different backend
path = self._url('/v2/images/%s' % image_id)
response = requests.get(path, headers=self._headers())
diff --git a/glance/tests/unit/api/test_common.py b/glance/tests/unit/api/test_common.py
index ab1ccb995..cf3c9f93f 100644
--- a/glance/tests/unit/api/test_common.py
+++ b/glance/tests/unit/api/test_common.py
@@ -34,7 +34,7 @@ class SimpleIterator(object):
yield chunk
chunk = read_chunk()
else:
- raise StopIteration()
+ return
class TestSizeCheckedIter(testtools.TestCase):
diff --git a/glance/tests/unit/common/test_utils.py b/glance/tests/unit/common/test_utils.py
index 48911c673..98ff61c21 100644
--- a/glance/tests/unit/common/test_utils.py
+++ b/glance/tests/unit/common/test_utils.py
@@ -87,7 +87,7 @@ class TestUtils(test_utils.BaseTestCase):
yield chunk
iteration += 1
if iteration >= max_iterations:
- raise StopIteration()
+ return
def _test_reader_chunked(self, chunk_size, read_size, max_iterations=5):
generator = self._create_generator(chunk_size, max_iterations)
diff --git a/glance/tests/unit/common/test_wsgi.py b/glance/tests/unit/common/test_wsgi.py
index adda23e11..794873d42 100644
--- a/glance/tests/unit/common/test_wsgi.py
+++ b/glance/tests/unit/common/test_wsgi.py
@@ -184,31 +184,20 @@ class RequestTest(test_utils.BaseTestCase):
req = wsgi.Request.blank('/', headers={'Accept-Language': 'unknown'})
self.assertIsNone(req.best_match_language())
- def test_best_match_language_unknown(self):
- # Test that we are actually invoking language negotiation by webop
+ @mock.patch.object(webob.acceptparse.AcceptLanguageValidHeader, 'lookup')
+ def test_best_match_language_unknown(self, mock_lookup):
+ # Test that we are actually invoking language negotiation by WebOb
request = wsgi.Request.blank('/')
accepted = 'unknown-lang'
request.headers = {'Accept-Language': accepted}
- # TODO(rosmaita): simplify when lower_constraints has webob >= 1.8.1
- try:
- from webob.acceptparse import AcceptLanguageValidHeader # noqa
- cls = webob.acceptparse.AcceptLanguageValidHeader
- funcname = 'lookup'
- # Bug #1765748: see comment in code in the function under test
- # to understand why this is the correct return value for the
- # webob 1.8.x mock
- retval = 'fake_LANG'
- except ImportError:
- cls = webob.acceptparse.AcceptLanguage
- funcname = 'best_match'
- retval = None
-
- with mock.patch.object(cls, funcname) as mocked_function:
- mocked_function.return_value = retval
-
- self.assertIsNone(request.best_match_language())
- mocked_function.assert_called_once()
+ # Bug #1765748: see comment in code in the function under test
+ # to understand why this is the correct return value for the
+ # webob 1.8.x mock
+ mock_lookup.return_value = 'fake_LANG'
+
+ self.assertIsNone(request.best_match_language())
+ mock_lookup.assert_called_once()
# If Accept-Language is missing or empty, match should be None
request.headers = {'Accept-Language': ''}
@@ -389,27 +378,18 @@ class ResourceTest(test_utils.BaseTestCase):
resource, request)
self.assertEqual(message_es, str(e))
+ @mock.patch.object(webob.acceptparse.AcceptLanguageValidHeader, 'lookup')
@mock.patch.object(i18n, 'translate')
- def test_translate_exception(self, mock_translate):
- # TODO(rosmaita): simplify when lower_constraints has webob >= 1.8.1
- try:
- from webob.acceptparse import AcceptLanguageValidHeader # noqa
- cls = webob.acceptparse.AcceptLanguageValidHeader
- funcname = 'lookup'
- except ImportError:
- cls = webob.acceptparse.AcceptLanguage
- funcname = 'best_match'
-
- with mock.patch.object(cls, funcname) as mocked_function:
- mock_translate.return_value = 'No Encontrado'
- mocked_function.return_value = 'de'
-
- req = wsgi.Request.blank('/tests/123')
- req.headers["Accept-Language"] = "de"
-
- e = webob.exc.HTTPNotFound(explanation='Not Found')
- e = wsgi.translate_exception(req, e)
- self.assertEqual('No Encontrado', e.explanation)
+ def test_translate_exception(self, mock_translate, mock_lookup):
+ mock_translate.return_value = 'No Encontrado'
+ mock_lookup.return_value = 'de'
+
+ req = wsgi.Request.blank('/tests/123')
+ req.headers["Accept-Language"] = "de"
+
+ e = webob.exc.HTTPNotFound(explanation='Not Found')
+ e = wsgi.translate_exception(req, e)
+ self.assertEqual('No Encontrado', e.explanation)
def test_response_headers_encoded(self):
# prepare environment
diff --git a/glance/tests/utils.py b/glance/tests/utils.py
index 0b0d143b0..bc55f5b0f 100644
--- a/glance/tests/utils.py
+++ b/glance/tests/utils.py
@@ -713,3 +713,28 @@ def is_sqlite_version_prior_to(major, minor):
import sqlite3
tup = sqlite3.sqlite_version_info
return tup[0] < major or (tup[0] == major and tup[1] < minor)
+
+
+def start_standalone_http_server():
+ def _get_http_handler_class():
+ class StaticHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def do_GET(self):
+ data = b"Hello World!!!"
+ self.send_response(http.OK)
+ self.send_header('Content-Length', str(len(data)))
+ self.end_headers()
+ self.wfile.write(data)
+ return
+
+ return StaticHTTPRequestHandler
+
+ server_address = ('127.0.0.1', 0)
+ handler_class = _get_http_handler_class()
+ httpd = BaseHTTPServer.HTTPServer(server_address, handler_class)
+ port = httpd.socket.getsockname()[1]
+
+ pid = os.fork()
+ if pid == 0:
+ httpd.serve_forever()
+ else:
+ return pid, port
diff --git a/lower-constraints.txt b/lower-constraints.txt
index beac1f160..4e158cd56 100644
--- a/lower-constraints.txt
+++ b/lower-constraints.txt
@@ -138,7 +138,7 @@ unittest2==1.1.0
urllib3==1.22
vine==1.1.4
voluptuous==0.11.1
-WebOb==1.7.1
+WebOb==1.8.1
whereto===0.3.0
wrapt==1.10.11
WSME==0.8.0
diff --git a/releasenotes/notes/use-webob-1.8.1-5c3cd1b1382f063e.yaml b/releasenotes/notes/use-webob-1.8.1-5c3cd1b1382f063e.yaml
new file mode 100644
index 000000000..21d8d3e5b
--- /dev/null
+++ b/releasenotes/notes/use-webob-1.8.1-5c3cd1b1382f063e.yaml
@@ -0,0 +1,12 @@
+---
+other:
+ - |
+ Negotiation of the 'Accept-Language' header now follows the "Lookup"
+ matching scheme described in `RFC 4647, section 3.4
+ <https://tools.ietf.org/html/rfc4647.html#section-3.4>`_. The
+ "Lookup" scheme is one of the algorithms suggested in `RFC 7231,
+ section 5.3.5
+ <https://tools.ietf.org/html/rfc7231.html#section-5.3.5>`_. (This is
+ due to a change in an underlying library, which previously used a
+ matching scheme that did not conform to `RFC 7231
+ <https://tools.ietf.org/html/rfc7231.html>`_.)
diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
index 63c1020c4..801bdcdbf 100644
--- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
+++ b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
@@ -4,11 +4,11 @@ msgid ""
msgstr ""
"Project-Id-Version: Glance Release Notes\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-09-21 23:35+0000\n"
+"POT-Creation-Date: 2018-11-08 05:54+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2018-09-27 12:04+0000\n"
+"PO-Revision-Date: 2018-11-07 06:12+0000\n"
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
"Language-Team: English (United Kingdom)\n"
"Language: en_GB\n"
@@ -1274,6 +1274,23 @@ msgstr ""
msgid "Mitaka Series Release Notes"
msgstr "Mitaka Series Release Notes"
+msgid ""
+"Negotiation of the 'Accept-Language' header now follows the \"Lookup\" "
+"matching scheme described in `RFC 4647, section 3.4 <https://tools.ietf.org/"
+"html/rfc4647.html#section-3.4>`_. The \"Lookup\" scheme is one of the "
+"algorithms suggested in `RFC 7231, section 5.3.5 <https://tools.ietf.org/"
+"html/rfc7231.html#section-5.3.5>`_. (This is due to a change in an "
+"underlying library, which previously used a matching scheme that did not "
+"conform to `RFC 7231 <https://tools.ietf.org/html/rfc7231.html>`_.)"
+msgstr ""
+"Negotiation of the 'Accept-Language' header now follows the \"Lookup\" "
+"matching scheme described in `RFC 4647, section 3.4 <https://tools.ietf.org/"
+"html/rfc4647.html#section-3.4>`_. The \"Lookup\" scheme is one of the "
+"algorithms suggested in `RFC 7231, section 5.3.5 <https://tools.ietf.org/"
+"html/rfc7231.html#section-5.3.5>`_. (This is due to a change in an "
+"underlying library, which previously used a matching scheme that did not "
+"conform to `RFC 7231 <https://tools.ietf.org/html/rfc7231.html>`_.)"
+
msgid "New Features"
msgstr "New Features"
diff --git a/requirements.txt b/requirements.txt
index 1b5027124..ee25e7e79 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,7 +10,7 @@ SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
PasteDeploy>=1.5.0 # MIT
Routes>=2.3.1 # MIT
-WebOb>=1.7.1 # MIT
+WebOb>=1.8.1 # MIT
sqlalchemy-migrate>=0.11.0 # Apache-2.0
sqlparse>=0.2.2 # BSD
alembic>=0.8.10 # MIT
@@ -38,7 +38,7 @@ six>=1.10.0 # MIT
oslo.db>=4.27.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
-oslo.messaging>=5.29.0 # Apache-2.0
+oslo.messaging>=5.29.0,!=9.0.0 # Apache-2.0
oslo.middleware>=3.31.0 # Apache-2.0
oslo.policy>=1.30.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 0f88bc383..8692ec68a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -34,6 +34,10 @@ commands = ostestr --slowest {posargs}
basepython = python3.5
commands = ostestr --slowest {posargs}
+[testenv:py37]
+basepython = python3.7
+commands = ostestr --slowest {posargs}
+
[testenv:functional]
setenv =
TEST_PATH = ./glance/tests/functional
@@ -51,6 +55,16 @@ whitelist_externals =
commands =
stestr run --blacklist-file ./broken-functional-py35-ssl-tests.txt {posargs}
+[testenv:functional-py37]
+basepython = python3.7
+setenv =
+ TEST_PATH = ./glance/tests/functional
+ignore_errors = True
+whitelist_externals =
+ bash
+commands =
+ stestr run --blacklist-file ./broken-functional-py35-ssl-tests.txt {posargs}
+
[testenv:broken-py35-ssl-tests]
# NOTE(rosmaita): these tests were being skipped due to bug #1482633, but we
# want it to be obvious that Glance is affected by the eventlet ssl-handshake