Skip to content

Commit

Permalink
models: provide human readable quota usage
Browse files Browse the repository at this point in the history
  • Loading branch information
Diego Rodriguez committed Oct 15, 2020
1 parent 0872447 commit f43268a
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
51 changes: 51 additions & 0 deletions reana_db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from __future__ import absolute_import

import enum
import math
import uuid
from datetime import datetime

Expand Down Expand Up @@ -145,14 +146,19 @@ def _get_health_status(usage, limit):

quota_usage = 0
quota_limit = 0
quota_human_readable_usage = ""
for user_resource in self.resources:
if user_resource.resource.type_ == resource_type:
quota_usage += user_resource.quota_used
quota_limit += user_resource.quota_limit
quota_human_readable_usage = ResourceUnit.human_readable_unit(
user_resource.resource.unit, user_resource.quota_used
)

return {
"usage": quota_usage,
"limit": quota_limit,
"human_readable_usage": quota_human_readable_usage,
"health": _get_health_status(quota_usage, quota_limit),
}

Expand Down Expand Up @@ -638,6 +644,51 @@ class ResourceUnit(enum.Enum):
bytes_ = 0
milliseconds = 1

@staticmethod
def _human_readable_milliseconds(milliseconds):
"""Convert bytes usage to human readable string."""
hours, minutes, seconds = (
milliseconds // (1000 * 60 * 60),
(milliseconds // (1000 * 60)) % 60,
(milliseconds // 1000) % 60,
)

human_readable_milliseconds = ""
for value, unit in [(hours, "h"), (minutes, "m"), (seconds, "s")]:
if value >= 1:
human_readable_milliseconds += "{value}{unit} ".format(
value=value, unit=unit
)

return human_readable_milliseconds.strip() or "0s"

@staticmethod
def _human_readable_bytes(bytes_):
"""Convert bytes usage to human readable string."""
if bytes_ == 0:
return "0 Bytes"
units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
digits = 2
k = 1024
unit_index = math.floor(math.log(bytes_) / math.log(k))

converted_value = round(bytes_ / math.pow(k, unit_index), digits)
return "{converted_value} {converted_unit}".format(
converted_value=int(converted_value)
if converted_value.is_integer()
else converted_value,
converted_unit=units[unit_index],
)

@staticmethod
def human_readable_unit(unit, value):
"""Convert passed value in units to human readable string."""
convert_to_human_readable = {
ResourceUnit.bytes_: ResourceUnit._human_readable_bytes,
ResourceUnit.milliseconds: ResourceUnit._human_readable_milliseconds,
}
return convert_to_human_readable[unit](value)


class Resource(Base, Timestamp):
"""Resource table."""
Expand Down
30 changes: 30 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ALLOWED_WORKFLOW_STATUS_TRANSITIONS,
AuditLogAction,
Resource,
ResourceUnit,
UserTokenStatus,
UserTokenType,
Workflow,
Expand Down Expand Up @@ -222,3 +223,32 @@ def test_user_cpu_usage(db, session, new_user, run_workflow):
>= num_workflows * time_elapsed_seconds * 1000
)
assert new_user.get_quota_usage()["disk"]["usage"] == 128


@pytest.mark.parametrize(
"unit, value, human_readable_string",
[
# Milliseconds VS human readable
(ResourceUnit.milliseconds, 0, "0s"),
(ResourceUnit.milliseconds, 1000 * 35, "35s"),
(ResourceUnit.milliseconds, 1000 * 60 * 7 + 1000 * 40, "7m 40s"),
(ResourceUnit.milliseconds, 1000 * 60 * 60 * 2, "2h"),
(ResourceUnit.milliseconds, 1000 * 60 * 60 * 2 + 1000 * 60 * 20, "2h 20m"),
(
ResourceUnit.milliseconds,
1000 * 60 * 60 * 2 + 1000 * 60 * 35 + 1000 * 10,
"2h 35m 10s",
),
# Bytes VS human readable
(ResourceUnit.bytes_, 0, "0 Bytes"),
(ResourceUnit.bytes_, 1024 * 35, "35 KB"),
(ResourceUnit.bytes_, 1024 * 200 + 512, "200.5 KB"),
(ResourceUnit.bytes_, 1024 ** 2, "1 MB"),
(ResourceUnit.bytes_, 1024 ** 2 + 1024 * 768, "1.75 MB"),
(ResourceUnit.bytes_, 1024 ** 3 * 5 + 1024 ** 2 * 100, "5.1 GB"),
(ResourceUnit.bytes_, 1024 ** 4 + 1024 ** 3 * 256, "1.25 TB"),
],
)
def test_human_readable_unit_values(unit, value, human_readable_string):
"""Test converting units from canonical values to ."""
assert ResourceUnit.human_readable_unit(unit, value) == human_readable_string

0 comments on commit f43268a

Please sign in to comment.