Is it possible to perform custom validation on two parameters and ensure they are equal?
I want to have something like password and password_confirm that must be equal before deploying any of the resources.
yeah, you can hack something like that, just create a resource that will fail and all the other resources would depend on it and then on the resource condition do:
"condition": "[not(equals(parameters('password'), parameters('password_confirm'))]"
that way if they are not equal fake resource would start getting deployed and would blow up (make sure you code it to blow up) and nothing would get deployed
now that I think of it, instead of creating a resource, just put a condition on all of the resources in the template:
"condition": "[equals(parameters('password'), parameters('password_confirm')]"
that way they will only get deployed if these match, but you won't have a failure.
Another option would be to add a parameter to do the validation... this is simpler but not as robust because the user could override the defaultValue of the parameter:
"validatePasswords": {
"type": "bool",
"allowedValues": [
true
],
"defaultValue": "[equals(parameters('password'), parameters('password_confirm'))]",
"metadata": {
"description": "Check to see if the 2 passwords match."
}
},
Putting a condition on each resource will work (and is harder to fool), but the deployment may succeed even though nothing is deployed.
Related
In Short:
Is it possible to have condition field (or something else to achieve this functionality), inside a parameter, so that this parameter input will be asked to the user, only based on another parameter's value.
i.e., Only if user selects Create New on a parameter, the input for the name of that parameter should be asked.
In Detail:
I have a parameter virtualNetworkCreateNewOrUseExisting which will accept two values - Create New and Use Existing.
"parameters": {
"virtualNetworkCreateNewOrUseExisting": {
"type": "string",
"defaultValue": "Create New",
"allowedValues": [
"Create New",
"Use Existing"
]
},
// Other parameters
}
I am trying to create a Virtual Network based on an input from user.
If user selects Create New, it will be created, and if they select Use Existing, it will be skipped. I see that this is achievable by using condition field inside the resource.
"resources": [
{
"condition": "[equals(parameters('virtualNetworkCreateNewOrUseExisting'), 'Create New')]",
// Other fields
}
// Other resources
]
Now, my question here is that,
Similar to this, is it possible to have condition field, inside another parameter, so that this parameter input will be asked to the user, only based on the previous parameter value.
i.e., Only if user selects Create New, the input for Virtual Network Name should be asked.
Something like this, by using a condition field:
"parameters": {
"virtualNetworksName": {
"condition": "[equals(parameters('virtualNetworkCreateNewOrUseExisting'), 'Create New')]",
"defaultValue": "vn-1",
"type": "string"
},
// Other parameters
}
But, I see that condition field, is not supported inside parameters (at least as of now).
Or, is it at least possible to have, if statements, like this (So that, the value of the field will be displayed empty by default if user selects Use Existing.):
"parameters": {
"virtualNetworksName": {
"defaultValue": "[if(equals(parameters('virtualNetworkCreateNewOrUseExisting'),'Create New'), 'vn-1', '')]",
"type": "string"
},
// Other parameters
}
Or, any other way to achieve this goal?
You can't do this natively in the template file, but in the portal user experiences for deploying the template you can... See:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-specs-create-portal-forms
and
https://learn.microsoft.com/en-us/azure/azure-resource-manager/managed-applications/create-uidefinition-overview
You don't have to use a templateSpec or managedApp (see the "Deploy to Azure button here: https://github.com/Azure/azure-quickstart-templates/tree/master/demos/100-marketplace-sample )
but templateSpec or managedApp will give you a better experience if that's an option.
As per the current Azure documentation, we cannot add conditions to parameters in parameters block.
As a side note you can use PowerShell parameter inline functions while deploying the template.
We see that there is a feature request already in place to add Support functions within the definition of parameters... ยท Community (azure.com) We would suggest you to make a comment & Upvote on the exiting feedback request .
I have a resource in my Arm Template as follows:
parameters:
env
prodparam
nonprodparam
resources:
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"url": "[if(equals(parameters('env'),'prod'), parameters('prodparam'), parameters('nonprodparam'))]"
}
I see the url is always set to parameters('nonprodparam') even if parameters('env') = 'prod'. Is this if condition correct? Am I missing something?
Your if condition statement is correct, I tested it and got the correct result successfully.
You need to do the following steps to check where your problem is:
1. Check if your parameter definition is correct, especially as Stringfellow mentioned in the comment, to be case sensitive. It should be defined as follows.
2. Pay attention to whether to save after editing arm templates in the azure portal.
You can check the value of the parameter during the deployment process:
I find instructions for using ARM templates to create or make changes to CosmosDB, but none of them contain instructions on how to add a CompositeIndex to the template. I have also heard it is not supported in the template and has to be done with PowerShell or Azure CLI script, but have not been able to find a supporting content on the net. Can someone please shed light on this?
I've not tested this but according to the Microsoft.DocumentDB resource provider docs / template reference there is a Microsoft.DocumentDB/databaseAccounts/apis/databases/containers resource which may give you what you need.
Every container has an IndexingPolicy in the template schema, which has an array of IncludedPath objects which themselves have an array of Index objects as follows:
"includedPaths": [
{
"path": "string",
"indexes": [
{
"dataType": "string",
"precision": "integer",
"kind": "string"
}
]
}
]
It's treated as a separate resource from the database / account altogether. You may want to add this resource to your template with an appropriate dependsOn value to ensure it's deployed after your database.
You can add multiple paths therefore making a composite index.
Full schema is here:
https://learn.microsoft.com/en-us/azure/templates/microsoft.documentdb/2015-04-08/databaseaccounts/apis/databases/containers
If this doesn't do it, you may want to look at this too as the schema docs may be out of date and compositeIndexes may be supported:
https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-manage-indexing-policy#composite-indexing-policy-examples
This is a known 'issue' from what I've gathered (https://github.com/Azure/azure-quickstart-templates/issues/2786)
I've build a python script that takes in a .csv and builds out an environment. All works fine. I have a second .csv that does peering, it works but making any changes to virtualNetworks after the fact (and not again specifying the subnets) deletes all subnets that were already there. You'd think I could just update my code to create the peerings on the fly in the same script, but I can't...incremental mode doesn't work. I'd like it to be a more dynamic and separate process.
Note: I'm also doing this across subscriptions, so that adds a bit of fun to the mix
Need some help understanding how I can go in after the fact and setup peerings:
Options I see:
Specify again the subnets when doing the peerings - issue with this is that my code will end up getting a lot larger AND the .csv files will be ugly. Not very efficient but it'll work, I think.
Use some kind of conditional in Python that'll perform the peerings at the time of initial build -- chicken and egg issue here and I still can't go back in and peer after the fact. Not to mention that I have a hub/spoke situation going on... so that'll be a lot to work through.
Can you even do this with nesting?
Also, a 'feature' of my script is that it'll spit out all of the completed ARM templates and parameters files when it is done. The whole idea is to make the initiator only have to fill out the .csv to make it all go.
Hopefully I'm missing something. Can post code but there is a lot and it's fairly straight forward.
EDIT: Remove child-parent comment I made which seemed to make it difficult to understand the issue.
this is how you create a peering without modifying other vnet properties:
{
"apiVersion": "2017-04-01",
"name": "%vnetname%/%peeringName%",
"location": "%location%",
"type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
"properties": {
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', '%vnetName%')]"
},
"allowVirtualNetworkAccess": true,
"allowForwardedTraffic": false,
"allowGatewayTransit": false,
"useRemoteGateways": false
}
}
note, you need to do this twice, one time for each vnet. doing it only on one vnets doesnt achieve anything really.
Given the URL https://github.com/foo/bar, I want to be able to get all the repos for foo. If foo is a user, I need to call api.repos.getForUser({username: 'foo'}) and if an org, I'll need to call api.repos.getForOrg({org: 'foo'}).
My problem is: how can I tell if "foo" is an org or a user?
Right now, I "solve" it in the costly way of trying to get an org called "foo", if I got it, I try to get its repos; if I end up getting an exception (I use promises) and if the code of the exception is "404", I assume "foo" is a user, and try to get user repos.
This is obviously inefficient, and has the side effect of adding calls that may trigger rate limit.
Is there an easier way to know whether "foo" is a user or an org?
As we all know, handling exceptions is costly. So instead of trying to get an org and handling the 404, you could instead look at the type property of the response to https://api.github.com/users/<username> in order to determine if the "user" is a user or organization and then proceed accordingly.
For example a call to my GitHub user API https://api.github.com/users/raghav710 returns
{
"login": "raghav710",
...
"type": "User",
...
}
And a call to an organization like https://api.github.com/users/Microsoft returns
{
"login": "Microsoft",
...
"type": "Organization",
...
}
Update: Doing it in a single call
I understand that you are already trying to access a URL https://github.com/<user or organization>/<repo name> and therein trying to get all the repos of that user or organization.
A suggestion is, instead of trying to do a GET on the above link, you could do a GET on https://api.github.com/repos/<user or organization>/<repo name>
For example doing a GET on https://api.github.com/repos/Microsoft/vscode
Gives
{
"id": 41881900,
"name": "vscode",
"full_name": "Microsoft/vscode",
"owner": {
"login": "Microsoft",
"id": 6154722,
...
"type": "Organization",
},
"private": false,
"html_url": "https://github.com/Microsoft/vscode",
...
}
As you can see the familiar type field is available under the owner key. You can use this to decide your next call
So even if there's an API call to differentiate, you'll still need that call to determine whether it's a user or not.
Considering the fact that most repositories should belong to users, why don't you reverse the checks? Try to retrieve the user repository, if that fails get the organization repository.
In addition, I'd cache as much information as necessary. Don't retrieve everything in real time while users use your tool. Many things won't change that often, if they're even able to be changed.