2016-08-17 87 views
0

我想使用python在Azure中的每個資源上創建標記。Azure SDK Python:標記特定資源

我看到這個模塊中的文檔: 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:創建訂閱資源,標籤 列表:獲取訂閱資源標籤的列表

好像我只能做資源標籤業務組而不是資源?

例子:

要將標籤添加到資源組:集AzureRmResourceGroup 添加標籤的資源:集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) 

Error Traceback (most recent call last): File "C:\Python35-32\Scripts\Azure\temp.py", line 56, in parameters=resource File "C:\Python35-32\lib\site-packages\azure\mgmt\resource\resources\operations\resources_operations.py", line 408, in create_or_update raise exp msrestazure.azure_exceptions.CloudError: Operation failed with status: 'Bad Request'. Details: 400 Client Error: Bad Request for 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={}, 
    ) 

並與您的代碼示例響應錯誤消息說,「參數屬性具有無效值「。所以我猜測參數=資源需要修復。我會更多地考慮這一點。

UPDATE(解決了!):

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無,請求不喜歡它。它一定要是 {}。

謝謝你的幫助特拉維斯!在我使用Azure SDK時,我會發布更多的問題;)

回答

2

如果您使用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) 

此外,還可以使用(在這個例子中)的azure network vnet set -t {tags}命令直掛Xplat-CLI你的資源。

您可以使用azure group set -t {tags}來標記資源組,並使用azure resource set -t {tags}來統一資源。

希望有幫助。

UPDATE(16年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的資源類型,使用資源提供程序get操作查找該資源類型的可用API版本。此代碼(缺少一些驗證)將檢索不是預覽版本的最新API版本(除非這是唯一可用的版本)。只是任意指定一個字符串中的版本不會一般工作,因爲不同的資源將有不同的API版本。

此外,您的代碼爲父路徑指定'',所以這通常不適用於子資源。

+0

嗨特拉維斯,感謝您的指導。我想遍歷每個資源並添加一個標籤,並且我發現azure.mgmt.resource.resources.operations.ResourcesOperations的create_or_update方法非常有用。但是我無法跟蹤文檔。我已經用示例代碼更新了我的原始帖子。 –

+0

我的更新答案是否適合您? –

+0

嗨特拉維斯,對於遲到的回覆感到抱歉。我仍然在那裏。如果我的參數是正確的,我使用get方法而不是create_or_update作爲初始檢查。我無法找到關於parent_resource_path和api_version的足夠信息。我用check_existence方法嘗試了一個代碼,每次迭代都會得到False。也許在Bash中使用Azure CLI對我來說更容易。 –