* [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/
@ 2015-08-14 5:21 Matt Thode
0 siblings, 0 replies; 5+ messages in thread
From: Matt Thode @ 2015-08-14 5:21 UTC (permalink / raw
To: gentoo-commits
commit: 2d4637cbfa732ff2cb94f440debc1ec813cafe58
Author: Matthew Thode <prometheanfire <AT> gentoo <DOT> org>
AuthorDate: Fri Aug 14 05:22:26 2015 +0000
Commit: Matt Thode <prometheanfire <AT> gentoo <DOT> org>
CommitDate: Fri Aug 14 05:22:26 2015 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=2d4637cb
app-admin/glance: fixing CVE-2015-5163
CVE: CVE-2015-5163
Signed-off-by: Matthew Thode <prometheanfire <AT> gentoo.org>
Package-Manager: portage-2.2.20.1
.../glance/files/cve-2015-5163-stable-kilo.patch | 260 +++++++++++++++++++++
...e-2015.1.1.ebuild => glance-2015.1.1-r1.ebuild} | 1 +
2 files changed, 261 insertions(+)
diff --git a/app-admin/glance/files/cve-2015-5163-stable-kilo.patch b/app-admin/glance/files/cve-2015-5163-stable-kilo.patch
new file mode 100644
index 0000000..91507c9
--- /dev/null
+++ b/app-admin/glance/files/cve-2015-5163-stable-kilo.patch
@@ -0,0 +1,260 @@
+From eb99e45829a1b4c93db5692bdbf636a86faa56c4 Mon Sep 17 00:00:00 2001
+From: Flavio Percoco <flaper87@gmail.com>
+Date: Thu, 9 Jul 2015 14:44:04 +0200
+Subject: Don't import files with backed files
+
+There's a security issue where it'd be possible to import images with
+backed files using the task engine and then use/convert those to access
+system files or any other file in the system. An example of an attack
+would be to import an image with a backing file pointing to
+`/etc/passwd`, then convert it to raw and download the generated image.
+
+This patch forbids importing files with baking files entirely. It does
+that in the `_ImportToFS` task, which is the one that imports the image
+locally to then execute other tasks on it. It's not necessary for the
+`_ImportToStore` task because other tasks won't be executed when the
+image is imported in the final store.
+
+Change-Id: I35f43c3b3f326942fb53b7dadb94700ac4513494
+Closes-bug: #1471912
+(cherry picked from commit d529863a1e8d2307526bdb395b4aebe97f81603d)
+
+diff --git a/glance/async/flows/base_import.py b/glance/async/flows/base_import.py
+index 7656bde..d216aa8 100644
+--- a/glance/async/flows/base_import.py
++++ b/glance/async/flows/base_import.py
+@@ -13,12 +13,15 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+
++import json
+ import logging
+ import os
+
+ import glance_store as store_api
+ from glance_store import backend
++from oslo_concurrency import processutils as putils
+ from oslo_config import cfg
++from oslo_utils import excutils
+ import six
+ from stevedore import named
+ from taskflow.patterns import linear_flow as lf
+@@ -146,6 +149,29 @@ class _ImportToFS(task.Task):
+ data = script_utils.get_image_data_iter(self.uri)
+
+ path = self.store.add(image_id, data, 0, context=None)[0]
++
++ try:
++ # NOTE(flaper87): Consider moving this code to a common
++ # place that other tasks can consume as well.
++ stdout, stderr = putils.trycmd('qemu-img', 'info',
++ '--output=json', path,
++ log_errors=putils.LOG_ALL_ERRORS)
++ except OSError as exc:
++ with excutils.save_and_reraise_exception():
++ msg = (_LE('Failed to execute security checks on the image '
++ '%(task_id)s: %(exc)s') %
++ {'task_id': self.task_id, 'exc': exc.message})
++ LOG.error(msg)
++
++ metadata = json.loads(stdout)
++
++ backing_file = metadata.get('backing-filename')
++ if backing_file is not None:
++ msg = _("File %(path)s has invalid backing file "
++ "%(bfile)s, aborting.") % {'path': path,
++ 'bfile': backing_file}
++ raise RuntimeError(msg)
++
+ return path
+
+ def revert(self, image_id, result=None, **kwargs):
+diff --git a/glance/tests/unit/async/flows/test_import.py b/glance/tests/unit/async/flows/test_import.py
+index 70f790c..4cf3d13 100644
+--- a/glance/tests/unit/async/flows/test_import.py
++++ b/glance/tests/unit/async/flows/test_import.py
+@@ -13,14 +13,17 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+
++import json
+ import mock
+ import os
+ import urllib2
+
+ import glance_store
++from oslo_concurrency import processutils as putils
+ from oslo_config import cfg
+ from six.moves import cStringIO
+ from taskflow import task
++from taskflow.types import failure
+
+ import glance.async.flows.base_import as import_flow
+ from glance.async import taskflow_executor
+@@ -106,16 +109,23 @@ class TestImportTask(test_utils.BaseTestCase):
+
+ with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
+ dmock.return_value = cStringIO("TEST_IMAGE")
+- executor.begin_processing(self.task.task_id)
+- image_path = os.path.join(self.test_dir, self.image.image_id)
+- tmp_image_path = os.path.join(self.work_dir,
+- "%s.tasks_import" % image_path)
+- self.assertFalse(os.path.exists(tmp_image_path))
+- self.assertTrue(os.path.exists(image_path))
+- self.assertEqual(1, len(list(self.image.locations)))
+- self.assertEqual("file://%s/%s" % (self.test_dir,
+- self.image.image_id),
+- self.image.locations[0]['url'])
++
++ with mock.patch.object(putils, 'trycmd') as tmock:
++ tmock.return_value = (json.dumps({
++ 'format': 'qcow2',
++ }), None)
++
++ executor.begin_processing(self.task.task_id)
++ image_path = os.path.join(self.test_dir, self.image.image_id)
++ tmp_image_path = os.path.join(self.work_dir,
++ "%s.tasks_import" % image_path)
++
++ self.assertFalse(os.path.exists(tmp_image_path))
++ self.assertTrue(os.path.exists(image_path))
++ self.assertEqual(1, len(list(self.image.locations)))
++ self.assertEqual("file://%s/%s" % (self.test_dir,
++ self.image.image_id),
++ self.image.locations[0]['url'])
+
+ def test_import_flow_missing_work_dir(self):
+ self.config(engine_mode='serial', group='taskflow_executor')
+@@ -151,6 +161,54 @@ class TestImportTask(test_utils.BaseTestCase):
+ self.assertFalse(os.path.exists(tmp_image_path))
+ self.assertTrue(os.path.exists(image_path))
+
++ def test_import_flow_backed_file_import_to_fs(self):
++ self.config(engine_mode='serial', group='taskflow_executor')
++
++ img_factory = mock.MagicMock()
++
++ executor = taskflow_executor.TaskExecutor(
++ self.context,
++ self.task_repo,
++ self.img_repo,
++ img_factory)
++
++ self.task_repo.get.return_value = self.task
++
++ def create_image(*args, **kwargs):
++ kwargs['image_id'] = UUID1
++ return self.img_factory.new_image(*args, **kwargs)
++
++ self.img_repo.get.return_value = self.image
++ img_factory.new_image.side_effect = create_image
++
++ with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
++ dmock.return_value = cStringIO("TEST_IMAGE")
++
++ with mock.patch.object(putils, 'trycmd') as tmock:
++ tmock.return_value = (json.dumps({
++ 'backing-filename': '/etc/password'
++ }), None)
++
++ with mock.patch.object(import_flow._ImportToFS,
++ 'revert') as rmock:
++ self.assertRaises(RuntimeError,
++ executor.begin_processing,
++ self.task.task_id)
++ self.assertTrue(rmock.called)
++ self.assertIsInstance(rmock.call_args[1]['result'],
++ failure.Failure)
++
++ image_path = os.path.join(self.test_dir,
++ self.image.image_id)
++
++ fname = "%s.tasks_import" % image_path
++ tmp_image_path = os.path.join(self.work_dir, fname)
++
++ self.assertFalse(os.path.exists(tmp_image_path))
++ # Note(sabari): The image should not have been uploaded to
++ # the store as the flow failed before ImportToStore Task.
++ self.assertFalse(os.path.exists(image_path))
++
+ def test_import_flow_revert(self):
+ self.config(engine_mode='serial',
+ group='taskflow_executor')
+@@ -175,20 +233,31 @@ class TestImportTask(test_utils.BaseTestCase):
+ with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
+ dmock.return_value = cStringIO("TEST_IMAGE")
+
+- with mock.patch.object(import_flow, "_get_import_flows") as imock:
+- imock.return_value = (x for x in [_ErrorTask()])
+- self.assertRaises(RuntimeError,
+- executor.begin_processing, self.task.task_id)
+- image_path = os.path.join(self.test_dir, self.image.image_id)
+- tmp_image_path = os.path.join(self.work_dir,
+- "%s.tasks_import" % image_path)
+- self.assertFalse(os.path.exists(tmp_image_path))
+-
+- # NOTE(flaper87): Eventually, we want this to be assertTrue.
+- # The current issue is there's no way to tell taskflow to
+- # continue on failures. That is, revert the subflow but keep
+- # executing the parent flow. Under discussion/development.
+- self.assertFalse(os.path.exists(image_path))
++ with mock.patch.object(putils, 'trycmd') as tmock:
++ tmock.return_value = (json.dumps({
++ 'format': 'qcow2',
++ }), None)
++
++ with mock.patch.object(import_flow,
++ "_get_import_flows") as imock:
++ imock.return_value = (x for x in [_ErrorTask()])
++ self.assertRaises(RuntimeError,
++ executor.begin_processing,
++ self.task.task_id)
++
++ image_path = os.path.join(self.test_dir,
++ self.image.image_id)
++ tmp_image_path = os.path.join(self.work_dir,
++ ("%s.tasks_import" %
++ image_path))
++ self.assertFalse(os.path.exists(tmp_image_path))
++
++ # NOTE(flaper87): Eventually, we want this to be assertTrue
++ # The current issue is there's no way to tell taskflow to
++ # continue on failures. That is, revert the subflow but
++ # keep executing the parent flow. Under
++ # discussion/development.
++ self.assertFalse(os.path.exists(image_path))
+
+ def test_import_flow_no_import_flows(self):
+ self.config(engine_mode='serial',
+@@ -271,15 +340,20 @@ class TestImportTask(test_utils.BaseTestCase):
+ with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
+ dmock.return_value = "test"
+
+- image_id = UUID1
+- path = import_fs.execute(image_id)
+- reader, size = glance_store.get_from_backend(path)
+- self.assertEqual(4, size)
+- self.assertEqual(dmock.return_value, "".join(reader))
++ with mock.patch.object(putils, 'trycmd') as tmock:
++ tmock.return_value = (json.dumps({
++ 'format': 'qcow2',
++ }), None)
++
++ image_id = UUID1
++ path = import_fs.execute(image_id)
++ reader, size = glance_store.get_from_backend(path)
++ self.assertEqual(4, size)
++ self.assertEqual(dmock.return_value, "".join(reader))
+
+- image_path = os.path.join(self.work_dir, image_id)
+- tmp_image_path = os.path.join(self.work_dir, image_path)
+- self.assertTrue(os.path.exists(tmp_image_path))
++ image_path = os.path.join(self.work_dir, image_id)
++ tmp_image_path = os.path.join(self.work_dir, image_path)
++ self.assertTrue(os.path.exists(tmp_image_path))
+
+ def test_delete_from_fs(self):
+ delete_fs = import_flow._DeleteFromFS(self.task.task_id,
+--
+cgit v0.10.2
+
diff --git a/app-admin/glance/glance-2015.1.1.ebuild b/app-admin/glance/glance-2015.1.1-r1.ebuild
similarity index 99%
rename from app-admin/glance/glance-2015.1.1.ebuild
rename to app-admin/glance/glance-2015.1.1-r1.ebuild
index b220166..e7df249 100644
--- a/app-admin/glance/glance-2015.1.1.ebuild
+++ b/app-admin/glance/glance-2015.1.1-r1.ebuild
@@ -137,6 +137,7 @@ RDEPEND="
"
PATCHES=(
+ "${FILESDIR}/cve-2015-5163-stable-kilo.patch"
)
pkg_setup() {
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/
@ 2015-09-22 17:46 Matt Thode
0 siblings, 0 replies; 5+ messages in thread
From: Matt Thode @ 2015-09-22 17:46 UTC (permalink / raw
To: gentoo-commits
commit: 4cb4bc39e1d1f115d6db596e0a7e6f23db3f924e
Author: Matthew Thode <mthode <AT> mthode <DOT> org>
AuthorDate: Tue Sep 22 17:45:22 2015 +0000
Commit: Matt Thode <prometheanfire <AT> gentoo <DOT> org>
CommitDate: Tue Sep 22 17:45:59 2015 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=4cb4bc39
app-admin/glance: fixing CVE-2015-5251
Package-Manager: portage-2.2.20.1
.../glance/files/cve-2015-5251-stable-kilo.patch | 192 +++++++++++++++++++++
app-admin/glance/glance-2015.1.1-r2.ebuild | 190 ++++++++++++++++++++
2 files changed, 382 insertions(+)
diff --git a/app-admin/glance/files/cve-2015-5251-stable-kilo.patch b/app-admin/glance/files/cve-2015-5251-stable-kilo.patch
new file mode 100644
index 0000000..f868645
--- /dev/null
+++ b/app-admin/glance/files/cve-2015-5251-stable-kilo.patch
@@ -0,0 +1,192 @@
+From 9beca533f42ae1fc87418de0c360e19bc59b24b5 Mon Sep 17 00:00:00 2001
+From: Stuart McLaren <stuart.mclaren@hp.com>
+Date: Tue, 11 Aug 2015 10:37:09 +0000
+Subject: [PATCH] Prevent image status being directly modified via v1
+
+Users shouldn't be able to change an image's status directly via the
+v1 API.
+
+Some existing consumers of Glance set the x-image-meta-status header in
+requests to the Glance API, eg:
+
+https://github.com/openstack/nova/blob/master/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance#L184
+
+We should try to prevent users setting 'status' via v1, but without breaking
+existing benign API calls such as these.
+
+I've adopted the following approach (which has some prior art in 'protected properties').
+
+If a PUT request is received which contains an x-image-meta-status header:
+
+* The user provided status is ignored if it matches the current image
+ status (this prevents benign calls such as the nova one above from
+ breaking). The usual code (eg 200) will be returned.
+
+* If the user provided status doesn't match the current image status (ie
+ there is a real attempt to change the value) 403 will be returned. This
+ will break any calls which currently intentionally change the status.
+
+APIImpact
+
+Closes-bug: 1482371
+
+Change-Id: I44fadf32abb57c962b67467091c3f51c1ccc25e6
+(cherry picked from commit 4d08db5b6d42323ac1958ef3b7417d875e7bea8c)
+---
+ glance/api/v1/__init__.py | 3 +
+ glance/api/v1/images.py | 9 +++
+ glance/tests/functional/v1/test_api.py | 89 ++++++++++++++++++++++
+ .../integration/legacy_functional/test_v1_api.py | 2 +
+ 4 files changed, 103 insertions(+)
+
+diff --git a/glance/api/v1/__init__.py b/glance/api/v1/__init__.py
+index 74de9aa1411d8e926770b67f7d851cf14e794414..9306bbb4fe78f77a26bb539c717fdfd2b38767c8 100644
+--- a/glance/api/v1/__init__.py
++++ b/glance/api/v1/__init__.py
+@@ -21,3 +21,6 @@ SUPPORTED_PARAMS = ('limit', 'marker', 'sort_key', 'sort_dir')
+
+ # Metadata which only an admin can change once the image is active
+ ACTIVE_IMMUTABLE = ('size', 'checksum')
++
++# Metadata which cannot be changed (irrespective of the current image state)
++IMMUTABLE = ('status',)
+diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
+index e33b91fbca79377e78ccfd329fa542ad422f5ffc..95e32949d958d0f57a3b60c141b91784a5801f5a 100644
+--- a/glance/api/v1/images.py
++++ b/glance/api/v1/images.py
+@@ -57,6 +57,7 @@ _LW = i18n._LW
+ SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
+ SUPPORTED_FILTERS = glance.api.v1.SUPPORTED_FILTERS
+ ACTIVE_IMMUTABLE = glance.api.v1.ACTIVE_IMMUTABLE
++IMMUTABLE = glance.api.v1.IMMUTABLE
+
+ CONF = cfg.CONF
+ CONF.import_opt('disk_formats', 'glance.common.config', group='image_format')
+@@ -912,6 +913,14 @@ class Controller(controller.BaseController):
+ request=req,
+ content_type="text/plain")
+
++ for key in IMMUTABLE:
++ if (image_meta.get(key) is not None and
++ image_meta.get(key) != orig_image_meta.get(key)):
++ msg = _("Forbidden to modify '%s' of image.") % key
++ raise HTTPForbidden(explanation=msg,
++ request=req,
++ content_type="text/plain")
++
+ # The default behaviour for a PUT /images/<IMAGE_ID> is to
+ # override any properties that were previously set. This, however,
+ # leads to a number of issues for the common use case where a caller
+diff --git a/glance/tests/functional/v1/test_api.py b/glance/tests/functional/v1/test_api.py
+index 9fba3bb5e40c8742530691228c7b436b385fc2ca..6b3bfbb4270f1eb0f50418504e65be30ea23d10b 100644
+--- a/glance/tests/functional/v1/test_api.py
++++ b/glance/tests/functional/v1/test_api.py
+@@ -715,3 +715,92 @@ class TestApi(functional.FunctionalTest):
+ self.assertEqual(404, response.status)
+
+ self.stop_servers()
++
++ def test_status_cannot_be_manipulated_directly(self):
++ self.cleanup()
++ self.start_servers(**self.__dict__.copy())
++ headers = minimal_headers('Image1')
++
++ # Create a 'queued' image
++ http = httplib2.Http()
++ headers = {'Content-Type': 'application/octet-stream',
++ 'X-Image-Meta-Disk-Format': 'raw',
++ 'X-Image-Meta-Container-Format': 'bare'}
++ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
++ response, content = http.request(path, 'POST', headers=headers,
++ body=None)
++ self.assertEqual(201, response.status)
++ image = jsonutils.loads(content)['image']
++ self.assertEqual('queued', image['status'])
++
++ # Ensure status of 'queued' image can't be changed
++ path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
++ image['id'])
++ http = httplib2.Http()
++ headers = {'X-Image-Meta-Status': 'active'}
++ response, content = http.request(path, 'PUT', headers=headers)
++ self.assertEqual(403, response.status)
++ response, content = http.request(path, 'HEAD')
++ self.assertEqual(200, response.status)
++ self.assertEqual('queued', response['x-image-meta-status'])
++
++ # We allow 'setting' to the same status
++ http = httplib2.Http()
++ headers = {'X-Image-Meta-Status': 'queued'}
++ response, content = http.request(path, 'PUT', headers=headers)
++ self.assertEqual(200, response.status)
++ response, content = http.request(path, 'HEAD')
++ self.assertEqual(200, response.status)
++ self.assertEqual('queued', response['x-image-meta-status'])
++
++ # Make image active
++ http = httplib2.Http()
++ headers = {'Content-Type': 'application/octet-stream'}
++ response, content = http.request(path, 'PUT', headers=headers,
++ body='data')
++ self.assertEqual(200, response.status)
++ image = jsonutils.loads(content)['image']
++ self.assertEqual('active', image['status'])
++
++ # Ensure status of 'active' image can't be changed
++ http = httplib2.Http()
++ headers = {'X-Image-Meta-Status': 'queued'}
++ response, content = http.request(path, 'PUT', headers=headers)
++ self.assertEqual(403, response.status)
++ response, content = http.request(path, 'HEAD')
++ self.assertEqual(200, response.status)
++ self.assertEqual('active', response['x-image-meta-status'])
++
++ # We allow 'setting' to the same status
++ http = httplib2.Http()
++ headers = {'X-Image-Meta-Status': 'active'}
++ response, content = http.request(path, 'PUT', headers=headers)
++ self.assertEqual(200, response.status)
++ response, content = http.request(path, 'HEAD')
++ self.assertEqual(200, response.status)
++ self.assertEqual('active', response['x-image-meta-status'])
++
++ # Create a 'queued' image, ensure 'status' header is ignored
++ http = httplib2.Http()
++ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
++ headers = {'Content-Type': 'application/octet-stream',
++ 'X-Image-Meta-Status': 'active'}
++ response, content = http.request(path, 'POST', headers=headers,
++ body=None)
++ self.assertEqual(201, response.status)
++ image = jsonutils.loads(content)['image']
++ self.assertEqual('queued', image['status'])
++
++ # Create an 'active' image, ensure 'status' header is ignored
++ http = httplib2.Http()
++ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
++ headers = {'Content-Type': 'application/octet-stream',
++ 'X-Image-Meta-Disk-Format': 'raw',
++ 'X-Image-Meta-Status': 'queued',
++ 'X-Image-Meta-Container-Format': 'bare'}
++ response, content = http.request(path, 'POST', headers=headers,
++ body='data')
++ self.assertEqual(201, response.status)
++ image = jsonutils.loads(content)['image']
++ self.assertEqual('active', image['status'])
++ self.stop_servers()
+diff --git a/glance/tests/integration/legacy_functional/test_v1_api.py b/glance/tests/integration/legacy_functional/test_v1_api.py
+index dff436465919569480bdbac537d20a6d61c98f46..511d46dfe18028bb430504784cc9d24c58736c3b 100644
+--- a/glance/tests/integration/legacy_functional/test_v1_api.py
++++ b/glance/tests/integration/legacy_functional/test_v1_api.py
+@@ -358,6 +358,8 @@ class TestApi(base.ApiTest):
+ path = "/v1/images"
+ response, content = self.http.request(path, 'POST', headers=headers)
+ self.assertEqual(201, response.status)
++ image = jsonutils.loads(content)['image']
++ self.assertEqual('active', image['status'])
+
+ # 2. HEAD image-location
+ # Verify image size is zero and the status is active
+--
+2.5.0
+
diff --git a/app-admin/glance/glance-2015.1.1-r2.ebuild b/app-admin/glance/glance-2015.1.1-r2.ebuild
new file mode 100644
index 0000000..2083b07
--- /dev/null
+++ b/app-admin/glance/glance-2015.1.1-r2.ebuild
@@ -0,0 +1,190 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=5
+PYTHON_COMPAT=( python2_7 )
+
+inherit distutils-r1 user
+
+DESCRIPTION="Provides services for discovering, registering, and retrieving
+virtual machine images"
+HOMEPAGE="https://launchpad.net/glance"
+SRC_URI="https://launchpad.net/${PN}/kilo/${PV}/+download/${P}.tar.gz"
+
+LICENSE="Apache-2.0"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE="doc mysql postgres +sqlite +swift test"
+REQUIRED_USE="|| ( mysql postgres sqlite )"
+
+DEPEND="
+ dev-python/setuptools[${PYTHON_USEDEP}]
+ >=dev-python/pbr-0.8.0[${PYTHON_USEDEP}]
+ <dev-python/pbr-1.0[${PYTHON_USEDEP}]
+ test? (
+ ${RDEPEND}
+ >=dev-python/hacking-0.10.0[${PYTHON_USEDEP}]
+ <dev-python/hacking-0.11[${PYTHON_USEDEP}]
+ ~dev-python/Babel-1.3[${PYTHON_USEDEP}]
+ >=dev-python/coverage-3.6[${PYTHON_USEDEP}]
+ >=dev-python/fixtures-0.3.14[${PYTHON_USEDEP}]
+ <dev-python/fixtures-1.3.0[${PYTHON_USEDEP}]
+ >=dev-python/mock-1.0[${PYTHON_USEDEP}]
+ <dev-python/mock-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}]
+ !~dev-python/sphinx-1.2.0[${PYTHON_USEDEP}]
+ <dev-python/sphinx-1.3[${PYTHON_USEDEP}]
+ >=dev-python/requests-2.2.0[${PYTHON_USEDEP}]
+ !~dev-python/requests-2.4.0[${PYTHON_USEDEP}]
+ >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
+ >=dev-python/testtools-0.9.36[${PYTHON_USEDEP}]
+ !~dev-python/testtools-1.2.0[${PYTHON_USEDEP}]
+ >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
+ <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
+ >=dev-python/oslotest-1.5.1[${PYTHON_USEDEP}]
+ <dev-python/oslotest-1.6.0[${PYTHON_USEDEP}]
+ dev-python/mysql-python[${PYTHON_USEDEP}]
+ dev-python/psycopg[${PYTHON_USEDEP}]
+ ~dev-python/pysendfile-2.0.1[${PYTHON_USEDEP}]
+ dev-python/qpid-python[${PYTHON_USEDEP}]
+ >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-sphinx-2.5.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-sphinx-2.6.0[${PYTHON_USEDEP}]
+ >=dev-python/elasticsearch-py-1.3.0[${PYTHON_USEDEP}]
+ )"
+
+#note to self, wsgiref is a python builtin, no need to package it
+#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
+
+RDEPEND="
+ >=dev-python/greenlet-0.3.2[${PYTHON_USEDEP}]
+ sqlite? (
+ >=dev-python/sqlalchemy-0.9.7[sqlite,${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[sqlite,${PYTHON_USEDEP}]
+ )
+ mysql? (
+ dev-python/mysql-python
+ >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
+ )
+ postgres? (
+ dev-python/psycopg:2
+ >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
+ )
+ >=dev-python/anyjson-0.3.3[${PYTHON_USEDEP}]
+ >=dev-python/eventlet-0.16.1[${PYTHON_USEDEP}]
+ !~dev-python/eventlet-0.17.0[${PYTHON_USEDEP}]
+ >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
+ !~dev-python/routes-2.0[${PYTHON_USEDEP}]
+ >=dev-python/webob-1.2.3[${PYTHON_USEDEP}]
+ >=dev-python/sqlalchemy-migrate-0.9.5[${PYTHON_USEDEP}]
+ >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
+ >=dev-python/kombu-2.5.0[${PYTHON_USEDEP}]
+ >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
+ >=dev-python/iso8601-0.1.9[${PYTHON_USEDEP}]
+ dev-python/ordereddict[${PYTHON_USEDEP}]
+ >=dev-python/oslo-config-1.9.3[${PYTHON_USEDEP}]
+ <dev-python/oslo-config-1.10.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-concurrency-1.8.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-concurrency-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-context-0.2.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-context-0.3.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-utils-1.4.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-utils-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/stevedore-1.3.0[${PYTHON_USEDEP}]
+ <dev-python/stevedore-1.4.0[${PYTHON_USEDEP}]
+ >=dev-python/taskflow-0.7.1[${PYTHON_USEDEP}]
+ <dev-python/taskflow-0.8.0[${PYTHON_USEDEP}]
+ >=dev-python/keystonemiddleware-1.5.0[${PYTHON_USEDEP}]
+ <dev-python/keystonemiddleware-1.6.0[${PYTHON_USEDEP}]
+ >=dev-python/WSME-0.6[${PYTHON_USEDEP}]
+ <dev-python/WSME-0.7[${PYTHON_USEDEP}]
+ dev-python/posix_ipc[${PYTHON_USEDEP}]
+ swift? (
+ >=dev-python/python-swiftclient-2.2.0[${PYTHON_USEDEP}]
+ <dev-python/python-swiftclient-2.5.0[${PYTHON_USEDEP}]
+ )
+ >=dev-python/oslo-vmware-0.11.1[${PYTHON_USEDEP}]
+ <dev-python/oslo-vmware-0.12.0[${PYTHON_USEDEP}]
+ dev-python/paste[${PYTHON_USEDEP}]
+ >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
+ <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
+ >=dev-python/python-keystoneclient-1.2.0[${PYTHON_USEDEP}]
+ <dev-python/python-keystoneclient-1.4.0[${PYTHON_USEDEP}]
+ >=dev-python/pyopenssl-0.11[${PYTHON_USEDEP}]
+ >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-db-1.7.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-db-1.8.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-i18n-1.5.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-i18n-1.6.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-log-1.0.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-log-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-messaging-1.8.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-messaging-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-policy-0.3.1[${PYTHON_USEDEP}]
+ <dev-python/oslo-policy-0.4.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-serialization-1.4.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-serialization-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
+ !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
+ >=dev-python/osprofiler-0.3.0[${PYTHON_USEDEP}]
+ >=dev-python/glance_store-0.3.0[${PYTHON_USEDEP}]
+ <dev-python/glance_store-0.5.0[${PYTHON_USEDEP}]
+ >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
+"
+
+PATCHES=(
+ "${FILESDIR}/cve-2015-5163-stable-kilo.patch"
+ "${FILESDIR}/cve-2015-5251-stable-kilo.patch"
+)
+
+pkg_setup() {
+ enewgroup glance
+ enewuser glance -1 -1 /var/lib/glance glance
+}
+
+python_prepare_all() {
+ sed -i '/xattr/d' test-requirements.txt || die
+ sed -i '/pysendfile/d' test-requirements.txt || die
+ distutils-r1_python_prepare_all
+}
+
+python_compile_all() {
+ use doc && "${PYTHON}" setup.py build_sphinx
+}
+
+python_test() {
+ # https://bugs.launchpad.net/glance/+bug/1251105
+ # https://bugs.launchpad.net/glance/+bug/1242501
+ testr init
+ testr run --parallel || die "failed testsuite under python2.7"
+}
+
+python_install() {
+ distutils-r1_python_install
+
+ for svc in api registry scrubber; do
+ newinitd "${FILESDIR}/glance.initd" glance-${svc}
+ done
+
+ diropts -m 0750 -o glance -g glance
+ dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
+ keepdir /etc/glance
+ keepdir /var/log/glance
+ keepdir /var/lib/glance/images
+ keepdir /var/lib/glance/scrubber
+
+ insinto /etc/glance
+ insopts -m 0640 -o glance -g glance
+ doins etc/*.ini
+ doins etc/*.conf
+ doins etc/*.sample
+}
+
+python_install_all() {
+ use doc && local HTML_DOCS=( doc/build/html/. )
+ distutils-r1_python_install_all
+}
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/
@ 2015-10-03 19:14 Matt Thode
0 siblings, 0 replies; 5+ messages in thread
From: Matt Thode @ 2015-10-03 19:14 UTC (permalink / raw
To: gentoo-commits
commit: 0cbb7fc1a349f095ff77fea9b8857c57e7c5fd54
Author: Matthew Thode <prometheanfire <AT> gentoo <DOT> org>
AuthorDate: Sat Oct 3 19:13:15 2015 +0000
Commit: Matt Thode <prometheanfire <AT> gentoo <DOT> org>
CommitDate: Sat Oct 3 19:13:49 2015 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0cbb7fc1
app-admin/glance: fixing CVE-2015-5286
Package-Manager: portage-2.2.20.1
.../glance/files/CVE-2015-3289_2015.1.0.patch | 50 ------
.../glance/files/CVE-2015-5286_2015.1.1.patch | 137 +++++++++++++++
app-admin/glance/glance-2015.1.1-r3.ebuild | 191 +++++++++++++++++++++
3 files changed, 328 insertions(+), 50 deletions(-)
diff --git a/app-admin/glance/files/CVE-2015-3289_2015.1.0.patch b/app-admin/glance/files/CVE-2015-3289_2015.1.0.patch
deleted file mode 100644
index 5b69774..0000000
--- a/app-admin/glance/files/CVE-2015-3289_2015.1.0.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 88f92eb11d556bf43e2800a05973ad2da0db0195 Mon Sep 17 00:00:00 2001
-From: Flavio Percoco <flaper87@gmail.com>
-Date: Fri, 8 May 2015 11:44:14 +0200
-Subject: [PATCH] Save image data after setting the data
-
-The image's locations are missing when image's are imported using tasks
-because the ImportToStore task is not saving the image metadata after
-the import. This patch fixes that.
-
-Change-Id: I43dec450d5fc4bee2131d78dbe3c2b2373c3f739
-Closes-bug: #1453068
-(cherry picked from commit 4efb56aae9288952bdb0d368a7c307e8524b80d8)
----
- glance/async/flows/base_import.py | 4 ++++
- glance/tests/unit/async/flows/test_import.py | 4 ++++
- 2 files changed, 8 insertions(+)
-
-diff --git a/glance/async/flows/base_import.py b/glance/async/flows/base_import.py
-index 487247c..7656bde 100644
---- a/glance/async/flows/base_import.py
-+++ b/glance/async/flows/base_import.py
-@@ -283,6 +283,10 @@ class _ImportToStore(task.Task):
-
- image_import.set_image_data(image, file_path or self.uri, None)
-
-+ # NOTE(flaper87): We need to save the image again after the locations
-+ # have been set in the image.
-+ self.image_repo.save(image)
-+
-
- class _SaveImage(task.Task):
-
-diff --git a/glance/tests/unit/async/flows/test_import.py b/glance/tests/unit/async/flows/test_import.py
-index 0f355bc..7acd599 100644
---- a/glance/tests/unit/async/flows/test_import.py
-+++ b/glance/tests/unit/async/flows/test_import.py
-@@ -112,6 +112,10 @@ class TestImportTask(test_utils.BaseTestCase):
- "%s.tasks_import" % image_path)
- self.assertFalse(os.path.exists(tmp_image_path))
- self.assertTrue(os.path.exists(image_path))
-+ self.assertEqual(1, len(list(self.image.locations)))
-+ self.assertEqual("file://%s/%s" % (self.test_dir,
-+ self.image.image_id),
-+ self.image.locations[0]['url'])
-
- def test_import_flow_missing_work_dir(self):
- self.config(engine_mode='serial', group='taskflow_executor')
---
-2.3.6
-
diff --git a/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch b/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch
new file mode 100644
index 0000000..0478135
--- /dev/null
+++ b/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch
@@ -0,0 +1,137 @@
+From 5bebd513fa71edcdb84f7dec7b16f3523c0c1092 Mon Sep 17 00:00:00 2001
+From: Mike Fedosin <mfedosin@mirantis.com>
+Date: Sun, 20 Sep 2015 17:01:22 +0300
+Subject: Cleanup chunks for deleted image if token expired
+
+In patch I47229b366c25367ec1bd48aec684e0880f3dfe60 it was
+introduced the logic that if image was deleted during file
+upload when we want to update image status from 'saving'
+to 'active' it's expected to get Duplicate error and delete
+stale chunks after that. But if user's token is expired
+there will be Unathorized exception and chunks will stay
+in store and clog it.
+And when, the upload operation for such an image is
+completed the operator configured quota can be exceeded.
+
+This patch fixes the issue of left over chunks for an image
+which was deleted from saving status, by correctly handle
+auth exceptions from registry server.
+
+Partial-bug: #1498163
+
+Conflicts:
+ glance/api/v1/upload_utils.py
+ (Kilo catches NotFound instead of ImagenotFound)
+
+Change-Id: I17a66eca55bfb83107046910e69c4da01415deec
+(cherry picked from commit 98a8832777a0639a4031e52c69f0d565b3f500c5)
+
+diff --git a/glance/api/v1/upload_utils.py b/glance/api/v1/upload_utils.py
+index 7adb2dc..ad4f724 100644
+--- a/glance/api/v1/upload_utils.py
++++ b/glance/api/v1/upload_utils.py
+@@ -171,6 +171,14 @@ def upload_data_to_store(req, image_meta, image_data, store, notifier):
+ raise exception.NotFound()
+ else:
+ raise
++
++ except exception.NotAuthenticated as e:
++ # Delete image data due to possible token expiration.
++ LOG.debug("Authentication error - the token may have "
++ "expired during file upload. Deleting image data for "
++ " %s " % image_id)
++ initiate_deletion(req, location_data, image_id)
++ raise webob.exc.HTTPUnauthorized(explanation=e.msg, request=req)
+ except exception.NotFound:
+ msg = _LI("Image %s could not be found after upload. The image may"
+ " have been deleted during the upload.") % image_id
+diff --git a/glance/api/v2/image_data.py b/glance/api/v2/image_data.py
+index 4025eeb..9967662 100644
+--- a/glance/api/v2/image_data.py
++++ b/glance/api/v2/image_data.py
+@@ -88,7 +88,19 @@ class ImageDataController(object):
+ raise webob.exc.HTTPGone(explanation=msg,
+ request=req,
+ content_type='text/plain')
+-
++ except exception.NotAuthenticated:
++ msg = (_("Authentication error - the token may have "
++ "expired during file upload. Deleting image data for "
++ "%s.") % image_id)
++ LOG.debug(msg)
++ try:
++ image.delete()
++ except exception.NotAuthenticated:
++ # NOTE: Ignore this exception
++ pass
++ raise webob.exc.HTTPUnauthorized(explanation=msg,
++ request=req,
++ content_type='text/plain')
+ except ValueError as e:
+ LOG.debug("Cannot save data for image %(id)s: %(e)s",
+ {'id': image_id, 'e': utils.exception_to_str(e)})
+diff --git a/glance/tests/unit/v1/test_upload_utils.py b/glance/tests/unit/v1/test_upload_utils.py
+index 1afaf00..8d05515 100644
+--- a/glance/tests/unit/v1/test_upload_utils.py
++++ b/glance/tests/unit/v1/test_upload_utils.py
+@@ -323,3 +323,29 @@ class TestUploadUtils(base.StoreClearingUnitTest):
+ 'metadata': {}}, image_meta['id'])
+ mock_safe_kill.assert_called_once_with(
+ req, image_meta['id'], 'saving')
++
++ @mock.patch.object(registry, 'update_image_metadata',
++ side_effect=exception.NotAuthenticated)
++ @mock.patch.object(upload_utils, 'initiate_deletion')
++ def test_activate_image_with_expired_token(
++ self, mocked_delete, mocked_update):
++ """Test token expiration during image upload.
++
++ If users token expired before image was uploaded then if auth error
++ was caught from registry during changing image status from 'saving'
++ to 'active' then it's required to delete all image data.
++ """
++ context = mock.Mock()
++ req = mock.Mock()
++ req.context = context
++ with self._get_store_and_notifier() as (location, checksum, image_meta,
++ image_data, store, notifier,
++ update_data):
++ self.assertRaises(webob.exc.HTTPUnauthorized,
++ upload_utils.upload_data_to_store,
++ req, image_meta, image_data, store, notifier)
++ self.assertEqual(2, mocked_update.call_count)
++ mocked_delete.assert_called_once_with(
++ req,
++ {'url': 'file://foo/bar', 'status': 'active', 'metadata': {}},
++ 'c80a1a6c-bd1f-41c5-90ee-81afedb1d58d')
+diff --git a/glance/tests/unit/v2/test_image_data_resource.py b/glance/tests/unit/v2/test_image_data_resource.py
+index bc8891e..7458eda 100644
+--- a/glance/tests/unit/v2/test_image_data_resource.py
++++ b/glance/tests/unit/v2/test_image_data_resource.py
+@@ -192,6 +192,23 @@ class TestImagesController(base.StoreClearingUnitTest):
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.upload,
+ request, unit_test_utils.UUID1, 'YYYY', 4)
+
++ def test_upload_with_expired_token(self):
++ def side_effect(image, from_state=None):
++ if from_state == 'saving':
++ raise exception.NotAuthenticated()
++
++ mocked_save = mock.Mock(side_effect=side_effect)
++ mocked_delete = mock.Mock()
++ request = unit_test_utils.get_fake_request()
++ image = FakeImage('abcd')
++ image.delete = mocked_delete
++ self.image_repo.result = image
++ self.image_repo.save = mocked_save
++ self.assertRaises(webob.exc.HTTPUnauthorized, self.controller.upload,
++ request, unit_test_utils.UUID1, 'YYYY', 4)
++ self.assertEqual(3, mocked_save.call_count)
++ mocked_delete.assert_called_once_with()
++
+ def test_upload_non_existent_image_during_save_initiates_deletion(self):
+ def fake_save_not_found(self):
+ raise exception.NotFound()
+--
+cgit v0.10.2
+
diff --git a/app-admin/glance/glance-2015.1.1-r3.ebuild b/app-admin/glance/glance-2015.1.1-r3.ebuild
new file mode 100644
index 0000000..10eda7d
--- /dev/null
+++ b/app-admin/glance/glance-2015.1.1-r3.ebuild
@@ -0,0 +1,191 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=5
+PYTHON_COMPAT=( python2_7 )
+
+inherit distutils-r1 user
+
+DESCRIPTION="Provides services for discovering, registering, and retrieving
+virtual machine images"
+HOMEPAGE="https://launchpad.net/glance"
+SRC_URI="https://launchpad.net/${PN}/kilo/${PV}/+download/${P}.tar.gz"
+
+LICENSE="Apache-2.0"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE="doc mysql postgres +sqlite +swift test"
+REQUIRED_USE="|| ( mysql postgres sqlite )"
+
+DEPEND="
+ dev-python/setuptools[${PYTHON_USEDEP}]
+ >=dev-python/pbr-0.8.0[${PYTHON_USEDEP}]
+ <dev-python/pbr-1.0[${PYTHON_USEDEP}]
+ test? (
+ ${RDEPEND}
+ >=dev-python/hacking-0.10.0[${PYTHON_USEDEP}]
+ <dev-python/hacking-0.11[${PYTHON_USEDEP}]
+ >=dev-python/Babel-1.3[${PYTHON_USEDEP}]
+ >=dev-python/coverage-3.6[${PYTHON_USEDEP}]
+ >=dev-python/fixtures-0.3.14[${PYTHON_USEDEP}]
+ <dev-python/fixtures-1.3.0[${PYTHON_USEDEP}]
+ >=dev-python/mock-1.0[${PYTHON_USEDEP}]
+ <dev-python/mock-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}]
+ !~dev-python/sphinx-1.2.0[${PYTHON_USEDEP}]
+ <dev-python/sphinx-1.3[${PYTHON_USEDEP}]
+ >=dev-python/requests-2.2.0[${PYTHON_USEDEP}]
+ !~dev-python/requests-2.4.0[${PYTHON_USEDEP}]
+ >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
+ >=dev-python/testtools-0.9.36[${PYTHON_USEDEP}]
+ !~dev-python/testtools-1.2.0[${PYTHON_USEDEP}]
+ >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
+ <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
+ >=dev-python/oslotest-1.5.1[${PYTHON_USEDEP}]
+ <dev-python/oslotest-1.6.0[${PYTHON_USEDEP}]
+ dev-python/mysql-python[${PYTHON_USEDEP}]
+ dev-python/psycopg[${PYTHON_USEDEP}]
+ ~dev-python/pysendfile-2.0.1[${PYTHON_USEDEP}]
+ dev-python/qpid-python[${PYTHON_USEDEP}]
+ >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-sphinx-2.5.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-sphinx-2.6.0[${PYTHON_USEDEP}]
+ >=dev-python/elasticsearch-py-1.3.0[${PYTHON_USEDEP}]
+ )"
+
+#note to self, wsgiref is a python builtin, no need to package it
+#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
+
+RDEPEND="
+ >=dev-python/greenlet-0.3.2[${PYTHON_USEDEP}]
+ sqlite? (
+ >=dev-python/sqlalchemy-0.9.7[sqlite,${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[sqlite,${PYTHON_USEDEP}]
+ )
+ mysql? (
+ dev-python/mysql-python
+ >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
+ )
+ postgres? (
+ dev-python/psycopg:2
+ >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
+ )
+ >=dev-python/anyjson-0.3.3[${PYTHON_USEDEP}]
+ >=dev-python/eventlet-0.16.1[${PYTHON_USEDEP}]
+ !~dev-python/eventlet-0.17.0[${PYTHON_USEDEP}]
+ >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
+ !~dev-python/routes-2.0[${PYTHON_USEDEP}]
+ >=dev-python/webob-1.2.3[${PYTHON_USEDEP}]
+ >=dev-python/sqlalchemy-migrate-0.9.5[${PYTHON_USEDEP}]
+ >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
+ >=dev-python/kombu-2.5.0[${PYTHON_USEDEP}]
+ >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
+ >=dev-python/iso8601-0.1.9[${PYTHON_USEDEP}]
+ dev-python/ordereddict[${PYTHON_USEDEP}]
+ >=dev-python/oslo-config-1.9.3[${PYTHON_USEDEP}]
+ <dev-python/oslo-config-1.10.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-concurrency-1.8.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-concurrency-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-context-0.2.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-context-0.3.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-utils-1.4.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-utils-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/stevedore-1.3.0[${PYTHON_USEDEP}]
+ <dev-python/stevedore-1.4.0[${PYTHON_USEDEP}]
+ >=dev-python/taskflow-0.7.1[${PYTHON_USEDEP}]
+ <dev-python/taskflow-0.8.0[${PYTHON_USEDEP}]
+ >=dev-python/keystonemiddleware-1.5.0[${PYTHON_USEDEP}]
+ <dev-python/keystonemiddleware-1.6.0[${PYTHON_USEDEP}]
+ >=dev-python/WSME-0.6[${PYTHON_USEDEP}]
+ <dev-python/WSME-0.7[${PYTHON_USEDEP}]
+ dev-python/posix_ipc[${PYTHON_USEDEP}]
+ swift? (
+ >=dev-python/python-swiftclient-2.2.0[${PYTHON_USEDEP}]
+ <dev-python/python-swiftclient-2.5.0[${PYTHON_USEDEP}]
+ )
+ >=dev-python/oslo-vmware-0.11.1[${PYTHON_USEDEP}]
+ <dev-python/oslo-vmware-0.12.0[${PYTHON_USEDEP}]
+ dev-python/paste[${PYTHON_USEDEP}]
+ >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
+ <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
+ >=dev-python/python-keystoneclient-1.2.0[${PYTHON_USEDEP}]
+ <dev-python/python-keystoneclient-1.4.0[${PYTHON_USEDEP}]
+ >=dev-python/pyopenssl-0.11[${PYTHON_USEDEP}]
+ >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-db-1.7.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-db-1.8.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-i18n-1.5.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-i18n-1.6.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-log-1.0.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-log-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-messaging-1.8.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-messaging-1.9.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-policy-0.3.1[${PYTHON_USEDEP}]
+ <dev-python/oslo-policy-0.4.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-serialization-1.4.0[${PYTHON_USEDEP}]
+ <dev-python/oslo-serialization-1.5.0[${PYTHON_USEDEP}]
+ >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
+ !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
+ >=dev-python/osprofiler-0.3.0[${PYTHON_USEDEP}]
+ >=dev-python/glance_store-0.3.0[${PYTHON_USEDEP}]
+ <dev-python/glance_store-0.5.0[${PYTHON_USEDEP}]
+ >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
+"
+
+PATCHES=(
+ "${FILESDIR}/cve-2015-5163-stable-kilo.patch"
+ "${FILESDIR}/cve-2015-5251-stable-kilo.patch"
+ "${FILESDIR}/CVE-2015-5286_2015.1.1.patch"
+)
+
+pkg_setup() {
+ enewgroup glance
+ enewuser glance -1 -1 /var/lib/glance glance
+}
+
+python_prepare_all() {
+ sed -i '/xattr/d' test-requirements.txt || die
+ sed -i '/pysendfile/d' test-requirements.txt || die
+ distutils-r1_python_prepare_all
+}
+
+python_compile_all() {
+ use doc && "${PYTHON}" setup.py build_sphinx
+}
+
+python_test() {
+ # https://bugs.launchpad.net/glance/+bug/1251105
+ # https://bugs.launchpad.net/glance/+bug/1242501
+ testr init
+ testr run --parallel || die "failed testsuite under python2.7"
+}
+
+python_install() {
+ distutils-r1_python_install
+
+ for svc in api registry scrubber; do
+ newinitd "${FILESDIR}/glance.initd" glance-${svc}
+ done
+
+ diropts -m 0750 -o glance -g glance
+ dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
+ keepdir /etc/glance
+ keepdir /var/log/glance
+ keepdir /var/lib/glance/images
+ keepdir /var/lib/glance/scrubber
+
+ insinto /etc/glance
+ insopts -m 0640 -o glance -g glance
+ doins etc/*.ini
+ doins etc/*.conf
+ doins etc/*.sample
+}
+
+python_install_all() {
+ use doc && local HTML_DOCS=( doc/build/html/. )
+ distutils-r1_python_install_all
+}
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/
@ 2016-02-04 17:34 Matt Thode
0 siblings, 0 replies; 5+ messages in thread
From: Matt Thode @ 2016-02-04 17:34 UTC (permalink / raw
To: gentoo-commits
commit: 9923cf35ae299d9643c1122dfea857e5f76667f8
Author: Matthew Thode <prometheanfire <AT> gentoo <DOT> org>
AuthorDate: Thu Feb 4 17:32:33 2016 +0000
Commit: Matt Thode <prometheanfire <AT> gentoo <DOT> org>
CommitDate: Thu Feb 4 17:33:45 2016 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=9923cf35
app-admin/glance: fix bug 573844 CVE-2016-0757
Package-Manager: portage-2.2.26
.../glance/files/CVE-2015-5286_2015.1.1.patch | 137 ---------
.../glance/files/cve-2015-5163-stable-kilo.patch | 260 ----------------
.../glance/files/cve-2015-5251-stable-kilo.patch | 192 ------------
.../files/cve-2016-0757-stable-liberty.patch | 332 +++++++++++++++++++++
.../files/glance-2013.2-sphinx_mapping.patch | 12 -
app-admin/glance/glance-11.0.1-r1.ebuild | 229 ++++++++++++++
6 files changed, 561 insertions(+), 601 deletions(-)
diff --git a/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch b/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch
deleted file mode 100644
index 0478135..0000000
--- a/app-admin/glance/files/CVE-2015-5286_2015.1.1.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From 5bebd513fa71edcdb84f7dec7b16f3523c0c1092 Mon Sep 17 00:00:00 2001
-From: Mike Fedosin <mfedosin@mirantis.com>
-Date: Sun, 20 Sep 2015 17:01:22 +0300
-Subject: Cleanup chunks for deleted image if token expired
-
-In patch I47229b366c25367ec1bd48aec684e0880f3dfe60 it was
-introduced the logic that if image was deleted during file
-upload when we want to update image status from 'saving'
-to 'active' it's expected to get Duplicate error and delete
-stale chunks after that. But if user's token is expired
-there will be Unathorized exception and chunks will stay
-in store and clog it.
-And when, the upload operation for such an image is
-completed the operator configured quota can be exceeded.
-
-This patch fixes the issue of left over chunks for an image
-which was deleted from saving status, by correctly handle
-auth exceptions from registry server.
-
-Partial-bug: #1498163
-
-Conflicts:
- glance/api/v1/upload_utils.py
- (Kilo catches NotFound instead of ImagenotFound)
-
-Change-Id: I17a66eca55bfb83107046910e69c4da01415deec
-(cherry picked from commit 98a8832777a0639a4031e52c69f0d565b3f500c5)
-
-diff --git a/glance/api/v1/upload_utils.py b/glance/api/v1/upload_utils.py
-index 7adb2dc..ad4f724 100644
---- a/glance/api/v1/upload_utils.py
-+++ b/glance/api/v1/upload_utils.py
-@@ -171,6 +171,14 @@ def upload_data_to_store(req, image_meta, image_data, store, notifier):
- raise exception.NotFound()
- else:
- raise
-+
-+ except exception.NotAuthenticated as e:
-+ # Delete image data due to possible token expiration.
-+ LOG.debug("Authentication error - the token may have "
-+ "expired during file upload. Deleting image data for "
-+ " %s " % image_id)
-+ initiate_deletion(req, location_data, image_id)
-+ raise webob.exc.HTTPUnauthorized(explanation=e.msg, request=req)
- except exception.NotFound:
- msg = _LI("Image %s could not be found after upload. The image may"
- " have been deleted during the upload.") % image_id
-diff --git a/glance/api/v2/image_data.py b/glance/api/v2/image_data.py
-index 4025eeb..9967662 100644
---- a/glance/api/v2/image_data.py
-+++ b/glance/api/v2/image_data.py
-@@ -88,7 +88,19 @@ class ImageDataController(object):
- raise webob.exc.HTTPGone(explanation=msg,
- request=req,
- content_type='text/plain')
--
-+ except exception.NotAuthenticated:
-+ msg = (_("Authentication error - the token may have "
-+ "expired during file upload. Deleting image data for "
-+ "%s.") % image_id)
-+ LOG.debug(msg)
-+ try:
-+ image.delete()
-+ except exception.NotAuthenticated:
-+ # NOTE: Ignore this exception
-+ pass
-+ raise webob.exc.HTTPUnauthorized(explanation=msg,
-+ request=req,
-+ content_type='text/plain')
- except ValueError as e:
- LOG.debug("Cannot save data for image %(id)s: %(e)s",
- {'id': image_id, 'e': utils.exception_to_str(e)})
-diff --git a/glance/tests/unit/v1/test_upload_utils.py b/glance/tests/unit/v1/test_upload_utils.py
-index 1afaf00..8d05515 100644
---- a/glance/tests/unit/v1/test_upload_utils.py
-+++ b/glance/tests/unit/v1/test_upload_utils.py
-@@ -323,3 +323,29 @@ class TestUploadUtils(base.StoreClearingUnitTest):
- 'metadata': {}}, image_meta['id'])
- mock_safe_kill.assert_called_once_with(
- req, image_meta['id'], 'saving')
-+
-+ @mock.patch.object(registry, 'update_image_metadata',
-+ side_effect=exception.NotAuthenticated)
-+ @mock.patch.object(upload_utils, 'initiate_deletion')
-+ def test_activate_image_with_expired_token(
-+ self, mocked_delete, mocked_update):
-+ """Test token expiration during image upload.
-+
-+ If users token expired before image was uploaded then if auth error
-+ was caught from registry during changing image status from 'saving'
-+ to 'active' then it's required to delete all image data.
-+ """
-+ context = mock.Mock()
-+ req = mock.Mock()
-+ req.context = context
-+ with self._get_store_and_notifier() as (location, checksum, image_meta,
-+ image_data, store, notifier,
-+ update_data):
-+ self.assertRaises(webob.exc.HTTPUnauthorized,
-+ upload_utils.upload_data_to_store,
-+ req, image_meta, image_data, store, notifier)
-+ self.assertEqual(2, mocked_update.call_count)
-+ mocked_delete.assert_called_once_with(
-+ req,
-+ {'url': 'file://foo/bar', 'status': 'active', 'metadata': {}},
-+ 'c80a1a6c-bd1f-41c5-90ee-81afedb1d58d')
-diff --git a/glance/tests/unit/v2/test_image_data_resource.py b/glance/tests/unit/v2/test_image_data_resource.py
-index bc8891e..7458eda 100644
---- a/glance/tests/unit/v2/test_image_data_resource.py
-+++ b/glance/tests/unit/v2/test_image_data_resource.py
-@@ -192,6 +192,23 @@ class TestImagesController(base.StoreClearingUnitTest):
- self.assertRaises(webob.exc.HTTPBadRequest, self.controller.upload,
- request, unit_test_utils.UUID1, 'YYYY', 4)
-
-+ def test_upload_with_expired_token(self):
-+ def side_effect(image, from_state=None):
-+ if from_state == 'saving':
-+ raise exception.NotAuthenticated()
-+
-+ mocked_save = mock.Mock(side_effect=side_effect)
-+ mocked_delete = mock.Mock()
-+ request = unit_test_utils.get_fake_request()
-+ image = FakeImage('abcd')
-+ image.delete = mocked_delete
-+ self.image_repo.result = image
-+ self.image_repo.save = mocked_save
-+ self.assertRaises(webob.exc.HTTPUnauthorized, self.controller.upload,
-+ request, unit_test_utils.UUID1, 'YYYY', 4)
-+ self.assertEqual(3, mocked_save.call_count)
-+ mocked_delete.assert_called_once_with()
-+
- def test_upload_non_existent_image_during_save_initiates_deletion(self):
- def fake_save_not_found(self):
- raise exception.NotFound()
---
-cgit v0.10.2
-
diff --git a/app-admin/glance/files/cve-2015-5163-stable-kilo.patch b/app-admin/glance/files/cve-2015-5163-stable-kilo.patch
deleted file mode 100644
index 91507c9..0000000
--- a/app-admin/glance/files/cve-2015-5163-stable-kilo.patch
+++ /dev/null
@@ -1,260 +0,0 @@
-From eb99e45829a1b4c93db5692bdbf636a86faa56c4 Mon Sep 17 00:00:00 2001
-From: Flavio Percoco <flaper87@gmail.com>
-Date: Thu, 9 Jul 2015 14:44:04 +0200
-Subject: Don't import files with backed files
-
-There's a security issue where it'd be possible to import images with
-backed files using the task engine and then use/convert those to access
-system files or any other file in the system. An example of an attack
-would be to import an image with a backing file pointing to
-`/etc/passwd`, then convert it to raw and download the generated image.
-
-This patch forbids importing files with baking files entirely. It does
-that in the `_ImportToFS` task, which is the one that imports the image
-locally to then execute other tasks on it. It's not necessary for the
-`_ImportToStore` task because other tasks won't be executed when the
-image is imported in the final store.
-
-Change-Id: I35f43c3b3f326942fb53b7dadb94700ac4513494
-Closes-bug: #1471912
-(cherry picked from commit d529863a1e8d2307526bdb395b4aebe97f81603d)
-
-diff --git a/glance/async/flows/base_import.py b/glance/async/flows/base_import.py
-index 7656bde..d216aa8 100644
---- a/glance/async/flows/base_import.py
-+++ b/glance/async/flows/base_import.py
-@@ -13,12 +13,15 @@
- # License for the specific language governing permissions and limitations
- # under the License.
-
-+import json
- import logging
- import os
-
- import glance_store as store_api
- from glance_store import backend
-+from oslo_concurrency import processutils as putils
- from oslo_config import cfg
-+from oslo_utils import excutils
- import six
- from stevedore import named
- from taskflow.patterns import linear_flow as lf
-@@ -146,6 +149,29 @@ class _ImportToFS(task.Task):
- data = script_utils.get_image_data_iter(self.uri)
-
- path = self.store.add(image_id, data, 0, context=None)[0]
-+
-+ try:
-+ # NOTE(flaper87): Consider moving this code to a common
-+ # place that other tasks can consume as well.
-+ stdout, stderr = putils.trycmd('qemu-img', 'info',
-+ '--output=json', path,
-+ log_errors=putils.LOG_ALL_ERRORS)
-+ except OSError as exc:
-+ with excutils.save_and_reraise_exception():
-+ msg = (_LE('Failed to execute security checks on the image '
-+ '%(task_id)s: %(exc)s') %
-+ {'task_id': self.task_id, 'exc': exc.message})
-+ LOG.error(msg)
-+
-+ metadata = json.loads(stdout)
-+
-+ backing_file = metadata.get('backing-filename')
-+ if backing_file is not None:
-+ msg = _("File %(path)s has invalid backing file "
-+ "%(bfile)s, aborting.") % {'path': path,
-+ 'bfile': backing_file}
-+ raise RuntimeError(msg)
-+
- return path
-
- def revert(self, image_id, result=None, **kwargs):
-diff --git a/glance/tests/unit/async/flows/test_import.py b/glance/tests/unit/async/flows/test_import.py
-index 70f790c..4cf3d13 100644
---- a/glance/tests/unit/async/flows/test_import.py
-+++ b/glance/tests/unit/async/flows/test_import.py
-@@ -13,14 +13,17 @@
- # License for the specific language governing permissions and limitations
- # under the License.
-
-+import json
- import mock
- import os
- import urllib2
-
- import glance_store
-+from oslo_concurrency import processutils as putils
- from oslo_config import cfg
- from six.moves import cStringIO
- from taskflow import task
-+from taskflow.types import failure
-
- import glance.async.flows.base_import as import_flow
- from glance.async import taskflow_executor
-@@ -106,16 +109,23 @@ class TestImportTask(test_utils.BaseTestCase):
-
- with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
- dmock.return_value = cStringIO("TEST_IMAGE")
-- executor.begin_processing(self.task.task_id)
-- image_path = os.path.join(self.test_dir, self.image.image_id)
-- tmp_image_path = os.path.join(self.work_dir,
-- "%s.tasks_import" % image_path)
-- self.assertFalse(os.path.exists(tmp_image_path))
-- self.assertTrue(os.path.exists(image_path))
-- self.assertEqual(1, len(list(self.image.locations)))
-- self.assertEqual("file://%s/%s" % (self.test_dir,
-- self.image.image_id),
-- self.image.locations[0]['url'])
-+
-+ with mock.patch.object(putils, 'trycmd') as tmock:
-+ tmock.return_value = (json.dumps({
-+ 'format': 'qcow2',
-+ }), None)
-+
-+ executor.begin_processing(self.task.task_id)
-+ image_path = os.path.join(self.test_dir, self.image.image_id)
-+ tmp_image_path = os.path.join(self.work_dir,
-+ "%s.tasks_import" % image_path)
-+
-+ self.assertFalse(os.path.exists(tmp_image_path))
-+ self.assertTrue(os.path.exists(image_path))
-+ self.assertEqual(1, len(list(self.image.locations)))
-+ self.assertEqual("file://%s/%s" % (self.test_dir,
-+ self.image.image_id),
-+ self.image.locations[0]['url'])
-
- def test_import_flow_missing_work_dir(self):
- self.config(engine_mode='serial', group='taskflow_executor')
-@@ -151,6 +161,54 @@ class TestImportTask(test_utils.BaseTestCase):
- self.assertFalse(os.path.exists(tmp_image_path))
- self.assertTrue(os.path.exists(image_path))
-
-+ def test_import_flow_backed_file_import_to_fs(self):
-+ self.config(engine_mode='serial', group='taskflow_executor')
-+
-+ img_factory = mock.MagicMock()
-+
-+ executor = taskflow_executor.TaskExecutor(
-+ self.context,
-+ self.task_repo,
-+ self.img_repo,
-+ img_factory)
-+
-+ self.task_repo.get.return_value = self.task
-+
-+ def create_image(*args, **kwargs):
-+ kwargs['image_id'] = UUID1
-+ return self.img_factory.new_image(*args, **kwargs)
-+
-+ self.img_repo.get.return_value = self.image
-+ img_factory.new_image.side_effect = create_image
-+
-+ with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
-+ dmock.return_value = cStringIO("TEST_IMAGE")
-+
-+ with mock.patch.object(putils, 'trycmd') as tmock:
-+ tmock.return_value = (json.dumps({
-+ 'backing-filename': '/etc/password'
-+ }), None)
-+
-+ with mock.patch.object(import_flow._ImportToFS,
-+ 'revert') as rmock:
-+ self.assertRaises(RuntimeError,
-+ executor.begin_processing,
-+ self.task.task_id)
-+ self.assertTrue(rmock.called)
-+ self.assertIsInstance(rmock.call_args[1]['result'],
-+ failure.Failure)
-+
-+ image_path = os.path.join(self.test_dir,
-+ self.image.image_id)
-+
-+ fname = "%s.tasks_import" % image_path
-+ tmp_image_path = os.path.join(self.work_dir, fname)
-+
-+ self.assertFalse(os.path.exists(tmp_image_path))
-+ # Note(sabari): The image should not have been uploaded to
-+ # the store as the flow failed before ImportToStore Task.
-+ self.assertFalse(os.path.exists(image_path))
-+
- def test_import_flow_revert(self):
- self.config(engine_mode='serial',
- group='taskflow_executor')
-@@ -175,20 +233,31 @@ class TestImportTask(test_utils.BaseTestCase):
- with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
- dmock.return_value = cStringIO("TEST_IMAGE")
-
-- with mock.patch.object(import_flow, "_get_import_flows") as imock:
-- imock.return_value = (x for x in [_ErrorTask()])
-- self.assertRaises(RuntimeError,
-- executor.begin_processing, self.task.task_id)
-- image_path = os.path.join(self.test_dir, self.image.image_id)
-- tmp_image_path = os.path.join(self.work_dir,
-- "%s.tasks_import" % image_path)
-- self.assertFalse(os.path.exists(tmp_image_path))
--
-- # NOTE(flaper87): Eventually, we want this to be assertTrue.
-- # The current issue is there's no way to tell taskflow to
-- # continue on failures. That is, revert the subflow but keep
-- # executing the parent flow. Under discussion/development.
-- self.assertFalse(os.path.exists(image_path))
-+ with mock.patch.object(putils, 'trycmd') as tmock:
-+ tmock.return_value = (json.dumps({
-+ 'format': 'qcow2',
-+ }), None)
-+
-+ with mock.patch.object(import_flow,
-+ "_get_import_flows") as imock:
-+ imock.return_value = (x for x in [_ErrorTask()])
-+ self.assertRaises(RuntimeError,
-+ executor.begin_processing,
-+ self.task.task_id)
-+
-+ image_path = os.path.join(self.test_dir,
-+ self.image.image_id)
-+ tmp_image_path = os.path.join(self.work_dir,
-+ ("%s.tasks_import" %
-+ image_path))
-+ self.assertFalse(os.path.exists(tmp_image_path))
-+
-+ # NOTE(flaper87): Eventually, we want this to be assertTrue
-+ # The current issue is there's no way to tell taskflow to
-+ # continue on failures. That is, revert the subflow but
-+ # keep executing the parent flow. Under
-+ # discussion/development.
-+ self.assertFalse(os.path.exists(image_path))
-
- def test_import_flow_no_import_flows(self):
- self.config(engine_mode='serial',
-@@ -271,15 +340,20 @@ class TestImportTask(test_utils.BaseTestCase):
- with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
- dmock.return_value = "test"
-
-- image_id = UUID1
-- path = import_fs.execute(image_id)
-- reader, size = glance_store.get_from_backend(path)
-- self.assertEqual(4, size)
-- self.assertEqual(dmock.return_value, "".join(reader))
-+ with mock.patch.object(putils, 'trycmd') as tmock:
-+ tmock.return_value = (json.dumps({
-+ 'format': 'qcow2',
-+ }), None)
-+
-+ image_id = UUID1
-+ path = import_fs.execute(image_id)
-+ reader, size = glance_store.get_from_backend(path)
-+ self.assertEqual(4, size)
-+ self.assertEqual(dmock.return_value, "".join(reader))
-
-- image_path = os.path.join(self.work_dir, image_id)
-- tmp_image_path = os.path.join(self.work_dir, image_path)
-- self.assertTrue(os.path.exists(tmp_image_path))
-+ image_path = os.path.join(self.work_dir, image_id)
-+ tmp_image_path = os.path.join(self.work_dir, image_path)
-+ self.assertTrue(os.path.exists(tmp_image_path))
-
- def test_delete_from_fs(self):
- delete_fs = import_flow._DeleteFromFS(self.task.task_id,
---
-cgit v0.10.2
-
diff --git a/app-admin/glance/files/cve-2015-5251-stable-kilo.patch b/app-admin/glance/files/cve-2015-5251-stable-kilo.patch
deleted file mode 100644
index f868645..0000000
--- a/app-admin/glance/files/cve-2015-5251-stable-kilo.patch
+++ /dev/null
@@ -1,192 +0,0 @@
-From 9beca533f42ae1fc87418de0c360e19bc59b24b5 Mon Sep 17 00:00:00 2001
-From: Stuart McLaren <stuart.mclaren@hp.com>
-Date: Tue, 11 Aug 2015 10:37:09 +0000
-Subject: [PATCH] Prevent image status being directly modified via v1
-
-Users shouldn't be able to change an image's status directly via the
-v1 API.
-
-Some existing consumers of Glance set the x-image-meta-status header in
-requests to the Glance API, eg:
-
-https://github.com/openstack/nova/blob/master/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance#L184
-
-We should try to prevent users setting 'status' via v1, but without breaking
-existing benign API calls such as these.
-
-I've adopted the following approach (which has some prior art in 'protected properties').
-
-If a PUT request is received which contains an x-image-meta-status header:
-
-* The user provided status is ignored if it matches the current image
- status (this prevents benign calls such as the nova one above from
- breaking). The usual code (eg 200) will be returned.
-
-* If the user provided status doesn't match the current image status (ie
- there is a real attempt to change the value) 403 will be returned. This
- will break any calls which currently intentionally change the status.
-
-APIImpact
-
-Closes-bug: 1482371
-
-Change-Id: I44fadf32abb57c962b67467091c3f51c1ccc25e6
-(cherry picked from commit 4d08db5b6d42323ac1958ef3b7417d875e7bea8c)
----
- glance/api/v1/__init__.py | 3 +
- glance/api/v1/images.py | 9 +++
- glance/tests/functional/v1/test_api.py | 89 ++++++++++++++++++++++
- .../integration/legacy_functional/test_v1_api.py | 2 +
- 4 files changed, 103 insertions(+)
-
-diff --git a/glance/api/v1/__init__.py b/glance/api/v1/__init__.py
-index 74de9aa1411d8e926770b67f7d851cf14e794414..9306bbb4fe78f77a26bb539c717fdfd2b38767c8 100644
---- a/glance/api/v1/__init__.py
-+++ b/glance/api/v1/__init__.py
-@@ -21,3 +21,6 @@ SUPPORTED_PARAMS = ('limit', 'marker', 'sort_key', 'sort_dir')
-
- # Metadata which only an admin can change once the image is active
- ACTIVE_IMMUTABLE = ('size', 'checksum')
-+
-+# Metadata which cannot be changed (irrespective of the current image state)
-+IMMUTABLE = ('status',)
-diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
-index e33b91fbca79377e78ccfd329fa542ad422f5ffc..95e32949d958d0f57a3b60c141b91784a5801f5a 100644
---- a/glance/api/v1/images.py
-+++ b/glance/api/v1/images.py
-@@ -57,6 +57,7 @@ _LW = i18n._LW
- SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
- SUPPORTED_FILTERS = glance.api.v1.SUPPORTED_FILTERS
- ACTIVE_IMMUTABLE = glance.api.v1.ACTIVE_IMMUTABLE
-+IMMUTABLE = glance.api.v1.IMMUTABLE
-
- CONF = cfg.CONF
- CONF.import_opt('disk_formats', 'glance.common.config', group='image_format')
-@@ -912,6 +913,14 @@ class Controller(controller.BaseController):
- request=req,
- content_type="text/plain")
-
-+ for key in IMMUTABLE:
-+ if (image_meta.get(key) is not None and
-+ image_meta.get(key) != orig_image_meta.get(key)):
-+ msg = _("Forbidden to modify '%s' of image.") % key
-+ raise HTTPForbidden(explanation=msg,
-+ request=req,
-+ content_type="text/plain")
-+
- # The default behaviour for a PUT /images/<IMAGE_ID> is to
- # override any properties that were previously set. This, however,
- # leads to a number of issues for the common use case where a caller
-diff --git a/glance/tests/functional/v1/test_api.py b/glance/tests/functional/v1/test_api.py
-index 9fba3bb5e40c8742530691228c7b436b385fc2ca..6b3bfbb4270f1eb0f50418504e65be30ea23d10b 100644
---- a/glance/tests/functional/v1/test_api.py
-+++ b/glance/tests/functional/v1/test_api.py
-@@ -715,3 +715,92 @@ class TestApi(functional.FunctionalTest):
- self.assertEqual(404, response.status)
-
- self.stop_servers()
-+
-+ def test_status_cannot_be_manipulated_directly(self):
-+ self.cleanup()
-+ self.start_servers(**self.__dict__.copy())
-+ headers = minimal_headers('Image1')
-+
-+ # Create a 'queued' image
-+ http = httplib2.Http()
-+ headers = {'Content-Type': 'application/octet-stream',
-+ 'X-Image-Meta-Disk-Format': 'raw',
-+ 'X-Image-Meta-Container-Format': 'bare'}
-+ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-+ response, content = http.request(path, 'POST', headers=headers,
-+ body=None)
-+ self.assertEqual(201, response.status)
-+ image = jsonutils.loads(content)['image']
-+ self.assertEqual('queued', image['status'])
-+
-+ # Ensure status of 'queued' image can't be changed
-+ path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
-+ image['id'])
-+ http = httplib2.Http()
-+ headers = {'X-Image-Meta-Status': 'active'}
-+ response, content = http.request(path, 'PUT', headers=headers)
-+ self.assertEqual(403, response.status)
-+ response, content = http.request(path, 'HEAD')
-+ self.assertEqual(200, response.status)
-+ self.assertEqual('queued', response['x-image-meta-status'])
-+
-+ # We allow 'setting' to the same status
-+ http = httplib2.Http()
-+ headers = {'X-Image-Meta-Status': 'queued'}
-+ response, content = http.request(path, 'PUT', headers=headers)
-+ self.assertEqual(200, response.status)
-+ response, content = http.request(path, 'HEAD')
-+ self.assertEqual(200, response.status)
-+ self.assertEqual('queued', response['x-image-meta-status'])
-+
-+ # Make image active
-+ http = httplib2.Http()
-+ headers = {'Content-Type': 'application/octet-stream'}
-+ response, content = http.request(path, 'PUT', headers=headers,
-+ body='data')
-+ self.assertEqual(200, response.status)
-+ image = jsonutils.loads(content)['image']
-+ self.assertEqual('active', image['status'])
-+
-+ # Ensure status of 'active' image can't be changed
-+ http = httplib2.Http()
-+ headers = {'X-Image-Meta-Status': 'queued'}
-+ response, content = http.request(path, 'PUT', headers=headers)
-+ self.assertEqual(403, response.status)
-+ response, content = http.request(path, 'HEAD')
-+ self.assertEqual(200, response.status)
-+ self.assertEqual('active', response['x-image-meta-status'])
-+
-+ # We allow 'setting' to the same status
-+ http = httplib2.Http()
-+ headers = {'X-Image-Meta-Status': 'active'}
-+ response, content = http.request(path, 'PUT', headers=headers)
-+ self.assertEqual(200, response.status)
-+ response, content = http.request(path, 'HEAD')
-+ self.assertEqual(200, response.status)
-+ self.assertEqual('active', response['x-image-meta-status'])
-+
-+ # Create a 'queued' image, ensure 'status' header is ignored
-+ http = httplib2.Http()
-+ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-+ headers = {'Content-Type': 'application/octet-stream',
-+ 'X-Image-Meta-Status': 'active'}
-+ response, content = http.request(path, 'POST', headers=headers,
-+ body=None)
-+ self.assertEqual(201, response.status)
-+ image = jsonutils.loads(content)['image']
-+ self.assertEqual('queued', image['status'])
-+
-+ # Create an 'active' image, ensure 'status' header is ignored
-+ http = httplib2.Http()
-+ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-+ headers = {'Content-Type': 'application/octet-stream',
-+ 'X-Image-Meta-Disk-Format': 'raw',
-+ 'X-Image-Meta-Status': 'queued',
-+ 'X-Image-Meta-Container-Format': 'bare'}
-+ response, content = http.request(path, 'POST', headers=headers,
-+ body='data')
-+ self.assertEqual(201, response.status)
-+ image = jsonutils.loads(content)['image']
-+ self.assertEqual('active', image['status'])
-+ self.stop_servers()
-diff --git a/glance/tests/integration/legacy_functional/test_v1_api.py b/glance/tests/integration/legacy_functional/test_v1_api.py
-index dff436465919569480bdbac537d20a6d61c98f46..511d46dfe18028bb430504784cc9d24c58736c3b 100644
---- a/glance/tests/integration/legacy_functional/test_v1_api.py
-+++ b/glance/tests/integration/legacy_functional/test_v1_api.py
-@@ -358,6 +358,8 @@ class TestApi(base.ApiTest):
- path = "/v1/images"
- response, content = self.http.request(path, 'POST', headers=headers)
- self.assertEqual(201, response.status)
-+ image = jsonutils.loads(content)['image']
-+ self.assertEqual('active', image['status'])
-
- # 2. HEAD image-location
- # Verify image size is zero and the status is active
---
-2.5.0
-
diff --git a/app-admin/glance/files/cve-2016-0757-stable-liberty.patch b/app-admin/glance/files/cve-2016-0757-stable-liberty.patch
new file mode 100644
index 0000000..19c8365
--- /dev/null
+++ b/app-admin/glance/files/cve-2016-0757-stable-liberty.patch
@@ -0,0 +1,332 @@
+From c6021e9b3642340036347026a3f251e066e53094 Mon Sep 17 00:00:00 2001
+From: Erno Kuvaja <jokke@usr.fi>
+Date: Tue, 19 Jan 2016 13:37:05 +0000
+Subject: [PATCH] Prevent user to remove last location of the image
+
+If the last location of the image is removed, image transitions back to queued.
+This allows user to upload new data into the existing image record. By
+preventing removal of the last location we prevent the image transition back to
+queued.
+
+This change also prevents doing the same operation via replacing the locations
+with empty list.
+
+SecurityImpact
+DocImpact
+APIImpact
+
+Conflicts:
+ glance/tests/unit/v2/test_images_resource.py
+
+Change-Id: Ieb03aaba887492819f9c58aa67f7acfcea81720e
+Closes-Bug: #1525915
+(cherry picked from commit 2f4504da2149697bcdb93ed855e15025d2a08f8c)
+---
+ glance/api/v2/images.py | 19 +++-
+ glance/tests/functional/v2/test_images.py | 14 ---
+ glance/tests/unit/v2/test_images_resource.py | 122 ++++-----------------
+ ...oving-last-image-location-d5ee3e00efe14f34.yaml | 10 ++
+ 4 files changed, 44 insertions(+), 121 deletions(-)
+ create mode 100644 releasenotes/notes/Prevent-removing-last-image-location-d5ee3e00efe14f34.yaml
+
+diff --git a/glance/api/v2/images.py b/glance/api/v2/images.py
+index 17678f2..cf667bf 100644
+--- a/glance/api/v2/images.py
++++ b/glance/api/v2/images.py
+@@ -181,7 +181,10 @@ class ImagesController(object):
+ path = change['path']
+ path_root = path[0]
+ value = change['value']
+- if path_root == 'locations':
++ if path_root == 'locations' and value == []:
++ msg = _("Cannot set locations to empty list.")
++ raise webob.exc.HTTPForbidden(message=msg)
++ elif path_root == 'locations' and value != []:
+ self._do_replace_locations(image, value)
+ elif path_root == 'owner' and req.context.is_admin == False:
+ msg = _("Owner can't be updated by non admin.")
+@@ -217,7 +220,10 @@ class ImagesController(object):
+ path = change['path']
+ path_root = path[0]
+ if path_root == 'locations':
+- self._do_remove_locations(image, path[1])
++ try:
++ self._do_remove_locations(image, path[1])
++ except exception.Forbidden as e:
++ raise webob.exc.HTTPForbidden(e.msg)
+ else:
+ if hasattr(image, path_root):
+ msg = _("Property %s may not be removed.")
+@@ -306,6 +312,11 @@ class ImagesController(object):
+ explanation=encodeutils.exception_to_unicode(ve))
+
+ def _do_remove_locations(self, image, path_pos):
++ if len(image.locations) == 1:
++ LOG.debug("User forbidden to remove last location of image %s",
++ image.image_id)
++ msg = _("Cannot remove last location in the image.")
++ raise exception.Forbidden(message=msg)
+ pos = self._get_locations_op_pos(path_pos,
+ len(image.locations), False)
+ if pos is None:
+@@ -315,11 +326,11 @@ class ImagesController(object):
+ # NOTE(zhiyan): this actually deletes the location
+ # from the backend store.
+ image.locations.pop(pos)
++ # TODO(jokke): Fix this, we should catch what store throws and
++ # provide definitely something else than IternalServerError to user.
+ except Exception as e:
+ raise webob.exc.HTTPInternalServerError(
+ explanation=encodeutils.exception_to_unicode(e))
+- if len(image.locations) == 0 and image.status == 'active':
+- image.status = 'queued'
+
+
+ class RequestDeserializer(wsgi.JSONRequestDeserializer):
+diff --git a/glance/tests/functional/v2/test_images.py b/glance/tests/functional/v2/test_images.py
+index aabc567..f199787 100644
+--- a/glance/tests/functional/v2/test_images.py
++++ b/glance/tests/functional/v2/test_images.py
+@@ -522,20 +522,6 @@ class TestImages(functional.FunctionalTest):
+ response = requests.patch(path, headers=headers, data=data)
+ self.assertEqual(200, response.status_code, response.text)
+
+- # Remove all locations of the image then the image size shouldn't be
+- # able to access
+- path = self._url('/v2/images/%s' % image2_id)
+- media_type = 'application/openstack-images-v2.1-json-patch'
+- headers = self._headers({'content-type': media_type})
+- doc = [{'op': 'replace', 'path': '/locations', 'value': []}]
+- data = jsonutils.dumps(doc)
+- response = requests.patch(path, headers=headers, data=data)
+- self.assertEqual(200, response.status_code, response.text)
+- image = jsonutils.loads(response.text)
+- self.assertIsNone(image['size'])
+- self.assertIsNone(image['virtual_size'])
+- self.assertEqual('queued', image['status'])
+-
+ # Deletion should work. Deleting image-1
+ path = self._url('/v2/images/%s' % image_id)
+ response = requests.delete(path, headers=self._headers())
+diff --git a/glance/tests/unit/v2/test_images_resource.py b/glance/tests/unit/v2/test_images_resource.py
+index 698c284..ee09ee7 100644
+--- a/glance/tests/unit/v2/test_images_resource.py
++++ b/glance/tests/unit/v2/test_images_resource.py
+@@ -1417,26 +1417,6 @@ class TestImagesController(base.IsolatedUnitTest):
+ self.assertRaises(webob.exc.HTTPConflict, self.controller.update,
+ another_request, created_image.image_id, changes)
+
+- def test_update_replace_locations(self):
+- self.stubs.Set(store, 'get_size_from_backend',
+- unit_test_utils.fake_get_size_from_backend)
+- request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- output = self.controller.update(request, UUID1, changes)
+- self.assertEqual(UUID1, output.image_id)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+- self.assertIsNone(output.size)
+-
+- new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+- changes = [{'op': 'replace', 'path': ['locations'],
+- 'value': [new_location]}]
+- output = self.controller.update(request, UUID1, changes)
+- self.assertEqual(UUID1, output.image_id)
+- self.assertEqual(1, len(output.locations))
+- self.assertEqual(new_location, output.locations[0])
+- self.assertEqual('active', output.status)
+-
+ def test_update_replace_locations_non_empty(self):
+ new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+ request = unit_test_utils.get_fake_request()
+@@ -1448,35 +1428,9 @@ class TestImagesController(base.IsolatedUnitTest):
+ def test_update_replace_locations_invalid(self):
+ request = unit_test_utils.get_fake_request()
+ changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- output = self.controller.update(request, UUID1, changes)
+- self.assertEqual(UUID1, output.image_id)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+-
+- request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'replace', 'path': ['locations'],
+- 'value': [{'url': 'unknow://foo', 'metadata': {}}]}]
+- self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
++ self.assertRaises(webob.exc.HTTPForbidden, self.controller.update,
+ request, UUID1, changes)
+
+- def test_update_replace_locations_status_exception(self):
+- self.stubs.Set(store, 'get_size_from_backend',
+- unit_test_utils.fake_get_size_from_backend)
+- request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- output = self.controller.update(request, UUID2, changes)
+- self.assertEqual(UUID2, output.image_id)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+-
+- self.db.image_update(None, UUID2, {'disk_format': None})
+-
+- new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+- changes = [{'op': 'replace', 'path': ['locations'],
+- 'value': [new_location]}]
+- self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+- request, UUID2, changes)
+-
+ def test_update_add_property(self):
+ request = unit_test_utils.get_fake_request()
+
+@@ -1600,24 +1554,6 @@ class TestImagesController(base.IsolatedUnitTest):
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+ request, UUID1, changes)
+
+- def test_update_add_locations_status_exception(self):
+- self.stubs.Set(store, 'get_size_from_backend',
+- unit_test_utils.fake_get_size_from_backend)
+- request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- output = self.controller.update(request, UUID2, changes)
+- self.assertEqual(UUID2, output.image_id)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+-
+- self.db.image_update(None, UUID2, {'disk_format': None})
+-
+- new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+- changes = [{'op': 'add', 'path': ['locations', '-'],
+- 'value': new_location}]
+- self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+- request, UUID2, changes)
+-
+ def test_update_add_duplicate_locations(self):
+ new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+ request = unit_test_utils.get_fake_request()
+@@ -1631,23 +1567,6 @@ class TestImagesController(base.IsolatedUnitTest):
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+ request, UUID1, changes)
+
+- def test_update_replace_duplicate_locations(self):
+- self.stubs.Set(store, 'get_size_from_backend',
+- unit_test_utils.fake_get_size_from_backend)
+- request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- output = self.controller.update(request, UUID1, changes)
+- self.assertEqual(UUID1, output.image_id)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+-
+- new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+- changes = [{'op': 'replace', 'path': ['locations'],
+- 'value': [new_location, new_location]}]
+-
+- self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+- request, UUID1, changes)
+-
+ def test_update_add_too_many_locations(self):
+ self.config(image_location_quota=1)
+ request = unit_test_utils.get_fake_request()
+@@ -1748,9 +1667,12 @@ class TestImagesController(base.IsolatedUnitTest):
+ {'op': 'add', 'path': ['locations', '-'],
+ 'value': {'url': '%s/fake_location_1' % BASE_URI,
+ 'metadata': {}}},
++ {'op': 'add', 'path': ['locations', '-'],
++ 'value': {'url': '%s/fake_location_2' % BASE_URI,
++ 'metadata': {}}},
+ ]
+ self.controller.update(request, UUID1, changes)
+- self.config(image_location_quota=1)
++ self.config(image_location_quota=2)
+
+ # We must remove two properties to avoid being
+ # over the limit of 1 property
+@@ -1763,8 +1685,8 @@ class TestImagesController(base.IsolatedUnitTest):
+ ]
+ output = self.controller.update(request, UUID1, changes)
+ self.assertEqual(UUID1, output.image_id)
+- self.assertEqual(1, len(output.locations))
+- self.assertIn('fake_location_3', output.locations[0]['url'])
++ self.assertEqual(2, len(output.locations))
++ self.assertIn('fake_location_3', output.locations[1]['url'])
+ self.assertNotEqual(output.created_at, output.updated_at)
+
+ def test_update_remove_base_property(self):
+@@ -1805,24 +1727,23 @@ class TestImagesController(base.IsolatedUnitTest):
+ unit_test_utils.fake_get_size_from_backend)
+
+ request = unit_test_utils.get_fake_request()
+- changes = [{'op': 'remove', 'path': ['locations', '0']}]
+- output = self.controller.update(request, UUID1, changes)
+- self.assertEqual(output.image_id, UUID1)
+- self.assertEqual(0, len(output.locations))
+- self.assertEqual('queued', output.status)
+- self.assertIsNone(output.size)
+-
+ new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
+ changes = [{'op': 'add', 'path': ['locations', '-'],
+ 'value': new_location}]
++ self.controller.update(request, UUID1, changes)
++ changes = [{'op': 'remove', 'path': ['locations', '0']}]
+ output = self.controller.update(request, UUID1, changes)
+ self.assertEqual(UUID1, output.image_id)
+ self.assertEqual(1, len(output.locations))
+- self.assertEqual(new_location, output.locations[0])
+ self.assertEqual('active', output.status)
+
+ def test_update_remove_location_invalid_pos(self):
+ request = unit_test_utils.get_fake_request()
++ changes = [
++ {'op': 'add', 'path': ['locations', '-'],
++ 'value': {'url': '%s/fake_location' % BASE_URI,
++ 'metadata': {}}}]
++ self.controller.update(request, UUID1, changes)
+ changes = [{'op': 'remove', 'path': ['locations', None]}]
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+ request, UUID1, changes)
+@@ -1844,6 +1765,11 @@ class TestImagesController(base.IsolatedUnitTest):
+ fake_delete_image_location_from_backend)
+
+ request = unit_test_utils.get_fake_request()
++ changes = [
++ {'op': 'add', 'path': ['locations', '-'],
++ 'value': {'url': '%s/fake_location' % BASE_URI,
++ 'metadata': {}}}]
++ self.controller.update(request, UUID1, changes)
+ changes = [{'op': 'remove', 'path': ['locations', '0']}]
+ self.assertRaises(webob.exc.HTTPInternalServerError,
+ self.controller.update, request, UUID1, changes)
+@@ -2137,16 +2063,6 @@ class TestImagesControllerPolicies(base.IsolatedUnitTest):
+ self.assertRaises(webob.exc.HTTPForbidden, self.controller.update,
+ request, UUID1, changes)
+
+- self.stubs.Set(self.store_utils, 'delete_image_location_from_backend',
+- fake_delete_image_location_from_backend)
+-
+- changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
+- self.controller.update(request, UUID1, changes)
+- changes = [{'op': 'replace', 'path': ['locations'],
+- 'value': [new_location]}]
+- self.assertRaises(webob.exc.HTTPForbidden, self.controller.update,
+- request, UUID1, changes)
+-
+ def test_update_delete_image_location_unauthorized(self):
+ rules = {"delete_image_location": False}
+ self.policy.set_rules(rules)
+diff --git a/releasenotes/notes/Prevent-removing-last-image-location-d5ee3e00efe14f34.yaml b/releasenotes/notes/Prevent-removing-last-image-location-d5ee3e00efe14f34.yaml
+new file mode 100644
+index 0000000..344e6e5
+--- /dev/null
++++ b/releasenotes/notes/Prevent-removing-last-image-location-d5ee3e00efe14f34.yaml
+@@ -0,0 +1,10 @@
++---
++security:
++ - Fixing bug 1525915; image might be transitioning
++ from active to queued by regular user by removing
++ last location of image (or replacing locations
++ with empty list). This allows user to re-upload
++ data to the image breaking Glance's promise of
++ image data immutability. From now on, last
++ location cannot be removed and locations cannot
++ be replaced with empty list.
+--
+1.9.1
+
diff --git a/app-admin/glance/files/glance-2013.2-sphinx_mapping.patch b/app-admin/glance/files/glance-2013.2-sphinx_mapping.patch
deleted file mode 100644
index 0a0f575..0000000
--- a/app-admin/glance/files/glance-2013.2-sphinx_mapping.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ur glance-2013.2.orig/doc/source/conf.py glance-2013.2/doc/source/conf.py
---- doc/source/conf.py 2013-10-17 21:39:46.000000000 +0800
-+++ doc/source/conf.py 2013-11-13 18:51:29.099839976 +0800
-@@ -250,8 +250,3 @@
-
- # If false, no module index is generated.
- #latex_use_modindex = True
--
--# Example configuration for intersphinx: refer to the Python standard library.
--intersphinx_mapping = {'python': ('http://docs.python.org/', None),
-- 'nova': ('http://nova.openstack.org', None),
-- 'swift': ('http://swift.openstack.org', None)}
diff --git a/app-admin/glance/glance-11.0.1-r1.ebuild b/app-admin/glance/glance-11.0.1-r1.ebuild
new file mode 100644
index 0000000..1126feb
--- /dev/null
+++ b/app-admin/glance/glance-11.0.1-r1.ebuild
@@ -0,0 +1,229 @@
+# Copyright 1999-2016 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=5
+PYTHON_COMPAT=( python2_7 )
+
+inherit distutils-r1 user
+
+DESCRIPTION="Services for discovering, registering, and retrieving VM images"
+HOMEPAGE="https://launchpad.net/glance"
+SRC_URI="https://tarballs.openstack.org/${PN}/${P}.tar.gz"
+
+LICENSE="Apache-2.0"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE="doc mysql postgres +sqlite +swift test"
+REQUIRED_USE="|| ( mysql postgres sqlite )"
+
+CDEPEND=">=dev-python/pbr-1.6.0[${PYTHON_USEDEP}]"
+DEPEND="
+ dev-python/setuptools[${PYTHON_USEDEP}]
+ ${CDEPEND}
+ test? (
+ ${RDEPEND}
+ >=dev-python/Babel-1.3[${PYTHON_USEDEP}]
+ <=dev-python/Babel-2.1.1[${PYTHON_USEDEP}]
+ >=dev-python/coverage-3.6[${PYTHON_USEDEP}]
+ <=dev-python/coverage-4.0.3[${PYTHON_USEDEP}]
+ >=dev-python/fixtures-1.3.1[${PYTHON_USEDEP}]
+ <=dev-python/fixtures-1.4.0-r9999[${PYTHON_USEDEP}]
+ >=dev-python/mox3-0.7.0[${PYTHON_USEDEP}]
+ <=dev-python/mox3-0.12.0[${PYTHON_USEDEP}]
+ >=dev-python/mock-1.2[${PYTHON_USEDEP}]
+ <=dev-python/mock-1.3.0[${PYTHON_USEDEP}]
+ >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}]
+ !~dev-python/sphinx-1.2.0[${PYTHON_USEDEP}]
+ <dev-python/sphinx-1.3[${PYTHON_USEDEP}]
+ >=dev-python/requests-2.5.2[${PYTHON_USEDEP}]
+ !~dev-python/requests-2.8.0[${PYTHON_USEDEP}]
+ <=dev-python/requests-2.8.1[${PYTHON_USEDEP}]
+ >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
+ <=dev-python/testrepository-0.0.20[${PYTHON_USEDEP}]
+ >=dev-python/testresources-0.2.4[${PYTHON_USEDEP}]
+ <=dev-python/testresources-1.0.0-r9999[${PYTHON_USEDEP}]
+ >=dev-python/testscenarios-0.4[${PYTHON_USEDEP}]
+ <=dev-python/testscenarios-0.5[${PYTHON_USEDEP}]
+ >=dev-python/testtools-1.4.0[${PYTHON_USEDEP}]
+ <=dev-python/testtools-1.8.1[${PYTHON_USEDEP}]
+ >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
+ <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
+ >=dev-python/oslotest-1.10.0[${PYTHON_USEDEP}]
+ <=dev-python/oslotest-2.0.0[${PYTHON_USEDEP}]
+ >=dev-python/pymysql-0.6.2[${PYTHON_USEDEP}]
+ <=dev-python/pymysql-0.6.7[${PYTHON_USEDEP}]
+ >=dev-python/psycopg-2.5[${PYTHON_USEDEP}]
+ <=dev-python/psycopg-2.6.1[${PYTHON_USEDEP}]
+ >=dev-python/pysendfile-2.0.0[${PYTHON_USEDEP}]
+ <=dev-python/pysendfile-2.0.1[${PYTHON_USEDEP}]
+ <=dev-python/qpid-python-0.32[$(python_gen_usedep 'python2_7')]
+ >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
+ >=dev-python/python-swiftclient-2.2.0[${PYTHON_USEDEP}]
+ <=dev-python/python-swiftclient-2.7.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-sphinx-2.5.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-sphinx-4.1.0[${PYTHON_USEDEP}]
+ >=dev-python/reno-0.1.1[${PYTHON_USEDEP}]
+ )"
+
+#note to self, wsgiref is a python builtin, no need to package it
+#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
+
+RDEPEND="
+ ${CDEPEND}
+ sqlite? (
+ >=dev-python/sqlalchemy-0.9.9[sqlite,${PYTHON_USEDEP}]
+ <dev-python/sqlalchemy-1.0.10[sqlite,${PYTHON_USEDEP}]
+ )
+ mysql? (
+ dev-python/mysql-python
+ >=dev-python/sqlalchemy-0.9.9[${PYTHON_USEDEP}]
+ <dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
+ )
+ postgres? (
+ dev-python/psycopg:2[${PYTHON_USEDEP}]
+ >=dev-python/sqlalchemy-0.9.9[${PYTHON_USEDEP}]
+ <dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
+ )
+ ~dev-python/anyjson-0.3.3[${PYTHON_USEDEP}]
+ ~dev-python/eventlet-0.17.4[${PYTHON_USEDEP}]
+ >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
+ <=dev-python/pastedeploy-1.5.2[${PYTHON_USEDEP}]
+ >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
+ !~dev-python/routes-2.0[${PYTHON_USEDEP}]
+ !~dev-python/routes-2.1[$(python_gen_usedep 'python2_7')]
+ <=dev-python/routes-2.2[${PYTHON_USEDEP}]
+ >=dev-python/webob-1.2.3[${PYTHON_USEDEP}]
+ <=dev-python/webob-1.5.1[${PYTHON_USEDEP}]
+ >=dev-python/sqlalchemy-migrate-0.9.6[${PYTHON_USEDEP}]
+ <=dev-python/sqlalchemy-migrate-0.10.0[${PYTHON_USEDEP}]
+ >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
+ <=dev-python/httplib2-0.9.2[${PYTHON_USEDEP}]
+ >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
+ <=dev-python/pycrypto-2.6.1[${PYTHON_USEDEP}]
+ >=dev-python/iso8601-0.1.9[${PYTHON_USEDEP}]
+ <=dev-python/iso8601-0.1.11[${PYTHON_USEDEP}]
+ >=dev-python/oslo-config-2.3.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-config-3.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-concurrency-2.3.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-concurrency-3.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-context-0.2.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-context-1.0.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-service-0.7.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-service-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-utils-2.0.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-utils-2.6.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-utils-3.2.0[${PYTHON_USEDEP}]
+ >=dev-python/stevedore-1.5.0[${PYTHON_USEDEP}]
+ <=dev-python/stevedore-1.10.0[${PYTHON_USEDEP}]
+ >=dev-python/futurist-0.1.2[${PYTHON_USEDEP}]
+ <=dev-python/futurist-0.8.0[${PYTHON_USEDEP}]
+ >=dev-python/taskflow-1.16.0[${PYTHON_USEDEP}]
+ <=dev-python/taskflow-1.25.0[${PYTHON_USEDEP}]
+ >=dev-python/keystonemiddleware-2.0.0[${PYTHON_USEDEP}]
+ !~dev-python/keystonemiddleware-2.4.0[${PYTHON_USEDEP}]
+ <=dev-python/keystonemiddleware-4.0.0[${PYTHON_USEDEP}]
+ >=dev-python/WSME-0.7[${PYTHON_USEDEP}]
+ <=dev-python/WSME-0.8.0[${PYTHON_USEDEP}]
+ <=dev-python/paste-2.0.2[${PYTHON_USEDEP}]
+ >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
+ !~dev-python/jsonschema-2.5.0[${PYTHON_USEDEP}]
+ <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
+ >=dev-python/python-keystoneclient-1.6.0[${PYTHON_USEDEP}]
+ !~dev-python/python-keystoneclient-1.8.0[${PYTHON_USEDEP}]
+ <=dev-python/python-keystoneclient-2.0.0-r9999[${PYTHON_USEDEP}]
+ >=dev-python/pyopenssl-0.14[${PYTHON_USEDEP}]
+ <=dev-python/pyopenssl-0.15.1-r9999[${PYTHON_USEDEP}]
+ >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
+ <=dev-python/six-1.10.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-db-2.4.1[${PYTHON_USEDEP}]
+ <=dev-python/oslo-db-4.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-i18n-1.5.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-i18n-3.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-log-1.8.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-log-2.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-messaging-1.16.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-1.17.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-1.17.1[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.6.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.6.1[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.7.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.8.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.8.1[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-2.9.0[${PYTHON_USEDEP}]
+ !~dev-python/oslo-messaging-3.1.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-messaging-3.0.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-middleware-2.8.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-middleware-3.3.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-policy-0.5.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-policy-1.1.0[${PYTHON_USEDEP}]
+ >=dev-python/oslo-serialization-1.4.0[${PYTHON_USEDEP}]
+ <=dev-python/oslo-serialization-2.1.0[${PYTHON_USEDEP}]
+ >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
+ !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
+ <=dev-python/retrying-1.3.3[${PYTHON_USEDEP}]
+ >=dev-python/osprofiler-0.3.0[${PYTHON_USEDEP}]
+ <=dev-python/osprofiler-0.3.1[${PYTHON_USEDEP}]
+ >=dev-python/glance_store-0.7.1[${PYTHON_USEDEP}]
+ !~dev-python/glance_store-0.9.0[${PYTHON_USEDEP}]
+ <=dev-python/glance_store-0.9.1[${PYTHON_USEDEP}]
+ >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
+ <=dev-python/semantic_version-2.4.2[${PYTHON_USEDEP}]
+ >=dev-python/castellan-0.2.0[${PYTHON_USEDEP}]
+ <=dev-python/castellan-0.3.1[${PYTHON_USEDEP}]
+ >=dev-python/cryptography-1.0[${PYTHON_USEDEP}]
+ <=dev-python/cryptography-1.1.2-r9999[${PYTHON_USEDEP}]
+"
+
+PATCHES=(
+ "${FILESDIR}/cve-2016-0757-stable-liberty.patch"
+)
+
+pkg_setup() {
+ enewgroup glance
+ enewuser glance -1 -1 /var/lib/glance glance
+}
+
+python_prepare_all() {
+ sed -i '/xattr/d' test-requirements.txt || die
+ sed -i '/pysendfile/d' test-requirements.txt || die
+ sed -i '/^hacking/d' test-requirements.txt || die
+ distutils-r1_python_prepare_all
+}
+
+python_compile_all() {
+ use doc && "${PYTHON}" setup.py build_sphinx
+}
+
+python_test() {
+ # https://bugs.launchpad.net/glance/+bug/1251105
+ # https://bugs.launchpad.net/glance/+bug/1242501
+ testr init
+ testr run --parallel || die "failed testsuite under python2.7"
+}
+
+python_install() {
+ distutils-r1_python_install
+
+ for svc in api registry scrubber; do
+ newinitd "${FILESDIR}/glance.initd" glance-${svc}
+ done
+
+ diropts -m 0750 -o glance -g glance
+ dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
+ keepdir /etc/glance
+ keepdir /var/log/glance
+ keepdir /var/lib/glance/images
+ keepdir /var/lib/glance/scrubber
+
+ insinto /etc/glance
+ insopts -m 0640 -o glance -g glance
+ doins etc/*.ini
+ doins etc/*.conf
+ doins etc/*.sample
+}
+
+python_install_all() {
+ use doc && local HTML_DOCS=( doc/build/html/. )
+ distutils-r1_python_install_all
+}
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/
@ 2018-01-28 4:13 Matt Thode
0 siblings, 0 replies; 5+ messages in thread
From: Matt Thode @ 2018-01-28 4:13 UTC (permalink / raw
To: gentoo-commits
commit: 99aaee53d4f3f580b511255ae8cd5181211be32d
Author: Matthew Thode <prometheanfire <AT> gentoo <DOT> org>
AuthorDate: Sun Jan 28 03:49:54 2018 +0000
Commit: Matt Thode <prometheanfire <AT> gentoo <DOT> org>
CommitDate: Sun Jan 28 04:13:05 2018 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=99aaee53
app-admin/glance: remove ocata
Package-Manager: Portage-2.3.19, Repoman-2.3.6
app-admin/glance/Manifest | 1 -
app-admin/glance/files/glance.initd | 16 ++--
app-admin/glance/files/glance.initd-2 | 15 ----
app-admin/glance/files/glance.initd-r2 | 17 ----
app-admin/glance/glance-14.0.0-r1.ebuild | 135 ----------------------------
app-admin/glance/glance-14.0.0.ebuild | 135 ----------------------------
app-admin/glance/glance-15.0.0.ebuild | 4 +-
app-admin/glance/glance-2017.1.9999.ebuild | 136 -----------------------------
app-admin/glance/glance-2017.2.9999.ebuild | 4 +-
9 files changed, 9 insertions(+), 454 deletions(-)
diff --git a/app-admin/glance/Manifest b/app-admin/glance/Manifest
index 4f6beea940c..0824f911194 100644
--- a/app-admin/glance/Manifest
+++ b/app-admin/glance/Manifest
@@ -1,2 +1 @@
-DIST glance-14.0.0.tar.gz 1788173 BLAKE2B 91834050aea925325a61f99c817e9d289270de30b88c53430b6b9c5845dbfc943678db734b9592657eb7ab8c49d5d6a7c110411c45c1fd82d8c829db67ef174b SHA512 4d0b6654dc6a9848e164422d138d4f6c1ec3711a7eb56a3c437202aa5c8cf86bf341201c9007b2f12173189f18beb73eadbaaade936ececf705a31e8b6eac155
DIST glance-15.0.0.tar.gz 1803491 BLAKE2B 70e0f1f7eab6aa0066d16e30e9325ac45d9c0eb9df875e3b26e90463e10299d6c7c272c0b070137f27332bdfcb33abeda68e3375e2562c83942ca72fcb24de38 SHA512 beb5744f9e8b296356cb731c79f1efd7b60408c1282e8a64ab7d414929c447c4f2ff0562a0d59c0a05f828d420ba190946866543a37dbd2df73ae322cbcabab5
diff --git a/app-admin/glance/files/glance.initd b/app-admin/glance/files/glance.initd
index 1ece1ad58f8..57274ac2dfe 100644
--- a/app-admin/glance/files/glance.initd
+++ b/app-admin/glance/files/glance.initd
@@ -1,21 +1,15 @@
#!/sbin/openrc-run
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
description="Starts ${SVCNAME} service for OpenStack"
-command=/usr/bin/${SVCNAME}
+command=/usr/bin/${RC_SVCNAME}
+command_user="${GLANCE_USER:-glance}"
command_background=yes
-pidfile=/var/run/glance/${SVCNAME}.pid
-required_files=/etc/glance/${SVCNAME}.conf
-
-start_stop_daemon_args="--quiet --user ${GLANCE_USER:-glance}"
+pidfile=/run/${RC_SVCNAME}.pid
+required_files=/etc/glance/${RC_SVCNAME}.conf
depend() {
need net
}
-
-start_pre() {
- checkpath --directory --owner ${GLANCE_USER:-glance}:${GLANCE_GROUP:-glance} --mode 0755 ${GLANCE_RUN:-/var/run/glance}
-}
-
diff --git a/app-admin/glance/files/glance.initd-2 b/app-admin/glance/files/glance.initd-2
deleted file mode 100644
index 4d4849f77e7..00000000000
--- a/app-admin/glance/files/glance.initd-2
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/sbin/openrc-run
-# Copyright 1999-2017 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-description="Starts ${SVCNAME} service for OpenStack"
-
-command=/usr/bin/${RC_SVCNAME}
-command_user="${GLANCE_USER:-glance}"
-command_background=yes
-pidfile=/run/${RC_SVCNAME}.pid
-required_files=/etc/glance/${RC_SVCNAME}.conf
-
-depend() {
- need net
-}
diff --git a/app-admin/glance/files/glance.initd-r2 b/app-admin/glance/files/glance.initd-r2
deleted file mode 100644
index 338de069750..00000000000
--- a/app-admin/glance/files/glance.initd-r2
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/sbin/openrc-run
-# Copyright 1999-2017 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-description="Starts ${RC_SVCNAME} service for OpenStack"
-
-command=/usr/bin/${RC_SVCNAME}
-command_user="${GLANCE_USER:-glance}"
-command_background=yes
-pidfile=/run/${RC_SVCNAME}.pid
-required_files=/etc/glance/${RC_SVCNAME}.conf
-
-start_stop_daemon_args="--quiet"
-
-depend() {
- need net
-}
diff --git a/app-admin/glance/glance-14.0.0-r1.ebuild b/app-admin/glance/glance-14.0.0-r1.ebuild
deleted file mode 100644
index 02f04305b64..00000000000
--- a/app-admin/glance/glance-14.0.0-r1.ebuild
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright 1999-2017 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=6
-PYTHON_COMPAT=( python2_7 python3_4 python3_5 )
-
-inherit distutils-r1 user
-
-DESCRIPTION="Services for discovering, registering, and retrieving VM images"
-HOMEPAGE="https://launchpad.net/glance"
-SRC_URI="https://tarballs.openstack.org/${PN}/${P}.tar.gz"
-
-LICENSE="Apache-2.0"
-SLOT="0"
-KEYWORDS="~amd64 ~arm64 ~x86"
-IUSE="doc mysql postgres +sqlite +swift"
-REQUIRED_USE="|| ( mysql postgres sqlite )"
-
-CDEPEND=">=dev-python/pbr-1.8.0[${PYTHON_USEDEP}]"
-DEPEND="
- dev-python/setuptools[${PYTHON_USEDEP}]
- ${CDEPEND}"
-
-#note to self, wsgiref is a python builtin, no need to package it
-#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
-
-RDEPEND="
- ${CDEPEND}
- sqlite? (
- >=dev-python/sqlalchemy-1.0.10[sqlite,${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[sqlite,${PYTHON_USEDEP}]
- )
- mysql? (
- >=dev-python/pymysql-0.7.6[${PYTHON_USEDEP}]
- !~dev-python/pymysql-0.7.7[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- postgres? (
- >=dev-python/psycopg-2.5.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- >=dev-python/eventlet-0.18.4[${PYTHON_USEDEP}]
- >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
- >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
- !~dev-python/routes-2.0[${PYTHON_USEDEP}]
- !~dev-python/routes-2.1[$(python_gen_usedep 'python2_7')]
- !~dev-python/routes-2.3[${PYTHON_USEDEP}]
- >=dev-python/webob-1.6.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-migrate-0.9.6[${PYTHON_USEDEP}]
- >=dev-python/python-sqlparse-0.2.2[${PYTHON_USEDEP}]
- >=dev-python/alembic-0.8.10[${PYTHON_USEDEP}]
- >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
- >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
- >=dev-python/oslo-config-3.14.0[${PYTHON_USEDEP}]
- !~dev-python/oslo-config-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-concurrency-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-context-2.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-utils-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/stevedore-1.17.1[${PYTHON_USEDEP}]
- >=dev-python/futurist-0.11.0[${PYTHON_USEDEP}]
- !~dev-python/futurist-0.15.0[${PYTHON_USEDEP}]
- >=dev-python/taskflow-2.7.0.0[${PYTHON_USEDEP}]
- >=dev-python/keystoneauth-2.18.0[${PYTHON_USEDEP}]
- >=dev-python/keystonemiddleware-4.12.0[${PYTHON_USEDEP}]
- >=dev-python/WSME-0.8.0[${PYTHON_USEDEP}]
- >=dev-python/prettytable-0.7.0[${PYTHON_USEDEP}]
- <dev-python/prettytable-0.8.0[${PYTHON_USEDEP}]
- dev-python/paste[${PYTHON_USEDEP}]
- >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
- !~dev-python/jsonschema-2.5.0[${PYTHON_USEDEP}]
- <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/python-keystoneclient-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/pyopenssl-0.14[${PYTHON_USEDEP}]
- >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-db-4.15.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-i18n-2.1.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-log-3.11.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-messaging-5.14.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-middleware-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-policy-1.17.0[${PYTHON_USEDEP}]
- >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
- !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/osprofiler-1.4.0[${PYTHON_USEDEP}]
- >=dev-python/glance_store-0.18.0[${PYTHON_USEDEP}]
- >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
- >=dev-python/debtcollector-1.2.0[${PYTHON_USEDEP}]
- >=dev-python/cryptography-1.0[${PYTHON_USEDEP}]
- !~dev-python/cryptography-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/cursive-0.1.1[${PYTHON_USEDEP}]
- >=dev-python/iso8601-0.1.11[${PYTHON_USEDEP}]
- >=dev-python/monotonic-0.6[${PYTHON_USEDEP}]
-"
-
-#PATCHES=(
-#)
-
-pkg_setup() {
- enewgroup glance
- enewuser glance -1 -1 /var/lib/glance glance
-}
-
-python_prepare_all() {
- sed -i '/xattr/d' test-requirements.txt || die
- sed -i '/pysendfile/d' test-requirements.txt || die
- sed -i '/^hacking/d' test-requirements.txt || die
- distutils-r1_python_prepare_all
-}
-
-python_compile_all() {
- use doc && "${PYTHON}" setup.py build_sphinx
-}
-
-python_install_all() {
- distutils-r1_python_install_all
-
- for svc in api glare registry scrubber; do
- newinitd "${FILESDIR}/glance.initd" glance-${svc}
- done
-
- diropts -m 0750 -o glance -g glance
- dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
- keepdir /etc/glance
- keepdir /var/log/glance
- keepdir /var/lib/glance/images
- keepdir /var/lib/glance/scrubber
-
- insinto /etc/glance
- insopts -m 0640 -o glance -g glance
- doins -r etc/*.ini etc/*.conf etc/*.sample etc/*.json etc/meta*
-
- use doc && local HTML_DOCS=( doc/build/html/. )
- distutils-r1_python_install_all
-}
diff --git a/app-admin/glance/glance-14.0.0.ebuild b/app-admin/glance/glance-14.0.0.ebuild
deleted file mode 100644
index d968f2a9e32..00000000000
--- a/app-admin/glance/glance-14.0.0.ebuild
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright 1999-2017 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=6
-PYTHON_COMPAT=( python2_7 python3_4 python3_5 )
-
-inherit distutils-r1 user
-
-DESCRIPTION="Services for discovering, registering, and retrieving VM images"
-HOMEPAGE="https://launchpad.net/glance"
-SRC_URI="https://tarballs.openstack.org/${PN}/${P}.tar.gz"
-
-LICENSE="Apache-2.0"
-SLOT="0"
-KEYWORDS="amd64 ~arm64 x86"
-IUSE="doc mysql postgres +sqlite +swift"
-REQUIRED_USE="|| ( mysql postgres sqlite )"
-
-CDEPEND=">=dev-python/pbr-1.8.0[${PYTHON_USEDEP}]"
-DEPEND="
- dev-python/setuptools[${PYTHON_USEDEP}]
- ${CDEPEND}"
-
-#note to self, wsgiref is a python builtin, no need to package it
-#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
-
-RDEPEND="
- ${CDEPEND}
- sqlite? (
- >=dev-python/sqlalchemy-1.0.10[sqlite,${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[sqlite,${PYTHON_USEDEP}]
- )
- mysql? (
- >=dev-python/pymysql-0.7.6[${PYTHON_USEDEP}]
- !~dev-python/pymysql-0.7.7[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- postgres? (
- >=dev-python/psycopg-2.5.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- >=dev-python/eventlet-0.18.4[${PYTHON_USEDEP}]
- >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
- >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
- !~dev-python/routes-2.0[${PYTHON_USEDEP}]
- !~dev-python/routes-2.1[$(python_gen_usedep 'python2_7')]
- !~dev-python/routes-2.3[${PYTHON_USEDEP}]
- >=dev-python/webob-1.6.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-migrate-0.9.6[${PYTHON_USEDEP}]
- >=dev-python/python-sqlparse-0.2.2[${PYTHON_USEDEP}]
- >=dev-python/alembic-0.8.10[${PYTHON_USEDEP}]
- >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
- >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
- >=dev-python/oslo-config-3.14.0[${PYTHON_USEDEP}]
- !~dev-python/oslo-config-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-concurrency-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-context-2.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-utils-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/stevedore-1.17.1[${PYTHON_USEDEP}]
- >=dev-python/futurist-0.11.0[${PYTHON_USEDEP}]
- !~dev-python/futurist-0.15.0[${PYTHON_USEDEP}]
- >=dev-python/taskflow-2.7.0.0[${PYTHON_USEDEP}]
- >=dev-python/keystoneauth-2.18.0[${PYTHON_USEDEP}]
- >=dev-python/keystonemiddleware-4.12.0[${PYTHON_USEDEP}]
- >=dev-python/WSME-0.8.0[${PYTHON_USEDEP}]
- >=dev-python/prettytable-0.7.0[${PYTHON_USEDEP}]
- <dev-python/prettytable-0.8.0[${PYTHON_USEDEP}]
- dev-python/paste[${PYTHON_USEDEP}]
- >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
- !~dev-python/jsonschema-2.5.0[${PYTHON_USEDEP}]
- <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/python-keystoneclient-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/pyopenssl-0.14[${PYTHON_USEDEP}]
- >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-db-4.15.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-i18n-2.1.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-log-3.11.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-messaging-5.14.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-middleware-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-policy-1.17.0[${PYTHON_USEDEP}]
- >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
- !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/osprofiler-1.4.0[${PYTHON_USEDEP}]
- >=dev-python/glance_store-0.18.0[${PYTHON_USEDEP}]
- >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
- >=dev-python/debtcollector-1.2.0[${PYTHON_USEDEP}]
- >=dev-python/cryptography-1.0[${PYTHON_USEDEP}]
- !~dev-python/cryptography-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/cursive-0.1.1[${PYTHON_USEDEP}]
- >=dev-python/iso8601-0.1.11[${PYTHON_USEDEP}]
- >=dev-python/monotonic-0.6[${PYTHON_USEDEP}]
-"
-
-#PATCHES=(
-#)
-
-pkg_setup() {
- enewgroup glance
- enewuser glance -1 -1 /var/lib/glance glance
-}
-
-python_prepare_all() {
- sed -i '/xattr/d' test-requirements.txt || die
- sed -i '/pysendfile/d' test-requirements.txt || die
- sed -i '/^hacking/d' test-requirements.txt || die
- distutils-r1_python_prepare_all
-}
-
-python_compile_all() {
- use doc && "${PYTHON}" setup.py build_sphinx
-}
-
-python_install_all() {
- distutils-r1_python_install_all
-
- for svc in api glare registry scrubber; do
- newinitd "${FILESDIR}/glance.initd" glance-${svc}
- done
-
- diropts -m 0750 -o glance -g glance
- dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
- keepdir /etc/glance
- keepdir /var/log/glance
- keepdir /var/lib/glance/images
- keepdir /var/lib/glance/scrubber
-
- insinto /etc/glance
- insopts -m 0640 -o glance -g glance
- doins -r etc/*.ini etc/*.conf etc/*.sample etc/*.json etc/meta*
-
- use doc && local HTML_DOCS=( doc/build/html/. )
- distutils-r1_python_install_all
-}
diff --git a/app-admin/glance/glance-15.0.0.ebuild b/app-admin/glance/glance-15.0.0.ebuild
index b32fcd4c7e8..56945afeb41 100644
--- a/app-admin/glance/glance-15.0.0.ebuild
+++ b/app-admin/glance/glance-15.0.0.ebuild
@@ -1,4 +1,4 @@
-# Copyright 1999-2017 Gentoo Foundation
+# Copyright 1999-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
EAPI=6
@@ -125,7 +125,7 @@ python_compile_all() {
python_install_all() {
distutils-r1_python_install_all
- newinitd "${FILESDIR}/glance.initd-2" glance-api
+ newinitd "${FILESDIR}/glance.initd" glance-api
diropts -m 0750 -o glance -g glance
dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
diff --git a/app-admin/glance/glance-2017.1.9999.ebuild b/app-admin/glance/glance-2017.1.9999.ebuild
deleted file mode 100644
index abe2dce6724..00000000000
--- a/app-admin/glance/glance-2017.1.9999.ebuild
+++ /dev/null
@@ -1,136 +0,0 @@
-# Copyright 1999-2017 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=6
-PYTHON_COMPAT=( python2_7 python3_4 python3_5 )
-
-inherit distutils-r1 git-r3 user
-
-DESCRIPTION="Services for discovering, registering, and retrieving VM images"
-HOMEPAGE="https://launchpad.net/glance"
-EGIT_REPO_URI="https://github.com/openstack/glance.git"
-EGIT_BRANCH="stable/ocata"
-
-LICENSE="Apache-2.0"
-SLOT="0"
-KEYWORDS=""
-IUSE="doc mysql postgres +sqlite +swift"
-REQUIRED_USE="|| ( mysql postgres sqlite )"
-
-CDEPEND=">=dev-python/pbr-1.8.0[${PYTHON_USEDEP}]"
-DEPEND="
- dev-python/setuptools[${PYTHON_USEDEP}]
- ${CDEPEND}"
-
-#note to self, wsgiref is a python builtin, no need to package it
-#>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
-
-RDEPEND="
- ${CDEPEND}
- sqlite? (
- >=dev-python/sqlalchemy-1.0.10[sqlite,${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[sqlite,${PYTHON_USEDEP}]
- )
- mysql? (
- >=dev-python/pymysql-0.7.6[${PYTHON_USEDEP}]
- !~dev-python/pymysql-0.7.7[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- postgres? (
- >=dev-python/psycopg-2.5.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-1.0.10[${PYTHON_USEDEP}]
- <dev-python/sqlalchemy-1.1.0[${PYTHON_USEDEP}]
- )
- >=dev-python/eventlet-0.18.4[${PYTHON_USEDEP}]
- >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
- >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
- !~dev-python/routes-2.0[${PYTHON_USEDEP}]
- !~dev-python/routes-2.1[$(python_gen_usedep 'python2_7')]
- !~dev-python/routes-2.3[${PYTHON_USEDEP}]
- >=dev-python/webob-1.6.0[${PYTHON_USEDEP}]
- >=dev-python/sqlalchemy-migrate-0.9.6[${PYTHON_USEDEP}]
- >=dev-python/python-sqlparse-0.2.2[${PYTHON_USEDEP}]
- >=dev-python/alembic-0.8.10[${PYTHON_USEDEP}]
- >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
- >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
- >=dev-python/oslo-config-3.14.0[${PYTHON_USEDEP}]
- !~dev-python/oslo-config-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-concurrency-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-context-2.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-utils-3.18.0[${PYTHON_USEDEP}]
- >=dev-python/stevedore-1.17.1[${PYTHON_USEDEP}]
- >=dev-python/futurist-0.11.0[${PYTHON_USEDEP}]
- !~dev-python/futurist-0.15.0[${PYTHON_USEDEP}]
- >=dev-python/taskflow-2.7.0.0[${PYTHON_USEDEP}]
- >=dev-python/keystoneauth-2.18.0[${PYTHON_USEDEP}]
- >=dev-python/keystonemiddleware-4.12.0[${PYTHON_USEDEP}]
- >=dev-python/WSME-0.8.0[${PYTHON_USEDEP}]
- >=dev-python/prettytable-0.7.0[${PYTHON_USEDEP}]
- <dev-python/prettytable-0.8.0[${PYTHON_USEDEP}]
- dev-python/paste[${PYTHON_USEDEP}]
- >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
- !~dev-python/jsonschema-2.5.0[${PYTHON_USEDEP}]
- <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/python-keystoneclient-3.8.0[${PYTHON_USEDEP}]
- >=dev-python/pyopenssl-0.14[${PYTHON_USEDEP}]
- >=dev-python/six-1.9.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-db-4.15.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-i18n-2.1.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-log-3.11.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-messaging-5.14.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-middleware-3.0.0[${PYTHON_USEDEP}]
- >=dev-python/oslo-policy-1.17.0[${PYTHON_USEDEP}]
- >=dev-python/retrying-1.2.3[${PYTHON_USEDEP}]
- !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/osprofiler-1.4.0[${PYTHON_USEDEP}]
- >=dev-python/glance_store-0.18.0[${PYTHON_USEDEP}]
- >=dev-python/semantic_version-2.3.1[${PYTHON_USEDEP}]
- >=dev-python/debtcollector-1.2.0[${PYTHON_USEDEP}]
- >=dev-python/cryptography-1.0[${PYTHON_USEDEP}]
- !~dev-python/cryptography-1.3.0[${PYTHON_USEDEP}]
- >=dev-python/cursive-0.1.1[${PYTHON_USEDEP}]
- >=dev-python/iso8601-0.1.11[${PYTHON_USEDEP}]
- >=dev-python/monotonic-0.6[${PYTHON_USEDEP}]
-"
-
-#PATCHES=(
-#)
-
-pkg_setup() {
- enewgroup glance
- enewuser glance -1 -1 /var/lib/glance glance
-}
-
-python_prepare_all() {
- sed -i '/xattr/d' test-requirements.txt || die
- sed -i '/pysendfile/d' test-requirements.txt || die
- sed -i '/^hacking/d' test-requirements.txt || die
- distutils-r1_python_prepare_all
-}
-
-python_compile_all() {
- use doc && "${PYTHON}" setup.py build_sphinx
-}
-
-python_install_all() {
- distutils-r1_python_install_all
-
- for svc in api glare registry scrubber; do
- newinitd "${FILESDIR}/glance.initd-r2" glance-${svc}
- done
-
- diropts -m 0750 -o glance -g glance
- dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
- keepdir /etc/glance
- keepdir /var/log/glance
- keepdir /var/lib/glance/images
- keepdir /var/lib/glance/scrubber
-
- insinto /etc/glance
- insopts -m 0640 -o glance -g glance
- doins -r etc/*.ini etc/*.conf etc/*.sample etc/*.json etc/meta*
-
- use doc && local HTML_DOCS=( doc/build/html/. )
- distutils-r1_python_install_all
-}
diff --git a/app-admin/glance/glance-2017.2.9999.ebuild b/app-admin/glance/glance-2017.2.9999.ebuild
index 71b923e6de6..34a29aa8cf5 100644
--- a/app-admin/glance/glance-2017.2.9999.ebuild
+++ b/app-admin/glance/glance-2017.2.9999.ebuild
@@ -1,4 +1,4 @@
-# Copyright 1999-2017 Gentoo Foundation
+# Copyright 1999-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
EAPI=6
@@ -126,7 +126,7 @@ python_compile_all() {
python_install_all() {
distutils-r1_python_install_all
- newinitd "${FILESDIR}/glance.initd-2" glance-api
+ newinitd "${FILESDIR}/glance.initd" glance-api
diropts -m 0750 -o glance -g glance
dodir /var/log/glance /var/lib/glance/images /var/lib/glance/scrubber
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-01-28 4:13 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-14 5:21 [gentoo-commits] repo/gentoo:master commit in: app-admin/glance/files/, app-admin/glance/ Matt Thode
-- strict thread matches above, loose matches on Subject: below --
2015-09-22 17:46 Matt Thode
2015-10-03 19:14 Matt Thode
2016-02-04 17:34 Matt Thode
2018-01-28 4:13 Matt Thode
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox