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

How to set undefined value #5471

Closed
joshuaspence opened this issue Mar 6, 2016 · 40 comments
Closed

How to set undefined value #5471

joshuaspence opened this issue Mar 6, 2016 · 40 comments

Comments

@joshuaspence
Copy link
Contributor

I am writing a module for creating EC2 instances. We have a lot of duplication between our EC2 instance configuration (tags, user data, common security groups, etc) and creating a module eliminates code duplication. I am not sure, however, how to set a value to be undefined. For example, suppose that my module looked like this:

variable "availability_zone" {
  type = "string"
  default = ""
}

resource "aws_instance" "instance" {
  availability_zone = "${var.availability_zone}"
}

My question here is what is the correct default value for the availability_zone variable such that it is essential an optional parameter? Empty string seems to work in some cases, but I'm not sure if this would work in all cases? Basically I am looking for the Terraform equivalent of puppet's undef.

@tmlink
Copy link

tmlink commented Jun 17, 2016

I could really use this too.
The vSphere provider's "vsphere_virtual_machine" resource "network_interface" block has a ipv4_prefix_length is numberic and therefore a default of "" gives cannot parse '' as int: strconv.ParseInt: parsing "": invalid syntax

So I can't write modules that allow either static or dynamic addresses. It's one or the other.

@elocnatsirt
Copy link

elocnatsirt commented Sep 17, 2016

Very interested in having the ability to set undefined variables. I am in the process of writing modules now, and it would be nice to be able to set optional values as undefined by default so that the module could contain everything the resource has to offer by default but not pulled in if it wasn't necessary.

@mitchellh
Copy link
Contributor

Most resources at the moment must just be written to accept some "zero" value as unset. If a resource doesn't support this please report a bug. We hope that in time we'll have a way to unset a value but at the moment we do not.

@joshuaspence
Copy link
Contributor Author

I'm curious... if this functionality does not currently exist and you do hope to implement it one day, then why close this issue? I ask out of curiosity rather than frustration. Is the reason that Hashicorp prefer only to use GitHub issues for tracking features that can be placed somewhere on the short-term roadmap rather than the long-term road map? If so, is there any place to record longer-term feature requests? Or is there no attempt to capture these feature requests because Terraform itself is moving so rapidly?

@dgolja
Copy link
Contributor

dgolja commented Apr 13, 2017

Resurrecting this conversation.

Most resources at the moment must just be written to accept some "zero" value as unset.

What are the "zero" - unset values for the parameters ? For example I would like to know the "zero" values for the resource aws_db_instance, particularly the parameter allocated_storage ? This parameter is optional unless a snapshot_identifier or replicate_source_db is provided. The documentation doens't define the zero/undef value.

I would like to have a module that allow either an allocated_storage size or replicate_source_db to be used.

So something along there lines.

resource "aws_db_instance" "db" {
	...
	allocated_storage = "${var.replicate_source_db == "none" ? var.allocated_storage : 0 }"
	replicate_source_db = "${var.replicate_source_db != "none" ? var.replicate_source_db : 0}"
    ...
}

If some of the parameters have precedence (example: replicate_source_db > snapshot_identifier > allocated_storage) would be great to document it.

@BijeshSamson11
Copy link

Hi,
I face an issue with terraform. I have several environments in Azure, some are having load balacers and some are not having load balancers. I made a very generic code for VM deployment, which will automatically add the VM's to load balancer backend pool when VM's are provisioned.
But using same code when I need to deploy VM's are not using load balancer, I need to manually comment out (#load_balancer_backend_address_pools_ids) in main file. Is there any way how to set undefined value (null value) in the "environment.tfvars" file, so that I don't need to change the "Main" file everytime?

Following option I tried, but doesn't help me. Any help greatly appreciated

main.ft file contains following

resource "azurerm_network_interface" "nic" {
name = "${var.nicname}${count.index +1}"
location = "${var.location}"
resource_group_name = "${var.azurerm_resource_group}"
count = "${var.count}"
ip_configuration {
name = "ipconfig${count.index}"
subnet_id = "${var.subnet_id}"
private_ip_address_allocation = "Dynamic"
load_balancer_backend_address_pools_ids = ["${var.backend_pool_ids}"]

variable.tf file contains following

variable "backend_pool_ids" {}

environment.tfvars file contains following

backend_pool_ids = ""

@AndrewFarley
Copy link

AndrewFarley commented Oct 18, 2017

So, I'm trying to develop some really dynamic modules, and there are SO many variables which do not support this "zero" to unset concept, and some elements in terraform that should actually accept 0 because 0 is a valid value for that parameter. This approach and the reason this bug was closed doesn't make sense, are we, the community supposed to go open 100 different bugs for each variable we run into (I've found 5 casually just now in addition to the 5 bugs linked above) and just get them fixed as we need them? This seems extremely retroactive and pessimistic of a design. I don't understand why we can't have something similar to...

resource "object" "name" {
   name = "my object name"
   optional_value = "${var.somevar == "production" ? 300 : null}"
}

I'm seeing a recurring theme in my almost two years of using terraform, that something like this above is absolutely necessary to create modern modules without having to create tons of different messy optional count-based resources with all the different types of optional values I might or might not set that don't suppor this "0 unset" concept. Would love some further thinking and feedback on this topic please. Especially with the recent terraform module registry going live, something like this is becoming more and more critical to implement (just like getting count support on modules is as well).

Nuances (aka, Flaws) like this really drive my clients away from wanting to adopt Terraform. Because of this flaw, I'm having to maintain multiple slightly modified copies of the same module. Anytime that is necessary usually indicates there is something wrong with the tool/language I'm using.

@gretel
Copy link

gretel commented Oct 25, 2017

i agree with @AndrewFarley - feel like hashicrop is trying to 'manage' the not-so-good feedback that counterfeits the initial hype of the tool we talk about.
having hundreds of circular issues is what i personally have observed in regards to other projects just before people started switching to more suitable (modern) approaches.

@mattolenik
Copy link

mattolenik commented Dec 7, 2017

I can't understand how this was closed. At present it is impossible to pass undefined vars into modules. E.g. my module wants to pass some variable foo to some AWS resource, for example. That resource's variable is optional, I can either define it in my HCL or not. In my module, I MUST define that variable, because its value will be passed into the module. But now I can't leave it "unset." I MUST set it to some value, be that 0 or empty string. But when I use 0, I get validation errors from AWS because it's supposed to be UNSET, not a "default" value. Saying this is a bug in the provider is just passing the buck. Who decides what is "default"? You'll get different "defaults" across providers. It forces everyone to implement a 0/empty string check in every resource rather than just having native support for a mechanism in TF.

It's really frustrating that issues like this seem to keep getting closed. It's like Hashicorp just doesn't want to hear about it and would rather put their fingers in their ears and assume it isn't their problem.

Imagine this were a programming language. It's like saying you don't want null or option types and everyone should pass around magic strings and numbers to indicate no value, and everyone should check for those values on their own, rather than having the language provide a feature. It is forcing everyone to do a check over and over again when it should really just be done once within TF. TF should not force you to pass variables around when they are undefined. That's just downright silly. If you make providers fix this, it becomes a neverending battle of trying to get every provider to implement a fix for this quirk.

@AndrewFarley
Copy link

Yeah, welcome to the club @mattolenik With modules being at the forefront of the future of Terraform, absolutely this is one of those pivotal "duh" moments where we need the language to evolve to support this. Anytime I do anything even remotely advanced with Terraform I run into this bug and it frustrates the hell out of me. Right now for one client I'm justifying having to have 3 versions of the same module in increasingly "creative" ways because of this bug. Can we raise a bounty to fix this or something? What will it take? :P

@mattolenik
Copy link

I understand it not being implemented just yet, and that's okay. What bothers me is why these keep getting closed.

@mattolenik
Copy link

This is also affected by this: hashicorp/terraform-provider-aws#2063

Assuming "-1" for a null value is just insane. This isn't even something providers CAN fix because -1 is a valid value, so there's no way to tell if it's "null" or not.

@clumsysnake
Copy link

I've had exactly the same issues.

IMO we need to be able to write real code to define the graph. Either using a new terraform-specific configuration language, or some kind of HCL templating that is closed over the variables and data sources, or give up on HCL-json compatibility and extend HCL, or some other idea. Is there a feature roadmap or RFC where this is atleast being thought about? I understand terraform is still young and things take time to mature, but I'm worried that the terraform team doesn't think the limtiations of HCL are a problem.

When I first started with terraform I remember the hope being that HCL itself would be "kinda basically just json" and 3rd parties would develop HCL-generation tools in front. Well those never really happened in a meaningful way, and IMO since we've been adding piecemeal a mishmash of functions that are incomplete and often unintuitive to use, or pushing the burden onto provider repos as-needed and with uncoordinated semantics. Now with backends and workspaces and data sources and modules, code-generation can't work, if it ever could have.

Addressing this is important for adoption. I'm beach-heading terraform within our client, a large multinational, and I'm at the point now where I have to pitch their internal ops department to adopt what i've done (and hopefully buy TF Enterprise!) All the issues with inflexibility in conditionalizing resource arguments impairs that pitch. Perhaps experts (like the gruntwork.io team) can get around the issues through extended trickery. But neither sharp learning curves nor "just write some wrapper scripts" endears.

@rahulkp220
Copy link

@AnthonyWC
Copy link

I've read it but that was made more than a year ago.

@wintergren
Copy link

Having the same problem and needing to maintain several versions of a module to support different use cases just becuase I can't unset optional settings or remove whole configuration blocks within a resource when they should not be present.

Really frustrating! Terraform needs to add better support for this if it's to become a mature product, and I do hope so because besides this I like it. But it's just not feasible having to maintain several module versions instead of one dynamic one.

@mitchellh When is the team going to prioritize and focus on this? The community is really behind this happening as can be seen by the comments here.

@amardomingo
Copy link

Same problem here. I need to conditionally set one of two mutually exclusive variables, and could really use a null/undefined value

@cornfeedhobo
Copy link

@AnthonyWC lol, yeah I didn't say it was a solution. And @mitchellh is notorious for muting threads once he's made a judgement. This is a dead-in-the-water request it appears. My guess is they are trying to solve it globally, probably when the make hcl-terraform v2.

@AnthonyWC
Copy link

Ok so one workaround at the resource level via count would be to do something like this:

variable "optional_resource_parameter" {
  default = "default_null"
}

resource "foo" "bar" {
  count = "${var.optional_resource_parameter == "default_null" ? 0 : 1}"
}

The trick is to define a default value to represent null and then use count to set to 0 if the default is not changed to anything else. This still require you to write out multiple version of resource level definition though so it's still not ideal but at least your module can reference the same directory.

@wintergren
Copy link

wintergren commented Apr 13, 2018

@AnthonyWC Yeah that's what I'm doing to toggle whole resources in the module and it works well, think it's been mentioned before in the comments here also. Have for example like this

resource "aws_cloudfront_distribution" "default" {
  viewer_certificate {
acm_certificate_arn            = "${var.acm_certificate_arn == "" ? join(" ",aws_acm_certificate_validation.cert.*.certificate_arn) : var.acm_certificate_arn}"
  }
}

resource "aws_acm_certificate" "cert" {
  count = "${var.acm_certificate_arn == "" ? 1 : 0}"
}

For a module which creates cloudfront dist, r53 records and accompanying acm certs. If you already have a cert created you provide a cert arn in the acm_certificate_arn variable which is optional, so if not provided it will create the required resources. Just showing on of them in the snippet above.

The issue for me is not toggling resources, it's about toggling fields and configuration blocks within a resource. The other day we got a use case where a team wanted to use Lambda@Edge. For cloudfront resource that's a specific config block which associates the lambda function with the distribution. I can't have the module always creating this association, only when it's needed. So had to branch out and have that as a separate version. That's one use case, there are many...

@apparentlymart @mitchellh Some attention to this, please?

@phinze
Copy link
Contributor

phinze commented Jun 1, 2018

To the 20 folks who are watching this issue - native null value support is coming in Terraform 0.12! The HCL2 integration effort is well underway.

This description from @apparentlymart is from last year but is still mostly accurate in its description of the incoming functionality: #14037 (comment)

wking added a commit to wking/openshift-installer that referenced this issue Jul 24, 2018
READMEs are part of the standard module structure [1], and docs like
this should make onboarding new contributors easier.  The example's
etcd ports are from [2,3].  The egress rule is based on [4], although
I've restricted it to the VPC.

I've also added some defaults, so users who are not interested
lower-level settings can ignore them.  You can find Container Linux
AMIs in [5] if you want to test ec2_ami.  I've added a dependency on
modules/container_linux to get local container_linux_version support
for 'lastest'.  Without that, even users setting ec2_ami would need to
set a major.minor.patch container_linux_version to avoid hitting:

  * module.etcd.data.aws_ami.coreos_ami: data.aws_ami.coreos_ami: Your
    query returned no results. Please change your search criteria and
    try again.

Some of the module variables are just passed through to lower-level
providers (e.g. ssh_key is passed through to aws_instance's key_name).
That sort of thing is awkward at the moment, because there's no
generic way to declare a variable unset (vs. setting it to some sort
of zero value).  Terraform will grow support for that distinction (via
a 'null' value) in 0.12 as part of HCL2 [6,7].  Terraform 0.12 is due
out in the next few months [7].

The hcl pretty printing is supported by Linguist [8], which GitHub
uses for syntax highlighting [9].

[1]: https://www.terraform.io/docs/modules/create.html#standard-module-structure
[2]: https://github.com/coreos/etcd/blob/master/README.md#etcd-tcp-ports
[3]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
[4]: https://www.terraform.io/docs/providers/aws/r/security_group.html#argument-reference
[5]: https://coreos.com/os/docs/latest/booting-on-ec2.html
[6]: hashicorp/terraform#5471 (comment)
[7]: https://www.hashicorp.com/blog/terraform-0-1-2-preview
[8]: https://github.com/github/linguist/blob/v6.3.1/lib/linguist/languages.yml#L1723-L1733
[9]: https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
frobware pushed a commit to frobware/installer that referenced this issue Sep 17, 2018
READMEs are part of the standard module structure [1], and docs like
this should make onboarding new contributors easier.  The example's
etcd ports are from [2,3].  The egress rule is based on [4], although
I've restricted it to the VPC.

I've also added some defaults, so users who are not interested
lower-level settings can ignore them.  You can find Container Linux
AMIs in [5] if you want to test ec2_ami.  I've added a dependency on
modules/container_linux to get local container_linux_version support
for 'lastest'.  Without that, even users setting ec2_ami would need to
set a major.minor.patch container_linux_version to avoid hitting:

  * module.etcd.data.aws_ami.coreos_ami: data.aws_ami.coreos_ami: Your
    query returned no results. Please change your search criteria and
    try again.

Some of the module variables are just passed through to lower-level
providers (e.g. ssh_key is passed through to aws_instance's key_name).
That sort of thing is awkward at the moment, because there's no
generic way to declare a variable unset (vs. setting it to some sort
of zero value).  Terraform will grow support for that distinction (via
a 'null' value) in 0.12 as part of HCL2 [6,7].  Terraform 0.12 is due
out in the next few months [7].

The hcl pretty printing is supported by Linguist [8], which GitHub
uses for syntax highlighting [9].

[1]: https://www.terraform.io/docs/modules/create.html#standard-module-structure
[2]: https://github.com/coreos/etcd/blob/master/README.md#etcd-tcp-ports
[3]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
[4]: https://www.terraform.io/docs/providers/aws/r/security_group.html#argument-reference
[5]: https://coreos.com/os/docs/latest/booting-on-ec2.html
[6]: hashicorp/terraform#5471 (comment)
[7]: https://www.hashicorp.com/blog/terraform-0-1-2-preview
[8]: https://github.com/github/linguist/blob/v6.3.1/lib/linguist/languages.yml#L1723-L1733
[9]: https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
@midacts
Copy link

midacts commented Dec 14, 2018

Terraform v12.0 does not have any end date in sight.
It has already been 6+ months since the v0.12 preview was announced.

This issue has been open for 2.5+ years. : [

@rcarmo
Copy link

rcarmo commented Jan 3, 2019

Well, I hope it's gonna be a great 2019 (for me, at least, having this will help make it a better year).

@dene14
Copy link

dene14 commented Mar 5, 2019

It's not gonna happen in my life...

@sprutner
Copy link
Contributor

0.12 is out!

@rapster83
Copy link

rapster83 commented May 29, 2019

https://github.com/hashicorp/terraform/releases/tag/v0.12.0 --> Solves the problem finally! :-)

@wontonst
Copy link

The value is just null

eg var.foo != "" ? var.foo : null

@mikalai-t
Copy link

But it seems doesn't work as expected :( Just called from the upstream module and passed null value as described at Terraform 0.12 docs expecting the value would be omitted

Error: Error in function call

  on ../aws-iam-role/main.tf line 20, in locals:
  20:   iam_role_tags                       = "${merge(var.iam_role_tags, map("Name", format("%s", local.iam_role_name)), map("terraform", "true"))}"
    |----------------
    | local.iam_role_name is "rds-config-role"
    | var.iam_role_tags is null

Call to function "merge" failed: panic in function implementation: can't use
ElementIterator on null value
goroutine 325 [running]:
runtime/debug.Stack(0xc00066dfa8, 0x1856a20, 0x1f7f5d0)

@pselle
Copy link
Contributor

pselle commented Jun 11, 2019

@mikalai-t Thank you for the report here! I've opened a fresh issue as this looks like a valid bug we should fix. I'm going to lock the conversation here, since the original issue has been closed by the release of 0.12, and I want to make sure we don't lose track of comments on this open issue.

@hashicorp hashicorp locked as resolved and limited conversation to collaborators Jun 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests