Search code examples
pythonazureazure-management-apiazure-python-sdk

Cannot get Azure subscriptions using Azure Python SDK


I can get Azure subscriptons list using REST API.

However, when I'm switching to Azure Python SDK, there seems to be some problems.

This is the code so far:

from azure.identity.aio import ClientSecretCredential
from azure.mgmt.resource import SubscriptionClient
import json

data = json.load(open("parameters.json"))

credential = ClientSecretCredential(
    tenant_id=data["tenant"],
    client_id=data["client_id"],
    client_secret=data["client_secret"],
)

subs = SubscriptionClient(credential=credential)
l = list(subs.subscriptions.list())
print(l)

I use an additional list in the pnultimate line because subs.subscriptions.list() returns an iterator. Despite that, the code seems pretty straightforward.

However, this code gives the following error:

Traceback (most recent call last):
  File "c:\Users\azureuser\Documents\GitHub\vmss-scripts\vm_create.py", line 14, in <module>
    l = list(subs.subscriptions.list())
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\paging.py", line 123, in __next__
    return next(self._page_iterator)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\paging.py", line 75, in __next__
    self._response = self._get_next(self.continuation_token)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\mgmt\resource\subscriptions\v2022_12_01\operations\_operations.py", line 526, in get_next
    pipeline_response: PipelineResponse = self._client._pipeline.run(  # pylint: disable=protected-access
                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\_base.py", line 230, in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\_base.py", line 86, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\_base.py", line 86, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\_base.py", line 86, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 2 more times]
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\mgmt\core\policies\_base.py", line 46, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\policies\_redirect.py", line 197, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\policies\_retry.py", line 531, in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\policies\_authentication.py", line 124, in send
    self.on_request(request)
  File "C:\Users\azureuser\scoop\apps\python\current\Lib\site-packages\azure\core\pipeline\policies\_authentication.py", line 100, in on_request
    self._update_headers(request.http_request.headers, self._token.token)
                                                       ^^^^^^^^^^^^^^^^^
AttributeError: 'coroutine' object has no attribute 'token'
sys:1: RuntimeWarning: coroutine 'GetTokenMixin.get_token' was never awaited

I don't know what was missing, and the error didn't gives much information.

It seems it was related with token. I can get a token with the following method:

async def print_token():
    token = await credential.get_token("https://management.azure.com/.default")
    print(token.token)
    await credential.close()

asyncio.run(print_token())

But it requires asyncio to run, which isn't compatible with my code. And where should I should put the token?

I've investigated the source code if Azure CLI. It seems it get subscriptions using the same method: https://github.com/Azure/azure-cli/blob/f369cead2604e37480611b0cc269fee615956ea2/src/azure-cli-core/azure/cli/core/_profile.py#L835

The client was acqurired from the function below, and the type was

https://github.com/Azure/azure-cli/blob/f369cead2604e37480611b0cc269fee615956ea2/src/azure-cli-core/azure/cli/core/profiles/_shared.py#L60

Which is essentially the SubscriptionClient.


Solution

  • Initially, I too got same error when I ran your code in my environment like this:

    from azure.identity.aio import ClientSecretCredential
    from azure.mgmt.resource import SubscriptionClient
    import json
    
    data = json.load(open("parameters.json"))
    
    credential = ClientSecretCredential(
        tenant_id=data["tenant"],
        client_id=data["client_id"],
        client_secret=data["client_secret"],
    )
    
    subs = SubscriptionClient(credential=credential)
    l = list(subs.subscriptions.list())
    print(l)
    

    Response:

    enter image description here

    To list subscriptions using Azure Python SDK without asyncio module, make use of below modified code:

    from azure.identity import ClientSecretCredential
    from azure.mgmt.resource import SubscriptionClient
    import json
    
    with open("parameters.json") as f:
        data = json.load(f)
    
    credential = ClientSecretCredential(
        tenant_id=data["tenant"],
        client_id=data["client_id"],
        client_secret=data["client_secret"],
    )
    
    subs_client = SubscriptionClient(credential)
    
    subscriptions = subs_client.subscriptions.list()
    
    for subscription in subscriptions:
        #print(f"Subscription ID: {subscription.subscription_id}, Display Name: {subscription.display_name}")
        print(json.dumps(subscription.as_dict(), indent=2))
    

    Response:

    enter image description here