DEV Community

holger
holger

Posted on

Azure SDK for Python - How to check for Available Resource Names

If we wanted to check in Azure whether or not a given resource name is still available, we can do so relatively easily within the Azure Portal by navigating to the All resources blade, making sure the subscription filter has all relevant subscriptions in scope and typing in the name that we want to check.

Search Resources in the Azure Portal

This is fine for a manual approach - but how could we do this programmatically?

Azure REST API

One option would be to use the Azure REST API [1]. Most Azure services include a REST API capability for checking for available resource names - let's take Storage Accounts as an example [2].

We could create a POST request against https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Storage/checkNameAvailability?api-version=2022-09-01 in order to verify the availability:

from azure.identity import AzureCliCredential
import requests

credential = AzureCliCredential()
access_token = credential.get_token("https://management.core.windows.net/")
bearer_token = f"Bearer {access_token.token}"

r_url = 'https://management.azure.com/subscriptions/{subscription_id}/providers/Microsoft.Storage/checkNameAvailability?api-version=2022-09-01'
r_header = {'Content-Type': 'application/json', 'Authorization' : bearer_token}
r_body = {'name': '{storage_account_name}','type': 'Microsoft.Storage/storageAccounts'}

result = requests.post(headers=r_header,url=r_url,json=r_body)

print(result.json())
Enter fullscreen mode Exit fullscreen mode

If the storage account name was already used, the response should be:

{'nameAvailable': False, 'reason': 'AlreadyExists', 'message': 'The storage account named storage_account_name is already taken.'}
Enter fullscreen mode Exit fullscreen mode

Otherwise, the response would simply be:

{'nameAvailable': True}
Enter fullscreen mode Exit fullscreen mode

As you can see, this works well, however, there are drawbacks:

  • Not all Azure services offer the capability for checking the available name through the Azure REST API.
  • If they do, we need to know the REST API URL.
  • We can only run the query against a single subscription.

To resolve the third point, we could first receive a list of available subscriptions and then iterate through each subscription and query the REST API on a per-subscription basis. This would work as well, however the other two drawbacks would still apply.

Azure SDK for Python

A simpler approach - since we are using Python anyways in this example - would be to use the Azure SDK for Python [6].

from azure.identity import AzureCliCredential
from azure.mgmt.storage import StorageManagementClient
credential = AzureCliCredential()

subscription_id = '{subscription_id}'
storage_account_name = '{storage_account_name}'

storage_client = StorageManagementClient(credential, subscription_id)



availability_result = storage_client.storage_accounts.check_name_availability(
    { 
        "name": storage_account_name
    }
)

print(availability_result)
Enter fullscreen mode Exit fullscreen mode

Similar to what we saw when querying the Azure REST API, the result indicating that the name was already used would look like this:

{'additional_properties': {}, 'name_available': False, 'reason': 'AlreadyExists', 'message': 'The storage account named storage_account_name is already taken.'}
Enter fullscreen mode Exit fullscreen mode

If the name was still available, the response would be:

{'additional_properties': {}, 'name_available': True, 'reason': None, 'message': None}
Enter fullscreen mode Exit fullscreen mode

This approach includes similar drawbacks as using the REST API directly.

  • Not all Azure services offer the capability for checking the available name.
  • If they, do we need to import the corresponding Python library.
  • We can only run the query against a single subscription.

Again, the last point can be remediated by using the SubscriptionClient Class [4], generating a list of subscription id's and iterating through it - however, the approach might not be very flexible.

Azure Resource Graph

Fortunately, Azure offers a great capability called Azure Resource Graph [3], which we can also use through the Azure SDK for Python.

Below, we see two functions created. resource_graph_query is used to run a query against Azure Resource Graph [5]. check_name_availability is then used to create and execute the query against a specific name - and optionally, resource type.

from azure.identity import AzureCliCredential
from azure.mgmt.resource import SubscriptionClient
import azure.mgmt.resourcegraph as arg

credential = AzureCliCredential()

def resource_graph_query( query ):
    # Get your credentials from Azure CLI (development only!) and get your subscription list
    subs_client = SubscriptionClient(credential)
    subscriptions_dict = []

    for subscription in subs_client.subscriptions.list():
        subscriptions_dict.append(subscription.as_dict())

    subscription_ids_dict = []

    for subscription in subscriptions_dict:
        subscription_ids_dict.append(subscription.get('subscription_id'))

    # Create Azure Resource Graph client and set options
    resource_graph_client = arg.ResourceGraphClient(credential)
    resource_graph_query_options = arg.models.QueryRequestOptions(result_format="objectArray")

    # Create query
    resource_graph_query = arg.models.QueryRequest(subscriptions=subscription_ids_dict, query=query, options=resource_graph_query_options)

    # Run query
    resource_graph_query_results = resource_graph_client.resources(resource_graph_query)

    # Show Python object
    return resource_graph_query_results

def check_name_availability(resource_name, resource_type=None):

    if(resource_type):
        rg_query = f"Resources | where name =~ '{resource_name}' | where type =~ '{resource_type}'"
    else:
        rg_query = f"Resources | where name =~ '{resource_name}'"


    rg_results = resource_graph_query(rg_query)

    results_dict = []

    if(rg_results.data):
        availability = False
    else:
        availability = True

    results_dict = dict({
        'resource_name': resource_name,
        'available': availability
    })

    return results_dict

r_name = '{storage_account_name}'
r_type = 'Microsoft.Storage/storageAccounts'

result = check_name_availability(resource_name=r_name, resource_type=r_type)

print(result)
Enter fullscreen mode Exit fullscreen mode

Thanks to Azure Resource Graph, we can just pass a list of subscription id's and query them all at once with a single call. Particularly when checking hundreds or thousands of subscriptions at once, Resource Graph improves performance significantly.

Furthermore, this approach prevents us from having to pass in exact REST API URLs or import Python libraries for the individual Azure resources that we are querying.

The results of above code would be like this (but could obviously be improved or extended) if the resource existed already:

{'resource_name': 'storage_account_name', 'available': False}
Enter fullscreen mode Exit fullscreen mode

Contrarily, if the resource did not exist yet, the response would be True:

{'resource_name': 'storage_account_name', 'available': True}
Enter fullscreen mode Exit fullscreen mode

References

Top comments (0)