rucio-clients 32.8.6__py3-none-any.whl → 35.8.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/__init__.py +0 -1
- rucio/alembicrevision.py +1 -2
- rucio/client/__init__.py +0 -1
- rucio/client/accountclient.py +45 -25
- rucio/client/accountlimitclient.py +37 -9
- rucio/client/baseclient.py +199 -154
- rucio/client/client.py +2 -3
- rucio/client/configclient.py +19 -6
- rucio/client/credentialclient.py +9 -4
- rucio/client/didclient.py +238 -63
- rucio/client/diracclient.py +13 -5
- rucio/client/downloadclient.py +162 -51
- rucio/client/exportclient.py +4 -4
- rucio/client/fileclient.py +3 -4
- rucio/client/importclient.py +4 -4
- rucio/client/lifetimeclient.py +21 -5
- rucio/client/lockclient.py +18 -8
- rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
- rucio/client/pingclient.py +0 -1
- rucio/client/replicaclient.py +15 -5
- rucio/client/requestclient.py +35 -19
- rucio/client/rseclient.py +133 -51
- rucio/client/ruleclient.py +29 -22
- rucio/client/scopeclient.py +8 -6
- rucio/client/subscriptionclient.py +47 -35
- rucio/client/touchclient.py +8 -4
- rucio/client/uploadclient.py +166 -82
- rucio/common/__init__.py +0 -1
- rucio/common/cache.py +4 -4
- rucio/common/config.py +52 -47
- rucio/common/constants.py +69 -2
- rucio/common/constraints.py +0 -1
- rucio/common/didtype.py +24 -22
- rucio/common/exception.py +281 -222
- rucio/common/extra.py +0 -1
- rucio/common/logging.py +54 -38
- rucio/common/pcache.py +122 -101
- rucio/common/plugins.py +153 -0
- rucio/common/policy.py +4 -4
- rucio/common/schema/__init__.py +17 -10
- rucio/common/schema/atlas.py +7 -5
- rucio/common/schema/belleii.py +7 -5
- rucio/common/schema/domatpc.py +7 -5
- rucio/common/schema/escape.py +7 -5
- rucio/common/schema/generic.py +8 -6
- rucio/common/schema/generic_multi_vo.py +7 -5
- rucio/common/schema/icecube.py +7 -5
- rucio/common/stomp_utils.py +0 -1
- rucio/common/stopwatch.py +0 -1
- rucio/common/test_rucio_server.py +2 -2
- rucio/common/types.py +262 -17
- rucio/common/utils.py +743 -451
- rucio/rse/__init__.py +3 -4
- rucio/rse/protocols/__init__.py +0 -1
- rucio/rse/protocols/bittorrent.py +184 -0
- rucio/rse/protocols/cache.py +1 -2
- rucio/rse/protocols/dummy.py +1 -2
- rucio/rse/protocols/gfal.py +12 -10
- rucio/rse/protocols/globus.py +7 -7
- rucio/rse/protocols/gsiftp.py +2 -3
- rucio/rse/protocols/http_cache.py +1 -2
- rucio/rse/protocols/mock.py +1 -2
- rucio/rse/protocols/ngarc.py +1 -2
- rucio/rse/protocols/posix.py +12 -13
- rucio/rse/protocols/protocol.py +116 -52
- rucio/rse/protocols/rclone.py +6 -7
- rucio/rse/protocols/rfio.py +4 -5
- rucio/rse/protocols/srm.py +9 -10
- rucio/rse/protocols/ssh.py +8 -9
- rucio/rse/protocols/storm.py +2 -3
- rucio/rse/protocols/webdav.py +17 -14
- rucio/rse/protocols/xrootd.py +23 -17
- rucio/rse/rsemanager.py +19 -7
- rucio/vcsversion.py +4 -4
- rucio/version.py +5 -13
- rucio_clients-35.8.0.data/data/requirements.client.txt +15 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/rucio_client/merge_rucio_configs.py +2 -5
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio +87 -85
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio-admin +45 -32
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/METADATA +13 -13
- rucio_clients-35.8.0.dist-info/RECORD +88 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/WHEEL +1 -1
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/common/schema/cms.py +0 -478
- rucio/common/schema/lsst.py +0 -423
- rucio_clients-32.8.6.data/data/requirements.txt +0 -55
- rucio_clients-32.8.6.dist-info/RECORD +0 -88
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.template +0 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/LICENSE +0 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/top_level.txt +0 -0
rucio/rse/__init__.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -47,8 +46,8 @@ def get_signed_url_server(rse, service, op, url, vo='def'):
|
|
|
47
46
|
'''
|
|
48
47
|
get_signed_url_server
|
|
49
48
|
'''
|
|
50
|
-
from rucio.core.rse import get_rse_id
|
|
51
49
|
from rucio.core.credential import get_signed_url
|
|
50
|
+
from rucio.core.rse import get_rse_id
|
|
52
51
|
|
|
53
52
|
rse_id = get_rse_id(rse=rse, vo=vo)
|
|
54
53
|
return get_signed_url(rse_id, service, op, url)
|
|
@@ -78,9 +77,9 @@ if rsemanager.CLIENT_MODE: # pylint:disable=no-member
|
|
|
78
77
|
|
|
79
78
|
|
|
80
79
|
if rsemanager.SERVER_MODE: # pylint:disable=no-member
|
|
81
|
-
from rucio.core.rse import get_rse_protocols, get_rse_id
|
|
82
|
-
from rucio.core.vo import map_vo
|
|
83
80
|
from rucio.common.cache import make_region_memcached
|
|
81
|
+
from rucio.core.rse import get_rse_id, get_rse_protocols
|
|
82
|
+
from rucio.core.vo import map_vo
|
|
84
83
|
|
|
85
84
|
def tmp_rse_info(rse=None, vo='def', rse_id=None, session=None):
|
|
86
85
|
if rse_id is None:
|
rucio/rse/protocols/__init__.py
CHANGED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import base64
|
|
16
|
+
import logging
|
|
17
|
+
import os.path
|
|
18
|
+
import time
|
|
19
|
+
from urllib.parse import parse_qs, urlencode, urlparse
|
|
20
|
+
|
|
21
|
+
from rucio.common import exception
|
|
22
|
+
from rucio.common.extra import import_extras
|
|
23
|
+
from rucio.common.utils import construct_torrent, resolve_ip
|
|
24
|
+
from rucio.rse import rsemanager
|
|
25
|
+
from rucio.rse.protocols.protocol import RSEProtocol
|
|
26
|
+
|
|
27
|
+
EXTRA_MODULES = import_extras(['libtorrent'])
|
|
28
|
+
|
|
29
|
+
lt = None
|
|
30
|
+
if EXTRA_MODULES['libtorrent']:
|
|
31
|
+
import libtorrent as lt # pylint: disable=E0401
|
|
32
|
+
|
|
33
|
+
if getattr(rsemanager, 'CLIENT_MODE', None):
|
|
34
|
+
from rucio.client.didclient import DIDClient
|
|
35
|
+
|
|
36
|
+
def _fetch_meta_client(rse_id: str, scope: str, name: str):
|
|
37
|
+
return DIDClient().get_metadata(scope=scope, name=name, plugin='all')
|
|
38
|
+
|
|
39
|
+
_fetch_meta = _fetch_meta_client
|
|
40
|
+
else:
|
|
41
|
+
from rucio.common.types import InternalScope
|
|
42
|
+
from rucio.core.did import get_metadata
|
|
43
|
+
from rucio.core.rse import get_rse_vo
|
|
44
|
+
|
|
45
|
+
def _fetch_meta_server(rse_id: str, scope: str, name: str):
|
|
46
|
+
vo = get_rse_vo(rse_id)
|
|
47
|
+
return get_metadata(scope=InternalScope(scope, vo=vo), name=name, plugin='all')
|
|
48
|
+
|
|
49
|
+
_fetch_meta = _fetch_meta_server
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Default(RSEProtocol):
|
|
53
|
+
|
|
54
|
+
def __init__(self, protocol_attr, rse_settings, logger=logging.log):
|
|
55
|
+
super(Default, self).__init__(protocol_attr, rse_settings, logger=logger)
|
|
56
|
+
self.logger = logger
|
|
57
|
+
|
|
58
|
+
def lfns2pfns(self, lfns):
|
|
59
|
+
pfns = {}
|
|
60
|
+
prefix = self.attributes['prefix']
|
|
61
|
+
|
|
62
|
+
if not prefix.startswith('/'):
|
|
63
|
+
prefix = ''.join(['/', prefix])
|
|
64
|
+
if not prefix.endswith('/'):
|
|
65
|
+
prefix = ''.join([prefix, '/'])
|
|
66
|
+
|
|
67
|
+
host_port = '%s:%s' % (self.attributes['hostname'], str(self.attributes['port']))
|
|
68
|
+
|
|
69
|
+
lfns = [lfns] if isinstance(lfns, dict) else lfns
|
|
70
|
+
for lfn in lfns:
|
|
71
|
+
scope, name = lfn['scope'], lfn['name']
|
|
72
|
+
|
|
73
|
+
if 'path' in lfn and lfn['path'] is not None:
|
|
74
|
+
path = lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]
|
|
75
|
+
else:
|
|
76
|
+
path = self._get_path(scope=scope, name=name)
|
|
77
|
+
|
|
78
|
+
scope_name = '%s:%s' % (scope, name)
|
|
79
|
+
|
|
80
|
+
query = {
|
|
81
|
+
'x.pe': host_port,
|
|
82
|
+
'x.rucio_scope': scope,
|
|
83
|
+
'x.rucio_name': name,
|
|
84
|
+
'x.rucio_path': ''.join((prefix, path))
|
|
85
|
+
}
|
|
86
|
+
pfns[scope_name] = 'magnet:?' + urlencode(query)
|
|
87
|
+
|
|
88
|
+
return pfns
|
|
89
|
+
|
|
90
|
+
def parse_pfns(self, pfns):
|
|
91
|
+
ret = dict()
|
|
92
|
+
pfns = [pfns] if isinstance(pfns, str) else pfns
|
|
93
|
+
|
|
94
|
+
for pfn in pfns:
|
|
95
|
+
parsed = urlparse(pfn)
|
|
96
|
+
scheme = parsed.scheme
|
|
97
|
+
|
|
98
|
+
query = parse_qs(parsed.query)
|
|
99
|
+
host_port = next(iter(query.get('x.pe', [])), ':')
|
|
100
|
+
hostname, port = host_port.split(':')
|
|
101
|
+
port = int(port)
|
|
102
|
+
path = next(iter(query.get('x.rucio_path', [])), '')
|
|
103
|
+
scope = next(iter(query.get('x.rucio_scope', [])), '')
|
|
104
|
+
name = next(iter(query.get('x.rucio_name', [])), '')
|
|
105
|
+
|
|
106
|
+
# Protect against 'lazy' defined prefixes for RSEs in the repository
|
|
107
|
+
if not self.attributes['prefix'].startswith('/'):
|
|
108
|
+
self.attributes['prefix'] = '/' + self.attributes['prefix']
|
|
109
|
+
if not self.attributes['prefix'].endswith('/'):
|
|
110
|
+
self.attributes['prefix'] += '/'
|
|
111
|
+
|
|
112
|
+
if self.attributes['hostname'] != hostname:
|
|
113
|
+
if self.attributes['hostname'] != 'localhost': # In the database empty hostnames are replaced with localhost but for some URIs (e.g. file) a hostname is not included
|
|
114
|
+
raise exception.RSEFileNameNotSupported('Invalid hostname: provided \'%s\', expected \'%s\'' % (hostname, self.attributes['hostname']))
|
|
115
|
+
|
|
116
|
+
if self.attributes['port'] != port:
|
|
117
|
+
raise exception.RSEFileNameNotSupported('Invalid port: provided \'%s\', expected \'%s\'' % (port, self.attributes['port']))
|
|
118
|
+
|
|
119
|
+
if not path.startswith(self.attributes['prefix']):
|
|
120
|
+
raise exception.RSEFileNameNotSupported('Invalid prefix: provided \'%s\', expected \'%s\'' % ('/'.join(path.split('/')[0:len(self.attributes['prefix'].split('/')) - 1]),
|
|
121
|
+
self.attributes['prefix'])) # len(...)-1 due to the leading '/
|
|
122
|
+
|
|
123
|
+
# Splitting parsed.path into prefix, path, filename
|
|
124
|
+
prefix = self.attributes['prefix']
|
|
125
|
+
path = path.partition(self.attributes['prefix'])[2]
|
|
126
|
+
path = '/'.join(path.split('/')[:-1])
|
|
127
|
+
if not path.startswith('/'):
|
|
128
|
+
path = '/' + path
|
|
129
|
+
if path != '/' and not path.endswith('/'):
|
|
130
|
+
path = path + '/'
|
|
131
|
+
ret[pfn] = {'path': path, 'scope': scope, 'name': name, 'scheme': scheme, 'prefix': prefix, 'port': port, 'hostname': hostname, }
|
|
132
|
+
|
|
133
|
+
return ret
|
|
134
|
+
|
|
135
|
+
def connect(self):
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
def close(self):
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
def get(self, path, dest, transfer_timeout=None):
|
|
142
|
+
if not lt:
|
|
143
|
+
raise exception.RucioException('The libtorrent python package is required to perform this operation')
|
|
144
|
+
|
|
145
|
+
[lfn] = self.parse_pfns([path]).values()
|
|
146
|
+
scope = lfn['scope']
|
|
147
|
+
name = lfn['name']
|
|
148
|
+
hostname = lfn['hostname']
|
|
149
|
+
port = lfn['port']
|
|
150
|
+
|
|
151
|
+
meta = _fetch_meta(rse_id=self.rse['id'], scope=scope, name=name)
|
|
152
|
+
pieces_root = base64.b64decode(meta.get('bittorrent_pieces_root', ''))
|
|
153
|
+
if not pieces_root:
|
|
154
|
+
raise exception.RucioException('Torrent metadata missing. Cannot download file.')
|
|
155
|
+
|
|
156
|
+
length = meta.get('bytes')
|
|
157
|
+
piece_length = meta.get('bittorrent_piece_length', 0)
|
|
158
|
+
pieces_layers = base64.b64decode(meta.get('bittorrent_pieces_layers', ''))
|
|
159
|
+
|
|
160
|
+
_, torrent = construct_torrent(
|
|
161
|
+
scope=scope,
|
|
162
|
+
name=name,
|
|
163
|
+
length=length,
|
|
164
|
+
piece_length=piece_length,
|
|
165
|
+
pieces_root=pieces_root,
|
|
166
|
+
pieces_layers=pieces_layers,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
ses = lt.session() # type: ignore # noqa
|
|
170
|
+
params = {
|
|
171
|
+
'ti': lt.torrent_info(torrent), # type: ignore # noqa
|
|
172
|
+
'save_path': os.path.dirname(dest),
|
|
173
|
+
'name': os.path.basename(dest),
|
|
174
|
+
'renamed_files': {0: os.path.basename(dest)},
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
handle = ses.add_torrent(params)
|
|
178
|
+
try:
|
|
179
|
+
handle.resume()
|
|
180
|
+
handle.connect_peer((resolve_ip(hostname), port))
|
|
181
|
+
while handle.status().progress != 1.0:
|
|
182
|
+
time.sleep(0.25)
|
|
183
|
+
finally:
|
|
184
|
+
ses.remove_torrent(handle)
|
rucio/rse/protocols/cache.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -41,7 +40,7 @@ class Default(protocol.RSEProtocol):
|
|
|
41
40
|
|
|
42
41
|
def path2pfn(self, path):
|
|
43
42
|
"""
|
|
44
|
-
|
|
43
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
45
44
|
|
|
46
45
|
:param path: The path to the file.
|
|
47
46
|
|
rucio/rse/protocols/dummy.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -30,7 +29,7 @@ class Default(protocol.RSEProtocol):
|
|
|
30
29
|
|
|
31
30
|
def path2pfn(self, path):
|
|
32
31
|
"""
|
|
33
|
-
|
|
32
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
34
33
|
|
|
35
34
|
:param path: The path to the file.
|
|
36
35
|
|
rucio/rse/protocols/gfal.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -22,7 +21,7 @@ import subprocess
|
|
|
22
21
|
import urllib.parse as urlparse
|
|
23
22
|
from threading import Timer
|
|
24
23
|
|
|
25
|
-
from rucio.common import
|
|
24
|
+
from rucio.common import config, exception
|
|
26
25
|
from rucio.common.constraints import STRING_TYPES
|
|
27
26
|
from rucio.common.utils import GLOBALLY_SUPPORTED_CHECKSUMS, PREFERRED_CHECKSUM
|
|
28
27
|
from rucio.rse.protocols import protocol
|
|
@@ -51,7 +50,7 @@ class Default(protocol.RSEProtocol):
|
|
|
51
50
|
|
|
52
51
|
:returns: Fully qualified PFN.
|
|
53
52
|
"""
|
|
54
|
-
lfns = [lfns] if
|
|
53
|
+
lfns = [lfns] if isinstance(lfns, dict) else lfns
|
|
55
54
|
|
|
56
55
|
pfns = {}
|
|
57
56
|
prefix = self.attributes['prefix']
|
|
@@ -126,7 +125,7 @@ class Default(protocol.RSEProtocol):
|
|
|
126
125
|
if not path.startswith(self.attributes['prefix']):
|
|
127
126
|
raise exception.RSEFileNameNotSupported('Invalid prefix: provided \'%s\', expected \'%s\'' % ('/'.join(path.split('/')[0:len(self.attributes['prefix'].split('/')) - 1]),
|
|
128
127
|
self.attributes['prefix'])) # len(...)-1 due to the leading '/
|
|
129
|
-
#
|
|
128
|
+
# Splitting path into prefix, path, filename
|
|
130
129
|
prefix = self.attributes['prefix']
|
|
131
130
|
path = path.partition(self.attributes['prefix'])[2]
|
|
132
131
|
name = path.split('/')[-1]
|
|
@@ -231,7 +230,7 @@ class Default(protocol.RSEProtocol):
|
|
|
231
230
|
:param transfer_timeout: Transfer timeout (in seconds)
|
|
232
231
|
|
|
233
232
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
234
|
-
:raises ServiceUnavailable: if some generic error
|
|
233
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
235
234
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
236
235
|
"""
|
|
237
236
|
self.logger(logging.DEBUG, 'downloading file from {} to {}'.format(path, dest))
|
|
@@ -261,7 +260,7 @@ class Default(protocol.RSEProtocol):
|
|
|
261
260
|
:param transfer_timeout: Transfer timeout (in seconds)
|
|
262
261
|
|
|
263
262
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
264
|
-
:raises ServiceUnavailable: if some generic error
|
|
263
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
265
264
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
266
265
|
"""
|
|
267
266
|
self.logger(logging.DEBUG, 'uploading file from {} to {}'.format(source, target))
|
|
@@ -294,7 +293,7 @@ class Default(protocol.RSEProtocol):
|
|
|
294
293
|
|
|
295
294
|
:param path: path to the to be deleted file
|
|
296
295
|
|
|
297
|
-
:raises ServiceUnavailable: if some generic error
|
|
296
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
298
297
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
299
298
|
"""
|
|
300
299
|
self.logger(logging.DEBUG, 'deleting file {}'.format(path))
|
|
@@ -318,7 +317,7 @@ class Default(protocol.RSEProtocol):
|
|
|
318
317
|
:param new_path: path to the new file on the storage
|
|
319
318
|
|
|
320
319
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
321
|
-
:raises ServiceUnavailable: if some generic error
|
|
320
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
322
321
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
323
322
|
"""
|
|
324
323
|
self.logger(logging.DEBUG, 'renaming file from {} to {}'.format(path, new_path))
|
|
@@ -370,7 +369,7 @@ class Default(protocol.RSEProtocol):
|
|
|
370
369
|
|
|
371
370
|
:param path: path to file
|
|
372
371
|
|
|
373
|
-
:raises ServiceUnavailable: if some generic error
|
|
372
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
374
373
|
|
|
375
374
|
:returns: a dict with two keys, filesize and an element of GLOBALLY_SUPPORTED_CHECKSUMS.
|
|
376
375
|
"""
|
|
@@ -394,6 +393,9 @@ class Default(protocol.RSEProtocol):
|
|
|
394
393
|
|
|
395
394
|
ret['filesize'] = stats[7]
|
|
396
395
|
|
|
396
|
+
if not self.rse.get('verify_checksum', True):
|
|
397
|
+
return ret
|
|
398
|
+
|
|
397
399
|
message = "\n"
|
|
398
400
|
try:
|
|
399
401
|
ret[PREFERRED_CHECKSUM] = ctx.checksum(path, str(PREFERRED_CHECKSUM.upper()))
|
|
@@ -551,7 +553,7 @@ class Default(protocol.RSEProtocol):
|
|
|
551
553
|
|
|
552
554
|
:returns: a list with dict containing 'totalsize' and 'unusedsize'
|
|
553
555
|
|
|
554
|
-
:raises ServiceUnavailable: if some generic error
|
|
556
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
555
557
|
"""
|
|
556
558
|
endpoint_basepath = self.path2pfn(self.attributes['prefix'])
|
|
557
559
|
self.logger(logging.DEBUG, 'getting space usage from {}'.format(endpoint_basepath))
|
rucio/rse/protocols/globus.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -17,10 +16,11 @@ import logging
|
|
|
17
16
|
from urllib.parse import urlparse
|
|
18
17
|
|
|
19
18
|
from rucio.common import exception
|
|
19
|
+
from rucio.common.constants import RseAttr
|
|
20
20
|
from rucio.common.extra import import_extras
|
|
21
21
|
from rucio.core.rse import get_rse_attribute
|
|
22
22
|
from rucio.rse.protocols.protocol import RSEProtocol
|
|
23
|
-
from rucio.transfertool.globus_library import get_transfer_client,
|
|
23
|
+
from rucio.transfertool.globus_library import get_transfer_client, send_bulk_delete_task, send_delete_task
|
|
24
24
|
|
|
25
25
|
EXTRA_MODULES = import_extras(['globus_sdk'])
|
|
26
26
|
|
|
@@ -37,12 +37,12 @@ class GlobusRSEProtocol(RSEProtocol):
|
|
|
37
37
|
:param props: Properties of the requested protocol
|
|
38
38
|
"""
|
|
39
39
|
super(GlobusRSEProtocol, self).__init__(protocol_attr, rse_settings, logger=logger)
|
|
40
|
-
self.globus_endpoint_id = get_rse_attribute(self.rse.get('id'),
|
|
40
|
+
self.globus_endpoint_id = get_rse_attribute(self.rse.get('id'), RseAttr.GLOBUS_ENDPOINT_ID)
|
|
41
41
|
self.logger = logger
|
|
42
42
|
|
|
43
43
|
def lfns2pfns(self, lfns):
|
|
44
44
|
"""
|
|
45
|
-
|
|
45
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
46
46
|
|
|
47
47
|
:param path: The path to the file.
|
|
48
48
|
|
|
@@ -80,7 +80,7 @@ class GlobusRSEProtocol(RSEProtocol):
|
|
|
80
80
|
|
|
81
81
|
def parse_pfns(self, pfns):
|
|
82
82
|
"""
|
|
83
|
-
Splits the given PFN into the parts known by the protocol. It is also checked if the provided protocol
|
|
83
|
+
Splits the given PFN into the parts known by the protocol. It is also checked if the provided protocol supports the given PFNs.
|
|
84
84
|
|
|
85
85
|
:param pfns: a list of a fully qualified PFNs
|
|
86
86
|
|
|
@@ -117,7 +117,7 @@ class GlobusRSEProtocol(RSEProtocol):
|
|
|
117
117
|
raise exception.RSEFileNameNotSupported('Invalid prefix: provided \'%s\', expected \'%s\'' % ('/'.join(path.split('/')[0:len(self.attributes['prefix'].split('/')) - 1]),
|
|
118
118
|
self.attributes['prefix'])) # len(...)-1 due to the leading '/
|
|
119
119
|
|
|
120
|
-
#
|
|
120
|
+
# Splitting parsed.path into prefix, path, filename
|
|
121
121
|
prefix = self.attributes['prefix']
|
|
122
122
|
path = path.partition(self.attributes['prefix'])[2]
|
|
123
123
|
name = path.split('/')[-1]
|
|
@@ -190,7 +190,7 @@ class GlobusRSEProtocol(RSEProtocol):
|
|
|
190
190
|
|
|
191
191
|
:param path: path to the to be deleted file
|
|
192
192
|
|
|
193
|
-
:raises ServiceUnavailable: if some generic error
|
|
193
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
194
194
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
195
195
|
"""
|
|
196
196
|
if self.globus_endpoint_id:
|
rucio/rse/protocols/gsiftp.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -53,12 +52,12 @@ class Default(protocol.RSEProtocol):
|
|
|
53
52
|
|
|
54
53
|
:returns: a list with dict containing 'totalsize' and 'unusedsize'
|
|
55
54
|
|
|
56
|
-
:raises ServiceUnavailable: if some generic error
|
|
55
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
57
56
|
"""
|
|
58
57
|
rse_name = self.rse['rse']
|
|
59
58
|
dest = '/tmp/rucio-gsiftp-site-size_' + rse_name
|
|
60
59
|
space_usage_url = ''
|
|
61
|
-
# url of space usage json,
|
|
60
|
+
# url of space usage json, would be nicer to have it in rse_settings
|
|
62
61
|
agis = requests.get('http://atlas-agis-api.cern.ch/request/ddmendpoint/query/list/?json').json()
|
|
63
62
|
agis_token = ''
|
|
64
63
|
for res in agis:
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -42,7 +41,7 @@ class Default(ngarc.Default):
|
|
|
42
41
|
|
|
43
42
|
def path2pfn(self, path):
|
|
44
43
|
"""
|
|
45
|
-
|
|
44
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
46
45
|
|
|
47
46
|
:param path: The path to the file.
|
|
48
47
|
|
rucio/rse/protocols/mock.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -31,7 +30,7 @@ class Default(protocol.RSEProtocol):
|
|
|
31
30
|
|
|
32
31
|
def path2pfn(self, path):
|
|
33
32
|
"""
|
|
34
|
-
|
|
33
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
35
34
|
|
|
36
35
|
:param path: The path to the file.
|
|
37
36
|
|
rucio/rse/protocols/ngarc.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -65,7 +64,7 @@ class Default(protocol.RSEProtocol):
|
|
|
65
64
|
|
|
66
65
|
def path2pfn(self, path):
|
|
67
66
|
"""
|
|
68
|
-
|
|
67
|
+
Returns a fully qualified PFN for the file referred by path.
|
|
69
68
|
|
|
70
69
|
:param path: The path to the file.
|
|
71
70
|
|
rucio/rse/protocols/posix.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -48,7 +47,7 @@ class Default(protocol.RSEProtocol):
|
|
|
48
47
|
"""
|
|
49
48
|
Establishes the actual connection to the referred RSE.
|
|
50
49
|
|
|
51
|
-
:param credentials: needed to establish a connection with the
|
|
50
|
+
:param credentials: needed to establish a connection with the storage.
|
|
52
51
|
|
|
53
52
|
:raises RSEAccessDenied: if no connection could be established.
|
|
54
53
|
"""
|
|
@@ -66,17 +65,17 @@ class Default(protocol.RSEProtocol):
|
|
|
66
65
|
:param transfer_timeout Transfer timeout (in seconds) - dummy
|
|
67
66
|
|
|
68
67
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
69
|
-
:raises ServiceUnavailable: if some generic error
|
|
68
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
70
69
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
71
70
|
"""
|
|
72
71
|
try:
|
|
73
72
|
shutil.copy(self.pfn2path(pfn), dest)
|
|
74
|
-
except
|
|
75
|
-
try: # To check if the error
|
|
73
|
+
except OSError as e:
|
|
74
|
+
try: # To check if the error happened local or remote
|
|
76
75
|
with open(dest, 'wb'):
|
|
77
76
|
pass
|
|
78
|
-
call(['rm', '-rf', dest])
|
|
79
|
-
except
|
|
77
|
+
call(['rm', '-rf', dest]) # noqa: S607
|
|
78
|
+
except OSError as e:
|
|
80
79
|
if e.errno == 2:
|
|
81
80
|
raise exception.DestinationNotAccessible(e)
|
|
82
81
|
else:
|
|
@@ -96,7 +95,7 @@ class Default(protocol.RSEProtocol):
|
|
|
96
95
|
:param transfer_timeout Transfer timeout (in seconds) - dummy
|
|
97
96
|
|
|
98
97
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
99
|
-
:raises ServiceUnavailable: if some generic error
|
|
98
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
100
99
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
101
100
|
"""
|
|
102
101
|
target = self.pfn2path(target)
|
|
@@ -110,7 +109,7 @@ class Default(protocol.RSEProtocol):
|
|
|
110
109
|
if not os.path.exists(dirs):
|
|
111
110
|
os.makedirs(dirs)
|
|
112
111
|
shutil.copy(sf, target)
|
|
113
|
-
except
|
|
112
|
+
except OSError as e:
|
|
114
113
|
if e.errno == 2:
|
|
115
114
|
raise exception.SourceNotFound(e)
|
|
116
115
|
elif not self.exists(self.rse['prefix']):
|
|
@@ -127,7 +126,7 @@ class Default(protocol.RSEProtocol):
|
|
|
127
126
|
|
|
128
127
|
:param pfn: pfn to the to be deleted file
|
|
129
128
|
|
|
130
|
-
:raises ServiceUnavailable: if some generic error
|
|
129
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
131
130
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
132
131
|
"""
|
|
133
132
|
try:
|
|
@@ -143,7 +142,7 @@ class Default(protocol.RSEProtocol):
|
|
|
143
142
|
:param new_path: path to the new file on the storage
|
|
144
143
|
|
|
145
144
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
146
|
-
:raises ServiceUnavailable: if some generic error
|
|
145
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
147
146
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
148
147
|
"""
|
|
149
148
|
path = self.pfn2path(pfn)
|
|
@@ -152,7 +151,7 @@ class Default(protocol.RSEProtocol):
|
|
|
152
151
|
if not os.path.exists(os.path.dirname(new_path)):
|
|
153
152
|
os.makedirs(os.path.dirname(new_path))
|
|
154
153
|
os.rename(path, new_path)
|
|
155
|
-
except
|
|
154
|
+
except OSError as e:
|
|
156
155
|
if e.errno == 2:
|
|
157
156
|
if self.exists(self.pfn2path(path)):
|
|
158
157
|
raise exception.SourceNotFound(e)
|
|
@@ -224,7 +223,7 @@ class Symlink(Default):
|
|
|
224
223
|
:param dest: Name and path of the files when stored at the client
|
|
225
224
|
:param transfer_timeout Transfer timeout (in seconds) - dummy
|
|
226
225
|
:raises DestinationNotAccessible: if the destination storage was not accessible.
|
|
227
|
-
:raises ServiceUnavailable: if some generic error
|
|
226
|
+
:raises ServiceUnavailable: if some generic error occurred in the library.
|
|
228
227
|
:raises SourceNotFound: if the source file was not found on the referred storage.
|
|
229
228
|
"""
|
|
230
229
|
path = self.pfn2path(pfn)
|