Azure / arm-ttk

Azure Resource Manager Template Toolkit
https://aka.ms/arm-ttk
MIT License
431 stars 186 forks source link

Empty property false positives with nested forms #756

Closed mdowst closed 6 months ago

mdowst commented 8 months ago

I have a template that contains a nested Template Spec with a uiFormDefinition that has a dropdown form populated via an API call. In order for this to work the form must be able to build and parse JSON. The string to do this contains the word null and empty brackets. This is triggering the Empty property test to fail.

The value that is return the failures is:

"[[map(steps('basics').resourceApi.value, (item) => parse(replace(concat('{\"label\":\"', item.name,' (', item.type,')', '\",\"value\":{\"id\": \"', item.id, '\",', '\"tags\":', string(item.tags),'}}'),':null}',':{}}' )))]"

Not only is this required functionality to make the form work, but it value is escaped to be a string, and is therefore not evaluated when the template deploys. For these reasons, it should not produce an Empty property failure.

I am using version 0.3 of the TTK module downloaded from https://aka.ms/arm-ttk-marketplace.

Below is a full example

{
  "type": "Microsoft.Resources/templateSpecs",
  "apiVersion": "2021-05-01",
  "name": "MyCustom_Label",
  "location": "[parameters('location')]",
  "properties": {}
},
{
  "type": "Microsoft.Resources/templateSpecs/versions",
  "apiVersion": "2021-05-01",
  "name": "[format('{0}/{1}', 'MyCustom_Label', '1')]",
  "location": "[parameters('location')]",
  "properties": {
    "uiFormDefinition": {
      "$schema": "https://schema.management.azure.com/schemas/2021-09-09/uiFormDefinition.schema.json",
      "view": {
        "kind": "Form",
        "properties": {
          "title": "MyCustom Label",
          "steps": [
            {
              "name": "basics",
              "label": "Basics",
              "elements": [
                {
                  "name": "resourceScope",
                  "type": "Microsoft.Common.ResourceScope",
                  "location": {
                    "resourceTypes": [
                      "microsoft.resources/resourcegroups"
                    ]
                  }
                },
                {
                  "name": "resourceApi",
                  "type": "Microsoft.Solutions.ArmApiControl",
                  "request": {
                    "method": "GET",
                    "path": "[[concat(steps('basics').resourceScope.resourceGroup.id, '/resources?api-version=2021-04-01')]"
                  }
                },
                {
                  "name": "resourcesDropdown",
                  "type": "Microsoft.Common.DropDown",
                  "label": "Resources",
                  "placeholder": "Select resources to tag...",
                  "filter": true,
                  "filterPlaceholder": "Filter items ...",
                  "multiselect": true,
                  "selectAll": true,
                  "constraints": {
                    "allowedValues": "[[map(steps('basics').resourceApi.value, (item) => parse(replace(concat('{\"label\":\"', item.name,' (', item.type,')', '\",\"value\":{\"id\": \"', item.id, '\",', '\"tags\":', string(item.tags),'}}'),':null}',':{}}' )))]",
                    "required": false
                  },
                  "visible": true
                },
                {
                  "name": "colLabel",
                  "type": "Microsoft.Common.TextBox",
                  "label": "Label",
                  "defaultValue": "",
                  "toolTip": "Use only allowed characters",
                  "constraints": {
                    "required": true,
                    "message": "Enter string value"
                  },
                  "visible": true
                }
              ]
            }
          ]
        },
        "outputs": {
          "parameters": {
            "TagObject": "[[steps('basics').resourcesDropdown]",
            "labelValue": "[[steps('basics').colLabel]"
          },
          "kind": "ResourceGroup",
          "location": "[[steps('basics').resourceScope.location.name]",
          "resourceGroupId": "[[if(empty(steps('basics').resourceScope.resourceGroup.id), steps('basics').resourceScope.resourceGroup.id, steps('basics').resourceScope.resourceGroup.id)]"
        }
      }
    },
    "mainTemplate": {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "TagObject": {
          "type": "Array"
        },
        "labelValue": {
          "defaultValue": "",
          "type": "String"
        }
      },
      "variables": {
        "defaultTag": {
          "MyCustom_Label": "[[parameters('labelValue')]"
        }
      },
      "resources": [
        {
          "type": "Microsoft.Resources/tags",
          "apiVersion": "2021-04-01",
          "name": "default",
          "scope": "[[parameters('TagObject')[copyIndex()].id]",
          "properties": {
            "tags": "[[if(empty(parameters('TagObject')[copyIndex()].tags),variables('defaultTag'), union(parameters('TagObject')[copyIndex()].tags,variables('defaultTag')))]"
          },
          "copy": {
            "name": "tagResource",
            "count": "[[length(parameters('TagObject'))]"
          }
        }
      ]
    }
  },
  "dependsOn": [
    "[resourceId('Microsoft.Resources/templateSpecs', 'MyCustom_Label')]"
  ]
}
vidapour commented 6 months ago

You can use this link to download the latest version of the TTK and try again: https://aka.ms/arm-ttk-azureapps

Let us know if you still have issues with this new version.

Additionally, can you also provide the documentation where you found the link you provided (arm-ttk-marketplace) so that we can update it? Thanks :)

psah434 commented 6 months ago

The marketplace link has been updated to point to the latest ttk.