异常:AttributeError:使用 Azure Function 和 Python 的“DefaultAzureCredential”对象没有属性“signed_session”

Ste*_*end 8 python azure-sdk-python

我编写了一个运行 Python3 的 Azure 函数来简单地打开 Azure VM。

该函数应用程序具有系统分配的托管标识,我已为其授予 VM 贡献者角色。为了让该函数使用托管标识,我使用了 DefaultAzureCredential() 类。

我得到的错误是: Exception: AttributeError: 'DefaultAzureCredential' object has no attribute 'signed_session' 我已经进行了大量的研究,但似乎找不到解决方案。

这是相关的代码:

from azure.identity import DefaultAzureCredential
credentials = DefaultAzureCredential()
compute_client = ComputeManagementClient(credentials, subscription_id)
# Starting the VM
print('\nStarting VM ' + VM_NAME)
vm_start = compute_client.virtual_machines.start(
    RG_NAME, VM_NAME)
vm_start.wait()
Run Code Online (Sandbox Code Playgroud)

请原谅我,我只是 Python 新手,但对学习非常感兴趣。

小智 7

EDIT May 2022: As of May 2022, all SDKs have been re-released with native support for azure-identity. If you still encounter this error with a given SDK on its latest version, please open an issue asking for a re-release of that SDK here: https://github.com/Azure/azure-sdk-for-python/issues

Original response:

This is addressed here: https://learn.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate?tabs=cmd

Search "Using DefaultAzureCredential with SDK management libraries" on this page and it will take you to the section that covers your problem in more detail.

In a nutshell....

他们更新了 DefaultAzureCredential 类,它不再具有“signed_session”属性。应更新最新版本的管理库来处理此问题。正如另一个解决方案中提到的,更新 azure-cli 库以确保您拥有最新版本。但是,并非所有管理库都已更新。您暂时可以使用由 Azure SDK 工程团队成员创建的这个包装器。 https://gist.github.com/lmazuel/cc683d82ea1d7b40208de7c9fc8de59d

# Wrap credentials from azure-identity to be compatible with SDK that needs msrestazure or azure.common.credentials
# Need msrest >= 0.6.0
# See also https://pypi.org/project/azure-identity/

from msrest.authentication import BasicTokenAuthentication
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
from azure.core.pipeline import PipelineRequest, PipelineContext
from azure.core.pipeline.transport import HttpRequest

from azure.identity import DefaultAzureCredential

class CredentialWrapper(BasicTokenAuthentication):
    def __init__(self, credential=None, resource_id="https://management.azure.com/.default", **kwargs):
        """Wrap any azure-identity credential to work with SDK that needs azure.common.credentials/msrestazure.
        Default resource is ARM (syntax of endpoint v2)
        :param credential: Any azure-identity credential (DefaultAzureCredential by default)
        :param str resource_id: The scope to use to get the token (default ARM)
        """
        super(CredentialWrapper, self).__init__(None)
        if credential is None:
            credential = DefaultAzureCredential()
        self._policy = BearerTokenCredentialPolicy(credential, resource_id, **kwargs)

    def _make_request(self):
        return PipelineRequest(
            HttpRequest(
                "CredentialWrapper",
                "https://fakeurl"
            ),
            PipelineContext(None)
        )

    def set_token(self):
        """Ask the azure-core BearerTokenCredentialPolicy policy to get a token.
        Using the policy gives us for free the caching system of azure-core.
        We could make this code simpler by using private method, but by definition
        I can't assure they will be there forever, so mocking a fake call to the policy
        to extract the token, using 100% public API."""
        request = self._make_request()
        self._policy.on_request(request)
        # Read Authorization, and get the second part after Bearer
        token = request.http_request.headers["Authorization"].split(" ", 1)[1]
        self.token = {"access_token": token}

    def signed_session(self, session=None):
        self.set_token()
        return super(CredentialWrapper, self).signed_session(session)

if __name__ == "__main__":
    import os
    credentials = CredentialWrapper()
    subscription_id = os.environ.get("AZURE_SUBSCRIPTION_ID", "<subscription_id>")

    from azure.mgmt.resource import ResourceManagementClient
    client = ResourceManagementClient(credentials, subscription_id)
    for rg in client.resource_groups.list():
        print(rg.name)
Run Code Online (Sandbox Code Playgroud)

您的代码将如下所示:

from cred_wrapper import CredentialWrapper
credentials = CredentialWrapper()
compute_client = ComputeManagementClient(credentials, subscription_id)
# Starting the VM
print('\nStarting VM ' + VM_NAME)
vm_start = compute_client.virtual_machines.start(
    RG_NAME, VM_NAME)
vm_start.wait()
Run Code Online (Sandbox Code Playgroud)

你应该从那里做饭!


Ste*_*end 2

如果您使用 azure-mgmt-compute (17.0.0b1) 的预览版,该问题似乎已修复

由于版本升级的另一个问题是他们将启动函数从 start 更改为 begin_start。

希望这对某人有帮助!