Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_template_deployment fails to pass "array" type parameters properly #34

Closed
hashibot opened this issue Jun 13, 2017 · 18 comments
Closed
Labels
Milestone

Comments

@hashibot
Copy link

This issue was originally opened by @rtyler as hashicorp/terraform#11085. It was migrated here as part of the provider split. The original body of the issue is below.


Terraform Version

v0.8.0

Affected Resource(s)

  • azurerm_template_deployment

Terraform Configuration Files

Consider the an ARM template with an "array" parameter, e.g.:

{
    "$schema": "http://schemas.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "documentDBs": {
            "type": "array"
        }
    },
resource "azurerm_template_deployment" "thing" {
    name                = "a-big-parameterized-arm-template"
    resource_group_name = "${azurerm_resource_group.things.name}"
    parameters          = {
        documentDBs = [
            "github-events",
        ],
    }
    deployment_mode     = "Incremental"
    template_body       = "${file("./arm_templates/the-template.json")}"
}

Output

Error running plan: 1 error(s) occurred:

* parameters: 1 error(s) decoding:

* '[documentDBs]' expected type 'string', got unconvertible type '[]interface {}'

Expected Behavior

I would have expected the array to be marshalled through to the template properly.
What should have happened?

@hashibot hashibot added the bug label Jun 13, 2017
@alexapplebaum
Copy link

alexapplebaum commented Jun 16, 2017

It also doesn't pass "type": "int" params either.

Testing on 0.9.8.

ex. test.tf

variable region         { default = "West US"                       }
variable resource_group { default = "terraform-arm-template-param-test" }


provider "azurerm" {
}

resource "azurerm_resource_group" "resource_group" {
 name     = "${var.resource_group}"
 location = "${var.region}"

 tags {
   environment = "terraform-arm-template-param-test"
 }
}


