bumping :D
authorMatt Thode <prometheanfire@gentoo.org>
Sun, 8 Feb 2015 01:52:01 +0000 (01:52 +0000)
committerMatt Thode <prometheanfire@gentoo.org>
Sun, 8 Feb 2015 01:52:01 +0000 (01:52 +0000)
Package-Manager: portage-2.2.14/cvs/Linux x86_64
Manifest-Sign-Key: 0x33ED3FD25AFC78BA

app-admin/glance/ChangeLog
app-admin/glance/Manifest
app-admin/glance/files/0001-Prevent-file-swift-config-and-filesystem-schemes.patch [deleted file]
app-admin/glance/files/0001-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch [deleted file]
app-admin/glance/files/glance-CVE-2014-9623.patch [deleted file]
app-admin/glance/glance-2014.2.2.ebuild [new file with mode: 0644]
app-admin/glance/glance-2014.2.9999.ebuild
app-admin/glance/glance-9999.ebuild [deleted file]

index 053b821e95ab9fd9fbf2eda965d5ea71af97a6c2..a75e5352ed945773b5670a12b06dbbade46b0e1b 100644 (file)
@@ -1,6 +1,16 @@
 # ChangeLog for app-admin/glance
 # Copyright 1999-2015 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/ChangeLog,v 1.58 2015/01/29 05:39:38 prometheanfire Exp $
+# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/ChangeLog,v 1.59 2015/02/08 01:51:56 prometheanfire Exp $
+
+*glance-2014.2.2 (08 Feb 2015)
+
+  08 Feb 2015; Matthew Thode <prometheanfire@gentoo.org>
+  +glance-2014.2.2.ebuild,
+  -files/0001-Prevent-file-swift-config-and-filesystem-schemes.patch,
+  -files/0001-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch,
+  -files/glance-CVE-2014-9623.patch, -glance-9999.ebuild,
+  glance-2014.2.9999.ebuild:
+  bumping :D
 
 *glance-2014.2.1-r2 (29 Jan 2015)
 
index bdb548b2f2420ae638ef7c3eae737730ac27a759..593314bab24931791f8a1de998c7cd243c323355 100644 (file)
@@ -1,32 +1,30 @@
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA256
 
-AUX 0001-Prevent-file-swift-config-and-filesystem-schemes.patch 5240 SHA256 0347ad2f28e5705df46ed90d4521263a4678b65c33f17bde52b80107eb14302c SHA512 f43c51a72534d82468f4c9aec77743b77e421644e3ac9fd64bfa60e6e05984666a05c1297178bd7fdf669c5ff5aa894837813737c6e2465ef1102bf2feaefad2 WHIRLPOOL 8fa9f3c6a6e83188444beaa49f061700dda563acc0fc5cd58f1ffd7ca91c31b23f876f1b4a5e3f1c73c53ca32ca53dfbf99ee68b8afff7106f44b21e66fd455f
-AUX 0001-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch 30796 SHA256 84bf7263401f5cf0227abd83bc9d0ac9caf53163b381e20083791bd5db91dbf2 SHA512 e714a3bc586f6c968008f93e7c81a5a1a76fcde76ba842689c54f699df9bb5f71ee168f8ca5641c0a9ada14b5db0c4b9b4c124c0ee30210512de07555a131c9a WHIRLPOOL bf3ef17c2b3dc86a4c8c35908aa87e5d805fe7c94379231c3e2d573d278db379d9b2475a7675b4ad4236466d665e965ab56f4b046faf55f550fbd5bafd80e7f6
 AUX glance-2013.2-sphinx_mapping.patch 582 SHA256 043c3f7ef413cf3675920880af57943b909ec9f3376f6e86a1ae1d5948d9ad98 SHA512 d012ce5eaed00c3ba7b6219813cee503f68cdb14b8e50eedc731afc63767e1867749d6e4824611e0d024b2fdebfe5a2b3ad53b0ad7b18a39defcc17094da4a0f WHIRLPOOL 659bf94e7740be3ea0d2f130b332e694ebdcca8b90acfb479b8502eec4b867eda999ec2c6cdecc1f3dcbe3e3ddf72798c76bdf16ab4ab561ce61975a451c4585
-AUX glance-CVE-2014-9623.patch 24751 SHA256 e37eb73d863952a056493ca9439cb7a601feaf9bd60fa327578e9ae0b703e8ca SHA512 08ffa4777abe8efeb5b8e0d74a08e3f2bd10fdfd2d81bc0edcc911fdade79ae16b275b18bbab15ee44e64c0406acadf453448f66eb63f349aee5e7ac1704d392 WHIRLPOOL b76fc794a7388c27c84436ec39608c178c6abc67ffea9fc00fa161f9bcf6bb184d4c2a47dc1120c30d4216cc88f87745b5d307b2e5e50c2a967a8cee8fd6bbd8
 AUX glance.confd 25 SHA256 5a53dcf1eece81a06a2dd0856b15f8abe20eb1072361b110f752e396e86a7843 SHA512 13e671d4544e58d7397c1a87eb1048ed4bb9561587fcd63783e377b2d25e810222ca3944e0c8cf13c524e64f94c435b456a0d6f7cacfb148e275377699a11ca9 WHIRLPOOL 862a310fbdd7b68f132c45797210011b607d9b5c8937d60c9f5933a4d625bc985ad0277fea26804681b7e0a674dc9da15fbef40502c4052d6742ef0a94e88f3d
 AUX glance.initd 651 SHA256 1b2fc0e11d572bfcc121cb995ea7b3cce63ee705a05d2fb34a9f99d655546553 SHA512 c0ed1cac2038dda8882d5ce013b948debf1e5e411a062d8c9cbfdb1e1683c94bfd78a3f3468de63e0cc28930c59c0ff323a3116ce6a74ccf5d8ad1d547805bad WHIRLPOOL b0b25f4e983bf9f46cb9dd5872d14b24dc90e3c383dc458c79d065e0855bbf838afc4a13f0c92db640cd64311e22985d0b92e1ca4d428ce8b1f08ff23b89cecf
 DIST glance-2014.2.1.tar.gz 780312 SHA256 8059435c485be487d7b1e73da2f758e9871abf74cddde9b592939f05eb77cb45 SHA512 53797d09672188092d667efed6a914d9ec5a2c014687c2ec61473ec27fb9426391213622e0166c37a969128290c4cb039f07398d5f9906504794f984cc94cf91 WHIRLPOOL 41d05b55d2ac2c9310f0d3583e782c40c5dfecd256bb51219947016f3e71874eb2321c98c3a1fe2fd807b0f312aca0dbaeff8196df4e7ad20ddde662b41be5c9
+DIST glance-2014.2.2.tar.gz 782152 SHA256 bf7273ff9e89e9a7edda76e7a2235989a25109fb728edc4afa956e74ef54a08c SHA512 c8ea798e8e265679c714a252337461414cfc11cafeaecfd8afb3e8483d1396a7b161ab05bd46959a6e831fa57f184dabad9af4140c91854151ffeba99c8d4225 WHIRLPOOL 3761db8233d487f9ca461b50f94438ea00a2c33540a2d26323f57280dcbf0fbb6187153ea0d14c604c1ea50f1252a4e715b8ee3e8cd0d7be7a8d40e9184ee3b9
 EBUILD glance-2014.2.1-r2.ebuild 6089 SHA256 2502dc282246dffa2cabe34ce1e8c6e3f3d45104e1af7308468129ea4a47834b SHA512 1a478828631099dc446dc1c53ec166ee317f9323f37e9caf20163fbfebf155a0cbc54ef22d52aae139ed656e48c44393e8243bf5189a44cbb40402f0d48d48b2 WHIRLPOOL 8c48eb81b8d8903b02d2d79bef9fc377cf1cf608a06174c4f34bf02f06666e21cd5e14a28029e8335e931a3c94a349978d0759b91d946c04725e22f1c3a7aabb
