Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/spaceone/identity/conf/global_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
]

# Dormancy Settings
DORMANCY_CHECK_HOUR = 13
DORMANCY_CHECK_HOUR = 14
DORMANCY_SETTINGS_KEY = "identity:dormancy:workspace"

# Database Settings
Expand Down
14 changes: 2 additions & 12 deletions src/spaceone/identity/manager/cost_analysis_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,11 @@ def __init__(self, *args, **kwargs):
"SpaceConnector", service="cost_analysis"
)

def analyze_cost_report_data(
def list_cost_reports(
self, params: dict, token: str = None, x_domain_id: str = None
) -> dict:
return self.cost_analysis_conn.dispatch(
"CostReportData.analyze",
params,
token=token,
x_domain_id=x_domain_id,
)

def list_cost_report_configs(
self, params: dict, token: str = None, x_domain_id: str = None
) -> dict:
return self.cost_analysis_conn.dispatch(
"CostReportConfig.list",
"CostReport.list",
params,
token=token,
x_domain_id=x_domain_id,
Expand Down
4 changes: 4 additions & 0 deletions src/spaceone/identity/manager/service_account_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ def _rollback(vo: ServiceAccount):
service_account_vo.delete()

params["state"] = "ACTIVE"
params["cost_info"] = {
"day": 0,
"month": 0,
}

service_account_vo = self.service_account_model.create(params)
self.transaction.add_rollback(_rollback, service_account_vo)
Expand Down
12 changes: 10 additions & 2 deletions src/spaceone/identity/manager/workspace_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ def _rollback(vo: Workspace):
)
vo.delete()

params["dormant_ttl"] = -1
params["service_account_count"] = 0
params["cost_info"] = {
"day": 0,
"month": 0,
}

workspace_vo = self.workspace_model.create(params)
self.transaction.add_rollback(_rollback, workspace_vo)

return workspace_vo

def update_workspace_by_vo(
self, params: dict, workspace_vo: Workspace
self, params: dict, workspace_vo: Workspace
) -> Workspace:
def _rollback(old_data):
_LOGGER.info(
Expand All @@ -50,7 +57,8 @@ def delete_workspace_by_vo(workspace_vo: Workspace) -> None:

if rb_vos.count() > 0:
_LOGGER.debug(
f"[delete_workspace_by_vo] Delete role bindings count with {workspace_vo.workspace_id} : {rb_vos.count()}")
f"[delete_workspace_by_vo] Delete role bindings count with {workspace_vo.workspace_id} : {rb_vos.count()}"
)
rb_vos.delete()

workspace_vo.delete()
Expand Down
3 changes: 1 addition & 2 deletions src/spaceone/identity/model/service_account/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class ServiceAccount(MongoModel):
tags = DictField(default=None)
reference_id = StringField(max_length=255, default=None, null=True)
is_managed = BooleanField(default=False)
asset_info = DictField(default=None)
cost_info = DictField(default=None)
secret_schema_id = StringField(max_length=40)
secret_id = StringField(max_length=40)
Expand All @@ -37,13 +36,13 @@ class ServiceAccount(MongoModel):
"data",
"tags",
"is_managed",
"asset_info",
"cost_info",
"secret_schema_id",
"secret_id",
"trusted_account_id",
"project_id",
"last_synced_at",
"inactivated_at",
],
"minimal_fields": [
"service_account_id",
Expand Down
3 changes: 2 additions & 1 deletion src/spaceone/identity/model/workspace/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Workspace(MongoModel):
is_managed = BooleanField(default=False)

is_dormant = BooleanField(default=False)
dormant_ttl = IntField(default=None)
dormant_ttl = IntField(default=None, required=True)
service_account_count = IntField(default=None)
cost_info = DictField(default=None)

Expand All @@ -42,6 +42,7 @@ class Workspace(MongoModel):
"references",
"deleted_at",
"last_synced_at",
"dormant_updated_at",
],
"minimal_fields": [
"workspace_id",
Expand Down
109 changes: 67 additions & 42 deletions src/spaceone/identity/service/job_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,16 +200,9 @@ def check_dormancy(self, params: dict) -> None:

domain_mgr = DomainManager()

# Temporary Code
# from spaceone.core import config, pygrpc, fastapi, utils, model
#
# model.init_all(False)

# domain_vos = domain_mgr.filter_domains(
# state="ENABLED", domain_id="domain-286776a1516a"
# )
# for domain_vo in domain_vos:
# self.job_mgr.push_dormancy_job({"domain_id": domain_vo.domain_id})
domain_vos = domain_mgr.filter_domains(state="ENABLED")
for domain_vo in domain_vos:
self.job_mgr.push_dormancy_job({"domain_id": domain_vo.domain_id})

@transaction(exclude=["authentication", "authorization", "mutation"])
def check_dormancy_by_domain(self, params: dict) -> None:
Expand All @@ -225,15 +218,20 @@ def check_dormancy_by_domain(self, params: dict) -> None:
domain_id = params["domain_id"]
dormancy_settings = self._get_dormancy_settings(domain_id)
dormancy_state = dormancy_settings.get("state")
threshold = dormancy_settings.get("cost")
dormancy_send_email = dormancy_settings.get("send_email")

cost_analysis_mgr = CostAnalysisManager()
is_report_exists, currency = self._get_currency(cost_analysis_mgr, domain_id)

workspace_vos = self.workspace_mgr.filter_workspaces(domain_id=domain_id)
for workspace_vo in workspace_vos:
if self._is_dormancy_updated(workspace_vo):
continue

cost_info = workspace_vo.cost_info or {}
before_month_cost = cost_info.get("month", 0)
before_day_cost = cost_info.get("day", 0)
before_dormant_ttl = workspace_vo.dormant_ttl or -1
before_is_dormant = workspace_vo.is_dormant

update_params = {
"is_dormant": workspace_vo.is_dormant,
Expand All @@ -248,62 +246,89 @@ def check_dormancy_by_domain(self, params: dict) -> None:

update_params["service_account_count"] = service_account_vos.count()

if is_report_exists:
month_cost = self._get_this_month_cost(
cost_analysis_mgr, domain_id, workspace_id, currency
)
update_params["cost_info"] = {"month": month_cost, "day": 0}
month_cost = self._get_this_month_cost(
cost_analysis_mgr, domain_id, workspace_id
)

day_cost = month_cost - before_month_cost
if day_cost < 0:
day_cost = 0

update_params["cost_info"] = {"month": month_cost, "day": day_cost}

if dormancy_state == "ENABLED" and before_dormant_ttl >= 0:
if day_cost <= threshold:
_LOGGER.debug(
f"[check_dormancy_by_domain] change dormant: {workspace_vo.name}"
)
update_params["is_dormant"] = True

if before_dormant_ttl > 0:
dormant_ttl = before_dormant_ttl - 1
if dormancy_send_email:
# Send Email
if dormant_ttl == 0:
pass
else:
pass

update_params["dormant_ttl"] = dormant_ttl
else:
if before_is_dormant:
_LOGGER.debug(
f"[check_dormancy_by_domain] change active: {workspace_vo.name}"
)

if dormancy_state == "ENABLED":
# Check Dormancy and Notify
pass
update_params["is_dormant"] = False
update_params["dormant_ttl"] = 3

update_params["dormant_updated_at"] = datetime.utcnow()
self.workspace_mgr.update_workspace_by_vo(update_params, workspace_vo)

@staticmethod
def _get_currency(
cost_analysis_mgr: CostAnalysisManager, domain_id: str
) -> Tuple[bool, str]:
system_token = config.get_global("TOKEN")
def _is_dormancy_updated(workspace_vo: Workspace) -> bool:
if not workspace_vo.dormant_updated_at:
return False

# Get Cost Report Config
response = cost_analysis_mgr.list_cost_report_configs(
{}, token=system_token, x_domain_id=domain_id
)
if response.get("total_count", 0) == 0:
return False, ""
today = datetime.utcnow().strftime("%Y-%m-%d")
last_dormant_updated_date = workspace_vo.dormant_updated_at.strftime("%Y-%m-%d")

cost_report_config = response["results"][0]
currency = cost_report_config.get("currency", "USD")
return True, currency
if today == last_dormant_updated_date:
_LOGGER.debug(
f"[_is_dormancy_updated] dormant has already been updated: {workspace_vo.name}"
)
return True
else:
return False

@staticmethod
def _get_this_month_cost(
cost_analysis_mgr: CostAnalysisManager,
domain_id: str,
workspace_id: str,
currency: str,
) -> float:
system_token = config.get_global("TOKEN")
now = datetime.utcnow()
report_month = now.strftime("%Y-%m")

# Get Monthly Cost
params = {
"status": "IN_PROGRESS",
"query": {
"granularity": "MONTHLY",
"start": report_month,
"end": report_month,
"fields": {"cost": {"key": f"cost.{currency}", "operator": "sum"}},
"filter": [{"k": "is_confirmed", "v": False, "o": "eq"}],
"filter": [
{"k": "report_month", "v": report_month, "o": "eq"},
{"k": "workspace_id", "v": workspace_id, "o": "eq"},
]
},
"workspace_id": workspace_id,
}

response = cost_analysis_mgr.analyze_cost_report_data(
response = cost_analysis_mgr.list_cost_reports(
params, token=system_token, x_domain_id=domain_id
)
results = response.get("results", [])
if len(results) > 0:
return results[0]["cost"]
currency = results[0]["currency"]
return results[0]["cost"][currency]
else:
return 0

Expand Down