Skip to content

Commit

Permalink
feat: modify change cost data parameter (cloudforet-io#199(
Browse files Browse the repository at this point in the history
  • Loading branch information
ImMin5 committed Apr 30, 2024
1 parent b316f13 commit d399ac5
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 103 deletions.
51 changes: 35 additions & 16 deletions src/spaceone/cost_analysis/manager/cost_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,17 @@ def _rollback(vo: Cost):
params["billed_year"] = billed_at.strftime("%Y")
params["billed_month"] = billed_at.strftime("%Y-%m")

params, ds_account_vo = self.data_source_account_mgr.connect_cost_data(params)
(
workspace_id,
v_workspace_id,
) = self.data_source_account_mgr.get_workspace_id_from_account_id(
params["domain_id"], params["data_source_id"]
)

if v_workspace_id:
params["workspace_id"] = v_workspace_id

params = self.data_source_rule_mgr.change_cost_data(params, ds_account_vo)
params = self.data_source_rule_mgr.change_cost_data(params, workspace_id)

cost_vo: Cost = self.cost_model.create(params)

Expand Down Expand Up @@ -110,14 +118,14 @@ def get_cost(
def filter_costs(self, **conditions):
return self.cost_model.filter(**conditions)

def list_costs(self, query: dict, domain_id: str):
def list_costs(self, query: dict, domain_id: str, data_source_id: str):
query = self._change_filter_project_group_id(query, domain_id)
# query = self._change_filter_v_workspace_id(query, domain_id)
# query = self._change_filter_v_workspace_id(query, domain_id, data_source_id)
return self.cost_model.query(**query)

def stat_costs(self, query: dict, domain_id: str):
def stat_costs(self, query: dict, domain_id: str, data_source_id: str):
query = self._change_filter_project_group_id(query, domain_id)
# query = self._change_filter_v_workspace_id(query, domain_id)
# query = self._change_filter_v_workspace_id(query, domain_id, data_source_id)

return self.cost_model.stat(**query)

Expand Down Expand Up @@ -205,14 +213,14 @@ def analyze_costs_by_granularity(
granularity = query["granularity"]

# Change filter v_workspace_id to workspace_id
data_source_vo = self.data_source_mgr.get_data_source(data_source_id, domain_id)
plugin_metadata = data_source_vo.plugin_info.metadata
use_account_routing = plugin_metadata.get("use_account_routing", False)
if use_account_routing:
_LOGGER.debug(
f"[analyze_costs_by_granularity] add v_workspace_id filter: {data_source_id}"
)
query = self._change_filter_v_workspace_id(query, domain_id)
# data_source_vo = self.data_source_mgr.get_data_source(data_source_id, domain_id)
# plugin_metadata = data_source_vo.plugin_info.metadata
# use_account_routing = plugin_metadata.get("use_account_routing", False)
# if use_account_routing:
# _LOGGER.debug(
# f"[analyze_costs_by_granularity] add v_workspace_id filter: {data_source_id}"
# )
query = self._change_filter_v_workspace_id(query, domain_id, data_source_id)

# Save query history to speed up data loading
query_hash: str = utils.dict_to_hash(query)
Expand Down Expand Up @@ -446,10 +454,21 @@ def _change_filter_project_group_id(self, query: dict, domain_id: str) -> dict:
query["filter"] = change_filter
return query

def _change_filter_v_workspace_id(self, query: dict, domain_id: str) -> dict:
def _change_filter_v_workspace_id(
self, query: dict, domain_id: str, data_source_id: str
) -> dict:
change_filter = []
workspace_ids = []
data_source_id = self._get_data_source_id_from_filter(query)

data_source_vo = self.data_source_mgr.get_data_source(data_source_id, domain_id)
plugin_metadata = data_source_vo.plugin_info.metadata
use_account_routing = plugin_metadata.get("use_account_routing", False)
if not use_account_routing:
return query

_LOGGER.debug(
f"[analyze_costs_by_granularity] add v_workspace_id filter: {data_source_id}"
)

for condition in query.get("filter", []):
key = condition.get("k", condition.get("key"))
Expand Down
108 changes: 39 additions & 69 deletions src/spaceone/cost_analysis/manager/data_source_account_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from mongoengine import QuerySet
from spaceone.core.manager import BaseManager
from spaceone.core import utils

from spaceone.cost_analysis.model import DataSource
from spaceone.cost_analysis.model.data_source_account.database import DataSourceAccount
Expand Down Expand Up @@ -83,45 +82,28 @@ def filter_data_source_accounts(self, **conditions) -> QuerySet:
def stat_data_source_accounts(self, query: dict) -> dict:
return self.data_source_account_model.stat(**query)

def connect_cost_data(
self, cost_data: dict
) -> Tuple[dict, Union[DataSourceAccount, None]]:
data_source_id = cost_data["data_source_id"]
domain_id = cost_data["domain_id"]
def get_workspace_id_from_account_id(
self, domain_id: str, data_source_id: str
) -> Tuple[str, str]:
workspace_id = None
v_workspace_id = None

data_source_vo = self._get_data_source(data_source_id, domain_id)
plugin_info_metadata = data_source_vo.plugin_info.metadata

use_account_routing = plugin_info_metadata.get("use_account_routing", False)

ds_account_vo = None
if use_account_routing:
account_connect_polices: list = plugin_info_metadata.get(
"account_connect_polices"
)
for account_connect_policy in account_connect_polices:
if account_connect_policy.get("name") == "connect_cost_to_account":
name = account_connect_policy.get("name")
policy = account_connect_policy["polices"].get(name)
source = policy["source"]
target_key = policy.get("target", "account_id")
target_value = utils.get_dict_value(cost_data, source)
operator = policy.get("operator")

if target_value:
ds_account_vo = self._get_data_source_account_vo(
target_key,
target_value,
data_source_id,
domain_id,
operator,
)

if ds_account_vo:
cost_data["account_id"] = ds_account_vo.account_id
cost_data["workspace_id"] = ds_account_vo.v_workspace_id

return cost_data, ds_account_vo
account_match_key_value = plugin_info_metadata.get("account_match_key")
if account_match_key_value:
ds_account_vo = self.get_data_source_account(
data_source_id, account_match_key_value, domain_id
)

workspace_id = ds_account_vo.workspace_id
v_workspace_id = ds_account_vo.v_workspace_id

return workspace_id, v_workspace_id

def connect_account_by_data_source_vo(
self,
Expand All @@ -130,64 +112,52 @@ def connect_account_by_data_source_vo(
) -> DataSourceAccount:
domain_id = data_source_vo.domain_id

plugin_info_metadata = data_source_vo.plugin_info.metadata
account_connect_polices: list = plugin_info_metadata.get(
"account_connect_polices"
)

for account_connect_policy in account_connect_polices:
if account_connect_policy.get("name") == "connect_account_to_workspace":
name = account_connect_policy.get("name")
policy = account_connect_policy["polices"].get(name)
source = policy["source"]
target_key = policy.get("target", "references")
reference_id = data_source_account_vo.account_id
workspace_info = self._get_workspace_by_references(reference_id, domain_id)
if workspace_info:
data_source_account_vo = self.update_data_source_account_by_vo(
{"workspace_id": workspace_info.get("workspace_id")},
data_source_account_vo,
)

target_value = utils.get_dict_value(
data_source_account_vo.to_dict(),
source,
)
operator = policy.get("operator")

if target_value:
workspace_info = self._get_workspace(
target_key, target_value, domain_id, operator
)

if workspace_info:
data_source_account_vo = self.update_data_source_account_by_vo(
{"workspace_id": workspace_info.get("workspace_id")},
data_source_account_vo,
)
return data_source_account_vo

def _get_workspace(
self, target_key: str, target_value: str, domain_id: str, operator: str = "eq"
def _get_workspace_by_references(
self, reference_id: str, domain_id: str
) -> Union[dict, None]:
if f"workspace:{domain_id}:{target_key}:{target_value}" in self._workspace_info:
if f"workspace:{domain_id}:references:{reference_id}" in self._workspace_info:
return self._workspace_info[
f"workspace:{domain_id}:{target_key}:{target_value}"
f"workspace:{domain_id}:references:{reference_id}"
]

query = {
"filter": [
{"k": "domain_id", "v": domain_id, "o": "eq"},
{"k": "references", "v": [reference_id], "o": "in"},
]
}
if operator == "in" and not isinstance(target_value, list):
target_value = [target_value]
query["filter"].append({"k": target_key, "v": target_value, "o": operator})

identity_mgr = self.locator.get_manager("IdentityManager")
response = identity_mgr.list_workspaces({"query": query}, domain_id)
results = response.get("results", [])
total_count = response.get("total_count", 0)

workspace_info = None
if total_count > 0:

if total_count == 0:
response = identity_mgr.list_workspaces(
{"query": {"filter": [{"k": "domain_id", "v": domain_id, "o": "eq"}]}},
domain_id,
)
total_count = response.get("total_count", 0)
if total_count == 1:
workspace_info = response.get("results")[0]

else:
workspace_info = results[0]

self._workspace_info[
f"workspace:{domain_id}:{target_key}:{target_value}"
f"workspace:{domain_id}:references:{reference_id}"
] = workspace_info

return workspace_info
Expand Down
26 changes: 9 additions & 17 deletions src/spaceone/cost_analysis/manager/data_source_rule_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from spaceone.core import utils
from spaceone.core.manager import BaseManager
from spaceone.cost_analysis.manager.identity_manager import IdentityManager
from spaceone.cost_analysis.model import DataSourceAccount
from spaceone.cost_analysis.model.data_source_rule_model import (
DataSourceRule,
DataSourceRuleCondition,
Expand Down Expand Up @@ -88,9 +87,7 @@ def list_data_source_rules(self, query: dict):
def stat_data_source_rules(self, query):
return self.data_source_rule_model.stat(**query)

def change_cost_data(
self, cost_data: dict, data_source_account_vo: DataSourceAccount = None
) -> dict:
def change_cost_data(self, cost_data: dict, workspace_id: str = None) -> dict:
data_source_id = cost_data["data_source_id"]
domain_id = cost_data["domain_id"]
(
Expand All @@ -99,11 +96,11 @@ def change_cost_data(
) = self._get_data_source_rules(data_source_id, domain_id)

cost_data = self._apply_data_source_rule_to_cost_data(
cost_data, managed_data_source_rule_vos, domain_id, data_source_account_vo
cost_data, managed_data_source_rule_vos, domain_id, workspace_id
)

cost_data = self._apply_data_source_rule_to_cost_data(
cost_data, custom_data_source_rule_vos, domain_id, data_source_account_vo
cost_data, custom_data_source_rule_vos, domain_id, workspace_id
)

return cost_data
Expand All @@ -113,7 +110,7 @@ def _apply_data_source_rule_to_cost_data(
cost_data: dict,
data_source_rule_vos: QuerySet,
domain_id: str,
data_source_account_vo: DataSourceAccount = None,
workspace_id: str = None,
):
for data_source_rule_vo in data_source_rule_vos:
is_match = self._change_cost_data_by_rule(cost_data, data_source_rule_vo)
Expand All @@ -122,7 +119,7 @@ def _apply_data_source_rule_to_cost_data(
cost_data,
data_source_rule_vo.actions,
domain_id,
data_source_account_vo,
workspace_id,
)

if is_match and data_source_rule_vo.options.stop_processing:
Expand All @@ -135,13 +132,8 @@ def _change_cost_data_with_actions(
cost_data: dict,
actions: dict,
domain_id: str,
data_source_account_vo: DataSourceAccount = None,
workspace_id: str = None,
):
if data_source_account_vo:
workspace_id = data_source_account_vo.workspace_id
else:
workspace_id = None

for action, value in actions.items():
if action == "change_project" and value:
cost_data["project_id"] = value
Expand All @@ -156,8 +148,8 @@ def _change_cost_data_with_actions(
)
if project_info:
cost_data["project_id"] = project_info["project_id"]
if not data_source_account_vo:
cost_data["workspace_id"] = project_info.get("workspace_id")
if not workspace_id:
cost_data["workspace_id"] = project_info["workspace_id"]

elif action == "match_service_account" and value:
source = value["source"]
Expand All @@ -172,7 +164,7 @@ def _change_cost_data_with_actions(
"service_account_id"
]
cost_data["project_id"] = service_account_info.get("project_id")
if not data_source_account_vo:
if not workspace_id:
cost_data["workspace_id"] = service_account_info.get(
"workspace_id"
)
Expand Down
3 changes: 2 additions & 1 deletion src/spaceone/cost_analysis/service/cost_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ def list(self, params):

query = params.get("query", {})
domain_id = params["domain_id"]
return self.cost_mgr.list_costs(query, domain_id)
data_source_id = params["data_source_id"]
return self.cost_mgr.list_costs(query, domain_id, data_source_id)

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

0 comments on commit d399ac5

Please sign in to comment.