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,243 @@
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
+ from urllib.parse import urlparse
18
+
19
+ from rucio.common import exception
20
+ from rucio.common.extra import import_extras
21
+ from rucio.core.rse import get_rse_attribute
22
+ from rucio.rse.protocols.protocol import RSEProtocol
23
+ from rucio.transfertool.globus_library import get_transfer_client, send_delete_task, send_bulk_delete_task
24
+
25
+ EXTRA_MODULES = import_extras(['globus_sdk'])
26
+
27
+ if EXTRA_MODULES['globus_sdk']:
28
+ from globus_sdk import TransferAPIError # pylint: disable=import-error
29
+
30
+
31
+ class GlobusRSEProtocol(RSEProtocol):
32
+ """ Implementing access to RSEs using the Globus service as a Rucio RSE protocol. """
33
+
34
+ def __init__(self, protocol_attr, rse_settings, logger=logging.log):
35
+ """ Initializes the object with information about the referred RSE.
36
+
37
+ :param props: Properties of the requested protocol
38
+ """
39
+ super(GlobusRSEProtocol, self).__init__(protocol_attr, rse_settings, logger=logger)
40
+ self.globus_endpoint_id = get_rse_attribute(self.rse.get('id'), 'globus_endpoint_id')
41
+ self.logger = logger
42
+
43
+ def lfns2pfns(self, lfns):
44
+ """
45
+ Retruns a fully qualified PFN for the file referred by path.
46
+
47
+ :param path: The path to the file.
48
+
49
+ :returns: Fully qualified PFN.
50
+ """
51
+ pfns = {}
52
+ prefix = self.attributes['prefix']
53
+
54
+ if not prefix.startswith('/'):
55
+ prefix = ''.join(['/', prefix])
56
+ if not prefix.endswith('/'):
57
+ prefix = ''.join([prefix, '/'])
58
+
59
+ lfns = [lfns] if isinstance(lfns, dict) else lfns
60
+ for lfn in lfns:
61
+ scope, name = lfn['scope'], lfn['name']
62
+
63
+ if 'path' in lfn and lfn['path'] is not None:
64
+ pfns['%s:%s' % (scope, name)] = ''.join([prefix, lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]])
65
+ else:
66
+ pfns['%s:%s' % (scope, name)] = ''.join([prefix, self._get_path(scope=scope, name=name)])
67
+ return pfns
68
+
69
+ def _get_path(self, scope, name):
70
+ """ Transforms the logical file name into a PFN.
71
+ Suitable for sites implementing the RUCIO naming convention.
72
+ This implementation is only invoked if the RSE is deterministic.
73
+
74
+ :param scope: scope
75
+ :param name: filename
76
+
77
+ :returns: RSE specific URI of the physical file
78
+ """
79
+ return self.translator.path(scope, name)
80
+
81
+ def parse_pfns(self, pfns):
82
+ """
83
+ Splits the given PFN into the parts known by the protocol. It is also checked if the provided protocol supportes the given PFNs.
84
+
85
+ :param pfns: a list of a fully qualified PFNs
86
+
87
+ :returns: dic with PFN as key and a dict with path and name as value
88
+
89
+ :raises RSEFileNameNotSupported: if the provided PFN doesn't match with the protocol settings
90
+ """
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
+ hostname = parsed.netloc.partition(':')[0]
98
+ port = int(parsed.netloc.partition(':')[2]) if parsed.netloc.partition(':')[2] != '' else 0
99
+ while '//' in parsed.path:
100
+ parsed = parsed._replace(path=parsed.path.replace('//', '/'))
101
+ path = parsed.path
102
+
103
+ # Protect against 'lazy' defined prefixes for RSEs in the repository
104
+ if not self.attributes['prefix'].startswith('/'):
105
+ self.attributes['prefix'] = '/' + self.attributes['prefix']
106
+ if not self.attributes['prefix'].endswith('/'):
107
+ self.attributes['prefix'] += '/'
108
+
109
+ if self.attributes['hostname'] != hostname:
110
+ 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
111
+ raise exception.RSEFileNameNotSupported('Invalid hostname: provided \'%s\', expected \'%s\'' % (hostname, self.attributes['hostname']))
112
+
113
+ if self.attributes['port'] != port:
114
+ raise exception.RSEFileNameNotSupported('Invalid port: provided \'%s\', expected \'%s\'' % (port, self.attributes['port']))
115
+
116
+ if not path.startswith(self.attributes['prefix']):
117
+ raise exception.RSEFileNameNotSupported('Invalid prefix: provided \'%s\', expected \'%s\'' % ('/'.join(path.split('/')[0:len(self.attributes['prefix'].split('/')) - 1]),
118
+ self.attributes['prefix'])) # len(...)-1 due to the leading '/
119
+
120
+ # Spliting parsed.path into prefix, path, filename
121
+ prefix = self.attributes['prefix']
122
+ path = path.partition(self.attributes['prefix'])[2]
123
+ name = path.split('/')[-1]
124
+ path = '/'.join(path.split('/')[:-1])
125
+ if not path.startswith('/'):
126
+ path = '/' + path
127
+ if path != '/' and not path.endswith('/'):
128
+ path = path + '/'
129
+ ret[pfn] = {'path': path, 'name': name, 'scheme': scheme, 'prefix': prefix, 'port': port, 'hostname': hostname, }
130
+
131
+ return ret
132
+
133
+ def exists(self, path):
134
+ """
135
+ Checks if the requested file is known by the referred RSE.
136
+
137
+ :param path: Physical file name
138
+
139
+ :returns: True if the file exists, False if it doesn't
140
+
141
+ :raises SourceNotFound: if the source file was not found on the referred storage.
142
+
143
+ """
144
+
145
+ filepath = '/'.join(path.split('/')[0:-1]) + '/'
146
+ filename = path.split('/')[-1]
147
+
148
+ transfer_client = get_transfer_client()
149
+ exists = False
150
+
151
+ if self.globus_endpoint_id:
152
+ try:
153
+ resp = transfer_client.operation_ls(endpoint_id=self.globus_endpoint_id, path=filepath)
154
+ exists = len([r for r in resp if r['name'] == filename]) > 0
155
+ except TransferAPIError as err:
156
+ print(err)
157
+ else:
158
+ print('No rse attribute found for globus endpoint id.')
159
+
160
+ return exists
161
+
162
+ def list(self, path):
163
+ """
164
+
165
+ Checks if the requested path is known by the referred RSE and returns a list of items
166
+
167
+ :param path: Physical file name
168
+
169
+ :returns: List of items
170
+
171
+ """
172
+
173
+ transfer_client = get_transfer_client()
174
+ items = []
175
+
176
+ if self.globus_endpoint_id:
177
+ try:
178
+ resp = transfer_client.operation_ls(endpoint_id=self.globus_endpoint_id, path=path)
179
+ items = resp['DATA']
180
+ except TransferAPIError as err:
181
+ print(err)
182
+ else:
183
+ print('No rse attribute found for globus endpoint id.')
184
+
185
+ return items
186
+
187
+ def delete(self, path):
188
+ """
189
+ Deletes a file from the connected RSE.
190
+
191
+ :param path: path to the to be deleted file
192
+
193
+ :raises ServiceUnavailable: if some generic error occured in the library.
194
+ :raises SourceNotFound: if the source file was not found on the referred storage.
195
+ """
196
+ if self.globus_endpoint_id:
197
+ try:
198
+ delete_response = send_delete_task(endpoint_id=self.globus_endpoint_id, path=path, logger=self.logger)
199
+ except TransferAPIError as err:
200
+ self.logger(logging.WARNING, str(err))
201
+ raise exception.RucioException(err)
202
+ else:
203
+ raise exception.RucioException('No rse attribute found for globus endpoint id.')
204
+
205
+ if delete_response['code'] != 'Accepted':
206
+ self.logger(logging.DEBUG, 'delete_response: %s' % delete_response)
207
+ raise exception.RucioException('delete_task not accepted by Globus')
208
+
209
+ def bulk_delete(self, pfns):
210
+ """
211
+ Submits an async task to bulk delete files on globus endpoint.
212
+
213
+ :param pfns: list of pfns to delete
214
+
215
+ :raises TransferAPIError: if unexpected response from the service.
216
+ """
217
+ if self.globus_endpoint_id:
218
+ try:
219
+ bulk_delete_response = send_bulk_delete_task(endpoint_id=self.globus_endpoint_id, pfns=pfns, logger=self.logger)
220
+ except TransferAPIError as err:
221
+ raise exception.RucioException(err)
222
+ else:
223
+ raise exception.RucioException('No rse attribute found for globus endpoint id.')
224
+
225
+ if bulk_delete_response['code'] != 'Accepted':
226
+ self.logger(logging.DEBUG, 'delete_response: %s' % bulk_delete_response)
227
+ raise exception.RucioException('delete_task not accepted by Globus')
228
+
229
+ def connect(self):
230
+ """
231
+ Establishes the actual connection to the referred RSE.
232
+
233
+ reaper2 daemon requires implementation of protocol.connect
234
+ """
235
+ pass
236
+
237
+ def close(self):
238
+ """
239
+ Closes the connection to RSE.
240
+
241
+ reaper2 daemon requires implementation of protocol.close
242
+ """
243
+ pass
@@ -0,0 +1,93 @@
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 json
17
+ import os
18
+
19
+ import requests
20
+
21
+ from rucio.common import exception
22
+ from rucio.rse.protocols import protocol
23
+
24
+
25
+ class Default(protocol.RSEProtocol):
26
+ """ Implementing access to RSEs using gsiftp."""
27
+
28
+ def __init__(self, protocol_attr, rse_settings, logger=None):
29
+ """ Initializes the object with information about the referred RSE.
30
+
31
+ :param props: Properties derived from the RSE Repository
32
+ """
33
+ super(Default, self).__init__(protocol_attr, rse_settings, logger=logger)
34
+
35
+ def connect(self):
36
+ """
37
+ Establishes the actual connection to the referred RSE.
38
+ If we decide to use gfal, init should be done here.
39
+
40
+ :raises RSEAccessDenied
41
+ """
42
+ pass
43
+
44
+ def close(self):
45
+ """
46
+ Closes the connection to RSE.
47
+ """
48
+ pass
49
+
50
+ def get_space_usage(self):
51
+ """
52
+ Get RSE space usage information.
53
+
54
+ :returns: a list with dict containing 'totalsize' and 'unusedsize'
55
+
56
+ :raises ServiceUnavailable: if some generic error occured in the library.
57
+ """
58
+ rse_name = self.rse['rse']
59
+ dest = '/tmp/rucio-gsiftp-site-size_' + rse_name
60
+ space_usage_url = ''
61
+ # url of space usage json, woud be nicer to have it in rse_settings
62
+ agis = requests.get('http://atlas-agis-api.cern.ch/request/ddmendpoint/query/list/?json').json()
63
+ agis_token = ''
64
+ for res in agis:
65
+ if rse_name == res['name']:
66
+ agis_token = res['token']
67
+ space_usage_url = res['space_usage_url']
68
+
69
+ import gfal2 # pylint: disable=import-error
70
+ gfal2.set_verbose(gfal2.verbose_level.normal) # pylint: disable=no-member
71
+ try:
72
+ if os.path.exists(dest):
73
+ os.remove(dest)
74
+ ctx = gfal2.creat_context() # pylint: disable=no-member
75
+ ctx.set_opt_string_list("SRM PLUGIN", "TURL_PROTOCOLS", ["gsiftp", "rfio", "gsidcap", "dcap", "kdcap"])
76
+ params = ctx.transfer_parameters()
77
+ params.timeout = 3600
78
+ ret = ctx.filecopy(params, str(space_usage_url), str('file://' + dest))
79
+
80
+ if ret == 0:
81
+ data_file = open(dest)
82
+ data = json.load(data_file)
83
+ data_file.close()
84
+ if agis_token not in list(data.keys()):
85
+ print('ERROR: space usage json has different token as key')
86
+ else:
87
+ totalsize = int(data[agis_token]['total_space'])
88
+ used = int(data[agis_token]['used_space'])
89
+ unusedsize = totalsize - used
90
+ return totalsize, unusedsize
91
+ except Exception as error:
92
+ print(error)
93
+ raise exception.ServiceUnavailable(error)
@@ -0,0 +1,83 @@
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
+ from rucio.rse.protocols import ngarc
17
+
18
+
19
+ class Default(ngarc.Default):
20
+
21
+ """ Implementing access to RSEs using the ngarc protocol."""
22
+
23
+ def __init__(self, protocol_attr, rse_settings, logger=None):
24
+ """ Initializes the object with information about the referred RSE.
25
+
26
+ :param props: Properties derived from the RSE Repository
27
+ """
28
+ super(Default, self).__init__(protocol_attr, rse_settings, logger=logger)
29
+ self.attributes.pop('determinism_type', None)
30
+ self.files = []
31
+
32
+ def _get_path(self, scope, name):
33
+ """ Transforms the physical file name into the local URI in the referred RSE.
34
+ Suitable for sites implementoing the RUCIO naming convention.
35
+
36
+ :param name: filename
37
+ :param scope: scope
38
+
39
+ :returns: RSE specific URI of the physical file
40
+ """
41
+ return '%s/%s' % (scope, name)
42
+
43
+ def path2pfn(self, path):
44
+ """
45
+ Retruns a fully qualified PFN for the file referred by path.
46
+
47
+ :param path: The path to the file.
48
+
49
+ :returns: Fully qualified PFN.
50
+
51
+ """
52
+ return ''.join([self.attributes['scheme'], '://%s' % self.attributes['hostname'], path])
53
+
54
+ def put(self, source, target, source_dir=None, transfer_timeout=None):
55
+ """ Allows to store files inside the referred RSE.
56
+
57
+ :param source: Physical file name
58
+ :param target: Name of the file on the storage system e.g. with prefixed scope
59
+ :param source_dir Path where the to be transferred files are stored in the local file system
60
+ :param transfer_timeout Transfer timeout (in seconds)
61
+
62
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
63
+ """
64
+ raise NotImplementedError
65
+
66
+ def delete(self, pfn):
67
+ """ Deletes a file from the connected RSE.
68
+
69
+ :param pfn: Physical file name
70
+
71
+ :raises ServiceUnavailable, SourceNotFound
72
+ """
73
+ raise NotImplementedError
74
+
75
+ def rename(self, pfn, new_pfn):
76
+ """ Allows to rename a file stored inside the connected RSE.
77
+
78
+ :param pfn: Current physical file name
79
+ :param new_pfn New physical file name
80
+
81
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
82
+ """
83
+ raise NotImplementedError
@@ -0,0 +1,124 @@
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
+ from rucio.common import exception
17
+ from rucio.rse.protocols import protocol
18
+
19
+
20
+ class Default(protocol.RSEProtocol):
21
+ """ Implementing access to RSEs using the local filesystem."""
22
+
23
+ def __init__(self, protocol_attr, rse_settings, logger=None):
24
+ """ Initializes the object with information about the referred RSE.
25
+
26
+ :param props: Properties derived from the RSE Repository
27
+ """
28
+ super(Default, self).__init__(protocol_attr, rse_settings, logger=logger)
29
+ self.attributes.pop('determinism_type', None)
30
+ self.files = []
31
+
32
+ def path2pfn(self, path):
33
+ """
34
+ Retruns a fully qualified PFN for the file referred by path.
35
+
36
+ :param path: The path to the file.
37
+
38
+ :returns: Fully qualified PFN.
39
+
40
+ """
41
+ return ''.join([self.rse['scheme'], '://%s' % self.rse['hostname'], path])
42
+
43
+ def exists(self, pfn):
44
+ """ Checks if the requested file is known by the referred RSE.
45
+
46
+ :param pfn: Physical file name
47
+
48
+ :returns: True if the file exists, False if it doesn't
49
+
50
+ :raise ServiceUnavailable
51
+ """
52
+ return pfn in self.files
53
+
54
+ def connect(self):
55
+ """ Establishes the actual connection to the referred RSE.
56
+
57
+ :param credentials: Provide all necessary information to establish a connection
58
+ to the referred storage system. Some is loaded from the repository inside the
59
+ RSE class and some must be provided specific for the SFTP protocol like
60
+ username, password, private_key, private_key_pass, port.
61
+ For details about possible additional parameters and details about their usage
62
+ see the pysftp.Connection() documentation.
63
+ NOTE: the host parametrer is overwritten with the value provided by the repository
64
+
65
+ :raise RSEAccessDenied
66
+ """
67
+ pass
68
+
69
+ def close(self):
70
+ """ Closes the connection to RSE."""
71
+ pass
72
+
73
+ def get(self, pfn, dest, transfer_timeout=None):
74
+ """ Provides access to files stored inside connected the RSE.
75
+
76
+ :param pfn: Physical file name of requested file
77
+ :param dest: Name and path of the files when stored at the client
78
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
79
+
80
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
81
+ """
82
+ if pfn not in self.files:
83
+ raise exception.SourceNotFound(pfn)
84
+
85
+ def put(self, source, target, source_dir=None, transfer_timeout=None):
86
+ """ Allows to store files inside the referred RSE.
87
+
88
+ :param source: Physical file name
89
+ :param target: Name of the file on the storage system e.g. with prefixed scope
90
+ :param source_dir Path where the to be transferred files are stored in the local file system
91
+ :param transfer_timeout Transfer timeout (in seconds) - dummy
92
+
93
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
94
+ """
95
+ self.files.append(target)
96
+
97
+ def delete(self, pfn):
98
+ """ Deletes a file from the connected RSE.
99
+
100
+ :param pfn: Physical file name
101
+
102
+ :raises ServiceUnavailable, SourceNotFound
103
+ """
104
+ pass
105
+
106
+ def bulk_delete(self, pfns):
107
+ """
108
+ Submits an async task to bulk delete files.
109
+
110
+ :param pfns: list of pfns to delete
111
+
112
+ :raises TransferAPIError: if unexpected response from the service.
113
+ """
114
+ pass
115
+
116
+ def rename(self, pfn, new_pfn):
117
+ """ Allows to rename a file stored inside the connected RSE.
118
+
119
+ :param pfn: Current physical file name
120
+ :param new_pfn New physical file name
121
+
122
+ :raises DestinationNotAccessible, ServiceUnavailable, SourceNotFound
123
+ """
124
+ pass