hguemar pushed to openstack-glance (f21). "Update to upstream 2014.1.4 (..more)"

notifications at fedoraproject.org notifications at fedoraproject.org
Thu Mar 26 22:30:04 UTC 2015


>From 3bdbdafa726555e9b2059cac8898c1526c473f22 Mon Sep 17 00:00:00 2001
From: Haikel Guemar <hguemar at fedoraproject.org>
Date: Thu, 26 Mar 2015 23:15:01 +0100
Subject: Update to upstream 2014.1.4

Change-Id: I486c85edf96199c44beac36a097e9264189baaf8

diff --git a/.gitignore b/.gitignore
index 4e74255..f70028c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@
 /glance-2014.1.1.tar.gz
 /glance-2014.1.2.tar.gz
 /glance-2014.1.3.tar.gz
+/glance-2014.1.4.tar.gz
diff --git a/0001-Remove-runtime-dep-on-python-pbr.patch b/0001-Remove-runtime-dep-on-python-pbr.patch
index 4a8761a..723710c 100644
--- a/0001-Remove-runtime-dep-on-python-pbr.patch
+++ b/0001-Remove-runtime-dep-on-python-pbr.patch
@@ -1,4 +1,4 @@
-From 5c6c96b1d6a60056c44ba7917ed0529cf5667cf3 Mon Sep 17 00:00:00 2001
+From 7a8f58f9aca5241c0608d8407c89333ec3b961a2 Mon Sep 17 00:00:00 2001
 From: John Bresnahan <jbresnah at redhat.com>
 Date: Wed, 18 Sep 2013 16:43:45 -1000
 Subject: [PATCH] Remove runtime dep on python pbr
diff --git a/0002-Don-t-access-the-net-while-building-docs.patch b/0002-Don-t-access-the-net-while-building-docs.patch
index 284446c..4635c0f 100644
--- a/0002-Don-t-access-the-net-while-building-docs.patch
+++ b/0002-Don-t-access-the-net-while-building-docs.patch
@@ -1,4 +1,4 @@
-From 31f45f617f9dcc4992418fce0e494bf0ad9115dd Mon Sep 17 00:00:00 2001
+From eb6f5cd5c34cd59b08dcb33bd306ae6a69133a47 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?P=C3=A1draig=20Brady?= <pbrady at redhat.com>
 Date: Fri, 6 Jan 2012 17:12:54 +0000
 Subject: [PATCH] Don't access the net while building docs
diff --git a/0003-avoid-unsupported-storage-drivers.patch b/0003-avoid-unsupported-storage-drivers.patch
index abbbf49..d1005fa 100644
--- a/0003-avoid-unsupported-storage-drivers.patch
+++ b/0003-avoid-unsupported-storage-drivers.patch
@@ -1,4 +1,4 @@
-From 2cc03f67361507d8c467f7719a2ba3c1fe6e8345 Mon Sep 17 00:00:00 2001
+From 6c1f50eb5e5e74066b9876b21142775ae9753ce3 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P at draigBrady.com>
 Date: Wed, 9 Apr 2014 10:31:27 +0100
 Subject: [PATCH] avoid unsupported storage drivers
@@ -39,10 +39,10 @@ index 0246b67..04e5623 100644
  # ============ Filesystem Store Options ========================
  
 diff --git a/glance/store/__init__.py b/glance/store/__init__.py
-index 273b7c7..c73d3da 100644
+index aa11487..3093dc4 100644
 --- a/glance/store/__init__.py
 +++ b/glance/store/__init__.py
