Predefined Resource Group in ARM Template - json

I'm working on a custom arm template.
I would like to have specific resource group to be hard coded inside the JSON so
when opening the template it will simulate "Resource Group: Use existing: predefined selected Resource group"
I've been scratching my head for hours and searched the web deeply, I also tried to export existing resource group template and import it to custom deployment but it still shows
Resource Group *Create New *Use Existing
Is there any way to define existing RG inside the JSON template?

You can use nested templates, like #4c74356b41 said, but you will still see the ugly "Select a resource group" field at the portal.
I have a similar problem (even if #4c74356b41 repeatedly claims that it doesn't make any sense). I want to generate the resource group name from a parameter.
You can find more about how to use nested templates here: Create resource group and deploy resources
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {
"someName": {
"type": "string"
}
},
"variables": {
"rgName": "[concat('rg-', parameters('someName'))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('rgLocation')]",
"name": "[variables('rgName')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "rgDeployment",
"resourceGroup": "[variables('rgName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', variables('rgName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
// PUT YOUR RESOURCES TEMPLATES HERE! //
}
],
"outputs": {}
}
}
}
],
"outputs": {}
}
Just replace the rgName variable with the name of your actual resource group name.

there are several ways to achieve this (not that it makes sense, but you can do this).
Use automation around the template to always deploy it to the same rg. this makes most sense as your template stays flexible
wrap your template with a parent template (so "convert" your template to a nested template). that way the parent template can control to which resource group your nested template gets deployed (look for cross resource group ARM Template deployments).
Make your template a nested inline template (worst case). this is pretty much the same as point 2, but kinda worse, because nested inline templates have this peculiar drawback of not being able to use their own parameters\variables, only the ones defined in the parent.
Again, none of this makes sense as you should just deploy it to the proper subscription\resource group combination. but there you have it, if you insist.
But the portal experience will stay the same (there is no way of working around that, you can forcé the template to always deploy to the same resource group (not that it makes any sense), but not alter the portal experience), if thats what you are concerned about.

Related

Proper validation of a referenced file when editing OpenAPI json in IntelliJ