####   THIS FAILS     ####
#### "type": "int"    ####
resource "azurerm_template_deployment" "terraform-arm-template-param-test" {
 depends_on          = ["azurerm_resource_group.resource_group"]
 name                = "terraform-arm-template-param-test"
 resource_group_name = "${azurerm_resource_group.resource_group.name}"
 deployment_mode = "Incremental"
 template_body =  <<DEPLOY

{
   "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
   "contentVersion": "1.0.0.0",
   "parameters": {
       "numberOfExternalIps": {
           "defaultValue": 1, 
           "metadata": {
               "description": "The number of public/private IP addresses you want to deploy."
           }, 
           "type": "int"
       }
   },
   "variables": {
       "location": "[resourceGroup().location]"
   },
   "resources": [
       {
           "apiVersion": "2015-06-15", 
           "location": "[variables('location')]", 
           "name": "terraform-arm-template-param-test-public-ip", 
           "properties": {
               "dnsSettings": {
                   "domainNameLabel": "terraform-arm-template-param-test"
               }, 
               "publicIPAllocationMethod": "static"
           }, 
           "type": "Microsoft.Network/publicIPAddresses"
       }
   ]
}
 DEPLOY

 parameters {
   numberOfExternalIps = 1
 } 

which results in:

* azurerm_template_deployment.terraform-arm-template-param-test: Error creating deployment: resources.DeploymentsClient#CreateOrUpdate: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="InvalidTemplate" Message="Deployment template validation failed: 'The provided value for the template parameter 'numberOfExternalIps' at line '1' and column '183' is not valid.'."

Supposedly that was fixed in 0.9.5
https://github.com/hashicorp/terraform/blob/v0.9.8/CHANGELOG.md#095-may-11-2017

provider/azurerm: azurerm_template_deployment now supports String/Int/Boolean outputs (#13670)
hashicorp/terraform#13670

???

@alexapplebaum
Copy link

"type": "object" also does not work

@echuvyrov
Copy link
Contributor

@StephenWeatherford can you take a look when you have a minute please?

@StephenWeatherford
Copy link
Contributor

@smooth-alg, #13670 dealt with outputs, not parameters (it was an incremental improvement - note that outputs still don't support arrays or objects).

It looks like parameters need to be fixed, too. Have you found a way to work around this? Does passing strings work for you?

@StephenWeatherford
Copy link
Contributor

StephenWeatherford commented Jun 29, 2017 via email

@phekmat
Copy link
Contributor

phekmat commented Jun 30, 2017

Have you found a way to work around this? Does passing strings work for you?

That's my current workaround, but it requires that the ARM template use string types everywhere for its parameters. It does not work for objects/arrays.

It's a complete hack, but I'm using terraform's template provider combined with a partial ARM template to create ARM templates with object/array parameters baked in.

@StephenWeatherford
Copy link
Contributor

@phekmat, @smooth-alg, @rtyler
On a related note, using azurerm_template_deployment is generally a hack to work around the lack of some Azure resource in terraform. Could I ask what is missing that you're needing to use templates deployments? Thx.

@phekmat
Copy link
Contributor

phekmat commented Jun 30, 2017

I'm currently using templates for:

  • App Service plans
  • App services (including setting a custom hostname, web app parameters, etc)
  • App service slots
  • Function Apps
  • Service bus queues (only old-style storage queues and new-style service bus topics seem to be supported at the moment)
  • Azure SendGrid
  • Adding a custom domain to Azure CDN
  • Adding secrets to Key Vault
  • Configuring diagnostic logging for Key Vault
  • Application Gateways

@StephenWeatherford
Copy link
Contributor

Thanks! That's a useful list. I will note that a lot of these are already in the pipeline.

@alexapplebaum
Copy link

Thanks Stephen.

Re: Resources

Mostly general fill in as you have alluded to.

Autoscale in Azure:
hashicorp/terraform#12889

which is in the pipeline. Even cloud provider templates often lag behind the full feature set available, much less third party orchestration tools, but in some cases have features not even avail in the api.

hashicorp/terraform#1552

Access to their native orchestration api is like backdoor to their full feature set (similar to the shell provisioner :-).

Re: strings.

Yes, they work. However, some vendors/projects are providing (and even recommend) solutions encapsulated in templates (which may not always have control of parameter types):

ex. object
https://github.com/Azure/azure-quickstart-templates/blob/master/elasticsearch/nestedtemplates/shared-resources.json
ex. "recommended"
from: http://docs.pivotal.io/pivotalcf/1-9/customizing/azure.html
Launching an Ops Manager Director Instance with an ARM Template (Recommended)

which don't necessarily want to build from scratch and as I use terraform to deploy a lot of my other infrastructure, like to keep everything in one place.

@rcarun rcarun added this to the M1 milestone Oct 11, 2017
@m4h3
Copy link

m4h3 commented Nov 22, 2017

Hi, please consider to support all template inputs types :

I don't know the expected implementation but integers and bool in terraform are not "truly" supported (they are string encoded) so they need to be converted somehow.

Secure* types are a bit out of the scope for parameters they don't differ from normal types "typewise".

@StephenWeatherford
Copy link
Contributor

@m4h3 I'm no longer working terraform. Perhaps @tombuildsstuff can comment on future plans.

@tombuildsstuff
Copy link
Contributor

hey @rtyler @smooth-alg @phekmat @m4h3

Apologies for the delayed response to this issue.

To provide some background on why this is implemented this way: in HCL all values in a Map needs to be of the same type - in the case of the Output field, this is a Map/Dictionary of Strings:Strings.

hashicorp/terraform#13670 updated the Output field to cast Boolean and Integer values returned from the Azure API's to Strings based on the return type - meaning that they could be represented correctly in the Schema/State as Strings - however this didn't handle Arrays, Objects or the 'Secure' prefixed types since they're more complex problems.

Whilst we updated the Outputs (since we can guarantee the return type) - Inputs are more complicated since all values coming in are going to be Strings, we have no guarantee on what the types are. We could probably attempt to cast around this - however it's not ideal and it'd be better to be explicit.

To achieve this we could adapt the Parameters value to take an additional type field as shown below:

parameters {
  name = "foo"
  type = "string"
  string_value = "bar"
}

parameters {
  name = "foo"
  type = "int"
  int_value = 3
}

However this would mean that it's no longer a Map but a Set - which means that we'd not be able to validate the name fields are unique until apply time - which isn't ideal. We also can't verify the types are valid until Apply time too - which means this option is a pretty bad user experience.

It's a complete hack, but I'm using terraform's template provider combined with a partial ARM template to create ARM templates with object/array parameters baked in.

Whilst this isn't ideal, unfortunately I think this may be the best route forward until these resources are supported natively in Terraform, if you need to make use of these parameters. That said, looking at the list above most of those are now either supported (App Service / Key Vault etc) or planned for the future.


Given I don't believe there's a route forward for this issue (at least, in the short/medium term) - I'm going to close it for the moment.

Thanks!

@m4h3
Copy link

m4h3 commented Nov 28, 2017

Terraform has the ability to deploy Azure ARM templates and AWS Cloudformation stacks, and therefore it can glue things together without rewriting everything.
This is about Infrastructure code reuse as we pull existing ARM/Cloudformation templates made by different teams to deploy complex topologies.

I'm wondering how cloudformation stacks parameters behave here: https://www.terraform.io/docs/providers/aws/r/cloudformation_stack.html

Casting or Parameter Set solution are both fine as templates/stacks won't ever be perfect solutions, but pragmatic ones waiting for native terraform implementations.

@phekmat
Copy link
Contributor

phekmat commented Nov 28, 2017

@m4h3 it looks like CloudFormation parameters are treated the same: https://github.com/terraform-providers/terraform-provider-aws/blob/84dcbf9ebf36414a932af5dcd2b7b3b871baeac3/aws/resource_aws_cloudformation_stack.go#L145

@iszekely
Copy link

iszekely commented Aug 29, 2018

Hi @tombuildsstuff
I don't understand why it is so hard to solve, at least for primitive types as int or bool. The Azure RM deployment template has the type information for all parameters. Even if the parameters block contains everything as string, those values should be converted to the corresponding type before execution. If something cannot be converted, than it is an error anyway, and the apply should fail, no matter what.

E.g.

"clusterWorkerNodeCount": {
    "defaultValue": 2,
    "type": "Int",
    "metadata": {
        "description": "The number of nodes in the HDInsight cluster."
    }
}

During apply:

parameters.clusterWorkerNodeCount:      "" => "2"

and it fails, however it would be trivial to convert "2" to 2.

* azurerm_template_deployment.hdinsight_template: Error creating deployment: resources.DeploymentsClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="InvalidTemplate" Message="Deployment template validation failed: 'The provided value for the template parameter 'clusterWorkerNodeCount' at line '1' and column '1592' is not valid.'."

@jnevins-gcm
Copy link

this is enough of a reason to completely stop using terraform for deploying Azure.

Terraform great concept, but when an abstraction starts to leak all over you, it's time to reconsider its value (or completely change your requirements to work within the abstraction and not have Azure Functions in your ecosystem I guess...)

Azure RM Templates (while clunky to write) are great in that almost every Azure portal operation generates an ARM template that runs against the resource group. Considering the documentation on the Azure APIs (and ARM templates themselves) is terrible, the best way to automate against Azure is often to check out the Deployments tab of a resource group and capture that template (which obviously often has arrays and objects as parameters). Having to start hacking at these templates makes such an approach much less viable.

@ghost
Copy link

ghost commented Aug 17, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!

@ghost ghost locked and limited conversation to collaborators Aug 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

10 participants