-@@ -69,10 +69,8 @@ _ALL_STORES = [
+@@ -70,10 +70,8 @@ _ALL_STORES = [
      'glance.store.rbd.Store',
      'glance.store.s3.Store',
      'glance.store.swift.Store',
@@ -52,4 +52,4 @@ index 273b7c7..c73d3da 100644
 -    'glance.store.vmware_datastore.Store'
  ]
  
- 
+ RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
diff --git a/0004-notify-calling-process-we-are-ready-to-serve.patch b/0004-notify-calling-process-we-are-ready-to-serve.patch
index b058ed3..aa8bbed 100644
--- a/0004-notify-calling-process-we-are-ready-to-serve.patch
+++ b/0004-notify-calling-process-we-are-ready-to-serve.patch
@@ -1,4 +1,4 @@
-From 2a9d2997d3bcd42ce0721ab1736b37df6a0bda53 Mon Sep 17 00:00:00 2001
+From 1416aae53fc8c8e170cf02b3b40335584ec77466 Mon Sep 17 00:00:00 2001
 From: Alan Pevec <apevec at redhat.com>
 Date: Tue, 11 Feb 2014 22:36:00 +0100
 Subject: [PATCH] notify calling process we are ready to serve
diff --git a/0005-Make-rbd-store-s-pool-handling-more-universal.patch b/0005-Make-rbd-store-s-pool-handling-more-universal.patch
deleted file mode 100644
index 6c49551..0000000
--- a/0005-Make-rbd-store-s-pool-handling-more-universal.patch
+++ /dev/null
@@ -1,156 +0,0 @@
-From ec4a8ccef8340939867a14872d98539ae653587e Mon Sep 17 00:00:00 2001
-From: Flavio Percoco <flavio at redhat.com>
-Date: Tue, 23 Sep 2014 17:55:13 +0200
-Subject: [PATCH] Make rbd store's pool handling more universal
-
-Currently we ignore the pool part of the location throughout the rbd store code.
-If there is a pool specified, use that. Otherwise we can still fall back to the
-configured pool.
-
-This is a required change if we want to support ephemeral disk snapshotting later on
-as in that scenario the ephemeral pool might be a different pool from images pool,
-yet we're going to need to reference the snapshot of a disk in the ephemeral pool.
-
-Resolves rhbz: 1148199
-Upstream-Closes-Bug: 1368128
-Upstream-Icehouse: https://review.openstack.org/#/c/125341/
-Upstream-Juno: https://review.openstack.org/#/c/125341/ (glance_store)
-
-Change-Id: Ie415667a809975948c8cfb71ec63a0905995fa67
-(cherry picked from commit 312e93eb165d66821a9f24c66a507e63e5fda9ab)
-Reviewed-on: https://code.engineering.redhat.com/gerrit/35437
-Reviewed-by: Jon Bernard <jobernar at redhat.com>
-Reviewed-by: Flavio Percoco <fpercoco at redhat.com>
-Tested-by: Flavio Percoco <fpercoco at redhat.com>
----
- glance/store/rbd.py                 | 23 +++++++++++++++--------
- glance/tests/unit/test_rbd_store.py | 12 +++++++-----
- 2 files changed, 22 insertions(+), 13 deletions(-)
-
-diff --git a/glance/store/rbd.py b/glance/store/rbd.py
-index 75f0270..2974a71 100644
---- a/glance/store/rbd.py
-+++ b/glance/store/rbd.py
-@@ -144,9 +144,10 @@ class ImageIterator(object):
-     Reads data from an RBD image, one chunk at a time.
-     """
- 
--    def __init__(self, name, store):
-+    def __init__(self, pool, name, snapshot, store):
-+        self.pool = pool or store.pool
-         self.name = name
--        self.pool = store.pool
-+        self.snapshot = snapshot
-         self.user = store.user
-         self.conf_file = store.conf_file
-         self.chunk_size = store.chunk_size
-@@ -156,7 +157,8 @@ class ImageIterator(object):
-             with rados.Rados(conffile=self.conf_file,
-                              rados_id=self.user) as conn:
-                 with conn.open_ioctx(self.pool) as ioctx:
--                    with rbd.Image(ioctx, self.name) as image:
-+                    with rbd.Image(ioctx, self.name,
-+                                   snapshot=self.snapshot) as image:
-                         img_info = image.stat()
-                         size = img_info['size']
-                         bytes_left = size
-@@ -211,7 +213,8 @@ class Store(glance.store.base.Store):
-         :raises `glance.exception.NotFound` if image does not exist
-         """
-         loc = location.store_location
--        return (ImageIterator(loc.image, self), self.get_size(location))
-+        return (ImageIterator(loc.pool, loc.image, loc.snapshot, self),
-+                self.get_size(location))
- 
-     def get_size(self, location):
-         """
-@@ -223,9 +226,12 @@ class Store(glance.store.base.Store):
-         :raises `glance.exception.NotFound` if image does not exist
-         """
-         loc = location.store_location
-+        # if there is a pool specific in the location, use it; otherwise
-+        # we fall back to the default pool specified in the config
-+        target_pool = loc.pool or self.pool
-         with rados.Rados(conffile=self.conf_file,
-                          rados_id=self.user) as conn:
--            with conn.open_ioctx(self.pool) as ioctx:
-+            with conn.open_ioctx(target_pool) as ioctx:
-                 try:
-                     with rbd.Image(ioctx, loc.image,
-                                    snapshot=loc.snapshot) as image:
-@@ -260,7 +266,7 @@ class Store(glance.store.base.Store):
-             librbd.create(ioctx, image_name, size, order, old_format=True)
-             return StoreLocation({'image': image_name})
- 
--    def _delete_image(self, image_name, snapshot_name=None):
-+    def _delete_image(self, target_pool, image_name, snapshot_name=None):
-         """
-         Delete RBD image and snapshot.
- 
-@@ -271,7 +277,7 @@ class Store(glance.store.base.Store):
-                 InUseByStore if image is in use or snapshot unprotect failed
-         """
-         with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn:
--            with conn.open_ioctx(self.pool) as ioctx:
-+            with conn.open_ioctx(target_pool) as ioctx:
-                 try:
-                     # First remove snapshot.
-                     if snapshot_name is not None:
-@@ -387,4 +393,5 @@ class Store(glance.store.base.Store):
-                 InUseByStore if image is in use or snapshot unprotect failed
-         """
-         loc = location.store_location
--        self._delete_image(loc.image, loc.snapshot)
-+        target_pool = loc.pool or self.pool
-+        self._delete_image(target_pool, loc.image, loc.snapshot)
-diff --git a/glance/tests/unit/test_rbd_store.py b/glance/tests/unit/test_rbd_store.py
-index f21cba5..828fee9 100644
---- a/glance/tests/unit/test_rbd_store.py
-+++ b/glance/tests/unit/test_rbd_store.py
-@@ -37,7 +37,8 @@ class TestStore(base.StoreClearingUnitTest):
-         self.store.chunk_size = 2
-         self.called_commands_actual = []
-         self.called_commands_expected = []
--        self.store_specs = {'image': 'fake_image',
-+        self.store_specs = {'pool': 'fake_pool',
-+                            'image': 'fake_image',
-                             'snapshot': 'fake_snapshot'}
-         self.location = StoreLocation(self.store_specs)
-         # Provide enough data to get more than one chunk iteration.
-@@ -99,7 +100,7 @@ class TestStore(base.StoreClearingUnitTest):
-             self.called_commands_actual.append('remove')
- 
-         self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove)
--        self.store._delete_image(self.location)
-+        self.store._delete_image('fake_pool', self.location)
-         self.called_commands_expected = ['remove']
- 
-     def test__delete_image_w_snap(self):
-@@ -115,7 +116,8 @@ class TestStore(base.StoreClearingUnitTest):
-         self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove)
-         self.stubs.Set(mock_rbd.Image, 'unprotect_snap', _fake_unprotect_snap)
-         self.stubs.Set(mock_rbd.Image, 'remove_snap', _fake_remove_snap)
--        self.store._delete_image(self.location, snapshot_name='snap')
-+        self.store._delete_image('fake_pool', self.location,
-+                                 snapshot_name='snap')
- 
-         self.called_commands_expected = ['unprotect_snap', 'remove_snap',
-                                          'remove']
-@@ -127,7 +129,7 @@ class TestStore(base.StoreClearingUnitTest):
- 
-         self.stubs.Set(mock_rbd.Image, 'unprotect_snap', _fake_unprotect_snap)
-         self.assertRaises(exception.NotFound, self.store._delete_image,
--                          self.location, snapshot_name='snap')
-+                          'fake_pool', self.location, snapshot_name='snap')
- 
-         self.called_commands_expected = ['unprotect_snap']
- 
-@@ -138,7 +140,7 @@ class TestStore(base.StoreClearingUnitTest):
- 
-         self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove)
-         self.assertRaises(exception.NotFound, self.store._delete_image,
--                          self.location, snapshot_name='snap')
-+                          'fake_pool', self.location, snapshot_name='snap')
- 
-         self.called_commands_expected = ['remove']
- 
diff --git a/0006-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch b/0006-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
deleted file mode 100644
index 1ee6607..0000000
--- a/0006-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
+++ /dev/null
@@ -1,668 +0,0 @@
-From 4c60b6f023e0f6cd1f59760e046885dad71c8518 Mon Sep 17 00:00:00 2001
-From: Zhi Yan Liu <zhiyanl at 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/common/store_utils.py
-	glance/location.py
-	glance/tests/functional/v1/test_copy_to_file.py
-	glance/tests/functional/v2/test_images.py
-	glance/tests/unit/test_store_image.py
-	glance/tests/unit/test_store_location.py
-	glance/tests/unit/utils.py
-	glance/tests/unit/v1/test_api.py
-
-(cherry picked from commit 4afdb017aa1ccef01482f117cb8d0736a6da38ed)
-Signed-off-by: Zhi Yan Liu <zhiyanl at cn.ibm.com>
-
-Change-Id: Id04c05b997ff93f302bafc7af8ebb27a54a84f91
-Resolves: rhbz #1174483
-Resolves: rhbz #1174484
-Upstream-Closes-Bug: #1400966
-Upstream-Kilo: https://review.openstack.org/#/c/141706/
-Upstream-Juno: https://review.openstack.org/#/c/142373/
-Upstream-Icehouse: https://review.openstack.org/#/c/142703/
-Upstream-change-Id: I72dbead3cb2dcb87f52658ddb880e26880cc229b
-Reviewed-on: https://code.engineering.redhat.com/gerrit/38836
-Reviewed-by: Eoghan Glynn <eglynn at redhat.com>
-Tested-by: Eoghan Glynn <eglynn at redhat.com>
----
- glance/api/v1/images.py                         |  27 ++--
- glance/store/__init__.py                        |  30 ++++-
- glance/tests/functional/v1/test_copy_to_file.py |  30 ++++-
- glance/tests/functional/v2/test_images.py       | 169 +++++++++++-------------
- glance/tests/unit/test_store_image.py           |   3 +-
- glance/tests/unit/test_store_location.py        |  30 ++++-
- glance/tests/unit/utils.py                      |   9 +-
- glance/tests/unit/v1/test_api.py                |  77 ++++++++++-
- 8 files changed, 252 insertions(+), 123 deletions(-)
-
-diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
-index dd6ec06..2f8afa0 100644
---- a/glance/api/v1/images.py
-+++ b/glance/api/v1/images.py
-@@ -48,6 +48,7 @@ from glance.store import get_known_schemes
- from glance.store import get_size_from_backend
- from glance.store import get_store_from_location
- from glance.store import get_store_from_scheme
-+from glance.store import validate_external_location
- 
- LOG = logging.getLogger(__name__)
- SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
-@@ -404,23 +405,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.
--        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 get_known_schemes()
--                       if scheme != 'file']
--            for scheme in schemes:
--                if pieces.scheme == scheme:
--                    return source
--            msg = _("External sourcing not supported for store %s") % source
--            LOG.debug(msg)
--            raise HTTPBadRequest(explanation=msg,
--                                 request=req,
--                                 content_type="text/plain")
-+            if 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/store/__init__.py b/glance/store/__init__.py
-index c73d3da..2ae8caa 100644
---- a/glance/store/__init__.py
-+++ b/glance/store/__init__.py
-@@ -19,6 +19,7 @@ import sys
- 
- from oslo.config import cfg
- import six
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import utils
-@@ -419,6 +420,24 @@ def set_acls(context, location_uri, public=False, read_tenants=[],
-         LOG.debug(_("Skipping store.set_acls... not implemented."))
- 
- 
-+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.
-+    """
-+    pieces = urlparse.urlparse(uri)
-+    valid_schemes = [scheme for scheme in get_known_schemes()
-+                     if scheme != 'file' and scheme != 'swift+config']
-+    return pieces.scheme in valid_schemes
-+
-+
- class ImageRepoProxy(glance.domain.proxy.Repo):
- 
-     def __init__(self, image_repo, context, store_api):
-@@ -451,22 +470,23 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
- 
- 
- def _check_location_uri(context, store_api, uri):
--    """
--    Check if an image location uri is valid.
-+    """Check if an image location is valid.
- 
-     :param context: Glance request context
-     :param store_api: store API module
-     :param uri: location's uri string
-     """
-+
-     is_ok = True
-     try:
--        size = store_api.get_size_from_backend(context, uri)
-         # NOTE(zhiyan): Some stores return zero when it catch exception
--        is_ok = size > 0
-+        is_ok = (store_api.validate_external_location(uri) and
-+                 store_api.get_size_from_backend(uri, context=context) > 0)
-     except (exception.UnknownScheme, exception.NotFound):
-         is_ok = False
-     if not is_ok:
--        raise exception.BadStoreUri(_('Invalid location: %s') % uri)
-+        reason = _('Invalid location')
-+        raise exception.BadStoreUri(message=reason)
- 
- 
- def _check_image_location(context, store_api, location):
-diff --git a/glance/tests/functional/v1/test_copy_to_file.py b/glance/tests/functional/v1/test_copy_to_file.py
-index ae2c320..2c5d833 100644
---- a/glance/tests/functional/v1/test_copy_to_file.py
-+++ b/glance/tests/functional/v1/test_copy_to_file.py
-@@ -248,9 +248,35 @@ class TestCopyToFile(functional.FunctionalTest):
-         path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-         http = httplib2.Http()
-         response, content = http.request(path, 'POST', headers=headers)
--        self.assertEqual(response.status, 400, content)
-+        self.assertEqual(400, response.status, content)
- 
--        expected = 'External sourcing not supported for store ' + copy_from
-+        expected = 'External source are not supported: \'%s\'' % copy_from
-+        msg = 'expected "%s" in "%s"' % (expected, content)
-+        self.assertTrue(expected in content, msg)
-+
-+        self.stop_servers()
-+
-+    @skip_if_disabled
-+    def test_copy_from_swift_config(self):
-+        """
-+        Ensure we can't copy from swift+config
-+        """
-+        self.cleanup()
-+
-+        self.start_servers(**self.__dict__.copy())
-+
-+        # POST /images with public image copied from file (to file)
-+        headers = {'X-Image-Meta-Name': 'copied',
-+                   'X-Image-Meta-disk_format': 'raw',
-+                   'X-Image-Meta-container_format': 'ovf',
-+                   'X-Image-Meta-Is-Public': 'True',
-+                   'X-Glance-API-Copy-From': 'swift+config://xxx'}
-+        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-+        http = httplib2.Http()
-+        response, content = http.request(path, 'POST', headers=headers)
-+        self.assertEqual(400, response.status, content)
-+
-+        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 4247434..1bb0e56 100644
---- a/glance/tests/functional/v2/test_images.py
-+++ b/glance/tests/functional/v2/test_images.py
-@@ -15,7 +15,6 @@
- 
- import os
- import signal
--import tempfile
- import uuid
- 
- import requests
-@@ -38,6 +37,19 @@ class TestImages(functional.FunctionalTest):
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
-         self.start_servers(**self.__dict__.copy())
-+        for i in range(3):
-+            ret = test_http.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)
-@@ -282,21 +294,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)
-@@ -1811,17 +1817,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)
- 
-@@ -1830,7 +1833,51 @@ 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(10, image['size'])
-+
-+    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.assertIsNone(image['size'])
-+        self.assertIsNone(image['virtual_size'])
-+
-+        # 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):
-+    def setUp(self):
-+        super(TestImagesWithRegistry, self).setUp()
-+        self.api_server.data_api = (
-+            'glance.tests.functional.v2.registry_data_api')
-+        self.registry_server.deployment_flavor = 'trusted-auth'
-+>>>>>>> 4afdb01... To prevent client use v2 patch api to handle file and swift location
- 
- 
- class TestImageDirectURLVisibility(functional.FunctionalTest):
-@@ -2040,16 +2087,17 @@ 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 = test_http.http_server("foo_image_id", "foo_image")
--        self.http_server_pid, self.http_port = ret
-+        for i in range(3):
-+            ret = test_http.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()
- 
-@@ -2098,73 +2146,14 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         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'}}]
--        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
-+        # 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}]
-@@ -2172,8 +2161,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 424915b..9d6cc4e 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -16,6 +16,7 @@ import mox
- 
- from glance.common import exception
- import glance.store
-+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
- 
-@@ -731,7 +732,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 df8d5d7..a19a33a 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -488,11 +488,12 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-                               ctx,
-                               store)
- 
-+    class FakeImageProxy():
-+        size = None
-+        context = None
-+        store_api = mock.Mock()
-+
-     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(context, uri):
-             return 1
-@@ -504,14 +505,31 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-             loc2 = {'url': 'file:///fake2.img.tar.gz', 'metadata': {}}
- 
-             # Test for insert location
--            image1 = FakeImageProxy()
-+            image1 = TestStoreLocation.FakeImageProxy()
-             locations = glance.store.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.store.StoreLocations(image2, [loc1])
-             locations[0] = loc2
-             self.assertTrue(loc2 in 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.store.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.store.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 1c4e16a..e0dfc43 100644
---- a/glance/tests/unit/utils.py
-+++ b/glance/tests/unit/utils.py
-@@ -14,9 +14,9 @@
- #    under the License.
- 
- import urllib
--import urlparse
- 
- from oslo.config import cfg
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import wsgi
-@@ -113,7 +113,6 @@ class FakeDB(object):
-     def __getattr__(self, key):
-         return getattr(simple_db, key)
- 
--
- class FakeStoreAPI(object):
-     def __init__(self, store_metadata=None):
-         self.data = {
-@@ -188,6 +187,12 @@ class FakeStoreAPI(object):
-     def check_location_metadata(self, val, key=''):
-         glance.store.check_location_metadata(val)
- 
-+    def validate_external_location(self, uri):
-+        if uri and urlparse.urlparse(uri).scheme:
-+            return glance.store.validate_external_location(uri)
-+        else:
-+            return True
-+
- 
- class FakePolicyEnforcer(object):
-     def __init__(self, *_args, **kwargs):
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index 5618cb0..9856487 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -379,7 +379,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
--        self.assertTrue('External sourcing not supported' in res.body)
-+        self.assertIn('External source are not supported', res.body)
- 
-     def test_create_with_location_bad_store_uri(self):
-         fixture_headers = {
-@@ -962,6 +962,53 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-             res = req.get_response(self.api)
-             self.assertEqual(res.status_int, 409)
- 
-+    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',
-+                           'x-image-meta-location': 'http://a/b/c.tar.gz',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F',
-+                           'x-image-meta-size': '1'}
-+
-+        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_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',
-@@ -978,6 +1025,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": '@'}
diff --git a/0007-Revert-To-prevent-client-use-v2-patch-api-to-handle-.patch b/0007-Revert-To-prevent-client-use-v2-patch-api-to-handle-.patch
deleted file mode 100644
index 5726722..0000000
--- a/0007-Revert-To-prevent-client-use-v2-patch-api-to-handle-.patch
+++ /dev/null
@@ -1,637 +0,0 @@
-From ebdddcd75040467447ec27f6ad28f4dfd757206a Mon Sep 17 00:00:00 2001
-From: Lon Hohberger <lhh at redhat.com>
-Date: Tue, 23 Dec 2014 13:42:45 -0500
-Subject: [PATCH] Revert "To prevent client use v2 patch api to handle file and
- swift location"
-
-This reverts commit 8b22786cd7d5e50235389548cf5e9f15aa0f06de.
-
-Change-Id: Ide10810280aa0f37cf45e9aeee60caa8829b5003
-Reviewed-on: https://code.engineering.redhat.com/gerrit/39076
-Reviewed-by: Lon Hohberger <lhh at redhat.com>
-Tested-by: Lon Hohberger <lhh at redhat.com>
----
- glance/api/v1/images.py                         |  27 ++--
- glance/store/__init__.py                        |  30 +----
- glance/tests/functional/v1/test_copy_to_file.py |  30 +----
- glance/tests/functional/v2/test_images.py       | 169 +++++++++++++-----------
- glance/tests/unit/test_store_image.py           |   3 +-
- glance/tests/unit/test_store_location.py        |  30 +----
- glance/tests/unit/utils.py                      |   9 +-
- glance/tests/unit/v1/test_api.py                |  77 +----------
- 8 files changed, 123 insertions(+), 252 deletions(-)
-
-diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
-index 2f8afa0..dd6ec06 100644
---- a/glance/api/v1/images.py
-+++ b/glance/api/v1/images.py
-@@ -48,7 +48,6 @@ from glance.store import get_known_schemes
- from glance.store import get_size_from_backend
- from glance.store import get_store_from_location
- from glance.store import get_store_from_scheme
--from glance.store import validate_external_location
- 
- LOG = logging.getLogger(__name__)
- SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
-@@ -405,19 +404,23 @@ class Controller(controller.BaseController):
-     @staticmethod
-     def _validate_source(source, req):
-         """
--        To validate if external sources (as specified via the location
--        or copy-from headers) are supported. Otherwise we reject
--        with 400 "Bad Request".
-+        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.
-+        If the above constraint is violated, we reject with 400 "Bad Request".
-         """
-         if source:
--            if 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")
-+            pieces = urlparse.urlparse(source)
-+            schemes = [scheme for scheme in get_known_schemes()
-+                       if scheme != 'file']
-+            for scheme in schemes:
-+                if pieces.scheme == scheme:
-+                    return source
-+            msg = _("External sourcing not supported for store %s") % source
-+            LOG.debug(msg)
-+            raise HTTPBadRequest(explanation=msg,
-+                                 request=req,
-+                                 content_type="text/plain")
- 
-     @staticmethod
-     def _copy_from(req):
-diff --git a/glance/store/__init__.py b/glance/store/__init__.py
-index 2ae8caa..c73d3da 100644
---- a/glance/store/__init__.py
-+++ b/glance/store/__init__.py
-@@ -19,7 +19,6 @@ import sys
- 
- from oslo.config import cfg
- import six
--import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import utils
-@@ -420,24 +419,6 @@ def set_acls(context, location_uri, public=False, read_tenants=[],
-         LOG.debug(_("Skipping store.set_acls... not implemented."))
- 
- 
--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.
--    """
--    pieces = urlparse.urlparse(uri)
--    valid_schemes = [scheme for scheme in get_known_schemes()
--                     if scheme != 'file' and scheme != 'swift+config']
--    return pieces.scheme in valid_schemes
--
--
- class ImageRepoProxy(glance.domain.proxy.Repo):
- 
-     def __init__(self, image_repo, context, store_api):
-@@ -470,23 +451,22 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
- 
- 
- def _check_location_uri(context, store_api, uri):
--    """Check if an image location is valid.
-+    """
-+    Check if an image location uri is valid.
- 
-     :param context: Glance request context
-     :param store_api: store API module
-     :param uri: location's uri string
-     """
--
-     is_ok = True
-     try:
-+        size = store_api.get_size_from_backend(context, uri)
-         # NOTE(zhiyan): Some stores return zero when it catch exception
--        is_ok = (store_api.validate_external_location(uri) and
--                 store_api.get_size_from_backend(uri, context=context) > 0)
-+        is_ok = size > 0
-     except (exception.UnknownScheme, exception.NotFound):
-         is_ok = False
-     if not is_ok:
--        reason = _('Invalid location')
--        raise exception.BadStoreUri(message=reason)
-+        raise exception.BadStoreUri(_('Invalid location: %s') % uri)
- 
- 
- def _check_image_location(context, store_api, location):
-diff --git a/glance/tests/functional/v1/test_copy_to_file.py b/glance/tests/functional/v1/test_copy_to_file.py
-index 2c5d833..ae2c320 100644
---- a/glance/tests/functional/v1/test_copy_to_file.py
-+++ b/glance/tests/functional/v1/test_copy_to_file.py
-@@ -248,35 +248,9 @@ class TestCopyToFile(functional.FunctionalTest):
-         path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-         http = httplib2.Http()
-         response, content = http.request(path, 'POST', headers=headers)
--        self.assertEqual(400, response.status, content)
-+        self.assertEqual(response.status, 400, content)
- 
--        expected = 'External source are not supported: \'%s\'' % copy_from
--        msg = 'expected "%s" in "%s"' % (expected, content)
--        self.assertTrue(expected in content, msg)
--
--        self.stop_servers()
--
--    @skip_if_disabled
--    def test_copy_from_swift_config(self):
--        """
--        Ensure we can't copy from swift+config
--        """
--        self.cleanup()
--
--        self.start_servers(**self.__dict__.copy())
--
--        # POST /images with public image copied from file (to file)
--        headers = {'X-Image-Meta-Name': 'copied',
--                   'X-Image-Meta-disk_format': 'raw',
--                   'X-Image-Meta-container_format': 'ovf',
--                   'X-Image-Meta-Is-Public': 'True',
--                   'X-Glance-API-Copy-From': 'swift+config://xxx'}
--        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
--        http = httplib2.Http()
--        response, content = http.request(path, 'POST', headers=headers)
--        self.assertEqual(400, response.status, content)
--
--        expected = 'External source are not supported: \'swift+config://xxx\''
-+        expected = 'External sourcing not supported for store ' + copy_from
-         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 1bb0e56..4247434 100644
---- a/glance/tests/functional/v2/test_images.py
-+++ b/glance/tests/functional/v2/test_images.py
-@@ -15,6 +15,7 @@
- 
- import os
- import signal
-+import tempfile
- import uuid
- 
- import requests
-@@ -37,19 +38,6 @@ class TestImages(functional.FunctionalTest):
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
-         self.start_servers(**self.__dict__.copy())
--        for i in range(3):
--            ret = test_http.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)
-@@ -294,15 +282,21 @@ 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': url, 'metadata': {}},
-+                            'value': {'url': 'file://{0}'.format(
-+                                os.path.join(self.test_dir,
-+                                             'fake_image_%i' % i)),
-+                                      'metadata': {}},
-                             })
- 
-         data = jsonutils.dumps(changes)
-@@ -1817,14 +1811,17 @@ 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': url, 'metadata': {}}]
--                                 }])
-+                                 'value': [{'url': 'file://' + file_path,
-+                                            'metadata': {}}]}])
-         response = requests.patch(path, headers=headers, data=data)
-         self.assertEqual(200, response.status_code, response.text)
- 
-@@ -1833,51 +1830,7 @@ class TestImages(functional.FunctionalTest):
-         response = requests.get(path, headers=headers)
-         self.assertEqual(200, response.status_code)
-         image = jsonutils.loads(response.text)
--        self.assertEqual(10, image['size'])
--
--    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.assertIsNone(image['size'])
--        self.assertIsNone(image['virtual_size'])
--
--        # 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):
--    def setUp(self):
--        super(TestImagesWithRegistry, self).setUp()
--        self.api_server.data_api = (
--            'glance.tests.functional.v2.registry_data_api')
--        self.registry_server.deployment_flavor = 'trusted-auth'
-->>>>>>> 4afdb01... To prevent client use v2 patch api to handle file and swift location
-+        self.assertEqual(image['size'], 6)
- 
- 
- class TestImageDirectURLVisibility(functional.FunctionalTest):
-@@ -2087,17 +2040,16 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         super(TestImageLocationSelectionStrategy, self).setUp()
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
--        for i in range(3):
--            ret = test_http.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])
-+        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 = test_http.http_server("foo_image_id", "foo_image")
-+        self.http_server_pid, self.http_port = ret
- 
-     def tearDown(self):
--        for i in range(3):
--            pid = getattr(self, 'http_server%d_pid' % i, None)
--            if pid:
--                os.kill(pid, signal.SIGKILL)
-+        if self.http_server_pid is not None:
-+            os.kill(self.http_server_pid, signal.SIGKILL)
- 
-         super(TestImageLocationSelectionStrategy, self).tearDown()
- 
-@@ -2146,14 +2098,73 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         self.assertTrue('locations' in image)
-         self.assertTrue(image["locations"] == [])
- 
--        # Update image locations via PATCH
-+       # 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'}}]
-+        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': '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': {}}]
-+        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}]
-@@ -2161,6 +2172,8 @@ 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 9d6cc4e..424915b 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -16,7 +16,6 @@ import mox
- 
- from glance.common import exception
- import glance.store
--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
- 
-@@ -732,7 +731,7 @@ class TestStoreImageRepo(utils.BaseTestCase):
-         self.assertEqual(acls['read'], [TENANT2])
- 
- 
--class TestImageFactory(unit_test_base.StoreClearingUnitTest):
-+class TestImageFactory(utils.BaseTestCase):
- 
-     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 a19a33a..df8d5d7 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -488,12 +488,11 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-                               ctx,
-                               store)
- 
--    class FakeImageProxy():
--        size = None
--        context = None
--        store_api = mock.Mock()
--
-     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(context, uri):
-             return 1
-@@ -505,31 +504,14 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-             loc2 = {'url': 'file:///fake2.img.tar.gz', 'metadata': {}}
- 
-             # Test for insert location
--            image1 = TestStoreLocation.FakeImageProxy()
-+            image1 = FakeImageProxy()
-             locations = glance.store.StoreLocations(image1, [])
-             locations.insert(0, loc2)
-             self.assertEqual(image1.size, 1)
- 
-             # Test for set_attr of _locations_proxy
--            image2 = TestStoreLocation.FakeImageProxy()
-+            image2 = FakeImageProxy()
-             locations = glance.store.StoreLocations(image2, [loc1])
-             locations[0] = loc2
-             self.assertTrue(loc2 in 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.store.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.store.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 e0dfc43..1c4e16a 100644
---- a/glance/tests/unit/utils.py
-+++ b/glance/tests/unit/utils.py
-@@ -14,9 +14,9 @@
- #    under the License.
- 
- import urllib
-+import urlparse
- 
- from oslo.config import cfg
--import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import wsgi
-@@ -113,6 +113,7 @@ class FakeDB(object):
-     def __getattr__(self, key):
-         return getattr(simple_db, key)
- 
-+
- class FakeStoreAPI(object):
-     def __init__(self, store_metadata=None):
-         self.data = {
-@@ -187,12 +188,6 @@ class FakeStoreAPI(object):
-     def check_location_metadata(self, val, key=''):
-         glance.store.check_location_metadata(val)
- 
--    def validate_external_location(self, uri):
--        if uri and urlparse.urlparse(uri).scheme:
--            return glance.store.validate_external_location(uri)
--        else:
--            return True
--
- 
- class FakePolicyEnforcer(object):
-     def __init__(self, *_args, **kwargs):
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index 9856487..5618cb0 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -379,7 +379,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
--        self.assertIn('External source are not supported', res.body)
-+        self.assertTrue('External sourcing not supported' in res.body)
- 
-     def test_create_with_location_bad_store_uri(self):
-         fixture_headers = {
-@@ -962,53 +962,6 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-             res = req.get_response(self.api)
-             self.assertEqual(res.status_int, 409)
- 
--    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',
--                           'x-image-meta-location': 'http://a/b/c.tar.gz',
--                           'x-image-meta-container-format': 'ovf',
--                           'x-image-meta-name': 'fake image #F',
--                           'x-image-meta-size': '1'}
--
--        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_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',
-@@ -1025,34 +978,6 @@ 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": '@'}
diff --git a/0008-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch b/0008-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
deleted file mode 100644
index d80fddc..0000000
--- a/0008-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
+++ /dev/null
@@ -1,670 +0,0 @@
-From 0b637884baaea4cefc46dc59314d54c57f567921 Mon Sep 17 00:00:00 2001
-From: Zhi Yan Liu <zhiyanl at 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/common/store_utils.py
-	glance/location.py
-	glance/tests/functional/v1/test_copy_to_file.py
-	glance/tests/functional/v2/test_images.py
-	glance/tests/unit/test_store_image.py
-	glance/tests/unit/test_store_location.py
-	glance/tests/unit/utils.py
-	glance/tests/unit/v1/test_api.py
-
-(cherry picked from commit 4afdb017aa1ccef01482f117cb8d0736a6da38ed)
-Signed-off-by: Zhi Yan Liu <zhiyanl at cn.ibm.com>
-
-Change-Id: I5a594731f18eb4dd4fba56de766e5c1c0e0cc442
-Resolves: rhbz #1174483
-Resolves: rhbz #1174484
-Upstream-Closes-Bug: #1400966
-Upstream-Kilo: https://review.openstack.org/#/c/141706/
-Upstream-Juno: https://review.openstack.org/#/c/142373/
-Upstream-Icehouse: https://review.openstack.org/#/c/142703/
-Upstream-change-Id: I72dbead3cb2dcb87f52658ddb880e26880cc229b
-Reviewed-on: https://code.engineering.redhat.com/gerrit/38836
-Reviewed-by: Eoghan Glynn <eglynn at redhat.com>
-Tested-by: Eoghan Glynn <eglynn at redhat.com>
-Reviewed-on: https://code.engineering.redhat.com/gerrit/39077
-Reviewed-by: Lon Hohberger <lhh at redhat.com>
-Tested-by: Lon Hohberger <lhh at redhat.com>
----
- glance/api/v1/images.py                         |  27 ++--
- glance/store/__init__.py                        |  30 ++++-
- glance/tests/functional/v1/test_copy_to_file.py |  30 ++++-
- glance/tests/functional/v2/test_images.py       | 168 +++++++++++-------------
- glance/tests/unit/test_store_image.py           |   3 +-
- glance/tests/unit/test_store_location.py        |  30 ++++-
- glance/tests/unit/utils.py                      |   9 +-
- glance/tests/unit/v1/test_api.py                |  77 ++++++++++-
- 8 files changed, 251 insertions(+), 123 deletions(-)
-
-diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
-index dd6ec06..2f8afa0 100644
---- a/glance/api/v1/images.py
-+++ b/glance/api/v1/images.py
-@@ -48,6 +48,7 @@ from glance.store import get_known_schemes
- from glance.store import get_size_from_backend
- from glance.store import get_store_from_location
- from glance.store import get_store_from_scheme
-+from glance.store import validate_external_location
- 
- LOG = logging.getLogger(__name__)
- SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS
-@@ -404,23 +405,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.
--        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 get_known_schemes()
--                       if scheme != 'file']
--            for scheme in schemes:
--                if pieces.scheme == scheme:
--                    return source
--            msg = _("External sourcing not supported for store %s") % source
--            LOG.debug(msg)
--            raise HTTPBadRequest(explanation=msg,
--                                 request=req,
--                                 content_type="text/plain")
-+            if 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/store/__init__.py b/glance/store/__init__.py
-index c73d3da..2ae8caa 100644
---- a/glance/store/__init__.py
-+++ b/glance/store/__init__.py
-@@ -19,6 +19,7 @@ import sys
- 
- from oslo.config import cfg
- import six
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import utils
-@@ -419,6 +420,24 @@ def set_acls(context, location_uri, public=False, read_tenants=[],
-         LOG.debug(_("Skipping store.set_acls... not implemented."))
- 
- 
-+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.
-+    """
-+    pieces = urlparse.urlparse(uri)
-+    valid_schemes = [scheme for scheme in get_known_schemes()
-+                     if scheme != 'file' and scheme != 'swift+config']
-+    return pieces.scheme in valid_schemes
-+
-+
- class ImageRepoProxy(glance.domain.proxy.Repo):
- 
-     def __init__(self, image_repo, context, store_api):
-@@ -451,22 +470,23 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
- 
- 
- def _check_location_uri(context, store_api, uri):
--    """
--    Check if an image location uri is valid.
-+    """Check if an image location is valid.
- 
-     :param context: Glance request context
-     :param store_api: store API module
-     :param uri: location's uri string
-     """
-+
-     is_ok = True
-     try:
--        size = store_api.get_size_from_backend(context, uri)
-         # NOTE(zhiyan): Some stores return zero when it catch exception
--        is_ok = size > 0
-+        is_ok = (store_api.validate_external_location(uri) and
-+                 store_api.get_size_from_backend(uri, context=context) > 0)
-     except (exception.UnknownScheme, exception.NotFound):
-         is_ok = False
-     if not is_ok:
--        raise exception.BadStoreUri(_('Invalid location: %s') % uri)
-+        reason = _('Invalid location')
-+        raise exception.BadStoreUri(message=reason)
- 
- 
- def _check_image_location(context, store_api, location):
-diff --git a/glance/tests/functional/v1/test_copy_to_file.py b/glance/tests/functional/v1/test_copy_to_file.py
-index ae2c320..2c5d833 100644
---- a/glance/tests/functional/v1/test_copy_to_file.py
-+++ b/glance/tests/functional/v1/test_copy_to_file.py
-@@ -248,9 +248,35 @@ class TestCopyToFile(functional.FunctionalTest):
-         path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-         http = httplib2.Http()
-         response, content = http.request(path, 'POST', headers=headers)
--        self.assertEqual(response.status, 400, content)
-+        self.assertEqual(400, response.status, content)
- 
--        expected = 'External sourcing not supported for store ' + copy_from
-+        expected = 'External source are not supported: \'%s\'' % copy_from
-+        msg = 'expected "%s" in "%s"' % (expected, content)
-+        self.assertTrue(expected in content, msg)
-+
-+        self.stop_servers()
-+
-+    @skip_if_disabled
-+    def test_copy_from_swift_config(self):
-+        """
-+        Ensure we can't copy from swift+config
-+        """
-+        self.cleanup()
-+
-+        self.start_servers(**self.__dict__.copy())
-+
-+        # POST /images with public image copied from file (to file)
-+        headers = {'X-Image-Meta-Name': 'copied',
-+                   'X-Image-Meta-disk_format': 'raw',
-+                   'X-Image-Meta-container_format': 'ovf',
-+                   'X-Image-Meta-Is-Public': 'True',
-+                   'X-Glance-API-Copy-From': 'swift+config://xxx'}
-+        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
-+        http = httplib2.Http()
-+        response, content = http.request(path, 'POST', headers=headers)
-+        self.assertEqual(400, response.status, content)
-+
-+        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 4247434..36c986e 100644
---- a/glance/tests/functional/v2/test_images.py
-+++ b/glance/tests/functional/v2/test_images.py
-@@ -15,7 +15,6 @@
- 
- import os
- import signal
--import tempfile
- import uuid
- 
- import requests
-@@ -38,6 +37,19 @@ class TestImages(functional.FunctionalTest):
-         self.cleanup()
-         self.api_server.deployment_flavor = 'noauth'
-         self.start_servers(**self.__dict__.copy())
-+        for i in range(3):
-+            ret = test_http.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)
-@@ -282,21 +294,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)
-@@ -1811,17 +1817,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)
- 
-@@ -1830,7 +1833,50 @@ 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(10, image['size'])
-+
-+    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.assertIsNone(image['size'])
-+        self.assertIsNone(image['virtual_size'])
-+
-+        # 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):
-+    def setUp(self):
-+        super(TestImagesWithRegistry, self).setUp()
-+        self.api_server.data_api = (
-+            'glance.tests.functional.v2.registry_data_api')
-+        self.registry_server.deployment_flavor = 'trusted-auth'
- 
- 
- class TestImageDirectURLVisibility(functional.FunctionalTest):
-@@ -2040,16 +2086,17 @@ 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 = test_http.http_server("foo_image_id", "foo_image")
--        self.http_server_pid, self.http_port = ret
-+        for i in range(3):
-+            ret = test_http.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()
- 
-@@ -2098,73 +2145,14 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
-         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'}}]
--        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
-+        # 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}]
-@@ -2172,8 +2160,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 424915b..9d6cc4e 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -16,6 +16,7 @@ import mox
- 
- from glance.common import exception
- import glance.store
-+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
- 
-@@ -731,7 +732,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 df8d5d7..a19a33a 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -488,11 +488,12 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-                               ctx,
-                               store)
- 
-+    class FakeImageProxy():
-+        size = None
-+        context = None
-+        store_api = mock.Mock()
-+
-     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(context, uri):
-             return 1
-@@ -504,14 +505,31 @@ class TestStoreLocation(base.StoreClearingUnitTest):
-             loc2 = {'url': 'file:///fake2.img.tar.gz', 'metadata': {}}
- 
-             # Test for insert location
--            image1 = FakeImageProxy()
-+            image1 = TestStoreLocation.FakeImageProxy()
-             locations = glance.store.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.store.StoreLocations(image2, [loc1])
-             locations[0] = loc2
-             self.assertTrue(loc2 in 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.store.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.store.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 1c4e16a..e0dfc43 100644
---- a/glance/tests/unit/utils.py
-+++ b/glance/tests/unit/utils.py
-@@ -14,9 +14,9 @@
- #    under the License.
- 
- import urllib
--import urlparse
- 
- from oslo.config import cfg
-+import six.moves.urllib.parse as urlparse
- 
- from glance.common import exception
- from glance.common import wsgi
-@@ -113,7 +113,6 @@ class FakeDB(object):
-     def __getattr__(self, key):
-         return getattr(simple_db, key)
- 
--
- class FakeStoreAPI(object):
-     def __init__(self, store_metadata=None):
-         self.data = {
-@@ -188,6 +187,12 @@ class FakeStoreAPI(object):
-     def check_location_metadata(self, val, key=''):
-         glance.store.check_location_metadata(val)
- 
-+    def validate_external_location(self, uri):
-+        if uri and urlparse.urlparse(uri).scheme:
-+            return glance.store.validate_external_location(uri)
-+        else:
-+            return True
-+
- 
- class FakePolicyEnforcer(object):
-     def __init__(self, *_args, **kwargs):
-diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
-index 5618cb0..9856487 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -379,7 +379,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
- 
-         res = req.get_response(self.api)
-         self.assertEqual(res.status_int, 400)
--        self.assertTrue('External sourcing not supported' in res.body)
-+        self.assertIn('External source are not supported', res.body)
- 
-     def test_create_with_location_bad_store_uri(self):
-         fixture_headers = {
-@@ -962,6 +962,53 @@ class TestGlanceAPI(base.IsolatedUnitTest):
-             res = req.get_response(self.api)
-             self.assertEqual(res.status_int, 409)
- 
-+    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',
-+                           'x-image-meta-location': 'http://a/b/c.tar.gz',
-+                           'x-image-meta-container-format': 'ovf',
-+                           'x-image-meta-name': 'fake image #F',
-+                           'x-image-meta-size': '1'}
-+
-+        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_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',
-@@ -978,6 +1025,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": '@'}
diff --git a/0009-Prevent-file-swift-config-and-filesystem-schemes.patch b/0009-Prevent-file-swift-config-and-filesystem-schemes.patch
deleted file mode 100644
index 4b19967..0000000
--- a/0009-Prevent-file-swift-config-and-filesystem-schemes.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From 0e47acd351d0a4793e0cce08b1958ad6129bd3fd Mon Sep 17 00:00:00 2001
-From: Grant Murphy <grant.murphy at 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.
-
-(cherry picked from commit 5191ed1879c5fd5b2694f922bcedec232f461088)
-
-Conflicts:
-	glance/common/store_utils.py
-
-Change-Id: Ib92f464331b7bab9ca49f164102313d8652dc723
-Resolves: rhbz #1174483
-Resolves: rhbz #1174484
-Upstream-Closes-Bug: #1408663
-Upstream-Kilo: https://review.openstack.org/#/c/145640/
-Upstream-Juno: https://review.openstack.org/#/c/145916/
-Upstream-Icehouse: https://review.openstack.org/#/c/145974/
-Upstream-change-Id: I02cd099a8634b9c7e3cf8f172bcbd33f8edcbc83
-Reviewed-on: https://code.engineering.redhat.com/gerrit/39653
-Reviewed-by: Jon Bernard <jobernar at redhat.com>
-Reviewed-by: Flavio Percoco <fpercoco at redhat.com>
-Tested-by: Flavio Percoco <fpercoco at redhat.com>
----
- glance/store/__init__.py                 | 11 +++++++----
- glance/tests/unit/test_store_location.py |  3 +++
- glance/tests/unit/v1/test_api.py         | 32 ++++++++++++--------------------
- 3 files changed, 22 insertions(+), 24 deletions(-)
-
-diff --git a/glance/store/__init__.py b/glance/store/__init__.py
-index 2ae8caa..d158f97 100644
---- a/glance/store/__init__.py
-+++ b/glance/store/__init__.py
-@@ -74,6 +74,8 @@ _ALL_STORES = [
-     'glance.store.gridfs.Store',
- ]
- 
-+RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
-+
- 
- class BackendException(Exception):
-     pass
-@@ -432,10 +434,11 @@ def validate_external_location(uri):
-     :param uri: The URI of external image location.
-     :return: Whether given URI of external image location are OK.
-     """
--    pieces = urlparse.urlparse(uri)
--    valid_schemes = [scheme for scheme in 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 get_known_schemes() and
-+            scheme not in RESTRICTED_URI_SCHEMAS)
- 
- 
- class ImageRepoProxy(glance.domain.proxy.Repo):
-diff --git a/glance/tests/unit/test_store_location.py b/glance/tests/unit/test_store_location.py
-index a19a33a..d64b783 100644
---- a/glance/tests/unit/test_store_location.py
-+++ b/glance/tests/unit/test_store_location.py
-@@ -521,12 +521,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.store.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 9856487..33af257 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -1027,31 +1027,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)
--
--        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'}
-+        schemas = ["file:///etc/passwd",
-+                   "swift+config:///xxx",
-+                   "filesystem:///etc/passwd"]
- 
--        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": '@',
diff --git a/0010-Cleanup-chunks-for-deleted-image-that-was-saving.patch b/0010-Cleanup-chunks-for-deleted-image-that-was-saving.patch
deleted file mode 100644
index 51817e3..0000000
--- a/0010-Cleanup-chunks-for-deleted-image-that-was-saving.patch
+++ /dev/null
@@ -1,500 +0,0 @@
-From cbec3b5c4e42ae61d14dda0aaae93c36ba5bfde5 Mon Sep 17 00:00:00 2001
-From: Zhi Yan Liu <zhiyanl at 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/quota/__init__.py
-        glance/tests/unit/test_domain_proxy.py
-        glance/tests/unit/test_quota.py
-        glance/tests/unit/v1/test_api.py
-
-Signed-off-by: Zhi Yan Liu <zhiyanl at cn.ibm.com>
-(cherry picked from commit 0dc8fbb3479a53c5bba8475d14f4c7206904c5ea)
-
-Change-Id: I47229b366c25367ec1bd48aec684e0880f3dfe60
-(cherry picked from commit f1260cc771ee068651aa62b972bef49d9af81eb0)
----
- glance/api/authorization.py                      |  4 +-
- glance/api/policy.py                             |  8 ++--
- glance/api/v1/upload_utils.py                    | 23 +++++++----
- glance/api/v2/image_data.py                      | 18 +++++----
- glance/db/__init__.py                            |  7 ++--
- glance/domain/proxy.py                           |  4 +-
- glance/notifier.py                               |  4 +-
- glance/quota/__init__.py                         |  4 +-
- glance/store/__init__.py                         |  2 +-
- glance/tests/unit/test_domain_proxy.py           | 14 ++++---
- glance/tests/unit/test_policy.py                 |  2 +-
- glance/tests/unit/test_quota.py                  |  6 ++-
- glance/tests/unit/test_store_image.py            |  2 +-
- glance/tests/unit/v1/test_api.py                 | 51 +++++++++++-------------
- glance/tests/unit/v2/test_image_data_resource.py | 24 ++++++-----
- 15 files changed, 95 insertions(+), 78 deletions(-)
-
-diff --git a/glance/api/authorization.py b/glance/api/authorization.py
-index 3a1045a..0b66af6 100644
---- a/glance/api/authorization.py
-+++ b/glance/api/authorization.py
-@@ -147,10 +147,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 22a561d..1838395 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', {})
-@@ -283,9 +283,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 8fcf766..f7e980b 100644
---- a/glance/api/v1/upload_utils.py
-+++ b/glance/api/v1/upload_utils.py
-@@ -146,14 +146,21 @@ 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:
--            msg = _("Image %s could not be found after upload. The image may "
--                    "have been deleted during the upload.") % image_id
-+            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 = _("Image %s could not be found after upload. The image may"
-+                    " have been deleted during the upload.") % image_id
-             LOG.info(msg)
- 
-             # NOTE(jculp): we need to clean up the datastore if an image
-diff --git a/glance/api/v2/image_data.py b/glance/api/v2/image_data.py
-index 1bff3d7..6253608 100644
---- a/glance/api/v2/image_data.py
-+++ b/glance/api/v2/image_data.py
-@@ -22,6 +22,7 @@ from glance.common import wsgi
- import glance.db
- import glance.gateway
- import glance.notifier
-+from glance.openstack.common import excutils
- import glance.openstack.common.log as logging
- import glance.store
- 
-@@ -66,13 +67,12 @@ class ImageDataController(object):
-             try:
-                 image_repo.save(image)
-                 image.set_data(data, size)
--                image_repo.save(image)
--            except exception.NotFound 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") %
--                       {'id': image_id,
--                        'error': e})
-+                image_repo.save(image, from_state='saving')
-+            except (exception.NotFound, exception.Conflict):
-+                msg = (_("Image %s could not be found after upload. "
-+                         "The image may have been deleted during the "
-+                         "upload, cleaning up the chunks uploaded.") %
-+                       image_id)
-                 LOG.warn(msg)
-                 # NOTE(sridevi): Cleaning up the uploaded chunks.
-                 try:
-@@ -131,6 +131,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(_("Failed to upload image data due to HTTP error"))
-+
-         except webob.exc.HTTPError as e:
-             LOG.error(_("Failed to upload image data due to HTTP error"))
-             self._restore(image_repo, image)
-diff --git a/glance/db/__init__.py b/glance/db/__init__.py
-index a59447d..379cf6f 100644
---- a/glance/db/__init__.py
-+++ b/glance/db/__init__.py
-@@ -162,7 +162,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
-@@ -170,7 +170,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)
-@@ -263,7 +264,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 89f138c..b27b448 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/notifier.py b/glance/notifier.py
-index 1eaadbf..1d27c07 100644
---- a/glance/notifier.py
-+++ b/glance/notifier.py
-@@ -178,8 +178,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 0fcc792..a8babe1 100644
---- a/glance/quota/__init__.py
-+++ b/glance/quota/__init__.py
-@@ -96,9 +96,9 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-             raise exception.ImagePropertyLimitExceeded(attempted=attempted,
-                                                        maximum=maximum)
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         self._enforce_image_property_quota(image)
--        super(ImageRepoProxy, self).save(image)
-+        return super(ImageRepoProxy, self).save(image, from_state=from_state)
- 
-     def add(self, image):
-         self._enforce_image_property_quota(image)
-diff --git a/glance/store/__init__.py b/glance/store/__init__.py
-index d158f97..25739ff 100644
---- a/glance/store/__init__.py
-+++ b/glance/store/__init__.py
-@@ -466,7 +466,7 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
-         self._set_acls(image)
-         return result
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         result = super(ImageRepoProxy, self).save(image)
-         self._set_acls(image)
-         return result
-diff --git a/glance/tests/unit/test_domain_proxy.py b/glance/tests/unit/test_domain_proxy.py
-index 86684fc..4260b2f 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.assertTrue(proxy_result is None)
-@@ -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 6306f1b..0b51e8e 100644
---- a/glance/tests/unit/test_policy.py
-+++ b/glance/tests/unit/test_policy.py
-@@ -69,7 +69,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 504cefd..a66b0ac 100644
---- a/glance/tests/unit/test_quota.py
-+++ b/glance/tests/unit/test_quota.py
-@@ -290,7 +290,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)
-@@ -306,7 +307,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)
-diff --git a/glance/tests/unit/test_store_image.py b/glance/tests/unit/test_store_image.py
-index 9d6cc4e..8858e5d 100644
---- a/glance/tests/unit/test_store_image.py
-+++ b/glance/tests/unit/test_store_image.py
-@@ -34,7 +34,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 33af257..8034682 100644
---- a/glance/tests/unit/v1/test_api.py
-+++ b/glance/tests/unit/v1/test_api.py
-@@ -1650,8 +1650,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',
-@@ -1685,30 +1684,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.assertEqual(200, res.status_int)
- 
-                 self.stubs.Set(registry, 'update_image_metadata',
-                                orig_update_image_metadata)
-@@ -1718,20 +1705,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 0dfb55e..19fb206 100644
---- a/glance/tests/unit/v2/test_image_data_resource.py
-+++ b/glance/tests/unit/v2/test_image_data_resource.py
-@@ -79,7 +79,7 @@ class FakeImageRepo(object):
-         else:
-             return self.result
- 
--    def save(self, image):
-+    def save(self, image, from_state=None):
-         self.saved_image = image
- 
- 
-@@ -180,17 +180,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_before_save(self):
-         request = unit_test_utils.get_fake_request()
diff --git a/openstack-glance.spec b/openstack-glance.spec
index 1d5d91d..4f78794 100644
--- a/openstack-glance.spec
+++ b/openstack-glance.spec
@@ -1,6 +1,6 @@
 Name:             openstack-glance
