Skip to content

Commit

Permalink
Merge pull request #122 from ImMin5/master
Browse files Browse the repository at this point in the history
Modify and fix error budget usage apis
  • Loading branch information
ImMin5 authored Dec 25, 2023
2 parents 25560f7 + 51aff00 commit d04c030
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 35 deletions.
62 changes: 36 additions & 26 deletions src/spaceone/cost_analysis/manager/budget_usage_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,27 +86,25 @@ def _rollback(old_data):
self.transaction.add_rollback(_rollback, budget_usage_vo.to_dict())
return budget_usage_vo.update(params)

def update_cost_usage(self, budget_id: str, workspace_id: str, domain_id: str):
_LOGGER.info(f"[update_cost_usage] Update Budget Usage: {budget_id}")
def update_cost_usage(
self,
budget_vo: Budget,
data_source_workspace_id: str,
):
_LOGGER.info(f"[update_cost_usage] Update Budget Usage: {budget_vo.budget_id}")
cost_mgr: CostManager = self.locator.get_manager("CostManager")

budget_vo = self.budget_mgr.get_budget(
budget_id=budget_id, domain_id=domain_id, workspace_id=workspace_id
)
self._update_monthly_budget_usage(budget_vo, cost_mgr)
self._update_monthly_budget_usage(budget_vo, cost_mgr, data_source_workspace_id)

def update_budget_usage(
self, domain_id: str, workspace_id: str, data_source_id: str
self, domain_id: str, workspace_id: str, data_source_id: str
):
budget_vos = self.budget_mgr.filter_budgets(
domain_id=domain_id,
workspace_id=workspace_id,
data_source_id=data_source_id,
)
for budget_vo in budget_vos:
self.update_cost_usage(
budget_vo.budget_id, budget_vo.workspace_id, domain_id
)
self.update_cost_usage(budget_vo, data_source_workspace_id=workspace_id)
self.notify_budget_usage(budget_vo)

def notify_budget_usage(self, budget_vo: Budget):
Expand Down Expand Up @@ -182,7 +180,7 @@ def notify_budget_usage(self, budget_vo: Budget):
"unit": unit,
"notification_type": notification_type,
"notified_months": notification.notified_months
+ [current_month],
+ [current_month],
}
)
except Exception as e:
Expand Down Expand Up @@ -210,22 +208,25 @@ def notify_budget_usage(self, budget_vo: Budget):
budget_vo.update({"notifications": updated_notifications})

def _notify_message(
self,
budget_vo: Budget,
current_month,
total_budget_usage,
budget_limit,
budget_percentage,
threshold,
unit,
notification_type,
self,
budget_vo: Budget,
current_month,
total_budget_usage,
budget_limit,
budget_percentage,
threshold,
unit,
notification_type,
):
data_source_name = self.data_source_mgr.get_data_source(
budget_vo.data_source_id, budget_vo.domain_id
).name
project_name = self.identity_mgr.get_project_name(
budget_vo.project_id, budget_vo.workspace_id, budget_vo.domain_id
)
workspace_name = self.identity_mgr.get_workspace_name_with_system_token(
budget_vo.workspace_id, budget_vo.domain_id
)

if unit == "PERCENT":
threshold_str = f"{int(threshold)}%"
Expand Down Expand Up @@ -277,10 +278,15 @@ def _notify_message(
"key": "Project",
"value": project_name,
},
{
"key": "Workspace",
"value": workspace_name,
},
],
"occurred_at": utils.datetime_to_iso8601(datetime.utcnow()),
},
"notification_level": "ALL",
"workspace_id": budget_vo.workspace_id,
"domain_id": budget_vo.domain_id,
}

Expand All @@ -300,9 +306,13 @@ def analyze_budget_usages(self, query):
query["date_field_format"] = "%Y-%m"
return self.budget_usage_model.analyze(**query)

def _update_monthly_budget_usage(self, budget_vo: Budget, cost_mgr: CostManager):
def _update_monthly_budget_usage(
self, budget_vo: Budget, cost_mgr: CostManager, data_source_workspace_id: str
):
update_data = {}
query = self._make_cost_analyze_query(budget_vo)
query = self._make_cost_analyze_query(
budget_vo=budget_vo, workspace_id=data_source_workspace_id
)
_LOGGER.debug(f"[_update_monthly_budget_usage]: query: {query}")

