-
Notifications
You must be signed in to change notification settings - Fork 33
Update wmcore_transferor global and local quotas dynamically #914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
haozturk
wants to merge
3
commits into
dmwm:master
Choose a base branch
from
haozturk:update_wmcore_transferor_quotas
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #! /usr/bin/env python3 | ||
|
|
||
| from rucio.client import Client | ||
|
|
||
| client = Client() | ||
|
|
||
| def get_sum_of_all_rse_statics(rse_expression): | ||
| rses = [rse["rse"] for rse in client.list_rses(rse_expression=rse_expression)] | ||
| result = 0 | ||
| for rse in rses: | ||
| static, _, _ = get_rse_usage(rse) | ||
| result += static | ||
| return result | ||
|
|
||
|
|
||
| def get_rse_usage(rse): | ||
| rse_usage = list(client.get_rse_usage(rse)) | ||
|
|
||
| required_fields = {"static", "rucio", "expired"} | ||
| relevant_info = {} | ||
|
|
||
| for source in rse_usage: | ||
| # Assuming source and used keys exist | ||
| relevant_info[source["source"]] = source["used"] | ||
|
|
||
| if not required_fields.issubset(relevant_info.keys()): | ||
| print("Skipping {} due to lack of relevant key in rse".format(rse)) | ||
| print("{} is not a subset of {}".format(required_fields, relevant_info.keys())) | ||
| return 0, 0, 0 | ||
|
|
||
| # Apparently, python integers do not overflow, https://docs.python.org/3/library/exceptions.html#OverflowError | ||
|
|
||
| static, rucio, expired = relevant_info["static"], relevant_info["rucio"], relevant_info["expired"] | ||
| return static, rucio, expired |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| #! /usr/bin/env python3 | ||
| """ | ||
| Script to update the global and the local quotas of the wmcore_transferor account. | ||
| Its global quota is set to X % of total disk capacity of T1 and T2 sites used in production | ||
| Its local quota is Y % of an RSE's (free + expired) space. | ||
| Global quota is introduced to have a global control on the usage of this account. | ||
| Local quotas are introduced to avoid the over-usage of certain RSEs. | ||
| """ | ||
|
|
||
| from rucio.client import Client | ||
| from rseUsageMetrics import get_rse_usage, get_sum_of_all_rse_statics | ||
|
|
||
| DEFAULT_GLOBAL_QUOTA_PCT = 15 | ||
| DEFAULT_LOCAL_QUOTA_PCT = 50 | ||
| DRY_RUN = False | ||
|
|
||
| client = Client() | ||
| account = "wmcore_transferor" | ||
| rse_expression = "rse_type=DISK&cms_type=real&tier<3&tier>0" | ||
|
|
||
| def get_global_quota_pct(): | ||
| try: | ||
| global_quota_pct = int(client.get_config(section="accounts", option="wmcore_transferor_global_quota_pct")) | ||
| except Exception as e: | ||
| global_quota_pct = DEFAULT_GLOBAL_QUOTA_PCT | ||
| return global_quota_pct | ||
|
|
||
| def get_local_quota_pct(): | ||
| try: | ||
| local_quota_pct = int(client.get_config(section="accounts", option="wmcore_transferor_local_quota_pct")) | ||
| except Exception as e: | ||
| local_quota_pct = DEFAULT_LOCAL_QUOTA_PCT | ||
| return local_quota_pct | ||
|
|
||
|
|
||
| def set_global_quota(): | ||
|
|
||
| total_disk_capacity = get_sum_of_all_rse_statics(rse_expression) | ||
| global_quota_pct = get_global_quota_pct() | ||
| global_quota_bytes = (total_disk_capacity * global_quota_pct) / 100 | ||
| if DRY_RUN: | ||
| print(f"DRY-RUN: Setting global quota of wmcore_transferor to {global_quota_bytes / 1e15} PB") | ||
| else: | ||
| print(f"Setting global quota of wmcore_transferor to {global_quota_bytes / 1e15} PB") | ||
| set_global_account_limit(account, rse_expression, global_quota_bytes) | ||
|
|
||
| def set_local_quotas(): | ||
|
|
||
| rses = [rse["rse"] for rse in client.list_rses(rse_expression=rse_expression)] | ||
| local_quota_pct = get_local_quota_pct() | ||
|
|
||
| for rse in rses: | ||
| static, rucio, expired = get_rse_usage(rse) | ||
| free = static - rucio | ||
|
|
||
| # Set it to 0 if it's negative | ||
| local_quota_bytes = max((((free + expired) * local_quota_pct) / 100), 0) | ||
| if DRY_RUN: | ||
| print(f"DRY-RUN: Setting local quota of wmcore_transferor at {rse} to {local_quota_bytes / 1e12} TB") | ||
| else: | ||
| print(f"Setting local quota of wmcore_transferor at {rse} to {local_quota_bytes / 1e12} TB") | ||
| set_local_account_limit(account, rse, local_quota_bytes) | ||
|
|
||
|
|
||
| def main(): | ||
| set_global_quota() | ||
| set_local_quotas() | ||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @amaltaro the global limit can be get by either [1] or [2]. Global limit means a limit across multiple RSEs. Rucio allows multiple global limits, so if you use [2], you will get an iterable object instead of a single value. We'll introduce only one global limit, which will be over this RSE expression.
I can't think of any reason why this RSE expression might change in the future or we can have multiple global limits with different RSE expressions, but since the system allows it, making your system rely on a configuration that can essentially change isn't a good idea in my opinion. Probably the best is not to touch MSTransferor and let it fail and retry. It will fail with a distinct error message [3] and the operator looking into the logs will know what's going on. (If s/he misses the alerts)
[1] https://rucio.github.io/documentation/html/client_api/accountclient.html#rucio.client.accountclient.AccountClient.get_global_account_limit
[2] https://rucio.github.io/documentation/html/client_api/accountclient.html#rucio.client.accountclient.AccountClient.get_global_account_limits
[3]