diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-01-21 23:05:19 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-01-21 23:05:19 +0000 |
commit | a4d608fa33b328d7ed77c7f9c40ffbb43c0ade6b (patch) | |
tree | cf59f08d89515cb1f20da8e01de685bd2f8a9e99 | |
parent | 07531ad264a4fd21faa89f19ad032bf34a223d38 (diff) | |
parent | 20fca1a2d75c2cd813245200c138df6e854b681b (diff) | |
download | nova-a4d608fa33b328d7ed77c7f9c40ffbb43c0ade6b.tar.gz nova-a4d608fa33b328d7ed77c7f9c40ffbb43c0ade6b.tar.xz nova-a4d608fa33b328d7ed77c7f9c40ffbb43c0ade6b.zip |
Merge "Directly copy a file URL from glance."
-rw-r--r-- | nova/image/glance.py | 20 | ||||
-rw-r--r-- | nova/tests/image/test_glance.py | 37 |
2 files changed, 56 insertions, 1 deletions
diff --git a/nova/image/glance.py b/nova/image/glance.py index 75551d35c..1a6bba62f 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -22,6 +22,7 @@ from __future__ import absolute_import import copy import itertools import random +import shutil import sys import time import urlparse @@ -58,7 +59,12 @@ glance_opts = [ cfg.IntOpt('glance_num_retries', default=0, help='Number retries when downloading an image from glance'), -] + cfg.ListOpt('allowed_direct_url_schemes', + default=[], + help='A list of url scheme that can be downloaded directly ' + 'via the direct_url. Currently supported schemes: ' + '[file].'), + ] LOG = logging.getLogger(__name__) CONF = cfg.CONF @@ -254,6 +260,18 @@ class GlanceImageService(object): def download(self, context, image_id, data): """Calls out to Glance for metadata and data and writes data.""" + if 'file' in CONF.allowed_direct_url_schemes: + location = self.get_location(context, image_id) + o = urlparse.urlparse(location) + if o.scheme == "file": + with open(o.path, "r") as f: + # FIXME(jbresnah) a system call to cp could have + # significant performance advantages, however we + # do not have the path to files at this point in + # the abstraction. + shutil.copyfileobj(f, data) + return + try: image_chunks = self._client.call(context, 1, 'data', image_id) except Exception: diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 7c13796a6..9dd9e5121 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -17,7 +17,10 @@ import datetime +import filecmp +import os import random +import tempfile import time import glanceclient.exc @@ -468,6 +471,40 @@ class TestGlanceImageService(test.TestCase): self.flags(glance_num_retries=1) service.download(self.context, image_id, writer) + def test_download_file_url(self): + class MyGlanceStubClient(glance_stubs.StubGlanceClient): + """A client that returns a file url.""" + + (outfd, s_tmpfname) = tempfile.mkstemp(prefix='directURLsrc') + outf = os.fdopen(outfd, 'w') + inf = open('/dev/urandom', 'r') + for i in range(10): + _data = inf.read(1024) + outf.write(_data) + outf.close() + + def get(self, image_id): + return type('GlanceTestDirectUrlMeta', (object,), + {'direct_url': 'file://%s' + self.s_tmpfname}) + + client = MyGlanceStubClient() + (outfd, tmpfname) = tempfile.mkstemp(prefix='directURLdst') + writer = os.fdopen(outfd, 'w') + + service = self._create_image_service(client) + image_id = 1 # doesn't matter + + self.flags(allowed_direct_url_schemes=['file']) + service.download(self.context, image_id, writer) + writer.close() + + # compare the two files + rc = filecmp.cmp(tmpfname, client.s_tmpfname) + self.assertTrue(rc, "The file %s and %s should be the same" % + (tmpfname, client.s_tmpfname)) + os.remove(client.s_tmpfname) + os.remove(tmpfname) + def test_client_forbidden_converts_to_imagenotauthed(self): class MyGlanceStubClient(glance_stubs.StubGlanceClient): """A client that raises a Forbidden exception.""" |