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

Semantic enable/disable resource #27936

Closed
schollii opened this issue Feb 26, 2021 · 6 comments
Closed

Semantic enable/disable resource #27936

schollii opened this issue Feb 26, 2021 · 6 comments

Comments

@schollii
Copy link

schollii commented Feb 26, 2021

[As recommended by @apparentlymart in https://github.com/hashicorp/hcl/issues/450, I'm moving this improvement request here.]

The notion of "nullness" or "existence" must be first class in a language, and the language should minimize how much "how" the user needs to express.

Currently in order to make resources and modules optional, we have to resort to using count = 0 or 1. Examples:

resource "provider_type" "name" {
  count = var.name_enabled ? 1 : 0
  ...
} 

The problem is that in current HCL the resource provider_type.name doesn't exist OR it is a list of one item, which is not only counter-intuitive (because a resource that exists is semantically very different from a list of 1 resource, and a resource that does not exist is fundamentally different from an empty list). Code which, prior to making the resource optional, was working, should have need modification to use list syntax instead. For example before making a resource optional,

resource "provider_type_1" "name1" {
  some_var = "abc"
} 
resource "provider_type_2" "name2" {
  some_other_var = provider_type_1.name
1.some_attribute ? "a" : "b"
}

Now make name1 optional, you have to change name2 to use list item 0:

resource "provider_type_1" "name1" {
  count = var.name1_enabled ? 1 : 0
  some_var = "abc"
} 
resource "provider_type_2" "name2" {
  some_other_var = provider_type_1.name1[0].some_attribute ? "a" : "b"
}

The name1[0] is actually anti-declarative: you are forcing the HCL code programmer to tell the HCL interpreter how to access the resource, whereas the fact that the resource is stored internally in a list of 1 item is an implementation detail that is of no concern to the user. Declarative implies to say what you want, and the program figures out how to do it. Here, it should be fine to write provider_type_1.name1.some_attribute ? "a" : "b" and HCL interpreter should know that obviously it is referring to the only resource provider_type_1.name1 that exists.

Similarly if I define an item as a list, it really is a list: a list of no items, 1 item, or N>1 items, all are lists and the code should reflect that. So if I write

resource "provider_type" "name" {
  count = var.number_of_name_items
  some_var = "abc"
} 

clearly the semantics of provider_type.name is that of a list, even if there is 1 item, or no items. And so all code that refers to provider_type.name should have to use list methods, even when there is only 1 or 0 item. This contrasts to the first example where count is being used as a boolean. Both uses are fundamentally different, and this should be reflected in the language.

Since enabling/disabling resources and modules is fundamentally different from creating and manipulating lists of items, it should have its own meta variable. I should be able to write

resource "provider_type_1" "name1" {
  enabled = var.name1_enabled
  some_var = "abc"
} 
resource "provider_type_2" "name2" {
  some_other_var = provider_type_1.name1.some_attribute ? "a" : "b"
}

In addition, the language should make it easy to handle the situation where code refers to a resource that has been disabled. It is probably reasonable for the above expression provider_type_1.name1.some_attribute ? "a" : "b" to fail if name1 disabled because for HCL interpreter, "if name1 exists then here is how you determine the value of provider_type_2.name2.some_other_var, but I (HCL) don't know what to do if provider_type_1.name1 does not exist". The failure is a good flag to raise to the user, so they have to think about what some_other_var should be if name1 does not exist. But in most cases, a reasonable default should be easy to write. One option would be to support a quarternary operator where the third option is used if any objects in the expression are nil. Eg

provider_type_1.name1.some_attribute ? "a" : "b" : "use_this_value_if_nil"

The third value (the 4th argument of the quaternary operator) would be used if the expression on the LHS (the 1st argument of quaternay operator) cannot be evaluated because some objects are nil. Syntax errors and calling an non-existent method on a non-nil object should still fail. An expression on LHS of ? like concat(a.b, c.d.e, f.g) would use the 3rd option if any of a, c, f, or c.d are nil.

The notion of "nullness" or "existence" should be first class in a language, and the language should minimize how much "how" the user needs to express.

@jbardin
Copy link
Member

jbardin commented Feb 26, 2021

Hi @schollii

Thanks for the detailed proposal. It appears you already have an enhancement request open in #24995, is this meant to differ in any significant way?

Just to link everything together, the request for an improved method for conditional resource handling is also being tracked in #21953.

@schollii
Copy link
Author

This latest one that I wrote just provides a lot more detail and use cases expand on #21953. Would it make sense for me to move the ticket description into #21953 and close the current one?

@jbardin
Copy link
Member

jbardin commented Feb 26, 2021

Moving the information over would be great. Keeping these together will make it more visible in the large volume of requests.

Thanks!

@jbardin
Copy link
Member

jbardin commented Mar 1, 2021

Merging into #21953 for greater visibility.

@jbardin jbardin closed this as completed Mar 1, 2021
@schollii
Copy link
Author

schollii commented Mar 1, 2021

Thanks @jbardin for moving it, I can check that one off my todo list!

@ghost
Copy link

ghost commented Apr 1, 2021

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 have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked as resolved and limited conversation to collaborators Apr 1, 2021
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

2 participants