rucio-clients 35.7.0__py3-none-any.whl → 37.0.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-clients might be problematic. Click here for more details.
- rucio/alembicrevision.py +1 -1
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio_clients-35.7.0.data/scripts/rucio → rucio/cli/bin_legacy/rucio.py +769 -486
- rucio_clients-35.7.0.data/scripts/rucio-admin → rucio/cli/bin_legacy/rucio_admin.py +476 -423
- 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/accountclient.py +0 -1
- rucio/client/baseclient.py +33 -24
- rucio/client/client.py +45 -1
- rucio/client/didclient.py +5 -3
- rucio/client/downloadclient.py +6 -8
- rucio/client/replicaclient.py +0 -2
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +4 -4
- rucio/client/uploadclient.py +26 -12
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +66 -29
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +22 -35
- rucio/common/constants.py +61 -3
- rucio/common/didtype.py +72 -24
- rucio/common/exception.py +65 -8
- rucio/common/extra.py +5 -10
- rucio/common/logging.py +13 -13
- rucio/common/pcache.py +8 -7
- rucio/common/plugins.py +59 -27
- rucio/common/policy.py +12 -3
- rucio/common/schema/__init__.py +84 -34
- rucio/common/schema/generic.py +0 -17
- rucio/common/schema/generic_multi_vo.py +0 -17
- rucio/common/test_rucio_server.py +12 -6
- rucio/common/types.py +132 -52
- rucio/common/utils.py +93 -643
- rucio/rse/__init__.py +3 -3
- rucio/rse/protocols/bittorrent.py +11 -1
- rucio/rse/protocols/cache.py +0 -11
- rucio/rse/protocols/dummy.py +0 -11
- rucio/rse/protocols/gfal.py +14 -9
- rucio/rse/protocols/globus.py +1 -1
- rucio/rse/protocols/http_cache.py +1 -1
- rucio/rse/protocols/posix.py +2 -2
- rucio/rse/protocols/protocol.py +84 -317
- rucio/rse/protocols/rclone.py +2 -1
- rucio/rse/protocols/rfio.py +10 -1
- rucio/rse/protocols/ssh.py +2 -1
- rucio/rse/protocols/storm.py +2 -13
- rucio/rse/protocols/webdav.py +74 -30
- rucio/rse/protocols/xrootd.py +2 -1
- rucio/rse/rsemanager.py +170 -53
- rucio/rse/translation.py +260 -0
- rucio/vcsversion.py +4 -4
- rucio/version.py +7 -0
- {rucio_clients-35.7.0.data → rucio_clients-37.0.0.data}/data/etc/rucio.cfg.atlas.client.template +3 -2
- {rucio_clients-35.7.0.data → rucio_clients-37.0.0.data}/data/etc/rucio.cfg.template +3 -19
- {rucio_clients-35.7.0.data → rucio_clients-37.0.0.data}/data/requirements.client.txt +11 -7
- rucio_clients-37.0.0.data/scripts/rucio +133 -0
- rucio_clients-37.0.0.data/scripts/rucio-admin +97 -0
- {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0.dist-info}/METADATA +18 -14
- rucio_clients-37.0.0.dist-info/RECORD +104 -0
- {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/common/schema/atlas.py +0 -413
- rucio/common/schema/belleii.py +0 -408
- rucio/common/schema/domatpc.py +0 -401
- rucio/common/schema/escape.py +0 -426
- rucio/common/schema/icecube.py +0 -406
- rucio/rse/protocols/gsiftp.py +0 -92
- rucio_clients-35.7.0.dist-info/RECORD +0 -88
- {rucio_clients-35.7.0.data → rucio_clients-37.0.0.data}/data/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-35.7.0.data → rucio_clients-37.0.0.data}/data/rucio_client/merge_rucio_configs.py +0 -0
- {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0.dist-info}/WHEEL +0 -0
- {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0.dist-info}/licenses/LICENSE +0 -0
- {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env python
|
|
2
2
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -15,46 +15,33 @@
|
|
|
15
15
|
|
|
16
16
|
import argparse
|
|
17
17
|
import datetime
|
|
18
|
-
import errno
|
|
19
18
|
import json
|
|
20
|
-
import logging
|
|
21
19
|
import math
|
|
22
20
|
import os
|
|
23
21
|
import signal
|
|
24
22
|
import sys
|
|
25
23
|
import time
|
|
26
|
-
import traceback
|
|
27
|
-
from configparser import NoOptionError, NoSectionError
|
|
28
|
-
from functools import wraps
|
|
29
24
|
from textwrap import dedent
|
|
30
25
|
|
|
26
|
+
from rich.console import Console
|
|
27
|
+
from rich.padding import Padding
|
|
28
|
+
from rich.status import Status
|
|
29
|
+
from rich.text import Text
|
|
30
|
+
from rich.theme import Theme
|
|
31
|
+
from rich.traceback import install
|
|
32
|
+
from rich.tree import Tree
|
|
31
33
|
from tabulate import tabulate
|
|
32
34
|
|
|
33
35
|
from rucio import version
|
|
34
|
-
from rucio.
|
|
35
|
-
from rucio.
|
|
36
|
+
from rucio.cli.utils import exception_handler, get_client, setup_gfal2_logger, signal_handler
|
|
37
|
+
from rucio.client.richclient import MAX_TRACEBACK_WIDTH, MIN_CONSOLE_WIDTH, CLITheme, generate_table, get_cli_config, get_pager, print_output, setup_rich_logger
|
|
36
38
|
from rucio.common.constants import RseAttr
|
|
37
39
|
from rucio.common.exception import (
|
|
38
|
-
AccessDenied,
|
|
39
|
-
AccountNotFound,
|
|
40
|
-
CannotAuthenticate,
|
|
41
|
-
ConfigNotFound,
|
|
42
|
-
DataIdentifierAlreadyExists,
|
|
43
|
-
DataIdentifierNotFound,
|
|
44
|
-
Duplicate,
|
|
45
|
-
DuplicateContent,
|
|
46
|
-
InputValidationError,
|
|
47
|
-
InvalidObject,
|
|
48
|
-
InvalidRSEExpression,
|
|
49
|
-
ReplicaIsLocked,
|
|
50
40
|
ReplicaNotFound,
|
|
51
|
-
RSENotFound,
|
|
52
41
|
RSEOperationNotSupported,
|
|
53
|
-
RuleNotFound,
|
|
54
|
-
ScopeNotFound,
|
|
55
42
|
)
|
|
56
43
|
from rucio.common.extra import import_extras
|
|
57
|
-
from rucio.common.utils import StoreAndDeprecateWarningAction, chunks, clean_pfns, construct_non_deterministic_pfn, extract_scope, get_bytes_value_from_string, parse_response, render_json, sizefmt
|
|
44
|
+
from rucio.common.utils import StoreAndDeprecateWarningAction, chunks, clean_pfns, construct_non_deterministic_pfn, extract_scope, get_bytes_value_from_string, parse_response, render_json, setup_logger, sizefmt
|
|
58
45
|
from rucio.rse import rsemanager as rsemgr
|
|
59
46
|
|
|
60
47
|
EXTRA_MODULES = import_extras(['argcomplete'])
|
|
@@ -71,170 +58,9 @@ SUCCESS = 0
|
|
|
71
58
|
FAILURE = 1
|
|
72
59
|
DEFAULT_PORT = 443
|
|
73
60
|
|
|
74
|
-
logger = logging.getLogger("user")
|
|
75
61
|
|
|
76
62
|
tablefmt = 'psql'
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def setup_logger(logger):
|
|
80
|
-
logger.setLevel(logging.DEBUG)
|
|
81
|
-
hdlr = logging.StreamHandler()
|
|
82
|
-
|
|
83
|
-
def emit_decorator(fcn):
|
|
84
|
-
def func(*args):
|
|
85
|
-
formatter = logging.Formatter("%(message)s")
|
|
86
|
-
hdlr.setFormatter(formatter)
|
|
87
|
-
return fcn(*args)
|
|
88
|
-
return func
|
|
89
|
-
hdlr.emit = emit_decorator(hdlr.emit)
|
|
90
|
-
logger.addHandler(hdlr)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
setup_logger(logger)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def signal_handler(signal, frame):
|
|
97
|
-
logger.warning('You pressed Ctrl+C! Exiting gracefully')
|
|
98
|
-
sys.exit(1)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
signal.signal(signal.SIGINT, signal_handler)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def exception_handler(function):
|
|
105
|
-
@wraps(function)
|
|
106
|
-
def new_funct(*args, **kwargs):
|
|
107
|
-
try:
|
|
108
|
-
return function(*args, **kwargs)
|
|
109
|
-
except InvalidObject as error:
|
|
110
|
-
logger.error(error)
|
|
111
|
-
return error.error_code
|
|
112
|
-
except DataIdentifierNotFound as error:
|
|
113
|
-
logger.error(error)
|
|
114
|
-
logger.debug('This means that the Data IDentifier you provided is not known by Rucio.')
|
|
115
|
-
return error.error_code
|
|
116
|
-
except AccessDenied as error:
|
|
117
|
-
logger.error(error)
|
|
118
|
-
logger.debug('This error is a permission issue. You cannot run this command with your account.')
|
|
119
|
-
return error.error_code
|
|
120
|
-
except DataIdentifierAlreadyExists as error:
|
|
121
|
-
logger.error(error)
|
|
122
|
-
logger.debug('This means that the data IDentifier you try to add is already registered in Rucio.')
|
|
123
|
-
return error.error_code
|
|
124
|
-
except RSENotFound as error:
|
|
125
|
-
logger.error(error)
|
|
126
|
-
logger.debug('This means that the Rucio Storage Element you provided is not known by Rucio.')
|
|
127
|
-
return error.error_code
|
|
128
|
-
except InvalidRSEExpression as error:
|
|
129
|
-
logger.error(error)
|
|
130
|
-
logger.debug('This means the RSE expression you provided is not syntactically correct.')
|
|
131
|
-
return error.error_code
|
|
132
|
-
except DuplicateContent as error:
|
|
133
|
-
logger.error(error)
|
|
134
|
-
logger.debug('This means that the DID you want to attach is already in the target DID.')
|
|
135
|
-
return error.error_code
|
|
136
|
-
except TypeError as error:
|
|
137
|
-
logger.error(error)
|
|
138
|
-
logger.debug('This means the parameter you passed has a wrong type.')
|
|
139
|
-
return FAILURE
|
|
140
|
-
except RuleNotFound as error:
|
|
141
|
-
logger.error(error)
|
|
142
|
-
logger.debug('This means the rule you specified does not exist.')
|
|
143
|
-
return error.error_code
|
|
144
|
-
except AccountNotFound as error:
|
|
145
|
-
logger.error(error)
|
|
146
|
-
logger.debug('This means that the specified account cannot be found.')
|
|
147
|
-
return error.error_code
|
|
148
|
-
except NotImplementedError as error:
|
|
149
|
-
logger.error(error)
|
|
150
|
-
logger.debug('This means that the method is not implemented yet.')
|
|
151
|
-
return FAILURE
|
|
152
|
-
except Duplicate as error:
|
|
153
|
-
logger.error(error)
|
|
154
|
-
logger.debug('This means that you are trying to add something that already exists.')
|
|
155
|
-
return error.error_code
|
|
156
|
-
except ReplicaIsLocked as error:
|
|
157
|
-
logger.error(error)
|
|
158
|
-
logger.error('This means that the replica has a lock and is therefore protected.')
|
|
159
|
-
return FAILURE
|
|
160
|
-
except ReplicaNotFound as error:
|
|
161
|
-
logger.error(error)
|
|
162
|
-
logger.error('This means that the replica does not exist.')
|
|
163
|
-
return FAILURE
|
|
164
|
-
except ConfigNotFound as error:
|
|
165
|
-
logger.error(error)
|
|
166
|
-
logger.error('This means that the configuration section you are looking for does not exist.')
|
|
167
|
-
return FAILURE
|
|
168
|
-
except ScopeNotFound as error:
|
|
169
|
-
logger.error(error)
|
|
170
|
-
logger.error('This means that no scopes were found for the specified account ID.')
|
|
171
|
-
return FAILURE
|
|
172
|
-
except InputValidationError as error:
|
|
173
|
-
logger.error(error)
|
|
174
|
-
logger.error('This means that the input you provided did not meet all the requirements.')
|
|
175
|
-
return FAILURE
|
|
176
|
-
except Exception as error:
|
|
177
|
-
if isinstance(error, IOError) and getattr(error, 'errno', None) == errno.EPIPE:
|
|
178
|
-
# Ignore Broken Pipe
|
|
179
|
-
# While in python3 we can directly catch 'BrokenPipeError', in python2 it doesn't exist.
|
|
180
|
-
|
|
181
|
-
# Python flushes standard streams on exit; redirect remaining output
|
|
182
|
-
# to devnull to avoid another BrokenPipeError at shutdown
|
|
183
|
-
devnull = os.open(os.devnull, os.O_WRONLY)
|
|
184
|
-
os.dup2(devnull, sys.stdout.fileno())
|
|
185
|
-
return SUCCESS
|
|
186
|
-
logger.error(error)
|
|
187
|
-
logger.error('Rucio exited with an unexpected/unknown error, please provide the traceback below to the developers.')
|
|
188
|
-
logger.debug(traceback.format_exc())
|
|
189
|
-
return FAILURE
|
|
190
|
-
return new_funct
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def get_client(args):
|
|
194
|
-
"""
|
|
195
|
-
Returns a new client object.
|
|
196
|
-
"""
|
|
197
|
-
if not args.auth_strategy:
|
|
198
|
-
if 'RUCIO_AUTH_TYPE' in os.environ:
|
|
199
|
-
auth_type = os.environ['RUCIO_AUTH_TYPE'].lower()
|
|
200
|
-
else:
|
|
201
|
-
try:
|
|
202
|
-
auth_type = config_get('client', 'auth_type').lower()
|
|
203
|
-
except (NoOptionError, NoSectionError):
|
|
204
|
-
logger.error('Cannot get AUTH_TYPE')
|
|
205
|
-
sys.exit(FAILURE)
|
|
206
|
-
else:
|
|
207
|
-
auth_type = args.auth_strategy.lower()
|
|
208
|
-
|
|
209
|
-
if auth_type in ['userpass', 'saml'] and args.username is not None and args.password is not None:
|
|
210
|
-
creds = {'username': args.username, 'password': args.password}
|
|
211
|
-
elif auth_type == 'oidc':
|
|
212
|
-
if args.oidc_issuer:
|
|
213
|
-
args.oidc_issuer = args.oidc_issuer.lower()
|
|
214
|
-
creds = {'oidc_auto': args.oidc_auto,
|
|
215
|
-
'oidc_scope': args.oidc_scope,
|
|
216
|
-
'oidc_audience': args.oidc_audience,
|
|
217
|
-
'oidc_polling': args.oidc_polling,
|
|
218
|
-
'oidc_refresh_lifetime': args.oidc_refresh_lifetime,
|
|
219
|
-
'oidc_issuer': args.oidc_issuer,
|
|
220
|
-
'oidc_username': args.oidc_username,
|
|
221
|
-
'oidc_password': args.oidc_password}
|
|
222
|
-
else:
|
|
223
|
-
creds = None
|
|
224
|
-
|
|
225
|
-
try:
|
|
226
|
-
client = Client(rucio_host=args.host, auth_host=args.auth_host,
|
|
227
|
-
account=args.issuer,
|
|
228
|
-
auth_type=auth_type, creds=creds,
|
|
229
|
-
ca_cert=args.ca_certificate, timeout=args.timeout, vo=args.vo)
|
|
230
|
-
except CannotAuthenticate as error:
|
|
231
|
-
logger.error(error)
|
|
232
|
-
if 'alert certificate expired' in str(error):
|
|
233
|
-
logger.error('The server certificate expired.')
|
|
234
|
-
elif auth_type.lower() == 'x509_proxy':
|
|
235
|
-
logger.error('Please verify that your proxy is still valid and renew it if needed.')
|
|
236
|
-
sys.exit(FAILURE)
|
|
237
|
-
return client
|
|
63
|
+
cli_config = get_cli_config()
|
|
238
64
|
|
|
239
65
|
|
|
240
66
|
def get_scope(did, client):
|
|
@@ -245,135 +71,145 @@ def get_scope(did, client):
|
|
|
245
71
|
scopes = client.list_scopes()
|
|
246
72
|
scope, name = extract_scope(did, scopes)
|
|
247
73
|
return scope, name
|
|
248
|
-
return None, did
|
|
249
74
|
|
|
250
75
|
|
|
251
76
|
@exception_handler
|
|
252
|
-
def add_account(args):
|
|
77
|
+
def add_account(args, client, logger, console, spinner):
|
|
253
78
|
"""
|
|
254
79
|
%(prog)s add [options] <field1=value1 field2=value2 ...>
|
|
255
80
|
|
|
256
81
|
Adds a new account. Specify metadata fields as arguments.
|
|
257
82
|
|
|
258
83
|
"""
|
|
259
|
-
client =
|
|
260
|
-
client.add_account(account=args.account, type_=args.accounttype, email=args.accountemail)
|
|
84
|
+
client.add_account(account=args.account, type_=args.account_type, email=args.email)
|
|
261
85
|
print('Added new account: %s' % args.account)
|
|
262
86
|
return SUCCESS
|
|
263
87
|
|
|
264
88
|
|
|
265
89
|
@exception_handler
|
|
266
|
-
def delete_account(args):
|
|
90
|
+
def delete_account(args, client, logger, console, spinner):
|
|
267
91
|
"""
|
|
268
92
|
%(prog)s disable [options] <field1=value1 field2=value2 ...>
|
|
269
93
|
|
|
270
94
|
Delete account.
|
|
271
95
|
|
|
272
96
|
"""
|
|
273
|
-
client
|
|
274
|
-
|
|
275
|
-
print('Deleted account: %s' % args.acnt)
|
|
97
|
+
client.delete_account(args.account)
|
|
98
|
+
print('Deleted account: %s' % args.account)
|
|
276
99
|
return SUCCESS
|
|
277
100
|
|
|
278
101
|
|
|
279
102
|
@exception_handler
|
|
280
|
-
def update_account(args):
|
|
103
|
+
def update_account(args, client, logger, console, spinner):
|
|
281
104
|
"""
|
|
282
105
|
%(prog)s update [options] <field1=value1 field2=value2 ...>
|
|
283
106
|
|
|
284
107
|
Update an account.
|
|
285
108
|
|
|
286
109
|
"""
|
|
287
|
-
client = get_client(args)
|
|
288
110
|
client.update_account(account=args.account, key=args.key, value=args.value)
|
|
289
111
|
print('%s of account %s changed to %s' % (args.key, args.account, args.value))
|
|
290
112
|
return SUCCESS
|
|
291
113
|
|
|
292
114
|
|
|
293
115
|
@exception_handler
|
|
294
|
-
def ban_account(args):
|
|
116
|
+
def ban_account(args, client, logger, console, spinner):
|
|
295
117
|
"""
|
|
296
118
|
%(prog)s ban [options] <field1=value1 field2=value2 ...>
|
|
297
119
|
|
|
298
120
|
Ban an account.
|
|
299
121
|
|
|
300
122
|
"""
|
|
301
|
-
client = get_client(args)
|
|
302
123
|
client.update_account(account=args.account, key='status', value='SUSPENDED')
|
|
303
124
|
print('Account %s banned' % args.account)
|
|
304
125
|
return SUCCESS
|
|
305
126
|
|
|
306
127
|
|
|
307
128
|
@exception_handler
|
|
308
|
-
def unban_account(args):
|
|
129
|
+
def unban_account(args, client, logger, console, spinner):
|
|
309
130
|
"""
|
|
310
131
|
%(prog)s unban [options] <field1=value1 field2=value2 ...>
|
|
311
132
|
|
|
312
133
|
Unban a banned account.
|
|
313
134
|
|
|
314
135
|
"""
|
|
315
|
-
client = get_client(args)
|
|
316
136
|
client.update_account(account=args.account, key='status', value='ACTIVE')
|
|
317
137
|
print('Account %s unbanned' % args.account)
|
|
318
138
|
return SUCCESS
|
|
319
139
|
|
|
320
140
|
|
|
321
141
|
@exception_handler
|
|
322
|
-
def list_accounts(args):
|
|
142
|
+
def list_accounts(args, client, logger, console, spinner):
|
|
323
143
|
"""
|
|
324
144
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
325
145
|
|
|
326
146
|
List accounts.
|
|
327
147
|
|
|
328
148
|
"""
|
|
329
|
-
client = get_client(args)
|
|
330
149
|
filters = {}
|
|
331
150
|
if args.filters:
|
|
332
151
|
for key, value in [(_.split('=')[0], _.split('=')[1]) for _ in args.filters.split(',')]:
|
|
333
152
|
filters[key] = value
|
|
334
153
|
accounts = client.list_accounts(identity=args.identity, account_type=args.account_type, filters=filters)
|
|
335
|
-
|
|
336
|
-
print(account['account'])
|
|
154
|
+
if args.csv:
|
|
155
|
+
print(*(account['account'] for account in accounts), sep=',')
|
|
156
|
+
elif cli_config == 'rich':
|
|
157
|
+
table = generate_table([[account['account']] for account in accounts], headers=['ACCOUNT'], col_alignments=['left'])
|
|
158
|
+
spinner.stop()
|
|
159
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
160
|
+
else:
|
|
161
|
+
for account in accounts:
|
|
162
|
+
print(account['account'])
|
|
337
163
|
return SUCCESS
|
|
338
164
|
|
|
339
165
|
|
|
340
166
|
@exception_handler
|
|
341
|
-
def info_account(args):
|
|
167
|
+
def info_account(args, client, logger, console, spinner):
|
|
342
168
|
"""
|
|
343
169
|
%(prog)s show [options] <field1=value1 field2=value2 ...>
|
|
344
170
|
|
|
345
171
|
Show extended information of a given account
|
|
346
172
|
|
|
347
173
|
"""
|
|
348
|
-
client = get_client(args)
|
|
349
174
|
info = client.get_account(account=args.account)
|
|
350
|
-
|
|
351
|
-
|
|
175
|
+
if cli_config == 'rich':
|
|
176
|
+
keyword_style = {**CLITheme.ACCOUNT_STATUS, **CLITheme.ACCOUNT_TYPE}
|
|
177
|
+
table_data = [(k, Text(str(v), style=keyword_style.get(str(v), 'default'))) for k, v in sorted(info.items())]
|
|
178
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
|
|
179
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
180
|
+
else:
|
|
181
|
+
for k in info:
|
|
182
|
+
print(k.ljust(10) + ' : ' + str(info[k]))
|
|
352
183
|
return SUCCESS
|
|
353
184
|
|
|
354
185
|
|
|
355
186
|
@exception_handler
|
|
356
|
-
def list_identities(args):
|
|
187
|
+
def list_identities(args, client, logger, console, spinner):
|
|
357
188
|
"""
|
|
358
189
|
%(prog)s list-identities [options] <field1=value1 field2=value2 ...>
|
|
359
190
|
|
|
360
191
|
List all identities on an account.
|
|
361
192
|
"""
|
|
362
|
-
|
|
193
|
+
table_data = []
|
|
363
194
|
identities = client.list_identities(account=args.account)
|
|
364
195
|
for identity in identities:
|
|
365
|
-
|
|
196
|
+
if cli_config == 'rich':
|
|
197
|
+
table_data.append([identity['identity'], identity['type']])
|
|
198
|
+
else:
|
|
199
|
+
print('Identity: %(identity)s,\ttype: %(type)s' % identity)
|
|
200
|
+
if cli_config == 'rich':
|
|
201
|
+
table = generate_table(table_data, headers=['IDENTITY', 'TYPE'], col_alignments=['left', 'left'])
|
|
202
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
366
203
|
return SUCCESS
|
|
367
204
|
|
|
368
205
|
|
|
369
206
|
@exception_handler
|
|
370
|
-
def set_limits(args):
|
|
207
|
+
def set_limits(args, client, logger, console, spinner):
|
|
371
208
|
"""
|
|
372
209
|
%(prog)s set [options] <field1=value1 field2=value2 ...>
|
|
373
210
|
|
|
374
211
|
Set account limit for an account and rse.
|
|
375
212
|
"""
|
|
376
|
-
client = get_client(args)
|
|
377
213
|
locality = args.locality.lower()
|
|
378
214
|
byte_limit = None
|
|
379
215
|
limit_input = args.bytes.lower()
|
|
@@ -395,14 +231,13 @@ def set_limits(args):
|
|
|
395
231
|
|
|
396
232
|
|
|
397
233
|
@exception_handler
|
|
398
|
-
def get_limits(args):
|
|
234
|
+
def get_limits(args, client, logger, console, spinner):
|
|
399
235
|
"""
|
|
400
236
|
%(prog)s get-limits [options] <field1=value1 field2=value2 ...>
|
|
401
237
|
|
|
402
238
|
Grant an identity access to an account.
|
|
403
239
|
|
|
404
240
|
"""
|
|
405
|
-
client = get_client(args)
|
|
406
241
|
locality = args.locality.lower()
|
|
407
242
|
limits = client.get_account_limits(account=args.account, rse_expression=args.rse, locality=locality)
|
|
408
243
|
for rse in limits:
|
|
@@ -411,27 +246,25 @@ def get_limits(args):
|
|
|
411
246
|
|
|
412
247
|
|
|
413
248
|
@exception_handler
|
|
414
|
-
def delete_limits(args):
|
|
249
|
+
def delete_limits(args, client, logger, console, spinner):
|
|
415
250
|
"""
|
|
416
251
|
%(prog)s delete [options] <field1=value1 field2=value2 ...>
|
|
417
252
|
|
|
418
253
|
Delete account limit for an account and rse.
|
|
419
254
|
"""
|
|
420
|
-
client = get_client(args)
|
|
421
255
|
client.delete_account_limit(account=args.account, rse=args.rse, locality=args.locality)
|
|
422
256
|
print('Deleted account limit for account %s and RSE %s' % (args.account, args.rse))
|
|
423
257
|
return SUCCESS
|
|
424
258
|
|
|
425
259
|
|
|
426
260
|
@exception_handler
|
|
427
|
-
def identity_add(args):
|
|
261
|
+
def identity_add(args, client, logger, console, spinner):
|
|
428
262
|
"""
|
|
429
263
|
%(prog)s del [options] <field1=value1 field2=value2 ...>
|
|
430
264
|
|
|
431
265
|
Grant an identity access to an account.
|
|
432
266
|
|
|
433
267
|
"""
|
|
434
|
-
client = get_client(args)
|
|
435
268
|
if args.email == "":
|
|
436
269
|
logger.error('Error: --email argument can\'t be an empty string. Failed to grant an identity access to an account')
|
|
437
270
|
return FAILURE
|
|
@@ -446,63 +279,71 @@ def identity_add(args):
|
|
|
446
279
|
|
|
447
280
|
|
|
448
281
|
@exception_handler
|
|
449
|
-
def identity_delete(args):
|
|
282
|
+
def identity_delete(args, client, logger, console, spinner):
|
|
450
283
|
"""
|
|
451
284
|
%(prog)s delete [options] <field1=value1 field2=value2 ...>
|
|
452
285
|
|
|
453
286
|
Revoke an identity's access to an account.
|
|
454
287
|
|
|
455
288
|
"""
|
|
456
|
-
client = get_client(args)
|
|
457
289
|
client.del_identity(args.account, args.identity, authtype=args.authtype)
|
|
458
290
|
print('Deleted identity: %s' % args.identity)
|
|
459
291
|
return SUCCESS
|
|
460
292
|
|
|
461
293
|
|
|
462
294
|
@exception_handler
|
|
463
|
-
def add_rse(args):
|
|
295
|
+
def add_rse(args, client, logger, console, spinner):
|
|
464
296
|
"""
|
|
465
297
|
%(prog)s add [options] <field1=value1 field2=value2 ...>
|
|
466
298
|
|
|
467
299
|
Adds a new RSE. Specify metadata fields as arguments.
|
|
468
300
|
|
|
469
301
|
"""
|
|
470
|
-
client = get_client(args)
|
|
471
302
|
client.add_rse(args.rse, deterministic=not args.non_deterministic)
|
|
472
303
|
print('Added new %sdeterministic RSE: %s' % ('non-' if args.non_deterministic else '', args.rse))
|
|
473
304
|
return SUCCESS
|
|
474
305
|
|
|
475
306
|
|
|
476
307
|
@exception_handler
|
|
477
|
-
def disable_rse(args):
|
|
308
|
+
def disable_rse(args, client, logger, console, spinner):
|
|
478
309
|
"""
|
|
479
310
|
%(prog)s del [options] <field1=value1 field2=value2 ...>
|
|
480
311
|
|
|
481
312
|
Disable RSE.
|
|
482
313
|
|
|
483
314
|
"""
|
|
484
|
-
client = get_client(args)
|
|
485
315
|
client.delete_rse(args.rse)
|
|
486
316
|
return SUCCESS
|
|
487
317
|
|
|
488
318
|
|
|
489
319
|
@exception_handler
|
|
490
|
-
def list_rses(args):
|
|
320
|
+
def list_rses(args, client, logger, console, spinner):
|
|
491
321
|
"""
|
|
492
322
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
493
323
|
|
|
494
324
|
List RSEs.
|
|
495
325
|
|
|
496
326
|
"""
|
|
497
|
-
|
|
327
|
+
if cli_config == 'rich':
|
|
328
|
+
spinner.update(status='Fetching RSEs')
|
|
329
|
+
spinner.start()
|
|
330
|
+
|
|
498
331
|
rses = client.list_rses()
|
|
499
|
-
|
|
500
|
-
print(
|
|
332
|
+
if args.csv:
|
|
333
|
+
print(*(rse['rse'] for rse in rses), sep='\n')
|
|
334
|
+
elif cli_config == 'rich':
|
|
335
|
+
table_data = [[rse['rse']] for rse in sorted(rses, key=lambda elem: elem['rse'])]
|
|
336
|
+
table = generate_table(table_data, headers=['RSE'], col_alignments=['left'])
|
|
337
|
+
spinner.stop()
|
|
338
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
339
|
+
else:
|
|
340
|
+
for rse in rses:
|
|
341
|
+
print(rse['rse'])
|
|
501
342
|
return SUCCESS
|
|
502
343
|
|
|
503
344
|
|
|
504
345
|
@exception_handler
|
|
505
|
-
def update_rse(args):
|
|
346
|
+
def update_rse(args, client, logger, console, spinner):
|
|
506
347
|
"""
|
|
507
348
|
%(prog)s update [options] <field1=value1 field2=value2 ...>
|
|
508
349
|
|
|
@@ -514,7 +355,6 @@ def update_rse(args):
|
|
|
514
355
|
Use '', 'None' or 'null' to wipe the value of following RSE settings:
|
|
515
356
|
qos_class
|
|
516
357
|
"""
|
|
517
|
-
client = get_client(args)
|
|
518
358
|
if args.value in ['true', 'True', 'TRUE', '1']:
|
|
519
359
|
args.value = True
|
|
520
360
|
if args.value in ['false', 'False', 'FALSE', '0']:
|
|
@@ -530,102 +370,192 @@ def update_rse(args):
|
|
|
530
370
|
|
|
531
371
|
|
|
532
372
|
@exception_handler
|
|
533
|
-
def info_rse(args):
|
|
373
|
+
def info_rse(args, client, logger, console, spinner):
|
|
534
374
|
"""
|
|
535
375
|
%(prog)s info [options] <field1=value1 field2=value2 ...>
|
|
536
376
|
|
|
537
377
|
Show extended information of a given RSE
|
|
538
378
|
|
|
539
379
|
"""
|
|
540
|
-
|
|
380
|
+
if cli_config == 'rich':
|
|
381
|
+
spinner.update(status='Fetching RSE info')
|
|
382
|
+
spinner.start()
|
|
383
|
+
|
|
541
384
|
rseinfo = client.get_rse(rse=args.rse)
|
|
542
385
|
attributes = client.list_rse_attributes(rse=args.rse)
|
|
543
386
|
usage = client.get_rse_usage(rse=args.rse)
|
|
544
387
|
rse_limits = client.get_rse_limits(args.rse)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
388
|
+
|
|
389
|
+
if cli_config == 'rich':
|
|
390
|
+
keyword_styles = {**CLITheme.BOOLEAN, **CLITheme.RSE_TYPE}
|
|
391
|
+
output = []
|
|
392
|
+
table_data = []
|
|
393
|
+
else:
|
|
394
|
+
print('Settings:')
|
|
395
|
+
print('=========')
|
|
396
|
+
for i, key in enumerate(sorted(rseinfo)):
|
|
397
|
+
if cli_config == 'rich':
|
|
398
|
+
if i == 0:
|
|
399
|
+
output.append('[b]Settings:[/]')
|
|
400
|
+
if key != 'protocols':
|
|
401
|
+
table_data.append([key, Text(str(rseinfo[key]), style=keyword_styles.get(str(rseinfo[key]), 'default'))])
|
|
402
|
+
else:
|
|
403
|
+
if key != 'protocols':
|
|
404
|
+
print(' ' + key + ': ' + str(rseinfo[key]))
|
|
405
|
+
|
|
406
|
+
if cli_config == 'rich':
|
|
407
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
|
|
408
|
+
output.append(table)
|
|
409
|
+
table_data = []
|
|
410
|
+
else:
|
|
411
|
+
print('Attributes:')
|
|
412
|
+
print('===========')
|
|
413
|
+
for i, attribute in enumerate(sorted(attributes)):
|
|
414
|
+
if cli_config == 'rich':
|
|
415
|
+
if i == 0:
|
|
416
|
+
output.append('\n[b]Attributes:[/]')
|
|
417
|
+
table_data.append([attribute, Text(str(attributes[attribute]), style=keyword_styles.get(str(attributes[attribute]), 'default'))])
|
|
418
|
+
else:
|
|
419
|
+
print(' ' + attribute + ': ' + str(attributes[attribute]))
|
|
420
|
+
|
|
421
|
+
if cli_config == 'rich':
|
|
422
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
|
|
423
|
+
output.append(table)
|
|
424
|
+
else:
|
|
425
|
+
print('Protocols:')
|
|
426
|
+
print('==========')
|
|
427
|
+
for i, protocol in enumerate(sorted(rseinfo['protocols'], key=lambda x: x['scheme'])):
|
|
428
|
+
if cli_config == 'rich':
|
|
429
|
+
if i == 0:
|
|
430
|
+
output.append('\n[b]Protocols:[/]')
|
|
431
|
+
output.append(Padding.indent(Text(protocol['scheme'], style=CLITheme.SUBHEADER_HIGHLIGHT), 2))
|
|
432
|
+
else:
|
|
433
|
+
print(' ' + protocol['scheme'])
|
|
434
|
+
|
|
435
|
+
table_data = []
|
|
558
436
|
for item in sorted(protocol):
|
|
559
|
-
if
|
|
560
|
-
|
|
437
|
+
if cli_config == 'rich':
|
|
438
|
+
if item == 'domains':
|
|
439
|
+
tree = Tree('')
|
|
440
|
+
for domain, values in protocol[item].items():
|
|
441
|
+
branch = tree.add(f'[{CLITheme.JSON_STR}]{domain}')
|
|
442
|
+
for k, v in values.items():
|
|
443
|
+
branch.add(f'[{CLITheme.JSON_STR}]{k}[/]: [{CLITheme.JSON_NUM}]{v}[/]')
|
|
444
|
+
table_data.append([item, tree])
|
|
445
|
+
else:
|
|
446
|
+
table_data.append([item, Text(str(protocol[item]), style=keyword_styles.get(protocol[item], 'default'))])
|
|
561
447
|
else:
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
print('===========')
|
|
571
|
-
for limit in rse_limits:
|
|
572
|
-
print(' ' + limit + ': ' + str(rse_limits[limit]) + ' B')
|
|
448
|
+
if item == 'domains':
|
|
449
|
+
print(' ' + item + ': \'' + json.dumps(protocol[item]) + '\'')
|
|
450
|
+
else:
|
|
451
|
+
print(' ' + item + ': ' + str(protocol[item]))
|
|
452
|
+
|
|
453
|
+
if cli_config == 'rich':
|
|
454
|
+
table = generate_table(table_data, col_alignments=['left', 'left'], row_styles=['none'])
|
|
455
|
+
output.append(Padding.indent(table, 2))
|
|
573
456
|
|
|
457
|
+
if cli_config == 'rich':
|
|
458
|
+
header = ['SOURCE', 'USED', 'FILES', 'FREE', 'TOTAL', 'UPDATED AT']
|
|
459
|
+
key2id = {header[i].lower().replace(' ', '_'): i for i in range(len(header))}
|
|
460
|
+
table_data = []
|
|
461
|
+
else:
|
|
462
|
+
print('Usage:')
|
|
463
|
+
print('======')
|
|
464
|
+
for i, elem in enumerate(sorted(usage, key=lambda x: x['source'])):
|
|
465
|
+
if cli_config == 'rich':
|
|
466
|
+
if i == 0:
|
|
467
|
+
output.append('\n[b]Usage:[/]')
|
|
468
|
+
|
|
469
|
+
row = [''] * len(header)
|
|
470
|
+
row[0] = elem['source']
|
|
471
|
+
for item in sorted(elem):
|
|
472
|
+
if item in ['used', 'free', 'total']:
|
|
473
|
+
row[key2id[item]] = sizefmt(elem[item], True)
|
|
474
|
+
elif item != 'source' and item in key2id:
|
|
475
|
+
row[key2id[item]] = str(elem[item])
|
|
476
|
+
table_data.append(row)
|
|
477
|
+
else:
|
|
478
|
+
print(' ' + elem['source'])
|
|
479
|
+
for item in sorted(elem):
|
|
480
|
+
print(' ' + item + ': ' + str(elem[item]))
|
|
481
|
+
|
|
482
|
+
if cli_config == 'rich':
|
|
483
|
+
if len(table_data) > 0:
|
|
484
|
+
usage_table = generate_table(table_data, headers=header, col_alignments=['left', 'right', 'right', 'right', 'right', 'left'])
|
|
485
|
+
output.append(usage_table)
|
|
486
|
+
table_data = []
|
|
487
|
+
else:
|
|
488
|
+
print('RSE limits:')
|
|
489
|
+
print('===========')
|
|
490
|
+
for i, limit in enumerate(rse_limits):
|
|
491
|
+
if cli_config == 'rich':
|
|
492
|
+
if i == 0:
|
|
493
|
+
output.append('\n[b]RSE limits:[/]')
|
|
494
|
+
table_data.append([limit, str(rse_limits[limit]) + ' B'])
|
|
495
|
+
else:
|
|
496
|
+
print(' ' + limit + ': ' + str(rse_limits[limit]) + ' B')
|
|
497
|
+
|
|
498
|
+
if cli_config == 'rich':
|
|
499
|
+
if len(table_data) > 0:
|
|
500
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'right'])
|
|
501
|
+
output.append(table)
|
|
502
|
+
spinner.stop()
|
|
503
|
+
print_output(*output, console=console, no_pager=args.no_pager)
|
|
574
504
|
return SUCCESS
|
|
575
505
|
|
|
576
506
|
|
|
577
507
|
@exception_handler
|
|
578
|
-
def set_attribute_rse(args):
|
|
508
|
+
def set_attribute_rse(args, client, logger, console, spinner):
|
|
579
509
|
"""
|
|
580
510
|
%(prog)s set-attribute [options] <field1=value1 field2=value2 ...>
|
|
581
511
|
|
|
582
512
|
Set RSE attributes.
|
|
583
513
|
|
|
584
514
|
"""
|
|
585
|
-
client = get_client(args)
|
|
586
515
|
client.add_rse_attribute(rse=args.rse, key=args.key, value=args.value)
|
|
587
516
|
print('Added new RSE attribute for %s: %s-%s ' % (args.rse, args.key, args.value))
|
|
588
517
|
return SUCCESS
|
|
589
518
|
|
|
590
519
|
|
|
591
520
|
@exception_handler
|
|
592
|
-
def get_attribute_rse(args):
|
|
521
|
+
def get_attribute_rse(args, client, logger, console, spinner):
|
|
593
522
|
"""
|
|
594
523
|
%(prog)s get-attribute [options] <field1=value1 field2=value2 ...>
|
|
595
524
|
|
|
596
525
|
Get RSE attributes.
|
|
597
526
|
|
|
598
527
|
"""
|
|
599
|
-
client = get_client(args)
|
|
600
528
|
attributes = client.list_rse_attributes(rse=args.rse)
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
529
|
+
if cli_config == 'rich':
|
|
530
|
+
table_data = [(k, Text(str(v), style=CLITheme.BOOLEAN.get(str(v), 'default'))) for k, v in sorted(attributes.items())]
|
|
531
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
|
|
532
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
533
|
+
else:
|
|
534
|
+
for k in attributes:
|
|
535
|
+
print(k + ': ' + str(attributes[k]))
|
|
604
536
|
return SUCCESS
|
|
605
537
|
|
|
606
538
|
|
|
607
539
|
@exception_handler
|
|
608
|
-
def delete_attribute_rse(args):
|
|
540
|
+
def delete_attribute_rse(args, client, logger, console, spinner):
|
|
609
541
|
"""
|
|
610
542
|
%(prog)s delete-attribute [options] <field1=value1 field2=value2 ...>
|
|
611
543
|
|
|
612
544
|
Delete RSE attributes.
|
|
613
545
|
|
|
614
546
|
"""
|
|
615
|
-
client = get_client(args)
|
|
616
547
|
client.delete_rse_attribute(rse=args.rse, key=args.key)
|
|
617
548
|
print('Deleted RSE attribute for %s: %s-%s ' % (args.rse, args.key, args.value))
|
|
618
549
|
return SUCCESS
|
|
619
550
|
|
|
620
551
|
|
|
621
552
|
@exception_handler
|
|
622
|
-
def add_distance_rses(args):
|
|
553
|
+
def add_distance_rses(args, client, logger, console, spinner):
|
|
623
554
|
"""
|
|
624
555
|
%(prog)s add-distance [options] SOURCE_RSE DEST_RSE
|
|
625
556
|
|
|
626
557
|
Set the distance between two RSEs.
|
|
627
558
|
"""
|
|
628
|
-
client = get_client(args)
|
|
629
559
|
params = {'distance': args.distance}
|
|
630
560
|
client.add_distance(args.source, args.destination, params)
|
|
631
561
|
print('Set distance from %s to %s to %d' % (args.source, args.destination, args.distance))
|
|
@@ -633,29 +563,35 @@ def add_distance_rses(args):
|
|
|
633
563
|
|
|
634
564
|
|
|
635
565
|
@exception_handler
|
|
636
|
-
def get_distance_rses(args):
|
|
566
|
+
def get_distance_rses(args, client, logger, console, spinner):
|
|
637
567
|
"""
|
|
638
568
|
%(prog)s get-distance SOURCE_RSE DEST_RSE
|
|
639
569
|
|
|
640
570
|
Retrieve the existing distance information between two RSEs.
|
|
641
571
|
"""
|
|
642
|
-
client = get_client(args)
|
|
643
572
|
distance_info = client.get_distance(args.source, args.destination)
|
|
644
|
-
if
|
|
645
|
-
|
|
573
|
+
if cli_config == 'rich':
|
|
574
|
+
if distance_info:
|
|
575
|
+
table = generate_table([[args.source, args.destination, str(distance_info[0]['distance'])]], headers=['SOURCE', 'DESTINATION', 'DISTANCE'],
|
|
576
|
+
col_alignments=['left', 'left', 'right'])
|
|
577
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
578
|
+
else:
|
|
579
|
+
print(f"No distance set from {args.source} to {args.destination}")
|
|
646
580
|
else:
|
|
647
|
-
|
|
581
|
+
if distance_info:
|
|
582
|
+
print('Distance information from %s to %s: distance=%d' % (args.source, args.destination, distance_info[0]['distance']))
|
|
583
|
+
else:
|
|
584
|
+
print("No distance set from %s to %s" % (args.source, args.destination))
|
|
648
585
|
return SUCCESS
|
|
649
586
|
|
|
650
587
|
|
|
651
588
|
@exception_handler
|
|
652
|
-
def update_distance_rses(args):
|
|
589
|
+
def update_distance_rses(args, client, logger, console, spinner):
|
|
653
590
|
"""
|
|
654
591
|
%(prog)s update-distance [options] SOURCE_RSE DEST_RSE
|
|
655
592
|
|
|
656
593
|
Update the existing distance entry between two RSEs.
|
|
657
594
|
"""
|
|
658
|
-
client = get_client(args)
|
|
659
595
|
params = {}
|
|
660
596
|
if args.distance is not None:
|
|
661
597
|
params['distance'] = args.distance
|
|
@@ -669,26 +605,24 @@ def update_distance_rses(args):
|
|
|
669
605
|
|
|
670
606
|
|
|
671
607
|
@exception_handler
|
|
672
|
-
def delete_distance_rses(args):
|
|
608
|
+
def delete_distance_rses(args, client, logger, console, spinner):
|
|
673
609
|
"""
|
|
674
610
|
%(prog)s delete-distance [options] SOURCE_RSE DEST_RSE
|
|
675
611
|
|
|
676
612
|
Update the existing distance entry between two RSEs.
|
|
677
613
|
"""
|
|
678
|
-
client = get_client(args)
|
|
679
614
|
client.delete_distance(args.source, args.destination)
|
|
680
615
|
print('Deleted distance information from %s to %s.' % (args.source, args.destination))
|
|
681
616
|
return SUCCESS
|
|
682
617
|
|
|
683
618
|
|
|
684
619
|
@exception_handler
|
|
685
|
-
def add_protocol_rse(args):
|
|
620
|
+
def add_protocol_rse(args, client, logger, console, spinner):
|
|
686
621
|
"""
|
|
687
622
|
%(prog)s add-protocol-rse [options] <rse>
|
|
688
623
|
|
|
689
624
|
Add a new protocol handler for an RSE
|
|
690
625
|
"""
|
|
691
|
-
client = get_client(args)
|
|
692
626
|
proto = {'hostname': args.hostname,
|
|
693
627
|
'scheme': args.scheme,
|
|
694
628
|
'port': args.port,
|
|
@@ -714,13 +648,12 @@ def add_protocol_rse(args):
|
|
|
714
648
|
|
|
715
649
|
|
|
716
650
|
@exception_handler
|
|
717
|
-
def del_protocol_rse(args):
|
|
651
|
+
def del_protocol_rse(args, client, logger, console, spinner):
|
|
718
652
|
"""
|
|
719
653
|
%(prog)s delete-protocol-rse [options] <rse>
|
|
720
654
|
|
|
721
655
|
Remove a protocol handler for a RSE
|
|
722
656
|
"""
|
|
723
|
-
client = get_client(args)
|
|
724
657
|
kwargs = {}
|
|
725
658
|
if args.port:
|
|
726
659
|
kwargs['port'] = args.port
|
|
@@ -730,53 +663,59 @@ def del_protocol_rse(args):
|
|
|
730
663
|
|
|
731
664
|
|
|
732
665
|
@exception_handler
|
|
733
|
-
def add_qos_policy(args):
|
|
666
|
+
def add_qos_policy(args, client, logger, console, spinner):
|
|
734
667
|
"""
|
|
735
668
|
%(prog)s add-qos-policy <rse> <qos_policy>
|
|
736
669
|
|
|
737
670
|
Add a QoS policy to an RSE.
|
|
738
671
|
"""
|
|
739
|
-
client = get_client(args)
|
|
740
672
|
client.add_qos_policy(args.rse, args.qos_policy)
|
|
741
673
|
print('Added QoS policy to RSE %s: %s' % (args.rse, args.qos_policy))
|
|
742
674
|
return SUCCESS
|
|
743
675
|
|
|
744
676
|
|
|
745
677
|
@exception_handler
|
|
746
|
-
def delete_qos_policy(args):
|
|
678
|
+
def delete_qos_policy(args, client, logger, console, spinner):
|
|
747
679
|
"""
|
|
748
680
|
%(prog)s delete-qos-policy <rse> <qos_policy>
|
|
749
681
|
|
|
750
682
|
Delete a QoS policy from an RSE.
|
|
751
683
|
"""
|
|
752
|
-
client = get_client(args)
|
|
753
684
|
client.delete_qos_policy(args.rse, args.qos_policy)
|
|
754
685
|
print('Deleted QoS policy from RSE %s: %s' % (args.rse, args.qos_policy))
|
|
755
686
|
return SUCCESS
|
|
756
687
|
|
|
757
688
|
|
|
758
689
|
@exception_handler
|
|
759
|
-
def list_qos_policies(args):
|
|
690
|
+
def list_qos_policies(args, client, logger, console, spinner):
|
|
760
691
|
"""
|
|
761
692
|
%(prog)s list-qos-policies <rse>
|
|
762
693
|
|
|
763
694
|
List all QoS policies of an RSE.
|
|
764
695
|
"""
|
|
765
|
-
|
|
696
|
+
if cli_config == 'rich':
|
|
697
|
+
spinner.update(status='Fetching QoS policies')
|
|
698
|
+
spinner.start()
|
|
699
|
+
|
|
766
700
|
qos_policies = client.list_qos_policies(args.rse)
|
|
767
|
-
|
|
768
|
-
|
|
701
|
+
if cli_config == 'rich':
|
|
702
|
+
qos_policies = [[qos_policy] for qos_policy in sorted(qos_policies)]
|
|
703
|
+
table = generate_table(qos_policies, headers=['QOS POLICY'], col_alignments=['left'])
|
|
704
|
+
spinner.stop()
|
|
705
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
706
|
+
else:
|
|
707
|
+
for qos_policy in sorted(qos_policies):
|
|
708
|
+
print(qos_policy)
|
|
769
709
|
return SUCCESS
|
|
770
710
|
|
|
771
711
|
|
|
772
712
|
@exception_handler
|
|
773
|
-
def set_limit_rse(args):
|
|
713
|
+
def set_limit_rse(args, client, logger, console, spinner):
|
|
774
714
|
"""
|
|
775
715
|
%(prog)s set-limit <rse> <name> <value>
|
|
776
716
|
|
|
777
717
|
Set the RSE limit given the rse name and the name and value of the limit
|
|
778
718
|
"""
|
|
779
|
-
client = get_client(args)
|
|
780
719
|
try:
|
|
781
720
|
args.value = int(args.value)
|
|
782
721
|
if client.set_rse_limits(args.rse, args.name, args.value):
|
|
@@ -788,13 +727,12 @@ def set_limit_rse(args):
|
|
|
788
727
|
|
|
789
728
|
|
|
790
729
|
@exception_handler
|
|
791
|
-
def delete_limit_rse(args):
|
|
730
|
+
def delete_limit_rse(args, client, logger, console, spinner):
|
|
792
731
|
"""
|
|
793
732
|
%(prog)s delete-limit <rse> <name>
|
|
794
733
|
|
|
795
734
|
Delete the RSE limit given the rse name and the name of the limit
|
|
796
735
|
"""
|
|
797
|
-
client = get_client(args)
|
|
798
736
|
limits = client.get_rse_limits(args.rse)
|
|
799
737
|
if args.name not in limits.keys():
|
|
800
738
|
logger.error('Limit %s not defined in RSE %s' % (args.name, args.rse))
|
|
@@ -806,46 +744,53 @@ def delete_limit_rse(args):
|
|
|
806
744
|
|
|
807
745
|
|
|
808
746
|
@exception_handler
|
|
809
|
-
def add_scope(args):
|
|
747
|
+
def add_scope(args, client, logger, console, spinner):
|
|
810
748
|
"""
|
|
811
749
|
%(prog)s add [options] <field1=value1 field2=value2 ...>
|
|
812
750
|
|
|
813
751
|
Add scope.
|
|
814
752
|
|
|
815
753
|
"""
|
|
816
|
-
client = get_client(args)
|
|
817
754
|
client.add_scope(account=args.account, scope=args.scope)
|
|
818
755
|
print('Added new scope to account: %s-%s' % (args.scope, args.account))
|
|
819
756
|
return SUCCESS
|
|
820
757
|
|
|
821
758
|
|
|
822
759
|
@exception_handler
|
|
823
|
-
def list_scopes(args):
|
|
760
|
+
def list_scopes(args, client, logger, console, spinner):
|
|
824
761
|
"""
|
|
825
762
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
826
763
|
|
|
827
764
|
List scopes.
|
|
828
765
|
|
|
829
766
|
"""
|
|
830
|
-
|
|
767
|
+
if cli_config == 'rich':
|
|
768
|
+
spinner.update(status='Fetching scopes')
|
|
769
|
+
spinner.start()
|
|
770
|
+
|
|
831
771
|
if args.account:
|
|
832
772
|
scopes = client.list_scopes_for_account(args.account)
|
|
833
773
|
else:
|
|
834
774
|
scopes = client.list_scopes()
|
|
835
|
-
|
|
836
|
-
if 'mock' not in scope
|
|
837
|
-
|
|
775
|
+
if cli_config == 'rich':
|
|
776
|
+
scopes = [[scope] for scope in sorted(scopes) if 'mock' not in scope]
|
|
777
|
+
table = generate_table(scopes, headers=['SCOPE'], col_alignments=['left'])
|
|
778
|
+
spinner.stop()
|
|
779
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
780
|
+
else:
|
|
781
|
+
for scope in scopes:
|
|
782
|
+
if 'mock' not in scope:
|
|
783
|
+
print(scope)
|
|
838
784
|
return SUCCESS
|
|
839
785
|
|
|
840
786
|
|
|
841
787
|
@exception_handler
|
|
842
|
-
def get_config(args):
|
|
788
|
+
def get_config(args, client, logger, console, spinner):
|
|
843
789
|
"""
|
|
844
790
|
%(prog)s get [options] <field1=value1 field2=value2 ...>
|
|
845
791
|
|
|
846
792
|
Get the configuration. Either everything, or matching the given section/option.
|
|
847
793
|
"""
|
|
848
|
-
client = get_client(args)
|
|
849
794
|
res = client.get_config(section=args.section, option=args.option)
|
|
850
795
|
if not isinstance(res, dict):
|
|
851
796
|
print('[%s]\n%s=%s' % (args.section, args.option, str(res)))
|
|
@@ -867,26 +812,24 @@ def get_config(args):
|
|
|
867
812
|
|
|
868
813
|
|
|
869
814
|
@exception_handler
|
|
870
|
-
def set_config_option(args):
|
|
815
|
+
def set_config_option(args, client, logger, console, spinner):
|
|
871
816
|
"""
|
|
872
817
|
%(prog)s set [options] <field1=value1 field2=value2 ...>
|
|
873
818
|
|
|
874
819
|
Set the configuration value for a matching section/option. Missing section/option will be created.
|
|
875
820
|
"""
|
|
876
|
-
client = get_client(args)
|
|
877
821
|
client.set_config_option(section=args.section, option=args.option, value=args.value)
|
|
878
822
|
print('Set configuration: %s.%s=%s' % (args.section, args.option, args.value))
|
|
879
823
|
return SUCCESS
|
|
880
824
|
|
|
881
825
|
|
|
882
826
|
@exception_handler
|
|
883
|
-
def delete_config_option(args):
|
|
827
|
+
def delete_config_option(args, client, logger, console, spinner):
|
|
884
828
|
"""
|
|
885
829
|
%(prog)s delete [options] <field1=value1 field2=value2 ...>
|
|
886
830
|
|
|
887
831
|
Delete a configuration option from a section
|
|
888
832
|
"""
|
|
889
|
-
client = get_client(args)
|
|
890
833
|
if client.delete_config_option(section=args.section, option=args.option):
|
|
891
834
|
print('Deleted section \'%s\' option \'%s\'' % (args.section, args.option))
|
|
892
835
|
else:
|
|
@@ -895,14 +838,13 @@ def delete_config_option(args):
|
|
|
895
838
|
|
|
896
839
|
|
|
897
840
|
@exception_handler
|
|
898
|
-
def add_subscription(args):
|
|
841
|
+
def add_subscription(args, client, logger, console, spinner):
|
|
899
842
|
"""
|
|
900
843
|
%(prog)s add [options] name Filter replication_rules
|
|
901
844
|
|
|
902
845
|
Add subscription.
|
|
903
846
|
|
|
904
847
|
"""
|
|
905
|
-
client = get_client(args)
|
|
906
848
|
if args.subs_account:
|
|
907
849
|
account = args.subs_account
|
|
908
850
|
elif args.issuer:
|
|
@@ -916,39 +858,85 @@ def add_subscription(args):
|
|
|
916
858
|
|
|
917
859
|
|
|
918
860
|
@exception_handler
|
|
919
|
-
def list_subscriptions(args):
|
|
861
|
+
def list_subscriptions(args, client, logger, console, spinner):
|
|
920
862
|
"""
|
|
921
863
|
%(prog)s list [options] [name]
|
|
922
864
|
|
|
923
865
|
List subscriptions.
|
|
924
866
|
|
|
925
867
|
"""
|
|
926
|
-
client = get_client(args)
|
|
927
868
|
if args.subs_account:
|
|
928
869
|
account = args.subs_account
|
|
929
870
|
elif args.issuer:
|
|
930
871
|
account = args.issuer
|
|
931
872
|
else:
|
|
932
873
|
account = client.account
|
|
874
|
+
|
|
875
|
+
if cli_config == 'rich':
|
|
876
|
+
spinner.update(status='Fetching subscriptions')
|
|
877
|
+
spinner.start()
|
|
878
|
+
keyword_styles = {**CLITheme.SUBSCRIPTION_STATE, **CLITheme.BOOLEAN}
|
|
879
|
+
|
|
933
880
|
subs = client.list_subscriptions(name=args.name, account=account)
|
|
934
881
|
for sub in subs:
|
|
882
|
+
table_data = []
|
|
935
883
|
if args.long:
|
|
936
|
-
|
|
937
|
-
|
|
884
|
+
if cli_config == 'rich':
|
|
885
|
+
for k, v in sorted(sub.items()):
|
|
886
|
+
if k == 'filter':
|
|
887
|
+
filter_tree = Tree('')
|
|
888
|
+
for filter, values in json.loads(sub['filter']).items():
|
|
889
|
+
values_str = ', '.join(values)
|
|
890
|
+
filter_tree.add(f'[{CLITheme.JSON_STR}]{filter}[/]: {values_str}')
|
|
891
|
+
table_data.append(['filter', filter_tree])
|
|
892
|
+
elif k == 'replication_rules':
|
|
893
|
+
rule_tree = Tree('')
|
|
894
|
+
for i, rule in enumerate(json.loads(sub['replication_rules'])):
|
|
895
|
+
branch = rule_tree.add(Text('rule:', style='default'))
|
|
896
|
+
for k, v in rule.items():
|
|
897
|
+
branch.add(f'[{CLITheme.JSON_STR}]{k}[/]: {v}')
|
|
898
|
+
table_data.append(['replication_rules', rule_tree])
|
|
899
|
+
else:
|
|
900
|
+
table_data.append([str(k), Text(str(v), style=keyword_styles.get(str(v), 'default'))])
|
|
901
|
+
else:
|
|
902
|
+
print('\n'.join('%s: %s' % (str(k), str(v)) for (k, v) in list(sub.items())))
|
|
903
|
+
print()
|
|
938
904
|
else:
|
|
939
|
-
|
|
905
|
+
if cli_config == 'rich':
|
|
906
|
+
table_data.append(['account', sub['account']])
|
|
907
|
+
table_data.append(['comments', sub.get('comments', '')])
|
|
908
|
+
filter_tree = Tree('')
|
|
909
|
+
for filter, values in json.loads(sub['filter']).items():
|
|
910
|
+
values_str = ', '.join(values)
|
|
911
|
+
filter_tree.add(f'[green]{filter}[/]: {values_str}')
|
|
912
|
+
table_data.append(['filter', filter_tree])
|
|
913
|
+
table_data.append(['name', sub['name']])
|
|
914
|
+
table_data.append(['policyid', str(sub['policyid'])])
|
|
915
|
+
rule_tree = Tree('')
|
|
916
|
+
for i, rule in enumerate(json.loads(sub['replication_rules'])):
|
|
917
|
+
branch = rule_tree.add(Text('rule:', style='default'))
|
|
918
|
+
for k, v in rule.items():
|
|
919
|
+
branch.add(f'[{CLITheme.JSON_STR}]{k}[/]: {v}')
|
|
920
|
+
table_data.append(['replication_rules', rule_tree])
|
|
921
|
+
table_data.append(['state', Text(str(sub['state']), keyword_styles.get(str(sub['state']), 'default'))])
|
|
922
|
+
else:
|
|
923
|
+
print("%s: %s %s\n priority: %s\n filter: %s\n rules: %s\n comments: %s" % (sub['account'], sub['name'], sub['state'], sub['policyid'], sub['filter'], sub['replication_rules'], sub.get('comments', '')))
|
|
924
|
+
|
|
925
|
+
if cli_config == 'rich':
|
|
926
|
+
table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
|
|
927
|
+
spinner.stop()
|
|
928
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
940
929
|
return SUCCESS
|
|
941
930
|
|
|
942
931
|
|
|
943
932
|
@exception_handler
|
|
944
|
-
def update_subscription(args):
|
|
933
|
+
def update_subscription(args, client, logger, console, spinner):
|
|
945
934
|
"""
|
|
946
935
|
%(prog)s update [options] name filter replication_rules
|
|
947
936
|
|
|
948
937
|
Update a subscription.
|
|
949
938
|
|
|
950
939
|
"""
|
|
951
|
-
client = get_client(args)
|
|
952
940
|
if args.subs_account:
|
|
953
941
|
account = args.subs_account
|
|
954
942
|
elif args.issuer:
|
|
@@ -961,14 +949,13 @@ def update_subscription(args):
|
|
|
961
949
|
|
|
962
950
|
|
|
963
951
|
@exception_handler
|
|
964
|
-
def reevaluate_did_for_subscription(args):
|
|
952
|
+
def reevaluate_did_for_subscription(args, client, logger, console, spinner):
|
|
965
953
|
"""
|
|
966
954
|
%(prog)s reevaulate [options] dids
|
|
967
955
|
|
|
968
956
|
Reevaluate a list of DIDs against all active subscriptions.
|
|
969
957
|
|
|
970
958
|
"""
|
|
971
|
-
client = get_client(args)
|
|
972
959
|
for did in args.dids.split(','):
|
|
973
960
|
scope, name = get_scope(did, client)
|
|
974
961
|
client.set_metadata(scope, name, 'is_new', True)
|
|
@@ -976,56 +963,57 @@ def reevaluate_did_for_subscription(args):
|
|
|
976
963
|
|
|
977
964
|
|
|
978
965
|
@exception_handler
|
|
979
|
-
def list_account_attributes(args):
|
|
966
|
+
def list_account_attributes(args, client, logger, console, spinner):
|
|
980
967
|
"""
|
|
981
968
|
%(prog)s show [options] <field1=value1 field2=value2 ...>
|
|
982
969
|
|
|
983
970
|
List the attributes for an account.
|
|
984
971
|
|
|
985
972
|
"""
|
|
986
|
-
client = get_client(args)
|
|
987
973
|
account = args.account or client.account
|
|
988
974
|
attributes = next(client.list_account_attributes(account))
|
|
989
|
-
|
|
975
|
+
table_data = []
|
|
990
976
|
for attr in attributes:
|
|
991
|
-
|
|
992
|
-
|
|
977
|
+
table_data.append([attr['key'], attr['value']])
|
|
978
|
+
|
|
979
|
+
if cli_config == 'rich':
|
|
980
|
+
table = generate_table(table_data, headers=['Key', 'Value'], col_alignments=['left', 'left'])
|
|
981
|
+
print_output(table, console=console, no_pager=args.no_pager)
|
|
982
|
+
else:
|
|
983
|
+
print(tabulate(table_data, tablefmt=tablefmt, headers=['Key', 'Value']))
|
|
993
984
|
return SUCCESS
|
|
994
985
|
|
|
995
986
|
|
|
996
987
|
@exception_handler
|
|
997
|
-
def add_account_attribute(args):
|
|
988
|
+
def add_account_attribute(args, client, logger, console, spinner):
|
|
998
989
|
"""
|
|
999
990
|
%(prog)s show [options] <field1=value1 field2=value2 ...>
|
|
1000
991
|
|
|
1001
992
|
Add attribute for an account.
|
|
1002
993
|
|
|
1003
994
|
"""
|
|
1004
|
-
client = get_client(args)
|
|
1005
995
|
client.add_account_attribute(account=args.account, key=args.key, value=args.value)
|
|
1006
996
|
return SUCCESS
|
|
1007
997
|
|
|
1008
998
|
|
|
1009
999
|
@exception_handler
|
|
1010
|
-
def delete_account_attribute(args):
|
|
1000
|
+
def delete_account_attribute(args, client, logger, console, spinner):
|
|
1011
1001
|
"""
|
|
1012
1002
|
%(prog)s show [options] <field1=value1 field2=value2 ...>
|
|
1013
1003
|
|
|
1014
1004
|
Delete attribute for an account.
|
|
1015
1005
|
|
|
1016
1006
|
"""
|
|
1017
|
-
client = get_client(args)
|
|
1018
1007
|
client.delete_account_attribute(account=args.account, key=args.key)
|
|
1019
1008
|
return SUCCESS
|
|
1020
1009
|
|
|
1021
1010
|
|
|
1022
1011
|
@exception_handler
|
|
1023
|
-
def quarantine_replicas(args):
|
|
1012
|
+
def quarantine_replicas(args, client, logger, console, spinner):
|
|
1024
1013
|
"""
|
|
1025
1014
|
%(prog)s quarantine --rse <rse> (--paths <file with replica paths>|<path> ...)
|
|
1026
1015
|
Quarantine replicas
|
|
1027
1016
|
"""
|
|
1028
|
-
client = get_client(args)
|
|
1029
1017
|
chunk = []
|
|
1030
1018
|
|
|
1031
1019
|
# send requests in chunks
|
|
@@ -1049,7 +1037,7 @@ def quarantine_replicas(args):
|
|
|
1049
1037
|
return SUCCESS
|
|
1050
1038
|
|
|
1051
1039
|
|
|
1052
|
-
def __declare_bad_file_replicas_by_lfns(args: object) -> object:
|
|
1040
|
+
def __declare_bad_file_replicas_by_lfns(args: object, client) -> object:
|
|
1053
1041
|
"""
|
|
1054
1042
|
Declare a list of bad replicas using RSE name, scope and list of LFNs.
|
|
1055
1043
|
"""
|
|
@@ -1059,7 +1047,6 @@ def __declare_bad_file_replicas_by_lfns(args: object) -> object:
|
|
|
1059
1047
|
reason = args.reason
|
|
1060
1048
|
scope = args.scope
|
|
1061
1049
|
rse = args.rse
|
|
1062
|
-
client = get_client(args)
|
|
1063
1050
|
replicas = []
|
|
1064
1051
|
|
|
1065
1052
|
# send requests in chunks
|
|
@@ -1084,7 +1071,7 @@ def __declare_bad_file_replicas_by_lfns(args: object) -> object:
|
|
|
1084
1071
|
|
|
1085
1072
|
|
|
1086
1073
|
@exception_handler
|
|
1087
|
-
def declare_bad_file_replicas(args):
|
|
1074
|
+
def declare_bad_file_replicas(args, client, logger, console, spinner):
|
|
1088
1075
|
"""
|
|
1089
1076
|
|
|
1090
1077
|
Declare replicas as bad.
|
|
@@ -1092,9 +1079,7 @@ def declare_bad_file_replicas(args):
|
|
|
1092
1079
|
"""
|
|
1093
1080
|
|
|
1094
1081
|
if args.lfns:
|
|
1095
|
-
return __declare_bad_file_replicas_by_lfns(args)
|
|
1096
|
-
|
|
1097
|
-
client = get_client(args)
|
|
1082
|
+
return __declare_bad_file_replicas_by_lfns(args, client)
|
|
1098
1083
|
|
|
1099
1084
|
if args.inputfile:
|
|
1100
1085
|
with open(args.inputfile) as infile:
|
|
@@ -1175,14 +1160,13 @@ def declare_bad_file_replicas(args):
|
|
|
1175
1160
|
|
|
1176
1161
|
|
|
1177
1162
|
@exception_handler
|
|
1178
|
-
def declare_temporary_unavailable_replicas(args):
|
|
1163
|
+
def declare_temporary_unavailable_replicas(args, client, logger, console, spinner):
|
|
1179
1164
|
"""
|
|
1180
1165
|
%(prog)s show [options] <field1=value1 field2=value2 ...>
|
|
1181
1166
|
|
|
1182
1167
|
Declare a list of temporary unavailable replicas.
|
|
1183
1168
|
|
|
1184
1169
|
"""
|
|
1185
|
-
client = get_client(args)
|
|
1186
1170
|
bad_files = []
|
|
1187
1171
|
if args.inputfile:
|
|
1188
1172
|
with open(args.inputfile) as infile:
|
|
@@ -1218,14 +1202,13 @@ def declare_temporary_unavailable_replicas(args):
|
|
|
1218
1202
|
|
|
1219
1203
|
|
|
1220
1204
|
@exception_handler
|
|
1221
|
-
def list_pfns(args):
|
|
1205
|
+
def list_pfns(args, client, logger, console, spinner):
|
|
1222
1206
|
"""
|
|
1223
1207
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
1224
1208
|
|
|
1225
1209
|
List the possible PFN for a file at a site.
|
|
1226
1210
|
|
|
1227
1211
|
"""
|
|
1228
|
-
client = get_client(args)
|
|
1229
1212
|
dids = args.dids.split(',')
|
|
1230
1213
|
rse = args.rse
|
|
1231
1214
|
protocol = args.protocol
|
|
@@ -1271,71 +1254,104 @@ def list_pfns(args):
|
|
|
1271
1254
|
|
|
1272
1255
|
|
|
1273
1256
|
@exception_handler
|
|
1274
|
-
def import_data(args):
|
|
1257
|
+
def import_data(args, client, logger, console, spinner):
|
|
1275
1258
|
"""
|
|
1276
1259
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
1277
1260
|
|
|
1278
1261
|
Import data from JSON file to Rucio.
|
|
1279
1262
|
|
|
1280
1263
|
"""
|
|
1281
|
-
client = get_client(args)
|
|
1282
1264
|
import_file_path = args.file_path
|
|
1283
1265
|
data = None
|
|
1284
|
-
|
|
1266
|
+
if cli_config == 'rich':
|
|
1267
|
+
spinner.update(status='Reading file')
|
|
1268
|
+
spinner.start()
|
|
1269
|
+
|
|
1285
1270
|
try:
|
|
1286
1271
|
with open(import_file_path) as import_file:
|
|
1287
1272
|
data_string = import_file.read()
|
|
1288
1273
|
data = parse_response(data_string)
|
|
1289
1274
|
except ValueError as error:
|
|
1290
|
-
|
|
1291
|
-
|
|
1275
|
+
if cli_config == 'rich':
|
|
1276
|
+
spinner.stop()
|
|
1277
|
+
print_output(f'{CLITheme.FAILURE_ICON} There was problem with decoding your file.', console=console, no_pager=True)
|
|
1278
|
+
logger.error(error)
|
|
1279
|
+
else:
|
|
1280
|
+
print('There was problem with decoding your file.')
|
|
1281
|
+
print(error)
|
|
1292
1282
|
return FAILURE
|
|
1293
1283
|
except OSError as error:
|
|
1294
|
-
|
|
1295
|
-
|
|
1284
|
+
if cli_config == 'rich':
|
|
1285
|
+
spinner.stop()
|
|
1286
|
+
print_output(f'{CLITheme.FAILURE_ICON} There was a problem with reading your file.', console=console, no_pager=True)
|
|
1287
|
+
logger.error(error)
|
|
1288
|
+
else:
|
|
1289
|
+
print('There was a problem with reading your file.')
|
|
1290
|
+
print(error)
|
|
1296
1291
|
return FAILURE
|
|
1297
1292
|
|
|
1298
1293
|
if data:
|
|
1299
1294
|
client.import_data(data)
|
|
1300
|
-
|
|
1295
|
+
if cli_config == 'rich':
|
|
1296
|
+
spinner.stop()
|
|
1297
|
+
print_output(f'{CLITheme.SUCCESS_ICON} Data successfully imported.', console=console, no_pager=True)
|
|
1298
|
+
else:
|
|
1299
|
+
print('Data successfully imported.')
|
|
1301
1300
|
return SUCCESS
|
|
1302
1301
|
else:
|
|
1303
|
-
|
|
1302
|
+
if cli_config == 'rich':
|
|
1303
|
+
spinner.stop()
|
|
1304
|
+
print_output('Nothing to import.', console=console, no_pager=True)
|
|
1305
|
+
else:
|
|
1306
|
+
print('Nothing to import.')
|
|
1304
1307
|
return FAILURE
|
|
1305
1308
|
|
|
1306
1309
|
|
|
1307
1310
|
@exception_handler
|
|
1308
|
-
def export_data(args):
|
|
1311
|
+
def export_data(args, client, logger, console, spinner):
|
|
1309
1312
|
"""
|
|
1310
1313
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
1311
1314
|
|
|
1312
1315
|
Export data from Rucio to JSON file.
|
|
1313
1316
|
|
|
1314
1317
|
"""
|
|
1315
|
-
client = get_client(args)
|
|
1316
1318
|
destination_file_path = args.file_path
|
|
1317
|
-
|
|
1319
|
+
if cli_config == 'rich':
|
|
1320
|
+
spinner.update(status='Querying data')
|
|
1321
|
+
spinner.start()
|
|
1322
|
+
else:
|
|
1323
|
+
print('Start querying data.')
|
|
1324
|
+
|
|
1318
1325
|
data = client.export_data()
|
|
1319
1326
|
try:
|
|
1320
1327
|
with open(destination_file_path, 'w+') as destination_file:
|
|
1321
1328
|
destination_file.write(render_json(**data))
|
|
1322
|
-
|
|
1323
|
-
|
|
1329
|
+
if cli_config != 'rich':
|
|
1330
|
+
print('File successfully written.')
|
|
1331
|
+
if cli_config == 'rich':
|
|
1332
|
+
spinner.stop()
|
|
1333
|
+
print_output(f'{CLITheme.SUCCESS_ICON} Data successfully exported to {args.file_path}', console=console, no_pager=True)
|
|
1334
|
+
else:
|
|
1335
|
+
print('Data successfully exported to %s' % args.file_path)
|
|
1324
1336
|
return SUCCESS
|
|
1325
1337
|
except OSError as error:
|
|
1326
|
-
|
|
1327
|
-
|
|
1338
|
+
if cli_config == 'rich':
|
|
1339
|
+
spinner.stop()
|
|
1340
|
+
print_output(f'{CLITheme.FAILURE_ICON} There was a problem with reading your file.', console=console, no_pager=True)
|
|
1341
|
+
logger.error(error)
|
|
1342
|
+
else:
|
|
1343
|
+
print('There was a problem with reading your file.')
|
|
1344
|
+
print(error)
|
|
1328
1345
|
return FAILURE
|
|
1329
1346
|
|
|
1330
1347
|
|
|
1331
1348
|
@exception_handler
|
|
1332
|
-
def set_tombstone(args):
|
|
1349
|
+
def set_tombstone(args, client, logger, console, spinner):
|
|
1333
1350
|
"""
|
|
1334
1351
|
%(prog)s list [options] <field1=value1 field2=value2 ...>
|
|
1335
1352
|
|
|
1336
1353
|
Set a tombstone on a list of replicas.
|
|
1337
1354
|
"""
|
|
1338
|
-
client = get_client(args)
|
|
1339
1355
|
dids = args.dids
|
|
1340
1356
|
rse = args.rse
|
|
1341
1357
|
dids = [dids] if ',' not in dids else dids.split(',')
|
|
@@ -1367,7 +1383,9 @@ def get_parser():
|
|
|
1367
1383
|
oparser.add_argument('-a', '--account', dest="issuer", metavar="ACCOUNT", help="Rucio account to use")
|
|
1368
1384
|
oparser.add_argument('-S', '--auth-strategy', dest="auth_strategy", default=None, help="Authentication strategy (userpass, x509, ssh ...)")
|
|
1369
1385
|
oparser.add_argument('-T', '--timeout', dest="timeout", type=float, default=None, help="Set all timeout values to SECONDS")
|
|
1386
|
+
oparser.add_argument('--user-agent', '-U', dest="user_agent", default='rucio-clients', action='store', help="Rucio User Agent")
|
|
1370
1387
|
oparser.add_argument('--vo', dest="vo", metavar="VO", default=None, help="VO to authenticate at. Only used in multi-VO mode.")
|
|
1388
|
+
oparser.add_argument("--no-pager", dest="no_pager", default=False, action='store_true', help=argparse.SUPPRESS)
|
|
1371
1389
|
|
|
1372
1390
|
# Options for the userpass auth_strategy
|
|
1373
1391
|
oparser.add_argument('-u', '--user', dest='username', default=None, help='username')
|
|
@@ -1391,6 +1409,7 @@ def get_parser():
|
|
|
1391
1409
|
|
|
1392
1410
|
# Options for the x509 auth_strategy
|
|
1393
1411
|
oparser.add_argument('--certificate', dest='certificate', default=None, help='Client certificate file')
|
|
1412
|
+
oparser.add_argument('--client-key', dest='client_key', default=None, help='Client key for x509 Authentication.')
|
|
1394
1413
|
oparser.add_argument('--ca-certificate', dest='ca_certificate', default=None, help='CA certificate to verify peer against (SSL)')
|
|
1395
1414
|
|
|
1396
1415
|
# The import export subparser
|
|
@@ -1440,6 +1459,7 @@ def get_parser():
|
|
|
1440
1459
|
list_account_parser.add_argument('--type', dest='account_type', action='store', help='Account Type (USER, GROUP, SERVICE)')
|
|
1441
1460
|
list_account_parser.add_argument('--id', dest='identity', action='store', help='Identity (e.g. DN)')
|
|
1442
1461
|
list_account_parser.add_argument('--filters', dest='filters', action='store', help='Filter arguments in form `key=value,another_key=next_value`')
|
|
1462
|
+
list_account_parser.add_argument("--csv", action='store_true', help='List result as a csv')
|
|
1443
1463
|
list_account_parser.set_defaults(which='list_accounts')
|
|
1444
1464
|
|
|
1445
1465
|
# The list_account_attributes command
|
|
@@ -1508,8 +1528,8 @@ def get_parser():
|
|
|
1508
1528
|
'\n')
|
|
1509
1529
|
add_account_parser.set_defaults(which='add_account')
|
|
1510
1530
|
add_account_parser.add_argument('account', action='store', help='Account name')
|
|
1511
|
-
add_account_parser.add_argument('--type', dest='
|
|
1512
|
-
add_account_parser.add_argument('--email', dest='
|
|
1531
|
+
add_account_parser.add_argument('--type', dest='account_type', default='USER', help='Account Type (USER, GROUP, SERVICE)')
|
|
1532
|
+
add_account_parser.add_argument('--email', dest='email', action='store',
|
|
1513
1533
|
help='Email address associated with the account')
|
|
1514
1534
|
|
|
1515
1535
|
# The disable_account command
|
|
@@ -1524,7 +1544,7 @@ def get_parser():
|
|
|
1524
1544
|
' Deleted account: jdoe-sister\n'
|
|
1525
1545
|
'\n')
|
|
1526
1546
|
delete_account_parser.set_defaults(which='delete_account')
|
|
1527
|
-
delete_account_parser.add_argument('
|
|
1547
|
+
delete_account_parser.add_argument('account', action='store', help='Account name')
|
|
1528
1548
|
|
|
1529
1549
|
# The info_account command
|
|
1530
1550
|
info_account_parser = account_subparser.add_parser('info',
|
|
@@ -1738,6 +1758,7 @@ def get_parser():
|
|
|
1738
1758
|
'\n'
|
|
1739
1759
|
' $ rucio list-rses --rses \"tier=2&type=DATADISK\"\n'
|
|
1740
1760
|
'\n')
|
|
1761
|
+
list_rse_parser.add_argument("--csv", action='store_true', help='Output a list of RSEs as a csv')
|
|
1741
1762
|
list_rse_parser.set_defaults(which='list_rses')
|
|
1742
1763
|
|
|
1743
1764
|
# The add_rse command
|
|
@@ -2368,7 +2389,7 @@ def get_parser():
|
|
|
2368
2389
|
return oparser
|
|
2369
2390
|
|
|
2370
2391
|
|
|
2371
|
-
|
|
2392
|
+
def main():
|
|
2372
2393
|
oparser = get_parser()
|
|
2373
2394
|
if EXTRA_MODULES['argcomplete']:
|
|
2374
2395
|
argcomplete.autocomplete(oparser)
|
|
@@ -2382,66 +2403,98 @@ if __name__ == '__main__':
|
|
|
2382
2403
|
if not hasattr(args, 'which'):
|
|
2383
2404
|
oparser.print_help()
|
|
2384
2405
|
sys.exit(FAILURE)
|
|
2406
|
+
else:
|
|
2407
|
+
commands = {'add_account': add_account,
|
|
2408
|
+
'list_accounts': list_accounts,
|
|
2409
|
+
'list_account_attributes': list_account_attributes,
|
|
2410
|
+
'add_account_attribute': add_account_attribute,
|
|
2411
|
+
'delete_account_attribute': delete_account_attribute,
|
|
2412
|
+
'delete_account': delete_account,
|
|
2413
|
+
'info_account': info_account,
|
|
2414
|
+
'ban_account': ban_account,
|
|
2415
|
+
'unban_account': unban_account,
|
|
2416
|
+
'update_account': update_account,
|
|
2417
|
+
'get_limits': get_limits,
|
|
2418
|
+
'set_limits': set_limits,
|
|
2419
|
+
'delete_limits': delete_limits,
|
|
2420
|
+
'list_identities': list_identities,
|
|
2421
|
+
'identity_add': identity_add,
|
|
2422
|
+
'identity_delete': identity_delete,
|
|
2423
|
+
'add_rse': add_rse,
|
|
2424
|
+
'update_rse': update_rse,
|
|
2425
|
+
'set_attribute_rse': set_attribute_rse,
|
|
2426
|
+
'get_attribute_rse': get_attribute_rse,
|
|
2427
|
+
'delete_attribute_rse': delete_attribute_rse,
|
|
2428
|
+
'add_distance_rses': add_distance_rses,
|
|
2429
|
+
'update_distance_rses': update_distance_rses,
|
|
2430
|
+
'get_distance_rses': get_distance_rses,
|
|
2431
|
+
'delete_distance_rses': delete_distance_rses,
|
|
2432
|
+
'add_protocol_rse': add_protocol_rse,
|
|
2433
|
+
'del_protocol_rse': del_protocol_rse,
|
|
2434
|
+
'list_rses': list_rses,
|
|
2435
|
+
'disable_rse': disable_rse,
|
|
2436
|
+
'add_qos_policy': add_qos_policy,
|
|
2437
|
+
'delete_qos_policy': delete_qos_policy,
|
|
2438
|
+
'list_qos_policies': list_qos_policies,
|
|
2439
|
+
'add_scope': add_scope,
|
|
2440
|
+
'list_scopes': list_scopes,
|
|
2441
|
+
'info_rse': info_rse,
|
|
2442
|
+
'get_config': get_config,
|
|
2443
|
+
'set_config_option': set_config_option,
|
|
2444
|
+
'delete_config_option': delete_config_option,
|
|
2445
|
+
'add_subscription': add_subscription,
|
|
2446
|
+
'list_subscriptions': list_subscriptions,
|
|
2447
|
+
'update_subscription': update_subscription,
|
|
2448
|
+
'reevaluate_did_for_subscription': reevaluate_did_for_subscription,
|
|
2449
|
+
'declare_bad_file_replicas': declare_bad_file_replicas,
|
|
2450
|
+
'quarantine_replicas': quarantine_replicas,
|
|
2451
|
+
'declare_temporary_unavailable_replicas': declare_temporary_unavailable_replicas,
|
|
2452
|
+
'list_pfns': list_pfns,
|
|
2453
|
+
'import': import_data,
|
|
2454
|
+
'export': export_data,
|
|
2455
|
+
'set_tombstone': set_tombstone,
|
|
2456
|
+
'set_limit_rse': set_limit_rse,
|
|
2457
|
+
'delete_limit_rse': delete_limit_rse,
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
pager = get_pager()
|
|
2461
|
+
console = Console(theme=Theme(CLITheme.LOG_THEMES), soft_wrap=True)
|
|
2462
|
+
console.width = max(MIN_CONSOLE_WIDTH, console.width)
|
|
2463
|
+
|
|
2464
|
+
cli_config = get_cli_config()
|
|
2465
|
+
spinner = Status('Initializing spinner', spinner=CLITheme.SPINNER, spinner_style=CLITheme.SPINNER_STYLE, console=console)
|
|
2466
|
+
|
|
2467
|
+
if cli_config == 'rich':
|
|
2468
|
+
install(console=console, word_wrap=True, width=min(console.width, MAX_TRACEBACK_WIDTH)) # Make rich exception tracebacks the default.
|
|
2469
|
+
logger = setup_rich_logger(module_name=__name__, logger_name='user', verbose=args.verbose, console=console)
|
|
2470
|
+
else:
|
|
2471
|
+
logger = setup_logger(module_name=__name__, logger_name='user', verbose=args.verbose)
|
|
2472
|
+
|
|
2473
|
+
signal.signal(signal.SIGINT, lambda sig, frame: signal_handler(sig, frame, logger))
|
|
2474
|
+
setup_gfal2_logger()
|
|
2475
|
+
start_time = time.time()
|
|
2476
|
+
command = commands.get(args.which)
|
|
2477
|
+
client = get_client(args, logger)
|
|
2478
|
+
result = command(args, client, logger, console, spinner) # type: ignore
|
|
2479
|
+
|
|
2480
|
+
end_time = time.time()
|
|
2481
|
+
if cli_config == 'rich':
|
|
2482
|
+
spinner.stop()
|
|
2483
|
+
if console.is_terminal and not args.no_pager:
|
|
2484
|
+
command_output = console.end_capture()
|
|
2485
|
+
if command_output == '' and args.verbose:
|
|
2486
|
+
print("Completed in %-0.4f sec." % (end_time - start_time))
|
|
2487
|
+
else:
|
|
2488
|
+
if args.verbose:
|
|
2489
|
+
command_output += "Completed in %-0.4f sec." % (end_time - start_time)
|
|
2490
|
+
# Ignore SIGINT during pager execution.
|
|
2491
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
2492
|
+
pager(command_output)
|
|
2493
|
+
else:
|
|
2494
|
+
if args.verbose:
|
|
2495
|
+
print("Completed in %-0.4f sec." % (end_time - start_time))
|
|
2496
|
+
sys.exit(result)
|
|
2385
2497
|
|
|
2386
|
-
commands = {'add_account': add_account,
|
|
2387
|
-
'list_accounts': list_accounts,
|
|
2388
|
-
'list_account_attributes': list_account_attributes,
|
|
2389
|
-
'add_account_attribute': add_account_attribute,
|
|
2390
|
-
'delete_account_attribute': delete_account_attribute,
|
|
2391
|
-
'delete_account': delete_account,
|
|
2392
|
-
'info_account': info_account,
|
|
2393
|
-
'ban_account': ban_account,
|
|
2394
|
-
'unban_account': unban_account,
|
|
2395
|
-
'update_account': update_account,
|
|
2396
|
-
'get_limits': get_limits,
|
|
2397
|
-
'set_limits': set_limits,
|
|
2398
|
-
'delete_limits': delete_limits,
|
|
2399
|
-
'list_identities': list_identities,
|
|
2400
|
-
'identity_add': identity_add,
|
|
2401
|
-
'identity_delete': identity_delete,
|
|
2402
|
-
'add_rse': add_rse,
|
|
2403
|
-
'update_rse': update_rse,
|
|
2404
|
-
'set_attribute_rse': set_attribute_rse,
|
|
2405
|
-
'get_attribute_rse': get_attribute_rse,
|
|
2406
|
-
'delete_attribute_rse': delete_attribute_rse,
|
|
2407
|
-
'add_distance_rses': add_distance_rses,
|
|
2408
|
-
'update_distance_rses': update_distance_rses,
|
|
2409
|
-
'get_distance_rses': get_distance_rses,
|
|
2410
|
-
'delete_distance_rses': delete_distance_rses,
|
|
2411
|
-
'add_protocol_rse': add_protocol_rse,
|
|
2412
|
-
'del_protocol_rse': del_protocol_rse,
|
|
2413
|
-
'list_rses': list_rses,
|
|
2414
|
-
'disable_rse': disable_rse,
|
|
2415
|
-
'add_qos_policy': add_qos_policy,
|
|
2416
|
-
'delete_qos_policy': delete_qos_policy,
|
|
2417
|
-
'list_qos_policies': list_qos_policies,
|
|
2418
|
-
'add_scope': add_scope,
|
|
2419
|
-
'list_scopes': list_scopes,
|
|
2420
|
-
'info_rse': info_rse,
|
|
2421
|
-
'get_config': get_config,
|
|
2422
|
-
'set_config_option': set_config_option,
|
|
2423
|
-
'delete_config_option': delete_config_option,
|
|
2424
|
-
'add_subscription': add_subscription,
|
|
2425
|
-
'list_subscriptions': list_subscriptions,
|
|
2426
|
-
'update_subscription': update_subscription,
|
|
2427
|
-
'reevaluate_did_for_subscription': reevaluate_did_for_subscription,
|
|
2428
|
-
'declare_bad_file_replicas': declare_bad_file_replicas,
|
|
2429
|
-
'quarantine_replicas': quarantine_replicas,
|
|
2430
|
-
'declare_temporary_unavailable_replicas': declare_temporary_unavailable_replicas,
|
|
2431
|
-
'list_pfns': list_pfns,
|
|
2432
|
-
'import': import_data,
|
|
2433
|
-
'export': export_data,
|
|
2434
|
-
'set_tombstone': set_tombstone,
|
|
2435
|
-
'set_limit_rse': set_limit_rse,
|
|
2436
|
-
'delete_limit_rse': delete_limit_rse,
|
|
2437
|
-
}
|
|
2438
2498
|
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
start_time = time.time()
|
|
2442
|
-
command = commands.get(args.which)
|
|
2443
|
-
result = command(args)
|
|
2444
|
-
end_time = time.time()
|
|
2445
|
-
if args.verbose:
|
|
2446
|
-
print("Completed in %-0.4f sec." % (end_time - start_time))
|
|
2447
|
-
sys.exit(result)
|
|
2499
|
+
if __name__ == '__main__':
|
|
2500
|
+
main()
|