Skip to content

Commit 662e530

Browse files
Zuulopenstack-gerrit
Zuul
authored andcommitted
Merge "Allow tempurl times to have units"
2 parents 02509ac + defbb4a commit 662e530

File tree

4 files changed

+112
-42
lines changed

4 files changed

+112
-42
lines changed

swiftclient/shell.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -1388,14 +1388,16 @@ def st_auth(parser, args, thread_manager, return_parser=False):
13881388
<method> An HTTP method to allow for this temporary URL.
13891389
Usually 'GET' or 'PUT'.
13901390
<time> The amount of time the temporary URL will be
1391-
valid. The time can be specified in two ways:
1392-
an integer representing the time in seconds or an
1393-
ISO 8601 timestamp in a specific format.
1394-
If --absolute is passed and time
1395-
is an integer, the seconds are intepreted as the Unix
1396-
timestamp when the temporary URL will expire. The ISO
1397-
8601 timestamp can be specified in one of following
1398-
formats:
1391+
valid. The time can be specified in three ways:
1392+
an integer representing the time in seconds;
1393+
a number with a 's', 'm', 'h', or 'd' suffix to specify
1394+
the time in seconds, minutes, hours, or days; or
1395+
an ISO 8601 timestamp in a specific format.
1396+
If --absolute is passed and time is an integer, the
1397+
seconds are intepreted as the Unix timestamp when the
1398+
temporary URL will expire.
1399+
The ISO 8601 timestamp can be specified in one of
1400+
following formats:
13991401
14001402
i) Complete date: YYYY-MM-DD (eg 1997-07-16)
14011403

swiftclient/utils.py

+55-34
Original file line numberDiff line numberDiff line change
@@ -70,40 +70,7 @@ def prt_bytes(num_bytes, human_flag):
7070
return '%.1f%s' % (num, suffix)
7171

7272

73-
def generate_temp_url(path, seconds, key, method, absolute=False,
74-
prefix=False, iso8601=False, ip_range=None,
75-
digest='sha256'):
76-
"""Generates a temporary URL that gives unauthenticated access to the
77-
Swift object.
78-
79-
:param path: The full path to the Swift object or prefix if
80-
a prefix-based temporary URL should be generated. Example:
81-
/v1/AUTH_account/c/o or /v1/AUTH_account/c/prefix.
82-
:param seconds: time in seconds or ISO 8601 timestamp.
83-
If absolute is False and this is the string representation of an
84-
integer, then this specifies the amount of time in seconds for which
85-
the temporary URL will be valid.
86-
If absolute is True then this specifies an absolute time at which the
87-
temporary URL will expire.
88-
:param key: The secret temporary URL key set on the Swift
89-
cluster. To set a key, run 'swift post -m
90-
"Temp-URL-Key: <substitute tempurl key here>"'
91-
:param method: A HTTP method, typically either GET or PUT, to allow
92-
for this temporary URL.
93-
:param absolute: if True then the seconds parameter is interpreted as a
94-
Unix timestamp, if seconds represents an integer.
95-
:param prefix: if True then a prefix-based temporary URL will be generated.
96-
:param iso8601: if True, a URL containing an ISO 8601 UTC timestamp
97-
instead of a UNIX timestamp will be created.
98-
:param ip_range: if a valid ip range, restricts the temporary URL to the
99-
range of ips.
100-
:param digest: digest algorithm to use. Must be one of ``sha1``,
101-
``sha256``, or ``sha512``.
102-
:raises ValueError: if timestamp or path is not in valid format,
103-
or if digest is not one of ``sha1``, ``sha256``, or
104-
``sha512``.
105-
:return: the path portion of a temporary URL
106-
"""
73+
def parse_timestamp(seconds, absolute=False):
10774
try:
10875
try:
10976
timestamp = float(seconds)
@@ -127,6 +94,20 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
12794
absolute = True
12895
break
12996

97+
if t is None and not absolute:
98+
for suffix, multiplier in (
99+
('s', 1),
100+
('m', 60),
101+
('min', 60),
102+
('h', 60 * 60),
103+
('hr', 60 * 60),
104+
('d', 24 * 60 * 60),
105+
):
106+
if seconds.endswith(suffix):
107+
timestamp = t = int(
108+
multiplier * float(seconds[:-len(suffix)]))
109+
break
110+
130111
if t is None:
131112
raise ValueError()
132113
else:
@@ -137,6 +118,46 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
137118
raise ValueError()
138119
except ValueError:
139120
raise ValueError(TIME_ERRMSG)
121+
return timestamp, absolute
122+
123+
124+
def generate_temp_url(path, seconds, key, method, absolute=False,
125+
prefix=False, iso8601=False, ip_range=None,
126+
digest='sha256'):
127+
"""Generates a temporary URL that gives unauthenticated access to the
128+
Swift object.
129+
130+
:param path: The full path to the Swift object or prefix if
131+
a prefix-based temporary URL should be generated. Example:
132+
/v1/AUTH_account/c/o or /v1/AUTH_account/c/prefix.
133+
:param seconds: time in seconds or ISO 8601 timestamp.
134+
If absolute is False and this is the string representation of an
135+
integer, then this specifies the amount of time in seconds for which
136+
the temporary URL will be valid. This may include a suffix to scale
137+
the value: 's' for seconds, 'm' (or 'min') for minutes,
138+
'h' (or 'hr') for hours, or 'd' for days.
139+
If absolute is True then this specifies an absolute time at which the
140+
temporary URL will expire.
141+
:param key: The secret temporary URL key set on the Swift
142+
cluster. To set a key, run 'swift post -m
143+
"Temp-URL-Key: <substitute tempurl key here>"'
144+
:param method: A HTTP method, typically either GET or PUT, to allow
145+
for this temporary URL.
146+
:param absolute: if True then the seconds parameter is interpreted as a
147+
Unix timestamp, if seconds represents an integer.
148+
:param prefix: if True then a prefix-based temporary URL will be generated.
149+
:param iso8601: if True, a URL containing an ISO 8601 UTC timestamp
150+
instead of a UNIX timestamp will be created.
151+
:param ip_range: if a valid ip range, restricts the temporary URL to the
152+
range of ips.
153+
:param digest: digest algorithm to use. Must be one of ``sha1``,
154+
``sha256``, or ``sha512``.
155+
:raises ValueError: if timestamp or path is not in valid format,
156+
or if digest is not one of ``sha1``, ``sha256``, or
157+
``sha512``.
158+
:return: the path portion of a temporary URL
159+
"""
160+
timestamp, absolute = parse_timestamp(seconds, absolute)
140161

