hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.39k stars 9.49k forks source link

Add support for lifecycle meta-argument in modules #27360

Open elliott-weston-cko opened 3 years ago

elliott-weston-cko commented 3 years ago

Current Terraform Version

Terraform v0.14.3

Use-cases

Terraform currently only allows the lifecycle meta-argument to be used within the declaration of a resource. It would be really useful if users were able to specify lifecycle blocks in modules that can then be applicable to some/all of the resources within that module.

The main use-case I have is being able to use the ignore_changes to instruct terraform to ignore changes to resources or particular attributes of resources.

Proposal

For example, lets assume I create a terraform module to be used in AWS, and as part of that module I create a dynamodb table. DynamoDB tables (among other resources) have the ability to autoscale, the autoscaling configuration is defined by another resource. Consequently, a lifecycle block must be used to prevent the resource that creates the dynamodb table from modifying the read/write capacity.

In this scenario I currently have to choose to either to support autoscaling or to not support autoscaling, as I cannot pass define a lifecycle block with the ignore_changes argument. Ideally, I'd like to be able to do something like this:

module "my-module" {
  source = "./my-module/"
  name = "foo-service"

  hash_key = "FooID"
  attributes = [
    {
      name = "FooID"
      type = "S"
    }
  ]
  lifecycle {
    ignore_changes = [
      aws_dynamodb_table.table.read_capacity,
      aws_dynamodb_table.table.write_capacity
    ]
  }
}

