rucio 37.2.0__py3-none-any.whl → 37.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/cli/rule.py +1 -1
- rucio/client/accountclient.py +205 -60
- rucio/client/accountlimitclient.py +84 -25
- rucio/client/baseclient.py +85 -48
- rucio/client/client.py +49 -41
- rucio/client/configclient.py +36 -13
- rucio/client/credentialclient.py +16 -6
- rucio/client/didclient.py +321 -133
- rucio/client/diracclient.py +13 -6
- rucio/client/downloadclient.py +435 -165
- rucio/client/exportclient.py +8 -2
- rucio/client/fileclient.py +10 -3
- rucio/client/importclient.py +4 -1
- rucio/client/lifetimeclient.py +48 -31
- rucio/client/lockclient.py +22 -7
- rucio/client/metaconventionsclient.py +59 -21
- rucio/client/pingclient.py +3 -1
- rucio/client/replicaclient.py +213 -96
- rucio/client/requestclient.py +123 -16
- rucio/client/rseclient.py +385 -160
- rucio/client/ruleclient.py +147 -51
- rucio/client/scopeclient.py +35 -10
- rucio/client/subscriptionclient.py +60 -27
- rucio/client/touchclient.py +16 -7
- rucio/common/plugins.py +1 -1
- rucio/core/did.py +2 -3
- rucio/core/permission/generic.py +37 -1
- rucio/core/replica.py +6 -6
- rucio/core/rule.py +5 -3
- rucio/daemons/judge/evaluator.py +1 -1
- rucio/db/sqla/util.py +1 -1
- rucio/gateway/authentication.py +58 -88
- rucio/gateway/config.py +63 -75
- rucio/gateway/did.py +245 -329
- rucio/gateway/dirac.py +33 -34
- rucio/gateway/exporter.py +27 -30
- rucio/gateway/importer.py +12 -14
- rucio/gateway/lifetime_exception.py +16 -24
- rucio/gateway/lock.py +27 -40
- rucio/gateway/replica.py +334 -249
- rucio/gateway/request.py +176 -103
- rucio/gateway/rse.py +191 -218
- rucio/gateway/rule.py +115 -146
- rucio/gateway/scope.py +18 -25
- rucio/gateway/subscription.py +90 -108
- rucio/gateway/trace.py +48 -0
- rucio/vcsversion.py +3 -3
- rucio/web/rest/flaskapi/v1/accounts.py +2 -2
- rucio/web/rest/flaskapi/v1/auth.py +15 -0
- rucio/web/rest/flaskapi/v1/common.py +3 -0
- rucio/web/rest/flaskapi/v1/config.py +7 -7
- rucio/web/rest/flaskapi/v1/dids.py +55 -55
- rucio/web/rest/flaskapi/v1/dirac.py +2 -2
- rucio/web/rest/flaskapi/v1/export.py +1 -1
- rucio/web/rest/flaskapi/v1/import.py +1 -1
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +5 -5
- rucio/web/rest/flaskapi/v1/locks.py +4 -4
- rucio/web/rest/flaskapi/v1/main.py +17 -10
- rucio/web/rest/flaskapi/v1/redirect.py +1 -1
- rucio/web/rest/flaskapi/v1/replicas.py +30 -29
- rucio/web/rest/flaskapi/v1/requests.py +211 -20
- rucio/web/rest/flaskapi/v1/rses.py +37 -37
- rucio/web/rest/flaskapi/v1/rules.py +15 -15
- rucio/web/rest/flaskapi/v1/scopes.py +3 -3
- rucio/web/rest/flaskapi/v1/subscriptions.py +9 -9
- rucio/web/rest/flaskapi/v1/traces.py +75 -77
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/rucio.cfg.template +0 -1
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -1
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/METADATA +1 -1
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/RECORD +127 -126
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/WHEEL +1 -1
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/requirements.server.txt +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-abacus-account +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-abacus-rse +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-admin +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-atropos +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-auditor +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-automatix +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-bb8 +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-cache-client +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-receiver +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-conveyor-throttler +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-dumper +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-follower +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-hermes +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-judge-cleaner +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-judge-injector +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-kronos +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-minos +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-necromancer +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-reaper +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-replica-recoverer +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-transmogrifier +0 -0
- {rucio-37.2.0.data → rucio-37.4.0.data}/scripts/rucio-undertaker +0 -0
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/licenses/LICENSE +0 -0
- {rucio-37.2.0.dist-info → rucio-37.4.0.dist-info}/top_level.txt +0 -0
rucio/gateway/dirac.py
CHANGED
|
@@ -15,28 +15,25 @@
|
|
|
15
15
|
from typing import TYPE_CHECKING, Any, Optional
|
|
16
16
|
|
|
17
17
|
from rucio.common.exception import AccessDenied
|
|
18
|
+
from rucio.common.types import InternalScope
|
|
18
19
|
from rucio.common.utils import extract_scope
|
|
19
20
|
from rucio.core import dirac
|
|
20
21
|
from rucio.core.rse import get_rse_id
|
|
21
|
-
from rucio.
|
|
22
|
+
from rucio.core.scope import list_scopes
|
|
23
|
+
from rucio.db.sqla.constants import DatabaseOperationType
|
|
24
|
+
from rucio.db.sqla.session import db_session
|
|
22
25
|
from rucio.gateway.permission import has_permission
|
|
23
|
-
from rucio.gateway.scope import list_scopes
|
|
24
26
|
|
|
25
27
|
if TYPE_CHECKING:
|
|
26
28
|
from collections.abc import Iterable
|
|
27
29
|
|
|
28
|
-
from sqlalchemy.orm import Session
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
@transactional_session
|
|
32
31
|
def add_files(
|
|
33
32
|
lfns: "Iterable[dict[str, Any]]",
|
|
34
33
|
issuer: str,
|
|
35
34
|
ignore_availability: bool,
|
|
36
35
|
parents_metadata: Optional[dict[str, Any]] = None,
|
|
37
36
|
vo: str = 'def',
|
|
38
|
-
*,
|
|
39
|
-
session: "Session"
|
|
40
37
|
) -> None:
|
|
41
38
|
"""
|
|
42
39
|
Bulk add files :
|
|
@@ -49,35 +46,37 @@ def add_files(
|
|
|
49
46
|
:param ignore_availability: A boolean to ignore blocked sites.
|
|
50
47
|
:param parents_metadata: Metadata for selected hierarchy DIDs. (dictionary {'lpn': {key : value}}). Default=None
|
|
51
48
|
:param vo: The VO to act on.
|
|
52
|
-
:param session: The database session in use.
|
|
53
49
|
|
|
54
50
|
"""
|
|
55
|
-
scopes = list_scopes(vo=vo, session=session)
|
|
56
|
-
dids = []
|
|
57
|
-
rses = {}
|
|
58
|
-
for lfn in lfns:
|
|
59
|
-
scope, name = extract_scope(lfn['lfn'], scopes)
|
|
60
|
-
dids.append({'scope': scope, 'name': name})
|
|
61
|
-
rse = lfn['rse']
|
|
62
|
-
if rse not in rses:
|
|
63
|
-
rse_id = get_rse_id(rse=rse, vo=vo, session=session)
|
|
64
|
-
rses[rse] = rse_id
|
|
65
|
-
lfn['rse_id'] = rses[rse]
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
with db_session(DatabaseOperationType.WRITE) as session:
|
|
53
|
+
filter_ = {'scope': InternalScope(scope='*', vo=vo)}
|
|
54
|
+
scopes = [scope.external for scope in list_scopes(filter_=filter_, session=session)]
|
|
55
|
+
dids = []
|
|
56
|
+
rses = {}
|
|
57
|
+
for lfn in lfns:
|
|
58
|
+
scope, name = extract_scope(lfn['lfn'], scopes)
|
|
59
|
+
dids.append({'scope': scope, 'name': name})
|
|
60
|
+
rse = lfn['rse']
|
|
61
|
+
if rse not in rses:
|
|
62
|
+
rse_id = get_rse_id(rse=rse, vo=vo, session=session)
|
|
63
|
+
rses[rse] = rse_id
|
|
64
|
+
lfn['rse_id'] = rses[rse]
|
|
76
65
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
# Check if the issuer can add dids and use skip_availabitlity
|
|
67
|
+
for rse in rses:
|
|
68
|
+
rse_id = rses[rse]
|
|
69
|
+
kwargs = {'rse': rse, 'rse_id': rse_id}
|
|
70
|
+
auth_result = has_permission(issuer=issuer, action='add_replicas', kwargs=kwargs, vo=vo, session=session)
|
|
71
|
+
if not auth_result.allowed:
|
|
72
|
+
raise AccessDenied('Account %s can not add file replicas on %s for VO %s. %s' % (issuer, rse, vo, auth_result.message))
|
|
73
|
+
if not has_permission(issuer=issuer, action='skip_availability_check', kwargs=kwargs, vo=vo, session=session):
|
|
74
|
+
ignore_availability = False
|
|
75
|
+
|
|
76
|
+
# Check if the issuer can add the files
|
|
77
|
+
kwargs = {'issuer': issuer, 'dids': dids}
|
|
78
|
+
auth_result = has_permission(issuer=issuer, action='add_dids', kwargs=kwargs, vo=vo, session=session)
|
|
79
|
+
if not auth_result.allowed:
|
|
80
|
+
raise AccessDenied('Account %s can not bulk add data identifier for VO %s. %s' % (issuer, vo, auth_result.message))
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
dirac.add_files(lfns=lfns, account=issuer, ignore_availability=ignore_availability, parents_metadata=parents_metadata, vo=vo, session=session)
|
rucio/gateway/exporter.py
CHANGED
|
@@ -12,49 +12,46 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import
|
|
15
|
+
from typing import Any
|
|
16
16
|
|
|
17
17
|
from rucio.common import exception
|
|
18
18
|
from rucio.core import exporter
|
|
19
19
|
from rucio.core.rse import get_rse_name
|
|
20
|
-
from rucio.db.sqla.
|
|
20
|
+
from rucio.db.sqla.constants import DatabaseOperationType
|
|
21
|
+
from rucio.db.sqla.session import db_session
|
|
21
22
|
from rucio.gateway import permission
|
|
22
23
|
|
|
23
|
-
if TYPE_CHECKING:
|
|
24
|
-
from sqlalchemy.orm import Session
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
@read_session
|
|
28
|
-
def export_data(issuer: str, distance: bool = True, vo: str = 'def', *, session: "Session") -> dict[str, Any]:
|
|
25
|
+
def export_data(issuer: str, distance: bool = True, vo: str = 'def') -> dict[str, Any]:
|
|
29
26
|
"""
|
|
30
27
|
Export data from Rucio.
|
|
31
28
|
|
|
32
29
|
:param issuer: the issuer.
|
|
33
30
|
:param distance: To enable the reporting of distance.
|
|
34
31
|
:param vo: the VO of the issuer.
|
|
35
|
-
:param session: The database session in use.
|
|
36
32
|
"""
|
|
37
33
|
kwargs = {'issuer': issuer}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
35
|
+
auth_result = permission.has_permission(issuer=issuer, vo=vo, action='export', kwargs=kwargs, session=session)
|
|
36
|
+
if not auth_result.allowed:
|
|
37
|
+
raise exception.AccessDenied('Account %s can not export data. %s' % (issuer, auth_result.message))
|
|
38
|
+
|
|
39
|
+
data = exporter.export_data(distance=distance, vo=vo, session=session)
|
|
40
|
+
rses = {}
|
|
41
|
+
distances = {}
|
|
42
|
+
|
|
43
|
+
for rse_id in data['rses']:
|
|
44
|
+
rse = data['rses'][rse_id]
|
|
45
|
+
rses[get_rse_name(rse_id=rse_id, session=session)] = rse
|
|
46
|
+
data['rses'] = rses
|
|
47
|
+
|
|
48
|
+
if distance:
|
|
49
|
+
for src_id in data['distances']:
|
|
50
|
+
dests = data['distances'][src_id]
|
|
51
|
+
src = get_rse_name(rse_id=src_id, session=session)
|
|
52
|
+
distances[src] = {}
|
|
53
|
+
for dest_id in dests:
|
|
54
|
+
dest = get_rse_name(rse_id=dest_id, session=session)
|
|
55
|
+
distances[src][dest] = dests[dest_id]
|
|
56
|
+
data['distances'] = distances
|
|
60
57
|
return data
|
rucio/gateway/importer.py
CHANGED
|
@@ -12,35 +12,33 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import
|
|
15
|
+
from typing import Any
|
|
16
16
|
|
|
17
17
|
from rucio.common import exception
|
|
18
18
|
from rucio.common.schema import validate_schema
|
|
19
19
|
from rucio.common.types import InternalAccount
|
|
20
20
|
from rucio.core import importer
|
|
21
|
-
from rucio.db.sqla.
|
|
21
|
+
from rucio.db.sqla.constants import DatabaseOperationType
|
|
22
|
+
from rucio.db.sqla.session import db_session
|
|
22
23
|
from rucio.gateway import permission
|
|
23
24
|
|
|
24
|
-
if TYPE_CHECKING:
|
|
25
|
-
from sqlalchemy.orm import Session
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
@transactional_session
|
|
29
|
-
def import_data(data: dict[str, Any], issuer: str, vo: str = 'def', *, session: "Session") -> None:
|
|
26
|
+
def import_data(data: dict[str, Any], issuer: str, vo: str = 'def') -> None:
|
|
30
27
|
"""
|
|
31
28
|
Import data to add/update/delete records in Rucio.
|
|
32
29
|
|
|
33
30
|
:param data: data to be imported.
|
|
34
31
|
:param issuer: the issuer.
|
|
35
32
|
:param vo: the VO of the issuer.
|
|
36
|
-
:param session: The database session in use.
|
|
37
33
|
"""
|
|
38
34
|
kwargs = {'issuer': issuer}
|
|
39
35
|
validate_schema(name='import', obj=data, vo=vo)
|
|
40
|
-
auth_result = permission.has_permission(issuer=issuer, vo=vo, action='import', kwargs=kwargs, session=session)
|
|
41
|
-
if not auth_result.allowed:
|
|
42
|
-
raise exception.AccessDenied('Account %s can not import data. %s' % (issuer, auth_result.message))
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
with db_session(DatabaseOperationType.WRITE) as session:
|
|
38
|
+
auth_result = permission.has_permission(issuer=issuer, vo=vo, action='import', kwargs=kwargs, session=session)
|
|
39
|
+
if not auth_result.allowed:
|
|
40
|
+
raise exception.AccessDenied('Account %s can not import data. %s' % (issuer, auth_result.message))
|
|
41
|
+
|
|
42
|
+
for account in data.get('accounts', []):
|
|
43
|
+
account['account'] = InternalAccount(account['account'], vo=vo)
|
|
44
|
+
return importer.import_data(data, vo=vo, session=session)
|
|
@@ -18,24 +18,20 @@ from rucio.common import exception
|
|
|
18
18
|
from rucio.common.types import InternalAccount, InternalScope
|
|
19
19
|
from rucio.common.utils import gateway_update_return_dict
|
|
20
20
|
from rucio.core import lifetime_exception
|
|
21
|
-
from rucio.db.sqla.
|
|
21
|
+
from rucio.db.sqla.constants import DatabaseOperationType
|
|
22
|
+
from rucio.db.sqla.session import db_session
|
|
22
23
|
from rucio.gateway import permission
|
|
23
24
|
|
|
24
25
|
if TYPE_CHECKING:
|
|
25
26
|
from collections.abc import Iterable, Iterator
|
|
26
27
|
|
|
27
|
-
from sqlalchemy.orm import Session
|
|
28
|
-
|
|
29
28
|
from rucio.db.sqla.constants import LifetimeExceptionsState
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
@stream_session
|
|
33
31
|
def list_exceptions(
|
|
34
32
|
exception_id: Optional[str] = None,
|
|
35
33
|
states: Optional["Iterable[LifetimeExceptionsState]"] = None,
|
|
36
34
|
vo: str = 'def',
|
|
37
|
-
*,
|
|
38
|
-
session: "Session"
|
|
39
35
|
) -> 'Iterator[dict[str, Any]]':
|
|
40
36
|
"""
|
|
41
37
|
List exceptions to Lifetime Model.
|
|
@@ -43,16 +39,15 @@ def list_exceptions(
|
|
|
43
39
|
:param id: The id of the exception
|
|
44
40
|
:param states: The states to filter
|
|
45
41
|
:param vo: The VO to act on
|
|
46
|
-
:param session: The database session in use.
|
|
47
42
|
"""
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
45
|
+
exceptions = lifetime_exception.list_exceptions(exception_id=exception_id, states=states, session=session)
|
|
46
|
+
for e in exceptions:
|
|
47
|
+
if vo == e['scope'].vo:
|
|
48
|
+
yield gateway_update_return_dict(e, session=session)
|
|
53
49
|
|
|
54
50
|
|
|
55
|
-
@transactional_session
|
|
56
51
|
def add_exception(
|
|
57
52
|
dids: "Iterable[dict[str, Any]]",
|
|
58
53
|
account: str,
|
|
@@ -60,8 +55,6 @@ def add_exception(
|
|
|
60
55
|
comments: str,
|
|
61
56
|
expires_at: str,
|
|
62
57
|
vo: str = 'def',
|
|
63
|
-
*,
|
|
64
|
-
session: "Session"
|
|
65
58
|
) -> dict[str, Any]:
|
|
66
59
|
"""
|
|
67
60
|
Add exceptions to Lifetime Model.
|
|
@@ -72,7 +65,6 @@ def add_exception(
|
|
|
72
65
|
:param comments: The comments associated to the exception.
|
|
73
66
|
:param expires_at: The expiration date of the exception.
|
|
74
67
|
:param vo: The VO to act on.
|
|
75
|
-
:param session: The database session in use.
|
|
76
68
|
|
|
77
69
|
returns: The id of the exception.
|
|
78
70
|
"""
|
|
@@ -80,7 +72,9 @@ def add_exception(
|
|
|
80
72
|
internal_account = InternalAccount(account, vo=vo)
|
|
81
73
|
for did in dids:
|
|
82
74
|
did['scope'] = InternalScope(did['scope'], vo=vo)
|
|
83
|
-
|
|
75
|
+
|
|
76
|
+
with db_session(DatabaseOperationType.WRITE) as session:
|
|
77
|
+
exceptions = lifetime_exception.add_exception(dids=dids, account=internal_account, pattern=pattern, comments=comments, expires_at=expires_at, session=session)
|
|
84
78
|
|
|
85
79
|
for key in exceptions:
|
|
86
80
|
if key == 'exceptions':
|
|
@@ -96,14 +90,11 @@ def add_exception(
|
|
|
96
90
|
return exceptions
|
|
97
91
|
|
|
98
92
|
|
|
99
|
-
@transactional_session
|
|
100
93
|
def update_exception(
|
|
101
94
|
exception_id: str,
|
|
102
95
|
state: 'LifetimeExceptionsState',
|
|
103
96
|
issuer: str,
|
|
104
97
|
vo: str = 'def',
|
|
105
|
-
*,
|
|
106
|
-
session: "Session"
|
|
107
98
|
) -> None:
|
|
108
99
|
"""
|
|
109
100
|
Update exceptions state to Lifetime Model.
|
|
@@ -112,10 +103,11 @@ def update_exception(
|
|
|
112
103
|
:param state: The states to filter.
|
|
113
104
|
:param issuer: The issuer account.
|
|
114
105
|
:param vo: The VO to act on.
|
|
115
|
-
:param session: The database session in use.
|
|
116
106
|
"""
|
|
117
107
|
kwargs = {'exception_id': exception_id, 'vo': vo}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
108
|
+
|
|
109
|
+
with db_session(DatabaseOperationType.WRITE) as session:
|
|
110
|
+
auth_result = permission.has_permission(issuer=issuer, vo=vo, action='update_lifetime_exceptions', kwargs=kwargs, session=session)
|
|
111
|
+
if not auth_result.allowed:
|
|
112
|
+
raise exception.AccessDenied('Account %s can not update lifetime exceptions. %s' % (issuer, auth_result.message))
|
|
113
|
+
return lifetime_exception.update_exception(exception_id=exception_id, state=state, session=session)
|
rucio/gateway/lock.py
CHANGED
|
@@ -19,26 +19,21 @@ from rucio.common.types import InternalScope
|
|
|
19
19
|
from rucio.common.utils import gateway_update_return_dict
|
|
20
20
|
from rucio.core import lock
|
|
21
21
|
from rucio.core.rse import get_rse_id
|
|
22
|
-
from rucio.db.sqla.constants import DIDType
|
|
23
|
-
from rucio.db.sqla.session import
|
|
22
|
+
from rucio.db.sqla.constants import DatabaseOperationType, DIDType
|
|
23
|
+
from rucio.db.sqla.session import db_session
|
|
24
24
|
|
|
25
25
|
if TYPE_CHECKING:
|
|
26
26
|
from collections.abc import Iterable, Iterator
|
|
27
27
|
|
|
28
|
-
from sqlalchemy.orm import Session
|
|
29
|
-
|
|
30
28
|
|
|
31
29
|
LOGGER = logging.getLogger('lock')
|
|
32
30
|
LOGGER.setLevel(logging.DEBUG)
|
|
33
31
|
|
|
34
32
|
|
|
35
|
-
@stream_session
|
|
36
33
|
def get_dataset_locks(
|
|
37
34
|
scope: str,
|
|
38
35
|
name: str,
|
|
39
36
|
vo: str = 'def',
|
|
40
|
-
*,
|
|
41
|
-
session: "Session"
|
|
42
37
|
) -> 'Iterator[dict[str, Any]]':
|
|
43
38
|
"""
|
|
44
39
|
Get the dataset locks of a dataset.
|
|
@@ -46,24 +41,21 @@ def get_dataset_locks(
|
|
|
46
41
|
:param scope: Scope of the dataset.
|
|
47
42
|
:param name: Name of the dataset.
|
|
48
43
|
:param vo: The VO to act on.
|
|
49
|
-
:param session: The database session in use.
|
|
50
44
|
:return: List of dicts {'rse_id': ..., 'state': ...}
|
|
51
45
|
"""
|
|
52
46
|
|
|
53
47
|
internal_scope = InternalScope(scope, vo=vo)
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
50
|
+
locks = lock.get_dataset_locks(scope=internal_scope, name=name, session=session)
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
for lock_object in locks:
|
|
53
|
+
yield gateway_update_return_dict(lock_object, session=session)
|
|
59
54
|
|
|
60
55
|
|
|
61
|
-
@stream_session
|
|
62
56
|
def get_dataset_locks_bulk(
|
|
63
57
|
dids: 'Iterable[dict[str, Any]]',
|
|
64
58
|
vo: str = 'def',
|
|
65
|
-
*,
|
|
66
|
-
session: "Session"
|
|
67
59
|
) -> 'Iterator[dict[str, Any]]':
|
|
68
60
|
"""
|
|
69
61
|
Get the dataset locks for multiple datasets or containers.
|
|
@@ -72,7 +64,6 @@ def get_dataset_locks_bulk(
|
|
|
72
64
|
"type" is optional. If present, will be either DIDType.DATASET or DIDType.CONTAINER,
|
|
73
65
|
or string "dataset" or "container"
|
|
74
66
|
:param vo: The VO to act on.
|
|
75
|
-
:param session: The database session in use.
|
|
76
67
|
:return: Generator of dicts describing found locks {'rse_id': ..., 'state': ...}. Duplicates are removed
|
|
77
68
|
"""
|
|
78
69
|
|
|
@@ -96,58 +87,54 @@ def get_dataset_locks_bulk(
|
|
|
96
87
|
dids_converted.append(did)
|
|
97
88
|
|
|
98
89
|
seen = set()
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
|
|
91
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
92
|
+
for lock_info in lock.get_dataset_locks_bulk(dids_converted, session=session):
|
|
93
|
+
# filter duplicates - same scope, name, rse_id, rule_id
|
|
94
|
+
scope_str = str(lock_info["scope"])
|
|
95
|
+
key = (scope_str, lock_info["name"], lock_info["rse_id"], lock_info["rule_id"])
|
|
96
|
+
if key not in seen:
|
|
97
|
+
seen.add(key)
|
|
98
|
+
yield lock_info
|
|
106
99
|
|
|
107
100
|
|
|
108
|
-
@stream_session
|
|
109
101
|
def get_dataset_locks_by_rse(
|
|
110
102
|
rse: str,
|
|
111
103
|
vo: str = 'def',
|
|
112
|
-
*,
|
|
113
|
-
session: "Session"
|
|
114
104
|
) -> 'Iterator[dict[str, Any]]':
|
|
115
105
|
"""
|
|
116
106
|
Get the dataset locks of an RSE.
|
|
117
107
|
|
|
118
108
|
:param rse: RSE name.
|
|
119
109
|
:param vo: The VO to act on.
|
|
120
|
-
:param session: The database session in use.
|
|
121
110
|
:return: List of dicts {'rse_id': ..., 'state': ...}
|
|
122
111
|
"""
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
114
|
+
rse_id = get_rse_id(rse=rse, vo=vo, session=session)
|
|
115
|
+
locks = lock.get_dataset_locks_by_rse_id(rse_id=rse_id, session=session)
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
|
|
117
|
+
for lock_object in locks:
|
|
118
|
+
yield gateway_update_return_dict(lock_object, session=session)
|
|
129
119
|
|
|
130
120
|
|
|
131
|
-
@stream_session
|
|
132
121
|
def get_replica_locks_for_rule_id(
|
|
133
122
|
rule_id: str,
|
|
134
123
|
vo: str = 'def',
|
|
135
|
-
*,
|
|
136
|
-
session: "Session"
|
|
137
124
|
) -> 'Iterator[dict[str, Any]]':
|
|
138
125
|
"""
|
|
139
126
|
Get the replica locks for a rule_id.
|
|
140
127
|
|
|
141
128
|
:param rule_id: Rule ID.
|
|
142
129
|
:param vo: The VO to act on.
|
|
143
|
-
:param session: The database session in use.
|
|
144
130
|
:return: List of dicts.
|
|
145
131
|
"""
|
|
146
132
|
|
|
147
|
-
|
|
133
|
+
with db_session(DatabaseOperationType.READ) as session:
|
|
134
|
+
locks = lock.get_replica_locks_for_rule_id(rule_id=rule_id, session=session)
|
|
148
135
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
136
|
+
for lock_object in locks:
|
|
137
|
+
if lock_object['scope'].vo != vo: # rule is on a different VO, so don't return any locks
|
|
138
|
+
LOGGER.debug('rule id %s is not present on VO %s' % (rule_id, vo))
|
|
139
|
+
break
|
|
140
|
+
yield gateway_update_return_dict(lock_object, session=session)
|