I'm editing an OpenAPI JSON spec in IntelliJ. The automatic validation and code completion work very nicely.
The OpenAPI version used is 3.0.3, which IntelliJ detects correctly. It seems that it uses "openapi30.json" internally for validation, and all is good.
However, the file is getting very large and it's time to move some commonly-used models out of it using $ref.
This is where things break. The main spec looks like this (snippet):
{
"openapi": "3.0.3",
"info": {
"title": "Cars REST API",
"description": "Calls, Responses and DTOs for REST",
"version": "1.0.0"
},
"components": {
"schemas": {
"car": {
"$ref": "car.json"
},
"car-group": {
"$ref": "car-group.json"
}
And when editing it, IntelliJ recognizes it as "openapi30".
However, the referenced documents are not recognized. For example, the car.json file looks like this:
{
"car": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
}
}
And it's recognized simply as a JSON document, not an OpenAPI one, so there is no proper validation and no code completion, etc.
How does one tell IntelliJ that the file is part of an OpenAPI specification, to be validated as such? One should think this could be inferred from begin $ref'ed from the main spec, but this doesn't work.
Trying to add a $schema value in the referenced file had no effect (and probably isn't in line with the OpenAPI spec anyway).
Manually selecting the OpenAPI 3.0 file type for car.json is not helpful, because then validation (rightly) fails - as it doesn't have the top-level structure required (info, openapi, paths).
Perhaps some specific JSON schema mapping needs to be added in IntelliJ preferences? If that's the case, it would be actually a sub-schema or some tag in the main OpenAPI spec, how can that be done?
IntelliJ version is: IntelliJ IDEA 2021.3.2 (Ultimate Edition)
Any help would be greatly appreciated.
Ron!
Such functionality is not yet supported. Please vote for https://youtrack.jetbrains.com/issue/IDEA-284305

Wanted to enable multi read region for azure cosmosdb account only if i am creating that for PROD environment (ARM Template)

I am creating Azure cosmosdb account using ARM template. wanted to enable multi read region for cosmosdb only if the environment name is "PROD". i am using the same template across all my other environment.
any suggestions. refer to the below sample script: Highlighted location should only be used if my environment name is prod.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": {
"type": "String",
"metadata": {
"description": "dev,dev1,qa,prod,etc"
}
},
-------------------
--------------------
-------------------
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2015-04-08",
"name": "[parameters('cosmosDBName')]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environmentName')]",
"Project": "DevOps",
"CreatedBy": "ARMTemplate",
"description": "Azure Cosmos DBName"
},
"properties": {
"name": "[parameters('cosmosDBName')]",
"databaseAccountOfferType": "[variables('cosmosdbOfferType')]",
"locations": [
{
"locationName": "[resourceGroup().location]",
"failoverPriority": 0
},
**{
"locationName": "Central US",
"failoverPriority": 1
}**
]
}
}
]
There are multiple possibilities here including logical functions, deployment conditions or even passing in the regions as a parameter that could help solve the particular situation you have.
The most flexible option would be to pass the regions into the script by a parameter. This would allow it to be more flexible for reuse, in case environment names change or new ones are added. Also it would not be reliant on having a specific environment name set and would give more flexibility for its use. You can then easily setup the correct regions to be passed through in your deployment pipeline or parameter files for each environment.
If you don't want to do down that route there are other options such as using conditions to selectively deploy a resource with the correct setup. For your example this would lead to code duplication as you would need to have the resource elements twice with different setup and a condition tag that determined which one is run. This is not ideal due to the code duplication but might be useful on certain occasions.
Finally there is also the option of using Logical Functions to generate the locations required. This is similar to passing the regions to the script but you would generate the regions required using a function. This is slightly less flexible than passing the regions into the script but if you really need to set this up from a environment name this would probably be the way to go.
I have described each of the options above in a little more detail below with a few script examples. Please note the examples have not been tested so there may be typos or minor amends needed but they should generally be along the lines of what you need.
Passing regions to the template
Using this method you would have something similar to the following. Add a regions array as part of your parameters. e.g.
"regionsList": {
"type": "string",
"defaultValue": "Central US",
"metadata": {
"description": "Comma separated region list"
}
},
You could then have a variable setup to generate your list of locations using the copy function to dynamically set the locations based on the list passed in. e.g.
"variables": {
"regionArray": "[split(parameters('regionsList'), ',')]",
"locations": {
"copy": [
{
"name": "values",
"count": "[length(variables('regionArray'))]",
"input": {
"locationName": "[variables('regionArray')[copyIndex('values')]]",
"failoverPriority": "[copyIndex('values')]"
}
}
]
},
Once that is setup you only need to reference the variable within the locations property on the resource e.g.
"locations": "[variables('locations').values]",
so your resource section would look something similar to this if you go down that route
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2015-04-08",
"name": "[parameters('cosmosDBName')]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environmentName')]",
"Project": "DevOps",
"CreatedBy": "ARMTemplate",
"description": "Azure Cosmos DBName"
},
"properties": {
"name": "[parameters('cosmosDBName')]",
"databaseAccountOfferType": "[variables('cosmosdbOfferType')]",
"locations": "[variables('locations').values]",
}
} ]
Deploy Conditions
For a conditional deployment you can setup a resource to have a deploy condition set on it. It works like an if statement so if the value is true it will deploy and if it is false it will not. In your case you would have something like this on the resource section itself.
"condition": "[equals(parameters('environmentName'), 'PROD')]"
As this is on the resource level though you would need to have your resource listed twice with different locations / setup and an opposite condition on each. So one setup with a condition of environment equal to PROD (this one with the additional location) and the other setup with an environment not equal to prod.
As mentioned above though this causes duplication and is not ideal and I would not go with it unless there are significant difference in the template for the prod environment and even then there are better ways.
Logical Functions
Logical functions can allow you to do transforms on values before using them and include things like if statements. In this case you could use them to determine the locations required for your resource based on the environment name passed in. This is similar to the passing regions to the template but without actually passing the regions in. It is slightly less flexible due to that.
You could then have a variable setup to generate your list of locations using the copy function to dynamically set the locations based on the list passed in. e.g.
"variables": {
"regionsList" : "[if(equals(parameters('environmentName'), 'PROD'), 'East US,Central US','East US')]"
"regionArray": "[split(variables('regionsList'), ',')]",
"locations": {
"copy": [
{
"name": "values",
"count": "[length(variables('regionArray'))]",
"input": {
"locationName": "[variables('regionArray')[copyIndex('values')]]",
"failoverPriority": "[copyIndex('values')]"
}
}
]
},
Once that is setup you only need to reference the variable within the locations property on the resource e.g.
"locations": "[variables('locations').values]",
so your resource section would look something similar to this.
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2015-04-08",
"name": "[parameters('cosmosDBName')]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environmentName')]",
"Project": "DevOps",
"CreatedBy": "ARMTemplate",
"description": "Azure Cosmos DBName"
},
"properties": {
"name": "[parameters('cosmosDBName')]",
"databaseAccountOfferType": "[variables('cosmosdbOfferType')]",
"locations": "[variables('locations').values]",
}
} ]
With all of these options its also good to understand what all of the features actually do / are for. Please see below for links to the docs around the features I mentioned above.
ARM Copy
ARM Logical Functions
ARM Deployment Conditions

Display number in adaptive card

