Skip to content

Commit af031ac

Browse files
authored
Merge edc8497 into 7fb234e
2 parents 7fb234e + edc8497 commit af031ac

2 files changed

Lines changed: 154 additions & 2 deletions

File tree

autoscaleMultiple-IOPS/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Last updated: 2025-05-13
2929

3030
## By Resource Group
3131

32-
> Overall process: <br/> (./scripts/enable_autoscale_iops_byRG.py)
32+
> Overall process: <br/>
3333
>
3434
> - Automatically retrieves your **Azure subscription ID** using the Azure CLI. <br/>
3535
> - List all Resource Groups in current subscription ID. <br/>
@@ -41,7 +41,7 @@ Review [the script](./scripts/enable_autoscale_iops_byRG.py), and download it to
4141

4242
> Example: enabling Autoscale IOPS on two different servers, each hosted in same resource group and same subscription.
4343
44-
<img width="550" alt="image" src="" />
44+
<https://github.com/user-attachments/assets/4c087afe-6fa1-40cb-bb2f-ef912edb974d>
4545

4646
## Across a Subscription
4747

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

0 commit comments

Comments
 (0)