23

So I have the following Python3 script to list all virtual machines.

import os, json
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.resource import ResourceManagementClient, SubscriptionClient
from azure.common.credentials import ServicePrincipalCredentials

credentials = ServicePrincipalCredentials(
        client_id="xxx",
        secret="xxx",
        tenant="xxx"
        )

resource_client = ResourceManagementClient(credentials, "my-subscription")
compute_client = ComputeManagementClient(credentials, "my-subscription")
network_client = NetworkManagementClient(credentials, "my-subscription")

for vm in compute_client.virtual_machines.list_all():
    print("\tVM: {}".format(vm.name))

but for some reason, I get the following error:

Traceback (most recent call last):
  File "/Users/me/a/azure-test.py", line 17, in <module>
    for vm in compute_client.virtual_machines.list_all():
...
  File "/usr/local/lib/python3.8/site-packages/azure/core/pipeline/policies/_authentication.py", line 93, in on_request
    self._token = self._credential.get_token(*self._scopes)
AttributeError: 'ServicePrincipalCredentials' object has no attribute 'get_token'

Am I doing something wrong?

Bhargavi Annadevara
  • 4,923
  • 2
  • 13
  • 30
dom_weissb03
  • 415
  • 2
  • 5
  • 8

2 Answers2

43

The Azure libraries for Python are currently being updated to share common cloud patterns such as authentication protocols, logging, tracing, transport protocols, buffered responses, and retries.

This would change the Authentication mechanism a bit as well. In the older version, ServicePrincipalCredentials in azure.common was used for authenticating to Azure and creating a service client.

In the newer version, the authentication mechanism has been re-designed and replaced by azure-identity library in order to provide unified authentication based on Azure Identity for all Azure SDKs. Run pip install azure-identity to get the package.

In terms of code, what then was:

from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient

credentials = ServicePrincipalCredentials(
    client_id='xxxxx',
    secret='xxxxx',
    tenant='xxxxx'
)

compute_client = ComputeManagementClient(
    credentials=credentials,
    subscription_id=SUBSCRIPTION_ID
)

is now:

from azure.identity import ClientSecretCredential
from azure.mgmt.compute import ComputeManagementClient

credential = ClientSecretCredential(
    tenant_id='xxxxx',
    client_id='xxxxx',
    client_secret='xxxxx'
)

compute_client = ComputeManagementClient(
    credential=credential,
    subscription_id=SUBSCRIPTION_ID
)

You can then use the list_all method with compute_client to list all VMs as usual:

# List all Virtual Machines in the specified subscription
def list_virtual_machines():
    for vm in compute_client.virtual_machines.list_all():
        print(vm.name)

list_virtual_machines()

References:

Bhargavi Annadevara
  • 4,923
  • 2
  • 13
  • 30
4

Incase of Azure sovereign cloud (AZURE_PUBLIC_CLOUD, AZURE_CHINA_CLOUD, AZURE_US_GOV_CLOUD, AZURE_GERMAN_CLOUD), accepted answer would extends to below code snippet.

from azure.identity import ClientSecretCredential
from azure.mgmt.compute import ComputeManagementClient
from msrestazure.azure_cloud import AZURE_US_GOV_CLOUD as cloud_env

credential = ClientSecretCredential(
    tenant_id='xxxxx',
    client_id='xxxxx',
    client_secret='xxxxx',
    authority=cloud_env.endpoints.active_directory
)

compute_client = ComputeManagementClient(
    credential=credential,
    subscription_id=SUBSCRIPTION_ID
    base_url=cloud_env.endpoints.resource_manager,
    credential_scopes=[cloud_env.endpoints.resource_manager + ".default"]
)
  • Thank you for pointing that out! It saved my day, but the `credential_scopes` must be corrected. It should be with a slash at the end: `credential_scopes=[cloud_env.endpoints.resource_manager + "/.default"]` Elsewise I got: "azure.core.exceptions.ClientAuthenticationError: Authentication failed: AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid." – ralfzen Jul 13 '22 at 09:33