I have the following simple card:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "{data}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
When I apply the following data to the card (value is number), the text box is empty:
{
"data":11111
}
With text, the I can see the data in the card:
{
"data":"11111"
}
This is not a code issue, this is how it looks in the designer. Am I missing something, is there a type for a text box that lets display numbers or is this by design and I have to change all numeric fields to text?
This is a limitation of the preview (known as Type Coercion) that we hope to address before release. As another workaround you can include a space after the binding expression which will force it into a string. See the below example, notice the space after {data}
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "{data} "
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
I'm guessing you're using Adaptive Cards Templating for this. Remember, this is (a) in preview only and (b) just one option for constructing an Adaptive Card. Basically, at the end of the day, the Card is just a string of JSON text so you can create it in 3 main ways:
Using Templates, as you're doing now
Doing string replacement of your own (e.g. var card = '..."text": "##Number##"...' and then card = card.Replace("##Number##", formattedNumberValue)
Using strongly-typed options like the AdaptiveCards Nuget package for C#, for instance
So, I'd suggest, if this is not possible using Templating, to look more at options 2 or 3 above. I described this a bit more here, with some links to C# and Node examples.
Hope that helps
You can now use the function formatNumber(value, decimalplaces)
Eg:
{
"type": "TextBlock",
"text": "${formatNumber(somenumber), 2}"
}
You can read mode here:
https://learn.microsoft.com/en-us/azure/bot-service/adaptive-expressions/adaptive-expressions-prebuilt-functions?view=azure-bot-service-4.0#formatNumber

How can I retrieve the query key for Bing Maps API for Enterprise in an Azure Resource Group Template?

I am working on an ARM template that deploys an entire infrastructure from scratch:
The resource group
App Service plans
Application Insights
an so forth...
At some point I get to the part where I write the scripts for deploying my App Service (for hosting and deploying my web app later on) to my resource group. Prior to that I have my BingMaps API deployed in the same script.
I am stuck at the part where I am setting the Application Settings for my web app:
"type": "Microsoft.Web/sites",
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "SomeKey",
"value": "SomeValue"
}, //rest of the code omitted
I would like to know how could I retrieve my BING MAPS query key within an ARM template?
I have tried, and have a feeling that this might be close to it, something like:
"value": "[reference(resourceId('Microsoft.BingMaps/mapApis', variables('bingMapsName')), '2016-08-18').queryKey]"
Anybody who has done this before? Many thanks in advance! Cheers
If you want to access query key in your ARM template for your web app setting, I would suggest you to use something like below:
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('webSiteName'))]"
],
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"key1": "[parameter('AppSetting_Key1_Value')]",
"key2": "value2"
}
}
and then in your template.Parmeter.jso file , you can declare the key AppSetting_Key1_Value with the value of your Bing maps query key.
Specify the Parameter Value
After the Parameter has been added to the ARM Template and it’s being used to populate an Application Setting, the final step is to define the Parameter value within the ARM Templates Parameter file used for deployments. In the Azure Resource Group project template in Visual Studio the Parameters file for the default deployment is the file that ends with “.parameters.json”.
Here’s a screenshot of the “WebSite.parameters.json” file created in the previous articles in this series with the “AppSetting_Key1_Value” Parameter set to a value:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"value": "WebApp1HostingPlan"
},
"WebApplication1PackageFolder": {
"value": "WebApplication1"
},
"WebApplication1PackageFileName": {
"value": "package.zip"
},
"WebApp_ConnString1": {
"value": "Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;"
},
"AppSetting_Key1_Value": {
"value": "Template Value 1"
}
}
}
for security complaint solution , you can move all your secure key and connection string to Azure key vault if you are not comfortable to have keys in param file.
This should work. Hope it helps.

Create second resource group for nested template

So I'm trying to deploy a template that sets up a site to site vpn and has a nested template that would setup a virtual machine connected to the azure side. Each template works by themselves as well as together when doing it as a nested template.
The problem comes in when I want to have the site to site deployed in one resource group and have the VM and related objects deployed to another resource group.
I have the following code I've put together:
{
"condition": "[equals(parameters('deployVm'),'True')]",
"type": "Microsoft.Resources/resourceGroups",
"name": "[variables('deployments').resourceGroup.name]",
"apiVersion": "2018-08-01",
"location": "[variables('deployments').resourceGroup.location]",
"properties": {}
},
{
"condition": "[equals(parameters('deployVm'),'True')]",
"type": "Microsoft.Resources/deployments",
"name": "[variables('deployments').name]",
"apiVersion": "2017-05-10",
"resourceGroup": "[variables('deployments').resourceGroup.name]",
"properties": {
"mode": "[variables('deployments').mode]",
"templateLink": {
"uri": "[variables('deployments').templateLink.uri]",
"contentVersion": "[variables('deployments').templateLink.contentVersion]"
},
"parameters": {}
}
},
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', variables('deployments').resourceGroup.name)]"
]
}
Based on some other templates I've put together I don't understand why when deployed the resource group that I have set in the dependson section doesn't get created.
When I run the template azure complains that resource group "[variables('deployments').resourceGroup.name]" can't be found.
The question doesnt explicitly specify this, but you need to create the resource group before hand.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-cross-resource-group-deployment#specify-a-subscription-and-resource-group
Apart from this - everything looks fine (you might want to check your deployment variable, which kinda looks like deployment() function.)