Stage 7 · Master
Cloud SDKs & Azure Automation
Managing Azure Resources
Create, list, delete VMs, AKS clusters, and storage accounts via SDK.
Resource Groups
Resource groups are containers for Azure resources. All resources must belong to a resource group. Managing resource groups is the foundation of Azure automation.
from azure.identity import DefaultAzureCredential
from azure.mgmt.resource import ResourceManagementClient
from azure.core.exceptions import ResourceExistsError
credential = DefaultAzureCredential()
client = ResourceManagementClient(credential, "subscription-id")
# Create a resource group
try:
rg = client.resource_groups.create_or_update(
"my-rg",
{"location": "eastus", "tags": {"env": "dev", "team": "platform"}},
)
print(f"Created resource group: {rg.name}")
except ResourceExistsError:
print("Resource group already exists")
# List all resource groups
for rg in client.resource_groups.list():
print(f"{rg.name} ({rg.location})")
# Delete a resource group and all its resources
client.resource_groups.begin_delete("dev-rg").result()
print("Deleted dev-rg")create_or_update is idempotent — it creates the resource group if it does not exist, or updates it if it does. This is the standard pattern for all Azure SDK operations.
Virtual Machines
from azure.identity import DefaultAzureCredential
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.resource import ResourceManagementClient
credential = DefaultAzureCredential()
sub_id = "subscription-id"
compute_client = ComputeManagementClient(credential, sub_id)
network_client = NetworkManagementClient(credential, sub_id)
resource_client = ResourceManagementClient(credential, sub_id)
# Ensure resource group exists
resource_client.resource_groups.create_or_update("vm-rg", {"location": "eastus"})
# Create a public IP address
poller = network_client.public_ip_addresses.begin_create_or_update(
"vm-rg", "my-pip",
{"location": "eastus", "sku": {"name": "Standard"}, "public_ip_allocation_method": "Static"},
)
pip = poller.result()
# Create a VM
vm_params = {
"location": "eastus",
"hardware_profile": {"vm_size": "Standard_B2s"},
"os_profile": {
"computer_name": "myvm",
"admin_username": "azureuser",
"admin_password": "ComplexPassword123!", # In production, use SSH keys
},
"storage_profile": {
"image_reference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "22_04-lts",
"version": "latest",
},
"os_disk": {"create_option": "FromImage", "disk_size_gb": 30},
},
"network_profile": {
"network_interfaces": [{"id": f"/subscriptions/{sub_id}/resourceGroups/vm-rg/providers/Microsoft.Network/networkInterfaces/my-nic"}]
},
}
poller = compute_client.virtual_machines.begin_create_or_update("vm-rg", "my-vm", vm_params)
vm = poller.result()
print(f"VM created: {vm.name}")VM creation requires networking, storage, and compute resources. Each SDK client manages its own resource type. The pattern is always: create dependencies, then create the main resource.
Storage Accounts
from azure.identity import DefaultAzureCredential
from azure.mgmt.storage import StorageManagementClient
credential = DefaultAzureCredential()
client = StorageManagementClient(credential, "subscription-id")
# Create a storage account
poller = client.storage_accounts.begin_create(
"my-rg",
"mystorageaccount123", # Must be globally unique, 3-24 chars, lowercase
{
"location": "eastus",
"sku": {"name": "Standard_LRS"},
"kind": "StorageV2",
"tags": {"env": "dev"},
},
)
account = poller.result()
print(f"Storage account: {account.name}")
# List storage accounts
for account in client.storage_accounts.list():
print(f"{account.name}: {account.sku.name}")
# Get storage account keys
keys = client.storage_accounts.list_keys("my-rg", account.name)
for key in keys.keys:
print(f"Key {key.key_name}: {key.value[:20]}...")Storage account names must be globally unique across all of Azure. Use a naming convention like {project}{env}{region} to avoid collisions.
AKS Clusters
from azure.identity import DefaultAzureCredential
from azure.mgmt.containerservice import ContainerServiceClient
credential = DefaultAzureCredential()
client = ContainerServiceClient(credential, "subscription-id")
# List AKS clusters
for cluster in client.managed_clusters.list():
print(f"{cluster.name}: {cluster.provisioning_state}")
print(f" Kubernetes version: {cluster.kubernetes_version}")
print(f" Node count: {cluster.agent_pool_profiles[0].count}")
# Get cluster credentials
cred_result = client.managed_clusters.list_cluster_admin_user_credentials(
"my-rg", "my-aks-cluster"
)
for cred in cred_result.kubeconfigs:
print(f"Cluster: {cred.name}")
# cred.value contains the kubeconfig contentAKS clusters take 10-15 minutes to create. Use begin_create_or_update for long-running operations. The SDK handles polling automatically.
Tags and Labels
from azure.identity import DefaultAzureCredential
from azure.mgmt.resource import ResourceManagementClient
credential = DefaultAzureCredential()
client = ResourceManagementClient(credential, "subscription-id")
# Tag all resources in a resource group
for resource in client.resources.list_by_resource_group("my-rg"):
client.resources.update_by_id(
resource.id,
api_version="2021-04-01",
{
"tags": {
**(resource.tags or {}),
"team": "platform",
"cost-center": "engineering",
"managed-by": "python-automation",
}
},
)
# Find resources by tag
resources = client.resources.list(
filter="tags.env eq 'production' and tags.team eq 'platform'"
)
for r in resources:
print(f"{r.type.split('/')[-1]}: {r.name}")Tags are key-value pairs applied to resources. Use them for cost allocation, environment identification, and automation filtering. Azure Policy can enforce required tags.
Cleanup Automation
from azure.identity import DefaultAzureCredential
from azure.mgmt.resource import ResourceManagementClient
from datetime import datetime, timedelta
credential = DefaultAzureCredential()
client = ResourceManagementClient(credential, "subscription-id")
def cleanup_old_resources(resource_group: str, max_age_days: int = 30):
"""Delete resources older than max_age_days."""
cutoff = datetime.utcnow() - timedelta(days=max_age_days)
deleted = []
for resource in client.resources.list_by_resource_group(resource_group):
if resource.created_at and resource.created_at < cutoff:
try:
client.resources.begin_delete_by_id(
resource.id, api_version="2021-04-01"
).result()
deleted.append(resource.name)
print(f"Deleted: {resource.name}")
except Exception as e:
print(f"Failed to delete {resource.name}: {e}")
print(f"Cleaned up {len(deleted)} resources")
return deleted
# Delete dev resources older than 7 days
cleanup_old_resources("dev-rg", max_age_days=7)Automated cleanup prevents resource sprawl. Tag resources with creation date and use that to identify old resources. Always log what you delete.
Azure operations like VM creation can take minutes. The SDK returns a poller that tracks the operation. Always use begin_create_or_update and call .result() to wait for completion.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.