-Version:          2014.1.3
-Release:          4%{?dist}
+Version:          2014.1.4
+Release:          1%{?dist}
 Summary:          OpenStack Image Service
 
 Group:            Applications/System
@@ -25,19 +25,10 @@ Source11:         openstack-glance-scrubber.init
 Source1100:       openstack-glance-scrubber.upstart
 Source9999:       daemon_notify.sh
 
-#
-# patches_base=2014.1.3
-#
 Patch0001: 0001-Remove-runtime-dep-on-python-pbr.patch
 Patch0002: 0002-Don-t-access-the-net-while-building-docs.patch
 Patch0003: 0003-avoid-unsupported-storage-drivers.patch
 Patch0004: 0004-notify-calling-process-we-are-ready-to-serve.patch
-Patch0005: 0005-Make-rbd-store-s-pool-handling-more-universal.patch
-Patch0006: 0006-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
-Patch0007: 0007-Revert-To-prevent-client-use-v2-patch-api-to-handle-.patch
-Patch0008: 0008-To-prevent-client-use-v2-patch-api-to-handle-file-an.patch
-Patch0009: 0009-Prevent-file-swift-config-and-filesystem-schemes.patch
-Patch0010: 0010-Cleanup-chunks-for-deleted-image-that-was-saving.patch
 
 BuildArch:        noarch
 BuildRequires:    python2-devel
