From 725b650b9b9ea373caaa8f878cc1437298d4934c Mon Sep 17 00:00:00 2001 From: alex-frankel Date: Tue, 17 Nov 2020 12:41:30 -0800 Subject: [PATCH 1/4] added the any() function doc, fixed an example with more bicep-native syntax, added some best practices to arm2bicep --- docs/arm2bicep.md | 7 ++ .../101/function-app-create/main.bicep | 10 +-- docs/the-any-function.md | 70 +++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 docs/the-any-function.md diff --git a/docs/arm2bicep.md b/docs/arm2bicep.md index 1a572114ddf..df78546ff70 100644 --- a/docs/arm2bicep.md +++ b/docs/arm2bicep.md @@ -12,3 +12,10 @@ Get a property (`resourceProperty`) from a created resource (assumes `resource` Conditionally declare a property value | `if(parameters('isMonday'), 'valueIfTrue', 'valueIfFalse')` | `isMonday ? 'valueIfTrue' | 'valueIfFalse'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/expressions.md#ternary-operator)) Separate a solution into multiple files | Use [linked templates](https://docs.microsoft.com/azure/azure-resource-manager/templates/linked-templates#linked-template) | Use [modules](https://github.com/Azure/bicep/blob/main/docs/spec/modules.md) Set the target scope of the deployment to a subscription | `"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#"` | `targetScope = 'subscription'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resource-scopes.md#declaring-the-target-scopes)) +Set a dependency between two resources | `"dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', 'parameters('storageAcountName'))]"`] | Either dependsOn not needed because of [auto-dependency management](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) or manually set dependsOn with `dependsOn: [ stg.id ]` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#resource-dependencies)) + +## Incorporating new syntax into best practices + +* Avoid the `reference()` and `resourceId()` functions like the plague. Anytime the resource you are referencing is declared in the same bicep project, you can pull the equivalent information from the resource identifier in bicep (i.e. `stg.id` or `stg.properties.primaryEndpoints.blob`). This also creates an [**implicit dependency**](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) between resources, which means you can eliminate your usage of the `dependsOn` property. All of this results in cleaner, more maintainable code. +* Use consistent casing for identifiers. When in doubt, use [camel case](https://en.wikipedia.org/wiki/Camel_case) (e.g. `param myCamelCasedParameter string`) +* If you are going to add a `description` to a parameter, ensure the parameter is in fact descriptive. If you have a `location` parameter, having a description of "the resource's location" is not particularly helpful and results in your code being noisier. Sometimes a `//` comment is more appropriate. diff --git a/docs/examples/101/function-app-create/main.bicep b/docs/examples/101/function-app-create/main.bicep index 115e9d17fee..7b2af4d04b2 100644 --- a/docs/examples/101/function-app-create/main.bicep +++ b/docs/examples/101/function-app-create/main.bicep @@ -129,19 +129,19 @@ resource functionApp 'Microsoft.Web/sites@2020-06-01' = { appSettings: [ { name: 'AzureWebJobsStorage' - value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, '2019-06-01').keys[0].value}' + value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}' } { name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' - value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, '2019-06-01').keys[0].value}' + value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}' } { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' - value: '${reference(appInsights.id, '2018-05-01-preview').InstrumentationKey}' + value: appInsights.properties.InstrumentationKey } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: 'InstrumentationKey=${reference(appInsights.id, '2018-05-01-preview').InstrumentationKey}' + value: 'InstrumentationKey=${appInsights.properties.InstrumentationKey}' } { name: 'FUNCTIONS_WORKER_RUNTIME' @@ -246,7 +246,7 @@ resource functionAppConfig 'Microsoft.Web/sites/config@2020-06-01' = { resource functionAppBinding 'Microsoft.Web/sites/hostNameBindings@2020-06-01' = { name: '${functionApp.name}/${functionApp.name}.azurewebsites.net' properties: { - siteName: functionAppName + siteName: functionApp.name hostNameType: 'Verified' } } diff --git a/docs/the-any-function.md b/docs/the-any-function.md new file mode 100644 index 00000000000..0f87194a78f --- /dev/null +++ b/docs/the-any-function.md @@ -0,0 +1,70 @@ +# When and how to use the any() function + +Bicep supports a special function called `any()` to resolve type errors in the bicep type system. For a number of reasons, the type system may throw a false-positive error or warning. These are cases where bicep is telling you something is wrong, even though it is correct. These cases typically come from two cases: + +* There is a genuine bug in the bicep type system +* The resource type that is being declared has an incorrect api definition (swagger spec). For example, their API definition may expect a value to be an int, even though the actual running API is expecting a string. + +When either of the above occurs you can use the `any()` function to suppress the error. + +To help us out, it would also be great if you can file a relevant issue on which false-positive you encountered. For missing or incorrect type info, you can add your details to the pinned issue we have tracking it ([missing type validation/inaccuracies](https://github.com/Azure/bicep/issues/784)). + +> **Note:** This function does not actually exist in the ARM Template runtime, it is only used by the bicep language and not emitted in the built template JSON. + +## How to use the any() function + +In the following example, at the time of this writing, the API definition for Azure Container Instances is incorrect because the `properties.containers[*].properties.resources.requests.cpu` and `properties.containers[*].properties.resources.requests.memoryInGB` properties expect an `int`, but actually require a number, since the expected values can be non-integer values (i.e. `0.5`). Since number types are not valid in bicep (or ARM templates) we are forced to pass the numbers as strings. As a result, if I use the below code in my bicep file, I will get warnings on those properties. + +You can see this example live in the [bicep playground](https://aka.ms/bicepdemo#eJyNVFtvmzAUfudX+I32IUDSbV2RNi1dtq5S17ISdQ/TVDnGSSzhS3wJjab899kQE0IUtfCAOed8F1vHR0AJKVCaS7jAY4S4YfoeUmxDkrAF+AQMIyuD8/r3TGLFjUT4RnIjzs4jUpwHoqEgGh8Cj0mDXS3d5Ksyg0pVXBYe8C8AQGFkJE6BlgYHW19ecgQ14WxP3bfhK4Ig8ClQiTEiIKQESa74XEeIMw0Jw/KWKQ0ZwnEbqXnUl1EyvBoMR4NkGFoRZ4hZ1ykInU9hmdWghZAdSWirvHzarmxQSC6w1ASrtKYCoMXayJ86AnYZ9/SlwjZzzNQ8hNrj7ULSd9HVAAqIljjs1AkudUeyL9yKaI54afmmX7Own7UUKfiYHIS3nb+/nTVmayI5o5jpJygJnJX4Vfnd7n8/PE6yx295/jy5fv7xkE/7RtawNK5wOLqMEvsO04uL5EN40tfblLJxnrtAX63px6dG87Br4xigJWQLXAC9JArMJacgrO3Z5vkMwg72tL3usa15aSj+6S7Lq8dFXVUG9dLuJF5DGVdVFS81Lfs76HfVnJRvtOMvUq/pXMLOA6WP4rbBhbFaSfS+74JiyuXmlt1c1/nL0w72a79qvo0zIsZFUXd6q33U3F1Tp5v6qKG9nD8CvRHu4DIzKwnyyIIpN8fu4AxbTj/ygj2eq2mDuyPMvDjY1s0xbrQwugZ8/zW53w+yekhF+wsetTuM5quC/Qf9MoIp) + +``` +resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = { + name: 'wordpress-containerinstance' + location: location + properties: { + containers: [ + { + name: 'wordpress' + properties: { + ... + resources: { + requests: { + cpu: '0.5' + memoryInGB: '0.7' + } + } + } + } + ] + } +} +``` + +In order to get rid of these warnings, simply wrap the relevant property value(s) in the any function like so: + +``` +resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = { + name: 'wordpress-containerinstance' + location: location + properties: { + containers: [ + { + name: 'wordpress' + properties: { + ... + resources: { + requests: { + cpu: any('0.5') + memoryInGB: any('0.7') + } + } + } + } + ] + } +} +``` + +You can see in the live code in [the playground](https://aka.ms/bicepdemo#eJyNVFtv2jAUfs+v8JvhgSTQbV0jbRodW1epa7MGdQ/TVBnHgKXENr5A0cR/n53gEIJQmzzEOT7fxUfHRyCJSqA0l2hBxhhzw/Q9KokNScoW4BMwjK4MyarfniSKG4nJjeRG9PohzfuBqCmoJsfAU9Jgn1tus1WRIqU2XOYe8C8AQBFsJEmAloYEO59ecIw05exA3bXhM4Ig8FtgI8aYAlhSLLnicx1izjSijMhbpjRimERNpOJRX0bx8GowHA3iIbQizhCzrhMAnU9hmdWggdA9CbRZXj5pVjYoJBdEakpUUlEB0GBt5E8VAfsd93SlYLNzylQ/tLTlbUOSd+HVAAmElwS28gSXuiXZFW5ENMe8sHzTryns7lqKBHyMj8K71t/f1pqwNZWclYTpJyQpmhXkVfn96X8/PE7Sx29Z9jy5fv7xkE27RtaoMC5xOLoMY/sOk4uL+AM86+ttSuk4y1ygq1b341Otedy1UQTwErEFyYFeUgXmkpcAVvZs83wGsIU9b69dtjUvTEl+usvyarlKl5UivbQnidZIRpvNJlrqsuieoNtVc1q80Y6/SJ2mcxt2Hih9ErcNLkwCENv2YBy+h/2uZ1Jyub1lN9dN0mUnqe3lsPar+lt7pGKc51XPNy5O2rxt73x7n7S2l/PF0FvhSpiaWUGxR+ZMuYl2h2bEcvrhFxzwXE1r3B1l5sXBdm6icaOF0RXg+6/J/WGkVeMqPFz1sDlhOF/l7D8GbIVb), the warnings go away. + +`any()` works on any assigned value in bicep. You can see a more complex use of `any()` in the `nested-vms-in-virtual-network` example on [line 31](https://github.com/Azure/bicep/blob/main/docs/examples/301/nested-vms-in-virtual-network/nic.bicep#L31) of `nic.bicep` in which the use of `any()` wraps the entire ternary expression as an argument. From 0cd6f57130adac80131d74b818235bd0b1b52493 Mon Sep 17 00:00:00 2001 From: alex-frankel Date: Tue, 17 Nov 2020 13:08:32 -0800 Subject: [PATCH 2/4] fixed test --- docs/examples/101/function-app-create/main.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/101/function-app-create/main.json b/docs/examples/101/function-app-create/main.json index b7304e6dc86..ac77ea20d59 100644 --- a/docs/examples/101/function-app-create/main.json +++ b/docs/examples/101/function-app-create/main.json @@ -151,11 +151,11 @@ }, { "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2018-05-01-preview').InstrumentationKey]" + "value": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName'))).InstrumentationKey]" }, { "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2018-05-01-preview').InstrumentationKey)]" + "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Insights/components', variables('appInsightsName'))).InstrumentationKey)]" }, { "name": "FUNCTIONS_WORKER_RUNTIME", From 10ac03e1ebd7b43fca845eec4b54a35a8aa5878d Mon Sep 17 00:00:00 2001 From: alex-frankel Date: Tue, 17 Nov 2020 13:10:00 -0800 Subject: [PATCH 3/4] fix dependsOn sample in arm2bicep --- docs/arm2bicep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/arm2bicep.md b/docs/arm2bicep.md index df78546ff70..5cc151b1071 100644 --- a/docs/arm2bicep.md +++ b/docs/arm2bicep.md @@ -12,7 +12,7 @@ Get a property (`resourceProperty`) from a created resource (assumes `resource` Conditionally declare a property value | `if(parameters('isMonday'), 'valueIfTrue', 'valueIfFalse')` | `isMonday ? 'valueIfTrue' | 'valueIfFalse'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/expressions.md#ternary-operator)) Separate a solution into multiple files | Use [linked templates](https://docs.microsoft.com/azure/azure-resource-manager/templates/linked-templates#linked-template) | Use [modules](https://github.com/Azure/bicep/blob/main/docs/spec/modules.md) Set the target scope of the deployment to a subscription | `"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#"` | `targetScope = 'subscription'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resource-scopes.md#declaring-the-target-scopes)) -Set a dependency between two resources | `"dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', 'parameters('storageAcountName'))]"`] | Either dependsOn not needed because of [auto-dependency management](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) or manually set dependsOn with `dependsOn: [ stg.id ]` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#resource-dependencies)) +Set a dependency between two resources | `"dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', 'parameters('storageAcountName'))]"`] | Either dependsOn not needed because of [auto-dependency management](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) or manually set dependsOn with `dependsOn: [ stg ]` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#resource-dependencies)) ## Incorporating new syntax into best practices From 397fe8ff5f168a4f1cedc500355b2fe087925460 Mon Sep 17 00:00:00 2001 From: alex-frankel Date: Tue, 17 Nov 2020 13:22:49 -0800 Subject: [PATCH 4/4] minor tweaks --- docs/the-any-function.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/the-any-function.md b/docs/the-any-function.md index 0f87194a78f..52ebb80b3f4 100644 --- a/docs/the-any-function.md +++ b/docs/the-any-function.md @@ -1,6 +1,6 @@ # When and how to use the any() function -Bicep supports a special function called `any()` to resolve type errors in the bicep type system. For a number of reasons, the type system may throw a false-positive error or warning. These are cases where bicep is telling you something is wrong, even though it is correct. These cases typically come from two cases: +Bicep supports a special function called `any()` to resolve type errors in the bicep type system. For a number of reasons, the type system may throw a false-positive error or warning. These are cases where bicep is telling you something is wrong, even though it is correct. These cases typically manifest in one of two ways: * There is a genuine bug in the bicep type system * The resource type that is being declared has an incorrect api definition (swagger spec). For example, their API definition may expect a value to be an int, even though the actual running API is expecting a string. @@ -13,7 +13,7 @@ To help us out, it would also be great if you can file a relevant issue on which ## How to use the any() function -In the following example, at the time of this writing, the API definition for Azure Container Instances is incorrect because the `properties.containers[*].properties.resources.requests.cpu` and `properties.containers[*].properties.resources.requests.memoryInGB` properties expect an `int`, but actually require a number, since the expected values can be non-integer values (i.e. `0.5`). Since number types are not valid in bicep (or ARM templates) we are forced to pass the numbers as strings. As a result, if I use the below code in my bicep file, I will get warnings on those properties. +In the following example, at the time of this writing, the API definition for Azure Container Instances is incorrect because the `properties.containers[*].properties.resources.requests.cpu` and `properties.containers[*].properties.resources.requests.memoryInGB` properties expect an `int`, but actually require a `number`, since the expected values can be non-integer values (i.e. `0.5`). Since `number` types are not valid in bicep (or ARM templates) we are forced to pass the `number` as a `string`. As a result, if I use the below code in my bicep file, I will get warnings on those properties. You can see this example live in the [bicep playground](https://aka.ms/bicepdemo#eJyNVFtvmzAUfudX+I32IUDSbV2RNi1dtq5S17ISdQ/TVDnGSSzhS3wJjab899kQE0IUtfCAOed8F1vHR0AJKVCaS7jAY4S4YfoeUmxDkrAF+AQMIyuD8/r3TGLFjUT4RnIjzs4jUpwHoqEgGh8Cj0mDXS3d5Ksyg0pVXBYe8C8AQGFkJE6BlgYHW19ecgQ14WxP3bfhK4Ig8ClQiTEiIKQESa74XEeIMw0Jw/KWKQ0ZwnEbqXnUl1EyvBoMR4NkGFoRZ4hZ1ykInU9hmdWghZAdSWirvHzarmxQSC6w1ASrtKYCoMXayJ86AnYZ9/SlwjZzzNQ8hNrj7ULSd9HVAAqIljjs1AkudUeyL9yKaI54afmmX7Own7UUKfiYHIS3nb+/nTVmayI5o5jpJygJnJX4Vfnd7n8/PE6yx295/jy5fv7xkE/7RtawNK5wOLqMEvsO04uL5EN40tfblLJxnrtAX63px6dG87Br4xigJWQLXAC9JArMJacgrO3Z5vkMwg72tL3usa15aSj+6S7Lq8dFXVUG9dLuJF5DGVdVFS81Lfs76HfVnJRvtOMvUq/pXMLOA6WP4rbBhbFaSfS+74JiyuXmlt1c1/nL0w72a79qvo0zIsZFUXd6q33U3F1Tp5v6qKG9nD8CvRHu4DIzKwnyyIIpN8fu4AxbTj/ygj2eq2mDuyPMvDjY1s0xbrQwugZ8/zW53w+yekhF+wsetTuM5quC/Qf9MoIp) @@ -40,7 +40,7 @@ resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = { } ``` -In order to get rid of these warnings, simply wrap the relevant property value(s) in the any function like so: +In order to get rid of these warnings, simply wrap the relevant property value(s) in the `any()` function like so: ``` resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = {