rucio 37.6.0__py3-none-any.whl → 37.7.1__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/bin_legacy/rucio.py +40 -21
- rucio/cli/rule.py +9 -5
- rucio/client/baseclient.py +4 -3
- rucio/client/downloadclient.py +2 -1
- rucio/client/exportclient.py +45 -4
- rucio/client/pingclient.py +35 -4
- rucio/client/touchclient.py +2 -1
- rucio/client/uploadclient.py +3 -2
- rucio/common/cache.py +1 -2
- rucio/common/client.py +4 -30
- rucio/common/config.py +26 -1
- rucio/common/constants.py +3 -1
- rucio/common/plugins.py +2 -2
- rucio/common/policy.py +3 -2
- rucio/common/schema/__init__.py +4 -3
- rucio/common/types.py +7 -5
- rucio/core/account.py +2 -1
- rucio/core/account_limit.py +3 -2
- rucio/core/did.py +8 -7
- rucio/core/dirac.py +2 -1
- rucio/core/distance.py +2 -1
- rucio/core/exporter.py +3 -2
- rucio/core/importer.py +5 -5
- rucio/core/permission/__init__.py +2 -1
- rucio/core/replica.py +5 -5
- rucio/core/request.py +2 -2
- rucio/core/rse.py +7 -7
- rucio/core/rule.py +8 -8
- rucio/core/transfer.py +2 -2
- rucio/core/vo.py +2 -1
- rucio/daemons/atropos/atropos.py +2 -1
- rucio/daemons/automatix/automatix.py +5 -5
- rucio/daemons/badreplicas/minos.py +3 -2
- rucio/daemons/bb8/bb8.py +2 -1
- rucio/daemons/bb8/nuclei_background_rebalance.py +2 -2
- rucio/daemons/conveyor/common.py +3 -3
- rucio/daemons/conveyor/submitter.py +2 -1
- rucio/daemons/hermes/hermes.py +36 -6
- rucio/daemons/reaper/dark_reaper.py +5 -4
- rucio/daemons/reaper/reaper.py +7 -7
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +3 -3
- rucio/daemons/tracer/kronos.py +3 -2
- rucio/daemons/transmogrifier/transmogrifier.py +70 -68
- rucio/daemons/undertaker/undertaker.py +2 -1
- rucio/db/sqla/models.py +2 -2
- rucio/db/sqla/util.py +3 -2
- rucio/gateway/account.py +13 -12
- rucio/gateway/account_limit.py +90 -116
- rucio/gateway/authentication.py +9 -8
- rucio/gateway/config.py +11 -10
- rucio/gateway/credential.py +2 -1
- rucio/gateway/did.py +32 -32
- rucio/gateway/dirac.py +2 -1
- rucio/gateway/exporter.py +2 -1
- rucio/gateway/heartbeat.py +3 -2
- rucio/gateway/identity.py +4 -3
- rucio/gateway/importer.py +2 -1
- rucio/gateway/lifetime_exception.py +4 -3
- rucio/gateway/lock.py +6 -5
- rucio/gateway/meta_conventions.py +3 -2
- rucio/gateway/permission.py +2 -1
- rucio/gateway/quarantined_replica.py +2 -1
- rucio/gateway/replica.py +18 -18
- rucio/gateway/request.py +10 -10
- rucio/gateway/rse.py +27 -26
- rucio/gateway/rule.py +12 -11
- rucio/gateway/scope.py +4 -3
- rucio/gateway/subscription.py +7 -6
- rucio/gateway/vo.py +5 -4
- rucio/rse/__init__.py +7 -6
- rucio/rse/rsemanager.py +5 -4
- rucio/rse/translation.py +2 -2
- rucio/tests/common.py +2 -1
- rucio/vcsversion.py +3 -3
- rucio/web/rest/flaskapi/v1/accountlimits.py +5 -5
- rucio/web/rest/flaskapi/v1/archives.py +2 -1
- rucio/web/rest/flaskapi/v1/common.py +4 -3
- rucio/web/rest/flaskapi/v1/dids.py +205 -154
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/METADATA +1 -1
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/RECORD +139 -139
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/rucio.cfg.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/requirements.server.txt +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-abacus-account +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-abacus-rse +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-admin +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-atropos +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-auditor +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-automatix +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-bb8 +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-cache-client +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-receiver +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-conveyor-throttler +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-dumper +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-follower +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-hermes +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-judge-cleaner +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-judge-injector +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-kronos +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-minos +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-minos-temporary-expiration +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-necromancer +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-reaper +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-replica-recoverer +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-transmogrifier +0 -0
- {rucio-37.6.0.data → rucio-37.7.1.data}/scripts/rucio-undertaker +0 -0
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/WHEEL +0 -0
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/licenses/LICENSE +0 -0
- {rucio-37.6.0.dist-info → rucio-37.7.1.dist-info}/top_level.txt +0 -0
|
@@ -22,7 +22,6 @@ from rucio.common.exception import (
|
|
|
22
22
|
DatabaseException,
|
|
23
23
|
DataIdentifierAlreadyExists,
|
|
24
24
|
DataIdentifierNotFound,
|
|
25
|
-
Duplicate,
|
|
26
25
|
DuplicateContent,
|
|
27
26
|
FileAlreadyExists,
|
|
28
27
|
FileConsistencyMismatch,
|
|
@@ -1295,172 +1294,304 @@ class Parents(ErrorHandlingMethodView):
|
|
|
1295
1294
|
class Meta(ErrorHandlingMethodView):
|
|
1296
1295
|
|
|
1297
1296
|
@check_accept_header_wrapper_flask(['application/json'])
|
|
1298
|
-
def get(self, scope_name):
|
|
1297
|
+
def get(self, scope_name, key=None):
|
|
1299
1298
|
"""
|
|
1300
1299
|
---
|
|
1301
1300
|
summary: Get metadata
|
|
1302
|
-
description: "
|
|
1301
|
+
description: "Retrieve the metadata of a data identifier (DID)."
|
|
1303
1302
|
tags:
|
|
1304
1303
|
- Data Identifiers
|
|
1305
1304
|
parameters:
|
|
1306
1305
|
- name: scope_name
|
|
1307
1306
|
in: path
|
|
1308
|
-
description: "The scope and the name of the DID."
|
|
1307
|
+
description: "The scope and the name of the DID (e.g., `scope:name`)."
|
|
1308
|
+
required: true
|
|
1309
|
+
style: simple
|
|
1309
1310
|
schema:
|
|
1310
1311
|
type: string
|
|
1311
|
-
style: simple
|
|
1312
1312
|
- name: plugin
|
|
1313
1313
|
in: query
|
|
1314
|
-
description: "The plugin to use."
|
|
1314
|
+
description: "The metadata plugin to use."
|
|
1315
|
+
required: false
|
|
1316
|
+
style: form
|
|
1315
1317
|
schema:
|
|
1316
1318
|
type: string
|
|
1317
1319
|
default: DID_COLUMN
|
|
1318
1320
|
responses:
|
|
1319
1321
|
200:
|
|
1320
|
-
description: "OK"
|
|
1322
|
+
description: "OK – returns the metadata of the DID."
|
|
1321
1323
|
content:
|
|
1322
1324
|
application/json:
|
|
1323
1325
|
schema:
|
|
1324
|
-
description: "A data identifier with all attributes."
|
|
1325
1326
|
type: object
|
|
1327
|
+
description: "A JSON object containing all attributes of the DID."
|
|
1328
|
+
examples:
|
|
1329
|
+
defaultPlugin:
|
|
1330
|
+
summary: "Response produced by the default 'DID_COLUMN' plug-in"
|
|
1331
|
+
value:
|
|
1332
|
+
scope: "user"
|
|
1333
|
+
name: "dataset_123"
|
|
1334
|
+
did_type: "DATASET"
|
|
1335
|
+
bytes: 123456789
|
|
1336
|
+
length: 42
|
|
1337
|
+
account: "root"
|
|
1338
|
+
is_open: true
|
|
1339
|
+
suppressed: false
|
|
1340
|
+
created_at: "2025-05-20T12:16:58"
|
|
1341
|
+
updated_at: "2025-05-20T12:17:27"
|
|
1342
|
+
# ... rest DID fields
|
|
1343
|
+
jsonPlugin:
|
|
1344
|
+
summary: "Response produced by the 'JSON' plugin"
|
|
1345
|
+
value:
|
|
1346
|
+
custom_key1: "value1"
|
|
1347
|
+
custom_key2: "value2"
|
|
1348
|
+
# ... etc
|
|
1326
1349
|
400:
|
|
1327
|
-
description: "Bad Request
|
|
1350
|
+
description: "Bad Request – invalid scope_name, or invalid metadata plugin specified."
|
|
1328
1351
|
401:
|
|
1329
|
-
description: "
|
|
1352
|
+
description: "Unauthorized – invalid Auth Token."
|
|
1330
1353
|
404:
|
|
1331
|
-
description: "DID not
|
|
1354
|
+
description: "Not found – the specified DID does not exist."
|
|
1355
|
+
405:
|
|
1356
|
+
description: "Method Not Allowed – the 'key' parameter is not supported with GET."
|
|
1332
1357
|
406:
|
|
1333
|
-
description: "Not
|
|
1358
|
+
description: "Not Acceptable – the requested format is not supported."
|
|
1334
1359
|
"""
|
|
1360
|
+
# Flask injects the `key` keyword argument here because the blueprint registers
|
|
1361
|
+
# the generic `/meta` endpoint with `defaults={'key': None}`. The GET endpoint is
|
|
1362
|
+
# intentionally *not* exposed as `/meta/<key>`—it always returns the complete
|
|
1363
|
+
# metadata record (optionally filtered by the `plugin` query parameter). Hence,
|
|
1364
|
+
# a non‑None `key` should never reach this method today. The following guard
|
|
1365
|
+
# defends against any future routing changes that might introduce
|
|
1366
|
+
# `/meta/<key>` for GET requests by explicitly rejecting such usage.
|
|
1367
|
+
if key is not None:
|
|
1368
|
+
return generate_http_error_flask(405,
|
|
1369
|
+
'MethodNotAllowed',
|
|
1370
|
+
'GET not allowing keys')
|
|
1371
|
+
|
|
1372
|
+
vo = request.environ['vo']
|
|
1335
1373
|
try:
|
|
1336
|
-
scope, name = parse_scope_name(scope_name,
|
|
1374
|
+
scope, name = parse_scope_name(scope_name, vo)
|
|
1337
1375
|
except ValueError as error:
|
|
1338
1376
|
return generate_http_error_flask(400, error)
|
|
1339
1377
|
|
|
1378
|
+
plugin = request.args.get('plugin', default='DID_COLUMN')
|
|
1340
1379
|
try:
|
|
1341
|
-
|
|
1342
|
-
meta = get_metadata(scope=scope, name=name, plugin=plugin, vo=request.environ['vo'])
|
|
1380
|
+
meta = get_metadata(scope=scope, name=name, plugin=plugin, vo=vo)
|
|
1343
1381
|
return Response(render_json(**meta), content_type='application/json')
|
|
1344
1382
|
except DataIdentifierNotFound as error:
|
|
1345
1383
|
return generate_http_error_flask(404, error)
|
|
1346
1384
|
except UnsupportedMetadataPlugin as error:
|
|
1347
1385
|
return generate_http_error_flask(400, error)
|
|
1348
1386
|
|
|
1349
|
-
def post(self, scope_name):
|
|
1387
|
+
def post(self, scope_name, key=None):
|
|
1350
1388
|
"""
|
|
1351
1389
|
---
|
|
1352
|
-
summary:
|
|
1353
|
-
description:
|
|
1390
|
+
summary: Set or update metadata
|
|
1391
|
+
description: |
|
|
1392
|
+
Set metadata for a data identifier (DID). If a piece of metadata for a given key
|
|
1393
|
+
already exists, it will be handled according to the underlying metadata plugin
|
|
1394
|
+
in use. Certain plugins may disallow updating specific metadata keys.
|
|
1395
|
+
|
|
1396
|
+
- **Single-key mode** (key provided in the path):
|
|
1397
|
+
The request body must contain a `value` field (e.g., `{"value": "some_value"}`).
|
|
1398
|
+
- **Multi-key mode** (no key in the path):
|
|
1399
|
+
The request body must contain a `meta` field with the dictionary containing
|
|
1400
|
+
multiple key-value pairs (e.g. `{"meta": {"k1": "v1", "k2": "v2"}}`).
|
|
1401
|
+
|
|
1402
|
+
The optional `recursive` flag indicates whether the metadata should be applied
|
|
1403
|
+
recursively to child DIDs. Note that whether recursion is supported depends on
|
|
1404
|
+
the plugin configured for your system.
|
|
1354
1405
|
tags:
|
|
1355
1406
|
- Data Identifiers
|
|
1356
1407
|
parameters:
|
|
1357
1408
|
- name: scope_name
|
|
1358
1409
|
in: path
|
|
1359
|
-
description: "The scope and the name of the DID."
|
|
1410
|
+
description: "The scope and the name of the DID (e.g., `scope:name`)."
|
|
1411
|
+
required: true
|
|
1412
|
+
style: simple
|
|
1360
1413
|
schema:
|
|
1361
1414
|
type: string
|
|
1415
|
+
- name: key
|
|
1416
|
+
in: path
|
|
1417
|
+
description: |
|
|
1418
|
+
The key parameter applies only to the `/meta/<key>` endpoint (**Single-key mode**)
|
|
1419
|
+
and defines which metadata key to set/update. If omitted (by calling just `/meta`
|
|
1420
|
+
without the extra path segment), it defaults to `None` and **Multi-key mode** is used.
|
|
1421
|
+
required: true
|
|
1362
1422
|
style: simple
|
|
1423
|
+
schema:
|
|
1424
|
+
type: string
|
|
1363
1425
|
requestBody:
|
|
1426
|
+
required: true
|
|
1364
1427
|
content:
|
|
1365
|
-
|
|
1428
|
+
application/json:
|
|
1366
1429
|
schema:
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1430
|
+
oneOf:
|
|
1431
|
+
- type: object
|
|
1432
|
+
description: "Schema for **Single-key mode** (`key` included in path)."
|
|
1433
|
+
required:
|
|
1434
|
+
- value
|
|
1435
|
+
properties:
|
|
1436
|
+
value:
|
|
1437
|
+
description: "The metadata value to set for this key."
|
|
1438
|
+
type: string
|
|
1439
|
+
recursive:
|
|
1440
|
+
description: "Whether to apply the update recursively to child DIDs."
|
|
1441
|
+
type: boolean
|
|
1442
|
+
default: false
|
|
1443
|
+
- type: object
|
|
1444
|
+
description: "Schema for **Multi-key mode** (`key` not included in path)."
|
|
1445
|
+
required:
|
|
1446
|
+
- meta
|
|
1447
|
+
properties:
|
|
1448
|
+
meta:
|
|
1449
|
+
description: "A dictionary of multiple metadata keys and their values."
|
|
1450
|
+
type: object
|
|
1451
|
+
recursive:
|
|
1452
|
+
description: "Whether to apply the update recursively to child DIDs."
|
|
1453
|
+
type: boolean
|
|
1454
|
+
default: false
|
|
1455
|
+
examples:
|
|
1456
|
+
singleKeyMode:
|
|
1457
|
+
summary: "Setting a single metadata key"
|
|
1458
|
+
value:
|
|
1459
|
+
value: "my_metadata_value"
|
|
1460
|
+
recursive: false
|
|
1461
|
+
multiKeyMode:
|
|
1462
|
+
summary: "Setting multiple metadata keys at once"
|
|
1463
|
+
value:
|
|
1464
|
+
meta:
|
|
1465
|
+
experiment: "ATLAS"
|
|
1466
|
+
physics_group: "Higgs"
|
|
1467
|
+
data_type: "RAW"
|
|
1468
|
+
recursive: true
|
|
1378
1469
|
responses:
|
|
1379
1470
|
201:
|
|
1380
|
-
description: "Created"
|
|
1471
|
+
description: "Created – metadata was successfully set (or updated)."
|
|
1381
1472
|
content:
|
|
1382
|
-
|
|
1473
|
+
text/plain:
|
|
1383
1474
|
schema:
|
|
1384
1475
|
type: string
|
|
1385
1476
|
enum: ["Created"]
|
|
1477
|
+
400:
|
|
1478
|
+
description: "Bad Request – invalid scope_name, or invalid key/value parameters."
|
|
1386
1479
|
401:
|
|
1387
|
-
description: "
|
|
1480
|
+
description: "Unauthorized – invalid Auth Token."
|
|
1388
1481
|
404:
|
|
1389
|
-
description: "Not found"
|
|
1390
|
-
406:
|
|
1391
|
-
description: "Not acceptable"
|
|
1482
|
+
description: "Not found – the specified DID does not exist."
|
|
1392
1483
|
"""
|
|
1484
|
+
vo = request.environ['vo']
|
|
1393
1485
|
try:
|
|
1394
|
-
scope, name = parse_scope_name(scope_name,
|
|
1486
|
+
scope, name = parse_scope_name(scope_name, vo)
|
|
1395
1487
|
except ValueError as error:
|
|
1396
1488
|
return generate_http_error_flask(400, error)
|
|
1397
1489
|
|
|
1398
1490
|
parameters = json_parameters()
|
|
1399
|
-
meta = param_get(parameters, 'meta')
|
|
1400
1491
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1492
|
+
if key is not None:
|
|
1493
|
+
value = param_get(parameters, 'value')
|
|
1494
|
+
try:
|
|
1495
|
+
set_metadata(
|
|
1496
|
+
scope=scope,
|
|
1497
|
+
name=name,
|
|
1498
|
+
key=key,
|
|
1499
|
+
value=value,
|
|
1500
|
+
issuer=request.environ['issuer'],
|
|
1501
|
+
recursive=param_get(parameters, 'recursive', default=False),
|
|
1502
|
+
vo=vo
|
|
1503
|
+
)
|
|
1504
|
+
except DataIdentifierNotFound as error:
|
|
1505
|
+
return generate_http_error_flask(404, error)
|
|
1506
|
+
except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
|
|
1507
|
+
return generate_http_error_flask(400, error)
|
|
1508
|
+
return 'Created', 201
|
|
1416
1509
|
|
|
1417
|
-
|
|
1510
|
+
else:
|
|
1511
|
+
meta = param_get(parameters, 'meta')
|
|
1512
|
+
try:
|
|
1513
|
+
set_metadata_bulk(
|
|
1514
|
+
scope=scope,
|
|
1515
|
+
name=name,
|
|
1516
|
+
meta=meta,
|
|
1517
|
+
issuer=request.environ['issuer'],
|
|
1518
|
+
recursive=param_get(parameters, 'recursive', default=False),
|
|
1519
|
+
vo=vo,
|
|
1520
|
+
)
|
|
1521
|
+
except DataIdentifierNotFound as error:
|
|
1522
|
+
return generate_http_error_flask(404, error)
|
|
1523
|
+
except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
|
|
1524
|
+
return generate_http_error_flask(400, error)
|
|
1525
|
+
return "Created", 201
|
|
1418
1526
|
|
|
1419
|
-
def delete(self, scope_name):
|
|
1527
|
+
def delete(self, scope_name, key=None):
|
|
1420
1528
|
"""
|
|
1421
1529
|
---
|
|
1422
1530
|
summary: Delete metadata
|
|
1423
|
-
description:
|
|
1531
|
+
description: |
|
|
1532
|
+
Delete a specific metadata key from a data identifier (DID).
|
|
1533
|
+
This `key` must be provided via the query parameter `?key=...`.
|
|
1424
1534
|
tags:
|
|
1425
1535
|
- Data Identifiers
|
|
1426
1536
|
parameters:
|
|
1427
1537
|
- name: scope_name
|
|
1428
1538
|
in: path
|
|
1429
|
-
description: "The scope and the name of the DID."
|
|
1539
|
+
description: "The scope and the name of the DID (e.g., `scope:name`)."
|
|
1540
|
+
required: true
|
|
1541
|
+
style: simple
|
|
1430
1542
|
schema:
|
|
1431
1543
|
type: string
|
|
1432
|
-
style: simple
|
|
1433
1544
|
- name: key
|
|
1434
1545
|
in: query
|
|
1435
|
-
description: "The key to delete."
|
|
1546
|
+
description: "The metadata key to delete."
|
|
1547
|
+
required: true
|
|
1548
|
+
style: form
|
|
1436
1549
|
schema:
|
|
1437
1550
|
type: string
|
|
1438
1551
|
responses:
|
|
1439
1552
|
200:
|
|
1440
|
-
description: "OK"
|
|
1553
|
+
description: "OK – the metadata key was successfully removed."
|
|
1554
|
+
content:
|
|
1555
|
+
text/plain:
|
|
1556
|
+
schema:
|
|
1557
|
+
type: string
|
|
1558
|
+
enum: [""]
|
|
1441
1559
|
400:
|
|
1442
|
-
description: "
|
|
1560
|
+
description: "Bad Request – invalid scope_name."
|
|
1443
1561
|
401:
|
|
1444
|
-
description: "
|
|
1562
|
+
description: "Unauthorized – invalid Auth Token."
|
|
1445
1563
|
404:
|
|
1446
|
-
description:
|
|
1447
|
-
|
|
1448
|
-
|
|
1564
|
+
description: >
|
|
1565
|
+
Not found – the specified DID or `key` does not exist, or no `key` query
|
|
1566
|
+
parameter provided.
|
|
1567
|
+
405:
|
|
1568
|
+
description: "Method Not Allowed – the 'key' parameter is not supported with DELETE."
|
|
1449
1569
|
409:
|
|
1450
|
-
description: "
|
|
1570
|
+
description: "Conflict – action not supported by the utilized metadata plugin."
|
|
1451
1571
|
"""
|
|
1572
|
+
# Flask injects the `key` keyword argument here because the blueprint registers the
|
|
1573
|
+
# generic `/meta` endpoint with `defaults={'key': None}`. For DELETE requests the
|
|
1574
|
+
# API currently expects any metadata key to be supplied via the **query string**
|
|
1575
|
+
# (e.g. `...?key=myfield`), so a non‑None `key` coming from the path is impossible
|
|
1576
|
+
# today. We still keep this guard as a defensive measure in case someone later
|
|
1577
|
+
# extends the routing to allow `/meta/<key>` for DELETE as well.
|
|
1578
|
+
if key is not None:
|
|
1579
|
+
return generate_http_error_flask(405,
|
|
1580
|
+
'MethodNotAllowed',
|
|
1581
|
+
'DELETE not allowing keys')
|
|
1582
|
+
|
|
1583
|
+
vo = request.environ['vo']
|
|
1452
1584
|
try:
|
|
1453
|
-
scope, name = parse_scope_name(scope_name,
|
|
1585
|
+
scope, name = parse_scope_name(scope_name, vo)
|
|
1454
1586
|
except ValueError as error:
|
|
1455
1587
|
return generate_http_error_flask(400, error)
|
|
1456
1588
|
|
|
1457
|
-
if 'key' in request.args:
|
|
1458
|
-
key = request.args['key']
|
|
1459
|
-
else:
|
|
1589
|
+
if 'key' not in request.args:
|
|
1460
1590
|
return generate_http_error_flask(404, KeyNotFound.__name__, 'No key provided to remove')
|
|
1461
1591
|
|
|
1592
|
+
delete_key = request.args['key']
|
|
1462
1593
|
try:
|
|
1463
|
-
delete_metadata(scope=scope, name=name, key=
|
|
1594
|
+
delete_metadata(scope=scope, name=name, key=delete_key, vo=vo)
|
|
1464
1595
|
except (KeyNotFound, DataIdentifierNotFound) as error:
|
|
1465
1596
|
return generate_http_error_flask(404, error)
|
|
1466
1597
|
except NotImplementedError as error:
|
|
@@ -1469,85 +1600,6 @@ class Meta(ErrorHandlingMethodView):
|
|
|
1469
1600
|
return '', 200
|
|
1470
1601
|
|
|
1471
1602
|
|
|
1472
|
-
class SingleMeta(ErrorHandlingMethodView):
|
|
1473
|
-
def post(self, scope_name, key):
|
|
1474
|
-
"""
|
|
1475
|
-
---
|
|
1476
|
-
summary: Add metadata
|
|
1477
|
-
description: "Add metadata to a DID."
|
|
1478
|
-
tags:
|
|
1479
|
-
- Data Identifiers
|
|
1480
|
-
parameters:
|
|
1481
|
-
- name: scope_name
|
|
1482
|
-
in: path
|
|
1483
|
-
description: "The scope and the name of the DID."
|
|
1484
|
-
schema:
|
|
1485
|
-
type: string
|
|
1486
|
-
style: simple
|
|
1487
|
-
- name: key
|
|
1488
|
-
in: path
|
|
1489
|
-
description: "The key for the metadata."
|
|
1490
|
-
schema:
|
|
1491
|
-
type: string
|
|
1492
|
-
style: simple
|
|
1493
|
-
requestBody:
|
|
1494
|
-
content:
|
|
1495
|
-
'application/json':
|
|
1496
|
-
schema:
|
|
1497
|
-
type: object
|
|
1498
|
-
required:
|
|
1499
|
-
- value
|
|
1500
|
-
properties:
|
|
1501
|
-
value:
|
|
1502
|
-
description: "The value to set."
|
|
1503
|
-
type: object
|
|
1504
|
-
responses:
|
|
1505
|
-
201:
|
|
1506
|
-
description: "Created"
|
|
1507
|
-
content:
|
|
1508
|
-
application/json:
|
|
1509
|
-
schema:
|
|
1510
|
-
type: string
|
|
1511
|
-
enum: ["Created"]
|
|
1512
|
-
401:
|
|
1513
|
-
description: "Invalid Auth Token"
|
|
1514
|
-
404:
|
|
1515
|
-
description: "DID not found"
|
|
1516
|
-
406:
|
|
1517
|
-
description: "Not acceptable"
|
|
1518
|
-
409:
|
|
1519
|
-
description: "Metadata already exists"
|
|
1520
|
-
400:
|
|
1521
|
-
description: "Invalid key or value"
|
|
1522
|
-
"""
|
|
1523
|
-
try:
|
|
1524
|
-
scope, name = parse_scope_name(scope_name, request.environ['vo'])
|
|
1525
|
-
except ValueError as error:
|
|
1526
|
-
return generate_http_error_flask(400, error)
|
|
1527
|
-
|
|
1528
|
-
parameters = json_parameters()
|
|
1529
|
-
value = param_get(parameters, 'value')
|
|
1530
|
-
|
|
1531
|
-
try:
|
|
1532
|
-
set_metadata(
|
|
1533
|
-
scope=scope,
|
|
1534
|
-
name=name,
|
|
1535
|
-
key=key,
|
|
1536
|
-
value=value,
|
|
1537
|
-
issuer=request.environ['issuer'],
|
|
1538
|
-
recursive=param_get(parameters, 'recursive', default=False),
|
|
1539
|
-
vo=request.environ['vo'],
|
|
1540
|
-
)
|
|
1541
|
-
except DataIdentifierNotFound as error:
|
|
1542
|
-
return generate_http_error_flask(404, error)
|
|
1543
|
-
except Duplicate as error:
|
|
1544
|
-
return generate_http_error_flask(409, error)
|
|
1545
|
-
except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
|
|
1546
|
-
return generate_http_error_flask(400, error)
|
|
1547
|
-
|
|
1548
|
-
return 'Created', 201
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
1603
|
class BulkDIDsMeta(ErrorHandlingMethodView):
|
|
1552
1604
|
|
|
1553
1605
|
def post(self):
|
|
@@ -2298,9 +2350,8 @@ def blueprint():
|
|
|
2298
2350
|
attachment_view = Attachment.as_view('attachment')
|
|
2299
2351
|
bp.add_url_rule('/<path:scope_name>/dids', view_func=attachment_view, methods=['get', 'post', 'delete'])
|
|
2300
2352
|
meta_view = Meta.as_view('meta')
|
|
2301
|
-
bp.add_url_rule('/<path:scope_name>/meta', view_func=meta_view, methods=['get', 'post', 'delete'])
|
|
2302
|
-
|
|
2303
|
-
bp.add_url_rule('/<path:scope_name>/meta/<key>', view_func=singlemeta_view, methods=['post', ])
|
|
2353
|
+
bp.add_url_rule('/<path:scope_name>/meta', defaults={'key': None}, view_func=meta_view, methods=['get', 'post', 'delete'])
|
|
2354
|
+
bp.add_url_rule('/<path:scope_name>/meta/<key>', view_func=meta_view, methods=['post', ])
|
|
2304
2355
|
bulkdidsmeta_view = BulkDIDsMeta.as_view('bulkdidsmeta')
|
|
2305
2356
|
bp.add_url_rule('/bulkdidsmeta', view_func=bulkdidsmeta_view, methods=['post', ])
|
|
2306
2357
|
rules_view = Rules.as_view('rules')
|