【问题标题】:Azure SDK Python: tag a particular resourceAzure SDK Python:标记特定资源
【发布时间】:2016-12-23 20:23:53
【问题描述】:

我想使用 python 在 Azure 中的每个资源上创建标签。

我在文档中看到了这个模块: http://azure-sdk-for-python.readthedocs.io/en/latest/ref/azure.mgmt.resource.resources.operations.html#azure.mgmt.resource.resources.operations.TagsOperations

create_or_update:创建订阅资源标签 list:获取订阅资源标签列表

好像只能对资源组做标签操作,不能对资源做标签操作?

例子:

向资源组添加标签:Set-AzureRmResourceGroup 为资源添加标签:Set-AzureRmResource

编辑:

感谢 api 查找代码,非常简洁。但我相信我手动放置的旧 api 也应该可以工作。我尝试了您的代码,几乎没有修改(我们可能有不同的 Azure SDK,我使用的是 2.0.0rc5)。添加api函数后(非常有帮助),不幸的是我仍然有同样的错误。

from azure.common.credentials import UserPassCredentials
from azure.mgmt.resource.resources import ResourceManagementClient

def resolve_resource_api(client, resource):
    """ This method retrieves the latest non-preview api version for
    the given resource (unless the preview version is the only available
    api version) """
    provider = client.providers.get(resource.id.split('/')[6])
    rt = next((t for t in provider.resource_types
               if t.resource_type == '/'.join(resource.type.split('/')[1:])), None)
    #print(rt)
    if rt and 'api_versions' in rt.__dict__:
        #api_version = [v for v in rt[0].api_versions if 'preview' not in v.lower()]
        #return npv[0] if npv else rt[0].api_versions[0]
        api_version = [v for v in rt.__dict__['api_versions'] if 'preview' not in v.lower()]
        return api_version[0] if api_version else rt.__dict__['api_versions'][0]

credentials = UserPassCredentials(
    '****@****.com',    # Your new user
    '******',  # Your password
)

subscription_id= '*****-***-****-****-*******'

resource_client = ResourceManagementClient(credentials,
                                                    subscription_id)

for resource in resource_client.resources.list():
    #print(resource)
    #print(resolve_resource_api(resource_client, resource))
    if resource.id.split('/')[4] == 'Build':
        #resource.tags = {'foo':'bar'}
        if resource.type == 'Microsoft.Web/sites':
            print('resource.id: ', resource.id)
            print('resource_group_name: ', resource.id.split('/')[4])
            print('resource_provider_namespace: ', resource.id.split('/')[6])
            print('parent_resource_path: ', '')
            print('resource_type: ', str(resource.type).split('/')[-1])
            print('resource_name: ', resource.name)
            print('api_version: ', resolve_resource_api(resource_client, resource))
            resource.tags['test'] = 'test1'

            #print(resolve_resource_api(resource_client, resource))
            #continue
            print(resource)
            resource_client.resources.create_or_update(
                resource_group_name= resource.id.split('/')[4], # Extract from resource.id
                resource_provider_namespace=resource.id.split('/')[6], # Extract from resource.id
                parent_resource_path='', # Extract from resource.id
                resource_type=str(resource.type).split('/')[-1], # Extract from resource type
                resource_name=resource.name,
                api_version=resolve_resource_api(resource_client, resource),
                parameters=resource
                )
        print('-'*10)

错误 回溯(最近一次通话最后): 文件“C:\Python35-32\Scripts\Azure\temp.py”,第 56 行,在 参数=资源 文件“C:\Python35-32\lib\site-packages\azure\mgmt\resource\resources\operations\resources_operations.py”,第 408 行,在 create_or_update 提高经验 msrestazure.azure_exceptions.CloudError:操作失败,状态为:“错误请求”。详细信息:400 客户端错误:对 url 的错误请求:https://management.azure.com/subscriptions/--***-*****-*******/resourcegroups/ Build/providers/Microsoft.Web/sites/build-dev?api-version=2016-03-01

我做了更多工作,发现我可以通过以下方式使用 create_or_update 方法:

from azure.mgmt.resource.resources.models import GenericResource
parameters=GenericResource(
        location='West US',
        properties={},
    )

您的代码示例的响应错误消息显示“参数属性的值无效”。所以我猜参数=资源需要修复。我会对此进行更多研究。

更新(已解决!):

for resource in resource_client.resources.list():
    #print(resource)
    if resource.id.split('/')[4] == 'Build':
        if resource.type == 'Microsoft.Web/sites':
            print('resource.id: ', resource.id)
            print('resource_group_name: ', resource.id.split('/')[4])
            print('resource_provider_namespace: ', resource.id.split('/')[6])
            print('parent_resource_path: ', '')
            print('resource_type: ', str(resource.type).split('/')[-1])
            print('resource_name: ', resource.name)
            print('api_version: ', resolve_resource_api(resource_client, resource))
            if not resource.tags:
                resource.tags = {}
                resource.tags['test'] = 'test1'
            else:
                resource.tags['test'] = 'test1'

            # This solves the error 400 Client Error: Bad Request. The parameter properties has an invalid value. 
            if not resource.properties:
                resource.properties = {}

            resource_client.resources.create_or_update(
                resource_group_name= resource.id.split('/')[4], # Extract from resource.id
                resource_provider_namespace=resource.id.split('/')[6], # Extract from resource.id
                parent_resource_path='', # Extract from resource.id
                resource_type=str(resource.type).split('/')[-1], # Extract from resource type
                resource_name=resource.name,
                api_version=resolve_resource_api(resource_client, resource),
                parameters=resource,
                )
        print('-'*10)

