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

Preconditions and Postconditions #30401

Merged
merged 8 commits into from
Feb 2, 2022
Merged

Conversation

alisdair
Copy link
Contributor

@alisdair alisdair commented Jan 24, 2022

This PR introduces two new concepts to help document expectations and assumptions about resources, data sources, and outputs. By specifying precondition and postcondition blocks, module authors can define explicit checks which must be true for the configuration to be valid.

Preconditions are checked before creating a resource, reading a data source, or recording a module output value. These can be thought of as documented assumptions about the referenced data, which are checked by Terraform on every plan and apply. Preconditions can refer to values elsewhere in the configuration (which may cause Terraform to reorder the operations on those dependencies).

Postconditions are checked after creating a resource or reading a data source. As such, they may refer to values in the resource or data source directly. These can be thought of as assertions about the referenced data, ensuring that the module adheres to an explicit contract.

In configuration, preconditions and postconditions look a lot like custom variable validation rules, and in fact use the same underlying code. Here's a brief example:

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = "ami-abc123"

  lifecycle {
    # A resource with a precondition can ensure that the selected AMI
    # is set up correctly to work with the instance configuration.
    precondition {
      condition     = data.aws_ami.example.architecture == "x86_64"
      error_message = "The selected AMI must be for the x86_64 architecture."
    }

    # A resource with a postcondition can react to server-decided values
    # during the apply step and halt work immediately if the result doesn't
    # meet expectations.
    postcondition {
      condition     = self.private_dns != ""
      error_message = "EC2 instance must be in a VPC that has private DNS hostnames enabled."
    }
  }
}

For more examples and further background, see the included documentation page.

This PR is a rebase and update of #27008, and as such most of the code was written by @apparentlymart, apart from the bugs which are probably mine.

This construct of a block containing a condition and an error message will
be useful for other sorts of blocks defining expectations or contracts, so
we'll give it a more generic name in anticipation of it being used in
other situations.
This allows precondition and postcondition checks to be declared for
resources and output values as long as the preconditions_postconditions
experiment is enabled.

Terraform Core doesn't currently know anything about these features, so
as of this commit declaring them does nothing at all.
If a resource or output value has a precondition or postcondition rule
then anything the condition depends on is a dependency of the object,
because the condition rules will be evaluated as part of visiting the
relevant graph node.
@alisdair alisdair force-pushed the f-preconditions-postconditions-rebased branch from ba06388 to 904bb28 Compare January 28, 2022 16:03
apparentlymart and others added 4 commits January 31, 2022 14:02
If the configuration contains preconditions and/or postconditions for any
objects, we'll check them during evaluation of those objects and generate
errors if any do not pass.

The handling of post-conditions is particularly interesting here because
we intentionally evaluate them _after_ we've committed our record of the
resulting side-effects to the state/plan, with the intent that future
plans against the same object will keep failing until the problem is
addressed either by changing the object so it would pass the precondition
or changing the precondition to accept the current object. That then
avoids the need for us to proactively taint managed resources whose
postconditions fail, as we would for provisioner failures: instead, we can
leave the resolution approach up to the user to decide.

Co-authored-by: Alisdair McDiarmid <alisdair@users.noreply.github.com>
This is not currently gated by the experiment only because it is awkward
to do so in the context of evaluationStateData, which doesn't have any
concept of experiments at the moment.
@alisdair alisdair force-pushed the f-preconditions-postconditions-rebased branch from 904bb28 to cdae6d4 Compare January 31, 2022 20:38
@alisdair alisdair changed the title Prototype: Preconditions and Postconditions Preconditions and Postconditions Jan 31, 2022
@alisdair alisdair marked this pull request as ready for review January 31, 2022 20:51
Copy link
Member

@jbardin jbardin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to verify that there are no self-references via a full address in these blocks, as that will bypass the self check in preconditions and possibly cause cycles to crop up during apply. This otherwise LGTM if you want to tackle that extra validation in a separate PR.

@alisdair
Copy link
Contributor Author

alisdair commented Feb 2, 2022

Thanks! Good catch, and I'll handle that in a follow-up PR for easier review.

@alisdair alisdair merged commit 0634c94 into main Feb 2, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2022

Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2022

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants