How to use an Azure Arm Template Output in a variable? - azure

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.

Related

Extracting raw (non string) parameter values from terraform using terraform-config-inspect

I'm trying to generate json from terraform modules using terraform-config-inspect (https://github.com/hashicorp/terraform-config-inspect).
Note: Started with terraform-docs but then found what it uses underneath and it's terraform-config-inspect library.
The problem is that I want to go beyond what terraform-config-inspect provides out of box at the moment:
As an example, I want to get the name of aws_ssm_parameter resource.
For example, I have resource like this:
resource "aws_ssm_parameter" "service_security_group_id" {
name = "/${var.deployment}/shared/${var.service_name}/security_group_id"
type = "String"
value = aws_security_group.service.id
overwrite = "true"
tags = var.tags
}
and I would like to extract the value of the name parameter but by default it does not output this parameter. I tried to hack the code by modifying resource schema and other parts but ended up in getting empty string instead of name value or error because it contains parts like ${var.deployment}.
When I set it to plain string then my modified code returns what I expect
"aws_ssm_parameter.service_security_group_id": {
"mode": "managed",
"type": "aws_ssm_parameter",
"name": "service_security_group_id",
"value": "/test-env/shared/my-service/security_group_id",
"provider": {
"name": "aws"
}
}
but in normal case it fails with the following error
{
"severity": "error",
"summary": "Unsuitable value type",
"detail": "Unsuitable value: value must be known",
...
}
I know that I could build something totally custom for my specific use case but I hope there is something that could be re-used :)
So the questions are:
Is it somehow possible to take the real raw value from terraform resource so I could get "/${var.deployment}/shared/${var.service_name}/security_group_id" in json output?
Maybe some other tool out there?
Thanks in advance!
Input Variables in Terraform are a planning option and so to resolve them fully requires creating a Terraform plan. If you are able to create a Terraform plan then you can find the resolved values in the JSON serialization of the plan, using steps like the following:
terraform plan -out=tfplan (optionally include -var=... and -var-file=... if you need to set particular values for those variables.
terraform show -json tfplan to get a JSON representation of the plan.
Alternatively, if you've already applied the configuration you want to analyse then you can get similar information from the JSON representation of the latest state snapshot:
terraform show -json to get a JSON representation of the latest state snapshot.
As you've seen, terraform-config-inspect is only for static analysis of the top-level declarations and so it contains no functionality for evaluating expressions.
In order to properly evaluate expressions here without creating a Terraform plan or reading from a Terraform state snapshot would require reimplementing the Terraform Core runtime, at least to some extent. However, for this particular expression (which only relies on input variable values) you could potentially use the HCL API directly with some hard-coded placeholder values for those variables in order to get a value for that argument, derived from whatever you happen to have set var.deployment and var.service_name to in the hcl.EvalContext you construct yourself.

How to generate unix timestamp in Azure ARM Template

I am creating an ARM template to provision keyvault and it's secrets. I want to generate unix timestamp inside template and supply to nbf and exp attributes which only take integers. Can't find much pointers on this.
i am referring to microsoft documentation https://learn.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults/secrets
If no solution in ARM template then i need to use powershell to generate and pass it to template which i may not prefer unless there is no other option.
There is no way to generate those with ARM templates. arm templates do not have a way to work with date\time
There is now a function available to generate Unix-style timestamps from an ISO-8601 format.
dateTimeToEpoch('2022-11-17T09:54:13Z')
Use utcNow() function to get Date/Time during deployment time. Note you can use it only in parameter's default value:
"parameters" : {
"todayUtc": {
"type": "string",
"defaultValue": "[utcNow('yyyy-MM-dd')]"
}
}
See: docs

Can I dynamically generate parameters in Azure templates?

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.

Azure ARM Template variable: Get Subscription name property

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.

How get a value from a puppet resource

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).

Resources