|
1 | 1 | import logging
|
2 | 2 | import os
|
3 | 3 | import time
|
4 |
| -from datetime import datetime |
5 |
| - |
6 | 4 | import requests
|
7 | 5 | import pandas as pd
|
8 | 6 | import numpy as np
|
| 7 | +from datetime import datetime |
| 8 | +from functools import wraps |
9 | 9 | from io import StringIO
|
| 10 | +from typing import get_type_hints, Union, Any |
10 | 11 |
|
11 | 12 | from azure.identity import DefaultAzureCredential
|
12 | 13 | from azure.mgmt.billing import BillingManagementClient
|
13 | 14 | from azure.mgmt.costmanagement import CostManagementClient
|
14 | 15 | from azure.mgmt.consumption import ConsumptionManagementClient
|
15 |
| -from azure.core.exceptions import ResourceNotFoundError |
| 16 | +from azure.core.exceptions import ResourceNotFoundError, HttpResponseError |
16 | 17 | from spaceone.core.connector import BaseConnector
|
17 | 18 |
|
18 | 19 | from cloudforet.cost_analysis.error.cost import *
|
|
25 | 26 | _PAGE_SIZE = 5000
|
26 | 27 |
|
27 | 28 |
|
| 29 | +def azure_exception_handler(func): |
| 30 | + @wraps(func) |
| 31 | + def wrapper(*args, **kwargs) -> Union[dict, list]: |
| 32 | + return_type = get_type_hints(func).get("return") |
| 33 | + try: |
| 34 | + return func(*args, **kwargs) |
| 35 | + except ResourceNotFoundError as error: |
| 36 | + _print_error_log(error) |
| 37 | + return _get_empty_value(return_type) |
| 38 | + except HttpResponseError as error: |
| 39 | + if error.status_code in ["404", "412"]: |
| 40 | + _print_error_log(error) |
| 41 | + else: |
| 42 | + _print_error_log(error) |
| 43 | + return _get_empty_value(return_type) |
| 44 | + except Exception as e: |
| 45 | + _print_error_log(ERROR_UNKNOWN(message=str(e))) |
| 46 | + raise e |
| 47 | + |
| 48 | + return wrapper |
| 49 | + |
| 50 | + |
| 51 | +def _get_empty_value(return_type: object) -> Any: |
| 52 | + return_type_name = getattr(return_type, "__name__") |
| 53 | + empty_values = { |
| 54 | + "int": 0, |
| 55 | + "float": 0.0, |
| 56 | + "str": "", |
| 57 | + "bool": False, |
| 58 | + "list": [], |
| 59 | + "dict": {}, |
| 60 | + "set": set(), |
| 61 | + "tuple": (), |
| 62 | + } |
| 63 | + |
| 64 | + return empty_values.get(return_type_name, None) |
| 65 | + |
| 66 | + |
| 67 | +def _print_error_log(error): |
| 68 | + _LOGGER.error(f"(Error) => {error.message} {error}", exc_info=True) |
| 69 | + |
| 70 | + |
28 | 71 | class AzureCostMgmtConnector(BaseConnector):
|
29 | 72 | def __init__(self, *args, **kwargs):
|
30 | 73 | super().__init__(*args, **kwargs)
|
@@ -173,32 +216,24 @@ def get_billing_account(self) -> dict:
|
173 | 216 | billing_account_info = self.convert_nested_dictionary(billing_account_info)
|
174 | 217 | return billing_account_info
|
175 | 218 |
|
| 219 | + @azure_exception_handler |
176 | 220 | def begin_create_operation(self, scope: str, parameters: dict) -> list:
|
177 |
| - try: |
178 |
| - content_type = "application/json" |
179 |
| - response = self.cost_mgmt_client.generate_cost_details_report.begin_create_operation( |
| 221 | + content_type = "application/json" |
| 222 | + response = ( |
| 223 | + self.cost_mgmt_client.generate_cost_details_report.begin_create_operation( |
180 | 224 | scope=scope, parameters=parameters, content_type=content_type
|
181 | 225 | )
|
182 |
| - result = self.convert_nested_dictionary(response.result()) |
183 |
| - _LOGGER.info( |
184 |
| - f"[begin_create_operation] result : {result} status : {response.status()}" |
185 |
| - ) |
| 226 | + ) |
| 227 | + result = self.convert_nested_dictionary(response.result()) |
| 228 | + _LOGGER.info( |
| 229 | + f"[begin_create_operation] result : {result} status : {response.status()}" |
| 230 | + ) |
186 | 231 |
|
187 |
| - blobs = result.get("blobs", []) or [] |
188 |
| - _LOGGER.debug( |
189 |
| - f"[begin_create_operation] csv_file_link: {blobs} / parameters: {parameters}" |
190 |
| - ) |
191 |
| - return blobs |
192 |
| - except ResourceNotFoundError as e: |
193 |
| - _LOGGER.error( |
194 |
| - f"[begin_create_operation] Cost data is not ready: {e} / parameters: {parameters}" |
195 |
| - ) |
196 |
| - return [] |
197 |
| - except Exception as e: |
198 |
| - _LOGGER.error( |
199 |
| - f"[begin_create_operation] error message: {e} / parameters: {parameters}" |
200 |
| - ) |
201 |
| - raise ERROR_UNKNOWN(message=f"[ERROR] begin_create_operation failed") |
| 232 | + blobs = result.get("blobs", []) or [] |
| 233 | + _LOGGER.debug( |
| 234 | + f"[begin_create_operation] csv_file_link: {blobs} / parameters: {parameters}" |
| 235 | + ) |
| 236 | + return blobs |
202 | 237 |
|
203 | 238 | def get_cost_data(self, blobs: list, options: dict) -> list:
|
204 | 239 | _LOGGER.debug(f"[get_cost_data] options: {options}")
|
|
0 commit comments