-EBUILD glance-2014.2.9999.ebuild 5899 SHA256 ad477d40b1be82df8abe638c68292a4ea17c7fdcef28fea6a6f78ecd603e174a SHA512 a5f14e2869eafc48a471d6404a81e57994b016b08e1de9e5eb3a5717cbdcd61da0ddd18b9a6d2c9d2847bbbffa2e73ef242a9420f0b2a1589d6ad480ab7fb5d8 WHIRLPOOL 5f2d86bb43054374959bc7a905e9489295e26d7476f574cbd3544b759cc493d78d606d19ff21be6a2462adee4877268af95fa8bb3ccecc81471b1ae6fa18c5da
-EBUILD glance-9999.ebuild 4843 SHA256 cb262eac190bee1adb59ccc125809a3633adbd3448f5a15ee567b3c9a9e0b829 SHA512 e4aa1b6862ded7694eda77bf440ad71e6e6d413a7a7786f1dcd90f0084b8fdcf200486fe50cb49cb78936f0e2242e52b8122c84daa82c142836858e52d8137e7 WHIRLPOOL be80f071732df48b517f40015296c6a921afa665fece31c1efb3a12bb7bf89df20b9d113c10fa470c5ddf25da09d2e97377042ff295cdd7db2bb05e5fc04691f
-MISC ChangeLog 11725 SHA256 54dbc32d5fdac1ed219ce566508758be93e24a54f0f6b43787e8535983f9d25a SHA512 bc0f774665e71ca0ced1aa455076d614a0a550b487e589909a18701c03632de38affc5f7f620111d2dd999f11f6dbbd83b600573c2a70b7113578498f86d48e1 WHIRLPOOL bc2cd572a6105f9839ec6ab6b959d8b03266cf7303df86ca98f10f71a534338cec18cf70486d9ae10d164fc1e057552aeced75632cd075d513f7b7eb7953ef7d
+EBUILD glance-2014.2.2.ebuild 5633 SHA256 411e80c1263829f7e5ab0ea08e3bcfc9e68b51b4b4555c366ffa410783795477 SHA512 013fb4e46c7d02d51f7f4b4b829f4c741c9419bf8c680558c9669e1a95e0fbcafc348beab02400e5042596951359d1cb57fbb20f43263ec77061f84f89badf7c WHIRLPOOL d9b089a2b1f4067152f7c36e1bbe781be15c0877d20e7a044193e7611c43d458c844a24cad606402ef550b4ecdc68881231ab8e122b92c3efd11290a8e001c6c
+EBUILD glance-2014.2.9999.ebuild 5643 SHA256 660c69ecf6aa38c5b73f96514bc65813ac6280bbed852c544cc630fd0d5b742a SHA512 0e7fa36b215579b17ec543c72da1c494526d4235cfbfae178e7d0995fcc2b28524016b72ab9080dd2f2da50813b40a886d6ef159c0f8457776f1a0ccb93c59d8 WHIRLPOOL 992e9a693e7b8b33460dc609232f674f8a7fd18d3da2fcfe1da2cc9484a3e855e2efe472295084c24572201e46e2cda2a7f594b6544abd9d4889ec8ab69737ad
+MISC ChangeLog 12086 SHA256 3877cebf88f33f84e8c2c35c66cba4e36ca7baf3e6164077701c7cc7ef987a54 SHA512 37227d5bdd25e0ceba1fca1c155d2a883609fb79284c55c2a634fee13dd67f8b7ccc1e255a0358cf4fa03f30f6aaee00d4fa2ac86dbb0fd6b428b22d35a578fd WHIRLPOOL e7f12b7f19f4590ed9980c56bbdb8463057c3b981859d262f3b94b0c24292f84c269ed836f6e145520ea464cb684208656dcc80b3b6bcf7968b4ea3ad605ccf3
 MISC metadata.xml 607 SHA256 b74d960c096528dbb7c9be6b0da777e10abe32928459f045e7c58b0156e22d95 SHA512 e38e4dd740fe55d73d6d97fd9ffa3aec5466fbb5f8e6484b125560313245ae697a0dcf612fb065125c6737a8254b6218c0703f7de79437bb2799c6c67f386e45 WHIRLPOOL 445bf712fd733fa90c395cc24fd02155bed15b092713d502b54331da9237f397877c2328adbf4049ee64ae163713ce031ebe5048c8826ed1a011d4ebcdbb681d
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
-iQIcBAEBCAAGBQJUyceuAAoJEGSje+quGaToiB4P/izHWx4ZwXuF4SUwT6xNnExv
-iB9E70ArbBX3T6vcarZw7+059k4Xynz9uf+9WTo9zydFafYBaBShUD9lbLqvezFp
-wwnr2efvsBPQkgXqjFx8c0Lbx8rYbVrn3FdUdDSM2fol9hrb3NbewJe2gZxFi2AZ
-NxFgBucZfQ36xe8XwoSHkuM25/2PccOuJe9nkUAK/8oNOyFMn6izPK4xH3082kUb
-9YmWZow2A2qNsxMqkTlWj6546ZzH/DiDdr9qvuQRPLnIKqK80uaR/Y5XCGF3gF5J
-GP3H7OBcbsBkpgcN8wzFUeDxeYdw13rA/G7jgBvAcH3tMPlhbJaXTqM9IIpbpzHh
-eMUkmBqa8mO2VS5AVTzQHaLHF9QZZ9ek0pN+7wGHjLeepEKgyKFWgFEIh8ioTBG6
-DxvZAPqVb0Cu8YsDDCJPNglYKjLiGBWouSPa40flUBtIJrOxBl3ispjnEhOQ1dbK
-bXvOOAoMbxHLGy7HS7GHQ6tH2jtTJ4//Cy27ttHjbD0VLD8a1TzCrnfQe277T/fe
-jTtxjfInakuRGbm6Gw2NGQr0ddfNnIT4m7AHmr0pICONopFmQXXcMQXI9EK5g4pF
-+3c0FRO+XptRgt/MlLbieeHbsoYwBZSof6VZwkVGoCYPTMGxQ/Qi3nxN3EHXPEg7
-6J7f6wNQsd+l+hAXfmwe
-=RIqF
+iQIcBAEBCAAGBQJU1sFYAAoJEGSje+quGaToJZsQANOj7yryANQIkRFSF9KMB4PW
+N7qlxyjae0la3pPnNQifuKOsRXodg40nWnjlqQEd8KEMESGJjz9q+GZL52LscldZ
+eiNx6Fn3fmOcrz5FguhsMmqaLQzn7pCcoqVdGnID4e5XnV+i1G1janNefUARR8gA
+rsAELjOBQX+1EZnUrte0tBt9pScg9iHwMJ6cNhVAVqMJQoPVczXqvO6yZBkgg2pZ
+TX6yeFl7JHsZnWW2x7IrDWh2HQKe+89xYPff+9O3Lnh7zXYVOlytkEBOMb4yfq9W
+vvjw7n5AYr4cMwc2vTGjba5fgY7X08DNoiIYkfQ/86wsvv1SQfDnrgL48v5ltM9/
+98LRvE/3BXsOIxITKSTqV3Q2uG7IzQHBo5kSbCTbsDe/dTNhNseSw8PFtZLE5SGE
+O2/Ix1a4t6Xdzv6Z1vJdwegY9nHK/hCO4g6Vz6aoFpsR1BFBIYOlJ5llOKv912c4
+51bWEAioV9HfGY+Y/IjXlirKKFiOGJ47hIQIraqIw9gC3DK8b7rIsAvxq7wHjt/m
+X/zdg9Af//rY+ycCaI7rizOgxjrQT5356ZYXWaHVOet+gNS1C59JoARj4LVYdHn9
+bUYiPkqSpj58ZrYGjCdUc9xUX61D19Yzsn8NJd0YWEoU6nrGEQ48e8MGOvePHg+B
+Q4YNmWcdrnOP//E8PKdi
+=MM1Q
 -----END PGP SIGNATURE-----