出于某种奇怪的原因,如果 resource.properties 为 None,则请求不喜欢它。它必须是 {}。

感谢您对特拉维斯的帮助!我会在使用 Azure SDK 时发布更多问题;)

【问题讨论】:

    标签: python azure azure-sdk-python


    【解决方案1】:

    如果您使用的是 Python SDK,您通常可以使用该资源的 create_or_update 方法向该资源添加标签。这些方法采用一个名为parameters 的对象,它通常是您感兴趣的资源的对象类型。您可以在这里找到标签。

    例如标记一个虚拟网络:

    from azure.mgmt.network.models import VirtualNetwork
    
    vnet = client.virtual_networks.get(resource_group_name, vnet_name)
    vnet.tags = {'a':'b'}
    client.virtual_networks.create_or_update(resource_group_name, virtual_network_name, vnet)
    

    此外,您可以通过 Xplat-Cli 使用(在本示例中)azure network vnet set -t {tags} 命令标记您的资源。

    您可以使用azure group set -t {tags} 标记资源组,并且通常使用azure resource set -t {tags} 标记资源。

    希望对您有所帮助。

    更新(2016 年 8 月 26 日)

    获取 API 版本可能很棘手。你会认为它只是通用资源对象的一部分,但由于某种原因它不是。但是,请尝试以下操作:

    from azure.common.credentials import UserPassCredentials
    from azure.mgmt.resource.resources import ResourceManagementClient
    
    def resolve_resource_api(client, resource):
        """ This method retrieves the latest non-preview api version for
        the given resource (unless the preview version is the only available
        api version) """
        provider = client.providers.get(resource.id.split('/')[6])
        rt = next((t for t in provider.resource_types if t.resource_type == resource.type), None)
        if rt and len(rt) == 1 and rt[0].api_versions:
            api_version = [v for v in rt[0].api_versions if 'preview' not in v.lower()]
            return npv[0] if npv else rt[0].api_versions[0]
    
    credentials = UserPassCredentials(
        '****@****.com',    # Your new user
        '******',  # Your password
    )
    
    subscription_id= '*****-***-****-****-*******'
    
    resource_client = ResourceManagementClient(credentials, subscription_id)
    
    for resource in resource_client.resources.list():
        resource.tags['test'] = 'test1'
    
        # avoid error 400 if properties must be set
        if not resource.properties:
            resource.properties = {}
    
        resource_client.resources.create_or_update(
            resource_group_name= resource.id.split('/')[4],
            resource_provider_namespace=resource.id.split('/')[6],
            parent_resource_path='', # WARNING: this will not work with child resources
            resource_type=str(resource.type).split('/')[-1],
            resource_name=resource.name,
            api_version=resolve_resource_api(resource_client, resource),
            parameters=resource
        )
    

    client.resources 下的列表操作给出了整个订阅的 GenericResource 对象的分页列表。您发布的方式是逐个遍历资源组,然后遍历每个资源组中的资源。这样可以正常工作,并且可以避免您必须从 ID 中提取资源组名称,但我认为这个解决方案更简洁一些。

    resolve_resource_api 方法使用提供者命名空间和资源 ID 中的资源类型,使用资源提供者获取操作来查找该资源类型的可用 API 版本。此代码(缺少一些验证)将检索不是预览版本的最新 API 版本(除非这是唯一可用的版本)。随便在字符串中指定一个版本一般是行不通的,因为不同的资源会有不同的 API 版本。

    此外,您的代码为父路径指定了 '',因此这通常不适用于子资源。

    【讨论】:

    • 您好 Travis,感谢您的指导。我想遍历每个资源并添加一个标签,我发现 azure.mgmt.resource.resources.operations.ResourcesOperations 的 create_or_update 方法很有用。但是我无法遵循该文件。我已经用示例代码更新了我的原始帖子。
    • 嗨,特拉维斯,很抱歉回复晚了。我还在原来的地方。我使用 get 方法而不是 create_or_update 作为初始检查我的参数是否正确。我无法找到有关 parent_resource_path 和 api_version 的足够信息。我尝试了一个带有 check_existence 方法的代码,每次迭代我都得到 False 。也许将 Azure CLI 与 Bash 结合使用对我来说是一个更简单的选择。
    • 使用前面的代码和 get 方法我得到了这些错误:msrestazure.azure_exceptions.CloudError: The resource type could not be found in the namespace 'Microsoft.ClassicCompute' for api version '2016-02-01 '。 msrestazure.azure_exceptions.CloudError:在 API 版本“2016-02-01”的命名空间“microsoft.insights”中找不到资源类型。
    • Travis,我做了更多的研究并找到了解决方案。谢谢你的帮助。我会尽快用我的解决方案更新帖子。资源类型其实是str(resource.type).split('/')[-1],而不是resource.type。
    • 嗨,Travis,当 get 方法为我工作时,我很高兴看到所有信息。但是我现在无法使用 create_or_update 方法。我认为我非常接近。你能帮忙吗?我已经更新了代码。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多