@@ -140,12 +131,6 @@ This package contains documentation files for glance.
 %patch0002 -p1
 %patch0003 -p1
 %patch0004 -p1
-%patch0005 -p1
-%patch0006 -p1
-%patch0007 -p1
-%patch0008 -p1
-%patch0009 -p1
-%patch0010 -p1
 
 # Remove bundled egg-info
 rm -rf glance.egg-info
@@ -397,6 +382,9 @@ fi
 %doc doc/build/html
 
 %changelog
+* Thu Mar 26 2015 Haikel Guemar <hguemar at fedoraproject.org> - 2014.1.4-1
+- Update to upstream 2014.1.4
+
 * Thu Jan 29 2015 Haïkel Guémar <hguemar at fedoraproject.org> - 2014.1.3-4
 - Usage storage quota bypass - CVE-2014-9623 (RHBZ #1187003)
 
diff --git a/sources b/sources
index c03b834..bad31ce 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-e7850ae017d6bf0dd53bdc78cff46f17  glance-2014.1.3.tar.gz
+d9937594e9a0c478f989bfa6ad1014cd  glance-2014.1.4.tar.gz
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/openstack-glance.git/commit/?h=f21&id=3bdbdafa726555e9b2059cac8898c1526c473f22


More information about the scm-commits mailing list