diff --git a/app-admin/glance/files/0001-Prevent-file-swift-config-and-filesystem-schemes.patch b/app-admin/glance/files/0001-Prevent-file-swift-config-and-filesystem-schemes.patch
deleted file mode 100644 (file)
index 4cb999b..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-From 5191ed1879c5fd5b2694f922bcedec232f461088 Mon Sep 17 00:00:00 2001
-From: Grant Murphy <grant.murphy@hp.com>
-Date: Wed, 7 Jan 2015 16:09:38 -0800
-Subject: [PATCH] Prevent file, swift+config and filesystem schemes
-
-This change ensures that 'file', 'filesystem', and 'swift+config' URI
-schemes are not allowed when setting the location field. A previous
-fix to CVE-2014-9493 attempted to address this issue but did not
-include 'filesystem', a URI scheme allowed by the glance_store.
-
-Without this fix in place it is possible for a client to access any file
-the glance-api server has read permissions for.
-
-Change-Id: I02cd099a8634b9c7e3cf8f172bcbd33f8edcbc83
-Closes-Bug: #1408663
-(cherry picked from commit a2d986b976e9325a272e2d422465165315d19fe6)
----
- glance/common/store_utils.py             | 11 ++++++-----
- glance/tests/unit/test_store_location.py |  3 +++
- glance/tests/unit/v1/test_api.py         | 32 ++++++++++++--------------------
- 3 files changed, 21 insertions(+), 25 deletions(-)
-
-diff --git a/glance/common/store_utils.py b/glance/common/store_utils.py
-index b7537ce..64cfa87 100644
---- a/glance/common/store_utils.py
-+++ b/glance/common/store_utils.py
-@@ -38,6 +38,8 @@ store_utils_opts = [
- CONF = cfg.CONF
- CONF.register_opts(store_utils_opts)
- 
-+RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
-+
- 
- def safe_delete_from_backend(context, image_id, location):
-     """
-@@ -136,8 +138,7 @@ def validate_external_location(uri):
-     """
- 
-     # TODO(zhiyan): This function could be moved to glance_store.
--
--    pieces = urlparse.urlparse(uri)
--    valid_schemes = [scheme for scheme in store_api.get_known_schemes()
--                     if scheme != 'file' and scheme != 'swift+config']
--    return pieces.scheme in valid_schemes
-+    # TODO(gm): Use a whitelist of allowed schemes
-+    scheme = urlparse.urlparse(uri).scheme
-+    return (scheme in store_api.get_known_schemes() and
-+            scheme not in RESTRICTED_URI_SCHEMAS)
-diff --git a/glance/tests/unit/test_store_location.py b/glance/tests/unit/test_store_location.py
-index c9ee44c..efaecd8 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -69,12 +69,15 @@ class TestStoreLocation(base.StoreClearingUnitTest):
- 
-         loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}}
-         loc2 = {'url': 'swift+config:///xxx', 'metadata': {}}
-+        loc3 = {'url': 'filesystem:///foo.img.tar.gz', 'metadata': {}}
- 
-         # Test for insert location
-         image1 = TestStoreLocation.FakeImageProxy()
-         locations = glance.location.StoreLocations(image1, [])
-         self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1)
-+        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc3)
-         self.assertNotIn(loc1, locations)
-+        self.assertNotIn(loc3, locations)
- 
-         # Test for set_attr of _locations_proxy
-         image2 = TestStoreLocation.FakeImageProxy()
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index 4ec136d..39e9a44 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -1071,31 +1071,23 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-     def test_add_copy_from_with_restricted_sources(self):
-         """Tests creates an image from copy-from with restricted sources"""
--        fixture_headers = {'x-image-meta-store': 'file',
-+        header_template = {'x-image-meta-store': 'file',
-                            'x-image-meta-disk-format': 'vhd',
--                           'x-glance-api-copy-from': 'file:///etc/passwd',
-                            'x-image-meta-container-format': 'ovf',
-                            'x-image-meta-name': 'fake image #F'}
- 
--        req = webob.Request.blank("/images")
--        req.method = 'POST'
--        for k, v in six.iteritems(fixture_headers):
--            req.headers[k] = v
--        res = req.get_response(self.api)
--        self.assertEqual(400, res.status_int)
-+        schemas = ["file:///etc/passwd",
-+                   "swift+config:///xxx",
-+                   "filesystem:///etc/passwd"]
- 
--        fixture_headers = {'x-image-meta-store': 'file',
--                           'x-image-meta-disk-format': 'vhd',
--                           'x-glance-api-copy-from': 'swift+config://xxx',
--                           'x-image-meta-container-format': 'ovf',
--                           'x-image-meta-name': 'fake image #F'}
--
--        req = webob.Request.blank("/images")
--        req.method = 'POST'
--        for k, v in six.iteritems(fixture_headers):
--            req.headers[k] = v
--        res = req.get_response(self.api)
--        self.assertEqual(400, res.status_int)
-+        for schema in schemas:
-+            req = webob.Request.blank("/images")
-+            req.method = 'POST'
-+            for k, v in six.iteritems(header_template):
-+                req.headers[k] = v
-+            req.headers['x-glance-api-copy-from'] = schema
-+            res = req.get_response(self.api)
-+            self.assertEqual(400, res.status_int)
- 
-     def test_add_copy_from_upload_image_unauthorized_with_body(self):
-         rules = {"upload_image": '!', "modify_image": '@',
--- 
-2.0.5
-
diff --git a/app-admin/glance/files/0001-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch b/app-admin/glance/files/0001-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
deleted file mode 100644 (file)
index 15b3d9a..0000000
+++ /dev/null
@@ -1,702 +0,0 @@
-From d9a928eac360add67477e29f516af868adfe0d5e Mon Sep 17 00:00:00 2001
-From: Zhi Yan Liu <zhiyanl@cn.ibm.com>
-Date: Mon, 15 Dec 2014 12:29:55 +0800
-Subject: [PATCH] To prevent client use v2 patch api to handle file and swift
- location
-
-The change will be used to restrict client to download and delete any
-file in glance-api server. The same resone and logic as what we did in
-v1:
-https://github.com/openstack/glance/blob/master/glance/api/v1/images.py#L429
-
-Closes-Bug: bug/1400966
-DocImpact
-
-Note: Even this change could fully resolve the problem for Glance, but
-we still need to fix this issue from glance_store perspective
-separatelly due to other projects can use the lib directly.
-
-Conflicts:
-       glance/api/v1/images.py
-       glance/location.py
-       glance/tests/functional/v2/test_images.py
-       glance/tests/unit/test_store_location.py
-       glance/tests/unit/v1/test_api.py
-
-(cherry-picked from 4afdb017aa1ccef01482f117cb8d0736a6da38ed)
-Signed-off-by: Zhi Yan Liu <zhiyanl@cn.ibm.com>
-Change-Id: I72dbead3cb2dcb87f52658ddb880e26880cc229b
----
- glance/api/v1/images.py                         |  31 ++---
- glance/common/store_utils.py                    |  22 ++++
- glance/location.py                              |  30 +++--
- glance/tests/functional/v1/test_copy_to_file.py |   4 +-
- glance/tests/functional/v2/test_images.py       | 158 ++++++++++--------------
- glance/tests/unit/test_store_image.py           |   3 +-
- glance/tests/unit/test_store_location.py        |  33 ++++-
- glance/tests/unit/utils.py                      |   9 +-
- glance/tests/unit/v1/test_api.py                |  62 +++++++++-
- 9 files changed, 221 insertions(+), 131 deletions(-)
-
-diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
-index c85b301..746f8cd 100644
---- a/glance/api/v1/images.py
-+++ b/glance/api/v1/images.py
-@@ -23,7 +23,6 @@ import eventlet
- import glance_store as store
- import glance_store.location
- from oslo.config import cfg
--import six.moves.urllib.parse as urlparse
- from webob.exc import HTTPBadRequest
- from webob.exc import HTTPConflict
- from webob.exc import HTTPForbidden
-@@ -40,6 +39,7 @@ from glance.api.v1 import filters
- from glance.api.v1 import upload_utils
- from glance.common import exception
- from glance.common import property_utils
-+from glance.common import store_utils
- from glance.common import utils
- from glance.common import wsgi
- from glance.i18n import _LE
-@@ -415,26 +415,19 @@ class Controller(controller.BaseController):
-     @staticmethod
-     def _validate_source(source, req):
-         """
--        External sources (as specified via the location or copy-from headers)
--        are supported only over non-local store types, i.e. S3, Swift, HTTP.
--        Note the absence of 'file://' for security reasons, see LP bug #942118.
--        'swift+config://' is also absent for security reasons, see LP bug
--        #1334196.
--        If the above constraint is violated, we reject with 400 "Bad Request".
-+        To validate if external sources (as specified via the location
-+        or copy-from headers) are supported. Otherwise we reject
-+        with 400 "Bad Request".
-         """
-         if source:
--            pieces = urlparse.urlparse(source)
--            schemes = [scheme for scheme in store.get_known_schemes()
--                       if scheme != 'file' and scheme != 'swift+config']
--            for scheme in schemes:
--                if pieces.scheme == scheme:
--                    return source
--            msg = ("External sourcing not supported for "
--                   "store '%s'" % pieces.scheme)
--            LOG.debug(msg)
--            raise HTTPBadRequest(explanation=msg,
--                                 request=req,
--                                 content_type="text/plain")
-+            if store_utils.validate_external_location(source):
-+                return source
-+            else:
-+                msg = _("External source are not supported: '%s'") % source
-+                LOG.debug(msg)
-+                raise HTTPBadRequest(explanation=msg,
-+                                     request=req,
-+                                     content_type="text/plain")
- 
-     @staticmethod
-     def _copy_from(req):
-diff --git a/glance/common/store_utils.py b/glance/common/store_utils.py
-index 8f04d39..b7537ce 100644
---- a/glance/common/store_utils.py
-+++ b/glance/common/store_utils.py
-@@ -16,6 +16,7 @@ import sys
- 
- import glance_store as store_api
- from oslo.config import cfg
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import utils
- import glance.db as db_api
-@@ -119,3 +120,24 @@ def delete_image_location_from_backend(context, image_id, location):
-         # such as uploading process failure then we can't use
-         # location status mechanism to support image pending delete.
-         safe_delete_from_backend(context, image_id, location)
-+
-+
-+def validate_external_location(uri):
-+    """
-+    Validate if URI of external location are supported.
-+
-+    Only over non-local store types are OK, i.e. S3, Swift,
-+    HTTP. Note the absence of 'file://' for security reasons,
-+    see LP bug #942118, 1400966, 'swift+config://' is also
-+    absent for security reasons, see LP bug #1334196.
-+
-+    :param uri: The URI of external image location.
-+    :return: Whether given URI of external image location are OK.
-+    """
-+
-+    # TODO(zhiyan): This function could be moved to glance_store.
-+
-+    pieces = urlparse.urlparse(uri)
-+    valid_schemes = [scheme for scheme in store_api.get_known_schemes()
-+                     if scheme != 'file' and scheme != 'swift+config']
-+    return pieces.scheme in valid_schemes
-diff --git a/glance/location.py b/glance/location.py
-index fcdba0a..f83fa7a 100644
---- a/glance/location.py
-+++ b/glance/location.py
-@@ -66,18 +66,20 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-         return result
- 
- 
--def _check_location_uri(context, store_api, uri):
-+def _check_location_uri(context, store_api, store_utils, uri):
-     """Check if an image location is valid.
- 
-     :param context: Glance request context
-     :param store_api: store API module
-+    :param store_utils: store utils module
-     :param uri: location's uri string
-     """
-+
-     is_ok = True
-     try:
--        size = store_api.get_size_from_backend(uri, context=context)
-         # NOTE(zhiyan): Some stores return zero when it catch exception
--        is_ok = size > 0
-+        is_ok = (store_utils.validate_external_location(uri) and
-+                 store_api.get_size_from_backend(uri, context=context) > 0)
-     except (store.UnknownScheme, store.NotFound):
-         is_ok = False
-     if not is_ok:
-@@ -85,8 +87,8 @@ def _check_location_uri(context, store_api, uri):
-         raise exception.BadStoreUri(message=reason)
- 
- 
--def _check_image_location(context, store_api, location):
--    _check_location_uri(context, store_api, location['url'])
-+def _check_image_location(context, store_api, store_utils, location):
-+    _check_location_uri(context, store_api, store_utils, location['url'])
-     store_api.check_location_metadata(location['metadata'])
- 
- 
-@@ -122,6 +124,7 @@ class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
-     def __init__(self, factory, context, store_api, store_utils):
-         self.context = context
-         self.store_api = store_api
-+        self.store_utils = store_utils
-         proxy_kwargs = {'context': context, 'store_api': store_api,
-                         'store_utils': store_utils}
-         super(ImageFactoryProxy, self).__init__(factory,
-@@ -131,7 +134,10 @@ class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
-     def new_image(self, **kwargs):
-         locations = kwargs.get('locations', [])
-         for loc in locations:
--            _check_image_location(self.context, self.store_api, loc)
-+            _check_image_location(self.context,
-+                                  self.store_api,
-+                                  self.store_utils,
-+                                  loc)
-             loc['status'] = 'active'
-             if _count_duplicated_locations(locations, loc) > 1:
-                 raise exception.DuplicateLocation(location=loc['url'])
-@@ -169,7 +175,9 @@ class StoreLocations(collections.MutableSequence):
- 
-     def insert(self, i, location):
-         _check_image_location(self.image_proxy.context,
--                              self.image_proxy.store_api, location)
-+                              self.image_proxy.store_api,
-+                              self.image_proxy.store_utils,
-+                              location)
-         location['status'] = 'active'
-         if _count_duplicated_locations(self.value, location) > 0:
-             raise exception.DuplicateLocation(location=location['url'])
-@@ -214,7 +222,9 @@ class StoreLocations(collections.MutableSequence):
- 
-     def __setitem__(self, i, location):
-         _check_image_location(self.image_proxy.context,
--                              self.image_proxy.store_api, location)
-+                              self.image_proxy.store_api,
-+                              self.image_proxy.store_utils,
-+                              location)
-         location['status'] = 'active'
-         self.value.__setitem__(i, location)
-         _set_image_size(self.image_proxy.context,
-@@ -303,7 +313,9 @@ def _locations_proxy(target, attr):
-                                           '%s') % ori_value)
-             # NOTE(zhiyan): Check locations are all valid.
-             for location in value:
--                _check_image_location(self.context, self.store_api,
-+                _check_image_location(self.context,
-+                                      self.store_api,
-+                                      self.store_utils,
-                                       location)
-                 location['status'] = 'active'
-                 if _count_duplicated_locations(value, location) > 1:
-diff --git a/glance/tests/functional/v1/test_copy_to_file.py b/glance/tests/functional/v1/test_copy_to_file.py
-index 15bb708..b64eac6 100644
---- a/glance/tests/functional/v1/test_copy_to_file.py
-+++ b/glance/tests/functional/v1/test_copy_to_file.py
-@@ -250,7 +250,7 @@ class TestCopyToFile(functional.FunctionalTest):
-         response, content = http.request(path, 'POST', headers=headers)
-         self.assertEqual(response.status, 400, content)
- 
--        expected = 'External sourcing not supported for store \'file\''
-+        expected = 'External source are not supported: \'%s\'' % copy_from
-         msg = 'expected "%s" in "%s"' % (expected, content)
-         self.assertTrue(expected in content, msg)
- 
-@@ -276,7 +276,7 @@ class TestCopyToFile(functional.FunctionalTest):
-         response, content = http.request(path, 'POST', headers=headers)
-         self.assertEqual(response.status, 400, content)
- 
--        expected = 'External sourcing not supported for store \'swift+config\''
-+        expected = 'External source are not supported: \'swift+config://xxx\''
-         msg = 'expected "%s" in "%s"' % (expected, content)
-         self.assertTrue(expected in content, msg)
- 
-diff --git a/glance/tests/functional/v2/test_images.py b/glance/tests/functional/v2/test_images.py
-index 14fe3c7..4c32375 100644
---- a/glance/tests/functional/v2/test_images.py
-+++ b/glance/tests/functional/v2/test_images.py
-@@ -16,7 +16,6 @@
- import BaseHTTPServer
- import os
- import signal
--import tempfile
- import uuid
- 
- import requests
-@@ -47,7 +46,7 @@ def get_handler_class(fixture):
-             self.end_headers()
-             return
- 
--        def log_message(*args, **kwargs):
-+        def log_message(self, *args, **kwargs):
-             # Override this method to prevent debug output from going
-             # to stderr during testing
-             return
-@@ -75,6 +74,18 @@ class TestImages(functional.FunctionalTest):
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
-         self.api_server.data_api = 'glance.db.sqlalchemy.api'
-+        for i in range(3):
-+            ret = http_server("foo_image_id%d" % i, "foo_image%d" % i)
-+            setattr(self, 'http_server%d_pid' % i, ret[0])
-+            setattr(self, 'http_port%d' % i, ret[1])
-+
-+    def tearDown(self):
-+        for i in range(3):
-+            pid = getattr(self, 'http_server%d_pid' % i, None)
-+            if pid:
-+                os.kill(pid, signal.SIGKILL)
-+
-+        super(TestImages, self).tearDown()
- 
-     def _url(self, path):
-         return 'http://127.0.0.1:%d%s' % (self.api_port, path)
-@@ -329,21 +340,15 @@ class TestImages(functional.FunctionalTest):
-         self.assertEqual(413, response.status_code, response.text)
- 
-         # Adding 3 image locations should fail since configured limit is 2
--        for i in range(3):
--            file_path = os.path.join(self.test_dir, 'fake_image_%i' % i)
--            with open(file_path, 'w') as fap:
--                fap.write('glance')
--
-         path = self._url('/v2/images/%s' % image_id)
-         media_type = 'application/openstack-images-v2.1-json-patch'
-         headers = self._headers({'content-type': media_type})
-         changes = []
-         for i in range(3):
-+            url = ('http://127.0.0.1:%s/foo_image' %
-+                   getattr(self, 'http_port%d' % i))
-             changes.append({'op': 'add', 'path': '/locations/-',
--                            'value': {'url': 'file://{0}'.format(
--                                os.path.join(self.test_dir,
--                                             'fake_image_%i' % i)),
--                                      'metadata': {}},
-+                            'value': {'url': url, 'metadata': {}},
-                             })
- 
-         data = jsonutils.dumps(changes)
-@@ -2176,17 +2181,14 @@ class TestImages(functional.FunctionalTest):
-         self.assertNotIn('size', image)
-         self.assertNotIn('virtual_size', image)
- 
--        file_path = os.path.join(self.test_dir, 'fake_image')
--        with open(file_path, 'w') as fap:
--            fap.write('glance')
--
-         # Update locations for the queued image
-         path = self._url('/v2/images/%s' % image_id)
-         media_type = 'application/openstack-images-v2.1-json-patch'
-         headers = self._headers({'content-type': media_type})
-+        url = 'http://127.0.0.1:%s/foo_image' % self.http_port0
-         data = jsonutils.dumps([{'op': 'replace', 'path': '/locations',
--                                 'value': [{'url': 'file://' + file_path,
--                                            'metadata': {}}]}])
-+                                 'value': [{'url': url, 'metadata': {}}]
-+                                 }])
-         response = requests.patch(path, headers=headers, data=data)
-         self.assertEqual(200, response.status_code, response.text)
- 
-@@ -2195,7 +2197,42 @@ class TestImages(functional.FunctionalTest):
-         response = requests.get(path, headers=headers)
-         self.assertEqual(200, response.status_code)
-         image = jsonutils.loads(response.text)
--        self.assertEqual(image['size'], 6)
-+        self.assertEqual(image['size'], 10)
-+
-+    def test_update_locations_with_restricted_sources(self):
-+        self.start_servers(**self.__dict__.copy())
-+        # Create an image
-+        path = self._url('/v2/images')
-+        headers = self._headers({'content-type': 'application/json'})
-+        data = jsonutils.dumps({'name': 'image-1', 'disk_format': 'aki',
-+                                'container_format': 'aki'})
-+        response = requests.post(path, headers=headers, data=data)
-+        self.assertEqual(201, response.status_code)
-+
-+        # Returned image entity should have a generated id and status
-+        image = jsonutils.loads(response.text)
-+        image_id = image['id']
-+        self.assertEqual('queued', image['status'])
-+        self.assertNotIn('size', image)
-+        self.assertNotIn('virtual_size', image)
-+
-+        # Update locations for the queued image
-+        path = self._url('/v2/images/%s' % image_id)
-+        media_type = 'application/openstack-images-v2.1-json-patch'
-+        headers = self._headers({'content-type': media_type})
-+        data = jsonutils.dumps([{'op': 'replace', 'path': '/locations',
-+                                 'value': [{'url': 'file:///foo_image',
-+                                            'metadata': {}}]
-+                                 }])
-+        response = requests.patch(path, headers=headers, data=data)
-+        self.assertEqual(400, response.status_code, response.text)
-+
-+        data = jsonutils.dumps([{'op': 'replace', 'path': '/locations',
-+                                 'value': [{'url': 'swift+config:///foo_image',
-+                                            'metadata': {}}]
-+                                 }])
-+        response = requests.patch(path, headers=headers, data=data)
-+        self.assertEqual(400, response.status_code, response.text)
- 
- 
- class TestImagesWithRegistry(TestImages):
-@@ -2421,16 +2458,16 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         super(TestImageLocationSelectionStrategy, self).setUp()
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
--        self.foo_image_file = tempfile.NamedTemporaryFile()
--        self.foo_image_file.write("foo image file")
--        self.foo_image_file.flush()
--        self.addCleanup(self.foo_image_file.close)
--        ret = http_server("foo_image_id", "foo_image")
--        self.http_server_pid, self.http_port = ret
-+        for i in range(3):
-+            ret = http_server("foo_image_id%d" % i, "foo_image%d" % i)
-+            setattr(self, 'http_server%d_pid' % i, ret[0])
-+            setattr(self, 'http_port%d' % i, ret[1])
- 
-     def tearDown(self):
--        if self.http_server_pid is not None:
--            os.kill(self.http_server_pid, signal.SIGKILL)
-+        for i in range(3):
-+            pid = getattr(self, 'http_server%d_pid' % i, None)
-+            if pid:
-+                os.kill(pid, signal.SIGKILL)
- 
-         super(TestImageLocationSelectionStrategy, self).tearDown()
- 
-@@ -2483,69 +2520,10 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         path = self._url('/v2/images/%s' % image_id)
-         media_type = 'application/openstack-images-v2.1-json-patch'
-         headers = self._headers({'content-type': media_type})
--        values = [{'url': 'file://%s' % self.foo_image_file.name,
--                   'metadata': {'idx': '1'}},
--                  {'url': 'http://127.0.0.1:%s/foo_image' % self.http_port,
--                   'metadata': {'idx': '0'}}]
--        doc = [{'op': 'replace',
--                'path': '/locations',
--                'value': values}]
--        data = jsonutils.dumps(doc)
--        response = requests.patch(path, headers=headers, data=data)
--        self.assertEqual(200, response.status_code)
--
--        # Image locations should be visible
--        path = self._url('/v2/images/%s' % image_id)
--        headers = self._headers({'Content-Type': 'application/json'})
--        response = requests.get(path, headers=headers)
--        self.assertEqual(200, response.status_code)
--        image = jsonutils.loads(response.text)
--        self.assertTrue('locations' in image)
--        self.assertEqual(image['locations'], values)
--        self.assertTrue('direct_url' in image)
--        self.assertEqual(image['direct_url'], values[0]['url'])
--
--        self.stop_servers()
--
--    def test_image_locatons_with_store_type_strategy(self):
--        self.api_server.show_image_direct_url = True
--        self.api_server.show_multiple_locations = True
--        self.image_location_quota = 10
--        self.api_server.location_strategy = 'store_type'
--        preference = "http, swift, filesystem"
--        self.api_server.store_type_location_strategy_preference = preference
--        self.start_servers(**self.__dict__.copy())
--
--        # Create an image
--        path = self._url('/v2/images')
--        headers = self._headers({'content-type': 'application/json'})
--        data = jsonutils.dumps({'name': 'image-1', 'type': 'kernel',
--                                'foo': 'bar', 'disk_format': 'aki',
--                                'container_format': 'aki'})
--        response = requests.post(path, headers=headers, data=data)
--        self.assertEqual(201, response.status_code)
--
--        # Get the image id
--        image = jsonutils.loads(response.text)
--        image_id = image['id']
--
--        # Image locations should not be visible before location is set
--        path = self._url('/v2/images/%s' % image_id)
--        headers = self._headers({'Content-Type': 'application/json'})
--        response = requests.get(path, headers=headers)
--        self.assertEqual(200, response.status_code)
--        image = jsonutils.loads(response.text)
--        self.assertTrue('locations' in image)
--        self.assertTrue(image["locations"] == [])
--
--        # Update image locations via PATCH
--        path = self._url('/v2/images/%s' % image_id)
--        media_type = 'application/openstack-images-v2.1-json-patch'
--        headers = self._headers({'content-type': media_type})
--        values = [{'url': 'file://%s' % self.foo_image_file.name,
--                   'metadata': {'idx': '1'}},
--                  {'url': 'http://127.0.0.1:%s/foo_image' % self.http_port,
--                   'metadata': {'idx': '0'}}]
-+        values = [{'url': 'http://127.0.0.1:%s/foo_image' % self.http_port0,
-+                   'metadata': {}},
-+                  {'url': 'http://127.0.0.1:%s/foo_image' % self.http_port1,
-+                   'metadata': {}}]
-         doc = [{'op': 'replace',
-                 'path': '/locations',
-                 'value': values}]
-@@ -2553,8 +2531,6 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         response = requests.patch(path, headers=headers, data=data)
-         self.assertEqual(200, response.status_code)
- 
--        values.sort(key=lambda loc: int(loc['metadata']['idx']))
--
-         # Image locations should be visible
-         path = self._url('/v2/images/%s' % image_id)
-         headers = self._headers({'Content-Type': 'application/json'})
-diff --git a/glance/tests/unit/test_store_image.py b/glance/tests/unit/test_store_image.py
-index 665f126..8b334ab 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -18,6 +18,7 @@ import glance_store
- 
- from glance.common import exception
- import glance.location
-+from glance.tests.unit import base as unit_test_base
- from glance.tests.unit import utils as unit_test_utils
- from glance.tests import utils
- 
-@@ -759,7 +760,7 @@ class TestStoreImageRepo(utils.BaseTestCase):
-         self.assertEqual(acls['read'], [TENANT2])
- 
- 
--class TestImageFactory(utils.BaseTestCase):
-+class TestImageFactory(unit_test_base.StoreClearingUnitTest):
- 
-     def setUp(self):
-         super(TestImageFactory, self).setUp()
-diff --git a/glance/tests/unit/test_store_location.py b/glance/tests/unit/test_store_location.py
-index 884221b..c9ee44c 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -17,6 +17,8 @@ import mock
- 
- import glance_store
- 
-+from glance.common import exception
-+from glance.common import store_utils
- import glance.location
- from glance.tests.unit import base
- 
-@@ -32,11 +34,13 @@ CONF = {'default_store': 'file',
- 
- class TestStoreLocation(base.StoreClearingUnitTest):
- 
-+    class FakeImageProxy():
-+        size = None
-+        context = None
-+        store_api = mock.Mock()
-+        store_utils = store_utils
-+
-     def test_add_location_for_image_without_size(self):
--        class FakeImageProxy():
--            size = None
--            context = None
--            store_api = mock.Mock()
- 
-         def fake_get_size_from_backend(uri, context=None):
-             return 1
-@@ -49,14 +53,31 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-             loc2 = {'url': 'file:///fake2.img.tar.gz', 'metadata': {}}
- 
-             # Test for insert location
--            image1 = FakeImageProxy()
-+            image1 = TestStoreLocation.FakeImageProxy()
-             locations = glance.location.StoreLocations(image1, [])
-             locations.insert(0, loc2)
-             self.assertEqual(image1.size, 1)
- 
-             # Test for set_attr of _locations_proxy
--            image2 = FakeImageProxy()
-+            image2 = TestStoreLocation.FakeImageProxy()
-             locations = glance.location.StoreLocations(image2, [loc1])
-             locations[0] = loc2
-             self.assertIn(loc2, locations)
-             self.assertEqual(image2.size, 1)
-+
-+    def test_add_location_with_restricted_sources(self):
-+
-+        loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}}
-+        loc2 = {'url': 'swift+config:///xxx', 'metadata': {}}
-+
-+        # Test for insert location
-+        image1 = TestStoreLocation.FakeImageProxy()
-+        locations = glance.location.StoreLocations(image1, [])
-+        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1)
-+        self.assertNotIn(loc1, locations)
-+
-+        # Test for set_attr of _locations_proxy
-+        image2 = TestStoreLocation.FakeImageProxy()
-+        locations = glance.location.StoreLocations(image2, [loc1])
-+        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc2)
-+        self.assertNotIn(loc2, locations)
-diff --git a/glance/tests/unit/utils.py b/glance/tests/unit/utils.py
-index df59160..f7c8d56 100644
---- a/glance/tests/unit/utils.py
-+++ b/glance/tests/unit/utils.py
-@@ -14,12 +14,13 @@
- #    under the License.
- 
- import urllib
--import urlparse
- 
- import glance_store as store
- from oslo.config import cfg
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
-+from glance.common import store_utils
- from glance.common import wsgi
- import glance.context
- import glance.db.simple.api as simple_db
-@@ -135,6 +136,12 @@ class FakeStoreUtils(object):
-         else:
-             self.safe_delete_from_backend(context, image_id, location)
- 
-+    def validate_external_location(self, uri):
-+        if uri and urlparse.urlparse(uri).scheme:
-+            return store_utils.validate_external_location(uri)
-+        else:
-+            return True
-+
- 
- class FakeStoreAPI(object):
-     def __init__(self, store_metadata=None):
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index bd2182e..4ec136d 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -419,7 +419,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
--        self.assertIn('External sourcing not supported', res.body)
-+        self.assertIn('External source are not supported', res.body)
- 
-     def test_create_with_location_bad_store_uri(self):
-         fixture_headers = {
-@@ -1006,7 +1006,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-             res = req.get_response(self.api)
-             self.assertEqual(res.status_int, 409)
- 
--    def test_add_location_with_invalid_location(self):
-+    def test_add_location_with_invalid_location_on_conflict_image_size(self):
-         """Tests creates an image from location and conflict image size"""
-         fixture_headers = {'x-image-meta-store': 'file',
-                            'x-image-meta-disk-format': 'vhd',
-@@ -1023,6 +1023,36 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
- 
-+    def test_add_location_with_invalid_location_on_restricted_sources(self):
-+        """Tests creates an image from location and restricted sources"""
-+        fixture_headers = {'x-image-meta-store': 'file',
-+                           'x-image-meta-disk-format': 'vhd',
-+                           'x-image-meta-location': 'file:///etc/passwd',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F'}
-+
-+        req = webob.Request.blank("/images")
-+        req.headers['Content-Type'] = 'application/octet-stream'
-+        req.method = 'POST'
-+        for k, v in fixture_headers.iteritems():
-+            req.headers[k] = v
-+        res = req.get_response(self.api)
-+        self.assertEqual(400, res.status_int)
-+
-+        fixture_headers = {'x-image-meta-store': 'file',
-+                           'x-image-meta-disk-format': 'vhd',
-+                           'x-image-meta-location': 'swift+config://xxx',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F'}
-+
-+        req = webob.Request.blank("/images")
-+        req.headers['Content-Type'] = 'application/octet-stream'
-+        req.method = 'POST'
-+        for k, v in fixture_headers.iteritems():
-+            req.headers[k] = v
-+        res = req.get_response(self.api)
-+        self.assertEqual(400, res.status_int)
-+
-     def test_add_copy_from_with_location(self):
-         """Tests creates an image from copy-from and location"""
-         fixture_headers = {'x-image-meta-store': 'file',
-@@ -1039,6 +1069,34 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
- 
-+    def test_add_copy_from_with_restricted_sources(self):
-+        """Tests creates an image from copy-from with restricted sources"""
-+        fixture_headers = {'x-image-meta-store': 'file',
-+                           'x-image-meta-disk-format': 'vhd',
-+                           'x-glance-api-copy-from': 'file:///etc/passwd',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F'}
-+
-+        req = webob.Request.blank("/images")
-+        req.method = 'POST'
-+        for k, v in six.iteritems(fixture_headers):
-+            req.headers[k] = v
-+        res = req.get_response(self.api)
-+        self.assertEqual(400, res.status_int)
-+
-+        fixture_headers = {'x-image-meta-store': 'file',
-+                           'x-image-meta-disk-format': 'vhd',
-+                           'x-glance-api-copy-from': 'swift+config://xxx',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F'}
-+
-+        req = webob.Request.blank("/images")
-+        req.method = 'POST'
-+        for k, v in six.iteritems(fixture_headers):
-+            req.headers[k] = v
-+        res = req.get_response(self.api)
-+        self.assertEqual(400, res.status_int)
-+
-     def test_add_copy_from_upload_image_unauthorized_with_body(self):
-         rules = {"upload_image": '!', "modify_image": '@',
-                  "add_image": '@'}
--- 
-2.0.5
-
diff --git a/app-admin/glance/files/glance-CVE-2014-9623.patch b/app-admin/glance/files/glance-CVE-2014-9623.patch
deleted file mode 100644 (file)
index a9cc123..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-From 7d5d8657fd70b20518610b3c6f8e41e16c72fa31 Mon Sep 17 00:00:00 2001
-From: Zhi Yan Liu <zhiyanl@cn.ibm.com>
-Date: Tue, 30 Dec 2014 22:25:50 +0800
-Subject: [PATCH] Cleanup chunks for deleted image that was 'saving'
-
-Currently image data cannot be removed synchronously for an image that
-is in saving state. 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. However, by the limitation of the design we
-cannot enforce a global quota check for the image in saving status.
-
-This change introduces a inconsonance between http response codes of
-v1 and v2 APIs. The status codes which we will now see after the upload
-process completes on an image which was deleted mid way are:
-
-v1: 412 Precondition Failed
-v2: 410 Gone
-
-SecurityImpact
-UpgradeImpact
-APIImpact
-
-Closes-Bug: 1383973
-Closes-Bug: 1398830
-Closes-Bug: 1188532
-
-Conflicts:
-       glance/api/v1/upload_utils.py
-       glance/api/v2/image_data.py
-       glance/tests/unit/test_domain_proxy.py
-       glance/tests/unit/v1/test_api.py
-
-Change-Id: I47229b366c25367ec1bd48aec684e0880f3dfe60
-Signed-off-by: Zhi Yan Liu <zhiyanl@cn.ibm.com>
-(cherry picked from commit 0dc8fbb3479a53c5bba8475d14f4c7206904c5ea)
----
- glance/api/authorization.py                      |  4 +-
- glance/api/policy.py                             |  8 ++--
- glance/api/v1/upload_utils.py                    | 19 +++++---
- glance/api/v2/image_data.py                      |  8 +++-
- glance/db/__init__.py                            |  7 +--
- glance/domain/proxy.py                           |  4 +-
- glance/location.py                               |  4 +-
- glance/notifier.py                               |  4 +-
- glance/quota/__init__.py                         |  4 +-
- glance/tests/unit/test_domain_proxy.py           | 14 +++---
- glance/tests/unit/test_policy.py                 |  2 +-
- glance/tests/unit/test_quota.py                  | 17 ++++---
- glance/tests/unit/test_store_image.py            |  2 +-
- glance/tests/unit/v1/test_api.py                 | 57 +++++++++++-------------
- glance/tests/unit/v2/test_image_data_resource.py | 24 +++++-----
- 15 files changed, 98 insertions(+), 80 deletions(-)
-
-diff --git a/glance/api/authorization.py b/glance/api/authorization.py
-index 149ff55..77f7ed3 100644
---- a/glance/api/authorization.py
-+++ b/glance/api/authorization.py
-@@ -158,10 +158,10 @@ class ImageMemberRepoProxy(glance.domain.proxy.Repo):
-             raise exception.Forbidden(message
-                                       % self.image.image_id)
- 
--    def save(self, image_member):
-+    def save(self, image_member, from_state=None):
-         if (self.context.is_admin or
-                 self.context.owner == image_member.member_id):
--            self.member_repo.save(image_member)
-+            self.member_repo.save(image_member, from_state=from_state)
-         else:
-             message = _("You cannot update image member %s")
-             raise exception.Forbidden(message % image_member.member_id)
-diff --git a/glance/api/policy.py b/glance/api/policy.py
-index 0bc8d56..e395876 100644
---- a/glance/api/policy.py
-+++ b/glance/api/policy.py
-@@ -182,9 +182,9 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-         self.policy.enforce(self.context, 'get_images', {})
-         return super(ImageRepoProxy, self).list(*args, **kwargs)
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         self.policy.enforce(self.context, 'modify_image', {})
--        return super(ImageRepoProxy, self).save(image)
-+        return super(ImageRepoProxy, self).save(image, from_state=from_state)
- 
-     def add(self, image):
-         self.policy.enforce(self.context, 'add_image', {})
-@@ -285,9 +285,9 @@ class ImageMemberRepoProxy(glance.domain.proxy.Repo):
-         self.policy.enforce(self.context, 'get_member', {})
-         return self.member_repo.get(member_id)
- 
--    def save(self, member):
-+    def save(self, member, from_state=None):
-         self.policy.enforce(self.context, 'modify_member', {})
--        self.member_repo.save(member)
-+        self.member_repo.save(member, from_state=from_state)
- 
-     def list(self, *args, **kwargs):
-         self.policy.enforce(self.context, 'get_members', {})
-diff --git a/glance/api/v1/upload_utils.py b/glance/api/v1/upload_utils.py
-index 8a190fc..60c3d3d 100644
---- a/glance/api/v1/upload_utils.py
-+++ b/glance/api/v1/upload_utils.py
-@@ -153,12 +153,19 @@ def upload_data_to_store(req, image_meta, image_data, store, notifier):
-         update_data = {'checksum': checksum,
-                        'size': size}
-         try:
--            image_meta = registry.update_image_metadata(req.context,
--                                                        image_id,
--                                                        update_data,
--                                                        from_state='saving')
--
--        except exception.NotFound as e:
-+            try:
-+                state = 'saving'
-+                image_meta = registry.update_image_metadata(req.context,
-+                                                            image_id,
-+                                                            update_data,
-+                                                            from_state=state)
-+            except exception.Duplicate:
-+                image = registry.get_image_metadata(req.context, image_id)
-+                if image['status'] == 'deleted':
-+                    raise exception.NotFound()
-+                else:
-+                    raise
-+        except exception.NotFound:
-             msg = _LI("Image %s could not be found after upload. The image may"
-                       " have been deleted during the upload.") % image_id
-             LOG.info(msg)
-diff --git a/glance/api/v2/image_data.py b/glance/api/v2/image_data.py
-index 430ffc5..cdfa34b 100644
---- a/glance/api/v2/image_data.py
-+++ b/glance/api/v2/image_data.py
-@@ -73,8 +73,8 @@ class ImageDataController(object):
-             try:
-                 image_repo.save(image)
-                 image.set_data(data, size)
--                image_repo.save(image)
--            except exception.NotFound as e:
-+                image_repo.save(image, from_state='saving')
-+            except (exception.NotFound, exception.Conflict) as e:
-                 msg = (_("Image %(id)s could not be found after upload."
-                          "The image may have been deleted during the upload: "
-                          "%(error)s Cleaning up the chunks uploaded") %
-@@ -152,6 +152,10 @@ class ImageDataController(object):
-             raise webob.exc.HTTPServiceUnavailable(explanation=msg,
-                                                    request=req)
- 
-+        except webob.exc.HTTPGone as e:
-+            with excutils.save_and_reraise_exception():
-+                LOG.error(_LE("Failed to upload image data due to HTTP error"))
-+
-         except webob.exc.HTTPError as e:
-             with excutils.save_and_reraise_exception():
-                 LOG.error(_LE("Failed to upload image data due to HTTP error"))
-diff --git a/glance/db/__init__.py b/glance/db/__init__.py
-index 05db7f8..483ba21 100644
---- a/glance/db/__init__.py
-+++ b/glance/db/__init__.py
-@@ -164,7 +164,7 @@ class ImageRepo(object):
-         image.created_at = new_values['created_at']
-         image.updated_at = new_values['updated_at']
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         image_values = self._format_image_to_db(image)
-         if image_values['size'] > CONF.image_size_cap:
-             raise exception.ImageSizeLimitExceeded
-@@ -172,7 +172,8 @@ class ImageRepo(object):
-             new_values = self.db_api.image_update(self.context,
-                                                   image.image_id,
-                                                   image_values,
--                                                  purge_props=True)
-+                                                  purge_props=True,
-+                                                  from_state=from_state)
-         except (exception.NotFound, exception.Forbidden):
-             msg = _("No image found with ID %s") % image.image_id
-             raise exception.NotFound(msg)
-@@ -265,7 +266,7 @@ class ImageMemberRepo(object):
-             msg = _("The specified member %s could not be found")
-             raise exception.NotFound(msg % image_member.id)
- 
--    def save(self, image_member):
-+    def save(self, image_member, from_state=None):
-         image_member_values = self._format_image_member_to_db(image_member)
-         try:
-             new_values = self.db_api.image_member_update(self.context,
-diff --git a/glance/domain/proxy.py b/glance/domain/proxy.py
-index 5a91d34..09c0fb2 100644
---- a/glance/domain/proxy.py
-+++ b/glance/domain/proxy.py
-@@ -94,9 +94,9 @@ class Repo(object):
-         result = self.base.add(base_item)
-         return self.helper.proxy(result)
- 
--    def save(self, item):
-+    def save(self, item, from_state=None):
-         base_item = self.helper.unproxy(item)
--        result = self.base.save(base_item)
-+        result = self.base.save(base_item, from_state=from_state)
-         return self.helper.proxy(result)
- 
-     def remove(self, item):
-diff --git a/glance/location.py b/glance/location.py
-index f83fa7a..b49546d 100644
---- a/glance/location.py
-+++ b/glance/location.py
-@@ -60,8 +60,8 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-         self._set_acls(image)
-         return result
- 
--    def save(self, image):
--        result = super(ImageRepoProxy, self).save(image)
-+    def save(self, image, from_state=None):
-+        result = super(ImageRepoProxy, self).save(image, from_state=from_state)
-         self._set_acls(image)
-         return result
- 
-diff --git a/glance/notifier.py b/glance/notifier.py
-index 5ec0854..21223da 100644
---- a/glance/notifier.py
-+++ b/glance/notifier.py
-@@ -122,8 +122,8 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-                                              item_proxy_class=ImageProxy,
-                                              item_proxy_kwargs=proxy_kwargs)
- 
--    def save(self, image):
--        super(ImageRepoProxy, self).save(image)
-+    def save(self, image, from_state=None):
-+        super(ImageRepoProxy, self).save(image, from_state=from_state)
-         self.notifier.info('image.update',
-                            format_image_notification(image))
- 
-diff --git a/glance/quota/__init__.py b/glance/quota/__init__.py
-index 4051992..d628a8c 100644
---- a/glance/quota/__init__.py
-+++ b/glance/quota/__init__.py
-@@ -104,10 +104,10 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-             LOG.debug(six.text_type(exc))
-             raise exc
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         if image.added_new_properties():
-             self._enforce_image_property_quota(len(image.extra_properties))
--        return super(ImageRepoProxy, self).save(image)
-+        return super(ImageRepoProxy, self).save(image, from_state=from_state)
- 
-     def add(self, image):
-         self._enforce_image_property_quota(len(image.extra_properties))
-diff --git a/glance/tests/unit/test_domain_proxy.py b/glance/tests/unit/test_domain_proxy.py
-index 1bb6863..2b8f792 100644
---- a/glance/tests/unit/test_domain_proxy.py
-+++ b/glance/tests/unit/test_domain_proxy.py
-@@ -74,7 +74,7 @@ class TestProxyRepoPlain(test_utils.BaseTestCase):
-         self._test_method('add', 'snuff', 'enough')
- 
-     def test_save(self):
--        self._test_method('save', 'snuff', 'enough')
-+        self._test_method('save', 'snuff', 'enough', from_state=None)
- 
-     def test_remove(self):
-         self._test_method('add', None, 'flying')
-@@ -121,14 +121,14 @@ class TestProxyRepoWrapping(test_utils.BaseTestCase):
-             self.assertEqual(results[i].args, tuple())
-             self.assertEqual(results[i].kwargs, {'a': 1})
- 
--    def _test_method_with_proxied_argument(self, name, result):
-+    def _test_method_with_proxied_argument(self, name, result, **kwargs):
-         self.fake_repo.result = result
-         item = FakeProxy('snoop')
-         method = getattr(self.proxy_repo, name)
-         proxy_result = method(item)
- 
--        self.assertEqual(self.fake_repo.args, ('snoop',))
--        self.assertEqual(self.fake_repo.kwargs, {})
-+        self.assertEqual(('snoop',), self.fake_repo.args)
-+        self.assertEqual(kwargs, self.fake_repo.kwargs)
- 
-         if result is None:
-             self.assertIsNone(proxy_result)
-@@ -145,10 +145,12 @@ class TestProxyRepoWrapping(test_utils.BaseTestCase):
-         self._test_method_with_proxied_argument('add', None)
- 
-     def test_save(self):
--        self._test_method_with_proxied_argument('save', 'dog')
-+        self._test_method_with_proxied_argument('save', 'dog',
-+                                                from_state=None)
- 
-     def test_save_with_no_result(self):
--        self._test_method_with_proxied_argument('save', None)
-+        self._test_method_with_proxied_argument('save', None,
-+                                                from_state=None)
- 
-     def test_remove(self):
-         self._test_method_with_proxied_argument('remove', 'dog')
-diff --git a/glance/tests/unit/test_policy.py b/glance/tests/unit/test_policy.py
-index 5b5e870..44546a0 100644
---- a/glance/tests/unit/test_policy.py
-+++ b/glance/tests/unit/test_policy.py
-@@ -78,7 +78,7 @@ class MemberRepoStub(object):
-     def get(self, *args, **kwargs):
-         return 'member_repo_get'
- 
--    def save(self, image_member):
-+    def save(self, image_member, from_state=None):
-         image_member.output = 'member_repo_save'
- 
-     def list(self, *args, **kwargs):
-diff --git a/glance/tests/unit/test_quota.py b/glance/tests/unit/test_quota.py
-index c12eda2..1c40fb4 100644
---- a/glance/tests/unit/test_quota.py
-+++ b/glance/tests/unit/test_quota.py
-@@ -367,7 +367,8 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         self.image.extra_properties = {'foo': 'bar'}
-         self.image_repo_proxy.save(self.image)
- 
--        self.image_repo_mock.save.assert_called_once_with(self.base_image)
-+        self.image_repo_mock.save.assert_called_once_with(self.base_image,
-+                                                          from_state=None)
- 
-     def test_save_image_too_many_image_properties(self):
-         self.config(image_property_quota=1)
-@@ -383,7 +384,8 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         self.image.extra_properties = {'foo': 'bar'}
-         self.image_repo_proxy.save(self.image)
- 
--        self.image_repo_mock.save.assert_called_once_with(self.base_image)
-+        self.image_repo_mock.save.assert_called_once_with(self.base_image,
-+                                                          from_state=None)
- 
-     def test_add_image_with_image_property(self):
-         self.config(image_property_quota=1)
-@@ -422,7 +424,8 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         self.config(image_property_quota=1)
-         self.image.extra_properties = {'foo': 'frob', 'spam': 'eggs'}
-         self.image_repo_proxy.save(self.image)
--        self.image_repo_mock.save.assert_called_once_with(self.base_image)
-+        self.image_repo_mock.save.assert_called_once_with(self.base_image,
-+                                                          from_state=None)
-         self.assertEqual('frob', self.base_image.extra_properties['foo'])
-         self.assertEqual('eggs', self.base_image.extra_properties['spam'])
- 
-@@ -431,7 +434,8 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         self.config(image_property_quota=1)
-         del self.image.extra_properties['foo']
-         self.image_repo_proxy.save(self.image)
--        self.image_repo_mock.save.assert_called_once_with(self.base_image)
-+        self.image_repo_mock.save.assert_called_once_with(self.base_image,
-+                                                          from_state=None)
-         self.assertNotIn('foo', self.base_image.extra_properties)
-         self.assertEqual('ham', self.base_image.extra_properties['spam'])
- 
-@@ -447,7 +451,7 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         del self.image.extra_properties['frob']
-         del self.image.extra_properties['lorem']
-         self.image_repo_proxy.save(self.image)
--        call_args = mock.call(self.base_image)
-+        call_args = mock.call(self.base_image, from_state=None)
-         self.assertEqual(call_args, self.image_repo_mock.save.call_args)
-         self.assertEqual('bar', self.base_image.extra_properties['foo'])
-         self.assertEqual('ham', self.base_image.extra_properties['spam'])
-@@ -466,7 +470,8 @@ class TestImagePropertyQuotas(test_utils.BaseTestCase):
-         self.config(image_property_quota=1)
-         del self.image.extra_properties['foo']
-         self.image_repo_proxy.save(self.image)
--        self.image_repo_mock.save.assert_called_once_with(self.base_image)
-+        self.image_repo_mock.save.assert_called_once_with(self.base_image,
-+                                                          from_state=None)
-         self.assertNotIn('foo', self.base_image.extra_properties)
-         self.assertEqual('ham', self.base_image.extra_properties['spam'])
-         self.assertEqual('baz', self.base_image.extra_properties['frob'])
-diff --git a/glance/tests/unit/test_store_image.py b/glance/tests/unit/test_store_image.py
-index 8b334ab..b656454 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -36,7 +36,7 @@ class ImageRepoStub(object):
-     def add(self, image):
-         return image
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         return image
- 
- 
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index 39e9a44..7dc0737 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -39,7 +39,6 @@ from glance.db.sqlalchemy import api as db_api
- from glance.db.sqlalchemy import models as db_models
- from glance.openstack.common import jsonutils
- from glance.openstack.common import timeutils
--
- import glance.registry.client.v1.api as registry
- from glance.tests.unit import base
- import glance.tests.unit.utils as unit_test_utils
-@@ -1735,8 +1734,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-         self.assertEqual(1, mock_store_add_to_backend.call_count)
- 
--    def test_delete_during_image_upload(self):
--        req = unit_test_utils.get_fake_request()
-+    def _check_delete_during_image_upload(self, is_admin=False):
- 
-         fixture_headers = {'x-image-meta-store': 'file',
-                            'x-image-meta-disk-format': 'vhd',
-@@ -1744,8 +1742,8 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-                            'x-image-meta-name': 'fake image #3',
-                            'x-image-meta-property-key1': 'value1'}
- 
--        req = webob.Request.blank("/images")
--        req.method = 'POST'
-+        req = unit_test_utils.get_fake_request(path="/images",
-+                                               is_admin=is_admin)
-         for k, v in six.iteritems(fixture_headers):
-             req.headers[k] = v
- 
-@@ -1770,31 +1768,18 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-                        mock_initiate_deletion)
- 
-         orig_update_image_metadata = registry.update_image_metadata
--        ctlr = glance.api.v1.controller.BaseController
--        orig_get_image_meta_or_404 = ctlr.get_image_meta_or_404
--
--        def mock_update_image_metadata(*args, **kwargs):
- 
--            if args[2].get('status', None) == 'deleted':
-+        data = "somedata"
- 
--                # One shot.
--                def mock_get_image_meta_or_404(*args, **kwargs):
--                    ret = orig_get_image_meta_or_404(*args, **kwargs)
--                    ret['status'] = 'queued'
--                    self.stubs.Set(ctlr, 'get_image_meta_or_404',
--                                   orig_get_image_meta_or_404)
--                    return ret
--
--                self.stubs.Set(ctlr, 'get_image_meta_or_404',
--                               mock_get_image_meta_or_404)
-+        def mock_update_image_metadata(*args, **kwargs):
- 
--                req = webob.Request.blank("/images/%s" % image_id)
--                req.method = 'PUT'
--                req.headers['Content-Type'] = 'application/octet-stream'
--                req.body = "somedata"
-+            if args[2].get('size', None) == len(data):
-+                path = "/images/%s" % image_id
-+                req = unit_test_utils.get_fake_request(path=path,
-+                                                       method='DELETE',
-+                                                       is_admin=is_admin)
-                 res = req.get_response(self.api)
--                self.assertEqual(res.status_int, 200)
--                self.assertFalse(res.location)
-+                self.assertEqual(200, res.status_int)
- 
-                 self.stubs.Set(registry, 'update_image_metadata',
-                                orig_update_image_metadata)
-@@ -1804,20 +1789,30 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-         self.stubs.Set(registry, 'update_image_metadata',
-                        mock_update_image_metadata)
- 
--        req = webob.Request.blank("/images/%s" % image_id)
--        req.method = 'DELETE'
-+        req = unit_test_utils.get_fake_request(path="/images/%s" % image_id,
-+                                               method='PUT')
-+        req.headers['Content-Type'] = 'application/octet-stream'
-+        req.body = data
-         res = req.get_response(self.api)
--        self.assertEqual(res.status_int, 200)
-+        self.assertEqual(412, res.status_int)
-+        self.assertFalse(res.location)
- 
-         self.assertTrue(called['initiate_deletion'])
- 
--        req = webob.Request.blank("/images/%s" % image_id)
--        req.method = 'HEAD'
-+        req = unit_test_utils.get_fake_request(path="/images/%s" % image_id,
-+                                               method='HEAD',
-+                                               is_admin=True)
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 200)
-         self.assertEqual(res.headers['x-image-meta-deleted'], 'True')
-         self.assertEqual(res.headers['x-image-meta-status'], 'deleted')
- 
-+    def test_delete_during_image_upload_by_normal_user(self):
-+        self._check_delete_during_image_upload(is_admin=False)
-+
-+    def test_delete_during_image_upload_by_admin(self):
-+        self._check_delete_during_image_upload(is_admin=True)
-+
-     def test_disable_purge_props(self):
-         """
-         Test the special x-glance-registry-purge-props header controls
-diff --git a/glance/tests/unit/v2/test_image_data_resource.py b/glance/tests/unit/v2/test_image_data_resource.py
-index cc8148a..a121e82 100644
---- a/glance/tests/unit/v2/test_image_data_resource.py
-+++ b/glance/tests/unit/v2/test_image_data_resource.py
-@@ -81,7 +81,7 @@ class FakeImageRepo(object):
-         else:
-             return self.result
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         self.saved_image = image
- 
- 
-@@ -184,17 +184,21 @@ class TestImagesController(base.StoreClearingUnitTest):
-                           request, unit_test_utils.UUID1, 'YYYY', 4)
- 
-     def test_upload_non_existent_image_during_save_initiates_deletion(self):
--        def fake_save(self):
-+        def fake_save_not_found(self):
-             raise exception.NotFound()
- 
--        request = unit_test_utils.get_fake_request()
--        image = FakeImage('abcd', locations=['http://example.com/image'])
--        self.image_repo.result = image
--        self.image_repo.save = fake_save
--        image.delete = mock.Mock()
--        self.assertRaises(webob.exc.HTTPGone, self.controller.upload,
--                          request, str(uuid.uuid4()), 'ABC', 3)
--        self.assertTrue(image.delete.called)
-+        def fake_save_conflict(self):
-+            raise exception.Conflict()
-+
-+        for fun in [fake_save_not_found, fake_save_conflict]:
-+            request = unit_test_utils.get_fake_request()
-+            image = FakeImage('abcd', locations=['http://example.com/image'])
-+            self.image_repo.result = image
-+            self.image_repo.save = fun
-+            image.delete = mock.Mock()
-+            self.assertRaises(webob.exc.HTTPGone, self.controller.upload,
-+                              request, str(uuid.uuid4()), 'ABC', 3)
-+            self.assertTrue(image.delete.called)
- 
-     def test_upload_non_existent_image_raises_not_found_exception(self):
-         def fake_save(self):
--- 
-2.0.5
-
diff --git a/app-admin/glance/glance-2014.2.2.ebuild b/app-admin/glance/glance-2014.2.2.ebuild
new file mode 100644 (file)
index 0000000..28140ce
--- /dev/null
@@ -0,0 +1,162 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/glance-2014.2.2.ebuild,v 1.1 2015/02/08 01:51:56 prometheanfire Exp $
+
+EAPI=5
+PYTHON_COMPAT=( python2_7 )
+
+inherit distutils-r1 user
+
+DESCRIPTION="Provides services for discovering, registering, and retrieving
+virtual machine images with Openstack"
+HOMEPAGE="https://launchpad.net/glance"
+SRC_URI="http://launchpad.net/${PN}/juno/${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.8.0[${PYTHON_USEDEP}]
+                       <dev-python/hacking-0.9[${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/mock-1.0[${PYTHON_USEDEP}]
+                       >=dev-python/mox-0.5.3[${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-1.2.1[${PYTHON_USEDEP}]
+                       !~dev-python/requests-2.4.0[${PYTHON_USEDEP}]
+                       >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
+                       >=dev-python/testtools-0.9.34[${PYTHON_USEDEP}]
+                       >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
+                       <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
+                       dev-python/mysql-python[${PYTHON_USEDEP}]
+                       dev-python/psycopg[${PYTHON_USEDEP}]
+                       ~dev-python/pysendfile-2.0.0[${PYTHON_USEDEP}]
+                       dev-python/qpid-python[${PYTHON_USEDEP}]
+                       >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
+                       >=dev-python/oslo-sphinx-2.2.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.15.1[${PYTHON_USEDEP}]
+       <dev-python/eventlet-0.16.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/boto-2.32.1[${PYTHON_USEDEP}]
+       >=dev-python/boto-2.35.0[${PYTHON_USEDEP}]
+       ~dev-python/sqlalchemy-migrate-0.9.1[${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.4.0[${PYTHON_USEDEP}]
+       >=dev-python/stevedore-1.0.0[${PYTHON_USEDEP}]
+       >=dev-python/netaddr-0.7.12[${PYTHON_USEDEP}]
+       >=dev-python/keystonemiddleware-1.0.0[${PYTHON_USEDEP}]
+       >=dev-python/WSME-0.6[${PYTHON_USEDEP}]
+       dev-python/posix_ipc[${PYTHON_USEDEP}]
+       swift? (
+               >=dev-python/python-swiftclient-2.2.0[${PYTHON_USEDEP}]
+       )
+       >=dev-python/oslo-vmware-0.6.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-vmware-0.9.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-cinderclient-1.1.0[${PYTHON_USEDEP}]
+       >=dev-python/python-keystoneclient-0.10.0[${PYTHON_USEDEP}]
+       >=dev-python/pyopenssl-0.11[${PYTHON_USEDEP}]
+       >=dev-python/six-1.7.0[${PYTHON_USEDEP}]
+       >=dev-python/oslo-db-1.0.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-db-1.1.0[${PYTHON_USEDEP}]
+       >=dev-python/oslo-i18n-1.0.0[${PYTHON_USEDEP}]
+       >=dev-python/oslo-messaging-1.4.0[${PYTHON_USEDEP}]
+       !~dev-python/oslo-messaging-1.5.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-messaging-1.6.0[${PYTHON_USEDEP}]
+       >=dev-python/retrying-1.2.2[${PYTHON_USEDEP}]
+       !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
+       >=dev-python/osprofiler-0.3.0[${PYTHON_USEDEP}]
+       >=dev-python/glance_store-0.1.1[${PYTHON_USEDEP}]"
+
+PATCHES=(
+       "${FILESDIR}/${PN}-2013.2-sphinx_mapping.patch"
+)
+
+pkg_setup() {
+       enewgroup glance
+       enewuser glance -1 -1 /var/lib/glance glance
+}
+
+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
+       nosetests glance/ || die "tests failed 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/glance-api-paste.ini"
+       doins "etc/glance-api.conf"
+       doins "etc/glance-cache.conf"
+       doins "etc/glance-registry-paste.ini"
+       doins "etc/glance-registry.conf"
+       doins "etc/glance-scrubber.conf"
+       doins "etc/logging.cnf.sample"
+       doins "etc/policy.json"
+       doins "etc/schema-image.json"
+}
+
+python_install_all() {
+       use doc && local HTML_DOCS=( doc/build/html/. )
+       distutils-r1_python_install_all
+}
index b25c6fbbec11602db3cba744bb3e89326505b62f..7ba4ef5cab3beaaa30e145587c5d921289e82717 100644 (file)
@@ -1,6 +1,6 @@
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/glance-2014.2.9999.ebuild,v 1.5 2014/12/09 01:20:13 prometheanfire Exp $
+# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/glance-2014.2.9999.ebuild,v 1.6 2015/02/08 01:51:56 prometheanfire Exp $
 
 EAPI=5
 PYTHON_COMPAT=( python2_7 )
@@ -22,28 +22,31 @@ 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? ( >=dev-python/hacking-0.8.0[${PYTHON_USEDEP}]
-                               <dev-python/hacking-0.9[${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/mock-1.0[${PYTHON_USEDEP}]
-                               >=dev-python/mox-0.5.3[${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-1.2.1[${PYTHON_USEDEP}]
-                               !~dev-python/requests-2.4.0[${PYTHON_USEDEP}]
-                               >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
-                               >=dev-python/testtools-0.9.34[${PYTHON_USEDEP}]
-                               >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
-                               <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
-                               dev-python/mysql-python[${PYTHON_USEDEP}]
-                               dev-python/psycopg[${PYTHON_USEDEP}]
-                               ~dev-python/pysendfile-2.0.0[${PYTHON_USEDEP}]
-                               dev-python/qpid-python[${PYTHON_USEDEP}]
-                               >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
-                               >=dev-python/oslo-sphinx-2.2.0[${PYTHON_USEDEP}] )"
+               test? (
+                       ${RDEPEND}
+                       >=dev-python/hacking-0.8.0[${PYTHON_USEDEP}]
+                       <dev-python/hacking-0.9[${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/mock-1.0[${PYTHON_USEDEP}]
+                       >=dev-python/mox-0.5.3[${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-1.2.1[${PYTHON_USEDEP}]
+                       !~dev-python/requests-2.4.0[${PYTHON_USEDEP}]
+                       >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
+                       >=dev-python/testtools-0.9.34[${PYTHON_USEDEP}]
+                       >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
+                       <dev-python/psutil-2.0.0[${PYTHON_USEDEP}]
+                       dev-python/mysql-python[${PYTHON_USEDEP}]
+                       dev-python/psycopg[${PYTHON_USEDEP}]
+                       ~dev-python/pysendfile-2.0.0[${PYTHON_USEDEP}]
+                       dev-python/qpid-python[${PYTHON_USEDEP}]
+                       >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
+                       >=dev-python/oslo-sphinx-2.2.0[${PYTHON_USEDEP}]
+               )"
 
 #note to self, wsgiref is a python builtin, no need to package it
 #>=dev-python/wsgiref-0.1.2[${PYTHON_USEDEP}]
@@ -51,52 +54,29 @@ DEPEND="dev-python/setuptools[${PYTHON_USEDEP}]
 RDEPEND="
        >=dev-python/greenlet-0.3.2[${PYTHON_USEDEP}]
        sqlite? (
-               || (
-                       (
-                               >=dev-python/sqlalchemy-0.8.4[sqlite,${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.8.99[sqlite,${PYTHON_USEDEP}]
-                       )
-                       (
-                               >=dev-python/sqlalchemy-0.9.7[sqlite,${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.9.99[sqlite,${PYTHON_USEDEP}]
-                       )
-               )
+               >=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.8.4[${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.8.99[${PYTHON_USEDEP}]
-                       )
-                       (
-                               >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
-                       )
-               )
+               >=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.8.4[${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.8.99[${PYTHON_USEDEP}]
-                       )
-                       (
-                               >=dev-python/sqlalchemy-0.9.7[${PYTHON_USEDEP}]
-                               <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
-                       )
-               )
+               >=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.15.1[${PYTHON_USEDEP}]
+       <dev-python/eventlet-0.16.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/boto-2.32.1[${PYTHON_USEDEP}]
-       >=dev-python/sqlalchemy-migrate-0.9.1[${PYTHON_USEDEP}]
-       !~dev-python/sqlalchemy-migrate-0.9.2[${PYTHON_USEDEP}]
+       >=dev-python/boto-2.35.0[${PYTHON_USEDEP}]
+       ~dev-python/sqlalchemy-migrate-0.9.1[${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}]
@@ -112,6 +92,7 @@ RDEPEND="
                >=dev-python/python-swiftclient-2.2.0[${PYTHON_USEDEP}]
        )
        >=dev-python/oslo-vmware-0.6.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-vmware-0.9.0[${PYTHON_USEDEP}]
        dev-python/paste[${PYTHON_USEDEP}]
        >=dev-python/jsonschema-2.0.0[${PYTHON_USEDEP}]
        <dev-python/jsonschema-3.0.0[${PYTHON_USEDEP}]
@@ -120,15 +101,19 @@ RDEPEND="
        >=dev-python/pyopenssl-0.11[${PYTHON_USEDEP}]
        >=dev-python/six-1.7.0[${PYTHON_USEDEP}]
        >=dev-python/oslo-db-1.0.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-db-1.1.0[${PYTHON_USEDEP}]
        >=dev-python/oslo-i18n-1.0.0[${PYTHON_USEDEP}]
        >=dev-python/oslo-messaging-1.4.0[${PYTHON_USEDEP}]
        !~dev-python/oslo-messaging-1.5.0[${PYTHON_USEDEP}]
+       <dev-python/oslo-messaging-1.6.0[${PYTHON_USEDEP}]
        >=dev-python/retrying-1.2.2[${PYTHON_USEDEP}]
        !~dev-python/retrying-1.3.0[${PYTHON_USEDEP}]
        >=dev-python/osprofiler-0.3.0[${PYTHON_USEDEP}]
        >=dev-python/glance_store-0.1.1[${PYTHON_USEDEP}]"
 
-PATCHES=( "${FILESDIR}/${PN}-2013.2-sphinx_mapping.patch" )
+PATCHES=(
+       "${FILESDIR}/${PN}-2013.2-sphinx_mapping.patch"
+)
 
 pkg_setup() {
        enewgroup glance
diff --git a/app-admin/glance/glance-9999.ebuild b/app-admin/glance/glance-9999.ebuild
deleted file mode 100644 (file)
index cdbd882..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-# Copyright 1999-2014 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/app-admin/glance/glance-9999.ebuild,v 1.12 2014/08/01 05:12:09 prometheanfire Exp $
-
-EAPI=5
-PYTHON_COMPAT=( python2_7 )
-
-inherit git-2 distutils-r1 user
-
-DESCRIPTION="Provides services for discovering, registering, and retrieving
-virtual machine images with Openstack"
-HOMEPAGE="https://launchpad.net/glance"
-EGIT_REPO_URI="https://github.com/openstack/glance.git"
-
-LICENSE="Apache-2.0"
-SLOT="0"
-KEYWORDS=""
-IUSE="doc mysql postgres +sqlite +swift test"
-REQUIRED_USE="|| ( mysql postgres sqlite )"
-
-DEPEND="dev-python/setuptools[${PYTHON_USEDEP}]
-               >=dev-python/pbr-0.6.0[${PYTHON_USEDEP}]
-               <dev-python/pbr-1.0[${PYTHON_USEDEP}]
-               test? ( >=dev-python/hacking-0.8.0[${PYTHON_USEDEP}]
-                               <dev-python/hacking-0.9[${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/mock-1.0[${PYTHON_USEDEP}]
-                               >=dev-python/mox-0.5.3[${PYTHON_USEDEP}]
-                               >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}]
-                               <dev-python/sphinx-1.2[${PYTHON_USEDEP}]
-                               >=dev-python/requests-1.1[${PYTHON_USEDEP}]
-                               >=dev-python/testrepository-0.0.18[${PYTHON_USEDEP}]
-                               >=dev-python/testtools-0.9.34[${PYTHON_USEDEP}]
-                               >=dev-python/psutil-1.1.1[${PYTHON_USEDEP}]
-                               dev-python/mysql-python[${PYTHON_USEDEP}]
-                               dev-python/psycopg[${PYTHON_USEDEP}]
-                               ~dev-python/pysendfile-2.0.0[${PYTHON_USEDEP}]
-                               dev-python/qpid-python[${PYTHON_USEDEP}]
-                               >=dev-python/pyxattr-0.5.0[${PYTHON_USEDEP}]
-                               dev-python/oslo-sphinx[${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.8.0[sqlite,${PYTHON_USEDEP}]
-                       !~dev-python/sqlalchemy-0.9.5[sqlite,${PYTHON_USEDEP}]
-                       <=dev-python/sqlalchemy-0.9.99[sqlite,${PYTHON_USEDEP}]
-               )
-               mysql? (
-                       dev-python/mysql-python
-                       >=dev-python/sqlalchemy-0.8.0[${PYTHON_USEDEP}]
-                       !~dev-python/sqlalchemy-0.9.5[${PYTHON_USEDEP}]
-                       <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
-               )
-               postgres? (
-               dev-python/psycopg:2
-                       >=dev-python/sqlalchemy-0.8.0[${PYTHON_USEDEP}]
-                       !~dev-python/sqlalchemy-0.9.5[${PYTHON_USEDEP}]
-                       <=dev-python/sqlalchemy-0.9.99[${PYTHON_USEDEP}]
-               )
-               >=dev-python/anyjson-0.3.3[${PYTHON_USEDEP}]
-               >=dev-python/eventlet-0.13.0[${PYTHON_USEDEP}]
-               >=dev-python/pastedeploy-1.5.0[${PYTHON_USEDEP}]
-               >=dev-python/routes-1.12.3[${PYTHON_USEDEP}]
-               >=dev-python/webob-1.2.3[${PYTHON_USEDEP}]
-               >=dev-python/boto-2.12.0[${PYTHON_USEDEP}]
-               !~dev-python/boto-2.13.0[${PYTHON_USEDEP}]
-               >=dev-python/sqlalchemy-migrate-0.9[${PYTHON_USEDEP}]
-               >=dev-python/httplib2-0.7.5[${PYTHON_USEDEP}]
-               >=dev-python/kombu-2.4.8[${PYTHON_USEDEP}]
-               >=dev-python/pycrypto-2.6[${PYTHON_USEDEP}]
-               >=dev-python/iso8601-0.1.9[${PYTHON_USEDEP}]
-               >=dev-python/oslo-config-1.2.1[${PYTHON_USEDEP}]
-               >=dev-python/stevedore-0.14[${PYTHON_USEDEP}]
-               swift? (
-                       >=dev-python/python-swiftclient-1.6[${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-cinderclient-1.0.6[${PYTHON_USEDEP}]
-               >=dev-python/python-keystoneclient-0.7.0[${PYTHON_USEDEP}]
-               >=dev-python/pyopenssl-0.11[${PYTHON_USEDEP}]
-               >=dev-python/six-1.6.0[${PYTHON_USEDEP}]
-               >=dev-python/oslo-messaging-1.3.0[${PYTHON_USEDEP}]
-               >=dev-python/oslo-vmware-0.2[${PYTHON_USEDEP}]"
-
-PATCHES=( "${FILESDIR}"/${PN}-2013.2-sphinx_mapping.patch )
-
-pkg_setup() {
-       enewgroup glance
-       enewuser glance -1 -1 /var/lib/glance glance
-}
-
-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
-       nosetests glance/ || die "tests failed 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/glance-api-paste.ini"
-       doins "etc/glance-api.conf"
-       doins "etc/glance-cache.conf"
-       doins "etc/glance-registry-paste.ini"
-       doins "etc/glance-registry.conf"
-       doins "etc/glance-scrubber.conf"
-       doins "etc/logging.cnf.sample"
-       doins "etc/policy.json"
-       doins "etc/schema-image.json"
-}
-
-python_install_all() {
-       use doc && local HTML_DOCS=( doc/build/html/. )
-       distutils-r1_python_install_all
-}