Merge "Allow tempurl times to have units"
This commit is contained in:
commit
662e530d8d
@ -1388,14 +1388,16 @@ Positional arguments:
|
|||||||
<method> An HTTP method to allow for this temporary URL.
|
<method> An HTTP method to allow for this temporary URL.
|
||||||
Usually 'GET' or 'PUT'.
|
Usually 'GET' or 'PUT'.
|
||||||
<time> The amount of time the temporary URL will be
|
<time> The amount of time the temporary URL will be
|
||||||
valid. The time can be specified in two ways:
|
valid. The time can be specified in three ways:
|
||||||
an integer representing the time in seconds or an
|
an integer representing the time in seconds;
|
||||||
ISO 8601 timestamp in a specific format.
|
a number with a 's', 'm', 'h', or 'd' suffix to specify
|
||||||
If --absolute is passed and time
|
the time in seconds, minutes, hours, or days; or
|
||||||
is an integer, the seconds are intepreted as the Unix
|
an ISO 8601 timestamp in a specific format.
|
||||||
timestamp when the temporary URL will expire. The ISO
|
If --absolute is passed and time is an integer, the
|
||||||
8601 timestamp can be specified in one of following
|
seconds are intepreted as the Unix timestamp when the
|
||||||
formats:
|
temporary URL will expire.
|
||||||
|
The ISO 8601 timestamp can be specified in one of
|
||||||
|
following formats:
|
||||||
|
|
||||||
i) Complete date: YYYY-MM-DD (eg 1997-07-16)
|
i) Complete date: YYYY-MM-DD (eg 1997-07-16)
|
||||||
|
|
||||||
|
@ -70,40 +70,7 @@ def prt_bytes(num_bytes, human_flag):
|
|||||||
return '%.1f%s' % (num, suffix)
|
return '%.1f%s' % (num, suffix)
|
||||||
|
|
||||||
|
|
||||||
def generate_temp_url(path, seconds, key, method, absolute=False,
|
def parse_timestamp(seconds, absolute=False):
|
||||||
prefix=False, iso8601=False, ip_range=None,
|
|
||||||
digest='sha256'):
|
|
||||||
"""Generates a temporary URL that gives unauthenticated access to the
|
|
||||||
Swift object.
|
|
||||||
|
|
||||||
:param path: The full path to the Swift object or prefix if
|
|
||||||
a prefix-based temporary URL should be generated. Example:
|
|
||||||
/v1/AUTH_account/c/o or /v1/AUTH_account/c/prefix.
|
|
||||||
:param seconds: time in seconds or ISO 8601 timestamp.
|
|
||||||
If absolute is False and this is the string representation of an
|
|
||||||
integer, then this specifies the amount of time in seconds for which
|
|
||||||
the temporary URL will be valid.
|
|
||||||
If absolute is True then this specifies an absolute time at which the
|
|
||||||
temporary URL will expire.
|
|
||||||
:param key: The secret temporary URL key set on the Swift
|
|
||||||
cluster. To set a key, run 'swift post -m
|
|
||||||
"Temp-URL-Key: <substitute tempurl key here>"'
|
|
||||||
:param method: A HTTP method, typically either GET or PUT, to allow
|
|
||||||
for this temporary URL.
|
|
||||||
:param absolute: if True then the seconds parameter is interpreted as a
|
|
||||||
Unix timestamp, if seconds represents an integer.
|
|
||||||
:param prefix: if True then a prefix-based temporary URL will be generated.
|
|
||||||
:param iso8601: if True, a URL containing an ISO 8601 UTC timestamp
|
|
||||||
instead of a UNIX timestamp will be created.
|
|
||||||
:param ip_range: if a valid ip range, restricts the temporary URL to the
|
|
||||||
range of ips.
|
|
||||||
:param digest: digest algorithm to use. Must be one of ``sha1``,
|
|
||||||
``sha256``, or ``sha512``.
|
|
||||||
:raises ValueError: if timestamp or path is not in valid format,
|
|
||||||
or if digest is not one of ``sha1``, ``sha256``, or
|
|
||||||
``sha512``.
|
|
||||||
:return: the path portion of a temporary URL
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
timestamp = float(seconds)
|
timestamp = float(seconds)
|
||||||
@ -127,6 +94,20 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
|
|||||||
absolute = True
|
absolute = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if t is None and not absolute:
|
||||||
|
for suffix, multiplier in (
|
||||||
|
('s', 1),
|
||||||
|
('m', 60),
|
||||||
|
('min', 60),
|
||||||
|
('h', 60 * 60),
|
||||||
|
('hr', 60 * 60),
|
||||||
|
('d', 24 * 60 * 60),
|
||||||
|
):
|
||||||
|
if seconds.endswith(suffix):
|
||||||
|
timestamp = t = int(
|
||||||
|
multiplier * float(seconds[:-len(suffix)]))
|
||||||
|
break
|
||||||
|
|
||||||
if t is None:
|
if t is None:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
else:
|
else:
|
||||||
@ -137,6 +118,46 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
|
|||||||
raise ValueError()
|
raise ValueError()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError(TIME_ERRMSG)
|
raise ValueError(TIME_ERRMSG)
|
||||||
|
return timestamp, absolute
|
||||||
|
|
||||||
|
|
||||||
|
def generate_temp_url(path, seconds, key, method, absolute=False,
|
||||||
|
prefix=False, iso8601=False, ip_range=None,
|
||||||
|
digest='sha256'):
|
||||||
|
"""Generates a temporary URL that gives unauthenticated access to the
|
||||||
|
Swift object.
|
||||||
|
|
||||||
|
:param path: The full path to the Swift object or prefix if
|
||||||
|
a prefix-based temporary URL should be generated. Example:
|
||||||
|
/v1/AUTH_account/c/o or /v1/AUTH_account/c/prefix.
|
||||||
|
:param seconds: time in seconds or ISO 8601 timestamp.
|
||||||
|
If absolute is False and this is the string representation of an
|
||||||
|
integer, then this specifies the amount of time in seconds for which
|
||||||
|
the temporary URL will be valid. This may include a suffix to scale
|
||||||
|
the value: 's' for seconds, 'm' (or 'min') for minutes,
|
||||||
|
'h' (or 'hr') for hours, or 'd' for days.
|
||||||
|
If absolute is True then this specifies an absolute time at which the
|
||||||
|
temporary URL will expire.
|
||||||
|
:param key: The secret temporary URL key set on the Swift
|
||||||
|
cluster. To set a key, run 'swift post -m
|
||||||
|
"Temp-URL-Key: <substitute tempurl key here>"'
|
||||||
|
:param method: A HTTP method, typically either GET or PUT, to allow
|
||||||
|
for this temporary URL.
|
||||||
|
:param absolute: if True then the seconds parameter is interpreted as a
|
||||||
|
Unix timestamp, if seconds represents an integer.
|
||||||
|
:param prefix: if True then a prefix-based temporary URL will be generated.
|
||||||
|
:param iso8601: if True, a URL containing an ISO 8601 UTC timestamp
|
||||||
|
instead of a UNIX timestamp will be created.
|
||||||
|
:param ip_range: if a valid ip range, restricts the temporary URL to the
|
||||||
|
range of ips.
|
||||||
|
:param digest: digest algorithm to use. Must be one of ``sha1``,
|
||||||
|
``sha256``, or ``sha512``.
|
||||||
|
:raises ValueError: if timestamp or path is not in valid format,
|
||||||
|
or if digest is not one of ``sha1``, ``sha256``, or
|
||||||
|
``sha512``.
|
||||||
|
:return: the path portion of a temporary URL
|
||||||
|
"""
|
||||||
|
timestamp, absolute = parse_timestamp(seconds, absolute)
|
||||||
|
|
||||||
if isinstance(path, bytes):
|
if isinstance(path, bytes):
|
||||||
try:
|
try:
|
||||||
|
@ -2079,6 +2079,14 @@ class TestShell(unittest.TestCase):
|
|||||||
'/v1/AUTH_account/c/o', "60", 'secret_key', 'GET', absolute=False,
|
'/v1/AUTH_account/c/o', "60", 'secret_key', 'GET', absolute=False,
|
||||||
iso8601=False, prefix=False, ip_range=None, digest='sha256')
|
iso8601=False, prefix=False, ip_range=None, digest='sha256')
|
||||||
|
|
||||||
|
# sanity check that suffixes will just pass through to utils.py
|
||||||
|
argv = ["", "tempurl", "GET", "2d", "/v1/AUTH_account/c/o",
|
||||||
|
"secret_key"]
|
||||||
|
swiftclient.shell.main(argv)
|
||||||
|
temp_url.assert_called_with(
|
||||||
|
'/v1/AUTH_account/c/o', "2d", 'secret_key', 'GET', absolute=False,
|
||||||
|
iso8601=False, prefix=False, ip_range=None, digest='sha256')
|
||||||
|
|
||||||
@mock.patch('swiftclient.shell.generate_temp_url', return_value='')
|
@mock.patch('swiftclient.shell.generate_temp_url', return_value='')
|
||||||
def test_temp_url_prefix_based(self, temp_url):
|
def test_temp_url_prefix_based(self, temp_url):
|
||||||
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/",
|
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/",
|
||||||
|
@ -122,6 +122,43 @@ class TestPrtBytes(unittest.TestCase):
|
|||||||
self.assertEqual('1024Y', u.prt_bytes(bytes_, True).lstrip())
|
self.assertEqual('1024Y', u.prt_bytes(bytes_, True).lstrip())
|
||||||
|
|
||||||
|
|
||||||
|
class TestParseTimestamp(unittest.TestCase):
|
||||||
|
def test_int(self):
|
||||||
|
self.assertEqual((1234, False), u.parse_timestamp(1234, False))
|
||||||
|
self.assertEqual((3600, False), u.parse_timestamp('3600', False))
|
||||||
|
|
||||||
|
def test_suffixed(self):
|
||||||
|
self.assertEqual((54, False), u.parse_timestamp('54.321s', False))
|
||||||
|
self.assertEqual((int(54.321 * 60), False),
|
||||||
|
u.parse_timestamp('54.321m', False))
|
||||||
|
self.assertEqual((900, False),
|
||||||
|
u.parse_timestamp('15min', False))
|
||||||
|
self.assertEqual((int(54.321 * 60 * 60), False),
|
||||||
|
u.parse_timestamp('54.321h', False))
|
||||||
|
self.assertEqual((7200, False),
|
||||||
|
u.parse_timestamp('2hr', False))
|
||||||
|
self.assertEqual((60 * 60 * 24, False), u.parse_timestamp('1d', False))
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
self.assertEqual((1615852800, True),
|
||||||
|
u.parse_timestamp('2021-03-16T00:00:00Z', False))
|
||||||
|
|
||||||
|
def test_absolute(self):
|
||||||
|
self.assertEqual((1234, True), u.parse_timestamp(1234, True))
|
||||||
|
self.assertEqual((1615852800, True),
|
||||||
|
u.parse_timestamp('2021-03-16T00:00:00Z', True))
|
||||||
|
|
||||||
|
def test_error(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
u.parse_timestamp('asdf', False)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
u.parse_timestamp(12.34, False)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
u.parse_timestamp('54.321', True)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
u.parse_timestamp(-1, False)
|
||||||
|
|
||||||
|
|
||||||
class TestTempURL(unittest.TestCase):
|
class TestTempURL(unittest.TestCase):
|
||||||
url = '/v1/AUTH_account/c/o'
|
url = '/v1/AUTH_account/c/o'
|
||||||
seconds = 3600
|
seconds = 3600
|
||||||
@ -422,6 +459,7 @@ class TestTempURL(unittest.TestCase):
|
|||||||
class TestTempURLUnicodePathAndKey(TestTempURL):
|
class TestTempURLUnicodePathAndKey(TestTempURL):
|
||||||
url = '/v1/\u00e4/c/\u00f3'
|
url = '/v1/\u00e4/c/\u00f3'
|
||||||
key = 'k\u00e9y'
|
key = 'k\u00e9y'
|
||||||
|
seconds = '1hr'
|
||||||
expected_body = '\n'.join([
|
expected_body = '\n'.join([
|
||||||
'GET',
|
'GET',
|
||||||
'1400003600',
|
'1400003600',
|
||||||
@ -432,6 +470,7 @@ class TestTempURLUnicodePathAndKey(TestTempURL):
|
|||||||
class TestTempURLUnicodePathBytesKey(TestTempURL):
|
class TestTempURLUnicodePathBytesKey(TestTempURL):
|
||||||
url = '/v1/\u00e4/c/\u00f3'
|
url = '/v1/\u00e4/c/\u00f3'
|
||||||
key = 'k\u00e9y'.encode('utf-8')
|
key = 'k\u00e9y'.encode('utf-8')
|
||||||
|
seconds = '60m'
|
||||||
expected_body = '\n'.join([
|
expected_body = '\n'.join([
|
||||||
'GET',
|
'GET',
|
||||||
'1400003600',
|
'1400003600',
|
||||||
|
Loading…
Reference in New Issue
Block a user