Merge "Allow tempurl times to have units"

This commit is contained in:
Zuul 2022-08-25 07:38:36 +00:00 committed by Gerrit Code Review
commit 662e530d8d
4 changed files with 112 additions and 42 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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/",

View File

@ -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',