Is there a way to get the current subscriptions name into a variable?
Something like this:
"variables": {
"Purpose": "[subscription().SubscriptionName]"
},
Visual Studio says "A property of 'subscription' must be one of the following: id, subscriptionId, tenantId." So the above won't work.
I've also found some examples of the "reference" function and tried to use it thus:
"variables": {
"SubName": "[reference('/subscriptions/subscription().subscriptionId','2015-01-01').outputs.name.value]"
},
But when calling the template it errors with:
function 'reference' is not expected at this location
I'm not sure where I should put it and how I get it into a variable.
In PowerShell, I could do this:
(Get-AzureRmSubscription).subscriptionname
For the sack of interest, we have several subscriptions. The subscription name contains a 3 digit "short code" that is used in the naming of resource groups within the given subscription. It serves no purpose other than make it easier to pinpoint what belongs to what. It is part of our naming convention to help admins (who aren't particularly familiar with Azure) easily see what resources are where. I know there are other ways like RBAC etc, but Microsoft's incessant credential cookie capture doesn't lend itself to logging in with different credentials to different subscriptions.
Thanks
W.
At the time of writing this answer (2016 Oct 16) I'm afraid you can't.
According to the docs, this is what subsbscription() returns:
{
"id": "/subscriptions/#####",
"subscriptionId": "#####",
"tenantId": "#####"
}
So you should expect failing on subscription().SubscriptionName.
In the same doc I linked, there is a discussion around this in the comments section, see comment #2694777590 where a Microsoftie say:
Ok - I've added a bug to add the name attribute to the subcription() expression.
this was 2016 June 6, So I guess it's on the way.
As a workaround, you could inject the subscription name from the thing that is executing the template. For example if it's PowerShell you could do
$subName = (Get-AzureRmSubscription).subscriptionname
New-AzureRmResourceGroupDeployment ... -SecscriptionName $subName
Also, I don't know what's the purpose of that string manipulation based on subscription name you talked about, but if is to create subscription scoped unique names, a good practice is to use uniqueString(subscription().subscriptionId) as part of the name.
The subscription() now does have an additional attribute displayName, according to documentation.
The following should work for you:
"variables": {
"Purpose": "[subscription().displayName]"
}
You should be able to use:
subscription().displayName
(I'll get a bug filed on the VS behavior)
I was able to get subscription().subscriptionId to work in a variable my template.
I think this error you are seeing is a result of how Azure reads the template. Based on Microsoft's reference documentation, references cannot be used in variables:
Remarks
The reference function derives its value from a runtime state, and therefore cannot be used in the variables section.
I got the same function 'reference' is not expected at this location until I moved my actual reference call into the body of the template.
Related
I'm trying to solve a problem I'm having with an Azure ARM template, whereby I need to capture the output of a queried resource in my ARM template, then in that same template, feed that output into a variable / inject that output into a script on another resource that depends on it.
An example -
"outputs":{
"downloadLocation": {
"type": "string",
"value": "[reference(resourceId('randomResource', variables('ResourceName'))).downloadLocation]"
}
}
And
variables: {
"downloadLocation": "[outputs('downloadLocation')]"
}
This variable is then referenced in one of the resources that depends on the source of the queried output.
The downloadLocation can't be formatted in anyway, it contains several signatures and unpredictable strings.
FYI - the below code stops the arm template from being used, by producing the error 'The template function 'outputs' is not valid.'
I'm not locked to storing it as an output, I just need to be able to use that value in another resource - however it's achieved!
The only other route I know would work, but I don't want to explore yet, is that the output could be stored in a file somewhere, then a subsequent script picks it up and injects it into a second ARM template.
If there is a way to use this please let me know, it would help me out significantly!
Thanks
I have found the solution.
The reference function can be called when inside a resource field. So I've had to use reference function as seen above, but it can't be stored in a variable or parameter, it instead needs to be called directly in the resource that's requiring it. Which in this case was the osProfile - customData field.
When writing the outputs part of ARM template how do the do what properties are available for a resource. in the below example for public ip resource how do I find out dnsSettings.fqdn or .ipAddress is available
"outputs": {
"fqdn": {
"value": "[reference(parameters('publicIPAddresses_name')).dnsSettings.fqdn]",
"type": "string"
},
"ipaddress": {
"value": "[reference(parameters('publicIPAddresses_name')).ipAddress]",
"type": "string"
}
}
Your ask is related to Retrieve FQDN of Azure SQL from a linkted template question.
The easiest way to accomplish your requirement is illustrated in below screenshot.
Hope this helps!! Cheers!!
Note: If you think your question has been answered then please 'accept' it, if just helped then click "This answer is useful" and provide an up vote. This can be beneficial to other community members reading this thread.
One way I've found, using only ARM, is to output the whole object:
"outputs": {
"ipaddress": {
"type": "Object",
"value": "[reference(parameters('publicIPAddresses_name'))]"
}
When you apply the policy, the output will show all the possible properties and their values.
You can view the whole data structure in json at https://resources.azure.com.
you dont really know, because some properties are amended by default (and the other answer doesnt mention that at all, which could mislead you badly). One thing you can do is look at the rest api definition of the resource and use Full reference to the resource, that way you will always get what you see in the api definition.
reference(parameters('publicIPAddresses_name'), 'api-version', 'Full')
but, object structure will be different, as far as I remember you'd need to access properties of the object for the most of the output. What I tend to do is - create a template that does nothing but output the existing object I'm interested in and run it and examine the output.
Outputs are almost never needed so it's not that big of an issue in my mind.
Rest Api definitions: https://learn.microsoft.com/en-us/rest/api/azure/
This is to find out if something I'm attempting is even possible...
I've seen several examples of developing an entry ARM template (azuredeploy.json) that refs/imports an external child resource template (eg: azuredeploy.sql.server.json) within which is defined a new SQL Server as well as -- within the sql server's resources section -- nested resources, such as a firewallrule.
I've seen one example (https://blogs.msdn.microsoft.com/azuresqldbsupport/2017/01/11/arm-template-to-deploy-server-with-auditing-and-threat-detection-turned-on/) where the entry/parent ARM template (eg: azuredeploy.json) defines the SQL Server, and instead of defining the firewall rules as a nested resources, defines the firewall rules in parallel, using dependsOn to define execution order.
That appears to be a bit more maintainable/less nested than the first approach.
But I'd like to push it further, where the above resources are all defined in external templates: azuredeploy.json invoking azuredeploy.sql.server.json and azuredeploy.sql.server.firewallRules.json
Unfortunately, I've not found a single example of the above approach.
I've tried for most of the afternoon -- but having changed slashes of ids and names to every configuration imaginable, have run over and over again into:
Code=InvalidTemplate
Message=Deployment template validation failed: 'The template resource {resource-name}'
for type {resource-type} has incorrect segment lengths.
So the questions are:
a) any reason it should not be done this way? (I felt it allowed for a more modular set of arm templates, that could be referenced from a flat entry arm file, only requiring a correct set of 'dependsOn' attributes being defined)
b) can the above actually be done?!
c) is there an online example to study of the above approach and understand my approach error?
d) Just in case: when it's giving the error messages regarding the segment lengths...any chance it's getting itself confused, and it's taking into account "Microsoft.Resources/deployments", when it should be taking into account only "Microsoft.Sql/servers" and "Microsoft.Sql/servers/firewallRules"?
Much appreciated if anybody can advance me on this sticking point.
Yes, you should be able to do this, see: https://learn.microsoft.com/en-us/azure/templates/microsoft.sql/servers/firewallrules
The error you posted suggests that you're missing a name segment or type segment - those must match as in the example below.
"type": "Microsoft.Sql/servers/firewallrules",
"apiVersion": "2015-05-01-preview",
"name": "[concat(parameters('serverName'), '/', 'AllowAllWindowsAzureIps')]",
"location": "[resourceGroup().location]",
"properties": {
"endIpAddress": "0.0.0.0",
"startIpAddress": "0.0.0.0"
}
So your name property will be something like
sqlServerResourceName/whateverYouWantToNameTheFirewallRules - and type exactly as in the example above.
AFAIK, all the parameters have to be defined in the parent template right from the start. Is it possible to generate parameters dynamically at all, such as looping n times to generate n name fields?
This shows how parameters are defined in templates. Note that none of the parameters are created dynamically.
You can use parameters that depend on parameters to emulate something like that:
"parameters": {
"first": {
"type": "string",
"defaultValue": "lol"
},
"second": {
"type": "string",
"defaultValue": "[concat('not_so_', parameters('first'))]"
}
}
would give you value of not_so_lol for the first parameter.
You another option is to create variables that take values depending on the parameter:
"parameterOne": "defaultValue": x, - I'm lazy to type out proper definition in json.
...
"option-x": "something"
"option-y": "something-else"
"result": "[variables(concat('option-', parameters('parameterOne')))]"
so this is basically an If statement in ARM template. the value of the result variable equals to "[variables('option-x')]" or "[variables('option-y')]", depending on your input.
Another (a bit more complex option) is to use deployments outputs. So an example would be, you create a deployment filled with different outputs needed by you (basically you create a pool of constants), and after that, you can reference that deployment outputs in all of your templates (given they reside in the same subscription, but you can create that deployment in all of the subscriptions). that would basically create a pool of constants you can get needed value based on the current value.
"something": "[reference(concat('resourceGroupName', 'Microsoft.Resources/deployments/', parameters('deploymentName')),'2015-01-01').outputs]",
The last (most complex) option is to construct needed stuff on the fly, using nested templates. That's a bit too much to get through in an answer, but I'll just say that in this case you need to use nested templates as aggregator\transformator, where you feed values in and get desired output. This is pretty advanced stuff, but worth knowing. This would be a good example (for starters).
According to your description, we can use uniqueString() to achieve generate parameters dynamically. This function is helpful when you need to create a unique name for a resource.
More information about uniqueString, please refer to this link.
I have a problem with my puppet script.
I would like to get a value set in my resource file. I declare a resource like that
define checkxml(
$account = '',
$pwd = template('abc/abc.erb'),
){
if(empty($pwd)){
fail('pwd empty')
}
}
I call it via :
checkxml{"$agtaccount":
account => $agtaccount,
}
I want to get the value of $pwd. The $pwd will get is value by Template. If i try to show the value in my resource definition it's ok, I get the right value, so the Template works fine.
My problem is to get access this value after calling the ressource. I saw the getparam of stdlib but doesn't work for me.
getparam(Checkxml["$agtaccount"],"pwd")
If i try to get the account parameters instead of pwd it's ok. I think as i doesn't declare the pwd i can't get him back
How can i get him ?
Thanks for your help
Ugh, this looks dangerous. First off I'd recommend to steer clear of that function and the concept it embodies. It faces you with evaluation order dependencies, which can always lead to inconsistent manifest behavior.
As for the retrieval of the value itself - that will likely not work if the default is used. That's because on a catalog building level, there is not yet a value that is being bound to the parameter, if that makes any sense.
The resolution of final parameter values is rather involved, so there are lots of things that can go wrong with a manifest that relies on such introspective functionality.
I recommend to retrieve the desired value in a more central location (that depends on your manifest structure) and use it both when declaring the Checkxml["$agtaccount"] resource as well as its other uses (for which you are currently trying to extract it).