rucio-clients 32.8.6__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.

Files changed (88) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/client/__init__.py +16 -0
  4. rucio/client/accountclient.py +413 -0
  5. rucio/client/accountlimitclient.py +155 -0
  6. rucio/client/baseclient.py +929 -0
  7. rucio/client/client.py +77 -0
  8. rucio/client/configclient.py +113 -0
  9. rucio/client/credentialclient.py +54 -0
  10. rucio/client/didclient.py +691 -0
  11. rucio/client/diracclient.py +48 -0
  12. rucio/client/downloadclient.py +1674 -0
  13. rucio/client/exportclient.py +44 -0
  14. rucio/client/fileclient.py +51 -0
  15. rucio/client/importclient.py +42 -0
  16. rucio/client/lifetimeclient.py +74 -0
  17. rucio/client/lockclient.py +99 -0
  18. rucio/client/metaclient.py +137 -0
  19. rucio/client/pingclient.py +45 -0
  20. rucio/client/replicaclient.py +444 -0
  21. rucio/client/requestclient.py +109 -0
  22. rucio/client/rseclient.py +664 -0
  23. rucio/client/ruleclient.py +287 -0
  24. rucio/client/scopeclient.py +88 -0
  25. rucio/client/subscriptionclient.py +161 -0
  26. rucio/client/touchclient.py +78 -0
  27. rucio/client/uploadclient.py +871 -0
  28. rucio/common/__init__.py +14 -0
  29. rucio/common/cache.py +74 -0
  30. rucio/common/config.py +796 -0
  31. rucio/common/constants.py +92 -0
  32. rucio/common/constraints.py +18 -0
  33. rucio/common/didtype.py +187 -0
  34. rucio/common/exception.py +1092 -0
  35. rucio/common/extra.py +37 -0
  36. rucio/common/logging.py +404 -0
  37. rucio/common/pcache.py +1387 -0
  38. rucio/common/policy.py +84 -0
  39. rucio/common/schema/__init__.py +143 -0
  40. rucio/common/schema/atlas.py +411 -0
  41. rucio/common/schema/belleii.py +406 -0
  42. rucio/common/schema/cms.py +478 -0
  43. rucio/common/schema/domatpc.py +399 -0
  44. rucio/common/schema/escape.py +424 -0
  45. rucio/common/schema/generic.py +431 -0
  46. rucio/common/schema/generic_multi_vo.py +410 -0
  47. rucio/common/schema/icecube.py +404 -0
  48. rucio/common/schema/lsst.py +423 -0
  49. rucio/common/stomp_utils.py +160 -0
  50. rucio/common/stopwatch.py +56 -0
  51. rucio/common/test_rucio_server.py +148 -0
  52. rucio/common/types.py +158 -0
  53. rucio/common/utils.py +1946 -0
  54. rucio/rse/__init__.py +97 -0
  55. rucio/rse/protocols/__init__.py +14 -0
  56. rucio/rse/protocols/cache.py +123 -0
  57. rucio/rse/protocols/dummy.py +112 -0
  58. rucio/rse/protocols/gfal.py +701 -0
  59. rucio/rse/protocols/globus.py +243 -0
  60. rucio/rse/protocols/gsiftp.py +93 -0
  61. rucio/rse/protocols/http_cache.py +83 -0
  62. rucio/rse/protocols/mock.py +124 -0
  63. rucio/rse/protocols/ngarc.py +210 -0
  64. rucio/rse/protocols/posix.py +251 -0
  65. rucio/rse/protocols/protocol.py +530 -0
  66. rucio/rse/protocols/rclone.py +365 -0
  67. rucio/rse/protocols/rfio.py +137 -0
  68. rucio/rse/protocols/srm.py +339 -0
  69. rucio/rse/protocols/ssh.py +414 -0
  70. rucio/rse/protocols/storm.py +207 -0
  71. rucio/rse/protocols/webdav.py +547 -0
  72. rucio/rse/protocols/xrootd.py +295 -0
  73. rucio/rse/rsemanager.py +752 -0
  74. rucio/vcsversion.py +11 -0
  75. rucio/version.py +46 -0
  76. rucio_clients-32.8.6.data/data/etc/rse-accounts.cfg.template +25 -0
  77. rucio_clients-32.8.6.data/data/etc/rucio.cfg.atlas.client.template +42 -0
  78. rucio_clients-32.8.6.data/data/etc/rucio.cfg.template +257 -0
  79. rucio_clients-32.8.6.data/data/requirements.txt +55 -0
  80. rucio_clients-32.8.6.data/data/rucio_client/merge_rucio_configs.py +147 -0
  81. rucio_clients-32.8.6.data/scripts/rucio +2540 -0
  82. rucio_clients-32.8.6.data/scripts/rucio-admin +2434 -0
  83. rucio_clients-32.8.6.dist-info/METADATA +50 -0
  84. rucio_clients-32.8.6.dist-info/RECORD +88 -0
  85. rucio_clients-32.8.6.dist-info/WHEEL +5 -0
  86. rucio_clients-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  87. rucio_clients-32.8.6.dist-info/licenses/LICENSE +201 -0
  88. rucio_clients-32.8.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,210 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import errno
