如何在ARM模板中检查资源是否存在

18

如何通过资源类型和标识符在ARM模板中识别Azure资源是否存在


ARM模板本质上是声明式的(因此理论上不需要这个)-根据您的情况,可能有另一种方法来实现您所考虑的内容... - bmoore-msft
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/conditional-resource-deployment - RClemens
4个回答

17

事实上,这是有可能的。您可以使用资源组标记来标记当前已部署的版本并跳过部署(如果设置了该标记)。所有这些都可以通过链接的模板实现。
请注意,我们不会检查资源是否存在,但仍允许编写包含一次性初始化模板的 ARM 模板。最后一个模板将在资源组被删除并且资源丢失的情况下恢复资源(前提是您重新创建了资源组)。您可以将其扩展以支持每个资源的标记,在某些情况下更加有用。

启动部署的模板可能如下所示:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "DeploymentTemplateLink": {
            "type": "string"
        },
        "DeploymentVersion": {
            "defaultValue": 1,
            "type": "int"
        }
    },
    "variables": {
      "rgWithDefaultVersion": {
          "tags": {
             "Version": "0"
          }
      }
    },
    "resources": [
        {
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2017-05-10",
            "name": "DeploymentTemplate",
            "condition": "[less(int(union(variables('rgWithDefaultVersion'), resourceGroup()).tags['Version']), parameters('DeploymentVersion'))]",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[parameters('DeploymentTemplateLink')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "DeploymentVersion": {
                        "value": "[parameters('DeploymentVersion')]"
                    }
                }
            }
        }
    ]
}
链接模板的条件检查标签,仅当当前版本(存储在标签中)小于请求的版本时返回true。实际上,您不必维护版本:只需不设置DeploymentVersion参数即可仅首次部署。如果您决定重新部署,则始终可以选择增加版本,这将导致链接模板(又名“主部署”)的部署。
主要部署模板由您自己创建,但应包含一个tags资源以保持逻辑。
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "DeploymentVersion": {
            "defaultValue": 1,
            "type": "int"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.Resources/tags",
            "name": "default",
            "apiVersion": "2019-10-01",
            "dependsOn": [],
            "properties": {
                "tags": {
                    "Version": "[string(parameters('DeploymentVersion'))]"
                }
            }
        }
    ]
}

注意:对于那些不理解union()rgWithDefaultVersion的人来说,ARM模板部署将会失败,如果所引用的对象不包含一个属性。在我们的情况下,我们有两个这样的属性:'tags''Version''Tags' 只在特定资源组具有或曾经具有标签时存在。'Version'只在我们已经写入它一次后才存在(在主部署中)。因此,在访问它们之前,我们使用一个适当的默认值执行union()操作,以确保我们可以安全地访问这些属性。


1
非常好,正是我今天所需要的..而且我甚至不是那个提问者。谢谢! - Razoll
这是一个很好的解决方法,谢谢!使用 union 的技巧真是太棒了。 - Vladislav
很好的回答Benny!有没有一种方法可以PATCH标签?(即merge,而不是replace) 当将多个资源作为RG标记保持状态时,如果并行运行ARM模板步骤而不是顺序,则维护标记会成为一个问题,因为由于某些竞争条件而丢失一些标记。 - johni
1
伙计,你意识到你所做的方式是无用的复杂性了吗?你打算在ARM模板中对每个资源应用条件吗?其次,如果真实资源存在配置漂移,如果该资源的版本标签未更改,则永远不会回滚。 - BMW
1
我的意思是,这基本上就是我在答案中提到的,但(与@BMW类似),我不鼓励这种方法。模板不应该真正关心当前存在的状态。它们只应该“使其成为可能”。你有git来跟踪以前的状态。 - 4c74356b41
虽然这正是我所寻找的,但我想知道是否有一种更简单的方法使用标签来控制部署与否。 - LFN

5

在 ARM 模板中无法实现此操作。您可以使用一些外部源(如 PowerShell)来确定并传递适当值的参数,或者您可以使用标记来找出 (具有资源存在\不存在的标记)。


2
资源管理器提供以下功能来获取资源值:Azure Resource Manager模板的资源函数
您可以使用一段Powershell或其他脚本将您的模板包装起来,以确定资源是否存在,并根据此传递参数值。在模板中使用条件语句,根据输入决定要执行什么操作(但输入必须来自其他地方)。最初的回答。

-5
最近我需要解决一个问题,即对 SQL 服务器进行增量更新。由于无法这样做,模板将会出现 NameAlreadyExists 错误。因此,我需要检查资源是否存在,只有在不存在时才创建。
为 Azure 资源 ID 添加“条件”检查,如果存在则不创建。
{
 ...
 "condition": "[empty(resourceId('[resourceGroup().id]', 'Microsoft.SQL/servers', parameters('serverName')))]",
 ...
}

您可以针对任何资源类型执行此操作。


这不起作用,因为resourceId函数实际上并没有检查资源是否存在,它只是返回给定资源组、类型和名称的ID。请参阅文档以获取更多信息-https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-resource#resourceid - David Gard
4
这个答案完全是错的。谁会点赞这个? - 4c74356b41
2
需要注意的是,这种方法错误的原因在于当找不到资源ID时会导致错误而不是空字符串。如果返回空字符串,则看起来似乎可以工作。 - The Gilbert Arenas Dagger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接