Skip to content

Commit

Permalink
fix: fix yearly unified cost bug
Browse files Browse the repository at this point in the history
Signed-off-by: ImMin5 <[email protected]>
  • Loading branch information
ImMin5 committed Nov 15, 2024
1 parent 04d2cb2 commit 2ba4426
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 1 deletion.
103 changes: 103 additions & 0 deletions src/spaceone/cost_analysis/manager/unified_cost_manager.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import logging
from datetime import datetime
from typing import Tuple, Union

from dateutil.relativedelta import relativedelta
from mongoengine import QuerySet

from spaceone.core import queue, utils, config
from spaceone.core.error import *
from spaceone.core.manager import BaseManager

from spaceone.cost_analysis.error import ERROR_INVALID_DATE_RANGE
from spaceone.cost_analysis.model.unified_cost.database import UnifiedCost

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -64,6 +70,29 @@ def analyze_unified_costs(self, query: dict, target="SECONDARY_PREFERRED") -> di

return self.unified_cost_model.analyze(**query)

def analyze_yearly_unified_costs(self, query, target="SECONDARY_PREFERRED"):
query["target"] = target
query["date_field"] = "billed_year"
query["date_field_format"] = "%Y"
_LOGGER.debug(f"[analyze_yearly_unified_costs] query: {query}")

return self.unified_cost_model.analyze(**query)

def analyze_unified_costs_by_granularity(self, query: dict) -> dict:
granularity = query["granularity"]
self._check_unified_cost_data_range(query)

if granularity == "DAILY":
raise ERROR_INVALID_PARAMETER(
key="query.granularity", reason=f"{granularity} is not supported"
)
elif granularity == "MONTHLY":
response = self.analyze_unified_costs(query)
else:
response = self.analyze_yearly_unified_costs(query)

return response

def stat_unified_costs(self, query) -> dict:
return self.unified_cost_model.stat(**query)

Expand Down Expand Up @@ -103,3 +132,77 @@ def get_exchange_currency(cost: float, currency: str, currency_map: dict) -> dic
)

return cost_info

def _check_unified_cost_data_range(self, query: dict):
start_str = query.get("start")
end_str = query.get("end")
granularity = query.get("granularity")

start = self._parse_start_time(start_str, granularity)
end = self._parse_end_time(end_str, granularity)
now = datetime.utcnow().date()

if len(start_str) != len(end_str):
raise ERROR_INVALID_DATE_RANGE(
start=start_str,
end=end_str,
reason="Start date and end date must be the same format.",
)

if start >= end:
raise ERROR_INVALID_DATE_RANGE(
start=start_str,
end=end_str,
reason="End date must be greater than start date.",
)

if granularity == "MONTHLY":
if start + relativedelta(months=24) < end:
raise ERROR_INVALID_DATE_RANGE(
start=start_str,
end=end_str,
reason="Request up to a maximum of 12 months.",
)

if start + relativedelta(months=48) < now.replace(day=1):
raise ERROR_INVALID_DATE_RANGE(
start=start_str,
end=end_str,
reason="For MONTHLY, you cannot request data older than 3 years.",
)
elif granularity == "YEARLY":
if start + relativedelta(years=5) < now.replace(month=1, day=1):
raise ERROR_INVALID_DATE_RANGE(
start=start_str,
end=end_str,
reason="For YEARLY, you cannot request data older than 3 years.",
)

@staticmethod
def _convert_date_from_string(date_str, key, granularity):
if granularity == "YEARLY":
date_format = "%Y"
date_type = "YYYY"
else:
if len(date_str) == 4:
date_format = "%Y"
date_type = "YYYY"
else:
date_format = "%Y-%m"
date_type = "YYYY-MM"

try:
return datetime.strptime(date_str, date_format).date()
except Exception as e:
raise ERROR_INVALID_PARAMETER_TYPE(key=key, type=date_type)

def _parse_start_time(self, date_str, granularity):
return self._convert_date_from_string(date_str.strip(), "start", granularity)

def _parse_end_time(self, date_str, granularity):
end = self._convert_date_from_string(date_str.strip(), "end", granularity)

if granularity == "YEARLY":
return end + relativedelta(years=1)
else:
return end + relativedelta(months=1)
2 changes: 1 addition & 1 deletion src/spaceone/cost_analysis/service/unified_cost_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def analyze(self, params: UnifiedCostAnalyzeQueryRequest) -> dict:

query = params.query or {}

return self.unified_cost_mgr.analyze_unified_costs(query)
return self.unified_cost_mgr.analyze_unified_costs_by_granularity(query)

@transaction(
permission="cost-analysis:UnifiedCost.read",
Expand Down

0 comments on commit 2ba4426

Please sign in to comment.