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
Labels
bug
Milestone

Comments

@hashibot
Copy link

@hashibot hashibot commented Jun 13, 2017

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
@smooth-alg

This comment has been minimized.

Copy link

@smooth-alg smooth-alg 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

???

@smooth-alg

This comment has been minimized.

Copy link

@smooth-alg smooth-alg commented Jun 19, 2017

"type": "object" also does not work

@echuvyrov

This comment has been minimized.

Copy link
Contributor

@echuvyrov echuvyrov commented Jun 24, 2017

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

@StephenWeatherford

This comment has been minimized.

Copy link
Contributor

@StephenWeatherford StephenWeatherford commented Jun 29, 2017

@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

This comment has been minimized.

Copy link
Contributor

@StephenWeatherford StephenWeatherford commented Jun 29, 2017

@phekmat

This comment has been minimized.

Copy link
Contributor

@phekmat 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

This comment has been minimized.

Copy link
Contributor

@StephenWeatherford StephenWeatherford commented Jun 30, 2017

@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

This comment has been minimized.

Copy link
Contributor

@phekmat 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

This comment has been minimized.

Copy link
Contributor

@StephenWeatherford StephenWeatherford commented Jun 30, 2017

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

@smooth-alg

This comment has been minimized.

Copy link

@smooth-alg smooth-alg commented Jul 10, 2017

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

This comment has been minimized.

Copy link

@m4h3 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

This comment has been minimized.

Copy link
Contributor

@StephenWeatherford StephenWeatherford commented Nov 25, 2017

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

@tombuildsstuff

This comment has been minimized.

Copy link
Contributor

@tombuildsstuff tombuildsstuff commented Nov 28, 2017

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

This comment has been minimized.

Copy link

@m4h3 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

This comment has been minimized.

Copy link
Contributor

@phekmat phekmat commented Nov 28, 2017

@iszekely

This comment has been minimized.

Copy link

@iszekely 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

This comment has been minimized.

Copy link

@jnevins-gcm jnevins-gcm commented Aug 16, 2019

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.

@hashibot

This comment has been minimized.

Copy link

@hashibot hashibot bot 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 👉 hashibot-feedback@hashicorp.com. Thanks!

@hashibot hashibot bot 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.
Projects
None yet
10 participants
You can’t perform that action at this time.