Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import requests
- import json
- acceptable_dc = ['gra','rbx','sbg','waw','fra','lon','bhs']
- ovhSubsidiary = 'IE'
- outputFileName = 'catalog.csv'
- outputFileNameReadable = 'catalog_with_names.csv'
- # -------------- BUILD AVAILABILITY DICT -------------------------------------------------------------------------
- def buildAvailabilityDict():
- myAvail = {}
- api_url = "https://eu.api.ovh.com/v1/dedicated/server/datacenter/availabilities"
- if acceptable_dc:
- api_url += "?datacenters=" + ",".join(acceptable_dc)
- try:
- response = requests.get(api_url)
- response.raise_for_status()
- avail_data = response.json()
- for avail_item in avail_data:
- myFqn = avail_item['fqn']
- for da in avail_item['datacenters']:
- myLongFqn = myFqn + "." + da['datacenter']
- myAvail[myLongFqn] = da['availability']
- except requests.exceptions.RequestException as e:
- print(f"Error fetching availability: {e}")
- except json.JSONDecodeError as e:
- print(f"Error decoding availability JSON: {e}")
- return myAvail
- # -------------- HELPER FUNCTION FOR ADDON INFO ------------------------------------------------------------------
- def get_addon_info(addon_plan_code, all_addons_list, expected_pricing_index):
- invoice_name = "N/A"
- price = 0.0
- if addon_plan_code == 'none' or not addon_plan_code:
- return "None", 0.0
- addon_details = [x for x in all_addons_list if x.get('planCode') == addon_plan_code]
- if addon_details:
- addon = addon_details[0]
- invoice_name = addon.get('invoiceName', "N/A")
- try:
- if addon.get('pricings') and len(addon['pricings']) > expected_pricing_index and addon['pricings'][expected_pricing_index].get('price') is not None:
- price = float(addon['pricings'][expected_pricing_index]['price']) / 100000000
- elif addon.get('pricings'):
- for p_entry in addon['pricings']:
- if p_entry and p_entry.get('price') is not None:
- price = float(p_entry['price']) / 100000000
- break
- except (IndexError, TypeError, ValueError, KeyError) as e:
- price = 0.0
- return invoice_name, price
- # -------------- BUILD LIST OF SERVERS ---------------------------------------------------------------------------
- # Here we fix errors in the catalog to match the FQN listed in the availabilities
- def fixMem(mem):
- fixedMem = mem
- # For 25rises011 and 021, OVH add "-rise-s" instead of the plancode at the end of the RAM
- # and in the availabilities there is an extra "-on-die-ecc-5200"
- if mem.endswith("-rise"):
- fixedMem = mem.removesuffix("-rise") + "-on-die-ecc-5200"
- return fixedMem
- def fixSto(sto):
- fixedSto = sto
- # For SYS-01 with hybrid disks, the availabilities have 500nvme instead of 512nvme
- if sto.endswith("4000sa-2x512nvme") or sto.endswith("4000sa-1x512nvme"):
- fixedSto = sto.replace("512", "500")
- return fixedSto
- def buildList(avail_dict):
- try:
- response = requests.get("https://eu.api.ovh.com/v1/order/catalog/public/eco?ovhSubsidiary=" + ovhSubsidiary)
- response.raise_for_status()
- API_catalog = response.json()
- except requests.exceptions.RequestException as e:
- print(f"Error fetching catalog: {e}")
- return []
- except json.JSONDecodeError as e:
- print(f"Error decoding catalog JSON: {e}")
- return []
- allPlans = API_catalog.get('plans', [])
- myPlans = []
- allAddons = API_catalog.get('addons', [])
- for plan in allPlans:
- planCode = plan['planCode']
- base_plan_price = 0.0
- allPrices = plan.get('pricings', [])
- if allPrices and allPrices[0].get('price') is not None:
- try:
- base_plan_price = float(allPrices[0]['price'])/100000000
- except (ValueError, TypeError):
- base_plan_price = 0.0
- else:
- base_plan_price = 0.0
- allStorages = []
- allMemories = []
- allBandwidths = []
- allVRack = []
- allGpus = []
- for family in plan.get('addonFamilies', []):
- if family['name'] == "storage":
- allStorages = family.get('addons', [])
- elif family['name'] == "memory":
- allMemories = family.get('addons', [])
- elif family['name'] == "bandwidth":
- allBandwidths = family.get('addons', [])
- elif family['name'] == "vrack":
- allVRack = family.get('addons', [])
- elif family['name'] == "gpu":
- allGpus = family.get('addons', [])
- if not allMemories: allMemories = ['none']
- if not allStorages: allStorages = ['none']
- if not allBandwidths: allBandwidths = ['none']
- if not allVRack: allVRack = ['none']
- if not allGpus: allGpus = ['none']
- allDatacenters = []
- for config in plan.get('configurations', []):
- if config['name'] == "dedicated_datacenter":
- allDatacenters = config.get('values', [])
- if not allDatacenters: allDatacenters = ['none']
- for da in allDatacenters:
- if not acceptable_dc or da == 'none' or da in acceptable_dc:
- for mem_code in allMemories:
- for st_code in allStorages:
- for ba_code in allBandwidths:
- for vr_code in allVRack:
- for gp_code in allGpus:
- mem_name, mem_addon_price = get_addon_info(mem_code, allAddons, 1)
- st_name, st_addon_price = get_addon_info(st_code, allAddons, 1)
- ba_name, ba_addon_price = get_addon_info(ba_code, allAddons, 1)
- vr_name, vr_addon_price = get_addon_info(vr_code, allAddons, 2)
- gp_name, gp_addon_price = get_addon_info(gp_code, allAddons, 1)
- thisPrice = base_plan_price + mem_addon_price + st_addon_price + ba_addon_price + vr_addon_price + gp_addon_price
- priceStr = "{:.2f}".format(thisPrice)
- shortme = fixMem("-".join(mem_code.split("-")[:-1])) if mem_code != 'none' else 'none'
- shortst = fixSto("-".join(st_code.split("-")[:-1])) if st_code != 'none' else 'none'
- myFqn = planCode + "." + shortme + "." + shortst + "." + da
- myavailability = 'unknown'
- if da != 'none' and shortme != 'none' and shortst != 'none':
- if myFqn in avail_dict:
- myavailability = avail_dict[myFqn]
- elif da == 'none' or shortme == 'none' or shortst == 'none':
- myavailability = 'config_incomplete_for_avail_check'
- myPlans.append({
- 'planCode': planCode,
- 'invoiceName': plan.get('invoiceName', 'N/A'),
- 'datacenter': da,
- 'storage_planCode': st_code, 'storage_name': st_name,
- 'memory_planCode': mem_code, 'memory_name': mem_name,
- 'bandwidth_planCode': ba_code, 'bandwidth_name': ba_name,
- 'vrack_planCode': vr_code, 'vrack_name': vr_name,
- 'gpu_planCode': gp_code, 'gpu_name': gp_name,
- 'price': priceStr,
- 'availability': myavailability
- })
- return myPlans
- # -------------- DUMP LIST OF SERVERS AS CSV (ORIGINAL) ------------------------------
- def dumpPlans(plans):
- with open(outputFileName, 'w') as file:
- file.write("planCode;invoiceName;datacenter;storage;memory;bandwidth;vrack;price;availability\n")
- for plan_item in plans:
- vRackStr = 'none'
- if plan_item['vrack_planCode'] != 'none' and plan_item['vrack_planCode']:
- try:
- vRackStr = plan_item['vrack_planCode'].split("-")[2]
- except IndexError:
- vRackStr = plan_item['vrack_planCode']
- storageStr = "-".join(plan_item['storage_planCode'].split("-")[1:-1]) if plan_item['storage_planCode'] != 'none' and plan_item['storage_planCode'] else 'none'
- 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'
- 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'
- file.write(plan_item['planCode'] + ';' +
- '\"' + plan_item['invoiceName'] + '\"' + ';' +
- plan_item['datacenter'] + ';' +
- storageStr + ';' +
- memoryStr + ';' +
- bandwidthStr + ';' +
- vRackStr + ';' +
- plan_item['price'] + ';' +
- plan_item['availability'] + '\n')
- # -------------- DUMP LIST OF SERVERS AS CSV (WITH READABLE NAMES) ------------------
- def dumpPlansWithReadableNames(plans, filename):
- with open(filename, 'w') as file:
- header = [
- "planCode", "serverInvoiceName", "datacenter",
- "storage_planCode", "storage_name",
- "memory_planCode", "memory_name",
- "bandwidth_planCode", "bandwidth_name",
- "vrack_planCode", "vrack_name",
- "gpu_planCode", "gpu_name",
- "totalPrice", "availability"
- ]
- file.write(";".join(header) + "\n")
- for plan_item in plans:
- row = [
- plan_item.get('planCode', ''),
- f"\"{plan_item.get('invoiceName', 'N/A')}\"",
- plan_item.get('datacenter', ''),
- plan_item.get('storage_planCode', 'none'), f"\"{plan_item.get('storage_name', 'N/A')}\"",
- plan_item.get('memory_planCode', 'none'), f"\"{plan_item.get('memory_name', 'N/A')}\"",
- plan_item.get('bandwidth_planCode', 'none'), f"\"{plan_item.get('bandwidth_name', 'N/A')}\"",
- plan_item.get('vrack_planCode', 'none'), f"\"{plan_item.get('vrack_name', 'N/A')}\"",
- plan_item.get('gpu_planCode', 'none'), f"\"{plan_item.get('gpu_name', 'N/A')}\"",
- plan_item.get('price', '0.00'),
- plan_item.get('availability', 'unknown')
- ]
- file.write(";".join(map(str, row)) + "\n")
- # --------------- MAIN PROGRAM ---------------------------------------------
- if __name__ == "__main__":
- availabilities = buildAvailabilityDict()
- plans = buildList(availabilities)
- if plans:
- dumpPlans(plans)
- dumpPlansWithReadableNames(plans, outputFileNameReadable)
- print(f"Original catalog written to {outputFileName}")
- print(f"Catalog with readable names written to {outputFileNameReadable}")
- else:
- print("No plans generated, CSV files not created.")
Advertisement