Add support for local file urls

Change-Id: Ie54508ade52b80790d11958a820998c902d10fd7
This commit is contained in:
Angus Salkeld 2013-08-26 14:37:05 +10:00
parent 8e64406c3f
commit 15de6d4309
2 changed files with 35 additions and 3 deletions

View File

@ -19,6 +19,7 @@ Utility for fetching a resource (e.g. a template) from a URL.
import requests import requests
from requests import exceptions from requests import exceptions
import urllib2
import urlparse import urlparse
from heat.openstack.common import log as logging from heat.openstack.common import log as logging
@ -27,20 +28,28 @@ from heat.openstack.common.gettextutils import _
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get(url): def get(url, allowed_schemes=('http', 'https')):
''' '''
Get the data at the specifier URL. Get the data at the specifier URL.
The URL must use the http: or https: schemes. The URL must use the http: or https: schemes.
The file: scheme is also supported if you override
the allowed_schemes argument.
Raise an IOError if getting the data fails. Raise an IOError if getting the data fails.
''' '''
logger.info(_('Fetching data from %s') % url) logger.info(_('Fetching data from %s') % url)
components = urlparse.urlparse(url) components = urlparse.urlparse(url)
if components.scheme not in ('http', 'https'): if components.scheme not in allowed_schemes:
raise IOError('Invalid URL scheme %s' % components.scheme) raise IOError('Invalid URL scheme %s' % components.scheme)
if components.scheme == 'file':
try:
return urllib2.urlopen(url).read()
except urllib2.URLError as uex:
raise IOError('Failed to retrieve template: %s' % str(uex))
try: try:
resp = requests.get(url) resp = requests.get(url)
resp.raise_for_status() resp.raise_for_status()

View File

@ -15,6 +15,8 @@
import requests import requests
from requests import exceptions from requests import exceptions
import urllib2
import cStringIO
from heat.common import urlfetch from heat.common import urlfetch
from heat.tests.common import HeatTestCase from heat.tests.common import HeatTestCase
@ -37,11 +39,32 @@ class UrlFetchTest(HeatTestCase):
super(UrlFetchTest, self).setUp() super(UrlFetchTest, self).setUp()
self.m.StubOutWithMock(requests, 'get') self.m.StubOutWithMock(requests, 'get')
def test_file_scheme(self): def test_file_scheme_default_behaviour(self):
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(IOError, urlfetch.get, 'file:///etc/profile') self.assertRaises(IOError, urlfetch.get, 'file:///etc/profile')
self.m.VerifyAll() self.m.VerifyAll()
def test_file_scheme_supported(self):
data = '{ "foo": "bar" }'
url = 'file:///etc/profile'
self.m.StubOutWithMock(urllib2, 'urlopen')
urllib2.urlopen(url).AndReturn(cStringIO.StringIO(data))
self.m.ReplayAll()
self.assertEqual(data, urlfetch.get(url, allowed_schemes=['file']))
self.m.VerifyAll()
def test_file_scheme_failure(self):
url = 'file:///etc/profile'
self.m.StubOutWithMock(urllib2, 'urlopen')
urllib2.urlopen(url).AndRaise(urllib2.URLError('oops'))
self.m.ReplayAll()
self.assertRaises(IOError, urlfetch.get, url, allowed_schemes=['file'])
self.m.VerifyAll()
def test_http_scheme(self): def test_http_scheme(self):
url = 'http://example.com/template' url = 'http://example.com/template'
data = '{ "foo": "bar" }' data = '{ "foo": "bar" }'