diff --git a/src/spaceone/cost_analysis/manager/budget_usage_manager.py b/src/spaceone/cost_analysis/manager/budget_usage_manager.py index 93a294af..1ef7eedf 100644 --- a/src/spaceone/cost_analysis/manager/budget_usage_manager.py +++ b/src/spaceone/cost_analysis/manager/budget_usage_manager.py @@ -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): @@ -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: @@ -210,15 +208,15 @@ 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 @@ -226,6 +224,9 @@ def _notify_message( 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)}%" @@ -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, } @@ -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( @@ -319,7 +329,7 @@ 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, @@ -327,7 +337,7 @@ def _make_cost_analyze_query(self, budget_vo: Budget): "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"}, ], } @@ -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"]) diff --git a/src/spaceone/cost_analysis/manager/identity_manager.py b/src/spaceone/cost_analysis/manager/identity_manager.py index a09f484f..ab181b11 100644 --- a/src/spaceone/cost_analysis/manager/identity_manager.py +++ b/src/spaceone/cost_analysis/manager/identity_manager.py @@ -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( diff --git a/src/spaceone/cost_analysis/service/budget_service.py b/src/spaceone/cost_analysis/service/budget_service.py index 9a326642..7a4dbd1c 100644 --- a/src/spaceone/cost_analysis/service/budget_service.py +++ b/src/spaceone/cost_analysis/service/budget_service.py @@ -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) @@ -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) diff --git a/src/spaceone/cost_analysis/service/cost_service.py b/src/spaceone/cost_analysis/service/cost_service.py index 3272edf4..8f226fa1 100644 --- a/src/spaceone/cost_analysis/service/cost_service.py +++ b/src/spaceone/cost_analysis/service/cost_service.py @@ -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: @@ -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) @@ -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", diff --git a/src/spaceone/cost_analysis/service/data_source_service.py b/src/spaceone/cost_analysis/service/data_source_service.py index 38af6b6d..a082433d 100644 --- a/src/spaceone/cost_analysis/service/data_source_service.py +++ b/src/spaceone/cost_analysis/service/data_source_service.py @@ -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 }