17
+ import os
18
+
19
+ from rucio.common.exception import FileAlreadyExists, ServiceUnavailable, SourceNotFound
20
+ from rucio.rse.protocols import protocol
21
+
22
+ try:
23
+ import arc # pylint: disable=import-error
24
+ except:
25
+ pass
26
+
27
+
28
+ class DataPoint:
29
+ '''
30
+ Wrapper around arc.datapoint_from_url() which does not clean up DataPoints
31
+ when python objects are destroyed, leading to connection leaking when used
32
+ with gridftp. This class should be used instead of arc.datapoint_from_url().
33
+ It can be called like dp = DataPoint('gsiftp://...', uc); dp.h.Stat()
34
+ where uc is an arc.UserConfig object.
35
+ '''
36
+ def __init__(self, u, uc):
37
+ self.h = arc.datapoint_from_url(u, uc)
38
+
39
+ def __del__(self):
40
+ arc.DataPoint.__swig_destroy__(self.h)
41
+
42
+
43
+ class Default(protocol.RSEProtocol):
44
+ """ Implementing access to RSEs using ARC client."""
45
+
46
+ def __init__(self, protocol_attr, rse_settings, logger=None):
47
+ """
48
+ Set up UserConfig object.
49
+ """
50
+ super(Default, self).__init__(protocol_attr, rse_settings, logger=logger)
51
+
52
+ # Arc logging to stdout, uncomment for debugging. Should use root
53
+ # logger level eventually.
54
+ # root_logger = arc.Logger_getRootLogger()
55
+ # stream = arc.LogStream(sys.stdout)
56
+ # root_logger.addDestination(stream)
57
+ # # Set threshold to VERBOSE or DEBUG for more information
58
+ # root_logger.setThreshold(arc.DEBUG)
59
+
60
+ self.cfg = arc.UserConfig()
61
+ try:
62
+ self.cfg.ProxyPath(os.environ['X509_USER_PROXY'])
63
+ except:
64
+ pass
65
+
66
+ def path2pfn(self, path):
67
+ """
68
+ Retruns a fully qualified PFN for the file referred by path.
69
+
70
+ :param path: The path to the file.
71
+
72
+ :returns: Fully qualified PFN.
73
+
74
+ """
75
+ return ''.join([self.rse['scheme'], '://%s' % self.rse['hostname'], path])
76
+
77
+ def exists(self, pfn):
78
+ """ Checks if the requested file is known by the referred RSE.
79
+
80
+ :param pfn: Physical file name
81
+
82
+ :returns: True if the file exists, False if it doesn't
83
+
84
+ :raise ServiceUnavailable
85
+ """
86
+ dp = DataPoint(str(pfn), self.cfg)
87
+ fileinfo = arc.FileInfo()
88
+
89
+ status = dp.h.Stat(fileinfo)
90
+ if not status:
91
+ if status.GetErrno() == errno.ENOENT:
92
+ return False
93
+ raise ServiceUnavailable(str(status))
94
+
95
+ return True
96
+
97
+ def connect(self):
98
+ """ Establishes the actual connection to the referred RSE.
99
+
100
+ :raise RSEAccessDenied
101
+ """
102
+ pass
103
+
104
+ def close(self):
105
+ """ Closes the connection to RSE."""
106
+ pass
107
+
108
+ def __arc_copy(self, src, dest, space_token=None, transfer_timeout=None):
109
+
110
+ # TODO set proxy path
111
+
112
+ # Convert the arguments to DataPoint objects
113
+ source = DataPoint(str(src), self.cfg)
114
+ if source.h is None:
115
+ raise ServiceUnavailable("Can't handle source %s" % src)
116
+
117
+ destination = DataPoint(str(dest), self.cfg)
118
+ if destination.h is None:
119
+ raise ServiceUnavailable("Can't handle destination %s" % dest)
120
+ if space_token:
121
+ destination.h.GetURL().AddOption('spacetoken', space_token)
122
+
123
+ # DataMover does the transfer
124
+ mover = arc.DataMover()
125
+ # Don't attempt to retry on error
126
+ mover.retry(False)
127
+ # Passive and insecure gridftp
128
+ mover.passive(True)
129
+ mover.secure(False)
130
+ # Do the transfer
131
+ status = mover.Transfer(source.h, destination.h, arc.FileCache(), arc.URLMap())
132
+
133
+ if not status:
134
+ if status.GetErrno() == errno.ENOENT:
135
+ raise SourceNotFound()
136
+ if status.GetErrno() == errno.EEXIST:
137
+ raise FileAlreadyExists()
138
+ raise ServiceUnavailable(str(status))
139
+
140
+ def get(self, pfn, dest, transfer_timeout=None):
141
+ """ Provides access to files stored inside connected the RSE.
142
+
143
+ :param pfn: Physical file name of requested file
144
+ :param dest: Name and path of the files when stored at the client
145
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
146
+
147
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
148
+ """
149
+ self.__arc_copy(pfn, dest, transfer_timeout=transfer_timeout)
150
+
151
+ def put(self, source, target, source_dir=None, transfer_timeout=None):
152
+ """ Allows to store files inside the referred RSE.
153
+
154
+ :param source: Physical file name
155
+ :param target: Name of the file on the storage system e.g. with prefixed scope
156
+ :param source_dir Path where the to be transferred files are stored in the local file system
157
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
158
+
159
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
160
+ """
161
+
162
+ if source_dir:
163
+ sf = source_dir + '/' + source
164
+ else:
165
+ sf = source
166
+
167
+ space_token = None
168
+ if self.attributes['extended_attributes'] is not None and 'space_token' in list(self.attributes['extended_attributes'].keys()):
169
+ space_token = self.attributes['extended_attributes']['space_token']
170
+
171
+ self.__arc_copy(sf, target, space_token, transfer_timeout=transfer_timeout)
172
+
173
+ def delete(self, pfn):
174
+ """ Deletes a file from the connected RSE.
175
+
176
+ :param pfn: Physical file name
177
+
178
+ :raises ServiceUnavailable, SourceNotFound
179
+ """
180
+ dp = DataPoint(str(pfn), self.cfg)
181
+ if dp.h is None:
182
+ raise ServiceUnavailable("Can't handle pfn %s" % pfn)
183
+
184
+ status = dp.h.Remove()
185
+ if not status:
186
+ if status.GetErrno() == errno.ENOENT:
187
+ raise SourceNotFound()
188
+ raise ServiceUnavailable(str(status))
189
+
190
+ def rename(self, pfn, new_pfn):
191
+ """ Allows to rename a file stored inside the connected RSE.
192
+
193
+ :param pfn: Current physical file name
194
+ :param new_pfn New physical file name
195
+
196
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
197
+ """
198
+ dp = DataPoint(str(pfn), self.cfg)
199
+ if dp.h is None:
200
+ raise ServiceUnavailable("Can't handle pfn %s" % pfn)
201
+
202
+ url = arc.URL(str(new_pfn))
203
+ if not url:
204
+ raise ServiceUnavailable("Can't handle new pfn %s" % new_pfn)
205
+
206
+ status = dp.h.Rename(url)
207
+ if not status:
208
+ if status.GetErrno() == errno.ENOENT:
209
+ raise SourceNotFound()
210
+ raise ServiceUnavailable(str(status))
@@ -0,0 +1,251 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+ import os
18
+ import os.path
19
+ import shutil
20
+ from subprocess import call
21
+
22
+ from rucio.common import exception
23
+ from rucio.common.utils import adler32
24
+ from rucio.rse.protocols import protocol
25
+
26
+
27
+ class Default(protocol.RSEProtocol):
28
+ """ Implementing access to RSEs using the local filesystem."""
29
+
30
+ def exists(self, pfn):
31
+ """
32
+ Checks if the requested file is known by the referred RSE.
33
+
34
+ :param pfn: Physical file name
35
+
36
+ :returns: True if the file exists, False if it doesn't
37
+
38
+ :raises SourceNotFound: if the source file was not found on the referred storage.
39
+ """
40
+ status = ''
41
+ try:
42
+ status = os.path.exists(self.pfn2path(pfn))
43
+ except Exception as e:
44
+ raise exception.ServiceUnavailable(e)
45
+ return status
46
+
47
+ def connect(self):
48
+ """
49
+ Establishes the actual connection to the referred RSE.
50
+
51
+ :param credentials: needed to establish a connection with the stroage.
52
+
53
+ :raises RSEAccessDenied: if no connection could be established.
54
+ """
55
+ pass
56
+
57
+ def close(self):
58
+ """ Closes the connection to RSE."""
59
+ pass
60
+
61
+ def get(self, pfn, dest, transfer_timeout=None):
62
+ """ Provides access to files stored inside connected the RSE.
63
+
64
+ :param pfn: Physical file name of requested file
65
+ :param dest: Name and path of the files when stored at the client
66
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
67
+
68
+ :raises DestinationNotAccessible: if the destination storage was not accessible.
69
+ :raises ServiceUnavailable: if some generic error occured in the library.
70
+ :raises SourceNotFound: if the source file was not found on the referred storage.
71
+ """
72
+ try:
73
+ shutil.copy(self.pfn2path(pfn), dest)
74
+ except IOError as e:
75
+ try: # To check if the error happend local or remote
76
+ with open(dest, 'wb'):
77
+ pass
78
+ call(['rm', '-rf', dest])
79
+ except IOError as e:
80
+ if e.errno == 2:
81
+ raise exception.DestinationNotAccessible(e)
82
+ else:
83
+ raise exception.ServiceUnavailable(e)
84
+ if e.errno == 2:
85
+ raise exception.SourceNotFound(e)
86
+ else:
87
+ raise exception.ServiceUnavailable(e)
88
+
89
+ def put(self, source, target, source_dir=None, transfer_timeout=None):
90
+ """
91
+ Allows to store files inside the referred RSE.
92
+
93
+ :param source: path to the source file on the client file system
94
+ :param target: path to the destination file on the storage
95
+ :param source_dir: Path where the to be transferred files are stored in the local file system
96
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
97
+
98
+ :raises DestinationNotAccessible: if the destination storage was not accessible.
99
+ :raises ServiceUnavailable: if some generic error occured in the library.
100
+ :raises SourceNotFound: if the source file was not found on the referred storage.
101
+ """
102
+ target = self.pfn2path(target)
103
+
104
+ if source_dir:
105
+ sf = source_dir + '/' + source
106
+ else:
107
+ sf = source
108
+ try:
109
+ dirs = os.path.dirname(target)
110
+ if not os.path.exists(dirs):
111
+ os.makedirs(dirs)
112
+ shutil.copy(sf, target)
113
+ except IOError as e:
114
+ if e.errno == 2:
115
+ raise exception.SourceNotFound(e)
116
+ elif not self.exists(self.rse['prefix']):
117
+ path = ''
118
+ for p in self.rse['prefix'].split('/'):
119
+ path += p + '/'
120
+ os.mkdir(path)
121
+ shutil.copy(sf, self.pfn2path(target))
122
+ else:
123
+ raise exception.DestinationNotAccessible(e)
124
+
125
+ def delete(self, pfn):
126
+ """ Deletes a file from the connected RSE.
127
+
128
+ :param pfn: pfn to the to be deleted file
129
+
130
+ :raises ServiceUnavailable: if some generic error occured in the library.
131
+ :raises SourceNotFound: if the source file was not found on the referred storage.
132
+ """
133
+ try:
134
+ os.remove(self.pfn2path(pfn))
135
+ except OSError as e:
136
+ if e.errno == 2:
137
+ raise exception.SourceNotFound(e)
138
+
139
+ def rename(self, pfn, new_pfn):
140
+ """ Allows to rename a file stored inside the connected RSE.
141
+
142
+ :param path: path to the current file on the storage
143
+ :param new_path: path to the new file on the storage
144
+
145
+ :raises DestinationNotAccessible: if the destination storage was not accessible.
146
+ :raises ServiceUnavailable: if some generic error occured in the library.
147
+ :raises SourceNotFound: if the source file was not found on the referred storage.
148
+ """
149
+ path = self.pfn2path(pfn)
150
+ new_path = self.pfn2path(new_pfn)
151
+ try:
152
+ if not os.path.exists(os.path.dirname(new_path)):
153
+ os.makedirs(os.path.dirname(new_path))
154
+ os.rename(path, new_path)
155
+ except IOError as e:
156
+ if e.errno == 2:
157
+ if self.exists(self.pfn2path(path)):
158
+ raise exception.SourceNotFound(e)
159
+ else:
160
+ raise exception.DestinationNotAccessible(e)
161
+ else:
162
+ raise exception.ServiceUnavailable(e)
163
+
164
+ def lfns2pfns(self, lfns):
165
+ """ Returns fully qualified PFNs for the file referred by each lfn in
166
+ the lfns list.
167
+
168
+ :param lfns: List of lfns. If lfn['path'] is present it is used as
169
+ the path to the file, otherwise the path is constructed
170
+ deterministically.
171
+
172
+ :returns: Fully qualified PFNs.
173
+ """
174
+ pfns = {}
175
+ prefix = self.attributes['prefix']
176
+
177
+ if not prefix.startswith('/'):
178
+ prefix = ''.join(['/', prefix])
179
+ if not prefix.endswith('/'):
180
+ prefix = ''.join([prefix, '/'])
181
+
182
+ lfns = [lfns] if isinstance(lfns, dict) else lfns
183
+ for lfn in lfns:
184
+ scope, name = str(lfn['scope']), lfn['name']
185
+ if lfn.get('path'):
186
+ pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],
187
+ '://',
188
+ self.attributes['hostname'],
189
+ prefix,
190
+ lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]
191
+ ])
192
+ else:
193
+ pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],
194
+ '://',
195
+ self.attributes['hostname'],
196
+ prefix,
197
+ self._get_path(scope=scope, name=name)
198
+ ])
199
+ return pfns
200
+
201
+ def pfn2path(self, pfn):
202
+ tmp = list(self.parse_pfns(pfn).values())[0]
203
+ return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])
204
+
205
+ def stat(self, pfn):
206
+ """ Determines the file size in bytes and checksum (adler32) of the provided file.
207
+
208
+ :param pfn: The PFN the file.
209
+
210
+ :returns: a dict containing the keys filesize and adler32.
211
+ """
212
+ path = self.pfn2path(pfn)
213
+ return {'filesize': os.stat(path)[os.path.stat.ST_SIZE], 'adler32': adler32(path)}
214
+
215
+
216
+ class Symlink(Default):
217
+ """ Implementing access to RSEs using the local filesystem, creating a symlink on a get """
218
+
219
+ def get(self, pfn, dest, transfer_timeout=None):
220
+ """ Provides access to files stored inside connected the RSE.
221
+ A download/get will create a symlink on the local file system pointing to the
222
+ underlying file. Other operations act directly on the remote file.
223
+ :param pfn: Physical file name of requested file
224
+ :param dest: Name and path of the files when stored at the client
225
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
226
+ :raises DestinationNotAccessible: if the destination storage was not accessible.
227
+ :raises ServiceUnavailable: if some generic error occured in the library.
228
+ :raises SourceNotFound: if the source file was not found on the referred storage.
229
+ """
230
+ path = self.pfn2path(pfn)
231
+ os.symlink(path, dest)
232
+ self.logger(logging.DEBUG,
233
+ 'Symlink {} created for {} from {}'
234
+ .format(dest, path, pfn))
235
+ if not os.lstat(dest):
236
+ # problem in creating the symlink
237
+ self.logger(logging.ERROR, 'Symlink {} could not be created'.format(dest))
238
+ raise exception.DestinationNotAccessible()
239
+ if not os.path.exists(dest):
240
+ # could not find the file following the symlink
241
+ self.logger(logging.ERROR, 'Symlink {} appears to be a broken link to {}'
242
+ .format(dest, path))
243
+ if os.lstat(dest) and os.path.islink(dest):
244
+ os.unlink(dest)
245
+ raise exception.SourceNotFound()
246
+
247
+ def pfn2path(self, pfn):
248
+ # obtain path and sanitise from multiple slashes, etc
249
+ path = os.path.normpath(super().pfn2path(pfn))
250
+ self.logger(logging.DEBUG, 'Extracted path: {} from: {}'.format(path, pfn))
251
+ return path