loayai

ovh_server_monitor.py

Aug 29th, 2025
126
0
Never
5
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.63 KB | Source Code | 0 0
  1. import requests
  2. import json
  3.  
  4. acceptable_dc = ['gra','rbx','sbg','waw','fra','lon','bhs']
  5. ovhSubsidiary = 'IE'
  6. outputFileName = 'catalog.csv'
  7. outputFileNameReadable = 'catalog_with_names.csv'
  8.  
  9. # -------------- BUILD AVAILABILITY DICT -------------------------------------------------------------------------
  10. def buildAvailabilityDict():
  11.     myAvail = {}
  12.     api_url = "https://eu.api.ovh.com/v1/dedicated/server/datacenter/availabilities"
  13.     if acceptable_dc:
  14.         api_url += "?datacenters=" + ",".join(acceptable_dc)
  15.  
  16.     try:
  17.         response = requests.get(api_url)
  18.         response.raise_for_status()
  19.         avail_data = response.json()
  20.         for avail_item in avail_data:
  21.             myFqn = avail_item['fqn']
  22.             for da in avail_item['datacenters']:
  23.                 myLongFqn = myFqn + "." + da['datacenter']
  24.                 myAvail[myLongFqn] = da['availability']
  25.     except requests.exceptions.RequestException as e:
  26.         print(f"Error fetching availability: {e}")
  27.     except json.JSONDecodeError as e:
  28.         print(f"Error decoding availability JSON: {e}")
  29.     return myAvail
  30.  
  31. # -------------- HELPER FUNCTION FOR ADDON INFO ------------------------------------------------------------------
  32. def get_addon_info(addon_plan_code, all_addons_list, expected_pricing_index):
  33.     invoice_name = "N/A"
  34.     price = 0.0
  35.     if addon_plan_code == 'none' or not addon_plan_code:
  36.         return "None", 0.0
  37.  
  38.     addon_details = [x for x in all_addons_list if x.get('planCode') == addon_plan_code]
  39.     if addon_details:
  40.         addon = addon_details[0]
  41.         invoice_name = addon.get('invoiceName', "N/A")
  42.         try:
  43.             if addon.get('pricings') and len(addon['pricings']) > expected_pricing_index and addon['pricings'][expected_pricing_index].get('price') is not None:
  44.                 price = float(addon['pricings'][expected_pricing_index]['price']) / 100000000
  45.             elif addon.get('pricings'):
  46.                 for p_entry in addon['pricings']:
  47.                     if p_entry and p_entry.get('price') is not None:
  48.                         price = float(p_entry['price']) / 100000000
  49.                         break
  50.         except (IndexError, TypeError, ValueError, KeyError) as e:
  51.             price = 0.0
  52.     return invoice_name, price
  53.  
  54. # -------------- BUILD LIST OF SERVERS ---------------------------------------------------------------------------
  55. # Here we fix errors in the catalog to match the FQN listed in the availabilities
  56. def fixMem(mem):
  57.     fixedMem = mem
  58.     # For 25rises011 and 021, OVH add "-rise-s" instead of the plancode at the end of the RAM
  59.     # and in the availabilities there is an extra "-on-die-ecc-5200"
  60.     if mem.endswith("-rise"):
  61.         fixedMem = mem.removesuffix("-rise") + "-on-die-ecc-5200"
  62.     return fixedMem
  63.  
  64. def fixSto(sto):
  65.     fixedSto = sto
  66.     # For SYS-01 with hybrid disks, the availabilities have 500nvme instead of 512nvme
  67.     if sto.endswith("4000sa-2x512nvme") or sto.endswith("4000sa-1x512nvme"):
  68.         fixedSto = sto.replace("512", "500")
  69.     return fixedSto
  70.  
  71. def buildList(avail_dict):
  72.     try:
  73.         response = requests.get("https://eu.api.ovh.com/v1/order/catalog/public/eco?ovhSubsidiary=" + ovhSubsidiary)
  74.         response.raise_for_status()
  75.         API_catalog = response.json()
  76.     except requests.exceptions.RequestException as e:
  77.         print(f"Error fetching catalog: {e}")
  78.         return []
  79.     except json.JSONDecodeError as e:
  80.         print(f"Error decoding catalog JSON: {e}")
  81.         return []
  82.  
  83.     allPlans = API_catalog.get('plans', [])
  84.     myPlans = []
  85.  
  86.     allAddons = API_catalog.get('addons', [])
  87.  
  88.     for plan in allPlans:
  89.         planCode = plan['planCode']
  90.         base_plan_price = 0.0
  91.         allPrices = plan.get('pricings', [])
  92.         if allPrices and allPrices[0].get('price') is not None:
  93.             try:
  94.                 base_plan_price = float(allPrices[0]['price'])/100000000
  95.             except (ValueError, TypeError):
  96.                 base_plan_price = 0.0
  97.         else:
  98.             base_plan_price = 0.0
  99.  
  100.         allStorages = []
  101.         allMemories = []
  102.         allBandwidths = []
  103.         allVRack = []
  104.         allGpus = []
  105.  
  106.         for family in plan.get('addonFamilies', []):
  107.             if family['name'] == "storage":
  108.                 allStorages = family.get('addons', [])
  109.             elif family['name'] == "memory":
  110.                 allMemories = family.get('addons', [])
  111.             elif family['name'] == "bandwidth":
  112.                 allBandwidths = family.get('addons', [])
  113.             elif family['name'] == "vrack":
  114.                 allVRack = family.get('addons', [])
  115.             elif family['name'] == "gpu":
  116.                 allGpus = family.get('addons', [])
  117.  
  118.         if not allMemories: allMemories = ['none']
  119.         if not allStorages: allStorages = ['none']
  120.         if not allBandwidths: allBandwidths = ['none']
  121.         if not allVRack: allVRack = ['none']
  122.         if not allGpus: allGpus = ['none']
  123.  
  124.         allDatacenters = []
  125.         for config in plan.get('configurations', []):
  126.             if config['name'] == "dedicated_datacenter":
  127.                 allDatacenters = config.get('values', [])
  128.  
  129.         if not allDatacenters: allDatacenters = ['none']
  130.  
  131.         for da in allDatacenters:
  132.             if not acceptable_dc or da == 'none' or da in acceptable_dc:
  133.                 for mem_code in allMemories:
  134.                     for st_code in allStorages:
  135.                         for ba_code in allBandwidths:
  136.                             for vr_code in allVRack:
  137.                                 for gp_code in allGpus:
  138.  
  139.                                     mem_name, mem_addon_price = get_addon_info(mem_code, allAddons, 1)
  140.                                     st_name, st_addon_price = get_addon_info(st_code, allAddons, 1)
  141.                                     ba_name, ba_addon_price = get_addon_info(ba_code, allAddons, 1)
  142.                                     vr_name, vr_addon_price = get_addon_info(vr_code, allAddons, 2)
  143.                                     gp_name, gp_addon_price = get_addon_info(gp_code, allAddons, 1)
  144.  
  145.                                     thisPrice = base_plan_price + mem_addon_price + st_addon_price + ba_addon_price + vr_addon_price + gp_addon_price
  146.                                     priceStr = "{:.2f}".format(thisPrice)
  147.  
  148.                                     shortme = fixMem("-".join(mem_code.split("-")[:-1])) if mem_code != 'none' else 'none'
  149.                                     shortst = fixSto("-".join(st_code.split("-")[:-1])) if st_code != 'none' else 'none'
  150.  
  151.                                     myFqn = planCode + "." + shortme + "." + shortst + "." + da
  152.                                     myavailability = 'unknown'
  153.                                     if da != 'none' and shortme != 'none' and shortst != 'none':
  154.                                         if myFqn in avail_dict:
  155.                                             myavailability = avail_dict[myFqn]
  156.                                     elif da == 'none' or shortme == 'none' or shortst == 'none':
  157.                                          myavailability = 'config_incomplete_for_avail_check'
  158.  
  159.                                     myPlans.append({
  160.                                         'planCode': planCode,
  161.                                         'invoiceName': plan.get('invoiceName', 'N/A'),
  162.                                         'datacenter': da,
  163.                                         'storage_planCode': st_code, 'storage_name': st_name,
  164.                                         'memory_planCode': mem_code, 'memory_name': mem_name,
  165.                                         'bandwidth_planCode': ba_code, 'bandwidth_name': ba_name,
  166.                                         'vrack_planCode': vr_code, 'vrack_name': vr_name,
  167.                                         'gpu_planCode': gp_code, 'gpu_name': gp_name,
  168.                                         'price': priceStr,
  169.                                         'availability': myavailability
  170.                                     })
  171.     return myPlans
  172.  
  173. # -------------- DUMP LIST OF SERVERS AS CSV (ORIGINAL) ------------------------------
  174. def dumpPlans(plans):
  175.     with open(outputFileName, 'w') as file:
  176.         file.write("planCode;invoiceName;datacenter;storage;memory;bandwidth;vrack;price;availability\n")
  177.         for plan_item in plans:
  178.             vRackStr = 'none'
  179.             if plan_item['vrack_planCode'] != 'none' and plan_item['vrack_planCode']:
  180.                 try:
  181.                     vRackStr = plan_item['vrack_planCode'].split("-")[2]
  182.                 except IndexError:
  183.                     vRackStr = plan_item['vrack_planCode']
  184.  
  185.             storageStr = "-".join(plan_item['storage_planCode'].split("-")[1:-1]) if plan_item['storage_planCode'] != 'none' and plan_item['storage_planCode'] else 'none'
  186.             memoryStr = plan_item['memory_planCode'].split("-")[1][:-1] if plan_item['memory_planCode'] != 'none' and plan_item['memory_planCode'] and len(plan_item['memory_planCode'].split("-")) > 1 and plan_item['memory_planCode'].split("-")[1] else 'none'
  187.             bandwidthStr = plan_item['bandwidth_planCode'].split("-")[1] if plan_item['bandwidth_planCode'] != 'none' and plan_item['bandwidth_planCode'] and len(plan_item['bandwidth_planCode'].split("-")) > 1 else 'none'
  188.  
  189.             file.write(plan_item['planCode'] + ';' +
  190.                 '\"' + plan_item['invoiceName'] + '\"' + ';' +
  191.                 plan_item['datacenter'] + ';' +
  192.                 storageStr + ';' +
  193.                 memoryStr + ';' +
  194.                 bandwidthStr + ';' +
  195.                 vRackStr + ';' +
  196.                 plan_item['price'] + ';' +
  197.                 plan_item['availability'] + '\n')
  198.  
  199. # -------------- DUMP LIST OF SERVERS AS CSV (WITH READABLE NAMES) ------------------
  200. def dumpPlansWithReadableNames(plans, filename):
  201.     with open(filename, 'w') as file:
  202.         header = [
  203.             "planCode", "serverInvoiceName", "datacenter",
  204.             "storage_planCode", "storage_name",
  205.             "memory_planCode", "memory_name",
  206.             "bandwidth_planCode", "bandwidth_name",
  207.             "vrack_planCode", "vrack_name",
  208.             "gpu_planCode", "gpu_name",
  209.             "totalPrice", "availability"
  210.         ]
  211.         file.write(";".join(header) + "\n")
  212.         for plan_item in plans:
  213.             row = [
  214.                 plan_item.get('planCode', ''),
  215.                 f"\"{plan_item.get('invoiceName', 'N/A')}\"",
  216.                 plan_item.get('datacenter', ''),
  217.                 plan_item.get('storage_planCode', 'none'), f"\"{plan_item.get('storage_name', 'N/A')}\"",
  218.                 plan_item.get('memory_planCode', 'none'), f"\"{plan_item.get('memory_name', 'N/A')}\"",
  219.                 plan_item.get('bandwidth_planCode', 'none'), f"\"{plan_item.get('bandwidth_name', 'N/A')}\"",
  220.                 plan_item.get('vrack_planCode', 'none'), f"\"{plan_item.get('vrack_name', 'N/A')}\"",
  221.                 plan_item.get('gpu_planCode', 'none'), f"\"{plan_item.get('gpu_name', 'N/A')}\"",
  222.                 plan_item.get('price', '0.00'),
  223.                 plan_item.get('availability', 'unknown')
  224.             ]
  225.             file.write(";".join(map(str, row)) + "\n")
  226.  
  227. # --------------- MAIN PROGRAM ---------------------------------------------
  228. if __name__ == "__main__":
  229.     availabilities = buildAvailabilityDict()
  230.     plans = buildList(availabilities)
  231.  
  232.     if plans:
  233.         dumpPlans(plans)
  234.         dumpPlansWithReadableNames(plans, outputFileNameReadable)
  235.         print(f"Original catalog written to {outputFileName}")
  236.         print(f"Catalog with readable names written to {outputFileNameReadable}")
  237.     else:
  238.         print("No plans generated, CSV files not created.")
Tags: ovh
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment