Skip to content

Commit 6c953e7

Browse files
authored
script across subs
1 parent 468f91a commit 6c953e7

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
Azure MySQL Flexible Server Auto IOPS Enabler
3+
4+
This script connects to Azure using the Azure CLI and Azure REST API to:
5+
1. Retrieve the current subscription ID.
6+
2. List all Resource Groups in the current subscription.
7+
3. List all MySQL Flexible Servers in each resource group.
8+
4. Skip resource groups with no MySQL Flexible Servers.
9+
5. Check if each server is eligible for Auto IOPS scaling (only GeneralPurpose or BusinessCritical tiers).
10+
6. Optionally enable Auto IOPS scaling if not already enabled.
11+
7. Print a summary of which servers were updated or skipped.
12+
"""
13+
14+
import subprocess
15+
import requests
16+
import shutil
17+
from azure.identity import AzureCliCredential
18+
19+
SUPPORTED_TIERS = {"GeneralPurpose", "BusinessCritical"}
20+
21+
def mask_value(value, start=4, end=4):
22+
return value[:start] + '*' * (len(value) - start - end) + value[-end:]
23+
24+
def get_subscription_id():
25+
az_path = shutil.which("az")
26+
if az_path is None:
27+
raise FileNotFoundError("Azure CLI (az) not found in system PATH.")
28+
result = subprocess.check_output([az_path, "account", "show", "--query", "id", "-o", "tsv"], text=True)
29+
return result.strip()
30+
31+
def get_access_token():
32+
credential = AzureCliCredential()
33+
token = credential.get_token("https://management.azure.com/.default")
34+
return token.token
35+
36+
def list_resource_groups(subscription_id, access_token):
37+
url = f"https://management.azure.com/subscriptions/{subscription_id}/resourcegroups?api-version=2024-06-01-preview"
38+
headers = {"Authorization": f"Bearer {access_token}"}
39+
response = requests.get(url, headers=headers)
40+
response.raise_for_status()
41+
return response.json()
42+
43+
def list_mysql_servers(subscription_id, resource_group, access_token):
44+
url = (
45+
f"https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/"
46+
f"{resource_group}/providers/Microsoft.DBforMySQL/flexibleServers?api-version=2024-06-01-preview"
47+
)
48+
headers = {"Authorization": f"Bearer {access_token}"}
49+
response = requests.get(url, headers=headers)
50+
if response.status_code == 404:
51+
return {"value": []}
52+
response.raise_for_status()
53+
return response.json()
54+
55+
def get_server_config(subscription_id, resource_group, server_name, access_token):
56+
url = (
57+
f"https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/{resource_group}/"
58+
f"providers/Microsoft.DBforMySQL/flexibleServers/{server_name}?api-version=2024-06-01-preview"
59+
)
60+
headers = {"Authorization": f"Bearer {access_token}"}
61+
response = requests.get(url, headers=headers)
62+
response.raise_for_status()
63+
return response.json()
64+
65+
def enable_auto_io_scaling_put(subscription_id, resource_group, server_name, access_token):
66+
url = (
67+
f"https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/{resource_group}/"
68+
f"providers/Microsoft.DBforMySQL/flexibleServers/{server_name}?api-version=2024-06-01-preview"
69+
)
70+
headers = {
71+
"Authorization": f"Bearer {access_token}",
72+
"Content-Type": "application/json"
73+
}
74+
payload = {
75+
"properties": {
76+
"storage": {
77+
"autoIoScaling": "Enabled"
78+
}
79+
}
80+
}
81+
response = requests.patch(url, headers=headers, json=payload)
82+
print(f"PATCH Response: {response.status_code} - {response.text}")
83+
response.raise_for_status()
84+
return response.json()
85+
86+
def main():
87+
try:
88+
print("Script started")
89+
subscription_id = get_subscription_id()
90+
print(f"Using subscription: {mask_value(subscription_id)}")
91+
92+
access_token = get_access_token()
93+
print(f"Access Token: {mask_value(access_token[:10])}...")
94+
95+
resource_groups = list_resource_groups(subscription_id, access_token)
96+
eligible_servers = []
97+
ineligible_servers = []
98+
99+
for rg in resource_groups.get("value", []):
100+
rg_name = rg["name"]
101+
servers = list_mysql_servers(subscription_id, rg_name, access_token).get("value", [])
102+
103+
if not servers:
104+
print(f"[SKIP] No MySQL Flexible Servers found in resource group: {rg_name}")
105+
continue
106+
107+
print(f"\nMySQL Flexible Servers in {rg_name}:")
108+
for server in servers:
109+
print(f" - {server['name']}")
110+
111+
target_server = input(f"Enter a specific server name in {rg_name} (or press Enter to apply to all): ").strip()
112+
113+
for server in servers:
114+
server_name = server["name"]
115+
if target_server and server_name.lower() != target_server.lower():
116+
continue
117+
118+
config = get_server_config(subscription_id, rg_name, server_name, access_token)
119+
tier = config["sku"]["tier"]
120+
auto_io = config["properties"]["storage"].get("autoIoScaling", "Disabled")
121+
122+
if tier not in SUPPORTED_TIERS:
123+
ineligible_servers.append((server_name, tier))
124+
continue
125+
126+
if auto_io == "Enabled":
127+
print(f"[SKIP] Auto IOPS already enabled for {server_name}")
128+
continue
129+
130+
print(f"[UPDATE] Enabling Auto IOPS for {server_name} (Tier: {tier})...")
131+
enable_auto_io_scaling_put(subscription_id, rg_name, server_name, access_token)
132+
eligible_servers.append(server_name)
133+
134+
print("\nSummary:")
135+
if eligible_servers:
136+
print("Auto IOPS enabled for:")
137+
for name in eligible_servers:
138+
print(f" - {name}")
139+
else:
140+
print("No servers were updated.")
141+
142+
if ineligible_servers:
143+
print("\nIneligible servers (unsupported tier):")
144+
for name, tier in ineligible_servers:
145+
print(f" - {name} (Tier: {tier})")
146+
147+
except Exception as e:
148+
print(f"Error: {e}")
149+
150+
if __name__ == "__main__":
151+
main()

0 commit comments

Comments
 (0)