rucio-clients 37.0.0rc1__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 +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio_clients-37.0.0rc1.data/data/etc/rse-accounts.cfg.template +25 -0
- rucio_clients-37.0.0rc1.data/data/etc/rucio.cfg.atlas.client.template +43 -0
- rucio_clients-37.0.0rc1.data/data/etc/rucio.cfg.template +241 -0
- rucio_clients-37.0.0rc1.data/data/requirements.client.txt +19 -0
- rucio_clients-37.0.0rc1.data/data/rucio_client/merge_rucio_configs.py +144 -0
- rucio_clients-37.0.0rc1.data/scripts/rucio +133 -0
- rucio_clients-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio_clients-37.0.0rc1.dist-info/METADATA +54 -0
- rucio_clients-37.0.0rc1.dist-info/RECORD +104 -0
- rucio_clients-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio_clients-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio_clients-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio_clients-37.0.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from requests.status_codes import codes
|
|
18
|
+
|
|
19
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
20
|
+
from rucio.common.utils import build_url, parse_response
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ExportClient(BaseClient):
|
|
24
|
+
"""RSE client class for exporting data from Rucio"""
|
|
25
|
+
|
|
26
|
+
EXPORT_BASEURL = 'export'
|
|
27
|
+
|
|
28
|
+
def export_data(self, distance: bool = True) -> dict[str, Any]:
|
|
29
|
+
"""
|
|
30
|
+
Export RSE data (RSE, settings, attributes and distance).
|
|
31
|
+
:param distance: To include the distance.
|
|
32
|
+
|
|
33
|
+
:returns: A dict containing data
|
|
34
|
+
"""
|
|
35
|
+
payload = {'distance': distance}
|
|
36
|
+
path = '/'.join([self.EXPORT_BASEURL])
|
|
37
|
+
url = build_url(choice(self.list_hosts), path=path, params=payload)
|
|
38
|
+
|
|
39
|
+
r = self._send_request(url, type_='GET')
|
|
40
|
+
if r.status_code == codes.ok:
|
|
41
|
+
return parse_response(r.text)
|
|
42
|
+
else:
|
|
43
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
44
|
+
raise exc_cls(exc_msg)
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
from json import loads
|
|
16
|
+
from typing import Any
|
|
17
|
+
from urllib.parse import quote_plus
|
|
18
|
+
|
|
19
|
+
from requests.status_codes import codes
|
|
20
|
+
|
|
21
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
22
|
+
from rucio.common.utils import build_url
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FileClient(BaseClient):
|
|
26
|
+
"""Dataset client class for working with dataset"""
|
|
27
|
+
|
|
28
|
+
BASEURL = 'files'
|
|
29
|
+
|
|
30
|
+
def list_file_replicas(self, scope: str, lfn: str) -> list[dict[str, Any]]:
|
|
31
|
+
"""
|
|
32
|
+
List file replicas.
|
|
33
|
+
|
|
34
|
+
:param scope: the scope.
|
|
35
|
+
:param lfn: the lfn.
|
|
36
|
+
|
|
37
|
+
:return: List of replicas.
|
|
38
|
+
"""
|
|
39
|
+
path = '/'.join([self.BASEURL, quote_plus(scope), quote_plus(lfn), 'rses'])
|
|
40
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
41
|
+
|
|
42
|
+
r = self._send_request(url, type_='GET')
|
|
43
|
+
|
|
44
|
+
if r.status_code == codes.ok:
|
|
45
|
+
rses = loads(r.text)
|
|
46
|
+
return rses
|
|
47
|
+
else:
|
|
48
|
+
print(r.status_code)
|
|
49
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
50
|
+
raise exc_cls(exc_msg)
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from requests.status_codes import codes
|
|
18
|
+
|
|
19
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
20
|
+
from rucio.common.utils import build_url, render_json
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ImportClient(BaseClient):
|
|
24
|
+
"""RSE client class for importing data into Rucio"""
|
|
25
|
+
|
|
26
|
+
IMPORT_BASEURL = 'import'
|
|
27
|
+
|
|
28
|
+
def import_data(self, data: dict[str, Any]) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Imports data into Rucio.
|
|
31
|
+
|
|
32
|
+
:param data: a dict containing data to be imported into Rucio.
|
|
33
|
+
"""
|
|
34
|
+
path = '/'.join([self.IMPORT_BASEURL])
|
|
35
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
36
|
+
|
|
37
|
+
r = self._send_request(url, type_='POST', data=render_json(**data))
|
|
38
|
+
if r.status_code == codes.created:
|
|
39
|
+
return r.text
|
|
40
|
+
else:
|
|
41
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
42
|
+
raise exc_cls(exc_msg)
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
from json import loads
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
17
|
+
|
|
18
|
+
from requests.status_codes import codes
|
|
19
|
+
|
|
20
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
21
|
+
from rucio.common.utils import build_url, render_json
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Iterator, Sequence
|
|
25
|
+
from datetime import datetime
|
|
26
|
+
|
|
27
|
+
from rucio.db.sqla.constants import LifetimeExceptionsState
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LifetimeClient(BaseClient):
|
|
31
|
+
|
|
32
|
+
"""Lifetime client class for working with Lifetime Model exceptions"""
|
|
33
|
+
|
|
34
|
+
LIFETIME_BASEURL = 'lifetime_exceptions'
|
|
35
|
+
|
|
36
|
+
def list_exceptions(
|
|
37
|
+
self,
|
|
38
|
+
exception_id: Optional[str] = None,
|
|
39
|
+
states: Optional['Sequence[LifetimeExceptionsState]'] = None
|
|
40
|
+
) -> 'Iterator[dict[str, Any]]':
|
|
41
|
+
"""
|
|
42
|
+
List exceptions to Lifetime Model.
|
|
43
|
+
|
|
44
|
+
:param id: The id of the exception
|
|
45
|
+
:param states: The states to filter
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
path = self.LIFETIME_BASEURL + '/'
|
|
49
|
+
params = {}
|
|
50
|
+
if exception_id:
|
|
51
|
+
params['exception_id'] = exception_id
|
|
52
|
+
if states:
|
|
53
|
+
params['states'] = exception_id
|
|
54
|
+
url = build_url(choice(self.list_hosts), path=path, params=params)
|
|
55
|
+
|
|
56
|
+
result = self._send_request(url)
|
|
57
|
+
if result.status_code == codes.ok:
|
|
58
|
+
lifetime_exceptions = self._load_json_data(result)
|
|
59
|
+
return lifetime_exceptions
|
|
60
|
+
else:
|
|
61
|
+
exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code)
|
|
62
|
+
raise exc_cls(exc_msg)
|
|
63
|
+
|
|
64
|
+
def add_exception(
|
|
65
|
+
self,
|
|
66
|
+
dids: list[dict[str, Any]],
|
|
67
|
+
account: str,
|
|
68
|
+
pattern: str,
|
|
69
|
+
comments: str,
|
|
70
|
+
expires_at: 'datetime'
|
|
71
|
+
) -> dict[str, Any]:
|
|
72
|
+
"""
|
|
73
|
+
Add exceptions to Lifetime Model.
|
|
74
|
+
|
|
75
|
+
:param dids: The list of dids
|
|
76
|
+
:param account: The account of the requester.
|
|
77
|
+
:param pattern: The account.
|
|
78
|
+
:param comments: The comments associated to the exception.
|
|
79
|
+
:param expires_at: The expiration date of the exception.
|
|
80
|
+
|
|
81
|
+
returns: The id of the exception.
|
|
82
|
+
"""
|
|
83
|
+
path = self.LIFETIME_BASEURL + '/'
|
|
84
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
85
|
+
data = {'dids': dids, 'account': account, 'pattern': pattern, 'comments': comments, 'expires_at': expires_at}
|
|
86
|
+
result = self._send_request(url, type_='POST', data=render_json(**data))
|
|
87
|
+
if result.status_code == codes.created:
|
|
88
|
+
return loads(result.text)
|
|
89
|
+
exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code, data=result.content)
|
|
90
|
+
raise exc_cls(exc_msg)
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
from urllib.parse import quote_plus
|
|
17
|
+
|
|
18
|
+
from requests.status_codes import codes
|
|
19
|
+
|
|
20
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
21
|
+
from rucio.common.utils import build_url, render_json
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Iterator, Mapping
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LockClient(BaseClient):
|
|
28
|
+
|
|
29
|
+
"""Lock client class for working with rucio locks"""
|
|
30
|
+
|
|
31
|
+
LOCKS_BASEURL = 'locks'
|
|
32
|
+
|
|
33
|
+
def get_dataset_locks(
|
|
34
|
+
self,
|
|
35
|
+
scope: str,
|
|
36
|
+
name: str
|
|
37
|
+
) -> "Iterator[dict[str, Any]]":
|
|
38
|
+
"""
|
|
39
|
+
Get a dataset locks of the specified dataset.
|
|
40
|
+
|
|
41
|
+
:param scope: the scope of the did of the locks to list.
|
|
42
|
+
:param name: the name of the did of the locks to list.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
path = '/'.join([self.LOCKS_BASEURL, quote_plus(scope), quote_plus(name)])
|
|
46
|
+
url = build_url(choice(self.list_hosts), path=path, params={'did_type': 'dataset'})
|
|
47
|
+
|
|
48
|
+
result = self._send_request(url)
|
|
49
|
+
if result.status_code == codes.ok: # pylint: disable-msg=E1101
|
|
50
|
+
locks = self._load_json_data(result)
|
|
51
|
+
return locks
|
|
52
|
+
else:
|
|
53
|
+
exc_cls, exc_msg = self._get_exception(headers=result.headers,
|
|
54
|
+
status_code=result.status_code)
|
|
55
|
+
raise exc_cls(exc_msg)
|
|
56
|
+
|
|
57
|
+
def get_locks_for_dids(
|
|
58
|
+
self,
|
|
59
|
+
dids: list["Mapping[str, Any]"],
|
|
60
|
+
**filter_args: dict[str, Any]
|
|
61
|
+
) -> list[dict[str, Any]]:
|
|
62
|
+
"""
|
|
63
|
+
Get list of locks for for all the files found, recursively, in the listed datasets or containers.
|
|
64
|
+
|
|
65
|
+
:param dids: list of dictionaries {"scope":..., "name":..., "type":...}
|
|
66
|
+
type can be either "dataset" or "container"
|
|
67
|
+
type is optional, but if specified, improves the query performance
|
|
68
|
+
:returns: list of dictionaries with lock info
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
# convert did list to list of dictionaries
|
|
72
|
+
if not all(did.get("type", "dataset") in ("dataset", "container") for did in dids):
|
|
73
|
+
raise ValueError("DID type can be either 'container' or 'dataset'")
|
|
74
|
+
|
|
75
|
+
path = '/'.join([self.LOCKS_BASEURL, "bulk_locks_for_dids"])
|
|
76
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
77
|
+
|
|
78
|
+
result = self._send_request(url, type_='POST', data=render_json(dids=dids))
|
|
79
|
+
if result.status_code == codes.ok: # pylint: disable-msg=E1101
|
|
80
|
+
out = []
|
|
81
|
+
for lock in self._load_json_data(result):
|
|
82
|
+
filter_ok = (not filter_args) or all(lock.get(name) == value for name, value in filter_args.items())
|
|
83
|
+
if filter_ok:
|
|
84
|
+
out.append(lock)
|
|
85
|
+
return out
|
|
86
|
+
else:
|
|
87
|
+
exc_cls, exc_msg = self._get_exception(headers=result.headers,
|
|
88
|
+
status_code=result.status_code)
|
|
89
|
+
raise exc_cls(exc_msg)
|
|
90
|
+
|
|
91
|
+
def get_dataset_locks_by_rse(self, rse: str) -> "Iterator[dict[str, Any]]":
|
|
92
|
+
"""
|
|
93
|
+
Get all dataset locks of the specified rse.
|
|
94
|
+
|
|
95
|
+
:param rse: the rse of the locks to list.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
path = '/'.join([self.LOCKS_BASEURL, rse])
|
|
99
|
+
url = build_url(choice(self.list_hosts), path=path, params={'did_type': 'dataset'})
|
|
100
|
+
|
|
101
|
+
result = self._send_request(url)
|
|
102
|
+
if result.status_code == codes.ok: # pylint: disable-msg=E1101
|
|
103
|
+
locks = self._load_json_data(result)
|
|
104
|
+
return locks
|
|
105
|
+
else:
|
|
106
|
+
exc_cls, exc_msg = self._get_exception(headers=result.headers,
|
|
107
|
+
status_code=result.status_code)
|
|
108
|
+
|
|
109
|
+
raise exc_cls(exc_msg)
|
|
@@ -0,0 +1,140 @@
|
|
|
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
|
+
from json import dumps, loads
|
|
16
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
17
|
+
from urllib.parse import quote_plus
|
|
18
|
+
|
|
19
|
+
from requests.status_codes import codes
|
|
20
|
+
|
|
21
|
+
from rucio.client.baseclient import BaseClient, choice
|
|
22
|
+
from rucio.common.utils import build_url
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from rucio.db.sqla.constants import KeyType
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MetaConventionClient(BaseClient):
|
|
29
|
+
|
|
30
|
+
"""Metadata client class for working with data identifier attributes"""
|
|
31
|
+
|
|
32
|
+
META_BASEURL = 'meta_conventions'
|
|
33
|
+
|
|
34
|
+
def add_key(self, key: str, key_type: Union['KeyType', str], value_type: Optional[str] = None, value_regexp: Optional[str] = None) -> Optional[bool]:
|
|
35
|
+
"""
|
|
36
|
+
Sends the request to add an allowed key for DID metadata (update the DID Metadata Conventions table with a new key).
|
|
37
|
+
|
|
38
|
+
:param key: the name for the new key.
|
|
39
|
+
:param key_type: the type of the key: all(container, dataset, file), collection(dataset or container), file, derived(compute from file for collection).
|
|
40
|
+
:param value_type: the type of the value, if defined.
|
|
41
|
+
:param value_regexp: the regular expression that values should match, if defined.
|
|
42
|
+
|
|
43
|
+
:return: True if key was created successfully.
|
|
44
|
+
:raises Duplicate: if key already exists.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
path = '/'.join([self.META_BASEURL, quote_plus(key)])
|
|
48
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
49
|
+
data = dumps({'value_type': value_type and str(value_type),
|
|
50
|
+
'value_regexp': value_regexp,
|
|
51
|
+
'key_type': key_type})
|
|
52
|
+
|
|
53
|
+
r = self._send_request(url, type_='POST', data=data)
|
|
54
|
+
|
|
55
|
+
if r.status_code == codes.created:
|
|
56
|
+
return True
|
|
57
|
+
else:
|
|
58
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
59
|
+
raise exc_cls(exc_msg)
|
|
60
|
+
|
|
61
|
+
def list_keys(self) -> Optional[list[str]]:
|
|
62
|
+
"""
|
|
63
|
+
Sends the request to list all keys for DID Metadata Conventions.
|
|
64
|
+
|
|
65
|
+
:return: a list containing the names of all keys.
|
|
66
|
+
"""
|
|
67
|
+
path = self.META_BASEURL + '/'
|
|
68
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
69
|
+
r = self._send_request(url)
|
|
70
|
+
if r.status_code == codes.ok:
|
|
71
|
+
keys = loads(r.text)
|
|
72
|
+
return keys
|
|
73
|
+
else:
|
|
74
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
75
|
+
raise exc_cls(exc_msg)
|
|
76
|
+
|
|
77
|
+
def list_values(self, key: str) -> Optional[list[str]]:
|
|
78
|
+
"""
|
|
79
|
+
Sends the request to lists all allowed values for a DID key (all values for a key in DID Metadata Conventions).
|
|
80
|
+
.
|
|
81
|
+
|
|
82
|
+
:return: a list containing the names of all values for a key.
|
|
83
|
+
"""
|
|
84
|
+
path = '/'.join([self.META_BASEURL, quote_plus(key)]) + '/'
|
|
85
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
86
|
+
r = self._send_request(url)
|
|
87
|
+
if r.status_code == codes.ok:
|
|
88
|
+
values = loads(r.text)
|
|
89
|
+
return values
|
|
90
|
+
else:
|
|
91
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
92
|
+
raise exc_cls(exc_msg)
|
|
93
|
+
|
|
94
|
+
def add_value(self, key: str, value: str) -> Optional[bool]:
|
|
95
|
+
"""
|
|
96
|
+
Sends the request to add a value for a key in DID Metadata Convention.
|
|
97
|
+
|
|
98
|
+
:param key: the name for key.
|
|
99
|
+
:param value: the value.
|
|
100
|
+
|
|
101
|
+
:return: True if value was created successfully.
|
|
102
|
+
:raises Duplicate: if valid already exists.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
path = '/'.join([self.META_BASEURL, quote_plus(key)]) + '/'
|
|
106
|
+
data = dumps({'value': value})
|
|
107
|
+
url = build_url(choice(self.list_hosts), path=path)
|
|
108
|
+
r = self._send_request(url, type_='POST', data=data)
|
|
109
|
+
if r.status_code == codes.created:
|
|
110
|
+
return True
|
|
111
|
+
else:
|
|
112
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
113
|
+
raise exc_cls(exc_msg)
|
|
114
|
+
|
|
115
|
+
def del_value(self, key, value):
|
|
116
|
+
"""
|
|
117
|
+
Delete a key in the DID Metadata Conventions table.
|
|
118
|
+
|
|
119
|
+
:param key: the name for key.
|
|
120
|
+
:param value: the value.
|
|
121
|
+
"""
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def del_key(self, key):
|
|
125
|
+
"""
|
|
126
|
+
Delete an allowed key.
|
|
127
|
+
|
|
128
|
+
:param key: the name for key.
|
|
129
|
+
"""
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
def update_key(self, key, type_=None, regexp=None):
|
|
133
|
+
"""
|
|
134
|
+
Update a key.
|
|
135
|
+
|
|
136
|
+
:param key: the name for key.
|
|
137
|
+
:param type_: the type of the value, if defined.
|
|
138
|
+
:param regexp: the regular expression that values should match, if defined.
|
|
139
|
+
"""
|
|
140
|
+
pass
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
from json import loads
|
|
16
|
+
|
|
17
|
+
from requests.status_codes import codes
|
|
18
|
+
|
|
19
|
+
from rucio.client.baseclient import BaseClient
|
|
20
|
+
from rucio.common.utils import build_url
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PingClient(BaseClient):
|
|
24
|
+
|
|
25
|
+
"""Ping client class"""
|
|
26
|
+
|
|
27
|
+
def ping(self):
|
|
28
|
+
"""
|
|
29
|
+
Sends a ping request to the rucio server.
|
|
30
|
+
|
|
31
|
+
:return: Dictonnary with server information
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
headers = None
|
|
35
|
+
path = 'ping'
|
|
36
|
+
url = build_url(self.host, path=path)
|
|
37
|
+
r = self._send_request(url, headers=headers, type_='GET')
|
|
38
|
+
|
|
39
|
+
if r.status_code == codes.ok:
|
|
40
|
+
server_info = loads(r.text)
|
|
41
|
+
return server_info
|
|
42
|
+
|
|
43
|
+
exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
|
|
44
|
+
raise exc_cls(exc_msg)
|