diff options
7 files changed, 141 insertions, 55 deletions
diff --git a/robusta_krr/core/models/result.py b/robusta_krr/core/models/result.py index d4e042f..46512bb 100644 --- a/robusta_krr/core/models/result.py +++ b/robusta_krr/core/models/result.py @@ -1,6 +1,5 @@ from __future__ import annotations -import enum from datetime import datetime from typing import Any, Optional, Union @@ -9,60 +8,7 @@ import pydantic as pd from robusta_krr.core.abstract.formatters import BaseFormatter from robusta_krr.core.models.allocations import RecommendationValue, ResourceAllocations, ResourceType from robusta_krr.core.models.objects import K8sObjectData - - -class Severity(str, enum.Enum): - """The severity of the scan.""" - - UNKNOWN = "UNKNOWN" - GOOD = "GOOD" - OK = "OK" - WARNING = "WARNING" - CRITICAL = "CRITICAL" - - @property - def color(self) -> str: - return { - self.UNKNOWN: "dim", - self.GOOD: "green", - self.OK: "gray", - self.WARNING: "yellow", - self.CRITICAL: "red", - }[self] - - @classmethod - def calculate( - cls, current: RecommendationValue, recommended: RecommendationValue, resource_type: ResourceType - ) -> Severity: - if isinstance(recommended, str) or isinstance(current, str): - return cls.UNKNOWN - - if current is None and recommended is None: - return cls.GOOD - if current is None or recommended is None: - return cls.WARNING - - diff = abs(current - recommended) - - if resource_type == ResourceType.CPU: - if diff >= 0.5: - return cls.CRITICAL - elif diff >= 0.25: - return cls.WARNING - elif diff >= 0.1: - return cls.OK - else: - return cls.GOOD - else: - diff_megabytes = diff / 1024 / 1024 - if diff_megabytes >= 500: - return cls.CRITICAL - elif diff_megabytes >= 250: - return cls.WARNING - elif diff_megabytes >= 100: - return cls.OK - else: - return cls.GOOD +from robusta_krr.core.models.severity import Severity class Recommendation(pd.BaseModel): diff --git a/robusta_krr/core/models/severity.py b/robusta_krr/core/models/severity.py new file mode 100644 index 0000000..cbe45a2 --- /dev/null +++ b/robusta_krr/core/models/severity.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import enum + +from robusta_krr.core.models.allocations import RecommendationValue, ResourceType + + +class Severity(str, enum.Enum): + """The severity of the scan.""" + + UNKNOWN = "UNKNOWN" + GOOD = "GOOD" + OK = "OK" + WARNING = "WARNING" + CRITICAL = "CRITICAL" + + @property + def color(self) -> str: + return { + self.UNKNOWN: "dim", + self.GOOD: "green", + self.OK: "gray", + self.WARNING: "yellow", + self.CRITICAL: "red", + }[self] + + @classmethod + def calculate( + cls, current: RecommendationValue, recommended: RecommendationValue, resource_type: ResourceType + ) -> Severity: + from robusta_krr.core.models.severity_calculator import BaseSeverityCalculator + + if isinstance(recommended, str) or isinstance(current, str): + return cls.UNKNOWN + + return BaseSeverityCalculator.get_by_resource(resource_type).calculate(current, recommended) diff --git a/robusta_krr/core/models/severity_calculator/__init__.py b/robusta_krr/core/models/severity_calculator/__init__.py new file mode 100644 index 0000000..edaafd7 --- /dev/null +++ b/robusta_krr/core/models/severity_calculator/__init__.py @@ -0,0 +1,4 @@ +from .base_calculator import BaseSeverityCalculator, bind_calculator +from .cpu_calculator import CPUSeverityCalculator +from .default_calculator import DefaultSeverityCalculator +from .memory_calculator import MemorySeverityCalculator diff --git a/robusta_krr/core/models/severity_calculator/base_calculator.py b/robusta_krr/core/models/severity_calculator/base_calculator.py new file mode 100644 index 0000000..832b5a5 --- /dev/null +++ b/robusta_krr/core/models/severity_calculator/base_calculator.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import abc +from typing import Callable, Optional, TypeVar + +from robusta_krr.core.models.allocations import ResourceType +from robusta_krr.core.models.severity import Severity + + +class BaseSeverityCalculator(abc.ABC): + # Is here as we are creating this object in get_by_resource method, so it can not have any arguments + def __init__(self) -> None: + ... + + @abc.abstractmethod + def calculate(self, current: Optional[float], recommended: Optional[float]) -> Severity: + ... + + @staticmethod + def get_by_resource(resource: ResourceType) -> BaseSeverityCalculator: + from robusta_krr.core.models.severity_calculator.default_calculator import DefaultSeverityCalculator + + return SEVERITY_CALCULATORS_MAP.get(resource, DefaultSeverityCalculator)() + + +Self = TypeVar("Self", bound=BaseSeverityCalculator) +SEVERITY_CALCULATORS_MAP: dict[ResourceType, type[BaseSeverityCalculator]] = {} + + +def bind_calculator(resource_type: ResourceType) -> Callable[[type[Self]], type[Self]]: + def decorator(cls: type[Self]) -> type[Self]: + SEVERITY_CALCULATORS_MAP[resource_type] = cls + return cls + + return decorator diff --git a/robusta_krr/core/models/severity_calculator/cpu_calculator.py b/robusta_krr/core/models/severity_calculator/cpu_calculator.py new file mode 100644 index 0000000..965adec --- /dev/null +++ b/robusta_krr/core/models/severity_calculator/cpu_calculator.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Optional + +from robusta_krr.core.models.allocations import ResourceType +from robusta_krr.core.models.severity import Severity +from robusta_krr.core.models.severity_calculator.base_calculator import BaseSeverityCalculator, bind_calculator + + +@bind_calculator(ResourceType.CPU) +class CPUSeverityCalculator(BaseSeverityCalculator): + def calculate(self, current: Optional[float], recommended: Optional[float]) -> Severity: + if current is None and recommended is None: + return Severity.GOOD + if current is None or recommended is None: + return Severity.WARNING + + diff = abs(current - recommended) + + if diff >= 0.5: + return Severity.CRITICAL + elif diff >= 0.25: + return Severity.WARNING + elif diff >= 0.1: + return Severity.OK + else: + return Severity.GOOD diff --git a/robusta_krr/core/models/severity_calculator/default_calculator.py b/robusta_krr/core/models/severity_calculator/default_calculator.py new file mode 100644 index 0000000..adcb4af --- /dev/null +++ b/robusta_krr/core/models/severity_calculator/default_calculator.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +from typing import Optional + +from robusta_krr.core.models.severity import Severity +from robusta_krr.core.models.severity_calculator.base_calculator import BaseSeverityCalculator + + +class DefaultSeverityCalculator(BaseSeverityCalculator): + def calculate(self, current: Optional[float], recommended: Optional[float]) -> Severity: + return Severity.UNKNOWN diff --git a/robusta_krr/core/models/severity_calculator/memory_calculator.py b/robusta_krr/core/models/severity_calculator/memory_calculator.py new file mode 100644 index 0000000..5948949 --- /dev/null +++ b/robusta_krr/core/models/severity_calculator/memory_calculator.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Optional + +from robusta_krr.core.models.allocations import ResourceType +from robusta_krr.core.models.severity import Severity +from robusta_krr.core.models.severity_calculator.base_calculator import BaseSeverityCalculator, bind_calculator + + +@bind_calculator(ResourceType.Memory) +class MemorySeverityCalculator(BaseSeverityCalculator): + def calculate(self, current: Optional[float], recommended: Optional[float]) -> Severity: + if current is None and recommended is None: + return Severity.GOOD + if current is None or recommended is None: + return Severity.WARNING + + diff = abs(current - recommended) / 1024 / 1024 + + if diff >= 500: + return Severity.CRITICAL + elif diff >= 250: + return Severity.WARNING + elif diff >= 100: + return Severity.OK + else: + return Severity.GOOD |
