def get(self): """ List all RSEs. .. :quickref: RSEs; List all RSEs. :query expression: The returned list only contains RSE matching this expression. :resheader Content-Type: application/x-json-stream :status 200: DIDs found. :status 400: Invalid RSE Expression. :status 401: Invalid Auth Token. :status 406: Not Acceptable. :status 500: Internal Error. :returns: A list containing all RSEs. """ expression = request.args.get('expression') if expression: try: def generate(vo): for rse in parse_rse_expression(expression, vo=vo): yield render_json(rse=rse) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except InvalidRSEExpression as error: return generate_http_error_flask(400, 'InvalidRSEExpression', error.args[0]) except InvalidObject as error: return generate_http_error_flask(400, 'InvalidObject', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) else: def generate(vo): for rse in list_rses(vo=vo): yield render_json(**rse) + '\n' return try_stream(generate(vo=request.environ.get('vo')))
def get(self, rule_id): """ get history for a given rule_id. .. :quickref: RuleHistory; get rule history by id :resheader Content-Type: application/x-json-stream :status 200: Rule found :status 406: Not Acceptable :status 500: Database Exception :returns: JSON dict containing informations about the requested user. """ try: def generate(issuer, vo): for history in list_replication_rule_history(rule_id, issuer=issuer, vo=vo): yield render_json(**history) + '\n' return try_stream( generate(issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def post(self): """ List dataset replicas for multiple DIDs. .. :quickref: DatasetReplicas; List replicas for multiple DIDs. :<json list dids: List of DIDs for querying the datasets. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 400: Bad Request. :status 401: Invalid auth token. :status 406: Not Acceptable. :returns: A dictionary containing all replicas information. """ parameters = json_parameters(parse_response) dids = param_get(parameters, 'dids') if len(dids) == 0: return generate_http_error_flask(400, ValueError.__name__, 'List of DIDs is empty') try: def generate(vo): for row in list_dataset_replicas_bulk(dids=dids, vo=vo): yield dumps(row, cls=APIEncoder) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except InvalidObject as error: return generate_http_error_flask(400, error, f'Cannot validate DIDs: {error}')
def get(self): """ Return a summary of the bad replicas by incident. .. :quickref: BadReplicasSummary; List bad replicas by incident. :query rse_expression: The RSE expression. :query from_date: The start date. :query to_date: The end date. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 406: Not Acceptable. :returns: List of bad replicas by incident. """ rse_expression, from_date, to_date = None, None, None if request.query_string: query_string = request.query_string.decode(encoding='utf-8') try: params = loads(unquote(query_string)) except ValueError: params = parse_qs(query_string) if 'rse_expression' in params: rse_expression = params['rse_expression'][0] if 'from_date' in params and params['from_date'][0]: from_date = datetime.strptime(params['from_date'][0], "%Y-%m-%d") if 'to_date' in params: to_date = datetime.strptime(params['to_date'][0], "%Y-%m-%d") def generate(vo): for row in get_bad_replicas_summary(rse_expression=rse_expression, from_date=from_date, to_date=to_date, vo=vo): yield dumps(row, cls=APIEncoder) + '\n' return try_stream(generate(vo=request.environ.get('vo')))
def get(self, scope_name): """ Return all associated rules of a file. .. :quickref: AssociatedRules; List associated rules of DID. :resheader Content-Type: application/x-json-stream :param scope_name: data identifier (scope)/(name). :status 200: DID found :status 401: Invalid Auth Token :status 404: DID not found :status 406: Not Acceptable :returns: List of associated rules. """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for rule in list_associated_replication_rules_for_file(scope=scope, name=name, vo=vo): yield dumps(rule, cls=APIEncoder) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error) except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, scope_name): """ List all parents of a data identifier. .. :quickref: Parents; List parents of DID. :resheader Content-Type: application/x-json-stream :param scope_name: data identifier (scope)/(name). :status 200: DID found :status 401: Invalid Auth Token :status 404: DID not found :status 406: Not Acceptable. :returns: A list of dictionary containing all dataset information. """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for dataset in list_parent_dids(scope=scope, name=name, vo=vo): yield render_json(**dataset) + "\n" return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error) except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, scope_name): """ Returns the contents history of a data identifier. .. :quickref: AttachementHistory; List the content history of a DID. :resheader Content-Type: application/x-json-stream :param scope_name: data identifier (scope)/(name). :status 200: DID found :status 401: Invalid Auth Token :status 404: DID not found :status 406: Not Acceptable :returns: Stream of dictionarys with DIDs """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for did in list_content_history(scope=scope, name=name, vo=vo): yield render_json(**did) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error) except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, scope_name): """ List archive content keys. .. :quickref: Archive; list archive content keys. :param scope_name: data identifier (scope)/(name). :resheader Content-Type: application/x-json-stream :status 200: OK. :status 400: Invalid value. :status 406: Not Acceptable. :status 500: Internal Error. """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for file in list_archive_content(scope=scope, name=name, vo=vo): yield dumps(file) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, 'ValueError', error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def get(self, rse): """ Get RSE usage information. .. :quickref: Usage; Get RSE usage. :param rse: the RSE name. :query source: The information source, e.g., srm. :query per_account: Boolean whether the usage should be also calculated per account or not. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 404: RSE Not Found. :status 406: Not Acceptable. :status 500: Internal Error. :returns: A list of dictionaries with the usage information. """ try: def generate(issuer, source, per_account, vo): for usage in get_rse_usage(rse, issuer=issuer, source=source, per_account=per_account, vo=vo): yield render_json(**usage) + '\n' return try_stream(generate(issuer=request.environ.get('issuer'), source=request.args.get('source'), per_account=(request.args.get('per_account') == 'True'), vo=request.environ.get('vo'))) except RSENotFound as error: return generate_http_error_flask(404, 'RSENotFound', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: logging.exception("Internal Error") return str(error), 500
def get(self, account=None, name=None): """ Retrieve a subscription. .. :quickref: Subscription; Get subscriptions. :param account: The account name. :param name: The subscription name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 404: Subscription Not Found. :status 406: Not Acceptable. :returns: Line separated list of dictionaries with subscription information. """ try: def generate(vo): for subscription in list_subscriptions(name=name, account=account, vo=vo): yield render_json(**subscription) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except SubscriptionNotFound as error: return generate_http_error_flask(404, error)
def get(self): """ --- summary: Return all rules for a given account tags: - Rule responses: 200: description: OK content: application/json: schema: type: string 401: description: Invalid Auth Token 404: description: No rule found for the given id 406: description: Not Acceptable """ try: def generate(filters, vo): for rule in list_replication_rules(filters=filters, vo=vo): yield dumps(rule, cls=APIEncoder) + '\n' return try_stream( generate(filters=dict(request.args.items(multi=False)), vo=request.environ.get('vo'))) except RuleNotFound as error: return generate_http_error_flask(404, error)
def get(self, account, name=None): """ Return a summary of the states of all rules of a given subscription id. .. :quickref: States; Get subscription rule states. :param account: The account name. :param name: The subscription name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 406: Not Acceptable. :status 500: Internal Error. :returns: Line separated list of dictionaries with rule information. """ try: def generate(vo): for row in list_subscription_rule_states(account=account, vo=vo): yield dumps(row, cls=APIEncoder) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: logging.exception("Internal Error") return str(error), 500
def get(self, name=None): """ Retrieve a subscription by name. .. :quickref: SubscriptionName; Get subscriptions by name. :param name: The subscription name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 404: Subscription Not Found. :status 406: Not Acceptable. :status 500: Internal Error. :returns: Line separated list of dictionaries with subscription information. """ try: def generate(vo): for subscription in list_subscriptions(name=name, vo=vo): yield render_json(**subscription) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except SubscriptionNotFound as error: return generate_http_error_flask(404, 'SubscriptionNotFound', error.args[0]) except Exception as error: logging.exception("Internal Error") return str(error), 500
def get(self, scope_name): """ get history for a given DID. .. :quickref: RuleHistoryFull; get rule history for DID :resheader Content-Type: application/x-json-stream :param scope_name: data identifier (scope)/(name). :status 200: Rule found :status 406: Not Acceptable :status 500: Database Exception :returns: JSON dict containing informations about the requested user. """ try: scope, name = parse_scope_name(scope_name) def generate(vo): for history in list_replication_rule_full_history(scope, name, vo=vo): yield render_json(**history) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, 'ValueError', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def get(self, account): """ Return all rules of a given account. .. :quickref: Rules; Get rules for account. :param account: The account name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 404: Rule not found. :status 406: Not Acceptable. :returns: Line separated list of rules. """ filters = {'account': account} filters.update(request.args) try: def generate(vo): for rule in list_replication_rules(filters=filters, vo=vo): yield dumps(rule, cls=APIEncoder) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except RuleNotFound as error: return generate_http_error_flask(404, error)
def get(self, rse): """ Get RSE usage information. .. :quickref: UsageHistory; Get RSE usage history. :param rse: the RSE name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 404: RSE Not Found. :status 406: Not Acceptable. :status 500: Internal Error. :returns: Line separated list of dictionary with RSE usage information. """ try: def generate(issuer, source, vo): for usage in list_rse_usage_history(rse=rse, issuer=issuer, source=source, vo=vo): yield render_json(**usage) + '\n' return try_stream(generate(issuer=request.environ.get('issuer'), source=request.args.get('source'), vo=request.environ.get('vo'))) except RSENotFound as error: return generate_http_error_flask(404, 'RSENotFound', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: logging.exception("Internal Error") return str(error), 500
def get(self, account, rse_expression=None): """ Return the global account usage of the account. .. :quickref: GlobalUsage; Get global account usage. :param account: The account name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 404: Account not found. :status 404: RSE not found. :status 406: Not Acceptable. :returns: Line separated list of account usages. """ try: def generate(vo, issuer): for usage in get_global_account_usage( account=account, rse_expression=rse_expression, issuer=issuer, vo=vo): yield dumps(usage, cls=APIEncoder) + '\n' return try_stream( generate(vo=request.environ.get('vo'), issuer=request.environ.get('issuer'))) except (AccountNotFound, RSENotFound) as error: return generate_http_error_flask(404, error) except AccessDenied as error: return generate_http_error_flask(401, error)
def get(self): """ --- summary: List description: List all accounts. tags: - Account responses: 200: description: OK content: application/x-json-stream: schema: type: array items: type: object properties: account: description: The account identifier. type: string type: description: The type. type: string email: description: The email. type: string """ def generate(_filter, vo): for account in list_accounts(filter_=_filter, vo=vo): yield render_json(**account) + "\n" return try_stream( generate(_filter=dict(request.args.items(multi=False)), vo=request.environ.get('vo')))
def get(self): """ List all VOs. .. :quickref: VOs; List all VOs. :resheader Content-Type: application/x-json-stream :status 200: VOs found. :status 401: Invalid Auth Token. :status 409: Unsupported operation. :status 500: Internal Error. :returns: A list containing all VOs. """ try: def generate(issuer, vo): for vo in list_vos(issuer=issuer, vo=vo): yield render_json(**vo) + '\n' return try_stream( generate(issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))) except AccessDenied as error: return generate_http_error_flask(401, 'AccessDenied', error.args[0]) except UnsupportedOperation as error: return generate_http_error_flask(409, 'UnsupportedOperation', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def get(self, scope_name): """ get locks for a given scope, name. :param scope_name: data identifier (scope)/(name). :query did_type: The type used to filter, e.g., DATASET, CONTAINER. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid Auth Token. :status 406: Not Acceptable. :status 500: Internal Error. :returns: Line separated list of dictionary with lock information. """ did_type = request.args.get('did_type', None) try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) if did_type == 'dataset': def generate(vo): for lock in get_dataset_locks(scope, name, vo=vo): yield render_json(**lock) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) else: return 'Wrong did_type specified', 500 except ValueError as error: return generate_http_error_flask(400, 'ValueError', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def get(self, scope_name): """ List all replicas of a data identifier. .. :quickref: Files; List replicas of DID. :resheader Content-Type: application/x-json-stream :param scope_name: data identifier (scope)/(name). :query long: Flag to trigger long output :status 200: DID found :status 401: Invalid Auth Token :status 404: DID not found :status 406: Not Acceptable :returns: A dictionary containing all replicas information. """ long = 'long' in request.args try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for file in list_files(scope=scope, name=name, long=long, vo=vo): yield dumps(file) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error) except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, account): """ Get all identities mapped to an account. .. :quickref: Identities; Get account idenitity mapping. :resheader Content-Type: application/x-json-stream :param account: The account identifier. :status 200: OK. :status 401: Invalid auth token. :status 404: Account not found. :statsu 406: Not Acceptable. :status 500: Database exception :returns: Line separated dicts of identities. """ try: def generate(vo): for identity in list_identities(account, vo=vo): yield render_json(**identity) + "\n" return try_stream(generate(request.environ.get('vo'))) except AccountNotFound as error: return generate_http_error_flask(404, 'AccountNotFound', error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def post(self): """ List all meta of a list of data identifiers. .. :quickref: Meta; List metadata of multiple DIDs :resheader Content-Type: application/x-json-stream :status 200: OK :status 400: Bad Request :status 401: Unauthorized :status 404: DataIdentifierNotFound :returns: A list of dictionaries containing all meta. """ parameters = json_parameters() dids = param_get(parameters, 'dids') try: def generate(vo): for meta in get_metadata_bulk(dids, vo=vo): yield render_json(**meta) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error, 'Cannot decode json parameter list') except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, account, rse=None): """ Return the local account usage of the account. .. :quickref: LocalUsage; Get local account usage. :param account: The account name. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 404: Account not found. :status 404: RSE not found. :status 406: Not Acceptable. :status 500: Database exception. :returns: Line separated list of account usages. """ try: def generate(issuer, vo): for usage in get_local_account_usage(account=account, rse=rse, issuer=issuer, vo=vo): yield dumps(usage, cls=APIEncoder) + '\n' return try_stream(generate(issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))) except AccountNotFound as error: return generate_http_error_flask(404, 'AccountNotFound', error.args[0]) except AccessDenied as error: return generate_http_error_flask(401, 'AccessDenied', error.args[0]) except RSENotFound as error: return generate_http_error_flask(404, 'RSENotFound', error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def post(self): """ List the DIDs associated to a list of replicas. .. :quickref: ReplicasDIDs; List DIDs for replicas. :<json string pfns: The list of PFNs. :<json string rse: The RSE name. :resheader Content-Type: application/x-json-string :status 200: OK. :status 400: Cannot decode json parameter list. :status 406: Not Acceptable. :returns: A list of dictionaries containing the mapping PFNs to DIDs. """ parameters = json_parameters() pfns = param_get(parameters, 'pfns', default=[]) rse = param_get(parameters, 'rse') try: def generate(vo): for pfn in get_did_from_pfns(pfns, rse, vo=vo): yield dumps(pfn) + '\n' return try_stream(generate(vo=request.environ.get('vo'))) except AccessDenied as error: return generate_http_error_flask(401, error)
def get(self, rse): """ Get account usage and limit for one RSE. .. :quickref: RSEAccountUsageLimit; Get account usage. :param rse: the RSE name. :resheader Content-Type: application/json :status 200: OK. :status 401: Invalid Auth Token. :status 404: RSE Not Found. :status 406: Not Acceptable. :status 500: Internal Error. :returns: Line separated list of dict with account usage and limits. """ try: def generate(vo): for usage in get_rse_account_usage(rse=rse, vo=vo): yield render_json(**usage) + '\n' return try_stream(generate(vo=request.environ.get('vo')), content_type='application/json') except RSENotFound as error: return generate_http_error_flask(404, 'RSENotFound', error.args[0]) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0]) except Exception as error: print(format_exc()) return str(error), 500
def get(self, scope_name): """ List dataset replicas. .. :quickref: DatasetReplicas; List dataset replicas. :param scope_name: data identifier (scope)/(name). :query deep: Flag to ennable lookup at the file level. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 406: Not Acceptable. :returns: A dictionary containing all replicas information. """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(_deep, vo): for row in list_dataset_replicas(scope=scope, name=name, deep=_deep, vo=vo): yield dumps(row, cls=APIEncoder) + '\n' deep = request.args.get('deep', default=False) return try_stream(generate(_deep=deep, vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error)
def get(self, scope_name): """ Return all users following a specific DID. .. :quickref: Follow; List users following DID. :status 200: OK :status 400: ValueError :status 401: Unauthorized :status 404: DataIdentifierNotFound :status 406: Not Acceptable """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(vo): for user in get_users_following_did(scope=scope, name=name, vo=vo): yield render_json(**user) + '\n' return try_stream(generate(vo=request.environ.get('vo')), content_type='application/json') except ValueError as error: return generate_http_error_flask(400, error) except DataIdentifierNotFound as error: return generate_http_error_flask(404, error)
def get(self, scope_name): """ List dataset replicas using the Virtual Placement service. NOTICE: This is an RnD function and might change or go away at any time. .. :quickref: DatasetReplicas; List dataset replicas with VP. :param scope_name: data identifier (scope)/(name). :query deep: Flag to ennable lookup at the file level. :resheader Content-Type: application/x-json-stream :status 200: OK. :status 401: Invalid auth token. :status 406: Not Acceptable. :returns: If VP exists a list of dicts of sites, otherwise nothing """ try: scope, name = parse_scope_name(scope_name, request.environ.get('vo')) def generate(_deep, vo): for row in list_dataset_replicas_vp(scope=scope, name=name, deep=_deep, vo=vo): yield dumps(row, cls=APIEncoder) + '\n' deep = request.args.get('deep', default=False) return try_stream(generate(_deep=deep, vo=request.environ.get('vo'))) except ValueError as error: return generate_http_error_flask(400, error)
def get(self): """ Return all rules of a given account. .. :quickref: AllRule; get all rules for account :resheader Content-Type: application/x-json-stream :status 200: Rule found :status 401: Invalid Auth Token :status 404: no rule found for id :status 406: Not Acceptable :query scope: The scope name. """ try: def generate(filters, vo): for rule in list_replication_rules(filters=filters, vo=vo): yield dumps(rule, cls=APIEncoder) + '\n' return try_stream( generate(filters=dict(request.args.items(multi=False)), vo=request.environ.get('vo'))) except RuleNotFound as error: return generate_http_error_flask(404, 'RuleNotFound', error.args[0]) except Exception as error: print(format_exc()) return str(error), 500