rucio-clients 37.3.0__py3-none-any.whl → 37.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio-clients might be problematic. Click here for more details.
- rucio/cli/rule.py +1 -1
- rucio/client/accountclient.py +205 -60
- rucio/client/accountlimitclient.py +84 -25
- rucio/client/baseclient.py +85 -48
- rucio/client/client.py +49 -41
- rucio/client/configclient.py +36 -13
- rucio/client/credentialclient.py +16 -6
- rucio/client/didclient.py +321 -133
- rucio/client/diracclient.py +13 -6
- rucio/client/downloadclient.py +435 -165
- rucio/client/exportclient.py +8 -2
- rucio/client/fileclient.py +10 -3
- rucio/client/importclient.py +4 -1
- rucio/client/lifetimeclient.py +48 -31
- rucio/client/lockclient.py +22 -7
- rucio/client/metaconventionsclient.py +59 -21
- rucio/client/pingclient.py +3 -1
- rucio/client/replicaclient.py +213 -96
- rucio/client/requestclient.py +123 -16
- rucio/client/rseclient.py +385 -160
- rucio/client/ruleclient.py +147 -51
- rucio/client/scopeclient.py +35 -10
- rucio/client/subscriptionclient.py +60 -27
- rucio/client/touchclient.py +16 -7
- rucio/vcsversion.py +3 -3
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/data/etc/rucio.cfg.template +0 -1
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/METADATA +1 -1
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/RECORD +38 -38
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/WHEEL +1 -1
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/data/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/data/requirements.client.txt +0 -0
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/data/rucio_client/merge_rucio_configs.py +0 -0
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/scripts/rucio +0 -0
- {rucio_clients-37.3.0.data → rucio_clients-37.4.0.data}/scripts/rucio-admin +0 -0
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/licenses/LICENSE +0 -0
- {rucio_clients-37.3.0.dist-info → rucio_clients-37.4.0.dist-info}/top_level.txt +0 -0
rucio/client/baseclient.py
CHANGED
|
@@ -23,7 +23,7 @@ import secrets
|
|
|
23
23
|
import sys
|
|
24
24
|
import time
|
|
25
25
|
from configparser import NoOptionError, NoSectionError
|
|
26
|
-
from os import environ, fdopen, geteuid, makedirs
|
|
26
|
+
from os import environ, fdopen, geteuid, makedirs
|
|
27
27
|
from shutil import move
|
|
28
28
|
from tempfile import mkstemp
|
|
29
29
|
from typing import TYPE_CHECKING, Any, Optional
|
|
@@ -37,7 +37,7 @@ from requests.status_codes import codes
|
|
|
37
37
|
|
|
38
38
|
from rucio import version
|
|
39
39
|
from rucio.common import exception
|
|
40
|
-
from rucio.common.config import config_get, config_get_bool, config_get_int
|
|
40
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int, config_has_section
|
|
41
41
|
from rucio.common.exception import CannotAuthenticate, ClientProtocolNotFound, ClientProtocolNotSupported, ConfigNotFound, MissingClientParameter, MissingModuleException, NoAuthInformation, ServerConnectionException
|
|
42
42
|
from rucio.common.extra import import_extras
|
|
43
43
|
from rucio.common.utils import build_url, get_tmp_dir, my_key_generator, parse_response, setup_logger, ssh_sign
|
|
@@ -73,6 +73,14 @@ def choice(hosts):
|
|
|
73
73
|
return secrets.choice(hosts)
|
|
74
74
|
|
|
75
75
|
|
|
76
|
+
def _expand_path(path: str) -> str:
|
|
77
|
+
"""Fully expand path, including ~ and env variables"""
|
|
78
|
+
path = path.strip()
|
|
79
|
+
if path == '':
|
|
80
|
+
return ''
|
|
81
|
+
return os.path.abspath(os.path.expanduser(os.path.expandvars(path)))
|
|
82
|
+
|
|
83
|
+
|
|
76
84
|
class BaseClient:
|
|
77
85
|
|
|
78
86
|
"""Main client class for accessing Rucio resources. Handles the authentication."""
|
|
@@ -95,15 +103,29 @@ class BaseClient:
|
|
|
95
103
|
logger: 'Logger' = LOG) -> None:
|
|
96
104
|
"""
|
|
97
105
|
Constructor of the BaseClient.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
rucio_host :
|
|
110
|
+
The address of the rucio server, if None it is read from the config file.
|
|
111
|
+
auth_host :
|
|
112
|
+
The address of the rucio authentication server, if None it is read from the config file.
|
|
113
|
+
account :
|
|
114
|
+
The account to authenticate to rucio.
|
|
115
|
+
ca_cert :
|
|
116
|
+
The path to the rucio server certificate.
|
|
117
|
+
auth_type :
|
|
118
|
+
The type of authentication (e.g.: 'userpass', 'kerberos' ...)
|
|
119
|
+
creds :
|
|
120
|
+
Dictionary with credentials needed for authentication.
|
|
121
|
+
timeout :
|
|
122
|
+
Timeout for requests.
|
|
123
|
+
user_agent :
|
|
124
|
+
Indicates the client.
|
|
125
|
+
vo :
|
|
126
|
+
The VO to authenticate into.
|
|
127
|
+
logger :
|
|
128
|
+
Logger object to use. If None, use the default LOG created by the module.
|
|
107
129
|
"""
|
|
108
130
|
|
|
109
131
|
self.logger = logger
|
|
@@ -173,7 +195,7 @@ class BaseClient:
|
|
|
173
195
|
if self.ca_cert is None:
|
|
174
196
|
self.logger.debug('HTTPS is required, but no ca_cert was passed and X509_CERT_DIR is not defined. Trying to get it from the config file.')
|
|
175
197
|
try:
|
|
176
|
-
self.ca_cert =
|
|
198
|
+
self.ca_cert = _expand_path(config_get('client', 'ca_cert'))
|
|
177
199
|
except (NoOptionError, NoSectionError):
|
|
178
200
|
self.logger.debug('No ca_cert found in configuration. Falling back to Mozilla default CA bundle (certifi).')
|
|
179
201
|
self.ca_cert = True
|
|
@@ -289,46 +311,61 @@ class BaseClient:
|
|
|
289
311
|
creds['client_cert'] = environ["RUCIO_CLIENT_CERT"]
|
|
290
312
|
else:
|
|
291
313
|
creds['client_cert'] = config_get('client', 'client_cert')
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
314
|
+
|
|
315
|
+
creds['client_cert'] = _expand_path(creds['client_cert'])
|
|
316
|
+
|
|
317
|
+
if not os.path.exists(creds['client_cert']):
|
|
318
|
+
raise MissingClientParameter('X.509 client certificate not found: %r' % creds['client_cert'])
|
|
295
319
|
|
|
296
320
|
if 'client_key' not in creds or creds['client_key'] is None:
|
|
297
321
|
if "RUCIO_CLIENT_KEY" in environ:
|
|
298
322
|
creds['client_key'] = environ["RUCIO_CLIENT_KEY"]
|
|
299
323
|
else:
|
|
300
324
|
creds['client_key'] = config_get('client', 'client_key')
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
325
|
+
|
|
326
|
+
creds['client_key'] = _expand_path(creds['client_key'])
|
|
327
|
+
if not os.path.exists(creds['client_key']):
|
|
328
|
+
raise MissingClientParameter('X.509 client key not found: %r' % creds['client_key'])
|
|
329
|
+
|
|
330
|
+
perms = oct(os.stat(creds['client_key']).st_mode)[-3:]
|
|
331
|
+
if perms not in ['400', '600']:
|
|
332
|
+
raise CannotAuthenticate('X.509 authentication selected, but private key (%s) permissions are liberal (required: 400 or 600, found: %s)' % (creds['client_key'], perms))
|
|
308
333
|
|
|
309
334
|
elif self.auth_type == 'x509_proxy':
|
|
335
|
+
# rucio specific configuration takes precedence over GSI logic
|
|
336
|
+
# environment variables take precedence over config values
|
|
337
|
+
# So we check in order:
|
|
338
|
+
# RUCIO_CLIENT_PROXY env variable
|
|
339
|
+
# client.client_x509_proxy rucio cfg variable
|
|
340
|
+
# X509_USER_PROXY env variable
|
|
341
|
+
# /tmp/x509up_u`id -u` if exists
|
|
342
|
+
|
|
343
|
+
gsi_proxy_path = '/tmp/x509up_u%d' % geteuid()
|
|
310
344
|
if 'client_proxy' not in creds or creds['client_proxy'] is None:
|
|
311
|
-
|
|
312
|
-
creds['client_proxy'] =
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
'\'x509_proxy\' not set in the configuration file.' % fname)
|
|
345
|
+
if 'RUCIO_CLIENT_PROXY' in environ:
|
|
346
|
+
creds['client_proxy'] = environ['RUCIO_CLIENT_PROXY']
|
|
347
|
+
elif config_has_section('client') and config_get('client', 'client_x509_proxy', default='') != '':
|
|
348
|
+
creds['client_proxy'] = config_get('client', 'client_x509_proxy')
|
|
349
|
+
elif 'X509_USER_PROXY' in environ:
|
|
350
|
+
creds['client_proxy'] = environ['X509_USER_PROXY']
|
|
351
|
+
elif os.path.isfile(gsi_proxy_path):
|
|
352
|
+
creds['client_proxy'] = gsi_proxy_path
|
|
353
|
+
|
|
354
|
+
creds['client_proxy'] = _expand_path(creds['client_proxy'])
|
|
355
|
+
|
|
356
|
+
if not os.path.isfile(creds['client_proxy']):
|
|
357
|
+
raise MissingClientParameter(
|
|
358
|
+
'Cannot find a valid X509 proxy; checked $RUCIO_CLIENT_PROXY, $X509_USER_PROXY'
|
|
359
|
+
'client/client_x509_proxy config and default path: %r' % gsi_proxy_path
|
|
360
|
+
)
|
|
328
361
|
|
|
329
362
|
elif self.auth_type == 'ssh':
|
|
330
363
|
if 'ssh_private_key' not in creds or creds['ssh_private_key'] is None:
|
|
331
|
-
creds['ssh_private_key'] =
|
|
364
|
+
creds['ssh_private_key'] = config_get('client', 'ssh_private_key')
|
|
365
|
+
|
|
366
|
+
creds['ssh_private_key'] = _expand_path(creds['ssh_private_key'])
|
|
367
|
+
if not os.path.isfile(creds["ssh_private_key"]):
|
|
368
|
+
raise CannotAuthenticate('Provided ssh private key %r does not exist' % creds['ssh_private_key'])
|
|
332
369
|
|
|
333
370
|
except (NoOptionError, NoSectionError) as error:
|
|
334
371
|
if error.args[0] != 'client_key':
|
|
@@ -535,11 +572,11 @@ class BaseClient:
|
|
|
535
572
|
|
|
536
573
|
if not self.auth_oidc_refresh_active:
|
|
537
574
|
return False
|
|
538
|
-
if path.exists(self.token_exp_epoch_file):
|
|
575
|
+
if os.path.exists(self.token_exp_epoch_file):
|
|
539
576
|
with open(self.token_exp_epoch_file, 'r') as token_epoch_file:
|
|
540
577
|
try:
|
|
541
578
|
self.token_exp_epoch = int(token_epoch_file.readline())
|
|
542
|
-
except:
|
|
579
|
+
except Exception:
|
|
543
580
|
self.token_exp_epoch = None
|
|
544
581
|
|
|
545
582
|
if self.token_exp_epoch is None:
|
|
@@ -718,10 +755,10 @@ class BaseClient:
|
|
|
718
755
|
url = build_url(self.auth_host, path='auth/x509_proxy')
|
|
719
756
|
client_cert = self.creds['client_proxy']
|
|
720
757
|
|
|
721
|
-
if (client_cert is not None) and not (path.exists(client_cert)):
|
|
758
|
+
if (client_cert is not None) and not (os.path.exists(client_cert)):
|
|
722
759
|
self.logger.error('given client cert (%s) doesn\'t exist' % client_cert)
|
|
723
760
|
return False
|
|
724
|
-
if client_key is not None and not path.exists(client_key):
|
|
761
|
+
if client_key is not None and not os.path.exists(client_key):
|
|
725
762
|
self.logger.error('given client key (%s) doesn\'t exist' % client_key)
|
|
726
763
|
|
|
727
764
|
if client_key is None:
|
|
@@ -755,10 +792,10 @@ class BaseClient:
|
|
|
755
792
|
headers = {}
|
|
756
793
|
|
|
757
794
|
private_key_path = self.creds['ssh_private_key']
|
|
758
|
-
if not path.exists(private_key_path):
|
|
795
|
+
if not os.path.exists(private_key_path):
|
|
759
796
|
self.logger.error('given private key (%s) doesn\'t exist' % private_key_path)
|
|
760
797
|
return False
|
|
761
|
-
if private_key_path is not None and not path.exists(private_key_path):
|
|
798
|
+
if private_key_path is not None and not os.path.exists(private_key_path):
|
|
762
799
|
self.logger.error('given private key (%s) doesn\'t exist' % private_key_path)
|
|
763
800
|
return False
|
|
764
801
|
|
|
@@ -906,7 +943,7 @@ class BaseClient:
|
|
|
906
943
|
|
|
907
944
|
:return: True if a token could be read. False if no file exists.
|
|
908
945
|
"""
|
|
909
|
-
if not path.exists(self.token_file):
|
|
946
|
+
if not os.path.exists(self.token_file):
|
|
910
947
|
return False
|
|
911
948
|
|
|
912
949
|
try:
|
|
@@ -927,7 +964,7 @@ class BaseClient:
|
|
|
927
964
|
Write the current auth_token to the local token file.
|
|
928
965
|
"""
|
|
929
966
|
# check if rucio temp directory is there. If not create it with permissions only for the current user
|
|
930
|
-
if not path.isdir(self.token_path):
|
|
967
|
+
if not os.path.isdir(self.token_path):
|
|
931
968
|
try:
|
|
932
969
|
self.logger.debug('rucio token folder \'%s\' not found. Create it.' % self.token_path)
|
|
933
970
|
makedirs(self.token_path, 0o700)
|
rucio/client/client.py
CHANGED
|
@@ -58,63 +58,71 @@ class Client(AccountClient,
|
|
|
58
58
|
LifetimeClient):
|
|
59
59
|
|
|
60
60
|
"""
|
|
61
|
-
|
|
61
|
+
Main client class for accessing Rucio resources. Handles the authentication.
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Note:
|
|
64
|
+
------
|
|
65
|
+
Used to access all client methods. Each entity client *can* be used to access methods, but using the main client class is recommended for ease of use.
|
|
65
66
|
|
|
66
|
-
For using general methods -
|
|
67
67
|
|
|
68
|
+
Example:
|
|
69
|
+
-------
|
|
70
|
+
from rucio.client import Client
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
client = Client() # authenticate with config or environ settings
|
|
73
|
+
client.add_replication_rule(...)
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
client = Client(
|
|
76
|
+
rucio_host = "my_host",
|
|
77
|
+
auth_host = "my_auth_host",
|
|
78
|
+
account = "jdoe12345",
|
|
79
|
+
auth_type = "userpass",
|
|
80
|
+
creds = {
|
|
81
|
+
"username": "jdoe12345",
|
|
82
|
+
"password": "******",
|
|
83
|
+
}
|
|
84
|
+
) # authenticate with kwargs
|
|
85
|
+
client.list_replicas(...)
|
|
74
86
|
|
|
75
|
-
client = Client(
|
|
76
|
-
rucio_host = "my_host",
|
|
77
|
-
auth_host = "my_auth_host",
|
|
78
|
-
account = "jdoe12345",
|
|
79
|
-
auth_type = "userpass",
|
|
80
|
-
creds = {
|
|
81
|
-
"username": "jdoe12345",
|
|
82
|
-
"password": "******",
|
|
83
|
-
}
|
|
84
|
-
) # authenticate with kwargs
|
|
85
|
-
client.list_replicas(...)
|
|
86
|
-
```
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
# For using the upload and download clients
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
from rucio.client.downloadclient import DownloadClient
|
|
90
|
+
from rucio.client import Client
|
|
91
|
+
from rucio.client.uploadclient import UploadClient
|
|
92
|
+
from rucio.client.downloadclient import DownloadClient
|
|
94
93
|
|
|
95
|
-
|
|
94
|
+
client = Client(...) # Initialize a client using your preferred method
|
|
96
95
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
download_client = DownloadClient(client)
|
|
101
|
-
download_client.download_dids(items=...)
|
|
102
|
-
```
|
|
96
|
+
upload_client = UploadClient(client) # Pass forward the initialized client
|
|
97
|
+
upload_client.upload(items=...)
|
|
103
98
|
|
|
99
|
+
download_client = DownloadClient(client)
|
|
100
|
+
download_client.download_dids(items=...)
|
|
104
101
|
"""
|
|
105
102
|
|
|
106
103
|
def __init__(self, **args):
|
|
107
104
|
"""
|
|
108
105
|
Constructor for the Rucio main client class.
|
|
109
106
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
rucio_host :
|
|
110
|
+
The host of the rucio system.
|
|
111
|
+
auth_host :
|
|
112
|
+
The host of the rucio authentication server.
|
|
113
|
+
account :
|
|
114
|
+
The rucio account that should be used to interact with the rucio system.
|
|
115
|
+
ca_cert :
|
|
116
|
+
The certificate to verify the server.
|
|
117
|
+
auth_type :
|
|
118
|
+
The type of authentication to use (e.g. userpass, x509 ...).
|
|
119
|
+
creds :
|
|
120
|
+
Credentials needed for authentication.
|
|
121
|
+
timeout :
|
|
122
|
+
Describes the timeout of the request (in seconds).
|
|
123
|
+
vo :
|
|
124
|
+
The vo that the client will interact with.
|
|
125
|
+
logger :
|
|
126
|
+
Logger instance to use.
|
|
119
127
|
"""
|
|
120
128
|
super(Client, self).__init__(**args)
|
rucio/client/configclient.py
CHANGED
|
@@ -35,9 +35,12 @@ class ConfigClient(BaseClient):
|
|
|
35
35
|
"""
|
|
36
36
|
Sends the request to get the matching configuration.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
:
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
section :
|
|
41
|
+
The name of the section.
|
|
42
|
+
option :
|
|
43
|
+
The option within the section.
|
|
41
44
|
"""
|
|
42
45
|
|
|
43
46
|
if section is None and option is not None:
|
|
@@ -68,18 +71,30 @@ class ConfigClient(BaseClient):
|
|
|
68
71
|
"""
|
|
69
72
|
Sends the request to create or set an option within a section. Missing sections will be created.
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
section :
|
|
77
|
+
The name of the section.
|
|
78
|
+
option :
|
|
79
|
+
The name of the option.
|
|
80
|
+
value :
|
|
81
|
+
The value to set on the config option.
|
|
82
|
+
use_body_for_params :
|
|
83
|
+
Send parameters in a json-encoded request body instead of url-encoded.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
bool
|
|
88
|
+
True if option was set successfully.
|
|
89
|
+
|
|
90
|
+
Note:
|
|
91
|
+
------
|
|
76
92
|
The format of the /config endpoint was recently changed. We migrated from performing a PUT on
|
|
77
93
|
"/config/<section>/<option>/<value>" to sending the parameters using a json-encoded body.
|
|
78
94
|
This was done to fix multiple un-wanted side effects related to how the middleware treats
|
|
79
95
|
values encoded in a path.
|
|
80
96
|
For a smooth transition, we allow both cases for now, but we should migrate to only passing
|
|
81
97
|
values via the request body.
|
|
82
|
-
:return: True if option was removed successfully. False otherwise.
|
|
83
98
|
"""
|
|
84
99
|
|
|
85
100
|
if use_body_for_params:
|
|
@@ -107,11 +122,19 @@ class ConfigClient(BaseClient):
|
|
|
107
122
|
option: str
|
|
108
123
|
) -> bool:
|
|
109
124
|
"""
|
|
110
|
-
Sends the request to remove an option from a section
|
|
125
|
+
Sends the request to remove an option from a section.
|
|
111
126
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
:
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
section :
|
|
130
|
+
The name of the section.
|
|
131
|
+
option :
|
|
132
|
+
The name of the option.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
|
|
137
|
+
True if option was removed successfully.
|
|
115
138
|
"""
|
|
116
139
|
|
|
117
140
|
path = '/'.join([self.CONFIG_BASEURL, section, option])
|
rucio/client/credentialclient.py
CHANGED
|
@@ -34,13 +34,23 @@ class CredentialClient(BaseClient):
|
|
|
34
34
|
"""
|
|
35
35
|
Return a signed version of the given URL for the given operation.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
rse :
|
|
40
|
+
The name of the RSE the URL points to.
|
|
41
|
+
service :
|
|
42
|
+
The service the URL points to (gcs, s3, swift)
|
|
43
|
+
operation :
|
|
44
|
+
The desired operation (read, write, delete)
|
|
45
|
+
url :
|
|
46
|
+
The URL to sign
|
|
47
|
+
lifetime :
|
|
48
|
+
The desired lifetime of the URL in seconds, by default 3600
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
|
|
53
|
+
The signed URL string
|
|
44
54
|
"""
|
|
45
55
|
path = '/'.join([self.CREDENTIAL_BASEURL, 'signurl'])
|
|
46
56
|
params = {}
|