141162
if isinstance(path, bytes):
142163
try:

test/unit/test_shell.py

+8
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,14 @@ def test_temp_url(self, temp_url):
20792079
'/v1/AUTH_account/c/o', "60", 'secret_key', 'GET', absolute=False,
20802080
iso8601=False, prefix=False, ip_range=None, digest='sha256')
20812081

2082+
# sanity check that suffixes will just pass through to utils.py
2083+
argv = ["", "tempurl", "GET", "2d", "/v1/AUTH_account/c/o",
2084+
"secret_key"]
2085+
swiftclient.shell.main(argv)
2086+
temp_url.assert_called_with(
2087+
'/v1/AUTH_account/c/o', "2d", 'secret_key', 'GET', absolute=False,
2088+
iso8601=False, prefix=False, ip_range=None, digest='sha256')
2089+
20822090
@mock.patch('swiftclient.shell.generate_temp_url', return_value='')
20832091
def test_temp_url_prefix_based(self, temp_url):
20842092
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/",

test/unit/test_utils.py

+39
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,43 @@ def test_overflow(self):
122122
self.assertEqual('1024Y', u.prt_bytes(bytes_, True).lstrip())
123123

124124

125+
class TestParseTimestamp(unittest.TestCase):
126+
def test_int(self):
127+
self.assertEqual((1234, False), u.parse_timestamp(1234, False))
128+
self.assertEqual((3600, False), u.parse_timestamp('3600', False))
129+
130+
def test_suffixed(self):
131+
self.assertEqual((54, False), u.parse_timestamp('54.321s', False))
132+
self.assertEqual((int(54.321 * 60), False),
133+
u.parse_timestamp('54.321m', False))
134+
self.assertEqual((900, False),
135+
u.parse_timestamp('15min', False))
136+
self.assertEqual((int(54.321 * 60 * 60), False),
137+
u.parse_timestamp('54.321h', False))
138+
self.assertEqual((7200, False),
139+
u.parse_timestamp('2hr', False))
140+
self.assertEqual((60 * 60 * 24, False), u.parse_timestamp('1d', False))
141+
142+
def test_str(self):
143+
self.assertEqual((1615852800, True),
144+
u.parse_timestamp('2021-03-16T00:00:00Z', False))
145+
146+
def test_absolute(self):
147+
self.assertEqual((1234, True), u.parse_timestamp(1234, True))
148+
self.assertEqual((1615852800, True),
149+
u.parse_timestamp('2021-03-16T00:00:00Z', True))
150+
151+
def test_error(self):
152+
with self.assertRaises(ValueError):
153+
u.parse_timestamp('asdf', False)
154+
with self.assertRaises(ValueError):
155+
u.parse_timestamp(12.34, False)
156+
with self.assertRaises(ValueError):
157+
u.parse_timestamp('54.321', True)
158+
with self.assertRaises(ValueError):
159+
u.parse_timestamp(-1, False)
160+
161+
125162
class TestTempURL(unittest.TestCase):
126163
url = '/v1/AUTH_account/c/o'
127164
seconds = 3600
@@ -422,6 +459,7 @@ def test_generate_temp_url_bad_path(self):
422459
class TestTempURLUnicodePathAndKey(TestTempURL):
423460
url = '/v1/\u00e4/c/\u00f3'
424461
key = 'k\u00e9y'
462+
seconds = '1hr'
425463
expected_body = '\n'.join([
426464
'GET',
427465
'1400003600',
@@ -432,6 +470,7 @@ class TestTempURLUnicodePathAndKey(TestTempURL):
432470
class TestTempURLUnicodePathBytesKey(TestTempURL):
433471
url = '/v1/\u00e4/c/\u00f3'
434472
key = 'k\u00e9y'.encode('utf-8')
473+
seconds = '60m'
435474
expected_body = '\n'.join([
436475
'GET',
437476
'1400003600',

0 commit comments

Comments
 (0)