Skip to content
Open
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
88 changes: 87 additions & 1 deletion libs/ShivaApi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
32 changes: 1 addition & 31 deletions libs/httpClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down
46 changes: 46 additions & 0 deletions tests/get_consumption.py
Original file line number Diff line number Diff line change
@@ -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}")