diff --git a/libs/ShivaApi.py b/libs/ShivaApi.py index ba454ec..9ea7db8 100644 --- a/libs/ShivaApi.py +++ b/libs/ShivaApi.py @@ -43,7 +43,41 @@ def get_esxi_datastores(self): if response.status_code == HTTPStatus.OK: return self.json_response(response) return self.error_response(response) + + def get_all_contentlibs(self): + """Find all content libraries""" + response = self.get(self.base_url + "/v1/vcenters/content_libraries") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) + def get_all_contentlibsitems(self): + """Find all content libraries items""" + response = self.get(self.base_url + "/v1/vcenters/content_libraries/items") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) + + def get_openiaas_templates(self): + """Find all openiaas templates""" + response = self.get(self.base_url + "/v1/open_iaas/templates") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) + + def get_all_vcnetworks(self): + """Find all vc networks""" + response = self.get(self.base_url + "/v1/vcenters/networks") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) + + def get_openiaas_networks(self): + """Find all vc networks""" + response = self.get(self.base_url + "/v1/open_iaas/networks") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) def get_vm_network_adapters(self, vm_id: str): """Find network adapters for virtual machine""" @@ -88,6 +122,13 @@ def get_hosts(self): if response.status_code == HTTPStatus.OK: return self.json_response(response) return self.error_response(response) + + def get_openiaas_hosts(self): + """Find Hosts""" + response = self.get(self.base_url + "/v1/open_iaas/hosts") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) def get_hosts_by_vdc(self, vdc_id): """Find Hots with Virtual Datacenter ID Filter""" @@ -137,6 +178,13 @@ def get_datastore_clusters_by_dc(self, id_dc): if response.status_code == HTTPStatus.OK: return self.json_response(response) return self.error_response(response) + + def get_openiaas_storage_repositories(self): + """Find all storage_repositories""" + response = self.get(self.base_url + "/v1/open_iaas/storage_repositories") + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) def get_vcenters(self): """Find vCenter servers""" @@ -253,7 +301,7 @@ def get_jobs(self): def get_policies(self): """Find SLA Policies""" - response = self.get(self.base_url + "/v1/policies") + response = self.get(self.base_url + "/v1/spp/policies") if response.status_code == HTTPStatus.OK: return self.json_response(response) return self.error_response(response) @@ -294,6 +342,44 @@ def get_tags(self): return self.error_response(response) +class Order(HttpClient): + def __init__(self, url: str, token_id: str, token_secret: str): + super().__init__(url=url, token_id=token_id, token_secret=token_secret) + self.base_url = "/api/order" + self.auth() + + def get_consumptions(self, start_date: str, end_date: str): + """Get consumptions for a time period + + Args: + start_date: Start date in format YYYY-MM-DD (e.g., "2025-01-15") + end_date: End date in format YYYY-MM-DD (e.g., "2025-01-17") + + Returns: + List of consumption items with usage and SKU information + """ + from datetime import datetime + + # Convert date strings to timestamp in milliseconds + try: + start_timestamp = int(datetime.strptime(start_date, "%Y-%m-%d").timestamp() * 1000) + end_timestamp = int(datetime.strptime(end_date, "%Y-%m-%d").timestamp() * 1000) + except ValueError as e: + raise ValueError(f"Invalid date format. Expected YYYY-MM-DD: {e}") + + # Validate that end_date >= start_date + if end_timestamp < start_timestamp: + raise ValueError("end_date must be greater than or equal to start_date") + + response = self.get( + self.base_url + f"/v1/consumptions?exportTimeStart={start_timestamp}&exportTimeEnd={end_timestamp}" + ) + + if response.status_code == HTTPStatus.OK: + return self.json_response(response) + return self.error_response(response) + + class Observability(HttpClient): def __init__(self, url: str, token_id: str, token_secret: str): super().__init__(url=url, token_id=token_id, token_secret=token_secret) diff --git a/libs/httpClient.py b/libs/httpClient.py index f18d351..c20bcd9 100644 --- a/libs/httpClient.py +++ b/libs/httpClient.py @@ -67,11 +67,7 @@ def auth(self): exp_epoch = datetime.fromtimestamp(self.jwt_decoded['exp']) time_now = datetime.now() diff = (exp_epoch - time_now).total_seconds() / 60 - if 10 > diff > 1: - if hasattr(self, 'logger'): - self.logger.debug("10 > diff > 1 - token is valide") - self.__refresh() - elif diff < 1: + if diff < 10: self.__login() def __login(self): @@ -100,32 +96,6 @@ def __login(self): self.logger.error("request exception %s", err) raise HttpClientException("request exception", err) from err - def __refresh(self): - try: - headers = { - 'Content-Type': 'application/json', - 'accept': 'application/json', - 'Authorization': "Bearer " + self.bearer_token - } - - refreshToken = { - 'refreshToken': self.bearer_token - } - - # Retrieve bearer - bearer_request = requests.post(url=self.url + "/api/iam/v2/auth/refresh", headers=headers, - json=refreshToken) - - if bearer_request.status_code != 200: - raise HttpClientException("Cannot generate bearer token", bearer_request.reason) - else: - self.bearer_token = bearer_request.json()['refresh_token'] - - except RequestException as err: - if hasattr(self, 'logger'): - self.logger.error("request exception %s", err) - raise HttpClientException("request exception", err) from err - def __execute(self, req: Request) -> Response: self.auth() try: diff --git a/tests/get_consumption.py b/tests/get_consumption.py new file mode 100644 index 0000000..de817fa --- /dev/null +++ b/tests/get_consumption.py @@ -0,0 +1,46 @@ +import sys +import os +# Add parent directory to path to allow imports from libs +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from libs.ShivaApi import Order + +# Init Order client +order_client = Order( + url="https://shiva.cloud-temple.com", + token_id="", + token_secret="" +) + +# Get consumptions for a specific period +# Format: YYYY-MM-DD +start_date = "2026-01-15" +end_date = "2026-01-17" + +print(f"Récupération des consommations du {start_date} au {end_date}...\n", flush=True) + +try: + consumptions = order_client.get_consumptions( + start_date=start_date, + end_date=end_date + ) + + print(f"Nombre total de SKU: {len(consumptions)}\n", flush=True) + print("=" * 80, flush=True) + + for item in consumptions: + usage = item.get('usage') + sku = item.get('sku', {}) + sku_name = sku.get('name', 'N/A') + sku_unit = sku.get('unit', 'N/A') + sku_desc_fr = sku.get('descriptionFr', 'N/A') + + print(f"\n📊 SKU: {sku_name}") + print(f" Usage: {usage} {sku_unit}") + print(f" Description: {sku_desc_fr}") + print("-" * 80) + +except ValueError as e: + print(f"❌ Erreur de validation: {e}") +except Exception as e: + print(f"❌ Erreur lors de la récupération des consommations: {e}")