-
Notifications
You must be signed in to change notification settings - Fork 2
/
azure_vm_pricing_cli.py
159 lines (142 loc) · 7.78 KB
/
azure_vm_pricing_cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import json
import urllib.request as request
import inquirer
import yaspin
from tabulate import tabulate
from colorama import init, Fore, Style
import pandas as pd
@yaspin.yaspin(text="Fetching Azure VM SKUs")
def fetch_virtual_machine_sku_prices(virtual_machine_calculator_api='https://azure.microsoft.com/api/v3/pricing/virtual-machines/calculator/?culture=en-us¤cy=$currency'):
try:
response=request.urlopen(virtual_machine_calculator_api)
data = response.read()
jsondata = json.loads(data)
return jsondata
except Exception as e:
print(f"Error occurred while fetching virtual machine prices: {e}")
def ensure_selection(func):
def wrapper(*args, **kwargs):
# Ensure the decorator only enforces selection for checkbox menus
if 'checkbox' in args:
while True:
answers = func(*args, **kwargs)
if answers:
return answers
print(Fore.RED, "Please select at least one option.\n" + Style.RESET_ALL)
else:
# For list menus, just call the function once
return func(*args, **kwargs)
return wrapper
@ensure_selection
def invoke_menu(menu_data, display_name_fallback,message_item,menu_type='list'):
choices = [(md.get('displayName',display_name_fallback),md['slug']) for md in menu_data]
question_type = inquirer.List if menu_type.lower() == 'list' else inquirer.Checkbox
questions = [
question_type('selected_item', message=f"Please select {message_item}", choices=choices),
]
answers = inquirer.prompt(questions)
return answers['selected_item']
def create_sku_string(os_software_selection,instance_selection):
sku=f"{'windows' if os_software_selection == 'windows-os' else os_software_selection}-{instance_selection}-standard"
return sku
def create_spec_display_string(os_software_selection,instance_selection,data):
sku=create_sku_string(os_software_selection,instance_selection)
offer=get_offer_sku(sku,data,'payg')
size_display_items = [item for item in data['sizesPayGo'] if item['slug'] == instance_selection]
size_display = size_display_items[0]['displayName']
disk_size = offer.get('diskSize',0)
return f"Size: {size_display} Cpu: {offer['cores']} Cores, Ram: {offer['ram']} GB, Disk: {disk_size} GB"
def create_instance_data(instance_data,os_software_selection,data):
updated_data = [{'slug': item['slug'], 'displayName': create_spec_display_string(os_software_selection,item['slug'],data)} for item in instance_data]
return updated_data
def get_offer_sku(sku,data,plan,return_string=False):
sku_items = data['skus'][sku][plan]
sku_items_corrected = [element.split('--')[0] for element in sku_items]
for sku in sku_items_corrected:
# Iterate over each offer in the data
offer = data['offers'][sku]
#print(f"getting sku for{offer}")
# Check if the SKU is in the current offer and if 'global' key is not present
if 'global' not in offer['prices']['perhour'].keys() :
if return_string:
return data['offers'][sku]
return offer
def get_vm_offer_skus(data,sku):
return data['skus'][sku]
def get_pricing_models():
return [
{'slug': 'payg', 'displayName': 'Pay as you go'},
{'slug': 'spot', 'displayName': 'Spot'},
{'slug': 'one-year', 'displayName': '1 Year Reserved'},
{'slug': 'three-year', 'displayName': '3 Year Reserved'},
{'slug': 'sv-one-year', 'displayName': '1 Year Savings Plan'},
{'slug': 'sv-three-year', 'displayName': '3 Year Savings Plan'},
{'slug': 'ahb', 'displayName': 'Pay as you go with AHB'},
{'slug': 'ahbspot', 'displayName': 'Spot with AHB'},
{'slug': 'ahb-oneyear', 'displayName': '1 Year Reserved with AHB'},
{'slug': 'ahb-threeyear', 'displayName': '3 Year Reserved with AHB'},
{'slug': 'ahbsv-one-year', 'displayName': '1 Year Savings Plan with AHB'},
{'slug': 'ahbsv-three-year', 'displayName': '3 Year Savings Plan with AHB'}
]
def get_pricing_model_display_name(pricing_model_slug,pricing_models):
pricing_model = [pm for pm in pricing_models if pm.get('slug') == pricing_model_slug][0]
return pricing_model['displayName']
def main():
# initialize colorama
init()
# fetch data from the Azure VM pricing API
data = fetch_virtual_machine_sku_prices()
software_licenses = data['softwareLicenses']
os_software_selection=invoke_menu(software_licenses, 'Windows','OS/Software')
categories= data['dropdown']
category_selection=invoke_menu(categories, 'all','Category')
vm_series_info = [c for c in categories if c.get('slug') == category_selection][0]
vm_series = vm_series_info['series']
vm_series_selection=invoke_menu(vm_series, 'all','VM Series')
vm_serie = [vs for vs in vm_series if vs.get('slug') == vm_series_selection][0]
instances = vm_serie['instances']
updated_instances = create_instance_data(instances,os_software_selection,data)
instance_selection = invoke_menu(updated_instances, 'all','VM Type')
sku=f"{'windows' if os_software_selection == 'windows-os' else os_software_selection}-{instance_selection}-standard"
print(f"Selected SKU: {sku}")
region_price_list=[]
regions = data['regions']
region_selection=invoke_menu(regions, 'all','Region','checkbox')
print(f"Selected Regions: {region_selection}")
pricing_models = get_pricing_models()
pricing_model_selection=invoke_menu(pricing_models, 'Pay as you go','Pricing Model','checkbox')
offer_skus = get_vm_offer_skus(data,sku)
offer_sku_keys = offer_skus.keys()
for region in region_selection:
for pricing_model in offer_sku_keys:
if pricing_model in pricing_model_selection:
offer=offer_skus[pricing_model]
region_price=0
for offer_name_raw in offer:
offer_info=offer_name_raw.split('--')
offer_name = offer_info[0]
offer_pricing_type=offer_info[1]
region_exists = data['offers'][offer_name]['prices'][offer_pricing_type].get(region)
#print(f"Offer Name: {offer_name}")
if 'global' in data['offers'][offer_name]['prices'][offer_pricing_type].keys() and region_exists:
region_price += data['offers'][offer_name]['prices'][offer_pricing_type]['global'].get('value')
else:
try:
region_price += data['offers'][offer_name]['prices'][offer_pricing_type].get(region).get('value')
except:
#region ha no price
region_price += 0
#region_price_list.append({"region":region,"Pricing Model":get_pricing_model_display_name(pricing_model,pricing_models),"pricing_type":offer_pricing_type,"hourly_price":region_price,"monthly_price":region_price*730})
region_price_list.append({"region":region,"Pricing Model":get_pricing_model_display_name(pricing_model,pricing_models),"monthly_price":region_price*730})
"""
table_headers = region_price_list[0].keys()
table_rows = [vs.values() for vs in region_price_list]
print(tabulate(table_rows, headers=table_headers, tablefmt="grid"))
"""
df = pd.DataFrame(region_price_list)
pivot_table = df.pivot_table(index=['region'], columns=['Pricing Model'],values=['monthly_price'])
pivot_table_flat = pivot_table.reset_index()
pivot_table_flat.columns = [f'{level1}' if level1=='region' else level2 for level1,level2 in pivot_table_flat.columns.values]
print(tabulate(pivot_table_flat, headers='keys', tablefmt='grid'))
if __name__ == "__main__":
main()