heat : Add HeatIdentifier from_url function
Add method to create a HeatIdentifier from a URL containing an ARN ref bug 1087799 Signed-off-by: Steven Hardy <shardy@redhat.com> Change-Id: Ie325de9105e85dbf9fd12be5e7b8c3d055e77795
This commit is contained in:
parent
4510eccddc
commit
be33b3364c
|
@ -14,6 +14,7 @@
|
|||
|
||||
import re
|
||||
import urllib
|
||||
import urlparse
|
||||
import collections
|
||||
|
||||
|
||||
|
@ -62,6 +63,28 @@ class HeatIdentifier(collections.Mapping):
|
|||
urllib.unquote(path.group(2)),
|
||||
urllib.unquote(path.group(3)))
|
||||
|
||||
@classmethod
|
||||
def from_arn_url(cls, url):
|
||||
'''
|
||||
Return a new HeatIdentifier generated by parsing the supplied URL
|
||||
The URL is expected to contain a valid arn as part of the path
|
||||
'''
|
||||
# Sanity check the URL
|
||||
urlp = urlparse.urlparse(url)
|
||||
if (urlp.scheme not in ('http', 'https') or
|
||||
not urlp.netloc or not urlp.path):
|
||||
raise ValueError('"%s" is not a valid URL' % url)
|
||||
|
||||
# Remove any query-string and extract the ARN
|
||||
arn_url_prefix = '/arn%3Aopenstack%3Aheat%3A%3A'
|
||||
match = re.search(arn_url_prefix, urlp.path, re.IGNORECASE)
|
||||
if match is None:
|
||||
raise ValueError('"%s" is not a valid ARN URL' % url)
|
||||
# the +1 is to skip the leading /
|
||||
url_arn = urlp.path[match.start() + 1:]
|
||||
arn = urllib.unquote(url_arn)
|
||||
return cls.from_arn(arn)
|
||||
|
||||
def arn(self):
|
||||
'''
|
||||
Return an ARN of the form:
|
||||
|
@ -70,6 +93,12 @@ class HeatIdentifier(collections.Mapping):
|
|||
return 'arn:openstack:heat::%s:%s' % (urllib.quote(self.tenant, ''),
|
||||
self._tenant_path())
|
||||
|
||||
def arn_url_path(self):
|
||||
'''
|
||||
Return an ARN quoted correctly for use in a URL
|
||||
'''
|
||||
return '/' + urllib.quote(self.arn(), '')
|
||||
|
||||
def url_path(self):
|
||||
'''
|
||||
Return a URL-encoded path segment of a URL in the form:
|
||||
|
|
|
@ -25,6 +25,7 @@ from heat.common import identifier
|
|||
@attr(tag=['unit', 'identifier'])
|
||||
@attr(speed='fast')
|
||||
class IdentifierTest(unittest.TestCase):
|
||||
url_prefix = 'http://1.2.3.4/foo/'
|
||||
|
||||
def test_attrs(self):
|
||||
hi = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
|
@ -58,6 +59,11 @@ class IdentifierTest(unittest.TestCase):
|
|||
hi = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
self.assertEqual(hi.arn(), 'arn:openstack:heat::t:stacks/s/i/p')
|
||||
|
||||
def test_arn_url(self):
|
||||
hi = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
self.assertEqual(hi.arn_url_path(),
|
||||
'/arn%3Aopenstack%3Aheat%3A%3At%3Astacks%2Fs%2Fi%2Fp')
|
||||
|
||||
def test_arn_id_int(self):
|
||||
hi = identifier.HeatIdentifier('t', 's', 42, 'p')
|
||||
self.assertEqual(hi.arn(), 'arn:openstack:heat::t:stacks/s/42/p')
|
||||
|
@ -70,6 +76,14 @@ class IdentifierTest(unittest.TestCase):
|
|||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '/p')
|
||||
|
||||
def test_arn_url_parse(self):
|
||||
url = self.url_prefix + 'arn%3Aopenstack%3Aheat%3A%3At%3Astacks/s/i/p'
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.tenant, 't')
|
||||
self.assertEqual(hi.stack_name, 's')
|
||||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '/p')
|
||||
|
||||
def test_arn_parse_path_default(self):
|
||||
arn = 'arn:openstack:heat::t:stacks/s/i'
|
||||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
|
@ -78,35 +92,112 @@ class IdentifierTest(unittest.TestCase):
|
|||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '')
|
||||
|
||||
def test_arn_url_parse_default(self):
|
||||
url = self.url_prefix + 'arn%3Aopenstack%3Aheat%3A%3At%3Astacks/s/i'
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.tenant, 't')
|
||||
self.assertEqual(hi.stack_name, 's')
|
||||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '')
|
||||
|
||||
def test_arn_parse_upper(self):
|
||||
arn = 'ARN:openstack:heat::t:stacks/s/i/p'
|
||||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.stack_name, 's')
|
||||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '/p')
|
||||
|
||||
def test_arn_url_parse_upper(self):
|
||||
url = self.url_prefix + 'ARN%3Aopenstack%3Aheat%3A%3At%3Astacks/s/i/p'
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.tenant, 't')
|
||||
self.assertEqual(hi.stack_name, 's')
|
||||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '/p')
|
||||
|
||||
def test_arn_url_parse_qs(self):
|
||||
url = self.url_prefix +\
|
||||
'arn%3Aopenstack%3Aheat%3A%3At%3Astacks/s/i/p?foo=bar'
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.tenant, 't')
|
||||
self.assertEqual(hi.stack_name, 's')
|
||||
self.assertEqual(hi.stack_id, 'i')
|
||||
self.assertEqual(hi.path, '/p')
|
||||
|
||||
def test_arn_parse_arn_invalid(self):
|
||||
arn = 'urn:openstack:heat::t:stacks/s/i'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_arn_invalid(self):
|
||||
url = self.url_prefix + 'urn:openstack:heat::t:stacks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_parse_os_invalid(self):
|
||||
arn = 'arn:aws:heat::t:stacks/s/i'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_os_invalid(self):
|
||||
url = self.url_prefix + 'arn:aws:heat::t:stacks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_parse_heat_invalid(self):
|
||||
arn = 'arn:openstack:cool::t:stacks/s/i'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_heat_invalid(self):
|
||||
url = self.url_prefix + 'arn:openstack:cool::t:stacks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_parse_stacks_invalid(self):
|
||||
arn = 'arn:openstack:heat::t:sticks/s/i'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_stacks_invalid(self):
|
||||
url = self.url_prefix + 'arn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_parse_missing_field(self):
|
||||
arn = 'arn:openstack:heat::t:stacks/s'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_missing_field(self):
|
||||
url = self.url_prefix + 'arn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_parse_empty_field(self):
|
||||
arn = 'arn:openstack:heat::t:stacks//i'
|
||||
self.assertRaises(ValueError, identifier.HeatIdentifier.from_arn, arn)
|
||||
|
||||
def test_arn_url_parse_empty_field(self):
|
||||
url = self.url_prefix + 'arn%3Aopenstack%3Aheat%3A%3At%3Asticks//i'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_url_parse_leading_char(self):
|
||||
url = self.url_prefix + 'Aarn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_url_parse_leading_space(self):
|
||||
url = self.url_prefix + ' arn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_url_parse_badurl_proto(self):
|
||||
url = 'htt://1.2.3.4/foo/arn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_url_parse_badurl_host(self):
|
||||
url = 'htt:///foo/arn%3Aopenstack%3Aheat%3A%3At%3Asticks/s/i/p'
|
||||
self.assertRaises(ValueError,
|
||||
identifier.HeatIdentifier.from_arn_url, url)
|
||||
|
||||
def test_arn_round_trip(self):
|
||||
hii = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
hio = identifier.HeatIdentifier.from_arn(hii.arn())
|
||||
|
@ -120,6 +211,12 @@ class IdentifierTest(unittest.TestCase):
|
|||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.arn(), arn)
|
||||
|
||||
def test_arn_url_parse_round_trip(self):
|
||||
arn = '/arn%3Aopenstack%3Aheat%3A%3At%3Astacks%2Fs%2Fi%2Fp'
|
||||
url = 'http://1.2.3.4/foo' + arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.arn_url_path(), arn)
|
||||
|
||||
def test_dict_round_trip(self):
|
||||
hii = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
hio = identifier.HeatIdentifier(**dict(hii))
|
||||
|
@ -165,21 +262,45 @@ class IdentifierTest(unittest.TestCase):
|
|||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.tenant, ':/')
|
||||
|
||||
def test_url_tenant_decode(self):
|
||||
enc_arn = 'arn%3Aopenstack%3Aheat%3A%3A%253A%252F%3Astacks%2Fs%2Fi'
|
||||
url = self.url_prefix + enc_arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.tenant, ':/')
|
||||
|
||||
def test_name_decode(self):
|
||||
arn = 'arn:openstack:heat::t:stacks/%3A%2F/i'
|
||||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.stack_name, ':/')
|
||||
|
||||
def test_url_name_decode(self):
|
||||
enc_arn = 'arn%3Aopenstack%3Aheat%3A%3At%3Astacks%2F%253A%252F%2Fi'
|
||||
url = self.url_prefix + enc_arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.stack_name, ':/')
|
||||
|
||||
def test_id_decode(self):
|
||||
arn = 'arn:openstack:heat::t:stacks/s/%3A%2F'
|
||||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.stack_id, ':/')
|
||||
|
||||
def test_url_id_decode(self):
|
||||
enc_arn = 'arn%3Aopenstack%3Aheat%3A%3At%3Astacks%2Fs%2F%253A%252F'
|
||||
url = self.url_prefix + enc_arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.stack_id, ':/')
|
||||
|
||||
def test_path_decode(self):
|
||||
arn = 'arn:openstack:heat::t:stacks/s/i/%3A%2F'
|
||||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.path, '/:/')
|
||||
|
||||
def test_url_path_decode(self):
|
||||
enc_arn = 'arn%3Aopenstack%3Aheat%3A%3At%3Astacks%2Fs%2Fi%2F%253A%252F'
|
||||
url = self.url_prefix + enc_arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
self.assertEqual(hi.path, '/:/')
|
||||
|
||||
def test_arn_escape_decode_round_trip(self):
|
||||
hii = identifier.HeatIdentifier(':/', ':/', ':/', ':/')
|
||||
hio = identifier.HeatIdentifier.from_arn(hii.arn())
|
||||
|
@ -193,6 +314,16 @@ class IdentifierTest(unittest.TestCase):
|
|||
hi = identifier.HeatIdentifier.from_arn(arn)
|
||||
self.assertEqual(hi.arn(), arn)
|
||||
|
||||
def test_arn_url_decode_escape_round_trip(self):
|
||||
enc_arn = "".join(['arn%3Aopenstack%3Aheat%3A%3A%253A%252F%3A',
|
||||
'stacks%2F%253A%252F%2F%253A%252F%2F%253A'])
|
||||
url = self.url_prefix + enc_arn
|
||||
hi = identifier.HeatIdentifier.from_arn_url(url)
|
||||
print "SHDEBUG hi.arn()=%s" % hi.arn()
|
||||
hi2 = identifier.HeatIdentifier.from_arn_url(self.url_prefix +
|
||||
hi.arn_url_path())
|
||||
self.assertEqual(hi, hi2)
|
||||
|
||||
def test_equal(self):
|
||||
hi1 = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
hi2 = identifier.HeatIdentifier('t', 's', 'i', 'p')
|
||||
|
|
Loading…
Reference in New Issue