result = cost_mgr.analyze_costs_by_granularity(
Expand All @@ -319,15 +329,15 @@ def _update_monthly_budget_usage(self, budget_vo: Budget, cost_mgr: CostManager)
else:
budget_usage_vo.update({"cost": 0})

def _make_cost_analyze_query(self, budget_vo: Budget):
def _make_cost_analyze_query(self, budget_vo: Budget, workspace_id: str):
query = {
"granularity": "MONTHLY",
"start": budget_vo.start,
"end": budget_vo.end,
"fields": {"cost": {"key": "cost", "operator": "sum"}},
"filter": [
{"k": "domain_id", "v": budget_vo.domain_id, "o": "eq"},
{"k": "workspace_id", "v": budget_vo.workspace_id, "o": "eq"},
{"k": "workspace_id", "v": workspace_id, "o": "eq"},
{"k": "data_source_id", "v": budget_vo.data_source_id, "o": "eq"},
],
}
Expand All @@ -348,7 +358,7 @@ def _make_cost_analyze_query(self, budget_vo: Budget):
}
projects_info = identity_mgr.list_projects(project_query)

project_ids = []
project_ids = ["*"]
for project_info in projects_info.get("results", []):
project_ids.append(project_info["project_id"])

Expand Down
15 changes: 15 additions & 0 deletions src/spaceone/cost_analysis/manager/identity_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ def check_workspace(self, workspace_id: str, domain_id: str) -> None:
{"workspace_id": workspace_id, "domain_id": domain_id},
)

@cache.cacheable(key="workspace-name:{domain_id}:{workspace_id}:name", expire=300)
def get_workspace_name_with_system_token(
self, workspace_id: str, domain_id: str
) -> str:
try:
workspace_info = self.identity_conn.dispatch(
"Workspace.get",
{"workspace_id": workspace_id},
x_domain_id=domain_id,
)
return workspace_info["name"]
except Exception as e:
_LOGGER.error(f"[get_project_name] API Error: {e}")
return workspace_id

def get_workspace(self, workspace_id: str) -> dict:
token = self.transaction.get_meta("token")
return self.identity_conn.dispatch(
Expand Down
10 changes: 6 additions & 4 deletions src/spaceone/cost_analysis/service/budget_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ def create(self, params):
)
budget_usage_mgr.create_budget_usages(budget_vo)
budget_usage_mgr.update_cost_usage(
budget_vo.budget_id,
budget_vo.workspace_id,
budget_vo.domain_id,
budget_vo=budget_vo, data_source_workspace_id=data_source_vo.workspace_id
)
budget_usage_mgr.notify_budget_usage(budget_vo)

Expand Down Expand Up @@ -210,9 +208,13 @@ def update(self, params):
budget_usage_mgr.update_budget_usage_by_vo(
{"name": params["name"]}, budget_usage_vo
)
data_source_mgr = self.locator.get_manager("DataSourceManager")
data_source_vo = data_source_mgr.get_data_source(
budget_vo.data_source_id, domain_id
)

budget_usage_mgr.update_cost_usage(
budget_vo.budget_id, budget_vo.workspace_id, budget_vo.domain_id
budget_vo=budget_vo, data_source_workspace_id=data_source_vo.workspace_id
)
budget_usage_mgr.notify_budget_usage(budget_vo)

Expand Down
18 changes: 14 additions & 4 deletions src/spaceone/cost_analysis/service/cost_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ def delete(self, params):
Args:
params (dict): {
'cost_id': 'str',
'domain_id': 'str'
'cost_id': 'str', # injected from path
'workspace_id' : str', # injected from auth(optional)
'domain_id': 'str' # injected from auth
}
Returns:
Expand All @@ -79,9 +80,17 @@ def delete(self, params):

domain_id = params["domain_id"]

cost_vo: Cost = self.cost_mgr.get_cost(params["cost_id"], params["domain_id"])
cost_vo: Cost = self.cost_mgr.get_cost(
params["cost_id"],
params["domain_id"],
params.get("workspace_id"),
)

self.cost_mgr.remove_stat_cache(domain_id, cost_vo.data_source_id)
self.cost_mgr.remove_stat_cache(
domain_id=domain_id,
data_source_id=cost_vo.data_source_id,
workspace_id=cost_vo.workspace_id,
)

self.cost_mgr.delete_cost_by_vo(cost_vo)

Expand Down Expand Up @@ -169,6 +178,7 @@ def list(self, params):
permission="cost-analysis:Cost.read",
role_types=["DOMAIN_ADMIN", "WORKSPACE_OWNER", "WORKSPACE_MEMBER"],
)
@change_value_by_rule("APPEND", "workspace_id", "*")
@check_required(
[
"query",
Expand Down
2 changes: 1 addition & 1 deletion src/spaceone/cost_analysis/service/data_source_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def deregister(self, params):
params (dict): {
'data_source_id': 'str', # required
'cascade_delete_cost: 'bool',
'workspace_id: 'str', # required
'workspace_id: 'str', # injected from auth (optional)
'domain_id': 'str' # injected from auth
}
Expand Down

0 comments on commit d04c030

Please sign in to comment.