Being able to apply lifecycle blocks similarly to the way shown above, would enable me to manage the attributes of this resource outside of this module (whether that's via some automated process, or another resource/module definition), and would allow more people to use this module as it would be usable for a wider range of use-cases.

The documentation states that the lifecycle block can only support literal values, I'm unsure if my proposal would fall under that, as its referring to resources (and possibly attributes) that are created within the module itself 🤔

References

sebastianrogers commented 1 year ago

Thank you @nlitchfield tags can contain information that is sensitive your examples are very good ones.

"Lastly tell you SOC to shhhhhhhhhhhhhhh its only tags :)"

I notice the use of 'only' in the above and really must blog about why you should always be very suspicious if either the word 'only' or 'just' are used when discussing technology. They indicate something someone doesn't want to deal with and almost certainly should.

PauloColegato commented 1 year ago

Thank you @nlitchfield tags can contain information that is sensitive your examples are very good ones.

"Lastly tell you SOC to shhhhhhhhhhhhhhh its only tags :)"

I notice the use of 'only' in the above and really must blog about why you should always be very suspicious if either the word 'only' or 'just' are used when discussing technology. They indicate something someone doesn't want to deal with and almost certainly should.

@sebastianrogers there are bigger things to worry about than just tags in my experience.

I would also take your assumption of my comments to indicate you are someone who jumps to conclusions about people, when they almost certainly shouldn't - especially if they are just trying to help you.

Perhaps have a look in the mirror buddy.

Have a cracking day and i wish all the best in your endeavours, hopefully you can sort your tagging woes out, along with your attitude.

sebastianrogers commented 1 year ago

OFFICIAL

Paulo sorry to cause offense, I do appreciate help, but the person I'm most concerned about saying just or only is actually myself not you, the phrasing was clumsy. I've noticed that when I try to dismiss something as unimportant it often means that I cannot be bothered to deal with it as I know its going to be hard or unpleasant to deal with. When I do blog about the use of just and only I'm going to bear your comments in mind so people realise that its something I guard against. Anyway we have wandered, somewhat enjoyably, off topic so I'll stop now.


From: PauloColegato @.> Sent: 21 November 2022 09:12 To: hashicorp/terraform @.> Cc: Sebastian Rogers @.>; Mention @.> Subject: Re: [hashicorp/terraform] Add support for lifecycle meta-argument in modules (#27360)

Thank you @nlitchfieldhttps://github.com/nlitchfield tags can contain information that is sensitive your examples are very good ones.

"Lastly tell you SOC to shhhhhhhhhhhhhhh its only tags :)"

I notice the use of 'only' in the above and really must blog about why you should always be very suspicious if either the word 'only' or 'just' are used when discussing technology. They indicate something someone doesn't want to deal with and almost certainly should.

@sebastianrogershttps://github.com/sebastianrogers there are bigger things to worry about than just tags in my experience.

I would also take your assumption of my comments to indicate you are someone who jumps to conclusions about people, when they almost certainly shouldn't - especially if they are just trying to help you.

Perhaps have a look in the mirror buddy.

Have a cracking day and i wish all the best in your endeavours, hopefully you can sort your tagging woes out, along with your attitude.

— Reply to this email directly, view it on GitHubhttps://github.com/hashicorp/terraform/issues/27360#issuecomment-1321735609, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ABNUOXFDKTJBMYZQF3GWZLTWJM4JBANCNFSM4VH7MFUQ. You are receiving this because you were mentioned.Message ID: @.***>

ferduz commented 1 year ago

+1 pleaseee

pantelis-karamolegkos commented 1 year ago

This would be highly helpful for also leveraging the precondition / postcondition arguments in module creation since this is not currently possible AFAIK.

lupass93 commented 1 year ago

+1, absolutely necessary feature!

pat-s commented 1 year ago

Can this issue be locked?

nlitchfield commented 1 year ago

Can this issue be locked?

Why? The discussion shows this would be a widely appreciated feature. What does closing off the discussion achieve?

glenthomas commented 1 year ago

Can this issue be locked?

Why? The discussion shows this would be a widely appreciated feature. What does closing off the discussion achieve?

The etiquette for expressing your appreciation for an issue, is to add a 'thumbs up' emoji to the original post. Commenting with "+1, I would ❤️ this too" is typically considered bad manners.

jbardin commented 1 year ago

Hello All!

I see that this is getting a lot of attention, but we don't yet have a clear goal in this issue. A lifecycle block is not applicable to a module, because a module has no lifecycle to which it can be applied. It does not store data, nor does it directly set any ordering of resource evaluation. Resources within a module may be evaluated before or after resources in any other module depending on the interdependencies of those resources. Preconditions, postconditions, replace_triggered_by, etc. also don't apply for the same reasons, there is not a clear definition of "before", "after", or replacement in module evaluation, at least in a sense that would be intuitive from the configuration.

I think the more general idea here is to have a way to override resource configuration from outside of a module. This is difficult for many reasons, some of which have been outlined already. The lifecycle block in particular contains special references which are relative to the containing resource, and themselves are not interpolated. What we would end up with essentially is an ad-hoc templating system, which has the ability to lead to a lot of unintended interactions within the language.

It's not that we're not considering these features at all, but I just want to convey that issues like this are often much more nuanced than they may appear on the surface.

Shocktrooper commented 1 year ago

@jbardin I think what could happen here and still allow for the module architecture to work is to only allow a specific subset of the lifecycle arguments and the ones that are allowed are propogated to every individual resource in the module as if they had their own individually declared. For instance let's say I want to prevent the destruction of all resources in a module, prevent_destroy would be handy to declare and propogate down. Replace_triggered_by could potentially work. Pre and post conditions I think are out. Create_before_destroy is a weird one, It almost has to be combined with a depends_on block at the module level for people to get use out if it if I am thinking of it correctly and even then it could have unintended consequences due to its nature.

jbardin commented 1 year ago

Thanks @Shocktrooper, the fact that it only works on a subset of features, or in certain combinations, or with a list of exceptions when describing the feature is usually a red flag when evaluating a potential design. For example, replace_triggered_by specifically cannot work like that, because the reference needs to be within scope of the resource to which it is applied, and if that in-scope resource could be referenced from outside the module, applying it to all resources within a module will create cycles.

The prevent_destroy feature is one which is closer to theoretically possible, but since the actual meaning of that feature is more along the lines of "prevent-replace", and a module itself has no changes to prevent, it risks being even more confusing than the existing resource feature which users historically have not found very useful. The only time it would come into play would be when the user directly plans a destroy operation, in which case the same behavior is had from a single null_resource in the root module with prevent_destroy=true.

This is why I think the more general problem statement of "alter resource configuration from outside the module" better encompasses what users appear to be trying to do, rather than prescribing solutions which are not a good fit within the current design.

Yakuza-UA commented 1 year ago

+1 for the feature

We use Azure Policy to set tags at a resource Group level so we want to tell Terraform to ignore all changes to these tags at a resource level.

For example:

module "my-module" {
  source = "./my-module/"
  name = "foo-service"

  lifecycle {
    ignore_changes = [
      tags["CostCenter"],
      tags["ProjectName"]
    ]
  }
}

We have exact same scenario now. We've been forced to apply Azure tags at resource group level using Azure Policy. The very same policy propagates tags to all resources within RG. For resources within root module we simply configure Lifecycle's ignore changes feature to ignore any changes in tags, except for the RG. However, modules made this more complicated... modules do not support lifecycle block AT module block (e.g. it's not possible to pass the intention to ignore certain changes to resources managed by the module)... as such, we see two options

  1. Change module code to add lifecycle block to each resource deployed by the module
  2. Accept the fact that Terraform will detect drift on each run of the plan phase (changed tags)

Both options are nasty... modules should be universal as much as possible, hence hardcoding lifecycle to ignore tags within a module goes against this principle. Having drift reported for each merge request is not ideal either... instead of seeing REAL changes in a summarized report, our engineers and reviewers will have to drill down to terraform plan logs to actually see what's changing.

A proper, more strategical solution, would be highly appreciated - such as an ability to pass lifecycle property(ies) into the module... or some other alternative

leanrobot commented 1 year ago

+1 tracking this feature, would be helpful for ignoring things such as asg_desired_size on our EKS cluster, as it may be scaled via the terminal. It is part of an external module, so I can't add the lifecycle to the resource directly.

ericitaquera commented 1 year ago

Hello.

Sorry for adding repetitive (maybe) argument here.

Our use case is a module which we need to use for both creation (apply) and deletion (destroy).

In order to align terraform to the rest of our pipeline it´d be great to be able to declare the lifecycle block in the root module instead of the main module.

As of:

{
  "module": {
    "pubsub_topic": {
      "source": "git::ssh://git@git.url.ur:7999/git-project/terraform-gcp-pubsub-topic.git",
      "pubsub_topics": "${var.pubsub_topics}",
      "lifecycle":{
        "prevent_destroy" : true
      }
    }
  },
  "variable": {
    "pubsub_topics": {
      "default": {}
    }
  }
}

Regards

suneerpm commented 1 year ago

we are looking for having this feature. This feature is critical for the adoption of modules. Currently lifecyclepolicy and moduleare not working very well - almost in a collision course. I cannot have resourceblock in a module that automatically prevent_destroyif my envis production.

thiagolsfortunato commented 1 year ago

Any news? 👀

gabrielmoterani commented 1 year ago

+1

crw commented 1 year ago

Thanks for your interest in this issue! This is just a reminder to please avoid "+1" comments, and to use the upvote mechanism (click or add the 👍 emoji to the original post) to indicate your support for this issue. We are aware of this issue (it is one of the highest-upvoted issues, currently 4th highest upvoted) and we do not have any updates to share. Thanks again for the feedback!

kderck commented 1 year ago

This would help with separation of concerns. I have a module that creates a resource, sometimes I want to ignore changes, other times I do not want to ignore changes.

tmpjg commented 9 months ago

In my company we stopped the free publication of a module that deploys a fully functional kubernetes cluster for AWS production because the cluster cloud controller generates changes in subnets, groups, tags, etc. and the terraform module tries to replace these changes constantly. We didn't find a reliable workaround for this.

naomichi-y commented 8 months ago

I use the Opensearch Service, but this service itself does not have delete protection, so I have had incidents in the past where I have unintentionally deleted resources. We have sent a feature request to AWS, but not all features have delete protection, so it would be very useful if Terraform could provide protection.

framctr commented 7 months ago

This would help in avoiding things from destroy

justin-octo commented 5 months ago

We use GuardDuty. We have this configured at the organizational level. Being able to ignore_changes might solve the problem we have of our security account trying to delete the Detectors (because it's not in our configs for that account).

justin-octo commented 5 months ago

We use GuardDuty. We have this configured at the organizational level. Being able to ignore_changes might solve the problem we have of our security account trying to delete the Detectors (because it's not in our configs for that account).

Never mind. Didn't need the ignore_changes after all. We upgraded versions of the terraform-aws-service-catalog and there were changes to the resource naming. A terragrunt import and terragrunt state rm fix the issue.

binnythomas-corsearch commented 3 months ago

Is some one actually doing something about this? Or is this a zombie ticket?

JamesDLD commented 3 months ago

Would be great, thanks!

jbbeal commented 2 months ago

Precondition are another useful feature in lifecycle blocks I would like to have for module references.

ilsaloving commented 1 month ago

Any updates to this? I realize there isn't much call for it since there's only over eleven hundred thumb-ups, but it would be kinda nice, y'know?

jorsmatthys commented 3 weeks ago

I would like to see this feature as well. We encapsulate resources in "base-modules" at my current customer, and those modules are re-used in many terraform projects to deploy solutions to Azure. In some cases things like standard tags we apply to those resources are overwritten by policy on Azure, triggering changes in every terraform run. Though what @chancez proposes would work for us, I feel like being able to just ignore these changes at the module level when the occasional need arises would feel more natural/cleaner/easier than modifying the interface of our "base-modules" to support passing lifecycle arguments to any of the underlying resources.