Merge branch 'main' into patch-1

This commit is contained in:
Adam J Bravo 2025-05-14 11:52:20 -04:00 committed by GitHub
commit a3948bad06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3660 changed files with 357525 additions and 65346 deletions

0
.changes/1.13.0.md Normal file
View file

5
.changes/README.md Normal file
View file

@ -0,0 +1,5 @@
# Changelog
This directory contains changelog entries for each release of Terraform.
The only important folder for changes is the `vX.XX` folder corresponding with the Terraform version released from this branch.
All other folders are just there to make backports easier. You can remove folders with releases we won't allow backports for.

View file

@ -0,0 +1,10 @@
EXPERIMENTS:
Experiments are only enabled in alpha releases of Terraform CLI. The following features are not yet available in stable releases.
- The new command `terraform rpcapi` exposes some Terraform Core functionality through an RPC interface compatible with [`go-plugin`](https://github.com/hashicorp/go-plugin). The exact RPC API exposed here is currently subject to change at any time, because it's here primarily as a vehicle to support the [Terraform Stacks](https://www.hashicorp.com/blog/terraform-stacks-explained) private preview and so will be broken if necessary to respond to feedback from private preview participants, or possibly for other reasons. Do not use this mechanism yet outside of Terraform Stacks private preview.
- The experimental "deferred actions" feature, enabled by passing the `-allow-deferral` option to `terraform plan`, permits `count` and `for_each` arguments in `module`, `resource`, and `data` blocks to have unknown values and allows providers to react more flexibly to unknown values. This experiment is under active development, and so it's not yet useful to participate in this experiment
## Previous Releases
For information on prior major and minor releases, refer to their changelogs:

3
.changes/footer.md Normal file
View file

@ -0,0 +1,3 @@
## Previous Releases
For information on prior major and minor releases, refer to their changelogs:

View file

@ -0,0 +1,18 @@
- [v1.12](https://github.com/hashicorp/terraform/blob/v1.12/CHANGELOG.md)
- [v1.11](https://github.com/hashicorp/terraform/blob/v1.11/CHANGELOG.md)
- [v1.10](https://github.com/hashicorp/terraform/blob/v1.10/CHANGELOG.md)
- [v1.9](https://github.com/hashicorp/terraform/blob/v1.9/CHANGELOG.md)
- [v1.8](https://github.com/hashicorp/terraform/blob/v1.8/CHANGELOG.md)
- [v1.7](https://github.com/hashicorp/terraform/blob/v1.7/CHANGELOG.md)
- [v1.6](https://github.com/hashicorp/terraform/blob/v1.6/CHANGELOG.md)
- [v1.5](https://github.com/hashicorp/terraform/blob/v1.5/CHANGELOG.md)
- [v1.4](https://github.com/hashicorp/terraform/blob/v1.4/CHANGELOG.md)
- [v1.3](https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md)
- [v1.2](https://github.com/hashicorp/terraform/blob/v1.2/CHANGELOG.md)
- [v1.1](https://github.com/hashicorp/terraform/blob/v1.1/CHANGELOG.md)
- [v1.0](https://github.com/hashicorp/terraform/blob/v1.0/CHANGELOG.md)
- [v0.15](https://github.com/hashicorp/terraform/blob/v0.15/CHANGELOG.md)
- [v0.14](https://github.com/hashicorp/terraform/blob/v0.14/CHANGELOG.md)
- [v0.13](https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md)
- [v0.12](https://github.com/hashicorp/terraform/blob/v0.12/CHANGELOG.md)
- [v0.11 and earlier](https://github.com/hashicorp/terraform/blob/v0.11/CHANGELOG.md)

0
.changes/v1.11/.gitkeep Normal file
View file

View file

@ -0,0 +1,5 @@
kind: BUG FIXES
body: 'write-only attributes: internal providers should set write-only attributes to null'
time: 2025-04-02T14:39:31.672249+02:00
custom:
Issue: "36824"

0
.changes/v1.12/.gitkeep Normal file
View file

View file

@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: 'backend/oss: Supports more standard environment variables to keep same with provider setting'
time: 2025-03-03T17:18:38.679213+08:00
custom:
Issue: "36581"

View file

@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: '`import` blocks: Now support importing a resource via a new identity attribute. This is mutually exclusive with the `id` attribute'
time: 2025-04-17T18:20:36.814657+02:00
custom:
Issue: "36703"

View file

@ -0,0 +1,5 @@
kind: NEW FEATURES
body: Added Terraform backend implementation for OCI Object Storage
time: 2025-04-10T15:48:05.919664+05:30
custom:
Issue: "34465"

0
.changes/v1.13/.gitkeep Normal file
View file

View file

@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: Filesystem functions are now checked for consistent results to catch invalid data during apply
time: 2025-05-08T13:01:35.450576-04:00
custom:
Issue: "37001"

32
.changie.yaml Normal file
View file

@ -0,0 +1,32 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
changesDir: .changes
unreleasedDir: v1.13
versionFooterPath: version_footer.tpl.md
changelogPath: CHANGELOG.md
versionExt: md
versionFormat: '## {{.Version}} ({{.Time.Format "January 2, 2006"}})'
kindFormat: "{{.Kind}}:"
changeFormat: "* {{.Body}} {{- if .Custom.Issue }} ([#{{.Custom.Issue}}](https://github.com/hashicorp/terraform/issues/{{.Custom.Issue}})){{- end}}"
custom:
- key: Issue
label: Issue/PR Number
type: int
minInt: 1
kinds:
- label: NEW FEATURES
- label: ENHANCEMENTS
- label: BUG FIXES
- label: NOTES
- label: UPGRADE NOTES
- label: BREAKING CHANGES
newlines:
afterChangelogHeader: 0
beforeKind: 1
afterKind: 1
afterChange: 1
afterVersion: 1
beforeChangelogVersion: 0
endOfVersion: 2
envPrefix: CHANGIE_

21
.copywrite.hcl Normal file
View file

@ -0,0 +1,21 @@
schema_version = 1
project {
license = "BUSL-1.1"
copyright_year = 2024
# (OPTIONAL) A list of globs that should not have copyright/license headers.
# Supports doublestar glob patterns for more flexibility in defining which
# files or folders should be ignored
header_ignore = [
"**/*.tf",
"**/testdata/**",
"**/*.pb.go",
"**/*_string.go",
"**/mock*.go",
".changes/**",
# these directories have their own copywrite config
"docs/plugin-protocol/**",
"internal/tfplugin*/**"
]
}

View file

@ -1,26 +1,21 @@
# Contributing to Terraform
This repository contains only Terraform core, which includes the command line interface and the main graph engine. Providers are implemented as plugins that each have their own repository linked from the [Terraform Registry index](https://registry.terraform.io/browse/providers). Instructions for developing each provider are usually in the associated README file. For more information, see [the provider development overview](https://www.terraform.io/docs/plugins/provider.html).
---
**Note:** Due to current low staffing on the Terraform Core team at HashiCorp, **we are not routinely reviewing and merging community-submitted pull requests**. We do hope to begin processing them again soon once we're back up to full staffing again, but for the moment we need to ask for patience. Thanks!
**Additional note:** The intent of the prior comment was to provide clarity for the community around what to expect for a small part of the work related to Terraform. This does not affect other PR reviews, such as those for Terraform providers. We expect that the relevant team will be appropriately staffed within the coming weeks, which should allow us to get back to normal community PR review practices. For the broader context and information on HashiCorps continued commitment to and investment in Terraform, see [this blog post](https://www.hashicorp.com/blog/terraform-community-contributions).
---
**All communication on GitHub, the community forum, and other HashiCorp-provided communication channels is subject to [the HashiCorp community guidelines](https://www.hashicorp.com/community-guidelines).**
This document provides guidance on Terraform contribution recommended practices. It covers what we're looking for in order to help set some expectations and help you get the most out of participation in this project.
This repository contains Terraform core, which includes the command line interface and the main graph engine.
To record a bug report, enhancement proposal, or give any other product feedback, please [open a GitHub issue](https://github.com/hashicorp/terraform/issues/new/choose) using the most appropriate issue template. Please do fill in all of the information the issue templates request, because we've seen from experience that this will maximize the chance that we'll be able to act on your feedback.
Providers are implemented as plugins that each have their own repository linked from the [Terraform Registry index](https://registry.terraform.io/browse/providers). Instructions for developing each provider are usually in the associated README file. For more information, see [the provider development overview](https://developer.hashicorp.com/terraform/plugin).
This document provides guidance on Terraform contribution recommended practices. It covers what we're looking for in order to help set expectations and help you get the most out of participation in this project.
To report a bug, an enhancement proposal, or give any other product feedback, please [open a GitHub issue](https://github.com/hashicorp/terraform/issues/new/choose) using the most appropriate issue template. Please fill in all of the information the issue templates request. This will maximize our ability to act on your feedback.
---
<!-- MarkdownTOC autolink="true" -->
- [Contributing Fixes](#contributing-fixes)
- [Introduction](#Introduction)
- [Contributing a Pull Request](#contributing-a-pull-request)
- [Proposing a Change](#proposing-a-change)
- [Caveats & areas of special concern](#caveats--areas-of-special-concern)
- [State Storage Backends](#state-storage-backends)
@ -28,6 +23,9 @@ To record a bug report, enhancement proposal, or give any other product feedback
- [Maintainers](#maintainers)
- [Pull Request Lifecycle](#pull-request-lifecycle)
- [Getting Your Pull Requests Merged Faster](#getting-your-pull-requests-merged-faster)
- [Changelog entries](#changelog-entries)
- [Create a change file using `changie`](#create-a-change-file-using-changie)
- [Backport a PR to a past release](#backport-a-pr-to-a-past-release)
- [PR Checks](#pr-checks)
- [Terraform CLI/Core Development Environment](#terraform-clicore-development-environment)
- [Acceptance Tests: Testing interactions with external services](#acceptance-tests-testing-interactions-with-external-services)
@ -36,15 +34,31 @@ To record a bug report, enhancement proposal, or give any other product feedback
<!-- /MarkdownTOC -->
## Contributing Fixes
## Introduction
It can be tempting to want to dive into an open source project and help _build the thing_ you believe you're missing. It's a wonderful and helpful intention. However, Terraform is a complex tool. Many seemingly simple changes can have serious effects on other areas of the code and it can take some time to become familiar with the effects of even basic changes. The Terraform team is not immune to unintended and sometimes undesirable changes. We do take our work seriously, and appreciate the globally diverse community that relies on Terraform for workflows of all sizes and criticality.
One of the great things about publicly available source code is that you can dive into the project and help _build the thing_ you believe is missing. It's a wonderful and generous instinct. However, Terraform is a complex tool. Even simple changes can have a serious impact on other areas of the code and it can take some time to become familiar with the effects of even basic changes. The Terraform team is not immune to unintended and sometimes undesirable consequences. We take our work seriously, and appreciate the responsibility of maintaining software for a globally diverse community that relies on Terraform for workflows of all sizes and criticality.
As a result of Terraform's complexity and high bar for stability, the most straightforward way to start helping with the Terraform project is to pick an existing bug and [get to work](#terraform-clicore-development-environment).
As a result of Terraform's complexity and high bar for stability, the most straightforward way to help with the Terraform project is to [file a feature request or bug report](https://github.com/hashicorp/terraform/issues/new/choose), following the template to fully express your desired use case.
For new contributors we've labeled a few issues with `Good First Issue` as a nod to issues which will help get you familiar with Terraform development, while also providing an onramp to the codebase itself.
If you believe you can also implement the solution for your bug or feature, we request that you first discuss the proposed solution with the core maintainer team. This discussion happens in GitHub, on the issue you created to describe the bug or feature. This discussion gives the core team a chance to explore any missing best practices or unintended consequences of the proposed change. Participating in this discussion and getting the go-ahead from a core maintainer is the only way to ensure your code is reviewed for inclusion with the project. It is also possible that the proposed solution is not workable, and will save you time writing code that will not be used due to unforeseen unintended consequences. Please read the section [Proposing a Change](#proposing-a-change) for the full details on this process.
(As a side note, this is how we work internally at HashiCorp as well. Changes are proposed internally via an RFC process, in which all impacted teams are able to review the proposed changes and give feedback before any code is written. Written communication of changes via the RFC process is a core pillar of our internal coordination.)
## Contributing a Pull Request
If you are a new contributor to Terraform, or looking to get started committing to the Terraform ecosystem, here are a couple of tips to get started.
First, the easiest way to get started is to make fixes or improvements to the documentation. This can be done completely within GitHub, no need to even clone the project!
Beyond documentation improvements, it is easiest to contribute to Terraform on the edges. If you are looking for a good starting place to contribute, finding and resolving issues in the providers is the best first step. These projects have huge breadth of coverage and are always looking for contributors to fix issues that might not otherwise get the attention of a maintainer.
Closer to home, within the Terraform core repository, working in areas like functions or backends tend to have less harmful unintended interactions with the core of Terraform (but, also, are not currently a high priority to be reviewed, so please discuss any changes with the team before you start.) It gets more difficult to contribute as you get closer to the core functionality (e.g., manipulating the graph and core language features). For these types of changes, please start with the [Proposing a Change](#proposing-a-change) section to understand how we think about managing this process.
Once you are ready to write code, please see the section [Terraform CLI/Core Development Environment](#terraform-clicore-development-environment) to create your dev environment. Please read the documentation, and don't be afraid to ask questions in our [community forum](https://discuss.hashicorp.com/c/terraform-core/27).
You may see the `Good First Issue` label on issues in the Terraform repository on GitHub. We use this label to maintain a list of issues for new internal core team members to ramp up the codebase. That said, if you are feeling particularly ambitious, you can follow our process to propose a solution. Other HashiCorp repositories (for example, https://github.com/hashicorp/terraform-provider-aws/) do use the `Good First Issue` to indicate good issues for external contributors to get started.
Read the documentation, and don't be afraid to [ask questions](https://discuss.hashicorp.com/c/terraform-core/27).
## Proposing a Change
@ -52,13 +66,14 @@ In order to be respectful of the time of community contributors, we aim to discu
If the bug you wish to fix or enhancement you wish to implement isn't already covered by a GitHub issue that contains feedback from the Terraform team, please do start a discussion (either in [a new GitHub issue](https://github.com/hashicorp/terraform/issues/new/choose) or an existing one, as appropriate) before you invest significant development time. If you mention your intent to implement the change described in your issue, the Terraform team can, as best as possible, prioritize including implementation-related feedback in the subsequent discussion.
At this time, we do not have a formal process for reviewing outside proposals that significantly change Terraform's workflow, its primary usage patterns, and its language. Additionally, some seemingly simple proposals can have deep effects across Terraform, which is why we strongly suggest starting with an issue-based proposal.
At this time, we do not have a formal process for reviewing outside proposals that significantly change Terraform's workflow, its primary usage patterns, and its language. Additionally, some seemingly simple proposals can have deep effects across Terraform, which is why we strongly suggest starting with an issue-based proposal. Also, we do not normally accept minor changes in comments or help text.
For large proposals that could entail a significant design phase, we wish to be up front with potential contributors that, unfortunately, we are unlikely to be able to give prompt feedback. We are still interested to hear about your use-cases so that we can consider ways to meet them as part of other larger projects.
Most changes will involve updates to the test suite, and changes to Terraform's documentation. The Terraform team can advise on different testing strategies for specific scenarios, and may ask you to revise the specific phrasing of your proposed documentation prose to match better with the standard "voice" of Terraform's documentation.
This repository is primarily maintained by a small team at HashiCorp along with their other responsibilities, so unfortunately we cannot always respond promptly to pull requests, particularly if they do not relate to an existing GitHub issue where the Terraform team has already participated and indicated willingness to work on the issue or accept PRs for the proposal. We *are* grateful for all contributions however, and will give feedback on pull requests as soon as we're able.
We cannot always respond promptly to pull requests, particularly if they do not relate to an existing GitHub issue where the Terraform team has already participated and indicated willingness to work on the issue or accept PRs for the proposal. We *are* grateful for all contributions however, and will give feedback on pull requests as soon as we are able.
### Caveats & areas of special concern
@ -66,13 +81,18 @@ There are some areas of Terraform which are of special concern to the Terraform
#### State Storage Backends
The Terraform team is not merging PRs for new state storage backends at the current time. Our priority regarding state storage backends is to find maintainers for existing backends and remove those backends without maintainers.
The Terraform team is not merging PRs for new state storage backends. Our priority regarding state storage backends is to find maintainers for existing backends and remove those backends without maintainers.
Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given backend. Community members with an interest in a particular standard backend are welcome to help maintain it.
Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given backend. Community members with an interest in a particular backend are welcome to offer to maintain it.
Currently, merging state storage backends places a significant burden on the Terraform team. The team must set up an environment and cloud service provider account, or a new database/storage/key-value service, in order to build and test remote state storage backends. The time and complexity of doing so prevents us from moving Terraform forward in other ways.
In terms of setting expectations, there are three categories of backends in the Terraform repository: backends maintained by the core team (ex.: http); backends maintained by one of HashiCorp's provider teams (e.g. AWS S3, Azure, etc); and backends maintained by third party maintainers (ex.: Postgres, COS).
* Backends maintained by the core team are unlikely to see accepted contributions. We are triaging incoming pull requests, but these are not highly prioritized against our other work. The smaller and more-contained the change, the more likely it will be reviewed (please see also [Proposing a Change](#proposing-a-change)).
* Backends maintained by one of HashiCorp's provider teams review contributions irregularly. There is no official commitment, typically once every few months one of the maintainers will review a number of backend PRs relating to their provider. The S3 and Azure backends tend to see the most on-going development.
* Backends maintained by third-party maintainers are reviewed at the whim and availability of those maintainers. When the maintainer gives a positive code review to the pull request, the core team will do a review and merge the changes.
We are working to remove ourselves from the critical path of state storage backends by moving them towards a plugin model. In the meantime, we won't be accepting new remote state backends into Terraform.
#### Provisioners
@ -80,17 +100,18 @@ Provisioners are an area of concern in Terraform for a number of reasons. Chiefl
There are two main types of provisioners in Terraform, the generic provisioners (`file`,`local-exec`, and `remote-exec`) and the tool-specific provisioners (`chef`, `habbitat`, `puppet` & `salt-masterless`). **The tool-specific provisioners [are deprecated](https://discuss.hashicorp.com/t/notice-terraform-to-begin-deprecation-of-vendor-tool-specific-provisioners-starting-in-terraform-0-13-4/13997).** In practice this means we will not be accepting PRs for these areas of the codebase.
From our [documentation](https://www.terraform.io/docs/provisioners/index.html):
From our [documentation](https://developer.hashicorp.com/terraform/language/resources/provisioners/syntax):
> ... they [...] add a considerable amount of complexity and uncertainty to Terraform usage.[...] we still recommend attempting to solve it [your problem] using other techniques first, and use provisioners only if there is no other option.
The Terraform team is in the process of building a way forward which continues to decrease reliance on provisioners. In the mean time however, as our documentation indicates, they are a tool of last resort. As such expect that PRs and issues for provisioners are not high in priority.
Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given provisioner. Community members with an interest in a particular provisioner are welcome to help maintain it.
Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given provisioner.
#### Maintainers
Maintainers are key contributors to our Open Source project. They contribute their time and expertise and we ask that the community take extra special care to be mindful of this when interacting with them.
Maintainers are key contributors to our community project. They contribute their time and expertise and we ask that the community take extra special care to be mindful of this when interacting with them.
For code that has a listed maintainer or maintainers in our [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file, the Terraform team will highlight them for participation in PRs which relate to the area of code they maintain. The expectation is that a maintainer will review the code and work with the PR contributor before the code is merged by the Terraform team.
@ -98,14 +119,16 @@ There is no expectation on response time for our maintainers; they may be indisp
If an an unmaintained area of code interests you and you'd like to become a maintainer, you may simply make a PR against our [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file with your github handle attached to the approriate area. If there is a maintainer or team of maintainers for that area, please coordinate with them as necessary.
### Pull Request Lifecycle
1. You are welcome to submit a [draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/) for commentary or review before it is fully completed. It's also a good idea to include specific questions or items you'd like feedback on.
2. Once you believe your pull request is ready to be merged you can create your pull request.
3. When time permits Terraform's core team members will look over your contribution and either merge, or provide comments letting you know if there is anything left to do. It may take some time for us to respond. We may also have questions that we need answered about the code, either because something doesn't make sense to us or because we want to understand your thought process. We kindly ask that you do not target specific team members.
4. If we have requested changes, you can either make those changes or, if you disagree with the suggested changes, we can have a conversation about our reasoning and agree on a path forward. This may be a multi-step process. Our view is that pull requests are a chance to collaborate, and we welcome conversations about how to do things better. It is the contributor's responsibility to address any changes requested. While reviewers are happy to give guidance, it is unsustainable for us to perform the coding work necessary to get a PR into a mergeable state.
5. Once all outstanding comments and checklist items have been addressed, your contribution will be merged! Merged PRs may or may not be included in the next release based on changes the Terraform teams deems as breaking or not. The core team takes care of updating the [CHANGELOG.md](https://github.com/hashicorp/terraform/blob/main/CHANGELOG.md) as they merge.
6. In some cases, we might decide that a PR should be closed without merging. We'll make sure to provide clear reasoning when this happens. Following the recommended process above is one of the ways to ensure you don't spend time on a PR we can't or won't merge.
3. If your change is user-facing, add a short description in a [changelog entry](#changelog-entries).
4. When time permits Terraform's core team members will look over your contribution and either merge, or provide comments letting you know if there is anything left to do. It may take some time for us to respond. We may also have questions that we need answered about the code, either because something doesn't make sense to us or because we want to understand your thought process. We kindly ask that you do not target specific team members.
5. If we have requested changes, you can either make those changes or, if you disagree with the suggested changes, we can have a conversation about our reasoning and agree on a path forward. This may be a multi-step process. Our view is that pull requests are a chance to collaborate, and we welcome conversations about how to do things better. It is the contributor's responsibility to address any changes requested. While reviewers are happy to give guidance, it is unsustainable for us to perform the coding work necessary to get a PR into a mergeable state.
6. Once all outstanding comments and checklist items have been addressed, your contribution will be merged! Merged PRs may or may not be included in the next release based on changes the Terraform teams deems as breaking or not. The core team takes care of updating the [CHANGELOG.md](https://github.com/hashicorp/terraform/blob/main/CHANGELOG.md) as they merge.
7. In some cases, we might decide that a PR should be closed without merging. We'll make sure to provide clear reasoning when this happens. Following the recommended process above is one of the ways to ensure you don't spend time on a PR we can't or won't merge.
#### Getting Your Pull Requests Merged Faster
@ -119,12 +142,45 @@ If we request changes, try to make those changes in a timely manner. Otherwise,
Even with everyone making their best effort to be responsive, it can be time-consuming to get a PR merged. It can be frustrating to deal with the back-and-forth as we make sure that we understand the changes fully. Please bear with us, and please know that we appreciate the time and energy you put into the project.
#### Changelog entries
If your PR's changes are not user-facing add the label `no-changelog-needed`. If this label isn't present and your PR doesn't include any change files a Github Action workflow will prompt you to add whichever is needed.
If your PR's changes are user-facing then you will need to add a change file in your PR. See the next section for how to create one. The change file will need to be created in the `.changes/v1.XX/` folder that matches the version number present in [version/VERSION on the main branch](https://github.com/hashicorp/terraform/blob/main/version/VERSION).
This is different if you are backporting your changes to an earlier release version. In that case, put the change file in the `.changes/v1.XX/` folder for the earliest version that the change is being backported into. For example if a PR was labelled 1.11-backport and 1.10-backport then the change file should be created in the `.changes/v1.10/` folder only.
#### Create a change file using `changie`
If your change is user-facing you can use `npx changie new` to create a new changelog entry via your terminal. The command is interactive and you will need to: select which kind of change you're introducing, provide a short description, and enter either the number of the GitHub issue your PR closes or your PR's number.
Make sure to select the correct kind of change:
| Change kind | When to use |
|------------------|-------------|
| NEW FEATURES | Use this if you've added new, separate functionality to Terraform. For example, introduction of ephemeral resources. |
| ENHANCEMENTS | Use this if you've improved existing functionality in Terraform. Examples include: adding a new field to a remote-state backend, or adding a new environment variable to use when configuring Terraform. |
| BUG FIXES | Use this if you've fixed a user-facing issue. Examples include: crash fixes, improvements to error feedback, regression fixes. |
| NOTES | This is used for changes that are unlikely to cause user-facing issues but might have edge cases. For example, changes to how the Terraform binary is built. |
| UPGRADE NOTES | Use this if you've introduced a change that forces users to take action when upgrading, or changes Terraform's behaviour notably. For example, deprecating a field on a remote-state backend or changing the output of Terraform operations. |
| BREAKING CHANGES | Use this if you've introduced a change that could make a valid Terraform configuration stop working after a user upgrades Terraform versions. This might be paired with an upgrade note change file. Examples include: removing a field on a remote-state backend, changing a builtin function's behavior, making validation stricter. |
#### Backport a PR to a past release
PRs can be backported to previous release version as part of preparing a patch release. For example, a fix for a bug could be merged into main but also backported to one or two previous minor versions.
If you want to backport your PR then the PR needs to have one or more [backport labels](https://github.com/hashicorp/terraform/labels?q=backport) added. The PR reviewer will then ensure that the PR is merged into those versions' release branches, as well as merged into `main`.
### PR Checks
The following checks run when a PR is opened:
- Contributor License Agreement (CLA): If this is your first contribution to Terraform you will be asked to sign the CLA.
- Tests: tests include unit tests and acceptance tests, and all tests must pass before a PR can be merged.
- Change files: PRs that include user-facing changes should include change files (see [Pull Request Lifecycle](#pull-request-lifecycle)). Automation will verify if PRs are labelled correctly and/or contain appropriate change files.
- Vercel: this is an internal tool that does not run correctly for external contributors. We are aware of this and work around it for external contributions.
----
@ -136,7 +192,7 @@ Terraform providers are not maintained in this repository; you can find relevant
repository and relevant issue tracker for each provider within the
[Terraform Registry index](https://registry.terraform.io/browse/providers).
This repository also does not include the source code for some other parts of the Terraform product including Terraform Cloud, Terraform Enterprise, and the Terraform Registry. Those components are not open source, though if you have feedback about them (including bug reports) please do feel free to [open a GitHub issue on this repository](https://github.com/hashicorp/terraform/issues/new/choose).
This repository also does not include the source code for some other parts of the Terraform product including HCP Terraform, Terraform Enterprise, and the Terraform Registry. The source for those components is not publicly available. If you have feedback about these products, including bug reports, please email [tf-cloud@hashicorp.support](mailto:tf-cloud@hashicorp.support) or [open a support request](https://support.hashicorp.com/hc/en-us/requests/new).
---
@ -144,7 +200,7 @@ If you wish to work on the Terraform CLI source code, you'll first need to insta
At this time the Terraform development environment is targeting only Linux and Mac OS X systems. While Terraform itself is compatible with Windows, unfortunately the unit test suite currently contains Unix-specific assumptions around maximum path lengths, path separators, etc.
Refer to the file [`.go-version`](https://github.com/hashicorp/terraform/blob/main/.go-version) to see which version of Go Terraform is currently built with. Other versions will often work, but if you run into any build or testing problems please try with the specific Go version indicated. You can optionally simplify the installation of multiple specific versions of Go on your system by installing [`goenv`](https://github.com/syndbg/goenv), which reads `.go-version` and automatically selects the correct Go version.
Refer to the file [`.go-version`](https://github.com/hashicorp/terraform/blob/main/.go-version) to see which version of Go Terraform is currently built with. As of Go 1.21, the `go` command (e.g. in `go build`) will automatically install the version of the Go toolchain corresponding to the version specified in `go.mod`, if it is newer than the version you have installed. The version in `go.mod` is considered the _minimum_ compatible Go version for Terraform, while the version in `.go-version` is what the production binary is actually built with.
Use Git to clone this repository into a location of your choice. Terraform is using [Go Modules](https://blog.golang.org/using-go-modules), and so you should *not* clone it inside your `GOPATH`.
@ -180,7 +236,7 @@ go test ./internal/addrs
Terraform's unit test suite is self-contained, using mocks and local files to help ensure that it can run offline and is unlikely to be broken by changes to outside systems.
However, several Terraform components interact with external services, such as the automatic provider installation mechanism, the Terraform Registry, Terraform Cloud, etc.
However, several Terraform components interact with external services, such as the automatic provider installation mechanism, the Terraform Registry, HCP Terraform, Terraform Enterprise, etc.
There are some optional tests in the Terraform CLI codebase that *do* interact with external services, which we collectively refer to as "acceptance tests". You can enable these by setting the environment variable `TF_ACC=1` when running the tests. We recommend focusing only on the specific package you are working on when enabling acceptance tests, both because it can help the test run to complete faster and because you are less likely to encounter failures due to drift in systems unrelated to your current goal:

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
name: Bug Report
description: Let us know about an unexpected error, a crash, or an incorrect behavior.
labels: ["bug", "new"]
@ -9,10 +12,11 @@ body:
The [hashicorp/terraform](https://github.com/hashicorp/terraform) issue tracker is reserved for bug reports relating to the core Terraform CLI application and configuration language.
For general usage questions, please see: https://www.terraform.io/community.html.
For general usage questions, please see the [Community Forum](https://discuss.hashicorp.com/c/terraform-core/27).
## If your issue relates to:
* **Terraform Cloud/Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
* **HCP Terraform or Terraform Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
* **Terraform Registry**: please email terraform-registry@hashicorp.com.
* **AWS Terraform Provider**: Open an issue at [hashicorp/terraform-provider-aws](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose).
* **Azure Terraform Provider**: Open an issue at [hashicorp/terraform-provider-azurerm](https://github.com/hashicorp/terraform-provider-azurerm/issues/new/choose).
* **Other Terraform Providers**: Please open an issue in the provider's own repository, which can be found by searching the [Terraform Registry](https://registry.terraform.io/browse/providers).
@ -26,7 +30,7 @@ body:
* Set defaults on (or omit) any variables. The person reproducing it should not need to invent variable settings
* If multiple steps are required, such as running terraform twice, consider scripting it in a simple shell script. Providing a script can be easier than explaining what changes to make to the config between runs.
* Omit any unneeded complexity: remove variables, conditional statements, functions, modules, providers, and resources that are not needed to trigger the bug
* When possible, use the [null resource](https://www.terraform.io/docs/providers/null/resource.html) provider rather than a real provider in order to minimize external dependencies. We know this isn't always feasible. The Terraform Core team doesn't have deep domain knowledge in every provider, or access to every cloud platform for reproduction cases.
* When possible, use the [null resource](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) provider rather than a real provider in order to minimize external dependencies. We know this isn't always feasible. The Terraform Core team doesn't have deep domain knowledge in every provider, or access to every cloud platform for reproduction cases.
- type: textarea
id: tf-version
@ -57,8 +61,11 @@ body:
attributes:
label: Debug Output
description: Full debug output can be obtained by running Terraform with the environment variable `TF_LOG=trace`. Please create a GitHub Gist containing the debug output. Please do _not_ paste the debug output in the issue, since debug output is long. Debug output may contain sensitive information. Please review it before posting publicly.
placeholder: ...link to gist...
value:
placeholder:
value: |
```
...debug output, or link to a gist...
```
validations:
required: true
- type: textarea
@ -117,6 +124,17 @@ body:
value:
validations:
required: false
- type: textarea
id: tf-genai
attributes:
label: Generative AI / LLM assisted development?
description: |
If you used a generative AI / LLM tool to assist in the development of your config, please let us know which tool you used here.
ex. ChatGPT 3.5 / CoPilot / AWS Q / etc.
placeholder: LLM assistance tool?
value:
validations:
required: false
- type: markdown
attributes:

View file

@ -1,8 +1,11 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
blank_issues_enabled: false
contact_links:
- name: Terraform Cloud/Enterprise Troubleshooting and Feature Requests
- name: HCP Terraform and Terraform Enterprise Troubleshooting and Feature Requests
url: https://support.hashicorp.com/hc/en-us/requests/new
about: For issues and feature requests related to the Terraform Cloud/Enterprise platform, please submit a HashiCorp support request or email tf-cloud@hashicorp.support
about: For issues and feature requests related to HCP Terraform or Terraform Enterprise, please submit a HashiCorp support request or email tf-cloud@hashicorp.support
- name: AWS Terraform Provider Feedback and Questions
url: https://github.com/hashicorp/terraform-provider-aws
about: The AWS Terraform Provider has its own repository, any provider related issues or questions should be directed there.
@ -17,4 +20,4 @@ contact_links:
about: Plugin SDK has its own repository, any SDK and provider development related issues or questions should be directed there.
- name: Terraform Usage, Language, or Workflow Questions
url: https://discuss.hashicorp.com/c/terraform-core
about: Please ask and answer language or workflow related questions through the Terraform Core Community Forum.
about: Please ask and answer language or workflow related questions through the Terraform Core Community Forum.

View file

@ -0,0 +1,76 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
name: Documentation Issue
description: Report an issue or suggest a change in the documentation.
labels: ["documentation", "new"]
body:
- type: markdown
attributes:
value: |
# Thank you for opening a documentation change request.
Please only use the [hashicorp/terraform](https://github.com/hashicorp/terraform) `Documentation` issue type to report problems with the documentation on [https://developer.hashicorp.com/terraform/docs](). Only technical writers (not engineers) monitor this issue type. Report Terraform bugs or feature requests with the `Bug report` or `Feature Request` issue types instead to get engineering attention.
For general usage questions, please see the [Community Forum](https://discuss.hashicorp.com/c/terraform-core/27).
- type: textarea
id: tf-version
attributes:
label: Terraform Version
description: Run `terraform version` to show the version, and paste the result below. If you're not using the latest version, please check to see if something related to your request has already been implemented in a later version.
render: shell
placeholder: ...output of `terraform version`...
value:
validations:
required: true
- type: textarea
id: tf-affected-pages
attributes:
label: Affected Pages
description: |
Link to the pages relevant to your documentation change request.
placeholder:
value:
validations:
required: false
- type: textarea
id: tf-problem
attributes:
label: What is the docs issue?
description: What problems or suggestions do you have about the documentation?
placeholder:
value:
validations:
required: true
- type: textarea
id: tf-proposal
attributes:
label: Proposal
description: What documentation changes would fix this issue and where would you expect to find them? Are one or more page headings unclear? Do one or more pages need additional context, examples, or warnings? Do we need a new page or section dedicated to a specific topic? Your ideas help us understand what you and other users need from our documentation and how we can improve the content.
placeholder:
value:
validations:
required: false
- type: textarea
id: tf-references
attributes:
label: References
description: |
Are there any other open or closed GitHub issues related to the problem or solution you described? If so, list them below. For example:
```
- #6017
```
placeholder:
value:
validations:
required: false
- type: markdown
attributes:
value: |
**Note:** If the submit button is disabled and you have filled out all required fields, please check that you did not forget a **Title** for the issue.

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
name: Feature Request
description: Suggest a new feature or other enhancement.
labels: ["enhancement", "new"]
@ -9,10 +12,10 @@ body:
The [hashicorp/terraform](https://github.com/hashicorp/terraform) issue tracker is reserved for feature requests relating to the core Terraform CLI application and configuration language.
For general usage questions, please see: https://www.terraform.io/community.html.
For general usage questions, please see the [Community Forum](https://discuss.hashicorp.com/c/terraform-core/27).
## If your feature request relates to:
* **Terraform Cloud/Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
* **HCP Terraform or Terraform Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
* **AWS Terraform Provider**: Open an issue at [hashicorp/terraform-provider-aws](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose).
* **Azure Terraform Provider**: Open an issue at [hashicorp/terraform-provider-azurerm](https://github.com/hashicorp/terraform-provider-azurerm/issues/new/choose).
* **Other Terraform Providers**: Please open an issue in the provider's own repository, which can be found by searching the [Terraform Registry](https://registry.terraform.io/browse/providers).

View file

@ -0,0 +1,79 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
name: equivalence-test
description: "Execute the suite of Terraform equivalence tests in testing/equivalence-tests and update the golden files."
inputs:
target-equivalence-test-version:
description: "The version of the Terraform equivalence tests to use."
default: "0.3.0"
target-os:
description: "Current operating system"
default: "linux"
target-arch:
description: "Current architecture"
default: "amd64"
current-branch:
description: "What branch are we currently on?"
required: true
new-branch:
description: "Name of new branch to be created for the review."
required: true
reviewers:
description: "Comma-separated list of GitHub usernames to request review from."
required: true
message:
description: "Message to include in the commit."
required: true
runs:
using: "composite"
steps:
- name: "download equivalence test binary"
shell: bash
run: |
./.github/scripts/equivalence-test.sh download_equivalence_test_binary \
${{ inputs.target-equivalence-test-version }} \
./bin/equivalence-tests \
${{ inputs.target-os }} \
${{ inputs.target-arch }}
- name: Build terraform
shell: bash
run: ./.github/scripts/equivalence-test.sh build_terraform_binary ./bin/terraform
- name: "run and update equivalence tests"
id: execute
shell: bash
run: |
./bin/equivalence-tests update \
--tests=testing/equivalence-tests/tests \
--goldens=testing/equivalence-tests/outputs \
--binary=$(pwd)/bin/terraform
git add --intent-to-add testing/equivalence-tests/outputs
changed=$(git diff --quiet -- testing/equivalence-tests/outputs || echo true)
echo "changed=$changed" >> "${GITHUB_OUTPUT}"
- name: "branch, commit, and push changes"
if: steps.execute.outputs.changed == 'true'
shell: bash
run: |
git config user.name "hc-github-team-tf-core"
git config user.email "github-team-tf-core@hashicorp.com"
git checkout -b ${{ inputs.new-branch }}
git add testing/equivalence-tests/outputs
git commit -m "Update equivalence test golden files."
git push --set-upstream origin ${{ inputs.new-branch }}
- name: "create pull request"
if: steps.execute.outputs.changed == 'true'
shell: bash
run: |
gh pr create \
--draft \
--base ${{ inputs.current-branch }} \
--head ${{ inputs.new-branch }} \
--title "Update equivalence test golden files" \
--body '${{ inputs.message }}' \
--reviewer ${{ inputs.reviewers }}

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
name: 'Determine Go Toolchain Version'
description: 'Uses the .go-version file to determine which Go toolchain to use for any Go-related actions downstream.'
outputs:
@ -20,4 +23,4 @@ runs:
# complex for automation.
run: |
echo "Building with Go $(cat .go-version)"
echo "::set-output name=version::$(cat .go-version)"
echo "version=$(cat .go-version)" >> "$GITHUB_OUTPUT"

30
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,30 @@
version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: daily
labels:
- dependencies
- go
- security
# Disable regular version updates and only use Dependabot for security updates
open-pull-requests-limit: 0
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
labels:
- dependencies
- build
- security
reviewers:
- hashicorp/terraform-core
groups:
github-actions-breaking:
update-types:
- major
github-actions-backward-compatible:
update-types:
- minor
- patch

46
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,46 @@
<!--
Describe in detail the changes you are proposing, and the rationale.
See the contributing guide:
https://github.com/hashicorp/terraform/blob/main/.github/CONTRIBUTING.md
-->
<!--
Link all GitHub issues fixed by this PR, and add references to prior
related PRs.
-->
Fixes #
## Target Release
<!--
In normal circumstances we only target changes at the upcoming minor
release, or as a patch to the current minor version. If you need to
port a security fix to an older release, highlight this here by listing
all targeted releases.
If targeting the next patch release, also add the relevant x.y-backport
label to enable the backport bot.
-->
1.13.x
## CHANGELOG entry
<!--
If your change is user-facing, add a short description in a changelog entry.
You can use `npx changie new` to create a new changelog entry or manually create a new file in the .changes/unreleasd directory (or .changes/backported if it's a bug fix that should be backported).
-->
- [ ] This change is user-facing and I added a changelog entry.
- [ ] This change is not user-facing.

18
.github/scripts/e2e_test_linux_darwin.sh vendored Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
set -uo pipefail
if [[ $arch == 'arm' || $arch == 'arm64' ]]
then
export DIR=$(mktemp -d)
unzip -d $DIR "${e2e_cache_path}/terraform-e2etest_${os}_${arch}.zip"
unzip -d $DIR "./terraform_${version}_${os}_${arch}.zip"
sudo chmod +x $DIR/e2etest
docker run --platform=linux/arm64 -v $DIR:/src -w /src arm64v8/alpine ./e2etest -test.v
else
unzip "${e2e_cache_path}/terraform-e2etest_${os}_${arch}.zip"
unzip "./terraform_${version}_${os}_${arch}.zip"
TF_ACC=1 ./e2etest -test.v
fi

157
.github/scripts/equivalence-test.sh vendored Executable file
View file

@ -0,0 +1,157 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
set -uo pipefail
function usage {
cat <<-'EOF'
Usage: ./equivalence-test.sh <command> [<args>] [<options>]
Description:
This script will handle various commands related to the execution of the
Terraform equivalence tests.
Commands:
get_target_branch <version>
get_target_branch returns the default target branch for a given Terraform
version.
target_branch=$(./equivalence-test.sh get_target_branch v1.4.3); target_branch=v1.4
target_branch=$(./equivalence-test.sh get_target_branch 1.4.3); target_branch=v1.4
download_equivalence_test_binary <version> <target> <os> <arch>
download_equivalence_test_binary downloads the equivalence testing binary
for a given version and places it at the target path.
./equivalence-test.sh download_equivalence_test_binary 0.3.0 ./bin/terraform-equivalence-testing linux amd64
build_terraform_binary <target>
download_terraform_binary builds the Terraform binary and places it at the
target path.
./equivalence-test.sh build_terraform_binary ./bin/terraform
EOF
}
function download_equivalence_test_binary {
VERSION="${1:-}"
TARGET="${2:-}"
OS="${3:-}"
ARCH="${4:-}"
if [[ -z "$VERSION" || -z "$TARGET" || -z "$OS" || -z "$ARCH" ]]; then
echo "missing at least one of [<version>, <target>, <os>, <arch>] arguments"
usage
exit 1
fi
curl \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/hashicorp/terraform-equivalence-testing/releases" > releases.json
ASSET="terraform-equivalence-testing_v${VERSION}_${OS}_${ARCH}.zip"
ASSET_ID=$(jq -r --arg VERSION "v$VERSION" --arg ASSET "$ASSET" '.[] | select(.name == $VERSION) | .assets[] | select(.name == $ASSET) | .id' releases.json)
mkdir -p zip
curl -L \
-H "Accept: application/octet-stream" \
"https://api.github.com/repos/hashicorp/terraform-equivalence-testing/releases/assets/$ASSET_ID" > "zip/$ASSET"
mkdir -p bin
unzip -p "zip/$ASSET" terraform-equivalence-testing > "$TARGET"
chmod u+x "$TARGET"
rm -r zip
rm releases.json
}
function build_terraform_binary {
TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
echo "target argument"
usage
exit 1
fi
go build -o "$TARGET" ./
chmod u+x "$TARGET"
}
function get_target_branch {
VERSION="${1:-}"
if [ -z "$VERSION" ]; then
echo "missing <version> argument"
usage
exit 1
fi
# Split off the build metadata part, if any
# (we won't actually include it in our final version, and handle it only for
# completeness against semver syntax.)
IFS='+' read -ra VERSION BUILD_META <<< "$VERSION"
# Separate out the prerelease part, if any
IFS='-' read -r BASE_VERSION PRERELEASE <<< "$VERSION"
# Separate out major, minor and patch versions.
IFS='.' read -r MAJOR_VERSION MINOR_VERSION PATCH_VERSION <<< "$BASE_VERSION"
if [[ "$PRERELEASE" == *"alpha"* ]]; then
TARGET_BRANCH=main
else
if [[ $MAJOR_VERSION = v* ]]; then
TARGET_BRANCH=${MAJOR_VERSION}.${MINOR_VERSION}
else
TARGET_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
fi
fi
echo "$TARGET_BRANCH"
}
function main {
case "$1" in
get_target_branch)
if [ "${#@}" != 2 ]; then
echo "invalid number of arguments"
usage
exit 1
fi
get_target_branch "$2"
;;
download_equivalence_test_binary)
if [ "${#@}" != 5 ]; then
echo "invalid number of arguments"
usage
exit 1
fi
download_equivalence_test_binary "$2" "$3" "$4" "$5"
;;
build_terraform_binary)
if [ "${#@}" != 2 ]; then
echo "invalid number of arguments"
usage
exit 1
fi
build_terraform_binary "$2"
;;
*)
echo "unrecognized command $*"
usage
exit 1
;;
esac
}
main "$@"
exit $?

41
.github/scripts/get_product_version.sh vendored Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
set -uo pipefail
# Trim the "v" prefix, if any.
VERSION="${RAW_VERSION#v}"
# Split off the build metadata part, if any
# (we won't actually include it in our final version, and handle it only for
# compleness against semver syntax.)
IFS='+' read -ra VERSION BUILD_META <<< "$VERSION"
# Separate out the prerelease part, if any
# (version.go expects it to be in a separate variable)
IFS='-' read -r BASE_VERSION PRERELEASE <<< "$VERSION"
EXPERIMENTS_ENABLED=0
if [[ "$PRERELEASE" == alpha* ]]; then
EXPERIMENTS_ENABLED=1
fi
if [[ "$PRERELEASE" == dev* ]]; then
EXPERIMENTS_ENABLED=1
fi
LDFLAGS="-w -s"
if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
LDFLAGS="${LDFLAGS} -X 'main.experimentsAllowed=yes'"
fi
LDFLAGS="${LDFLAGS} -X 'github.com/hashicorp/terraform/version.dev=no'"
echo "Building Terraform CLI ${VERSION}"
if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
echo "This build allows use of experimental features"
fi
echo "product-version=${VERSION}" | tee -a "${GITHUB_OUTPUT}"
echo "product-version-base=${BASE_VERSION}" | tee -a "${GITHUB_OUTPUT}"
echo "product-version-pre=${PRERELEASE}" | tee -a "${GITHUB_OUTPUT}"
echo "experiments=${EXPERIMENTS_ENABLED}" | tee -a "${GITHUB_OUTPUT}"
echo "go-ldflags=${LDFLAGS}" | tee -a "${GITHUB_OUTPUT}"

47
.github/scripts/verify_docker vendored Executable file
View file

@ -0,0 +1,47 @@
#!/bin/bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
set -euo pipefail
# verify_docker invokes the given Docker image with the argument `version` and inspects its output.
# If its output doesn't match the version given, the script will exit 1 and report why it failed.
# This is meant to be run as part of the build workflow to verify the built image meets some basic
# criteria for validity.
#
# Because this is meant to be run as the `smoke_test` for the docker-build workflow, the script expects
# the image name parameter to be provided by the `IMAGE_NAME` environment variable, rather than a
# positional argument.
function usage {
echo "IMAGE_NAME=<image uri> ./verify_docker <expect_version>"
}
function main {
local image_name="${IMAGE_NAME:-}"
local expect_version="${1:-}"
local got_version
if [[ -z "${image_name}" ]]; then
echo "ERROR: IMAGE_NAME is not set"
usage
exit 1
fi
if [[ -z "${expect_version}" ]]; then
echo "ERROR: expected version argument is required"
usage
exit 1
fi
got_version="$( awk '{print $2}' <(head -n1 <(docker run --rm "${image_name}" version)) )"
if [ "${got_version}" != "${expect_version}" ]; then
echo "Test FAILED"
echo "Got: ${got_version}, Want: ${expect_version}"
exit 1
fi
echo "Test PASSED"
}
main "$@"

View file

@ -0,0 +1,99 @@
---
name: build_terraform
# This workflow is intended to be called by the build workflow. The crt make
# targets that are utilized automatically determine build metadata and
# handle building and packing Terraform.
on:
workflow_call:
inputs:
cgo-enabled:
type: string
default: 0
required: true
goos:
required: true
type: string
goarch:
required: true
type: string
go-version:
type: string
package-name:
type: string
default: terraform
product-version:
type: string
required: true
ld-flags:
type: string
required: true
runson:
type: string
required: true
jobs:
build:
runs-on: ${{ inputs.runson }}
name: Terraform ${{ inputs.goos }} ${{ inputs.goarch }} v${{ inputs.product-version }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ inputs.go-version }}
- name: Build Terraform
env:
GOOS: ${{ inputs.goos }}
GOARCH: ${{ inputs.goarch }}
GO_LDFLAGS: ${{ inputs.ld-flags }}
ACTIONSOS: ${{ inputs.runson }}
CGO_ENABLED: ${{ inputs.cgo-enabled }}
uses: hashicorp/actions-go-build@37358f6098ef21b09542d84a9814ebb843aa4e3e # v1
with:
product_name: ${{ inputs.package-name }}
product_version: ${{ inputs.product-version }}
go_version: ${{ inputs.go-version }}
os: ${{ inputs.goos }}
arch: ${{ inputs.goarch }}
reproducible: nope
instructions: |-
go build -ldflags "${{ inputs.ld-flags }}" -o "$BIN_PATH" -trimpath -buildvcs=false
cp LICENSE "$TARGET_DIR/LICENSE.txt"
- name: Copy license file to config_dir
if: ${{ inputs.goos == 'linux' }}
env:
LICENSE_DIR: ".release/linux/package/usr/share/doc/${{ inputs.package-name }}"
run: |
mkdir -p "$LICENSE_DIR" && cp LICENSE "$LICENSE_DIR/LICENSE.txt"
- if: ${{ inputs.goos == 'linux' }}
uses: hashicorp/actions-packaging-linux@8d55a640bb30b5508f16757ea908b274564792d4 # v1.9
with:
name: "terraform"
description: "Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned."
arch: ${{ inputs.goarch }}
version: ${{ inputs.product-version }}
maintainer: "HashiCorp"
homepage: "https://terraform.io/"
license: "BUSL-1.1"
binary: "dist/terraform"
deb_depends: "git"
rpm_depends: "git"
config_dir: ".release/linux/package/"
- if: ${{ inputs.goos == 'linux' }}
name: Determine package file names
run: |
echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV
echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV
- if: ${{ inputs.goos == 'linux' }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ env.RPM_PACKAGE }}
path: out/${{ env.RPM_PACKAGE }}
if-no-files-found: error
- if: ${{ inputs.goos == 'linux' }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ env.DEB_PACKAGE }}
path: out/${{ env.DEB_PACKAGE }}
if-no-files-found: error

View file

@ -1,31 +1,19 @@
name: Build Terraform CLI Packages
name: build
# If you want to test changes to this file before merging to a main branch,
# push them up to a branch whose name has the prefix "build-workflow-dev/",
# which is a special prefix that triggers this workflow even though it's not
# actually a release branch.
# NOTE: This workflow is currently used only to verify that all commits to a
# release branch are buildable. It's set up to generate some artifacts that
# might in principle be consumed by a downstream release process, but currently
# they are not used in this way and official Terraform CLI releases are instead
# built using a separate process maintained elsewhere. We intend to adopt this
# new process fully later, once other HashiCorp-internal tooling is ready.
#
# Currently this process produces what should be working packages but packages
# NOT suitable for distribution to end-users as official releases, because it
# doesn't include a step to ensure that "terraform version" (and similar) will
# report the intended version number. Consequently we can safely use these
# results for testing purposes, but not yet for release purposes. See the
# "build" job below for a FIXME comment related to version numbers.
on:
workflow_dispatch:
push:
branches:
- main
- 'v[0-9]+.[0-9]+'
- build-workflow-dev/*
- releng/**
- tsccr-auto-pinning/**
- dependabot/**
tags:
- 'v[0-9]+.[0-9]+.[0-9]+*'
@ -42,71 +30,28 @@ jobs:
runs-on: ubuntu-latest
outputs:
product-version: ${{ steps.get-product-version.outputs.product-version }}
product-version-base: ${{ steps.get-product-version.outputs.product-version-base }}
product-version-pre: ${{ steps.get-product-version.outputs.product-version-pre }}
experiments: ${{ steps.get-product-version.outputs.experiments }}
go-ldflags: ${{ steps.get-product-version.outputs.go-ldflags }}
product-version-base: ${{ steps.get-product-version.outputs.base-product-version }}
product-version-pre: ${{ steps.get-product-version.outputs.prerelease-product-version }}
experiments: ${{ steps.get-ldflags.outputs.experiments }}
go-ldflags: ${{ steps.get-ldflags.outputs.go-ldflags }}
pkg-name: ${{ steps.get-pkg-name.outputs.pkg-name }}
steps:
- uses: actions/checkout@v3
- name: Git Describe
id: git-describe
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Get Package Name
id: get-pkg-name
run: |
# The actions/checkout action tries hard to fetch as little as
# possible, to the extent that even with "depth: 0" it fails to
# produce enough tag metadata for us to "describe" successfully.
# We'll therefore re-fetch the tags here to make sure we will
# select the most accurate version number.
git fetch origin --force --tags --quiet --unshallow
git log --tags --simplify-by-decoration --decorate-refs='refs/tags/v*' --pretty=format:'%h %<|(35)%S %ci' --max-count 15 --topo-order
set -e
RAW_VERSION=$(git describe --tags --match='v*' ${GITHUB_SHA})
echo "
Raw version is ${RAW_VERSION}"
echo "::set-output name=raw-version::${RAW_VERSION}"
pkg_name=${{ env.PKG_NAME }}
echo "pkg-name=${pkg_name}" | tee -a "${GITHUB_OUTPUT}"
- name: Decide version number
id: get-product-version
shell: bash
uses: hashicorp/actions-set-product-version@d9b52fb778068099ca4c5e28e1ca0fee2544e114 # v2
- name: Determine experiments
id: get-ldflags
env:
RAW_VERSION: ${{ steps.git-describe.outputs.raw-version }}
run: |
# Trim the "v" prefix, if any.
VERSION="${RAW_VERSION#v}"
# Split off the build metadata part, if any
# (we won't actually include it in our final version, and handle it only for
# compleness against semver syntax.)
IFS='+' read -ra VERSION BUILD_META <<< "$VERSION"
# Separate out the prerelease part, if any
# (version.go expects it to be in a separate variable)
IFS='-' read -r BASE_VERSION PRERELEASE <<< "$VERSION"
EXPERIMENTS_ENABLED=0
if [[ "$PRERELEASE" == alpha* ]]; then
EXPERIMENTS_ENABLED=1
fi
if [[ "$PRERELEASE" == dev* ]]; then
EXPERIMENTS_ENABLED=1
fi
LDFLAGS="-w -s"
if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
LDFLAGS="${LDFLAGS} -X 'main.experimentsAllowed=yes'"
fi
LDFLAGS="${LDFLAGS} -X 'github.com/hashicorp/terraform/version.Version=${BASE_VERSION}'"
LDFLAGS="${LDFLAGS} -X 'github.com/hashicorp/terraform/version.Prerelease=${PRERELEASE}'"
echo "Building Terraform CLI ${VERSION}"
if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
echo "This build allows use of experimental features"
fi
echo "::set-output name=product-version::${VERSION}"
echo "::set-output name=product-version-base::${BASE_VERSION}"
echo "::set-output name=product-version-pre::${PRERELEASE}"
echo "::set-output name=experiments::${EXPERIMENTS_ENABLED}"
echo "::set-output name=go-ldflags::${LDFLAGS}"
RAW_VERSION: ${{ steps.get-product-version.outputs.product-version }}
shell: bash
run: .github/scripts/get_product_version.sh
- name: Report chosen version number
run: |
[ -n "${{steps.get-product-version.outputs.product-version}}" ]
@ -119,7 +64,7 @@ jobs:
go-version: ${{ steps.get-go-version.outputs.version }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Determine Go version
id: get-go-version
uses: ./.github/actions/go-version
@ -132,165 +77,54 @@ jobs:
filepath: ${{ steps.generate-metadata-file.outputs.filepath }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Generate package metadata
id: generate-metadata-file
uses: hashicorp/actions-generate-metadata@v1
uses: hashicorp/actions-generate-metadata@fdbc8803a0e53bcbb912ddeee3808329033d6357 # v1.1.1
with:
version: ${{ needs.get-product-version.outputs.product-version }}
product: ${{ env.PKG_NAME }}
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: metadata.json
path: ${{ steps.generate-metadata-file.outputs.filepath }}
build:
name: Build for ${{ matrix.goos }}_${{ matrix.goarch }}
runs-on: ${{ matrix.runson }}
needs:
- get-product-version
- get-go-version
uses: ./.github/workflows/build-terraform-cli.yml
with:
goarch: ${{ matrix.goarch }}
goos: ${{ matrix.goos }}
go-version: ${{ needs.get-go-version.outputs.go-version }}
package-name: ${{ needs.get-product-version.outputs.pkg-name }}
product-version: ${{ needs.get-product-version.outputs.product-version }}
ld-flags: ${{ needs.get-product-version.outputs.go-ldflags }}
cgo-enabled: ${{ matrix.cgo-enabled }}
runson: ${{ matrix.runson }}
secrets: inherit
strategy:
matrix:
include:
- {goos: "freebsd", goarch: "386", runson: "ubuntu-latest"}
- {goos: "freebsd", goarch: "amd64", runson: "ubuntu-latest"}
- {goos: "freebsd", goarch: "arm", runson: "ubuntu-latest"}
- {goos: "linux", goarch: "386", runson: "ubuntu-latest"}
- {goos: "linux", goarch: "amd64", runson: "ubuntu-latest"}
- {goos: "linux", goarch: "arm", runson: "ubuntu-latest"}
- {goos: "linux", goarch: "arm64", runson: "ubuntu-latest"}
- {goos: "openbsd", goarch: "386", runson: "ubuntu-latest"}
- {goos: "openbsd", goarch: "amd64", runson: "ubuntu-latest"}
- {goos: "solaris", goarch: "amd64", runson: "ubuntu-latest"}
- {goos: "windows", goarch: "386", runson: "ubuntu-latest"}
- {goos: "windows", goarch: "amd64", runson: "ubuntu-latest"}
- {goos: "darwin", goarch: "amd64", runson: "macos-latest"}
- {goos: "darwin", goarch: "arm64", runson: "macos-latest"}
- {goos: "freebsd", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "freebsd", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "freebsd", goarch: "arm", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "linux", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "linux", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "linux", goarch: "arm", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "linux", goarch: "arm64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "openbsd", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "openbsd", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "solaris", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "windows", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "windows", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "darwin", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
- {goos: "darwin", goarch: "arm64", runson: "ubuntu-latest", cgo-enabled: "0"}
fail-fast: false
env:
FULL_VERSION: ${{ needs.get-product-version.outputs.product-version }}
BASE_VERSION: ${{ needs.get-product-version.outputs.product-version-base }}
VERSION_PRERELEASE: ${{ needs.get-product-version.outputs.product-version-pre }}
EXPERIMENTS_ENABLED: ${{ needs.get-product-version.outputs.experiments }}
GO_LDFLAGS: ${{ needs.get-product-version.outputs.go-ldflags }}
steps:
- uses: actions/checkout@v2
- name: Install Go toolchain
uses: actions/setup-go@v2
with:
go-version: ${{ needs.get-go-version.outputs.go-version }}
# FIXME: We're not currently setting the hard-coded version string in
# version/version.go at any point here, which means that the packages
# this process builds are not suitable for release. Once we're using
# Go 1.18 we may begin using the version information automatically
# embedded by the Go toolchain, at which point we won't need any
# special steps during build, but failing that we'll need to rework
# the version/version.go package so we can more readily update it
# using linker flags rather than direct code modification.
- name: Build
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
ACTIONSOS: ${{ matrix.runson }}
run: |
mkdir dist out
if [ "$ACTIONSOS" == "macos-latest" ] && [ "$GOOS" == "darwin" ]; then
# When building for macOS _on_ macOS we must force CGo to get
# correct hostname resolution behavior. (This must be conditional
# because other cross-compiles won't have suitable headers
# available to use CGo; darwin_amd64 has suitable headers to
# cross-build for darwin_arm64.)
export CGO_ENABLED=1
fi
set -x
go build -ldflags "${GO_LDFLAGS}" -o dist/ .
zip -r -j out/${{ env.PKG_NAME }}_${FULL_VERSION}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/
- uses: actions/upload-artifact@v2
with:
name: ${{ env.PKG_NAME }}_${{ env.FULL_VERSION }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip
path: out/${{ env.PKG_NAME }}_${{ env.FULL_VERSION }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip
package-linux:
name: "Build Linux distro packages for ${{ matrix.arch }}"
runs-on: ubuntu-latest
needs:
- get-product-version
- build
strategy:
matrix:
include:
- {arch: "386"}
- {arch: "amd64"}
- {arch: "arm"}
- {arch: "arm64"}
fail-fast: false
env:
os: linux
arch: ${{matrix.arch}}
version: ${{needs.get-product-version.outputs.product-version}}
steps:
- name: "Download Terraform CLI package"
uses: actions/download-artifact@v2
id: clipkg
with:
name: terraform_${{ env.version }}_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: Extract packages
run: |
mkdir -p dist
(cd dist && unzip "../terraform_${{ env.version }}_${{ env.os }}_${{ env.arch }}.zip")
mkdir -p out
- name: Build Linux distribution packages
uses: hashicorp/actions-packaging-linux@v1
with:
name: "terraform"
description: "Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned."
arch: ${{ matrix.arch }}
version: ${{ env.version }}
maintainer: "HashiCorp"
homepage: "https://terraform.io/"
license: "MPL-2.0"
binary: "dist/terraform"
deb_depends: "git"
rpm_depends: "git"
- name: Gather Linux distribution package filenames
run: |
echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV
echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV
- name: "Save .rpm package"
uses: actions/upload-artifact@v2
with:
name: ${{ env.RPM_PACKAGE }}
path: out/${{ env.RPM_PACKAGE }}
- name: "Save .deb package"
uses: actions/upload-artifact@v2
with:
name: ${{ env.DEB_PACKAGE }}
path: out/${{ env.DEB_PACKAGE }}
# TODO: homebrew packages for macOS
#package-homebrew:
# name: Build Homebrew package for darwin_${{ matrix.arch }}
# runs-on: macos-latest
# needs:
# - get-product-version
# - build
# strategy:
# matrix:
# arch: ["amd64", "arm64"]
# fail-fast: false
# ...
package-docker:
name: Build Docker image for linux_${{ matrix.arch }}
runs-on: ubuntu-latest
@ -299,61 +133,64 @@ jobs:
- build
strategy:
matrix:
arch: ["amd64"]
arch: ["amd64", "386", "arm", "arm64"]
fail-fast: false
env:
repo: "terraform"
version: ${{needs.get-product-version.outputs.product-version}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build Docker images
uses: hashicorp/actions-docker-build@v1
uses: hashicorp/actions-docker-build@11d43ef520c65f58683d048ce9b47d6617893c9a # v2
with:
pkg_name: "terraform_${{env.version}}"
version: ${{env.version}}
bin_name: terraform
target: default
arch: ${{matrix.arch}}
dockerfile: .github/workflows/build-Dockerfile
dockerfile: build.Dockerfile
smoke_test: .github/scripts/verify_docker v${{ env.version }}
tags: |
docker.io/hashicorp/${{env.repo}}:${{env.version}}
986891699432.dkr.ecr.us-east-1.amazonaws.com/hashicorp/${{env.repo}}:${{env.version}}
public.ecr.aws/hashicorp/${{env.repo}}:${{env.version}}
e2etest-build:
name: Build e2etest for ${{ matrix.goos }}_${{ matrix.goarch }}
runs-on: ubuntu-latest
outputs:
e2e-cache-key: ${{ steps.set-cache-values.outputs.e2e-cache-key }}
e2e-cache-path: ${{ steps.set-cache-values.outputs.e2e-cache-path }}
needs:
- get-product-version
- get-go-version
strategy:
matrix:
# We build test harnesses only for the v1.0 Compatibility Promises
# supported platforms. Even within that set, we can only run on
# architectures for which we have GitHub Actions runners available,
# which is currently only amd64 (x64).
# TODO: GitHub Actions does support _self-hosted_ arm and arm64
# runners, so we could potentially run some ourselves to run our
# tests there, but at the time of writing there is no documented
# support for darwin_arm64 (macOS on Apple Silicon).
include:
- {goos: "darwin", goarch: "amd64"}
#- {goos: "darwin", goarch: "arm64"}
- {goos: "darwin", goarch: "arm64"}
- {goos: "windows", goarch: "amd64"}
- {goos: "windows", goarch: "386"}
- {goos: "linux", goarch: "386"}
- {goos: "linux", goarch: "amd64"}
#- {goos: "linux", goarch: "arm"}
#- {goos: "linux", goarch: "arm64"}
- {goos: "linux", goarch: "arm"}
- {goos: "linux", goarch: "arm64"}
fail-fast: false
env:
build_script: ./internal/command/e2etest/make-archive.sh
steps:
- uses: actions/checkout@v2
- name: Set Cache Values
id: set-cache-values
run: |
cache_key=e2e-cache-${{ github.sha }}
cache_path=internal/command/e2etest/build
echo "e2e-cache-key=${cache_key}" | tee -a "${GITHUB_OUTPUT}"
echo "e2e-cache-path=${cache_path}" | tee -a "${GITHUB_OUTPUT}"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go toolchain
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ needs.get-go-version.outputs.go-version }}
@ -369,15 +206,15 @@ jobs:
# that "terraform version" is returning that version number.
bash ./internal/command/e2etest/make-archive.sh
- uses: actions/upload-artifact@v2
- name: Save test harness to cache
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
name: terraform-e2etest_${{ matrix.goos }}_${{ matrix.goarch }}.zip
path: internal/command/e2etest/build/terraform-e2etest_${{ matrix.goos }}_${{ matrix.goarch }}.zip
if-no-files-found: error
path: ${{ steps.set-cache-values.outputs.e2e-cache-path }}
key: ${{ steps.set-cache-values.outputs.e2e-cache-key }}_${{ matrix.goos }}_${{ matrix.goarch }}
e2etest-linux:
name: e2etest for linux_${{ matrix.goarch }}
runs-on: ubuntu-latest
e2e-test:
name: Run e2e test for ${{ matrix.goos }}_${{ matrix.goarch }}
runs-on: ${{ matrix.runson }}
needs:
- get-product-version
- build
@ -385,13 +222,17 @@ jobs:
strategy:
matrix:
include:
- {goarch: "amd64"}
#- {goarch: "arm64"}
#- {goarch: "arm"}
- { runson: ubuntu-latest, goos: linux, goarch: "amd64" }
- { runson: ubuntu-latest, goos: linux, goarch: "386" }
- { runson: ubuntu-latest, goos: linux, goarch: "arm" }
- { runson: ubuntu-latest, goos: linux, goarch: "arm64" }
- { runson: macos-latest, goos: darwin, goarch: "amd64" }
- { runson: windows-latest, goos: windows, goarch: "amd64" }
- { runson: windows-latest, goos: windows, goarch: "386" }
fail-fast: false
env:
os: linux
os: ${{ matrix.goos }}
arch: ${{ matrix.goarch }}
version: ${{needs.get-product-version.outputs.product-version}}
@ -402,140 +243,81 @@ jobs:
# and e2etest package for this platform. (This helps ensure that we're
# really testing the release package and not inadvertently testing a
# fresh build from source.)
- name: "Download e2etest package"
uses: actions/download-artifact@v2
- name: Checkout repo
if: ${{ (matrix.goos == 'linux') || (matrix.goos == 'darwin') }}
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Restore cache"
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: e2etestpkg
with:
name: terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip
path: .
path: ${{ needs.e2etest-build.outputs.e2e-cache-path }}
key: ${{ needs.e2etest-build.outputs.e2e-cache-key }}_${{ matrix.goos }}_${{ matrix.goarch }}
fail-on-cache-miss: true
enableCrossOsArchive: true
- name: "Download Terraform CLI package"
uses: actions/download-artifact@v2
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
id: clipkg
with:
name: terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: Extract packages
if: ${{ matrix.goos == 'windows' }}
run: |
unzip "./terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip"
unzip "${{ needs.e2etest-build.outputs.e2e-cache-path }}/terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip"
unzip "./terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip"
- name: Run E2E Tests
run: |
TF_ACC=1 ./e2etest -test.v
e2etest-darwin:
name: e2etest for darwin_${{ matrix.goarch }}
runs-on: macos-latest
needs:
- get-product-version
- build
- e2etest-build
strategy:
matrix:
include:
- {goarch: "amd64"}
#- {goarch: "arm64"}
fail-fast: false
env:
os: darwin
arch: ${{ matrix.goarch }}
version: ${{needs.get-product-version.outputs.product-version}}
steps:
# NOTE: This intentionally _does not_ check out the source code
# for the commit/tag we're building, because by now we should
# have everything we need in the combination of CLI release package
# and e2etest package for this platform. (This helps ensure that we're
# really testing the release package and not inadvertently testing a
# fresh build from source.)
- name: "Download e2etest package"
uses: actions/download-artifact@v2
id: e2etestpkg
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
if: ${{ contains(matrix.goarch, 'arm') }}
with:
name: terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: "Download Terraform CLI package"
uses: actions/download-artifact@v2
id: clipkg
with:
name: terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: Extract packages
run: |
unzip "./terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip"
unzip "./terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip"
- name: Run E2E Tests
run: |
TF_ACC=1 ./e2etest -test.v
e2etest-windows:
name: e2etest for windows_${{ matrix.goarch }}
runs-on: windows-latest
needs:
- get-product-version
- build
- e2etest-build
strategy:
matrix:
include:
- {goarch: "amd64"}
fail-fast: false
env:
os: windows
arch: ${{ matrix.goarch }}
version: ${{needs.get-product-version.outputs.product-version}}
steps:
# NOTE: This intentionally _does not_ check out the source code
# for the commit/tag we're building, because by now we should
# have everything we need in the combination of CLI release package
# and e2etest package for this platform. (This helps ensure that we're
# really testing the release package and not inadvertently testing a
# fresh build from source.)
- name: "Download e2etest package"
uses: actions/download-artifact@v2
id: e2etestpkg
with:
name: terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: "Download Terraform CLI package"
uses: actions/download-artifact@v2
id: clipkg
with:
name: terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip
path: .
- name: Extract packages
shell: pwsh
run: |
Expand-Archive -LiteralPath 'terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip' -DestinationPath '.'
Expand-Archive -LiteralPath 'terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip' -DestinationPath '.'
- name: Run E2E Tests
platforms: all
- name: Run E2E Tests (Darwin & Linux)
id: get-product-version
shell: bash
if: ${{ (matrix.goos == 'linux') || (matrix.goos == 'darwin') }}
env:
e2e_cache_path: ${{ needs.e2etest-build.outputs.e2e-cache-path }}
run: .github/scripts/e2e_test_linux_darwin.sh
- name: Run E2E Tests (Windows)
if: ${{ matrix.goos == 'windows' }}
env:
TF_ACC: 1
shell: cmd
run: |
e2etest.exe -test.v
run: e2etest.exe -test.v
docs-source-package:
name: "Build documentation bundle"
e2e-test-exec:
name: Run terraform-exec test for linux amd64
runs-on: ubuntu-latest
needs:
- get-product-version
- get-go-version
- build
env:
os: ${{ matrix.goos }}
arch: ${{ matrix.goarch }}
version: ${{needs.get-product-version.outputs.product-version}}
steps:
- uses: actions/checkout@v2
# FIXME: We should include some sort of pre-validation step here, to
# confirm that the doc content is mechanically valid so that the
# publishing pipeline will be able to render all content without errors.
- name: "Create documentation source bundle"
run: |
(cd website && zip -9 -r ../terraform-cli-docs-source_${{ env.version }}.zip .)
- uses: actions/upload-artifact@v2
- name: Install Go toolchain
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
name: terraform-cli-docs-source_${{ env.version }}.zip
path: terraform-cli-docs-source_${{ env.version }}.zip
if-no-files-found: error
go-version: ${{ needs.get-go-version.outputs.go-version }}
- name: Download Terraform CLI package
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
id: clipkg
with:
name: terraform_${{ env.version }}_linux_amd64.zip
path: .
- name: Checkout terraform-exec repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: hashicorp/terraform-exec
path: terraform-exec
- name: Run terraform-exec end-to-end tests
run: |
FULL_RELEASE_VERSION="${{ env.version }}"
unzip terraform_${FULL_RELEASE_VERSION}_linux_amd64.zip
export TFEXEC_E2ETEST_TERRAFORM_PATH="$(pwd)/terraform"
cd terraform-exec
go test -race -timeout=30m -v ./tfexec/internal/e2etest

194
.github/workflows/changelog.yml vendored Normal file
View file

@ -0,0 +1,194 @@
# This workflow makes sure contributors don't forget to add a changelog entry or explicitly opt-out of it.
#
# Do not extend this workflow to include checking out the code (e.g. for building and testing purposes) while the pull_request_target trigger is used.
# Instead, see use of workflow_run in https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
name: Changelog
on:
# The pull_request_target trigger event allows PRs raised from forks to have write permissions and access secrets.
# We uses it in this workflow to enable writing comments to the PR.
pull_request_target:
types:
- opened
- ready_for_review
- reopened
- synchronize
- labeled
- unlabeled
# This workflow runs for not-yet-reviewed external contributions.
# Following a pull_request_target trigger the workflow would have write permissions,
# so we intentionally restrict the permissions to only include write access on pull-requests.
permissions:
contents: read
pull-requests: write
jobs:
check-changelog-entry:
name: "Check Changelog Entry"
runs-on: ubuntu-latest
concurrency:
group: changelog-${{ github.head_ref }}
cancel-in-progress: true
steps:
- name: "Changed files"
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changelog
with:
filters: |
changes:
- '.changes/*/*.yaml'
changelog:
- 'CHANGELOG.md'
version:
- 'version/VERSION'
list-files: json
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
sparse-checkout: |
version/VERSION
.changie.yaml
.changes/
sparse-checkout-cone-mode: false
ref: ${{ github.ref }} # Ref refers to the target branch of this PR
- name: "Check for changelog entry"
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const fs = require("fs");
async function createOrUpdateChangelogComment(commentDetails, deleteComment) {
const commentStart = "## Changelog Warning"
const body = commentStart + "\n\n" + commentDetails;
const { number: issue_number } = context.issue;
const { owner, repo } = context.repo;
// List all comments
const allComments = (await github.rest.issues.listComments({
issue_number,
owner,
repo,
})).data;
const existingComment = allComments.find(c => c.body.startsWith(commentStart));
const comment_id = existingComment?.id;
if (deleteComment) {
if (existingComment) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id,
});
}
return;
}
core.setFailed(commentDetails);
if (existingComment) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
}
const changesPresent = ${{steps.changelog.outputs.changes}};
const changedChangesFiles = ${{steps.changelog.outputs.changes_files}};
const changelogChangesPresent = ${{steps.changelog.outputs.changelog}};
const versionChangesPresent = ${{steps.changelog.outputs.version}};
const prLabels = await github.rest.issues.listLabelsOnIssue({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
const backportLabels = prLabels.data.filter(label => label.name.endsWith("-backport"));
const backportVersions = backportLabels.map(label => label.name.split("-")[0]);
const currentVersionFile = fs.readFileSync("./version/VERSION", "utf-8");
const currentVersionParts = currentVersionFile.split(".");
currentVersionParts.pop();
const currentVersion = currentVersionParts.join(".");
const allVersions = [currentVersion, ...backportVersions]
allVersions.sort((a, b) => {
const as = a.split(".").map(Number);
const bs = b.split(".").map(Number);
if (as[0] !== bs[0]) {
return as[0] - bs[0];
}
if (as[1] !== bs[1]) {
return as[1] - bs[1];
}
});
const noChangelogNeededLabel = prLabels.data.find(label => label.name === 'no-changelog-needed');
const dependenciesLabel = prLabels.data.find(label => label.name === 'dependencies');
// We want to prohibit contributors from directly changing the CHANGELOG.md, it's
// generated so all changes will be lost during the release process.
// Therefore we only allow the changelog to change together with the version.
// In very rare cases where we generate changes in the changelog without changing the
// version we will just ignore this failing check.
if (changelogChangesPresent && !versionChangesPresent) {
await createOrUpdateChangelogComment("Please don't edit the CHANGELOG.md manually. We use changie to control the Changelog generation, please use `npx changie new` to create a new changelog entry.");
return;
}
if (dependenciesLabel) {
return;
}
if (noChangelogNeededLabel) {
if (changesPresent) {
await createOrUpdateChangelogComment("Please remove either the 'no-changelog-needed' label or the changelog entry from this PR.");
return;
}
// Nothing to complain about, so delete any existing comment
await createOrUpdateChangelogComment("", true);
return;
}
// We only want to have a changelog entry for the oldest version this PR will
// land in.
const onlyExpectedChangeVersion = allVersions[0]
const missingChangelogEntry = !changedChangesFiles.some(filePath => filePath.includes("/v"+onlyExpectedChangeVersion+"/"))
const unexpectedChangelogEntry = changedChangesFiles.filter(filePath => !filePath.includes("/v"+onlyExpectedChangeVersion+"/"))
if (missingChangelogEntry) {
await createOrUpdateChangelogComment(`Currently this PR would target a v${onlyExpectedChangeVersion} release. Please add a changelog entry for in the .changes/v${onlyExpectedChangeVersion} folder, or discuss which release you'd like to target with your reviewer. If you believe this change does not need a changelog entry, please add the 'no-changelog-needed' label.`);
return;
}
if (unexpectedChangelogEntry.length > 0) {
await createOrUpdateChangelogComment(`Please remove the changelog entry for the following paths: ${unexpectedChangelogEntry.join(", ")}. If you believe this change does not need a changelog entry, please add the 'no-changelog-needed' label.`);
return;
}
// Nothing to complain about, so delete any existing comment
await createOrUpdateChangelogComment("", true);
- name: Validate changie fragment is valid
uses: miniscruff/changie-action@6dcc2533cac0495148ed4046c438487e4dceaa23 # v2.0.0
with:
version: latest
args: merge -u "." --dry-run

View file

@ -17,11 +17,14 @@ name: Quick Checks
on:
pull_request:
types:
- opened
- ready_for_review
- reopened
- synchronize
push:
branches:
- main
- 'v[0-9]+.[0-9]+'
- checks-workflow-dev/*
- '*'
tags:
- 'v[0-9]+.[0-9]+.[0-9]+*'
@ -38,31 +41,24 @@ jobs:
steps:
- name: "Fetch source code"
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
# NOTE: This cache is shared so the following step must always be
# identical across the unit-tests, e2e-tests, and consistency-checks
# jobs, or else weird things could happen.
- name: Cache Go modules
uses: actions/cache@v3
with:
path: "~/go/pkg"
key: go-mod-${{ hashFiles('go.sum') }}
restore-keys: |
go-mod-
cache-dependency-path: go.sum
- name: "Unit tests"
run: |
go test ./...
# We run tests for all packages from all modules in this repository.
for dir in $(go list -m -f '{{.Dir}}' github.com/hashicorp/terraform/...); do
(cd $dir && go test -cover "./...")
done
race-tests:
name: "Race Tests"
@ -70,27 +66,17 @@ jobs:
steps:
- name: "Fetch source code"
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
# NOTE: This cache is shared so the following step must always be
# identical across the unit-tests, e2e-tests, and consistency-checks
# jobs, or else weird things could happen.
- name: Cache Go modules
uses: actions/cache@v3
with:
path: "~/go/pkg"
key: go-mod-${{ hashFiles('go.sum') }}
restore-keys: |
go-mod-
cache-dependency-path: go.sum
# The race detector add significant time to the unit tests, so only run
# it for select packages.
@ -108,27 +94,17 @@ jobs:
steps:
- name: "Fetch source code"
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
# NOTE: This cache is shared so the following step must always be
# identical across the unit-tests, e2e-tests, and consistency-checks
# jobs, or else weird things could happen.
- name: Cache Go modules
uses: actions/cache@v3
with:
path: "~/go/pkg"
key: go-mod-${{ hashFiles('go.sum') }}
restore-keys: |
go-mod-
cache-dependency-path: go.sum
- name: "End-to-end tests"
run: |
@ -140,7 +116,7 @@ jobs:
steps:
- name: "Fetch source code"
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # We need to do comparisons against the main branch.
@ -149,31 +125,24 @@ jobs:
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
# NOTE: This cache is shared so the following step must always be
# identical across the unit-tests, e2e-tests, and consistency-checks
# jobs, or else weird things could happen.
- name: Cache Go modules
uses: actions/cache@v3
with:
path: "~/go/pkg"
key: go-mod-${{ hashFiles('go.sum') }}
restore-keys: |
go-mod-
cache-dependency-path: go.sum
- name: "go.mod and go.sum consistency check"
run: |
go mod tidy
if [[ -n "$(git status --porcelain)" ]]; then
echo >&2 "ERROR: go.mod/go.sum are not up-to-date. Run 'go mod tidy' and then commit the updated files."
make syncdeps
CHANGED="$(git status --porcelain)"
if [[ -n "$CHANGED" ]]; then
git diff
echo >&2 "ERROR: go.mod/go.sum files are not up-to-date. Run 'make syncdeps' and then commit the updated files."
echo >&2 $'Affected files:\n'"$CHANGED"
exit 1
fi
- name: Cache protobuf tools
uses: actions/cache@v3
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: "tools/protobuf-compile/.workdir"
key: protobuf-tools-${{ hashFiles('tools/protobuf-compile/protobuf-compile.go') }}
@ -182,7 +151,7 @@ jobs:
- name: "Code consistency checks"
run: |
make fmtcheck importscheck generate staticcheck exhaustive protobuf
make fmtcheck importscheck vetcheck copyright generate staticcheck exhaustive protobuf
if [[ -n "$(git status --porcelain)" ]]; then
echo >&2 "ERROR: Generated files are inconsistent. Run 'make generate' and 'make protobuf' locally and then commit the updated files."
git >&2 status --porcelain

View file

@ -0,0 +1,73 @@
name: equivalence-test-diff
on:
pull_request:
types:
- opened
- synchronize
- ready_for_review
- reopened
permissions:
contents: read
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
jobs:
equivalence-test-diff:
name: "Equivalence Test Diff"
runs-on: ubuntu-latest
steps:
- name: Fetch source code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
cache-dependency-path: go.sum
- name: Download testing framework
shell: bash
run: |
./.github/scripts/equivalence-test.sh download_equivalence_test_binary \
0.5.0 \
./bin/equivalence-tests \
linux \
amd64
- name: Build terraform
shell: bash
run: ./.github/scripts/equivalence-test.sh build_terraform_binary ./bin/terraform
- name: Run equivalence tests
id: equivalence-tests
shell: bash {0} # we want to capture the exit code
run: |
./bin/equivalence-tests diff \
--tests=testing/equivalence-tests/tests \
--goldens=testing/equivalence-tests/outputs \
--binary=$(pwd)/bin/terraform
echo "exit-code=$?" >> "${GITHUB_OUTPUT}"
- name: Equivalence tests failed
if: steps.equivalence-tests.outputs.exit-code == 1 # 1 is the exit code for failure
shell: bash
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "The equivalence tests failed. Please investigate [here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})."
exit 1 # fail the job
- name: Equivalence tests changed
if: steps.equivalence-tests.outputs.exit-code == 2 # 2 is the exit code for changed
shell: bash
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "The equivalence tests will be updated. Please verify the changes [here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})."

View file

@ -0,0 +1,54 @@
name: equivalence-tests-manual
on:
workflow_dispatch:
inputs:
target-branch:
type: string
description: "Which branch should be updated?"
required: true
new-branch:
type: string
description: "Name of new branch to be created for the review."
required: true
equivalence-test-version:
type: string
description: 'Equivalence testing framework version to use (no v prefix, eg. 0.5.0).'
default: "0.5.0"
required: true
permissions:
contents: write
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
jobs:
run-equivalence-tests:
name: "Run equivalence tests"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.target-branch }}
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
cache-dependency-path: go.sum
- uses: ./.github/actions/equivalence-test
with:
target-equivalence-test-version: ${{ inputs.equivalence-test-version }}
target-os: linux
target-arch: amd64
current-branch: ${{ inputs.target-branch }}
new-branch: ${{ inputs.new-branch }}
reviewers: ${{ github.actor }}
message: "Update equivalence test golden files."

View file

@ -0,0 +1,69 @@
name: equivalence-test-update
on:
pull_request_target:
types: [ closed ]
permissions:
contents: write
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
jobs:
check:
name: "Should run equivalence tests?"
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.target_branch.outputs.should_run }}
steps:
- name: target_branch
id: target_branch
run: |
merged='${{ github.event.pull_request.merged }}'
target_branch='${{ github.event.pull_request.base.ref }}'
targets_release_branch=false
if [ "$target_branch" == "main" ]; then
targets_release_branch=true
elif [ "$target_branch" =~ ^v[0-9]+\.[0-9]+$ ]; then
targets_release_branch=true
fi
should_run=false
if [ "$merged" == "true" ] && [ "$targets_release_branch" == "true" ]; then
should_run=true
fi
echo "should_run=$should_run" >> ${GITHUB_OUTPUT}
run-equivalence-tests:
name: "Run equivalence tests"
needs:
- check
if: needs.check.outputs.should_run == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.target-branch }}
- name: Determine Go version
id: go
uses: ./.github/actions/go-version
- name: Install Go toolchain
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ steps.go.outputs.version }}
cache-dependency-path: go.sum
- uses: ./.github/actions/equivalence-test
with:
target-equivalence-test-version: 0.5.0
target-os: linux
target-arch: amd64
current-branch: ${{ github.event.pull_request.base.ref }}
new-branch: equivalence-testing/${{ github.event.pull_request.head.ref }}
reviewers: ${{ github.event.pull_request.merged_by.login }}
message: "Update equivalence test golden files after ${{ github.event.pull_request.html_url }}."

View file

@ -8,7 +8,7 @@ jobs:
issue_comment_triage:
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-remove-labels@v1
- uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.3.0
with:
labels: |
stale

View file

@ -8,16 +8,17 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
with:
process-only: 'issues, prs'
github-token: ${{ github.token }}
issue-lock-comment: >
issue-comment: >
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.
issue-lock-inactive-days: '30'
pr-lock-comment: >
issue-inactive-days: '30'
pr-comment: >
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.
pr-lock-inactive-days: '30'
pr-inactive-days: '30'

View file

@ -1,16 +1,23 @@
---
name: Backport Assistant Runner
on:
pull_request_target:
types:
- closed
pull_request:
types:
- labeled
permissions:
contents: write # to push to a new branch
pull-requests: write # to create a new PR
jobs:
backport:
if: github.event.pull_request.merged
if: github.event.pull_request
runs-on: ubuntu-latest
container: hashicorpdev/backport-assistant:0.2.1
container: hashicorpdev/backport-assistant:0.4.7@sha256:36f9d4fba82b9454f1f62bf76c8078fafe3ab0be71356cb96af6d56ac4482cd8
steps:
- name: Run Backport Assistant
run: |
@ -18,4 +25,5 @@ jobs:
env:
BACKPORT_LABEL_REGEXP: "(?P<target>\\d+\\.\\d+)-backport"
BACKPORT_TARGET_TEMPLATE: "v{{.target}}"
GITHUB_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
BACKPORT_CREATE_DRAFT_ALWAYS: true
GITHUB_TOKEN: ${{ github.token }}

View file

@ -1,24 +0,0 @@
name: Merged Pull Request
permissions:
pull-requests: write
# only trigger on pull request closed events
on:
pull_request_target:
types: [ closed ]
jobs:
merge_job:
# this job will only run if the PR has been merged
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v5
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch."
})

5
.gitignore vendored
View file

@ -18,6 +18,8 @@ website/node_modules
*.test
*.iml
go.work*
/terraform
website/vendor
@ -25,3 +27,6 @@ vendor/
# Coverage
coverage.txt
# IDEs
.vscode/

View file

@ -1 +1 @@
1.19.0
1.24.2

97
.release/ci.hcl Normal file
View file

@ -0,0 +1,97 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
schema = "2"
project "terraform" {
// the team key is not used by CRT currently
team = "terraform"
slack {
notification_channel = "C011WJ112MD"
}
github {
organization = "hashicorp"
repository = "terraform"
release_branches = [
"main",
"release/**",
"v**.**",
]
}
}
event "build" {
depends = ["merge"]
action "build" {
organization = "hashicorp"
repository = "terraform"
workflow = "build"
}
}
// Read more about what the `prepare` workflow does here:
// https://hashicorp.atlassian.net/wiki/spaces/RELENG/pages/2489712686/Dec+7th+2022+-+Introducing+the+new+Prepare+workflow
event "prepare" {
depends = ["build"]
action "prepare" {
organization = "hashicorp"
repository = "crt-workflows-common"
workflow = "prepare"
depends = ["build"]
}
notification {
on = "fail"
}
}
## These are promotion and post-publish events
## they should be added to the end of the file after the verify event stanza.
event "trigger-staging" {
// This event is dispatched by the bob trigger-promotion command
// and is required - do not delete.
}
event "promote-staging" {
depends = ["trigger-staging"]
action "promote-staging" {
organization = "hashicorp"
repository = "crt-workflows-common"
workflow = "promote-staging"
config = "release-metadata.hcl"
}
notification {
on = "always"
}
}
event "trigger-production" {
// This event is dispatched by the bob trigger-promotion command
// and is required - do not delete.
}
event "promote-production" {
depends = ["trigger-production"]
action "promote-production" {
organization = "hashicorp"
repository = "crt-workflows-common"
workflow = "promote-production"
}
promotion-events {
update-ironbank = true
post-promotion {
organization = "hashicorp"
repository = "terraform-releases"
workflow = "crt-hook-tfc-upload"
}
}
notification {
on = "always"
}
}

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
url_docker_registry_dockerhub = "https://hub.docker.com/r/hashicorp/terraform"
url_docker_registry_ecr = "https://gallery.ecr.aws/hashicorp/terraform"
url_license = "https://github.com/hashicorp/terraform/blob/main/LICENSE"

View file

@ -0,0 +1,16 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
container {
dependencies = false
alpine_secdb = true
secrets = false
}
binary {
secrets = true
go_modules = true
osv = false
oss_index = true
nvd = false
}

View file

@ -3,7 +3,7 @@ The Terraform Core team has adopted a more structured bug triage process than we
When a bug report is filed, our goal is to either:
1. Get it to a state where it is ready for engineering to fix it in an upcoming Terraform release, or
2. Close it explain why, if we can't help
2. Close it and explain why, if we can't help
## Process

42
BUILDING.md Normal file
View file

@ -0,0 +1,42 @@
# Building from Source
Pre-built binaries are available for download for a variety of supported platforms through the [HashiCorp Releases website](https://releases.hashicorp.com/terraform/).
However, if you'd like to build Terraform yourself, you can do so using the Go build toolchain and the options specified in this document.
## Prerequisites
1. Ensure you've installed the Go language version specified in [`.go-version`](https://github.com/hashicorp/terraform/blob/main/.go-version).
2. Clone this repository to a location of your choice.
## Terraform Build Options
Terraform accepts certain options passed using `ldflags` at build time which control the behavior of the resulting binary.
### Dev Version Reporting
Terraform will include a `-dev` flag when reporting its own version (ex: 1.5.0-dev) unless `version.dev` is set to `no`:
```
go build -ldflags "-w -s -X 'github.com/hashicorp/terraform/version.dev=no'" -o bin/ .
```
### Experimental Features
Experimental features of Terraform will be disabled unless `main.experimentsAllowed` is set to `yes`:
```
go build -ldflags "-w -s -X 'main.experimentsAllowed=yes'" -o bin/ .
```
In the official build process for Terraform, experiments are only allowed in alpha release builds. We recommend that third-party distributors follow that convention in order to reduce user confusion.
## Go Options
For the most part, the Terraform release process relies on the Go toolchain defaults for the target operating system and processor architecture.
### `CGO_ENABLED`
One exception is the `CGO_ENABLED` option, which is set explicitly when building Terraform binaries. For most platforms, we build with `CGO_ENABLED=0` in order to produce a statically linked binary. For MacOS/Darwin operating systems, we build with `CGO_ENABLED=1` to avoid a platform-specific issue with DNS resolution.

View file

@ -1,82 +1,32 @@
## 1.3.0 (Unreleased)
## 1.13.0 (Unreleased)
NEW FEATURES:
* **Optional attributes for object type constraints:** When declaring an input variable whose type constraint includes an object type, you can now declare individual attributes as optional, and specify a default value to use if the caller doesn't set it. For example:
```terraform
variable "with_optional_attribute" {
type = object({
a = string # a required attribute
b = optional(string) # an optional attribute
c = optional(number, 127) # an optional attribute with a default value
})
}
```
Assigning `{ a = "foo" }` to this variable will result in the value `{ a = "foo", b = null, c = 127 }`.
* Added functions: `startswith` and `endswith` allow you to check whether a given string has a specified prefix or suffix. ([#31220](https://github.com/hashicorp/terraform/issues/31220))
UPGRADE NOTES:
* `terraform show -json`: Output changes now include more detail about the unknown-ness of the planned value. Previously, a planned output would be marked as either fully known or partially unknown, with the `after_unknown` field having value `false` or `true` respectively. Now outputs correctly expose the full structure of unknownness for complex values, allowing consumers of the JSON output format to determine which values in a collection are known only after apply.
* `terraform import`: The `-allow-missing-config` has been removed, and at least an empty configuration block must exist to import a resource.
* Consumers of the JSON output format expecting on the `after_unknown` field to be only `false` or `true` should be updated to support [the change representation](https://www.terraform.io/internals/json-format#change-representation) described in the documentation, and as was already used for resource changes. ([#31235](https://github.com/hashicorp/terraform/issues/31235))
* AzureRM Backend: This release concludes [the deprecation cycle started in Terraform v1.1](https://www.terraform.io/language/upgrade-guides/1-1#preparation-for-removing-azure-ad-graph-support-in-the-azurerm-backend) for the `azurerm` backend's support of "ADAL" authentication. This backend now supports only "MSAL" (Microsoft Graph) authentication.
This follows from [Microsoft's own deprecation of Azure AD Graph](https://docs.microsoft.com/en-us/graph/migrate-azure-ad-graph-faq), and so you must follow the migration instructions presented in that Azure documentation to adopt Microsoft Graph and then change your backend configuration to use MSAL authentication before upgrading to Terraform v1.3.
* When making requests to HTTPS servers, Terraform will now reject invalid handshakes that have duplicate extensions, as required by RFC 5246 section 7.4.1.4 and RFC 8446 section 4.2. This may cause new errors when interacting with existing buggy or misconfigured TLS servers, but should not affect correct servers.
This only applies to requests made directly by Terraform CLI, such as provider installation and remote state storage. Terraform providers are separate programs which decide their own policy for handling of TLS handshakes.
ENHANCEMENTS:
* config: Optional attributes for object type constraints, as described under new features above. ([#31154](https://github.com/hashicorp/terraform/issues/31154))
* config: New built-in function `timecmp` allows determining the ordering relationship between two timestamps while taking potentially-different UTC offsets into account. ([#31154](https://github.com/hashicorp/terraform/issues/31154))
* `terraform fmt` now accepts multiple target paths, allowing formatting of several individual files at once. ([#31687](https://github.com/hashicorp/terraform/issues/31687))
* When reporting an error message related to a function call, Terraform will now include contextual information about the signature of the function that was being called, as an aid to understanding why the call might have failed. ([#31299](https://github.com/hashicorp/terraform/issues/31299))
* When reporting an error or warning message that isn't caused by values being unknown or marked as sensitive, Terraform will no longer mention any values having those characteristics in the contextual information presented alongside the error. Terraform will still return this information for the small subset of error messages that are specifically about unknown values or sensitive values being invalid in certain contexts. ([#31299](https://github.com/hashicorp/terraform/issues/31299))
* The Terraform CLI now calls `PlanResourceChange` for compatible providers when destroying resource instances. ([#31179](https://github.com/hashicorp/terraform/issues/31179))
* The AzureRM Backend now only supports MSAL (and Microsoft Graph) and no longer makes use of ADAL (and Azure Active Directory Graph) for authentication ([#31070](https://github.com/hashicorp/terraform/issues/31070))
* The COS backend now supports global acceleration. ([#31425](https://github.com/hashicorp/terraform/issues/31425))
* providercache: include host in provider installation error ([#31524](https://github.com/hashicorp/terraform/issues/31524))
* refactoring: `moved` blocks can now be used to move resources to and from external modules ([#31556](https://github.com/hashicorp/terraform/issues/31556))
* When showing the progress of a remote operation running in Terraform Cloud, Terraform CLI will include information about pre-plan run tasks ([#31617](https://github.com/hashicorp/terraform/issues/31617))
BUG FIXES:
* config: Terraform was not previously evaluating preconditions and postconditions during the apply phase for resource instances that didn't have any changes pending, which was incorrect because the outcome of a condition can potentially be affected by changes to _other_ objects in the configuration. Terraform will now always check the conditions for every resource instance included in a plan during the apply phase, even for resource instances that have "no-op" changes. This means that some failures that would previously have been detected only by a subsequent run will now be detected during the same run that caused them, thereby giving the feedback at the appropriate time. ([#31491](https://github.com/hashicorp/terraform/issues/31491))
* `terraform show -json`: Fixed missing unknown markers in the encoding of partially unknown tuples and sets. ([#31236](https://github.com/hashicorp/terraform/issues/31236))
* `terraform output` CLI help documentation is now more consistent with web-based documentation. ([#29354](https://github.com/hashicorp/terraform/issues/29354))
* getproviders: account for occasionally missing Host header in errors ([#31542](https://github.com/hashicorp/terraform/issues/31542))
* core: Do not create "delete" changes for nonexistent outputs ([#31471](https://github.com/hashicorp/terraform/issues/31471))
* configload: validate implied provider names in submodules to avoid crash ([#31573](https://github.com/hashicorp/terraform/issues/31573))
* core: `import` fails when resources or modules are expanded with for each, or input from data sources is required ([#31283](https://github.com/hashicorp/terraform/issues/31283))
EXPERIMENTS:
* This release concludes the `module_variable_optional_attrs` experiment, which started in Terraform v0.14.0. The final design of the optional attributes feature is similar to the experimental form in the previous releases, but with two major differences:
* The `optional` function-like modifier for declaring an optional attribute now accepts an optional second argument for specifying a default value to use when the attribute isn't set by the caller. If not specified, the default value is a null value of the appropriate type as before.
* The built-in `defaults` function, previously used to meet the use-case of replacing null values with default values, will not graduate to stable and has been removed. Use the second argument of `optional` inline in your type constraint to declare default values instead.
Experiments are only enabled in alpha releases of Terraform CLI. The following features are not yet available in stable releases.
If you have any experimental modules that were participating in this experiment, you will need to remove the experiment opt-in and adopt the new syntax for declaring default values in order to migrate your existing module to the stablized version of this feature. If you are writing a shared module for others to use, we recommend declaring that your module requires Terraform v1.3.0 or later to give specific feedback when using the new feature on older Terraform versions, in place of the previous declaration to use the experimental form of this feature:
```hcl
terraform {
required_version = ">= 1.3.0"
}
```
- The new command `terraform rpcapi` exposes some Terraform Core functionality through an RPC interface compatible with [`go-plugin`](https://github.com/hashicorp/go-plugin). The exact RPC API exposed here is currently subject to change at any time, because it's here primarily as a vehicle to support the [Terraform Stacks](https://www.hashicorp.com/blog/terraform-stacks-explained) private preview and so will be broken if necessary to respond to feedback from private preview participants, or possibly for other reasons. Do not use this mechanism yet outside of Terraform Stacks private preview.
- The experimental "deferred actions" feature, enabled by passing the `-allow-deferral` option to `terraform plan`, permits `count` and `for_each` arguments in `module`, `resource`, and `data` blocks to have unknown values and allows providers to react more flexibly to unknown values. This experiment is under active development, and so it's not yet useful to participate in this experiment
## Previous Releases
For information on prior major and minor releases, see their changelogs:
For information on prior major and minor releases, refer to their changelogs:
* [v1.2](https://github.com/hashicorp/terraform/blob/v1.2/CHANGELOG.md)
* [v1.1](https://github.com/hashicorp/terraform/blob/v1.1/CHANGELOG.md)
* [v1.0](https://github.com/hashicorp/terraform/blob/v1.0/CHANGELOG.md)
* [v0.15](https://github.com/hashicorp/terraform/blob/v0.15/CHANGELOG.md)
* [v0.14](https://github.com/hashicorp/terraform/blob/v0.14/CHANGELOG.md)
* [v0.13](https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md)
* [v0.12](https://github.com/hashicorp/terraform/blob/v0.12/CHANGELOG.md)
* [v0.11 and earlier](https://github.com/hashicorp/terraform/blob/v0.11/CHANGELOG.md)
- [v1.12](https://github.com/hashicorp/terraform/blob/v1.12/CHANGELOG.md)
- [v1.11](https://github.com/hashicorp/terraform/blob/v1.11/CHANGELOG.md)
- [v1.10](https://github.com/hashicorp/terraform/blob/v1.10/CHANGELOG.md)
- [v1.9](https://github.com/hashicorp/terraform/blob/v1.9/CHANGELOG.md)
- [v1.8](https://github.com/hashicorp/terraform/blob/v1.8/CHANGELOG.md)
- [v1.7](https://github.com/hashicorp/terraform/blob/v1.7/CHANGELOG.md)
- [v1.6](https://github.com/hashicorp/terraform/blob/v1.6/CHANGELOG.md)
- [v1.5](https://github.com/hashicorp/terraform/blob/v1.5/CHANGELOG.md)
- [v1.4](https://github.com/hashicorp/terraform/blob/v1.4/CHANGELOG.md)
- [v1.3](https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md)
- [v1.2](https://github.com/hashicorp/terraform/blob/v1.2/CHANGELOG.md)
- [v1.1](https://github.com/hashicorp/terraform/blob/v1.1/CHANGELOG.md)
- [v1.0](https://github.com/hashicorp/terraform/blob/v1.0/CHANGELOG.md)
- [v0.15](https://github.com/hashicorp/terraform/blob/v0.15/CHANGELOG.md)
- [v0.14](https://github.com/hashicorp/terraform/blob/v0.14/CHANGELOG.md)
- [v0.13](https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md)
- [v0.12](https://github.com/hashicorp/terraform/blob/v0.12/CHANGELOG.md)
- [v0.11 and earlier](https://github.com/hashicorp/terraform/blob/v0.11/CHANGELOG.md)

View file

@ -1,27 +1,56 @@
# Each line is a file pattern followed by one or more owners.
# More on CODEOWNERS files: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
# Remote-state backend # Maintainer
/internal/backend/remote-state/artifactory Unmaintained
/internal/backend/remote-state/azure @hashicorp/terraform-azure
/internal/backend/remote-state/consul @hashicorp/consul @remilapeyre
/internal/backend/remote-state/cos @likexian
/internal/backend/remote-state/etcdv2 Unmaintained
/internal/backend/remote-state/etcdv3 Unmaintained
/internal/backend/remote-state/gcs @hashicorp/terraform-google
# The rules are evaluated in order, if a file matches multiple patterns, the last match "wins".
# We want to have a default rule for all files
* @hashicorp/terraform-core
# Entries that are commented out have maintainers that are not in the
# HashiCorp organization and so cannot be automatically added as reviewers.
#
# We retain those as documentation of who agreed to maintain, but they
# cannot be used automatically by GitHub's pull request workflow and would
# make GitHub consider this file invalid if not commented.
# Remote-state backend # Maintainer
/internal/backend/remote-state/azure @hashicorp/terraform-core @hashicorp/terraform-azure
#/internal/backend/remote-state/consul Unmaintained
#/internal/backend/remote-state/cos @likexian
/internal/backend/remote-state/gcs @hashicorp/terraform-core @hashicorp/tf-eco-hybrid-cloud
/internal/backend/remote-state/http @hashicorp/terraform-core
/internal/backend/remote-state/manta Unmaintained
/internal/backend/remote-state/oss @xiaozhu36
/internal/backend/remote-state/pg @remilapeyre
/internal/backend/remote-state/s3 @hashicorp/terraform-aws
/internal/backend/remote-state/swift Unmaintained
/internal/backend/remote-state/kubernetes @jrhouston @alexsomesan
#/internal/backend/remote-state/oss @xiaozhu36
#/internal/backend/remote-state/pg @remilapeyre
/internal/backend/remote-state/s3 @hashicorp/terraform-core @hashicorp/terraform-aws
/internal/backend/remote-state/kubernetes @hashicorp/terraform-core @hashicorp/tf-eco-hybrid-cloud
#/internal/backend/remote-state/oci @ravinitp @pvkrishnachaitanya
# Cloud backend
/internal/backend/remote @hashicorp/terraform-core @hashicorp/tf-core-cloud
/internal/cloud @hashicorp/terraform-core @hashicorp/tf-core-cloud
# Provisioners
builtin/provisioners/chef Deprecated
builtin/provisioners/file @hashicorp/terraform-core
builtin/provisioners/habitat Deprecated
builtin/provisioners/local-exec @hashicorp/terraform-core
builtin/provisioners/puppet Deprecated
builtin/provisioners/remote-exec @hashicorp/terraform-core
builtin/provisioners/salt-masterless Deprecated
# engineering and web presence get notified of, and can approve changes to web tooling, but not content at developer.hashicorp.com/terraform/docs
/website/ @hashicorp/web-presence @hashicorp/terraform-core
/website/data/
/website/public/
/website/content/
# education and engineering get notified of, and can approve changes to web content at developer.hashicorp.com/terraform/docs
/website/data/ @hashicorp/terraform-education @hashicorp/terraform-core
/website/docs/ @hashicorp/terraform-education @hashicorp/terraform-core
/website/img/ @hashicorp/terraform-education @hashicorp/terraform-core
/website/README.md @hashicorp/terraform-education @hashicorp/terraform-core
/website/public/ @hashicorp/terraform-education @hashicorp/terraform-core
/website/content/ @hashicorp/terraform-education @hashicorp/terraform-core
# Backend maintainers also get co-ownership of their backend docs pages
/website/docs/language/backend/azurerm.mdx @hashicorp/terraform-education @hashicorp/terraform-core @hashicorp/terraform-azure
/website/docs/language/backend/gcs.mdx @hashicorp/terraform-education @hashicorp/terraform-core @hashicorp/tf-eco-hybrid-cloud
/website/docs/language/backend/kubernetes.mdx @hashicorp/terraform-education @hashicorp/terraform-core @hashicorp/tf-eco-hybrid-cloud
/website/docs/language/backend/s3.mdx @hashicorp/terraform-education @hashicorp/terraform-core @hashicorp/terraform-aws

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
# This Dockerfile builds on golang:alpine by building Terraform from source
# using the current working directory.
#
@ -10,7 +13,7 @@
FROM docker.mirror.hashicorp.services/golang:alpine
LABEL maintainer="HashiCorp Terraform Team <terraform@hashicorp.com>"
RUN apk add --no-cache git bash openssh
RUN apk add --no-cache git bash openssh ca-certificates
ENV TF_DEV=true
ENV TF_RELEASE=1

446
LICENSE
View file

@ -1,354 +1,92 @@
Mozilla Public License, version 2.0
1. Definitions
1.1. “Contributor”
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. “Contributor Version”
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributors Contribution.
1.3. “Contribution”
means Covered Software of a particular Contributor.
1.4. “Covered Software”
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. “Incompatible With Secondary Licenses”
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.
1.6. “Executable Form”
means any form of the work other than Source Code Form.
1.7. “Larger Work”
means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.
1.8. “License”
means this document.
1.9. “Licensable”
means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.
1.10. “Modifications”
means any of the following:
a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. “Patent Claims” of a Contributor
means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.
1.12. “Secondary License”
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. “Source Code Form”
means the form of the work preferred for making modifications.
1.14. “You” (or “Your”)
means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, “control” means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third partys
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.
This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients
rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an “as is” basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
partys negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a partys ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - “Incompatible With Secondary Licenses” Notice
This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
Parameters
Licensor: HashiCorp, Inc.
Licensed Work: Terraform Version 1.6.0 or later. The Licensed Work is (c) 2024
HashiCorp, Inc.
Additional Use Grant: You may make production use of the Licensed Work, provided
Your use does not include offering the Licensed Work to third
parties on a hosted or embedded basis in order to compete with
HashiCorp's paid version(s) of the Licensed Work. For purposes
of this license:
A "competitive offering" is a Product that is offered to third
parties on a paid basis, including through paid support
arrangements, that significantly overlaps with the capabilities
of HashiCorp's paid version(s) of the Licensed Work. If Your
Product is not a competitive offering when You first make it
generally available, it will not become a competitive offering
later due to HashiCorp releasing a new version of the Licensed
Work with additional capabilities. In addition, Products that
are not provided on a paid basis are not competitive.
"Product" means software that is offered to end users to manage
in their own environments or offered as a service on a hosted
basis.
"Embedded" means including the source code or executable code
from the Licensed Work in a competitive offering. "Embedded"
also means packaging the competitive offering in such a way
that the Licensed Work must be accessed or downloaded for the
competitive offering to operate.
Hosting or using the Licensed Work(s) for internal purposes
within an organization is not considered a competitive
offering. HashiCorp considers your organization to include all
of your affiliates under common control.
For binding interpretive guidance on using HashiCorp products
under the Business Source License, please visit our FAQ.
(https://www.hashicorp.com/license-faq)
Change Date: Four years from the date the Licensed Work is published.
Change License: MPL 2.0
For information about alternative licensing arrangements for the Licensed Work,
please contact licensing@hashicorp.com.
Notice
Business Source License 1.1
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.

View file

@ -1,21 +1,3 @@
WEBSITE_REPO=github.com/hashicorp/terraform-website
VERSION?="0.3.44"
PWD=$$(pwd)
DOCKER_IMAGE="hashicorp/terraform-website:full"
DOCKER_IMAGE_LOCAL="hashicorp-terraform-website-local"
DOCKER_RUN_FLAGS=--interactive \
--rm \
--tty \
--workdir "/website" \
--volume "$(shell pwd):/website/ext/terraform" \
--volume "$(shell pwd)/website:/website/preview" \
--publish "3000:3000" \
-e "IS_CONTENT_PREVIEW=true" \
-e "PREVIEW_FROM_REPO=terraform" \
-e "NAV_DATA_DIRNAME=./preview/data" \
-e "CONTENT_DIRNAME=./preview/docs" \
-e "CURRENT_GIT_BRANCH=$$(git rev-parse --abbrev-ref HEAD)"
# generate runs `go generate` to build the dynamically generated
# source files, except the protobuf stubs which are built instead with
# "make protobuf".
@ -38,32 +20,40 @@ fmtcheck:
importscheck:
"$(CURDIR)/scripts/goimportscheck.sh"
vetcheck:
@echo "==> Checking that the code complies with go vet requirements"
@go vet ./...
staticcheck:
"$(CURDIR)/scripts/staticcheck.sh"
exhaustive:
"$(CURDIR)/scripts/exhaustive.sh"
# Default: run this if working on the website locally to run in watch mode.
copyright:
"$(CURDIR)/scripts/copyright.sh" --plan
copyrightfix:
"$(CURDIR)/scripts/copyright.sh"
syncdeps:
"$(CURDIR)/scripts/syncdeps.sh"
# Run this if working on the website locally to run in watch mode.
website:
@echo "==> Downloading latest Docker image..."
@docker pull ${DOCKER_IMAGE}
@echo "==> Starting website in Docker..."
@docker run ${DOCKER_RUN_FLAGS} ${DOCKER_IMAGE} npm start
$(MAKE) -C website website
# Use this if you have run `website/build-local` to use the locally built image.
website/local:
@echo "==> Starting website in Docker..."
@docker run ${DOCKER_RUN_FLAGS} ${DOCKER_IMAGE_LOCAL} npm start
$(MAKE) -C website website/local
.PHONY: website/build-local
# Run this to generate a new local Docker image.
website/build-local:
@echo "==> Building local Docker image"
@docker build https://github.com/hashicorp/terraform-website.git\#master \
-t $(DOCKER_IMAGE_LOCAL)
$(MAKE) -C website website/build-local
# disallow any parallelism (-j) for Make. This is necessary since some
# commands during the build process create temporary files that collide
# under parallel conditions.
.NOTPARALLEL:
.PHONY: fmtcheck importscheck generate protobuf website website-test staticcheck website/local website/build-local
.PHONY: fmtcheck importscheck vetcheck generate protobuf staticcheck syncdeps website website/local website/build-local

View file

@ -1,12 +1,12 @@
# Terraform
- Website: https://www.terraform.io
- Website: https://developer.hashicorp.com/terraform
- Forums: [HashiCorp Discuss](https://discuss.hashicorp.com/c/terraform-core)
- Documentation: [https://www.terraform.io/docs/](https://www.terraform.io/docs/)
- Tutorials: [HashiCorp's Learn Platform](https://learn.hashicorp.com/terraform)
- Documentation: [https://developer.hashicorp.com/terraform/docs](https://developer.hashicorp.com/terraform/docs)
- Tutorials: [HashiCorp's Learn Platform](https://developer.hashicorp.com/terraform/tutorials)
- Certification Exam: [HashiCorp Certified: Terraform Associate](https://www.hashicorp.com/certification/#hashicorp-certified-terraform-associate)
<img alt="Terraform" src="https://www.datocms-assets.com/2885/1629941242-logo-terraform-main.svg" width="600px">
<img alt="Terraform" src="https://www.datocms-assets.com/2885/1731373310-terraform_white.svg" width="600px">
Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.
@ -24,10 +24,10 @@ For more information, refer to the [What is Terraform?](https://www.terraform.io
## Getting Started & Documentation
Documentation is available on the [Terraform website](https://www.terraform.io):
Documentation is available on the [Terraform website](https://developer.hashicorp.com/terraform):
- [Introduction](https://www.terraform.io/intro)
- [Documentation](https://www.terraform.io/docs)
- [Introduction](https://developer.hashicorp.com/terraform/intro)
- [Documentation](https://developer.hashicorp.com/terraform/docs)
If you're new to Terraform and want to get started creating infrastructure, please check out our [Getting Started guides](https://learn.hashicorp.com/terraform#getting-started) on HashiCorp's learning platform. There are also [additional guides](https://learn.hashicorp.com/terraform#operations-and-development) to continue your learning.
@ -35,7 +35,7 @@ Show off your Terraform knowledge by passing a certification exam. Visit the [ce
## Developing Terraform
This repository contains only Terraform core, which includes the command line interface and the main graph engine. Providers are implemented as plugins, and Terraform can automatically download providers that are published on [the Terraform Registry](https://registry.terraform.io). HashiCorp develops some providers, and others are developed by other organizations. For more information, see [Extending Terraform](https://www.terraform.io/docs/extend/index.html).
This repository contains only Terraform core, which includes the command line interface and the main graph engine. Providers are implemented as plugins, and Terraform can automatically download providers that are published on [the Terraform Registry](https://registry.terraform.io). HashiCorp develops some providers, and others are developed by other organizations. For more information, refer to [Plugin development](https://developer.hashicorp.com/terraform/plugin).
- To learn more about compiling Terraform and contributing suggested changes, refer to [the contributing guide](.github/CONTRIBUTING.md).
@ -45,4 +45,4 @@ This repository contains only Terraform core, which includes the command line in
## License
[Mozilla Public License v2.0](https://github.com/hashicorp/terraform/blob/main/LICENSE)
[Business Source License 1.1](https://github.com/hashicorp/terraform/blob/main/LICENSE)

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
# This Dockerfile is not intended for general use, but is rather used to
# produce our "light" release packages as part of our official release
# pipeline.
@ -29,7 +32,22 @@ LABEL version=$PRODUCT_VERSION
# Historical Terraform-specific label preserved for backward compatibility.
LABEL "com.hashicorp.terraform.version"="${PRODUCT_VERSION}"
RUN apk add --no-cache git openssh
# @see https://specs.opencontainers.org/image-spec/annotations/?v=v1.0.1#pre-defined-annotation-keys
LABEL org.opencontainers.image.title=${BIN_NAME} \
org.opencontainers.image.description="Terraform enables you to safely and predictably create, change, and improve infrastructure" \
org.opencontainers.image.authors="HashiCorp Terraform Team <terraform@hashicorp.com>" \
org.opencontainers.image.url="https://www.terraform.io/" \
org.opencontainers.image.documentation="https://www.terraform.io/docs" \
org.opencontainers.image.source="https://github.com/hashicorp/terraform" \
org.opencontainers.image.version=${PRODUCT_VERSION} \
org.opencontainers.image.revision=${PRODUCT_REVISION} \
org.opencontainers.image.vendor="HashiCorp" \
org.opencontainers.image.licenses="BUSL-1.1"
RUN apk add --no-cache git openssh ca-certificates
# Copy the license file as per Legal requirement
COPY LICENSE "/usr/share/doc/${BIN_NAME}/LICENSE.txt"
# The hashicorp/actions-docker-build GitHub Action extracts the appropriate
# release package for our target architecture into the current working

17
catalog-info.yaml Normal file
View file

@ -0,0 +1,17 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
#
# Intended for internal HashiCorp use only
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: terraform
description: HashiCorp Terraform
annotations:
github.com/project-slug: hashicorp/terraform
jira/project-key: TF
jira/label: terraform
spec:
type: library
owner: team-tf-core
lifecycle: production

View file

@ -1,6 +1,10 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package main
import (
"context"
"fmt"
"log"
"path/filepath"
@ -8,6 +12,7 @@ import (
"github.com/hashicorp/go-checkpoint"
"github.com/hashicorp/terraform/internal/command"
"github.com/hashicorp/terraform/internal/command/cliconfig"
"go.opentelemetry.io/otel/codes"
)
func init() {
@ -18,7 +23,7 @@ var checkpointResult chan *checkpoint.CheckResponse
// runCheckpoint runs a HashiCorp Checkpoint request. You can read about
// Checkpoint here: https://github.com/hashicorp/go-checkpoint.
func runCheckpoint(c *cliconfig.Config) {
func runCheckpoint(ctx context.Context, c *cliconfig.Config) {
// If the user doesn't want checkpoint at all, then return.
if c.DisableCheckpoint {
log.Printf("[INFO] Checkpoint disabled. Not running.")
@ -26,6 +31,10 @@ func runCheckpoint(c *cliconfig.Config) {
return
}
ctx, span := tracer.Start(ctx, "HashiCorp Checkpoint")
_ = ctx // prevent staticcheck from complaining to avoid a maintenence hazard of having the wrong ctx in scope here
defer span.End()
configDir, err := cliconfig.ConfigDir()
if err != nil {
log.Printf("[ERR] Checkpoint setup error: %s", err)
@ -52,7 +61,10 @@ func runCheckpoint(c *cliconfig.Config) {
})
if err != nil {
log.Printf("[ERR] Checkpoint error: %s", err)
span.SetStatus(codes.Error, err.Error())
resp = nil
} else {
span.SetStatus(codes.Ok, "checkpoint request succeeded")
}
checkpointResult <- resp

View file

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
comment:
layout: "flags, files"
behavior: default

View file

@ -1,15 +1,19 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package main
import (
"context"
"os"
"os/signal"
"github.com/mitchellh/cli"
"github.com/hashicorp/cli"
"github.com/hashicorp/go-plugin"
svchost "github.com/hashicorp/terraform-svchost"
"github.com/hashicorp/terraform-svchost/auth"
"github.com/hashicorp/terraform-svchost/disco"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/command"
"github.com/hashicorp/terraform/internal/command/cliconfig"
@ -17,6 +21,7 @@ import (
"github.com/hashicorp/terraform/internal/command/webbrowser"
"github.com/hashicorp/terraform/internal/getproviders"
pluginDiscovery "github.com/hashicorp/terraform/internal/plugin/discovery"
"github.com/hashicorp/terraform/internal/rpcapi"
"github.com/hashicorp/terraform/internal/terminal"
)
@ -49,6 +54,7 @@ var HiddenCommands map[string]struct{}
var Ui cli.Ui
func initCommands(
ctx context.Context,
originalWorkingDir string,
streams *terminal.Streams,
config *cliconfig.Config,
@ -85,7 +91,7 @@ func initCommands(
View: views.NewView(streams).SetRunningInAutomation(inAutomation),
Color: true,
GlobalPluginDirs: globalPluginDirs(),
GlobalPluginDirs: cliconfig.GlobalPluginDirs(),
Ui: Ui,
Services: services,
@ -95,7 +101,10 @@ func initCommands(
CLIConfigDir: configDir,
PluginCacheDir: config.PluginCacheDir,
ShutdownCh: makeShutdownCh(),
PluginCacheMayBreakDependencyLockFile: config.PluginCacheMayBreakDependencyLockFile,
ShutdownCh: makeShutdownCh(),
CallerContext: ctx,
ProviderSource: providerSrc,
ProviderDevOverrides: providerDevOverrides,
@ -207,6 +216,24 @@ func initCommands(
}, nil
},
"metadata": func() (cli.Command, error) {
return &command.MetadataCommand{
Meta: meta,
}, nil
},
"metadata functions": func() (cli.Command, error) {
return &command.MetadataFunctionsCommand{
Meta: meta,
}, nil
},
"modules": func() (cli.Command, error) {
return &command.ModulesCommand{
Meta: meta,
}, nil
},
"output": func() (cli.Command, error) {
return &command.OutputCommand{
Meta: meta,
@ -351,6 +378,12 @@ func initCommands(
}, nil
},
"state identities": func() (cli.Command, error) {
return &command.StateIdentitiesCommand{
Meta: meta,
}, nil
},
"state rm": func() (cli.Command, error) {
return &command.StateRmCommand{
StateMeta: command.StateMeta{
@ -394,6 +427,25 @@ func initCommands(
},
}
if meta.AllowExperimentalFeatures {
Commands["cloud"] = func() (cli.Command, error) {
return &command.CloudCommand{
Meta: meta,
}, nil
}
// "rpcapi" is handled a bit differently because the whole point of
// this interface is to bypass the CLI layer so wrapping automation can
// get as-direct-as-possible access to Terraform Core functionality,
// without interference from behaviors that are intended for CLI
// end-user convenience. We bypass the "command" package entirely
// for this command in particular.
Commands["rpcapi"] = rpcapi.CLICommandFactory(rpcapi.CommandFactoryOpts{
ExperimentsAllowed: meta.AllowExperimentalFeatures,
ShutdownCh: meta.ShutdownCh,
})
}
PrimaryCommands = []string{
"init",
"validate",
@ -403,11 +455,11 @@ func initCommands(
}
HiddenCommands = map[string]struct{}{
"env": struct{}{},
"internal-plugin": struct{}{},
"push": struct{}{},
"env": {},
"internal-plugin": {},
"push": {},
"rpcapi": {},
}
}
// makeShutdownCh creates an interrupt listener and returns a channel.
@ -429,6 +481,6 @@ func makeShutdownCh() <-chan struct{} {
}
func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) {
helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs())
helperPlugins := pluginDiscovery.FindPlugins("credentials", cliconfig.GlobalPluginDirs())
return config.CredentialsSource(helperPlugins)
}

View file

@ -4,13 +4,18 @@ This directory contains some documentation about the Terraform Core codebase,
aimed at readers who are interested in making code contributions.
If you're looking for information on _using_ Terraform, please instead refer
to [the main Terraform CLI documentation](https://www.terraform.io/docs/cli/index.html).
to [the main Terraform CLI documentation](https://developer.hashicorp.com/terraform/cli).
## Terraform Core Architecture Documents
* [Terraform Core Architecture Summary](./architecture.md): an overview of the
main components of Terraform Core and how they interact. This is the best
starting point if you are diving in to this codebase for the first time.
* [Modules Runtime Architecture Summary](./architecture.md): an overview of the
main components of Terraform Core related to planning and applying modules.
This is the best starting point if you are diving in to this codebase for the
first time.
* [Stacks Runtime Architecture Summary](../internal/stacks/README.md): an
overview of the main components of Terraform Core related to planning and
applying stack configurations.
* [Resource Instance Change Lifecycle](./resource-instance-change-lifecycle.md):
a description of the steps in validating, planning, and applying a change
@ -21,7 +26,7 @@ to [the main Terraform CLI documentation](https://www.terraform.io/docs/cli/inde
SDK and so wish to conform to them.
(If you are planning to write a new provider using the _official_ SDK then
please refer to [the Extend documentation](https://www.terraform.io/docs/extend/index.html)
please refer to [the Plugin development documentation](https://developer.hashicorp.com/terraform/plugin)
instead; it presents similar information from the perspective of the SDK
API, rather than the plugin wire protocol.)
@ -31,11 +36,21 @@ to [the main Terraform CLI documentation](https://www.terraform.io/docs/cli/inde
This documentation is for SDK developers, and is not necessary reading for
those implementing a provider using the official SDK.
* [Terraform Core RPC API](../internal/rpcapi/README.md): an integration point
for external software that needs to integrate Terraform Core functionality.
* [Upgrading Terraform's Dependencies](./dependency-upgrades.md): guidance on
some special details that arise when we upgrade Go Module dependencies, due
to this codebase containing Terraform CLI, Terraform Core, and the various
remote state backends which all have some overlapping dependencies.
* [How Terraform Uses Unicode](./unicode.md): an overview of the various
features of Terraform that rely on Unicode and how to change those features
to adopt new versions of Unicode.
* [Deadlock-free Promises](../internal/promising/README.md): a utility package
used by the Terraform Stacks runtime to coordinate its concurrent work.
## Contribution Guides
* [Maintainer Etiquette](./maintainer-etiquette.md): guidelines and expectations
for those who serve as Pull Request reviewers, issue triagers, etc.
* [Contributing to Terraform](../.github/CONTRIBUTING.md): a complete guideline for those who want to contribute to this project.

View file

@ -8,6 +8,8 @@ We assume some familiarity with user-facing Terraform concepts like
configuration, state, CLI workflow, etc. The Terraform website has
documentation on these ideas.
**Links to Go documentation assume you are running [`pkgsite`](https://pkg.go.dev/golang.org/x/pkgsite/cmd/pkgsite) locally, with the default URL of localhost:8080.**
## Terraform Request Flow
The following diagram shows an approximation of how a user command is
@ -23,7 +25,7 @@ in more detail in a corresponding section below.
Each time a user runs the `terraform` program, aside from some initial
bootstrapping in the root package (not shown in the diagram) execution
transfers immediately into one of the "command" implementations in
[the `command` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/command).
[the `command` package](http://localhost:8080/github.com/hashicorp/terraform/internal/command).
The mapping between the user-facing command names and
their corresponding `command` package types can be found in the `commands.go`
file in the root of the repository.
@ -35,13 +37,13 @@ but it applies to the main Terraform workflow commands `terraform plan` and
For these commands, the role of the command implementation is to read and parse
any command line arguments, command line options, and environment variables
that are needed for the given command and use them to produce a
[`backend.Operation`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Operation)
[`backendrun.Operation`](http://localhost:8080/github.com/hashicorp/terraform/internal/backend/backendrun#Operation)
object that describes an action to be taken.
An _operation_ consists of:
* The action to be taken (e.g. "plan", "apply").
* The name of the [workspace](https://www.terraform.io/docs/state/workspaces.html)
* The name of the [workspace](https://developer.hashicorp.com/terraform/language/state/workspaces)
where the action will be taken.
* Root module input variables to use for the action.
* For the "plan" operation, a path to the directory containing the configuration's root module.
@ -50,25 +52,25 @@ An _operation_ consists of:
"force" flag, etc.
The operation is then passed to the currently-selected
[backend](https://www.terraform.io/docs/backends/index.html). Each backend name
[backend](https://developer.hashicorp.com/terraform/language/backend). Each backend name
corresponds to an implementation of
[`backend.Backend`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Backend), using a
[`backend.Backend`](http://localhost:8080/github.com/hashicorp/terraform/internal/backend#Backend), using a
mapping table in
[the `backend/init` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend/init).
[the `backend/init` package](http://localhost:8080/github.com/hashicorp/terraform/internal/backend/init).
Backends that are able to execute operations additionally implement
[`backend.Enhanced`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Enhanced);
[`backendrun.OperationsBackend`](http://localhost:8080/github.com/hashicorp/terraform/internal/backend/backendrun#OperationsBackend);
the command-handling code calls `Operation` with the operation it has
constructed, and then the backend is responsible for executing that action.
Backends that execute operations, however, do so as an architectural implementation detail and not a
general feature of backends. That is, the term 'backend' as a Terraform feature is used to refer to
a plugin that determines where Terraform stores its state snapshots - only the default `local`
backend and Terraform Cloud's backends (`remote`, `cloud`) perform operations.
backend and HCP Terraform's backends (`remote`, `cloud`) perform operations.
Thus, most backends do _not_ implement this interface, and so the `command` package wraps these
backends in an instance of
[`local.Local`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend/local#Local),
[`local.Local`](http://localhost:8080/github.com/hashicorp/terraform/internal/backend/local#Local),
causing the operation to be executed locally within the `terraform` process itself.
## Backends
@ -78,19 +80,19 @@ A _backend_ determines where Terraform should store its state snapshots.
As described above, the `local` backend also executes operations on behalf of most other
backends. It uses a _state manager_
(either
[`statemgr.Filesystem`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) if the
[`statemgr.Filesystem`](http://localhost:8080/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) if the
local backend is being used directly, or an implementation provided by whatever
backend is being wrapped) to retrieve the current state for the workspace
specified in the operation, then uses the _config loader_ to load and do
initial processing/validation of the configuration specified in the
operation. It then uses these, along with the other settings given in the
operation, to construct a
[`terraform.Context`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context),
[`terraform.Context`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#Context),
which is the main object that actually performs Terraform operations.
The `local` backend finally calls an appropriate method on that context to
begin execution of the relevant command, such as
[`Plan`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context.Plan)
[`Plan`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#Context.Plan)
or
[`Apply`](), which in turn constructs a graph using a _graph builder_,
described in a later section.
@ -98,21 +100,21 @@ described in a later section.
## Configuration Loader
The top-level configuration structure is represented by model types in
[package `configs`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs).
A whole configuration (the root module plus all of its descendent modules)
[package `configs`](http://localhost:8080/github.com/hashicorp/terraform/internal/configs).
A whole configuration (the root module plus all of its descendant modules)
is represented by
[`configs.Config`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs#Config).
[`configs.Config`](http://localhost:8080/github.com/hashicorp/terraform/internal/configs#Config).
The `configs` package contains some low-level functionality for constructing
configuration objects, but the main entry point is in the sub-package
[`configload`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs/configload]),
[`configload`](http://localhost:8080/github.com/hashicorp/terraform/internal/configs/configload),
via
[`configload.Loader`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs/configload#Loader).
[`configload.Loader`](http://localhost:8080/github.com/hashicorp/terraform/internal/configs/configload#Loader).
A loader deals with all of the details of installing child modules
(during `terraform init`) and then locating those modules again when a
configuration is loaded by a backend. It takes the path to a root module
and recursively loads all of the child modules to produce a single
[`configs.Config`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs#Config)
[`configs.Config`](http://localhost:8080/github.com/hashicorp/terraform/internal/configs#Config)
representing the entire configuration.
Terraform expects configuration files written in the Terraform language, which
@ -121,37 +123,37 @@ is a DSL built on top of
cannot be interpreted until we build and walk the graph, since they depend
on the outcome of other parts of the configuration, and so these parts of
the configuration remain represented as the low-level HCL types
[`hcl.Body`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Body)
[`hcl.Body`](http://localhost:8080/github.com/hashicorp/hcl/v2/#Body)
and
[`hcl.Expression`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression),
[`hcl.Expression`](http://localhost:8080/github.com/hashicorp/hcl/v2/#Expression),
allowing Terraform to interpret them at a more appropriate time.
## State Manager
A _state manager_ is responsible for storing and retrieving snapshots of the
[Terraform state](https://www.terraform.io/docs/language/state/index.html)
[Terraform state](https://developer.hashicorp.com/terraform/language/state)
for a particular workspace. Each manager is an implementation of
some combination of interfaces in
[the `statemgr` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr),
[the `statemgr` package](http://localhost:8080/github.com/hashicorp/terraform/internal/states/statemgr),
with most practical managers implementing the full set of operations
described by
[`statemgr.Full`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Full)
[`statemgr.Full`](http://localhost:8080/github.com/hashicorp/terraform/internal/states/statemgr#Full)
provided by a _backend_. The smaller interfaces exist primarily for use in
other function signatures to be explicit about what actions the function might
take on the state manager; there is little reason to write a state manager
that does not implement all of `statemgr.Full`.
The implementation
[`statemgr.Filesystem`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) is used
[`statemgr.Filesystem`](http://localhost:8080/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) is used
by default (by the `local` backend) and is responsible for the familiar
`terraform.tfstate` local file that most Terraform users start with, before
they switch to [remote state](https://www.terraform.io/docs/language/state/remote.html).
they switch to [remote state](https://developer.hashicorp.com/terraform/language/state/remote).
Other implementations of `statemgr.Full` are used to implement remote state.
Each of these saves and retrieves state via a remote network service
appropriate to the backend that creates it.
A state manager accepts and returns a state snapshot as a
[`states.State`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states#State)
[`states.State`](http://localhost:8080/github.com/hashicorp/terraform/internal/states#State)
object. The state manager is responsible for exactly how that object is
serialized and stored, but all state managers at the time of writing use
the same JSON serialization format, storing the resulting JSON bytes in some
@ -160,7 +162,7 @@ kind of arbitrary blob store.
## Graph Builder
A _graph builder_ is called by a
[`terraform.Context`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context)
[`terraform.Context`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#Context)
method (e.g. `Plan` or `Apply`) to produce the graph that will be used
to represent the necessary steps for that operation and the dependency
relationships between them.
@ -170,7 +172,7 @@ In most cases, the
graphs each represent a specific object in the configuration, or something
derived from those configuration objects. For example, each `resource` block
in the configuration has one corresponding
[`GraphNodeConfigResource`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeConfigResource)
[`GraphNodeConfigResource`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#GraphNodeConfigResource)
vertex representing it in the "plan" graph. (Terraform Core uses terminology
inconsistently, describing graph _vertices_ also as graph _nodes_ in various
places. These both describe the same concept.)
@ -187,26 +189,26 @@ graph from the set of changes described in the plan that is being applied.
The graph builders all work in terms of a sequence of _transforms_, which
are implementations of
[`terraform.GraphTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphTransformer).
[`terraform.GraphTransformer`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#GraphTransformer).
Implementations of this interface just take a graph and mutate it in any
way needed, and so the set of available transforms is quite varied. Some
important examples include:
* [`ConfigTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ConfigTransformer),
* [`ConfigTransformer`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#ConfigTransformer),
which creates a graph vertex for each `resource` block in the configuration.
* [`StateTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#StateTransformer),
* [`StateTransformer`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#StateTransformer),
which creates a graph vertex for each resource instance currently tracked
in the state.
* [`ReferenceTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ReferenceTransformer),
* [`ReferenceTransformer`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#ReferenceTransformer),
which analyses the configuration to find dependencies between resources and
other objects and creates any necessary "happens after" edges for these.
* [`ProviderTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ProviderTransformer),
* [`ProviderTransformer`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#ProviderTransformer),
which associates each resource or resource instance with exactly one
provider configuration (implementing
[the inheritance rules](https://www.terraform.io/docs/language/modules/develop/providers.html))
[the inheritance rules](https://developer.hashicorp.com/terraform/language/modules/develop/providers))
and then creates "happens after" edges to ensure that the providers are
initialized before taking any actions with the resources that belong to
them.
@ -217,7 +219,7 @@ builder uses a different subset of these depending on the needs of the
operation that is being performed.
The result of graph building is a
[`terraform.Graph`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Graph), which
[`terraform.Graph`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#Graph), which
can then be processed using a _graph walker_.
## Graph Walk
@ -225,17 +227,17 @@ can then be processed using a _graph walker_.
The process of walking the graph visits each vertex of that graph in a way
which respects the "happens after" edges in the graph. The walk algorithm
itself is implemented in
[the low-level `dag` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk)
[the low-level `dag` package](http://localhost:8080/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk)
(where "DAG" is short for [_Directed Acyclic Graph_](https://en.wikipedia.org/wiki/Directed_acyclic_graph)), in
[`AcyclicGraph.Walk`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk).
[`AcyclicGraph.Walk`](http://localhost:8080/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk).
However, the "interesting" Terraform walk functionality is implemented in
[`terraform.ContextGraphWalker`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ContextGraphWalker),
[`terraform.ContextGraphWalker`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#ContextGraphWalker),
which implements a small set of higher-level operations that are performed
during the graph walk:
* `EnterPath` is called once for each module in the configuration, taking a
module address and returning a
[`terraform.EvalContext`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#EvalContext)
[`terraform.EvalContext`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#EvalContext)
that tracks objects within that module. `terraform.Context` is the _global_
context for the entire operation, while `terraform.EvalContext` is a
context for processing within a single module, and is the primary means
@ -247,7 +249,7 @@ will evaluate multiple vertices concurrently. Vertex evaluation code must
therefore make careful use of concurrency primitives such as mutexes in order
to coordinate access to shared objects such as the `states.State` object.
In most cases, we use the helper wrapper
[`states.SyncState`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states#SyncState)
[`states.SyncState`](http://localhost:8080/github.com/hashicorp/terraform/internal/states#SyncState)
to safely implement concurrent reads and writes from the shared state.
## Vertex Evaluation
@ -280,27 +282,27 @@ a plan operation would include the following high-level steps:
this operation.
Each execution step for a vertex is an implementation of
[`terraform.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/erraform#Execute).
[`terraform.GraphNodeExecutable.Execute`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#GraphNodeExecutable.Execute).
As with graph transforms, the behavior of these implementations varies widely:
whereas graph transforms can take any action against the graph, an `Execute`
implementation can take any action against the `EvalContext`.
The implementation of `terraform.EvalContext` used in real processing
(as opposed to testing) is
[`terraform.BuiltinEvalContext`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#BuiltinEvalContext).
[`terraform.BuiltinEvalContext`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#BuiltinEvalContext).
It provides coordinated access to plugins, the current state, and the current
plan via the `EvalContext` interface methods.
In order to be executed, a vertex must implement
[`terraform.GraphNodeExecutable`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeExecutable),
[`terraform.GraphNodeExecutable`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#GraphNodeExecutable),
which has a single `Execute` method that handles. There are numerous `Execute`
implementations with different behaviors, but some prominent examples are:
* [NodePlannableResource.Execute](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#NodePlannableResourceInstance.Execute), which handles the `plan` operation.
* [`NodePlannableResource.Execute`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#NodePlannableResourceInstance.Execute), which handles the `plan` operation.
* [`NodeApplyableResourceInstance.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#NodeApplyableResourceInstance.Execute), which handles the main `apply` operation.
* [`NodeApplyableResourceInstance.Execute`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#NodeApplyableResourceInstance.Execute), which handles the main `apply` operation.
* [`NodeDestroyResourceInstance.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#EvalWriteState), which handles the main `destroy` operation.
* [`NodeDestroyResourceInstance.Execute`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#EvalWriteState), which handles the main `destroy` operation.
A vertex must complete successfully before the graph walk will begin evaluation
for other vertices that have "happens after" edges. Evaluation can fail with one
@ -320,11 +322,11 @@ The high-level process for expression evaluation is:
to. For example, the expression `aws_instance.example[1]` refers to one of
the instances created by a `resource "aws_instance" "example"` block in
configuration. This analysis is performed by
[`lang.References`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#References),
[`lang.References`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#References),
or more often one of the helper wrappers around it:
[`lang.ReferencesInBlock`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#ReferencesInBlock)
[`lang.ReferencesInBlock`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#ReferencesInBlock)
or
[`lang.ReferencesInExpr`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#ReferencesInExpr)
[`lang.ReferencesInExpr`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#ReferencesInExpr)
1. Retrieve from the state the data for the objects that are referred to and
create a lookup table of the values from these objects that the
@ -334,18 +336,18 @@ The high-level process for expression evaluation is:
them.
1. Ask HCL to evaluate each attribute's expression (a
[`hcl.Expression`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression)
[`hcl.Expression`](http://localhost:8080/github.com/hashicorp/hcl/v2/#Expression)
object) against the data and function lookup tables.
In practice, steps 2 through 4 are usually run all together using one
of the methods on [`lang.Scope`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope);
of the methods on [`lang.Scope`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#Scope);
most commonly,
[`lang.EvalBlock`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope.EvalBlock)
[`lang.EvalBlock`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#Scope.EvalBlock)
or
[`lang.EvalExpr`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope.EvalExpr).
[`lang.EvalExpr`](http://localhost:8080/github.com/hashicorp/terraform/internal/lang#Scope.EvalExpr).
Expression evaluation produces a dynamic value represented as a
[`cty.Value`](https://pkg.go.dev/github.com/zclconf/go-cty/cty#Value).
[`cty.Value`](http://localhost:8080/github.com/zclconf/go-cty/cty#Value).
This Go type represents values from the Terraform language and such values
are eventually passed to provider plugins.
@ -367,7 +369,7 @@ known when the main graph is constructed, but become known while evaluating
other vertices in the main graph.
This special behavior applies to vertex objects that implement
[`terraform.GraphNodeDynamicExpandable`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeDynamicExpandable).
[`terraform.GraphNodeDynamicExpandable`](http://localhost:8080/github.com/hashicorp/terraform/internal/terraform#GraphNodeDynamicExpandable).
Such vertices have their own nested _graph builder_, _graph walk_,
and _vertex evaluation_ steps, with the same behaviors as described in these
sections for the main graph. The difference is in which graph transforms

View file

@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
// Highlight a test's name with your cursor and run this debugger configuration
// from the debugger tools in the left-side Activity Bar.
// This will result in the equivalent of this command being run using the debugger:
// `go test -v -run ^<selected text>$ <the current opened file's folder path>`
"name": "Run selected test",
"request": "launch",
"type": "go",
"args": [
"-test.v",
"-test.run",
"^${selectedText}$"
],
// Environment variables can be set from a file or as key-value pairs in the configuration.
// "env": {
// "MY_ENV": "my-value",
// },
// "envFile": "./vscode/private.env",
"mode": "auto",
"program": "${fileDirname}",
"showLog": true // dlv's logs
}
]
}

View file

@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
// Runs Terraform using the Terraform configuration specified via the chdir argument
"name": "Run Terraform in debug mode",
"request": "launch",
"type": "go",
"args": [
"-chdir=<absolute path to a Terraform configuration>",
// Change this array to perform different terraform commands with different arguments.
"plan",
"-var='name=value'"
],
// "cwd": "<absolute path to a Terraform configuration>", // An alternative to using the -chdir global flag above.
// Environment variables can be set from a file or as key-value pairs in the configuration.
// "env": {
// "MY_ENV": "my-value",
// },
// "envFile": "./vscode/private.env",
"mode": "debug",
"program": "${workspaceFolder}",
"console": "integratedTerminal", // allows responding to y/n in terminal, e.g. in apply command.
"showLog": false // dlv's logs
}
]
}

View file

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Connect to dlv server",
"type": "go",
"debugAdapter": "dlv-dap",
"request": "attach",
"mode": "remote",
"remotePath": "${workspaceFolder}",
"port": 2345,
"host": "127.0.0.1",
}
]
}

97
docs/debugging.md Normal file
View file

@ -0,0 +1,97 @@
# How to Debug Terraform
Contents:
- [Debugging automated tests](#debugging-automated-tests)
- [Debugging automated tests in VSCode](#debugging-automated-tests-in-vscode)
- [Debugging Terraform operations that use real Terraform configurations](#debugging-terraform-operations-that-use-real-terraform-configurations)
- [Launch Terraform with the `dlv` CLI tool](#launch-terraform-with-the-dlv-cli-tool)
- [Launch Terraform with VS Code's debugging tool](#launch-terraform-with-vs-codes-debugging-tool)
As Terraform is written in Go you may use [Delve](https://github.com/go-delve/delve) to debug it.
GoLand includes [debugging features](https://www.jetbrains.com/help/go/debugging-code.html), and the [Go extension for VS Code](https://code.visualstudio.com/docs/languages/go#_debugging) makes it easy to use Delve when debugging Go codebases in VS Code.
## Debugging automated tests
Debugging an automated test is often the most straightforward workflow for debugging a section of the codebase. For example, the Go extension for VS Code](https://code.visualstudio.com/docs/languages/go#_debugging) adds `run test | debug test` options above all tests in a `*_test.go` file. These allow debugging without any prior configuration.
### Debugging automated tests in VSCode
As described above, debugging tests in VS Code is easily achieved through the Go extension.
If you need more control over how tests are run while debugging, e.g. environment variable values, look at the [example debugger launch configuration 'Run selected test'](./debugging-configs/vscode/debug-automated-tests/launch.json). You can adapt this example to create your own [launch configuration file](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations).
When using this launch configuration you must highlight a test's name before starting the debugger:
<p align="center">
<img width="75%" alt="Debugging a single test using the example 'Run selected test' debugger configuration shared in this repository" src="./images/vscode-debugging-test.png"/>
</p>
## Debugging Terraform operations that use real Terraform configurations
### Launch Terraform with the `dlv` CLI tool
In this workflow you:
* Build Terraform using compiler flags.
* Start a debug server with a command containing the terraform command you want to debug.
* This command is run in the working directory that contains your Terraform configuration.
* Connect to the debug server to monitor progress through breakpoints.
#### 1. Compile & Start Debug Server
One way to do it is to compile a binary with the [appropriate compiler flags](https://pkg.go.dev/cmd/compile#hdr-Command_Line):
```sh
go install -gcflags="all=-N -l"
```
This enables you to then execute the compiled binary via Delve, pass any arguments and spin up a debug server which you can then connect to:
```sh
# Update the path to the terraform binary if your install directory is influenced by $GOPATH or $GOBIN
dlv exec $HOME/go/bin/terraform --headless --listen :2345 --log -- apply
```
#### 2a. Connect via CLI
You may connect to the headless debug server via Delve CLI
```sh
dlv connect :2345
```
#### 2b. Connect from VS Code
The repository provides [an example 'Connect to dlv server' launch configuration](./debugging-configs/vscode/launch-via-cli/launch.json), making it possible to use VS Code's native debugging integration via the [Go extension for VS Code](https://code.visualstudio.com/docs/languages/go#_debugging):
<p align="center">
<img width="75%" alt="vscode debugger" src="./images/vscode-debugging.png"/>
</p>
### Launch Terraform with VS Code's debugging tool
In this workflow you:
* Update the debugger's launch configuration to point at the directory containing your Terraform configuration.
* Start the debugger through VS Code and monitor progress through breakpoints.
#### 1. Update the debugger's launch configuration
Look at the [example debugger launch configuration 'Run Terraform in debug mode'](./debugging-configs/vscode/launch-from-vscode-debugger/launch.json). You can adapt this example to create your own [launch configuration file](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations).
To use this launch configuration:
* Prepare a local Terraform project.
* Get the absolute path to that directory.
* Update the launch configuration to use that path, either in the `-chdir` argument or as a `cwd` attribute in the launch configuration.
* Make sure the `args` array's element reflect the command you'd like to debug.
* Provide any required environment variables through the `env` or `envFile` attributes.
#### 2. Run the launch configuration in VS Code
Navigate to the Run and Debug view in the left-side Activity Bar. After selecting the `Run Terraform in debug mode` configuration in the Run and Debug view from the left-side, press the green arrow.
This is equivalent to running a Terraform CLI command in the local Terraform project's directory. For example, if you run and debug a plan command that saves a plan file, that plan file will be created.
This workflow is useful if you need to set up a complicated prior state to replicate a bug or if you want to debug code behaviour given a specific configuration.

153
docs/dependency-upgrades.md Normal file
View file

@ -0,0 +1,153 @@
# Upgrading Terraform's Library Dependencies
This codebase depends on a variety of external Go modules. At the time of
writing, a Terraform CLI build includes the union of all dependencies required
by Terraform CLI and Core itself and each of the remote state backends.
Because the remote state backends have quite a different set of needs than
Terraform itself -- special client libraries, in particular -- we've declared
them as being separate Go Modules with their own `go.mod` and `go.sum` files,
even though we don't intend to ever publish them separately. The goal is just
to help track which dependencies are used by each of these components, and to
more easily determine which of the components are affected by a particular
dependency upgrade so that we can make sure to do the appropriate testing.
## Dependency Synchronization
Because all of these components ultimately link into the same executable, there
can be only one version of each distinct module and thus all of the modules
must agree on which version to use.
The makefile target `syncdeps` runs a script which synchronizes all of the
modules to declare compatible dependencies, selecting the newest version of
each external module selected across all of the internal modules:
```shell
make syncdeps
```
After running this, use `git status` to see what's been changed. If you've
changed the dependencies of any of the modules then that should typically
cause an update to the root module, because that one imports all of the others.
## Upgrading a Dependency
To select a newer version of one of the dependencies, use `go get` in the
root to specify which version to use:
```shell
go get example.com/foo/bar@v1.0.0
```
Or, if you just want to move to the latest stable release, you can use the
`latest` pseudo-version:
```shell
go get example.com/foo/bar@latest
```
Then run `make syncdeps` to update any of the child modules that also use
this dependency. The remote state backends use only a subset of the packages
in Terraform CLI/Core, so not all dependency updates will affect the remote
state backends, and an update might affect only a subset of the backends.
When you open the pull request for your change, our code owners rules will
automatically request review from the team that maintains any affected remote
state backend. The affected teams can judge whether the update seems likely
to affect their backend and run their acceptance tests if so, before approving
the pull request. As usual, these PRs should also be reviewed by at least
one member of the Terraform Core team since they are ultimately responsible
for the complete set of dependencies used in Terraform CLI releases.
**Note:** Currently our code owners rules are simplistic and will request
review for _any_ change under a remote state backend module directory, but
in practice an update that only changes a backend's `go.sum` cannot affect
the runtime behavior of the backend, and so those review requests are not
strictly required. You should therefore remove the review requests for
any backend whose only diff is the `go.sum` file once you've opened the
pull request.
## Dependabot Updates
When Dependabot automatically opens a pull request to upgrade a dependency,
unfortunately it isn't smart enough to automatically synchronize the change
across the modules and so the code consistency checks for the change will
typically fail.
To apply the proposed change, you'll need to check out the branch that
Dependabot created on your development system, run `make syncdeps`, add
all of the files that get modified, and then amend Dependabot's commit using
`git commit --amend`.
After you've done this, use `git push --force` to replace Dependabot's original
commit with your new commit, and then wait for GitHub to re-run the PR
checks. The code consistency checks should now pass.
We've configured Dependabot to monitor only the root `go.mod` file for potential
upgrades, because that one aggregates the dependencies for all other child
modules. Therefore there should never be a Dependabot upgrade targeting a
module in a subdirectory. If one _does_ get created somehow, you should close
it and perform the same upgrade at the root of the repository instead, using
the instructions in [Upgrading a Dependency](#upgrading-a-dependency) above.
## Dependencies with Special Requirements
Most of our dependencies can be treated generically, but a few have some
special constraints due to how Terraform uses them:
* HCL, cty, and their indirect dependencies `golang.org/x/text` and
`github.com/apparentlymart/go-textseg` all include logic based on Unicode
specifications, and so should be updated with care to make sure that
Terraform's support for Unicode follows a consistent Unicode version
throughout.
Additionally, each time we adopt a new minor release of Go, we may need to
upgrade some or all of these dependencies to match the Unicode version used
by the Go standard library.
For more information, refer to [How Terraform Uses Unicode](unicode.md).
(This concern does not apply if the new version we're upgrading to is built
for the same version of Unicode that Terraform was already using.)
* `github.com/hashicorp/go-getter` represents a significant part of Terraform
CLI's remote module installer, and is the final interpreter of Terraform's
module source address syntax. Because the module source address syntax is
protected by the Terraform v1.x Compatibility Promises, for each upgrade
we must make sure that:
- The upgrade doesn't expand the source address syntax in a way that is
undesirable from a Terraform product standpoint or in a way that we would
not feel comfortable supporting indefinitely under the compatibility
promises.
- The upgrade doesn't break any already-supported source address forms
that would therefore cause the next Terraform version to break the
v1.x compatibility promises.
Terraform's use of `go-getter` is all encapsulated in `internal/getmodules`
and is set up to try to minimize the possibility that a go-getter upgrade
would immediately introduce new functionality, but that encapsulation cannot
prevent adoption of changes made to pre-existing functionality that
Terraform already exposes.
* `github.com/hashicorp/go-tfe` -- the client library for the HCP Terraform
API -- includes various types corresponding to HCP Terraform API
requests and responses. The internal package `internal/cloud` contains mock
implementations of some of those types, which may need to be updated when
the client library is upgraded.
These upgrades should typically be done only in conjunction with a project
that will somehow use the new features through the Cloud integration, so
that the team working on that project can perform any needed updates to
the mocks as part of their work.
* `go.opentelemetry.io/otel` and the other supporting OpenTelemetry modules
should typically be upgraded together in lockstep, because some of the
modules define interfaces that other modules implement, and strange behavior
can emerge if one is upgraded without the other.
The main modules affected by this rule are the ones under the
`go.opentelemetry.io/otel` prefix. The "contrib" packages can be trickier
to upgrade because they tend to have dependencies that overlap with ours
and so might affect non-telemetry-related behavior, and so it's acceptable
for those to lag slightly behind to reduce risk in routine upgrades.

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

View file

@ -1,95 +0,0 @@
# Maintainer's Etiquette
Are you a core maintainer of Terraform? Great! Here's a few notes
to help you get comfortable when working on the project.
This documentation is somewhat outdated since it still includes provider-related
information even though providers are now developed in their own separate
codebases, but the general information is still valid.
## Expectations
We value the time you spend on the project and as such your maintainer status
doesn't imply any obligations to do any specific work.
### Your PRs
These apply to all contributors, but maintainers should lead by examples! :wink:
- for `provider/*` PRs it's useful to attach test results & advise on how to run the relevant tests
- for `bug` fixes it's useful to attach repro case, ideally in a form of a test
### PRs/issues from others
- you're welcomed to triage (attach labels to) other PRs and issues
- we generally use 2-label system (= at least 2 labels per issue/PR) where one label is generic and other one API-specific, e.g. `enhancement` & `provider/aws`
## Merging
- you're free to review PRs from the community or other HC employees and give :+1: / :-1:
- if the PR submitter has push privileges (recognizable via `Collaborator`, `Member` or `Owner` badge) - we expect **the submitter** to merge their own PR after receiving a positive review from either HC employee or another maintainer. _Exceptions apply - see below._
- we prefer to use the GitHub's interface or API to do this, just click the green button
- squash?
- squash when you think the commit history is irrelevant (will not be helpful for any readers in T+6months)
- Add the new PR to the **Changelog** if it may affect the user (almost any PR except test changes and docs updates)
- we prefer to use the GitHub's web interface to modify the Changelog and use `[GH-12345]` to format the PR number. These will be turned into links as part of the release process. Breaking changes should be always documented separately.
## Release process
- HC employees are responsible for cutting new releases
- The employee cutting the release will always notify all maintainers via Slack channel before & after each release
so you can avoid merging PRs during the release process.
## Exceptions
Any PR that is significantly changing or even breaking user experience cross-providers should always get at least one :+1: from a HC employee prior to merge.
It is generally advisable to leave PRs labelled as `core` for HC employees to review and merge.
Examples include:
- adding/changing/removing a CLI (sub)command or a [flag](https://github.com/hashicorp/terraform/pull/12939)
- introduce a new feature like [Environments](https://github.com/hashicorp/terraform/pull/12182) or [Shadow Graph](https://github.com/hashicorp/terraform/pull/9334)
- changing config (HCL) like [adding support for lists](https://github.com/hashicorp/terraform/pull/6322)
- change of the [build process or test environment](https://github.com/hashicorp/terraform/pull/9355)
## Breaking Changes
- we always try to avoid breaking changes where possible and/or defer them to the nearest major release
- [state migration](https://github.com/hashicorp/terraform/blob/2fe5976aec290f4b53f07534f4cde13f6d877a3f/helper/schema/resource.go#L33-L56) may help you avoid breaking changes, see [example](https://github.com/hashicorp/terraform/blob/351c6bed79abbb40e461d3f7d49fe4cf20bced41/builtin/providers/aws/resource_aws_route53_record_migrate.go)
- either way BCs should be clearly documented in special section of the Changelog
- Any BC must always receive at least one :+1: from HC employee prior to merge, two :+1:s are advisable
### Examples of Breaking Changes
- https://github.com/hashicorp/terraform/pull/12396
- https://github.com/hashicorp/terraform/pull/13872
- https://github.com/hashicorp/terraform/pull/13752
## Unsure?
If you're unsure about anything, ask in the committer's Slack channel.
## New Providers
These will require :+1: and some extra effort from HC employee.
We expect all acceptance tests to be as self-sustainable as possible
to keep the bar for running any acceptance test low for anyone
outside of HashiCorp or core maintainers team.
We expect any test to run **in parallel** alongside any other test (even the same test).
To ensure this is possible, we need all tests to avoid sharing namespaces or using static unique names.
In rare occasions this may require the use of mutexes in the resource code.
### New Remote-API-based provider (e.g. AWS, Google Cloud, PagerDuty, Atlas)
We will need some details about who to contact or where to register for a new account
and generally we can't merge providers before ensuring we have a way to test them nightly,
which usually involves setting up a new account and obtaining API credentials.
### Local provider (e.g. MySQL, PostgreSQL, Kubernetes, Vault)
We will need either Terraform configs that will set up the underlying test infrastructure
(e.g. GKE cluster for Kubernetes) or Dockerfile(s) that will prepare test environment (e.g. MySQL)
and expose the endpoint for testing.

View file

@ -20,7 +20,7 @@ their behaviors in a way comparable to the resource instance behaviors.
This is developer-oriented documentation rather than user-oriented
documentation. See
[the main Terraform documentation](https://www.terraform.io/docs) for
[the main Terraform documentation](https://developer.hashicorp.com/terraform/docs) for
information on existing planning behaviors and other behaviors as viewed from
an end-user perspective.

View file

@ -0,0 +1,6 @@
schema_version = 1
project {
license = "MPL-2.0"
copyright_year = 2024
}

View file

@ -0,0 +1,355 @@
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
1. Definitions
1.1. “Contributor”
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. “Contributor Version”
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributors Contribution.
1.3. “Contribution”
means Covered Software of a particular Contributor.
1.4. “Covered Software”
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. “Incompatible With Secondary Licenses”
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.
1.6. “Executable Form”
means any form of the work other than Source Code Form.
1.7. “Larger Work”
means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.
1.8. “License”
means this document.
1.9. “Licensable”
means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.
1.10. “Modifications”
means any of the following:
a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. “Patent Claims” of a Contributor
means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.
1.12. “Secondary License”
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. “Source Code Form”
means the form of the work preferred for making modifications.
1.14. “You” (or “Your”)
means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, “control” means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third partys
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.
This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients
rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an “as is” basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
partys negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a partys ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - “Incompatible With Secondary Licenses” Notice
This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.

View file

@ -10,7 +10,7 @@ the SDK's API.
----
**If you want to write a plugin for Terraform, please refer to
[Extending Terraform](https://www.terraform.io/docs/extend/index.html) instead.**
[Plugin development](https://developer.hashicorp.com/terraform/plugin) instead.**
This documentation is for those who are developing _Terraform SDKs_, rather
than those implementing plugins.
@ -56,8 +56,7 @@ do not follow this strategy.
The authoritative definition for each protocol version is in this directory
as a Protocol Buffers (protobuf) service definition. The files follow the
naming pattern `tfpluginX.Y.proto`, where X is the major version and Y
is the minor version.
naming pattern `tfpluginX.proto`, where X is the major version.
### Major and minor versioning
@ -211,3 +210,22 @@ new file in this directory for each new minor version and consider all
previously-tagged definitions as immutable. The outdated comments in those
files are retained in order to keep the promise of immutability, even though
it is now incorrect.
## Updating the plugin protocol in Terraform core
> Note: This section's audience is contributors to Terraform, not developers creating a new SDK.
New features added to Terraform core often require an update to the plugin protocol. These changes are reflected in a new minor version of the plugin protocol.
A new minor release of Terraform should only introduce one new minor release of the plugin-protocol. The minor release numbers of the plugin protocol and Terraform do not match, but they should have a one-to-one relationship.
### Add updates to a new plugin protocol minor version
1) Edit the `.proto` files for Protocol 5 and 6 in `docs/plugin-protocol/`.
* If this is the first bigger change after a Terraform release, you may want to increase the minor protocol version in the file header
1) Commit your changes.
1) Run `make protobuf`.
* This will use the symlinks in the `internal/tfplugin*` directories to access the latest minor versions' `.proto` files.
* You should see diffs in `internal/tfplugin5/tfplugin5.pb.go` and `internal/tfplugin6/tfplugin6.pb.go`.
1) Run `make generate`.
* You should see diffs in `internal/plugin/mock_proto/mock.go` and `internal/plugin6/mock_proto/mock.go`.

View file

@ -63,7 +63,7 @@ The key-value pairs representing nested block types have values based on
The MessagePack serialization of an attribute value depends on the value of the
`type` field of the corresponding `Schema.Attribute` message. The `type` field is
a compact JSON serialization of a
[Terraform type constraint](https://www.terraform.io/docs/configuration/types.html),
[Terraform type constraint](https://developer.hashicorp.com/terraform/language/expressions/type-constraints),
which consists either of a single
string value (for primitive types) or a two-element array giving a type kind
and a type argument.
@ -76,8 +76,7 @@ in the table below, regardless of type:
* An unknown value (that is, a placeholder for a value that will be decided
only during the apply operation) is represented as a
[MessagePack extension](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types)
value whose type identifier is zero and whose value is unspecified and
meaningless.
value, described in more detail below.
| `type` Pattern | MessagePack Representation |
|---|---|
@ -91,6 +90,64 @@ in the table below, regardless of type:
| `["tuple",TYPES]` | A MessagePack array with one element per element described by the `TYPES` array. The element values are constructed by applying these same mapping rules to the corresponding element of `TYPES`. |
| `"dynamic"` | A MessagePack array with exactly two elements. The first element is a MessagePack binary value containing a JSON-serialized type constraint in the same format described in this table. The second element is the result of applying these same mapping rules to the value with the type given in the first element. This special type constraint represents values whose types will be decided only at runtime. |
Unknown values have two possible representations, both using
[MessagePack extension](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types)
values.
The older encoding is for unrefined unknown values and uses an extension
code of zero, with the extension value payload completely ignored.
Newer Terraform versions can produce "refined" unknown values which carry some
additional information that constrains the possible range of the final value/
Refined unknown values have extension code 12 and then the extension object's
payload is a MessagePack-encoded map using integer keys to represent different
kinds of refinement:
* `1` represents "nullness", and the value of that key will be a boolean
value that is true if the value is definitely null or false if it is
definitely not null. If this key isn't present at all then the value may or
may not be null. It's not actually useful to encode that an unknown value
is null; use a known null value instead in that case, because there is only
one null value of each type.
* `2` represents string prefix, and the value is a string that the final
value is known to begin with. This is valid only for unknown values of string
type.
* `3` and `4` represent the lower and upper bounds respectively of a number
value, and the value of both is a two-element msgpack array whose
first element is a valid encoding of a number (as in the table above)
and whose second element is a boolean value that is true for an inclusive
bound and false for an exclusive bound. This is valid only for unknown values
of number type.
* `5` and `6` represent the lower and upper bounds respectively of the length
of a collection value. The value of both is an integer representing an
inclusive bound. This is valid only for unknown values of the three kinds of
collection types: list, set, and map.
Unknown value refinements are an optional way to reduce the range of possible
values for situations where that makes it possible to produce a known result
for unknown inputs or where it allows detecting an error during the planning
phase that would otherwise be detected only during the apply phase. It's always
safe to ignore refinements and just treat an unknown value as wholly unknown,
but considering refinements may allow a more precise answer. A provider that
produces refined values in its planned new state (from `PlanResourceChange`)
_must_ honor those refinements in the final state (from `ApplyResourceChange`).
Unmarshalling code should ignore refinement map keys that they don't know about,
because future versions of the protocol might define additional refinements.
When encoding an unknown value without any refinements, always use the older
format with extension code zero instead of using extension code 12 with an
empty refinement map. Any refined unknown value _must_ have at least one
refinement map entry. This rule ensures backward compatibility with older
implementations that predate the value refinements concept.
A server implementation of the protocol should treat _any_ MessagePack extension
code as representing an unknown value, but should ignore the payload of that
extension value entirely unless the extension code is 12 to indicate that
the body represents refinements. Future versions of this protocol may define
specific formats for other extension codes, but they will always represent
unknown values.
### `Schema.NestedBlock` Mapping Rules for MessagePack
The MessagePack serialization of a collection of blocks of a particular type
@ -155,7 +212,7 @@ The properties representing nested block types have property values based on
The JSON serialization of an attribute value depends on the value of the `type`
field of the corresponding `Schema.Attribute` message. The `type` field is
a compact JSON serialization of a
[Terraform type constraint](https://www.terraform.io/docs/configuration/types.html),
[Terraform type constraint](https://developer.hashicorp.com/terraform/language/expressions/type-constraints),
which consists either of a single
string value (for primitive types) or a two-element array giving a type kind
and a type argument.

View file

@ -1,353 +0,0 @@
// Terraform Plugin RPC protocol version 5.0
//
// This file defines version 5.0 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will be updated in-place in the source Terraform repository for
// any minor versions of protocol 5, but later minor versions will always be
// backwards compatible. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
package tfplugin5;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message Stop {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
// Schema is the configuration schema for a Resource, Provider, or Provisioner.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
}
message Attribute {
string name = 1;
bytes type = 2;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc Configure(Configure.Request) returns (Configure.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
}
}
message PrepareProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
DynamicValue prepared_config = 1;
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceTypeConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataSourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message Configure {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}
service Provisioner {
rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProvisionerSchema {
message Request {
}
message Response {
Schema provisioner = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ValidateProvisionerConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ProvisionResource {
message Request {
DynamicValue config = 1;
DynamicValue connection = 2;
}
message Response {
string output = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,353 +0,0 @@
// Terraform Plugin RPC protocol version 5.1
//
// This file defines version 5.1 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will be updated in-place in the source Terraform repository for
// any minor versions of protocol 5, but later minor versions will always be
// backwards compatible. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
package tfplugin5;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message Stop {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
// Schema is the configuration schema for a Resource, Provider, or Provisioner.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
}
message Attribute {
string name = 1;
bytes type = 2;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc Configure(Configure.Request) returns (Configure.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
}
}
message PrepareProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
DynamicValue prepared_config = 1;
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceTypeConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataSourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message Configure {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}
service Provisioner {
rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProvisionerSchema {
message Request {
}
message Response {
Schema provisioner = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ValidateProvisionerConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ProvisionResource {
message Request {
DynamicValue config = 1;
DynamicValue connection = 2;
}
message Response {
string output = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,369 +0,0 @@
// Terraform Plugin RPC protocol version 5.2
//
// This file defines version 5.2 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 5 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin5";
package tfplugin5;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message Stop {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource, Provider, or Provisioner.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc Configure(Configure.Request) returns (Configure.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
}
}
message PrepareProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
DynamicValue prepared_config = 1;
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceTypeConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataSourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message Configure {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}
service Provisioner {
rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProvisionerSchema {
message Request {
}
message Response {
Schema provisioner = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ValidateProvisionerConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ProvisionResource {
message Request {
DynamicValue config = 1;
DynamicValue connection = 2;
}
message Response {
string output = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,381 +0,0 @@
// Terraform Plugin RPC protocol version 5.3
//
// This file defines version 5.3 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 5 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin5";
package tfplugin5;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message Stop {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource, Provider, or Provisioner.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc Configure(Configure.Request) returns (Configure.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
ServerCapabilities server_capabilities = 6;
}
// ServerCapabilities allows providers to communicate extra information
// regarding supported protocol features. This is used to indicate
// availability of certain forward-compatible changes which may be optional
// in a major protocol version, but cannot be tested for directly.
message ServerCapabilities {
// The plan_destroy capability signals that a provider expects a call
// to PlanResourceChange when a resource is going to be destroyed.
bool plan_destroy = 1;
}
}
message PrepareProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
DynamicValue prepared_config = 1;
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceTypeConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataSourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message Configure {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}
service Provisioner {
rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProvisionerSchema {
message Request {
}
message Response {
Schema provisioner = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ValidateProvisionerConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ProvisionResource {
message Request {
DynamicValue config = 1;
DynamicValue connection = 2;
}
message Response {
string output = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -0,0 +1,813 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// Terraform Plugin RPC protocol version 5.9
//
// This file defines version 5.9 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// Any minor versions of protocol 5 to follow should modify this file while
// maintaining backwards compatibility. Breaking changes, if any are required,
// will come in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin5";
import "google/protobuf/timestamp.proto";
package tfplugin5;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message FunctionError {
string text = 1;
// The optional function_argument records the index position of the
// argument which caused the error.
optional int64 function_argument = 2;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message Stop {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// ResourceIdentitySchema represents the structure and types of data used to identify
// a managed resource type. Effectively, resource identity is a versioned object
// that can be used to compare resources, whether already managed and/or being
// discovered.
message ResourceIdentitySchema {
// IdentityAttribute represents one value of data within resource identity. These
// are always used in resource identity comparisons.
message IdentityAttribute {
// name is the identity attribute name
string name = 1;
// type is the identity attribute type
bytes type = 2;
// required_for_import when enabled signifies that this attribute must be
// defined for ImportResourceState to complete successfully
bool required_for_import = 3;
// optional_for_import when enabled signifies that this attribute is not
// required for ImportResourceState, because it can be supplied by the
// provider. It is still possible to supply this attribute during import.
bool optional_for_import = 4;
// description is a human-readable description of the attribute in Markdown
string description = 5;
}
// version is the identity version and separate from the Schema version.
// Any time the structure or format of identity_attributes changes, this version
// should be incremented. Versioning implicitly starts at 0 and by convention
// should be incremented by 1 each change.
//
// When comparing identity_attributes data, differing versions should always be treated
// as inequal.
int64 version = 1;
// identity_attributes are the individual value definitions which define identity data
// for a managed resource type. This information is used to decode DynamicValue of
// identity data.
//
// These attributes are intended for permanent identity data and must be wholly
// representative of all data necessary to compare two managed resource instances
// with no other data. This generally should include account, endpoint, location,
// and automatically generated identifiers. For some resources, this may include
// configuration-based data, such as a required name which must be unique.
repeated IdentityAttribute identity_attributes = 2;
}
message ResourceIdentityData {
// identity_data is the resource identity data for the given definition. It should
// be decoded using the identity schema.
//
// This data is considered permanent for the identity version and suitable for
// longer-term storage.
DynamicValue identity_data = 1;
}
// Schema is the configuration schema for a Resource, Provider, or Provisioner.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
bool write_only = 10;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
// ServerCapabilities allows providers to communicate extra information
// regarding supported protocol features. This is used to indicate
// availability of certain forward-compatible changes which may be optional
// in a major protocol version, but cannot be tested for directly.
message ServerCapabilities {
// The plan_destroy capability signals that a provider expects a call
// to PlanResourceChange when a resource is going to be destroyed.
bool plan_destroy = 1;
// The get_provider_schema_optional capability indicates that this
// provider does not require calling GetProviderSchema to operate
// normally, and the caller can used a cached copy of the provider's
// schema.
bool get_provider_schema_optional = 2;
// The move_resource_state capability signals that a provider supports the
// MoveResourceState RPC.
bool move_resource_state = 3;
}
// ClientCapabilities allows Terraform to publish information regarding
// supported protocol features. This is used to indicate availability of
// certain forward-compatible changes which may be optional in a major
// protocol version, but cannot be tested for directly.
message ClientCapabilities {
// The deferral_allowed capability signals that the client is able to
// handle deferred responses from the provider.
bool deferral_allowed = 1;
// The write_only_attributes_allowed capability signals that the client
// is able to handle write_only attributes for managed resources.
bool write_only_attributes_allowed = 2;
}
message Function {
// parameters is the ordered list of positional function parameters.
repeated Parameter parameters = 1;
// variadic_parameter is an optional final parameter which accepts
// zero or more argument values, in which Terraform will send an
// ordered list of the parameter type.
Parameter variadic_parameter = 2;
// Return is the function return parameter.
Return return = 3;
// summary is the human-readable shortened documentation for the function.
string summary = 4;
// description is human-readable documentation for the function.
string description = 5;
// description_kind is the formatting of the description.
StringKind description_kind = 6;
// deprecation_message is human-readable documentation if the
// function is deprecated.
string deprecation_message = 7;
message Parameter {
// name is the human-readable display name for the parameter.
string name = 1;
// type is the type constraint for the parameter.
bytes type = 2;
// allow_null_value when enabled denotes that a null argument value can
// be passed to the provider. When disabled, Terraform returns an error
// if the argument value is null.
bool allow_null_value = 3;
// allow_unknown_values when enabled denotes that only wholly known
// argument values will be passed to the provider. When disabled,
// Terraform skips the function call entirely and assumes an unknown
// value result from the function.
bool allow_unknown_values = 4;
// description is human-readable documentation for the parameter.
string description = 5;
// description_kind is the formatting of the description.
StringKind description_kind = 6;
}
message Return {
// type is the type constraint for the function result.
bytes type = 1;
}
}
// Deferred is a message that indicates that change is deferred for a reason.
message Deferred {
// Reason is the reason for deferring the change.
enum Reason {
// UNKNOWN is the default value, and should not be used.
UNKNOWN = 0;
// RESOURCE_CONFIG_UNKNOWN is used when the config is partially unknown and the real
// values need to be known before the change can be planned.
RESOURCE_CONFIG_UNKNOWN = 1;
// PROVIDER_CONFIG_UNKNOWN is used when parts of the provider configuration
// are unknown, e.g. the provider configuration is only known after the apply is done.
PROVIDER_CONFIG_UNKNOWN = 2;
// ABSENT_PREREQ is used when a hard dependency has not been satisfied.
ABSENT_PREREQ = 3;
}
// reason is the reason for deferring the change.
Reason reason = 1;
}
service Provider {
//////// Information about what a provider supports/expects
// GetMetadata returns upfront information about server capabilities and
// supported resource types without requiring the server to instantiate all
// schema information, which may be memory intensive. This RPC is optional,
// where clients may receive an unimplemented RPC error. Clients should
// ignore the error and call the GetSchema RPC as a fallback.
rpc GetMetadata(GetMetadata.Request) returns (GetMetadata.Response);
// GetSchema returns schema information for the provider, data resources,
// and managed resources.
rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
// GetResourceIdentitySchemas returns the identity schemas for all managed
// resources.
rpc GetResourceIdentitySchemas(GetResourceIdentitySchemas.Request) returns (GetResourceIdentitySchemas.Response);
// UpgradeResourceIdentityData should return the upgraded resource identity
// data for a managed resource type.
rpc UpgradeResourceIdentity(UpgradeResourceIdentity.Request) returns (UpgradeResourceIdentity.Response);
//////// One-time initialization, called before other functions below
rpc Configure(Configure.Request) returns (Configure.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc MoveResourceState(MoveResourceState.Request) returns (MoveResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Ephemeral Resource Lifecycle
rpc ValidateEphemeralResourceConfig(ValidateEphemeralResourceConfig.Request) returns (ValidateEphemeralResourceConfig.Response);
rpc OpenEphemeralResource(OpenEphemeralResource.Request) returns (OpenEphemeralResource.Response);
rpc RenewEphemeralResource(RenewEphemeralResource.Request) returns (RenewEphemeralResource.Response);
rpc CloseEphemeralResource(CloseEphemeralResource.Request) returns (CloseEphemeralResource.Response);
// GetFunctions returns the definitions of all functions.
rpc GetFunctions(GetFunctions.Request) returns (GetFunctions.Response);
//////// Provider-contributed Functions
rpc CallFunction(CallFunction.Request) returns (CallFunction.Response);
//////// Graceful Shutdown
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetMetadata {
message Request {
}
message Response {
ServerCapabilities server_capabilities = 1;
repeated Diagnostic diagnostics = 2;
repeated DataSourceMetadata data_sources = 3;
repeated ResourceMetadata resources = 4;
// functions returns metadata for any functions.
repeated FunctionMetadata functions = 5;
repeated EphemeralMetadata ephemeral_resources = 6;
}
message EphemeralMetadata {
string type_name = 1;
}
message FunctionMetadata {
// name is the function name.
string name = 1;
}
message DataSourceMetadata {
string type_name = 1;
}
message ResourceMetadata {
string type_name = 1;
}
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
map<string, Function> functions = 7;
map<string, Schema> ephemeral_resource_schemas = 8;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
ServerCapabilities server_capabilities = 6;
}
}
message PrepareProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
DynamicValue prepared_config = 1;
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
// Request is the message that is sent to the provider during the
// UpgradeResourceState RPC.
//
// This message intentionally does not include configuration data as any
// configuration-based or configuration-conditional changes should occur
// during the PlanResourceChange RPC. Additionally, the configuration is
// not guaranteed to exist (in the case of resource destruction), be wholly
// known, nor match the given prior state, which could lead to unexpected
// provider behaviors for practitioners.
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message GetResourceIdentitySchemas {
message Request {
}
message Response {
// identity_schemas is a mapping of resource type names to their identity schemas.
map<string, ResourceIdentitySchema> identity_schemas = 1;
// diagnostics is the collection of warning and error diagnostics for this request.
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceIdentity {
message Request {
// type_name is the managed resource type name
string type_name = 1;
// version is the version of the resource identity data to upgrade
int64 version = 2;
// raw_identity is the raw identity as stored for the resource. Core does
// not have access to the identity schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_identity will be json encoded.
RawState raw_identity = 3;
}
message Response {
// upgraded_identity returns the upgraded resource identity data
ResourceIdentityData upgraded_identity = 1;
// diagnostics is the collection of warning and error diagnostics for this request
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceTypeConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataSourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateEphemeralResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message Configure {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
// Request is the message that is sent to the provider during the
// ReadResource RPC.
//
// This message intentionally does not include configuration data as any
// configuration-based or configuration-conditional changes should occur
// during the PlanResourceChange RPC. Additionally, the configuration is
// not guaranteed to be wholly known nor match the given prior state, which
// could lead to unexpected provider behaviors for practitioners.
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
ClientCapabilities client_capabilities = 5;
ResourceIdentityData current_identity = 6;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 4;
ResourceIdentityData new_identity = 5;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
ClientCapabilities client_capabilities = 7;
ResourceIdentityData prior_identity = 8;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 6;
ResourceIdentityData planned_identity = 7;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
ResourceIdentityData planned_identity = 7;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
ResourceIdentityData new_identity = 5;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
ClientCapabilities client_capabilities = 3;
ResourceIdentityData identity = 4;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
ResourceIdentityData identity = 4;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 3;
}
}
message MoveResourceState {
message Request {
// The address of the provider the resource is being moved from.
string source_provider_address = 1;
// The resource type that the resource is being moved from.
string source_type_name = 2;
// The schema version of the resource type that the resource is being
// moved from.
int64 source_schema_version = 3;
// The raw state of the resource being moved. Only the json field is
// populated, as there should be no legacy providers using the flatmap
// format that support newly introduced RPCs.
RawState source_state = 4;
// The resource type that the resource is being moved to.
string target_type_name = 5;
// The private state of the resource being moved.
bytes source_private = 6;
// The raw identity of the resource being moved. Only the json field is
// populated, as there should be no legacy providers using the flatmap
// format that support newly introduced RPCs.
RawState source_identity = 7;
// The identity schema version of the resource type that the resource
// is being moved from.
int64 source_identity_schema_version = 8;
}
message Response {
// The state of the resource after it has been moved.
DynamicValue target_state = 1;
// Any diagnostics that occurred during the move.
repeated Diagnostic diagnostics = 2;
// The private state of the resource after it has been moved.
bytes target_private = 3;
ResourceIdentityData target_identity = 4;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
ClientCapabilities client_capabilities = 4;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 3;
}
}
service Provisioner {
rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
rpc Stop(Stop.Request) returns (Stop.Response);
}
message GetProvisionerSchema {
message Request {
}
message Response {
Schema provisioner = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ValidateProvisionerConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ProvisionResource {
message Request {
DynamicValue config = 1;
DynamicValue connection = 2;
}
message Response {
string output = 1;
repeated Diagnostic diagnostics = 2;
}
}
message OpenEphemeralResource {
message Request {
string type_name = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
optional google.protobuf.Timestamp renew_at = 2;
DynamicValue result = 3;
optional bytes private = 4;
Deferred deferred = 5;
}
}
message RenewEphemeralResource {
message Request {
string type_name = 1;
optional bytes private = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
optional google.protobuf.Timestamp renew_at = 2;
optional bytes private = 3;
}
}
message CloseEphemeralResource {
message Request {
string type_name = 1;
optional bytes private = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message GetFunctions {
message Request {}
message Response {
// functions is a mapping of function names to definitions.
map<string, Function> functions = 1;
// diagnostics is any warnings or errors.
repeated Diagnostic diagnostics = 2;
}
}
message CallFunction {
message Request {
string name = 1;
repeated DynamicValue arguments = 2;
}
message Response {
DynamicValue result = 1;
FunctionError error = 2;
}
}

View file

@ -1,321 +0,0 @@
// Terraform Plugin RPC protocol version 6.0
//
// This file defines version 6.0 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 6 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
package tfplugin6;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message StopProvider {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource or Provider.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
Object nested_type = 10;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
message Object {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
}
repeated Attribute attributes = 1;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
}
}
message ValidateProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ConfigureProvider {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,324 +0,0 @@
// Terraform Plugin RPC protocol version 6.1
//
// This file defines version 6.1 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 6 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
package tfplugin6;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message StopProvider {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource or Provider.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
Object nested_type = 10;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
message Object {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
}
repeated Attribute attributes = 1;
NestingMode nesting = 3;
// MinItems and MaxItems were never used in the protocol, and have no
// effect on validation.
int64 min_items = 4 [deprecated = true];
int64 max_items = 5 [deprecated = true];
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
}
}
message ValidateProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ConfigureProvider {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,350 +0,0 @@
// Terraform Plugin RPC protocol version 6.2
//
// This file defines version 6.2 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 6 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
package tfplugin6;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message StopProvider {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource or Provider.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
Object nested_type = 10;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
message Object {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
}
repeated Attribute attributes = 1;
NestingMode nesting = 3;
// MinItems and MaxItems were never used in the protocol, and have no
// effect on validation.
int64 min_items = 4 [deprecated = true];
int64 max_items = 5 [deprecated = true];
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
}
}
message ValidateProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ConfigureProvider {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -1,362 +0,0 @@
// Terraform Plugin RPC protocol version 6.3
//
// This file defines version 6.3 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// This file will not be updated. Any minor versions of protocol 6 to follow
// should copy this file and modify the copy while maintaing backwards
// compatibility. Breaking changes, if any are required, will come
// in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
package tfplugin6;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message StopProvider {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// Schema is the configuration schema for a Resource or Provider.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
Object nested_type = 10;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
message Object {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
}
repeated Attribute attributes = 1;
NestingMode nesting = 3;
// MinItems and MaxItems were never used in the protocol, and have no
// effect on validation.
int64 min_items = 4 [deprecated = true];
int64 max_items = 5 [deprecated = true];
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
service Provider {
//////// Information about what a provider supports/expects
rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
//////// One-time initialization, called before other functions below
rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Graceful Shutdown
rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
ServerCapabilities server_capabilities = 6;
}
// ServerCapabilities allows providers to communicate extra information
// regarding supported protocol features. This is used to indicate
// availability of certain forward-compatible changes which may be optional
// in a major protocol version, but cannot be tested for directly.
message ServerCapabilities {
// The plan_destroy capability signals that a provider expects a call
// to PlanResourceChange when a resource is going to be destroyed.
bool plan_destroy = 1;
}
}
message ValidateProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ConfigureProvider {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
}
}

View file

@ -0,0 +1,793 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// Terraform Plugin RPC protocol version 6.9
//
// This file defines version 6.9 of the RPC protocol. To implement a plugin
// against this protocol, copy this definition into your own codebase and
// use protoc to generate stubs for your target language.
//
// Any minor versions of protocol 6 to follow should modify this file while
// maintaining backwards compatibility. Breaking changes, if any are required,
// will come in a subsequent major version with its own separate proto definition.
//
// Note that only the proto files included in a release tag of Terraform are
// official protocol releases. Proto files taken from other commits may include
// incomplete changes or features that did not make it into a final release.
// In all reasonable cases, plugin developers should take the proto file from
// the tag of the most recent release of Terraform, and not from the main
// branch or any other development branch.
//
syntax = "proto3";
option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
import "google/protobuf/timestamp.proto";
package tfplugin6;
// DynamicValue is an opaque encoding of terraform data, with the field name
// indicating the encoding scheme used.
message DynamicValue {
bytes msgpack = 1;
bytes json = 2;
}
message Diagnostic {
enum Severity {
INVALID = 0;
ERROR = 1;
WARNING = 2;
}
Severity severity = 1;
string summary = 2;
string detail = 3;
AttributePath attribute = 4;
}
message FunctionError {
string text = 1;
// The optional function_argument records the index position of the
// argument which caused the error.
optional int64 function_argument = 2;
}
message AttributePath {
message Step {
oneof selector {
// Set "attribute_name" to represent looking up an attribute
// in the current object value.
string attribute_name = 1;
// Set "element_key_*" to represent looking up an element in
// an indexable collection type.
string element_key_string = 2;
int64 element_key_int = 3;
}
}
repeated Step steps = 1;
}
message StopProvider {
message Request {
}
message Response {
string Error = 1;
}
}
// RawState holds the stored state for a resource to be upgraded by the
// provider. It can be in one of two formats, the current json encoded format
// in bytes, or the legacy flatmap format as a map of strings.
message RawState {
bytes json = 1;
map<string, string> flatmap = 2;
}
enum StringKind {
PLAIN = 0;
MARKDOWN = 1;
}
// ResourceIdentitySchema represents the structure and types of data used to identify
// a managed resource type. Effectively, resource identity is a versioned object
// that can be used to compare resources, whether already managed and/or being
// discovered.
message ResourceIdentitySchema {
// IdentityAttribute represents one value of data within resource identity. These
// are always used in resource identity comparisons.
message IdentityAttribute {
// name is the identity attribute name
string name = 1;
// type is the identity attribute type
bytes type = 2;
// required_for_import when enabled signifies that this attribute must be
// defined for ImportResourceState to complete successfully
bool required_for_import = 3;
// optional_for_import when enabled signifies that this attribute is not
// required for ImportResourceState, because it can be supplied by the
// provider. It is still possible to supply this attribute during import.
bool optional_for_import = 4;
// description is a human-readable description of the attribute in Markdown
string description = 5;
}
// version is the identity version and separate from the Schema version.
// Any time the structure or format of identity_attributes changes, this version
// should be incremented. Versioning implicitly starts at 0 and by convention
// should be incremented by 1 each change.
//
// When comparing identity_attributes data, differing versions should always be treated
// as inequal.
int64 version = 1;
// identity_attributes are the individual value definitions which define identity data
// for a managed resource type. This information is used to decode DynamicValue of
// identity data.
//
// These attributes are intended for permanent identity data and must be wholly
// representative of all data necessary to compare two managed resource instances
// with no other data. This generally should include account, endpoint, location,
// and automatically generated identifiers. For some resources, this may include
// configuration-based data, such as a required name which must be unique.
repeated IdentityAttribute identity_attributes = 2;
}
message ResourceIdentityData {
// identity_data is the resource identity data for the given definition. It should
// be decoded using the identity schema.
//
// This data is considered permanent for the identity version and suitable for
// longer-term storage.
DynamicValue identity_data = 1;
}
// Schema is the configuration schema for a Resource or Provider.
message Schema {
message Block {
int64 version = 1;
repeated Attribute attributes = 2;
repeated NestedBlock block_types = 3;
string description = 4;
StringKind description_kind = 5;
bool deprecated = 6;
}
message Attribute {
string name = 1;
bytes type = 2;
Object nested_type = 10;
string description = 3;
bool required = 4;
bool optional = 5;
bool computed = 6;
bool sensitive = 7;
StringKind description_kind = 8;
bool deprecated = 9;
bool write_only = 11;
}
message NestedBlock {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
GROUP = 5;
}
string type_name = 1;
Block block = 2;
NestingMode nesting = 3;
int64 min_items = 4;
int64 max_items = 5;
}
message Object {
enum NestingMode {
INVALID = 0;
SINGLE = 1;
LIST = 2;
SET = 3;
MAP = 4;
}
repeated Attribute attributes = 1;
NestingMode nesting = 3;
// MinItems and MaxItems were never used in the protocol, and have no
// effect on validation.
int64 min_items = 4 [deprecated = true];
int64 max_items = 5 [deprecated = true];
}
// The version of the schema.
// Schemas are versioned, so that providers can upgrade a saved resource
// state when the schema is changed.
int64 version = 1;
// Block is the top level configuration block for this schema.
Block block = 2;
}
message Function {
// parameters is the ordered list of positional function parameters.
repeated Parameter parameters = 1;
// variadic_parameter is an optional final parameter which accepts
// zero or more argument values, in which Terraform will send an
// ordered list of the parameter type.
Parameter variadic_parameter = 2;
// Return is the function return parameter.
Return return = 3;
// summary is the human-readable shortened documentation for the function.
string summary = 4;
// description is human-readable documentation for the function.
string description = 5;
// description_kind is the formatting of the description.
StringKind description_kind = 6;
// deprecation_message is human-readable documentation if the
// function is deprecated.
string deprecation_message = 7;
message Parameter {
// name is the human-readable display name for the parameter.
string name = 1;
// type is the type constraint for the parameter.
bytes type = 2;
// allow_null_value when enabled denotes that a null argument value can
// be passed to the provider. When disabled, Terraform returns an error
// if the argument value is null.
bool allow_null_value = 3;
// allow_unknown_values when enabled denotes that only wholly known
// argument values will be passed to the provider. When disabled,
// Terraform skips the function call entirely and assumes an unknown
// value result from the function.
bool allow_unknown_values = 4;
// description is human-readable documentation for the parameter.
string description = 5;
// description_kind is the formatting of the description.
StringKind description_kind = 6;
}
message Return {
// type is the type constraint for the function result.
bytes type = 1;
}
}
// ServerCapabilities allows providers to communicate extra information
// regarding supported protocol features. This is used to indicate
// availability of certain forward-compatible changes which may be optional
// in a major protocol version, but cannot be tested for directly.
message ServerCapabilities {
// The plan_destroy capability signals that a provider expects a call
// to PlanResourceChange when a resource is going to be destroyed.
bool plan_destroy = 1;
// The get_provider_schema_optional capability indicates that this
// provider does not require calling GetProviderSchema to operate
// normally, and the caller can used a cached copy of the provider's
// schema.
bool get_provider_schema_optional = 2;
// The move_resource_state capability signals that a provider supports the
// MoveResourceState RPC.
bool move_resource_state = 3;
}
// ClientCapabilities allows Terraform to publish information regarding
// supported protocol features. This is used to indicate availability of
// certain forward-compatible changes which may be optional in a major
// protocol version, but cannot be tested for directly.
message ClientCapabilities {
// The deferral_allowed capability signals that the client is able to
// handle deferred responses from the provider.
bool deferral_allowed = 1;
// The write_only_attributes_allowed capability signals that the client
// is able to handle write_only attributes for managed resources.
bool write_only_attributes_allowed = 2;
}
// Deferred is a message that indicates that change is deferred for a reason.
message Deferred {
// Reason is the reason for deferring the change.
enum Reason {
// UNKNOWN is the default value, and should not be used.
UNKNOWN = 0;
// RESOURCE_CONFIG_UNKNOWN is used when the config is partially unknown and the real
// values need to be known before the change can be planned.
RESOURCE_CONFIG_UNKNOWN = 1;
// PROVIDER_CONFIG_UNKNOWN is used when parts of the provider configuration
// are unknown, e.g. the provider configuration is only known after the apply is done.
PROVIDER_CONFIG_UNKNOWN = 2;
// ABSENT_PREREQ is used when a hard dependency has not been satisfied.
ABSENT_PREREQ = 3;
}
// reason is the reason for deferring the change.
Reason reason = 1;
}
service Provider {
//////// Information about what a provider supports/expects
// GetMetadata returns upfront information about server capabilities and
// supported resource types without requiring the server to instantiate all
// schema information, which may be memory intensive. This RPC is optional,
// where clients may receive an unimplemented RPC error. Clients should
// ignore the error and call the GetProviderSchema RPC as a fallback.
rpc GetMetadata(GetMetadata.Request) returns (GetMetadata.Response);
// GetSchema returns schema information for the provider, data resources,
// and managed resources.
rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
// GetResourceIdentitySchemas returns the identity schemas for all managed
// resources.
rpc GetResourceIdentitySchemas(GetResourceIdentitySchemas.Request) returns (GetResourceIdentitySchemas.Response);
// UpgradeResourceIdentityData should return the upgraded resource identity
// data for a managed resource type.
rpc UpgradeResourceIdentity(UpgradeResourceIdentity.Request) returns (UpgradeResourceIdentity.Response);
//////// One-time initialization, called before other functions below
rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
//////// Managed Resource Lifecycle
rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
rpc MoveResourceState(MoveResourceState.Request) returns (MoveResourceState.Response);
rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
//////// Ephemeral Resource Lifecycle
rpc ValidateEphemeralResourceConfig(ValidateEphemeralResourceConfig.Request) returns (ValidateEphemeralResourceConfig.Response);
rpc OpenEphemeralResource(OpenEphemeralResource.Request) returns (OpenEphemeralResource.Response);
rpc RenewEphemeralResource(RenewEphemeralResource.Request) returns (RenewEphemeralResource.Response);
rpc CloseEphemeralResource(CloseEphemeralResource.Request) returns (CloseEphemeralResource.Response);
// GetFunctions returns the definitions of all functions.
rpc GetFunctions(GetFunctions.Request) returns (GetFunctions.Response);
//////// Provider-contributed Functions
rpc CallFunction(CallFunction.Request) returns (CallFunction.Response);
//////// Graceful Shutdown
rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
}
message GetMetadata {
message Request {
}
message Response {
ServerCapabilities server_capabilities = 1;
repeated Diagnostic diagnostics = 2;
repeated DataSourceMetadata data_sources = 3;
repeated ResourceMetadata resources = 4;
// functions returns metadata for any functions.
repeated FunctionMetadata functions = 5;
repeated EphemeralMetadata ephemeral_resources = 6;
}
message EphemeralMetadata {
string type_name = 1;
}
message FunctionMetadata {
// name is the function name.
string name = 1;
}
message DataSourceMetadata {
string type_name = 1;
}
message ResourceMetadata {
string type_name = 1;
}
}
message GetProviderSchema {
message Request {
}
message Response {
Schema provider = 1;
map<string, Schema> resource_schemas = 2;
map<string, Schema> data_source_schemas = 3;
map<string, Function> functions = 7;
map<string, Schema> ephemeral_resource_schemas = 8;
repeated Diagnostic diagnostics = 4;
Schema provider_meta = 5;
ServerCapabilities server_capabilities = 6;
}
}
message ValidateProviderConfig {
message Request {
DynamicValue config = 1;
}
message Response {
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceState {
// Request is the message that is sent to the provider during the
// UpgradeResourceState RPC.
//
// This message intentionally does not include configuration data as any
// configuration-based or configuration-conditional changes should occur
// during the PlanResourceChange RPC. Additionally, the configuration is
// not guaranteed to exist (in the case of resource destruction), be wholly
// known, nor match the given prior state, which could lead to unexpected
// provider behaviors for practitioners.
message Request {
string type_name = 1;
// version is the schema_version number recorded in the state file
int64 version = 2;
// raw_state is the raw states as stored for the resource. Core does
// not have access to the schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_state will be the json encoded
// state, or a legacy flat-mapped format.
RawState raw_state = 3;
}
message Response {
// new_state is a msgpack-encoded data structure that, when interpreted with
// the _current_ schema for this resource type, is functionally equivalent to
// that which was given in prior_state_raw.
DynamicValue upgraded_state = 1;
// diagnostics describes any errors encountered during migration that could not
// be safely resolved, and warnings about any possibly-risky assumptions made
// in the upgrade process.
repeated Diagnostic diagnostics = 2;
}
}
message GetResourceIdentitySchemas {
message Request {
}
message Response {
// identity_schemas is a mapping of resource type names to their identity schemas.
map<string, ResourceIdentitySchema> identity_schemas = 1;
// diagnostics is the collection of warning and error diagnostics for this request.
repeated Diagnostic diagnostics = 2;
}
}
message UpgradeResourceIdentity {
message Request {
// type_name is the managed resource type name
string type_name = 1;
// version is the version of the resource identity data to upgrade
int64 version = 2;
// raw_identity is the raw identity as stored for the resource. Core does
// not have access to the identity schema of prior_version, so it's the
// provider's responsibility to interpret this value using the
// appropriate older schema. The raw_identity will be json encoded.
RawState raw_identity = 3;
}
message Response {
// upgraded_identity returns the upgraded resource identity data
ResourceIdentityData upgraded_identity = 1;
// diagnostics is the collection of warning and error diagnostics for this request
repeated Diagnostic diagnostics = 2;
}
}
message ValidateResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateDataResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ValidateEphemeralResourceConfig {
message Request {
string type_name = 1;
DynamicValue config = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ConfigureProvider {
message Request {
string terraform_version = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message ReadResource {
// Request is the message that is sent to the provider during the
// ReadResource RPC.
//
// This message intentionally does not include configuration data as any
// configuration-based or configuration-conditional changes should occur
// during the PlanResourceChange RPC. Additionally, the configuration is
// not guaranteed to be wholly known nor match the given prior state, which
// could lead to unexpected provider behaviors for practitioners.
message Request {
string type_name = 1;
DynamicValue current_state = 2;
bytes private = 3;
DynamicValue provider_meta = 4;
ClientCapabilities client_capabilities = 5;
ResourceIdentityData current_identity = 6;
}
message Response {
DynamicValue new_state = 1;
repeated Diagnostic diagnostics = 2;
bytes private = 3;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 4;
ResourceIdentityData new_identity = 5;
}
}
message PlanResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue proposed_new_state = 3;
DynamicValue config = 4;
bytes prior_private = 5;
DynamicValue provider_meta = 6;
ClientCapabilities client_capabilities = 7;
ResourceIdentityData prior_identity = 8;
}
message Response {
DynamicValue planned_state = 1;
repeated AttributePath requires_replace = 2;
bytes planned_private = 3;
repeated Diagnostic diagnostics = 4;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 6;
ResourceIdentityData planned_identity = 7;
}
}
message ApplyResourceChange {
message Request {
string type_name = 1;
DynamicValue prior_state = 2;
DynamicValue planned_state = 3;
DynamicValue config = 4;
bytes planned_private = 5;
DynamicValue provider_meta = 6;
ResourceIdentityData planned_identity = 7;
}
message Response {
DynamicValue new_state = 1;
bytes private = 2;
repeated Diagnostic diagnostics = 3;
// This may be set only by the helper/schema "SDK" in the main Terraform
// repository, to request that Terraform Core >=0.12 permit additional
// inconsistencies that can result from the legacy SDK type system
// and its imprecise mapping to the >=0.12 type system.
// The change in behavior implied by this flag makes sense only for the
// specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
ResourceIdentityData new_identity = 5;
}
}
message ImportResourceState {
message Request {
string type_name = 1;
string id = 2;
ClientCapabilities client_capabilities = 3;
ResourceIdentityData identity = 4;
}
message ImportedResource {
string type_name = 1;
DynamicValue state = 2;
bytes private = 3;
ResourceIdentityData identity = 4;
}
message Response {
repeated ImportedResource imported_resources = 1;
repeated Diagnostic diagnostics = 2;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 3;
}
}
message MoveResourceState {
message Request {
// The address of the provider the resource is being moved from.
string source_provider_address = 1;
// The resource type that the resource is being moved from.
string source_type_name = 2;
// The schema version of the resource type that the resource is being
// moved from.
int64 source_schema_version = 3;
// The raw state of the resource being moved. Only the json field is
// populated, as there should be no legacy providers using the flatmap
// format that support newly introduced RPCs.
RawState source_state = 4;
// The resource type that the resource is being moved to.
string target_type_name = 5;
// The private state of the resource being moved.
bytes source_private = 6;
// The raw identity of the resource being moved. Only the json field is
// populated, as there should be no legacy providers using the flatmap
// format that support newly introduced RPCs.
RawState source_identity = 7;
// The identity schema version of the resource type that the resource
// is being moved from.
int64 source_identity_schema_version = 8;
}
message Response {
// The state of the resource after it has been moved.
DynamicValue target_state = 1;
// Any diagnostics that occurred during the move.
repeated Diagnostic diagnostics = 2;
// The private state of the resource after it has been moved.
bytes target_private = 3;
ResourceIdentityData target_identity = 4;
}
}
message ReadDataSource {
message Request {
string type_name = 1;
DynamicValue config = 2;
DynamicValue provider_meta = 3;
ClientCapabilities client_capabilities = 4;
}
message Response {
DynamicValue state = 1;
repeated Diagnostic diagnostics = 2;
// deferred is set if the provider is deferring the change. If set the caller
// needs to handle the deferral.
Deferred deferred = 3;
}
}
message OpenEphemeralResource {
message Request {
string type_name = 1;
DynamicValue config = 2;
ClientCapabilities client_capabilities = 3;
}
message Response {
repeated Diagnostic diagnostics = 1;
optional google.protobuf.Timestamp renew_at = 2;
DynamicValue result = 3;
optional bytes private = 4;
Deferred deferred = 5;
}
}
message RenewEphemeralResource {
message Request {
string type_name = 1;
optional bytes private = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
optional google.protobuf.Timestamp renew_at = 2;
optional bytes private = 3;
}
}
message CloseEphemeralResource {
message Request {
string type_name = 1;
optional bytes private = 2;
}
message Response {
repeated Diagnostic diagnostics = 1;
}
}
message GetFunctions {
message Request {}
message Response {
// functions is a mapping of function names to definitions.
map<string, Function> functions = 1;
// diagnostics is any warnings or errors.
repeated Diagnostic diagnostics = 2;
}
}
message CallFunction {
message Request {
string name = 1;
repeated DynamicValue arguments = 2;
}
message Response {
DynamicValue result = 1;
FunctionError error = 2;
}
}

View file

@ -33,9 +33,11 @@ The various object values used in different parts of this process are:
which a provider may use as a starting point for its planning operation.
The built-in logic primarily deals with the expected behavior for attributes
marked in the schema as both "optional" _and_ "computed", which means that
the user may either set it or may leave it unset to allow the provider
to choose a value instead.
marked in the schema as "computed". If an attribute is only "computed",
Terraform expects the value to only be chosen by the provider and it will
preserve any Prior State. If an attribute is marked as "computed" and
"optional", this means that the user may either set it or may leave it
unset to allow the provider to choose a value.
Terraform Core therefore constructs the proposed new state by taking the
attribute value from Configuration if it is non-null, and then using the
@ -245,6 +247,8 @@ information as the **Previous Run State** but does so in a way that conforms
to the current version of the resource type schema, which therefore allows
Terraform Core to interact with the data fully for subsequent steps.
No unknown values are permitted in the **Updated State**.
### ReadResource
Although Terraform typically expects to have exclusive control over any remote
@ -287,7 +291,7 @@ following two situations for each attribute:
This operation returns the **Prior State** to use for the next call to
`PlanResourceChange`, thus completing the circle and beginning this process
over again.
over again. No unknown values are permitted in the **Prior State**.
## Handling of Nested Blocks in Configuration

View file

@ -45,6 +45,31 @@ The other subsystems described below should always be set up to match
themselves with `unicode.Version` and generate an error if they cannot, but
that isn't true of all of them.
## Unicode Identifier Rules in HCL
_Identifier and Pattern Syntax_ (TF31) is a Unicode standards annex which
describe a set of rules for tokenizing "identifiers", such as variable names
in a programming language.
HCL uses a superset of that specification for its own identifier tokenization
rules, and so it includes some code derived from the TF31 data tables that
describe which characters belong to the "ID_Start" and "ID_Continue" classes.
Since Terraform is the primary user of HCL, it's typically Terraform's adoption
of a new Unicode version which drives HCL to adopt one. To update the Unicode
tables to a new version:
* Edit `hclsyntax/generate.go`'s line which runs `unicode2ragel.rb` to specify
the URL of the `DerivedCoreProperties.txt` data file for the intended Unicode
version.
* Run `go generate ./hclsyntax` to run the generation code to update both
`unicode_derived.rl` and, indirectly, `scan_tokens.go`. (You will need both
a Ruby interpreter and the Ragel state machine compiler on your system in
order to complete this step.)
* Run all the tests to check for regressions: `go test ./...`
* If all looks good, commit all of the changes and open a PR to HCL.
* Once that PR is merged and released, update Terraform to use the new version
of HCL.
## Unicode Text Segmentation
_Text Segmentation_ (TR29) is a Unicode standards annex which describes

View file

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package main
// experimentsAllowed can be set to any non-empty string using Go linker

404
go.mod
View file

@ -1,195 +1,337 @@
module github.com/hashicorp/terraform
go 1.24.2
godebug winsymlink=0
require (
cloud.google.com/go/storage v1.10.0
github.com/Azure/azure-sdk-for-go v59.2.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.24
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
github.com/ProtonMail/go-crypto v1.1.3
github.com/agext/levenshtein v1.2.3
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1501
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70
github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible
github.com/apparentlymart/go-cidr v1.1.0
github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0
github.com/apparentlymart/go-shquot v0.0.1
github.com/apparentlymart/go-userdirs v0.0.0-20200915174352-b0c018a67c13
github.com/apparentlymart/go-versions v1.0.1
github.com/apparentlymart/go-versions v1.0.2
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
github.com/aws/aws-sdk-go v1.42.35
github.com/bgentry/speakeasy v0.1.0
github.com/bmatcuk/doublestar v1.1.5
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
github.com/davecgh/go-spew v1.1.1
github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6
github.com/go-test/deep v1.0.3
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.8
github.com/google/uuid v1.2.0
github.com/gophercloud/gophercloud v0.10.1-0.20200424014253-c3bfe50899e5
github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d
github.com/hashicorp/aws-sdk-go-base v0.7.1
github.com/hashicorp/consul/api v1.9.1
github.com/hashicorp/consul/sdk v0.8.0
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/go-azure-helpers v0.31.1
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/hashicorp/cli v1.1.7
github.com/hashicorp/go-checkpoint v0.5.0
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-getter v1.6.2
github.com/hashicorp/go-hclog v0.15.0
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-plugin v1.4.3
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hashicorp/go-tfe v1.7.0
github.com/hashicorp/go-getter v1.7.8
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-plugin v1.6.3
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/go-slug v0.16.3
github.com/hashicorp/go-tfe v1.74.1
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
github.com/hashicorp/hcl/v2 v2.13.0
github.com/hashicorp/terraform-config-inspect v0.0.0-20210209133302-4fd17a0faac2
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734
github.com/jmespath/go-jmespath v0.4.0
github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl/v2 v2.23.1-0.20250203194505-ba0759438da2
github.com/hashicorp/jsonapi v1.3.2
github.com/hashicorp/terraform-registry-address v0.2.4
github.com/hashicorp/terraform-svchost v0.1.1
github.com/hashicorp/terraform/internal/backend/remote-state/azure v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/consul v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/cos v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/gcs v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/kubernetes v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/oci v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/oss v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/pg v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/backend/remote-state/s3 v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/legacy v0.0.0-00010101000000-000000000000
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/lib/pq v1.10.3
github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82
github.com/manicminer/hamilton v0.44.0
github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-shellwords v1.0.4
github.com/mitchellh/cli v1.1.4
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-shellwords v1.0.12
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
github.com/mitchellh/copystructure v1.2.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb
github.com/mitchellh/go-wordwrap v1.0.1
github.com/mitchellh/gox v1.0.1
github.com/mitchellh/mapstructure v1.1.2
github.com/mitchellh/reflectwalk v1.0.2
github.com/nishanths/exhaustive v0.7.11
github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db
github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23
github.com/pkg/errors v0.9.1
github.com/nishanths/exhaustive v0.12.0
github.com/packer-community/winrmcp v0.0.0-20221126162354-6e900dd2c68f
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/posener/complete v1.2.3
github.com/spf13/afero v1.2.2
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.232
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.233
github.com/tencentyun/cos-go-sdk-v5 v0.7.29
github.com/tombuildsstuff/giovanni v0.15.1
github.com/xanzy/ssh-agent v0.3.1
github.com/spf13/afero v1.9.5
github.com/xanzy/ssh-agent v0.3.3
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/zclconf/go-cty v1.11.0
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b
github.com/zclconf/go-cty-yaml v1.0.2
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.11
google.golang.org/api v0.44.0-impersonate-preview
google.golang.org/grpc v1.47.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
google.golang.org/protobuf v1.27.1
honnef.co/go/tools v0.3.0
k8s.io/api v0.23.4
k8s.io/apimachinery v0.23.4
k8s.io/client-go v0.23.4
k8s.io/utils v0.0.0-20211116205334-6203023598ed
github.com/zclconf/go-cty v1.16.2
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940
github.com/zclconf/go-cty-yaml v1.1.0
go.opentelemetry.io/contrib/exporters/autoexport v0.45.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
go.opentelemetry.io/otel v1.34.0
go.opentelemetry.io/otel/sdk v1.31.0
go.opentelemetry.io/otel/trace v1.34.0
go.uber.org/mock v0.4.0
golang.org/x/crypto v0.36.0
golang.org/x/mod v0.24.0
golang.org/x/net v0.38.0
golang.org/x/oauth2 v0.27.0
golang.org/x/sys v0.31.0
golang.org/x/term v0.30.0
golang.org/x/text v0.23.0
golang.org/x/tools v0.31.0
golang.org/x/tools/cmd/cover v0.1.0-deprecated
google.golang.org/grpc v1.69.4
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0
google.golang.org/protobuf v1.36.5
honnef.co/go/tools v0.6.0
)
require (
cloud.google.com/go v0.81.0 // indirect
cloud.google.com/go v0.110.10 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.4 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Azure/go-autorest/autorest v0.11.30 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.2 // indirect
github.com/Azure/go-autorest/tracing v0.6.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d // indirect
github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.0 // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1501 // indirect
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70 // indirect
github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible // indirect
github.com/antchfx/xmlquery v1.3.5 // indirect
github.com/antchfx/xpath v1.1.10 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.44.122 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.4 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.57 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.31 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.39.8 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.38.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.5.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.12 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.75.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sns v1.33.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.37.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.12 // indirect
github.com/aws/smithy-go v1.22.2 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/cli/go-gh/v2 v2.11.2 // indirect
github.com/cli/safeexec v1.0.1 // indirect
github.com/cloudflare/circl v1.4.0 // indirect
github.com/creack/pty v1.1.17 // indirect
github.com/dylanmei/iso8601 v0.1.0 // indirect
github.com/fatih/color v1.9.0 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gofrs/flock v0.10.0 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-github/v45 v45.2.0 // indirect
github.com/google/go-github/v62 v62.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.62 // indirect
github.com/hashicorp/consul/api v1.13.0 // indirect
github.com/hashicorp/copywrite v0.20.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-azure-helpers v0.72.0 // indirect
github.com/hashicorp/go-azure-sdk/resource-manager v0.20250131.1134653 // indirect
github.com/hashicorp/go-azure-sdk/sdk v0.20250131.1134653 // indirect
github.com/hashicorp/go-cty v1.4.1 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.5.4 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-slug v0.9.1 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect
github.com/hashicorp/serf v0.9.5 // indirect
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/serf v0.9.6 // indirect
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackofallops/giovanni v0.28.0 // indirect
github.com/jedib0t/go-pretty v4.3.0+incompatible // indirect
github.com/jedib0t/go-pretty/v6 v6.5.9 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jstemmer/go-junit-report v0.9.1 // indirect
github.com/klauspost/compress v1.11.2 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/manicminer/hamilton-autorest v0.2.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/knadh/koanf v1.5.0 // indirect
github.com/lib/pq v1.10.3 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/mitchellh/go-testing-interface v1.0.4 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mergestat/timediff v0.0.3 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/iochan v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mozillazg/go-httpheader v0.3.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oracle/oci-go-sdk/v65 v65.89.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/samber/lo v1.47.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.1.1 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
github.com/vmihailenco/tagparser v0.1.1 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.588 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.588 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.233 // indirect
github.com/tencentyun/cos-go-sdk-v5 v0.7.42 // indirect
github.com/thanhpk/randstr v1.0.6 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver v1.16.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.59.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.155.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
k8s.io/api v0.25.5 // indirect
k8s.io/apimachinery v0.25.5 // indirect
k8s.io/client-go v0.25.5 // indirect
k8s.io/klog/v2 v2.70.1 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect
)
go 1.18
// Some of the packages in this codebase are split into separate Go modules
// just so that we can more easily determine how dependency updates might
// affect components with different code ownership. These modules are never
// actually published separately from the toplevel module, and so we exclusively
// use the "pseudo-revisions" generated by the Go toolchain to describe them
// in go.mod files.
//
// If you change the dependencies of any one of these components, use
// "make syncdeps" to resynchronize the others. That will then make sure that
// your updates will be visible to the code owners of each affected component.
//
// In the long run we want to make each of these either move to another codebase
// or get deleted entirely, but as long as we keep maintaining this all together
// in one codebase this is a pragmatic compromise to help us understand the
// impact of and responsibilities for dependency upgrades.
//
// We don't expect to add any new modules here because the ones that are here
// are here just as technical debt. If you _do_ end up adding another one,
// you'll need to add similar replace directives to each of the other modules
// so that they all agree with each other that we're never publishing any of
// these modules as a separate unit. (But please add to this only as a last
// resort!)
replace github.com/hashicorp/terraform/internal/backend/remote-state/azure => ./internal/backend/remote-state/azure
replace github.com/hashicorp/terraform/internal/backend/remote-state/consul => ./internal/backend/remote-state/consul
replace github.com/hashicorp/terraform/internal/backend/remote-state/cos => ./internal/backend/remote-state/cos
replace github.com/hashicorp/terraform/internal/backend/remote-state/gcs => ./internal/backend/remote-state/gcs
replace github.com/hashicorp/terraform/internal/backend/remote-state/kubernetes => ./internal/backend/remote-state/kubernetes
replace github.com/hashicorp/terraform/internal/backend/remote-state/oss => ./internal/backend/remote-state/oss
replace github.com/hashicorp/terraform/internal/backend/remote-state/pg => ./internal/backend/remote-state/pg
replace github.com/hashicorp/terraform/internal/backend/remote-state/s3 => ./internal/backend/remote-state/s3
replace github.com/hashicorp/terraform/internal/backend/remote-state/oci => ./internal/backend/remote-state/oci
replace github.com/hashicorp/terraform/internal/legacy => ./internal/legacy
tool (
github.com/hashicorp/copywrite
github.com/nishanths/exhaustive/cmd/exhaustive
go.uber.org/mock/mockgen
golang.org/x/tools/cmd/cover
golang.org/x/tools/cmd/goimports
golang.org/x/tools/cmd/stringer
honnef.co/go/tools/cmd/staticcheck
)

1960
go.sum

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package main
import (
@ -7,7 +10,7 @@ import (
"sort"
"strings"
"github.com/mitchellh/cli"
"github.com/hashicorp/cli"
)
// helpFunc is a cli.HelpFunc that can be used to output the help CLI instructions for Terraform.
@ -57,7 +60,7 @@ All other commands:
Global options (use these before the subcommand, if any):
-chdir=DIR Switch to a different working directory before executing the
given subcommand.
-help Show this help output, or the help for a specified subcommand.
-help Show this help output or the help for a specified subcommand.
-version An alias for the "version" subcommand.
`, listCommands(commands, PrimaryCommands, maxKeyLen), listCommands(commands, otherCommands, maxKeyLen))

329
internal/addrs/action.go Normal file
View file

@ -0,0 +1,329 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"fmt"
"strings"
)
// Action is an address for an action block within configuration, which
// contains potentially-multiple action instances if that configuration
// block uses "count" or "for_each".
type Action struct {
referenceable
Type string
Name string
}
func (a Action) String() string {
return fmt.Sprintf("action.%s.%s", a.Type, a.Name)
}
func (a Action) Equal(o Action) bool {
return a.Name == o.Name && a.Type == o.Type
}
func (a Action) Less(o Action) bool {
switch {
case a.Type != o.Type:
return a.Type < o.Type
case a.Name != o.Name:
return a.Name < o.Name
default:
return false
}
}
func (a Action) UniqueKey() UniqueKey {
return a // An Action is its own UniqueKey
}
func (a Action) uniqueKeySigil() {}
// Instance produces the address for a specific instance of the receiver
// that is identified by the given key.
func (a Action) Instance(key InstanceKey) ActionInstance {
return ActionInstance{
Action: a,
Key: key,
}
}
// Absolute returns an AbsAction from the receiver and the given module
// instance address.
func (a Action) Absolute(module ModuleInstance) AbsAction {
return AbsAction{
Module: module,
Action: a,
}
}
// InModule returns a ConfigAction from the receiver and the given module
// address.
func (a Action) InModule(module Module) ConfigAction {
return ConfigAction{
Module: module,
Action: a,
}
}
// ImpliedProvider returns the implied provider type name, for e.g. the "aws" in
// "aws_instance"
func (a Action) ImpliedProvider() string {
typeName := a.Type
if under := strings.Index(typeName, "_"); under != -1 {
typeName = typeName[:under]
}
return typeName
}
// ActionInstance is an address for a specific instance of an action.
// When an action is defined in configuration with "count" or "for_each" it
// produces zero or more instances, which can be addressed using this type.
type ActionInstance struct {
referenceable
Action Action
Key InstanceKey
}
func (a ActionInstance) ContainingAction() Action {
return a.Action
}
func (a ActionInstance) String() string {
if a.Key == NoKey {
return a.Action.String()
}
return a.Action.String() + a.Key.String()
}
func (a ActionInstance) Equal(o ActionInstance) bool {
return a.Key == o.Key && a.Action.Equal(o.Action)
}
func (a ActionInstance) Less(o ActionInstance) bool {
if !a.Action.Equal(o.Action) {
return a.Action.Less(o.Action)
}
if a.Key != o.Key {
return InstanceKeyLess(a.Key, o.Key)
}
return false
}
func (a ActionInstance) UniqueKey() UniqueKey {
return a // An ActionInstance is its own UniqueKey
}
func (a ActionInstance) uniqueKeySigil() {}
// Absolute returns an AbsActionInstance from the receiver and the given module
// instance address.
func (a ActionInstance) Absolute(module ModuleInstance) AbsActionInstance {
return AbsActionInstance{
Module: module,
Action: a,
}
}
// AbsAction is an absolute address for an action under a given module path.
type AbsAction struct {
Module ModuleInstance
Action Action
}
// Action returns the address of a particular action within the receiver.
func (m ModuleInstance) Action(typeName string, name string) AbsAction {
return AbsAction{
Module: m,
Action: Action{
Type: typeName,
Name: name,
},
}
}
// Instance produces the address for a specific instance of the receiver that is
// identified by the given key.
func (a AbsAction) Instance(key InstanceKey) AbsActionInstance {
return AbsActionInstance{
Module: a.Module,
Action: a.Action.Instance(key),
}
}
// Config returns the unexpanded ConfigAction for this AbsAction.
func (a AbsAction) Config() ConfigAction {
return ConfigAction{
Module: a.Module.Module(),
Action: a.Action,
}
}
func (a AbsAction) String() string {
if len(a.Module) == 0 {
return a.Action.String()
}
return fmt.Sprintf("%s.%s", a.Module.String(), a.Action.String())
}
// AffectedAbsAction returns the AbsAction.
func (a AbsAction) AffectedAbsAction() AbsAction {
return a
}
func (a AbsAction) Equal(o AbsAction) bool {
return a.Module.Equal(o.Module) && a.Action.Equal(o.Action)
}
func (a AbsAction) Less(o AbsAction) bool {
if !a.Module.Equal(o.Module) {
return a.Module.Less(o.Module)
}
if !a.Action.Equal(o.Action) {
return a.Action.Less(o.Action)
}
return false
}
type absActionKey string
func (a absActionKey) uniqueKeySigil() {}
func (a AbsAction) UniqueKey() UniqueKey {
return absActionKey(a.String())
}
// AbsActionInstance is an absolute address for an action instance under a
// given module path.
type AbsActionInstance struct {
Module ModuleInstance
Action ActionInstance
}
// ActionInstance returns the address of a particular action instance within the receiver.
func (m ModuleInstance) ActionInstance(typeName string, name string, key InstanceKey) AbsActionInstance {
return AbsActionInstance{
Module: m,
Action: ActionInstance{
Action: Action{
Type: typeName,
Name: name,
},
Key: key,
},
}
}
// ContainingAction returns the address of the action that contains the
// receiving action instance. In other words, it discards the key portion of the
// address to produce an AbsAction value.
func (a AbsActionInstance) ContainingAction() AbsAction {
return AbsAction{
Module: a.Module,
Action: a.Action.ContainingAction(),
}
}
// ConfigAction returns the address of the configuration block that declared
// this instance.
func (a AbsActionInstance) ConfigAction() ConfigAction {
return ConfigAction{
Module: a.Module.Module(),
Action: a.Action.Action,
}
}
func (a AbsActionInstance) String() string {
if len(a.Module) == 0 {
return a.Action.String()
}
return fmt.Sprintf("%s.%s", a.Module.String(), a.Action.String())
}
// AffectedAbsAction returns the AbsAction for the instance.
func (a AbsActionInstance) AffectedAbsAction() AbsAction {
return AbsAction{
Module: a.Module,
Action: a.Action.Action,
}
}
func (a AbsActionInstance) Equal(o AbsActionInstance) bool {
return a.Module.Equal(o.Module) && a.Action.Equal(o.Action)
}
// Less returns true if the receiver should sort before the given other value
// in a sorted list of addresses.
func (a AbsActionInstance) Less(o AbsActionInstance) bool {
if !a.Module.Equal(o.Module) {
return a.Module.Less(o.Module)
}
if !a.Action.Equal(o.Action) {
return a.Action.Less(o.Action)
}
return false
}
type absActionInstanceKey string
func (a AbsActionInstance) UniqueKey() UniqueKey {
return absActionInstanceKey(a.String())
}
func (r absActionInstanceKey) uniqueKeySigil() {}
// ConfigAction is the address for an action within the configuration.
type ConfigAction struct {
Module Module
Action Action
}
// Action returns the address of a particular action within the module.
func (m Module) Action(typeName string, name string) ConfigAction {
return ConfigAction{
Module: m,
Action: Action{
Type: typeName,
Name: name,
},
}
}
// Absolute produces the address for the receiver within a specific module instance.
func (a ConfigAction) Absolute(module ModuleInstance) AbsAction {
return AbsAction{
Module: module,
Action: a.Action,
}
}
func (a ConfigAction) String() string {
if len(a.Module) == 0 {
return a.Action.String()
}
return fmt.Sprintf("%s.%s", a.Module.String(), a.Action.String())
}
func (a ConfigAction) Equal(o ConfigAction) bool {
return a.Module.Equal(o.Module) && a.Action.Equal(o.Action)
}
func (a ConfigAction) UniqueKey() UniqueKey {
return configActionKey(a.String())
}
type configActionKey string
func (k configActionKey) uniqueKeySigil() {}

View file

@ -0,0 +1,343 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"fmt"
"testing"
)
func TestActionEqual(t *testing.T) {
actions := []Action{
{Type: "foo", Name: "bar"},
{Type: "the", Name: "bloop"},
}
for _, r := range actions {
t.Run(r.String(), func(t *testing.T) {
if !r.Equal(r) {
t.Fatalf("expected %#v to be equal to itself", r)
}
})
}
// not equal
testCases := []struct {
right Action
left Action
}{
{
Action{Type: "a", Name: "b"},
Action{Type: "b", Name: "b"},
},
{
Action{Type: "a", Name: "b"},
Action{Type: "a", Name: "c"},
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
if tc.left.Equal(tc.right) {
t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
}
if tc.right.Equal(tc.left) {
t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
}
})
}
}
func TestActionInstanceEqual(t *testing.T) {
actions := []ActionInstance{
{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
{
Action: Action{Type: "the", Name: "bloop"},
Key: StringKey("fish"),
},
}
for _, r := range actions {
t.Run(r.String(), func(t *testing.T) {
if !r.Equal(r) {
t.Fatalf("expected %#v to be equal to itself", r)
}
})
}
// not equal
testCases := []struct {
right ActionInstance
left ActionInstance
}{
{
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: IntKey(1),
},
},
{
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
ActionInstance{
Action: Action{Type: "baz", Name: "bat"},
Key: IntKey(1),
},
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
if tc.left.Equal(tc.right) {
t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
}
if tc.right.Equal(tc.left) {
t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
}
})
}
}
func TestAbsActionInstanceEqual(t *testing.T) {
actions := []AbsActionInstance{
{
RootModuleInstance,
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
},
{
mustParseModuleInstanceStr("module.child"),
ActionInstance{
Action: Action{Type: "the", Name: "bloop"},
Key: StringKey("fish"),
},
},
}
for _, r := range actions {
t.Run(r.String(), func(t *testing.T) {
if !r.Equal(r) {
t.Fatalf("expected %#v to be equal to itself", r)
}
})
}
// not equal
testCases := []struct {
right AbsActionInstance
left AbsActionInstance
}{
{ // different keys
AbsActionInstance{
RootModuleInstance,
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
},
AbsActionInstance{
RootModuleInstance,
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: IntKey(1),
},
},
},
{ // different module
AbsActionInstance{
RootModuleInstance,
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
},
AbsActionInstance{
mustParseModuleInstanceStr("module.child[1]"),
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: NoKey,
},
},
},
{ // totally different
AbsActionInstance{
RootModuleInstance,
ActionInstance{
Action: Action{Type: "oof", Name: "rab"},
Key: NoKey,
},
},
AbsActionInstance{
mustParseModuleInstanceStr("module.foo"),
ActionInstance{
Action: Action{Type: "foo", Name: "bar"},
Key: IntKey(11),
},
},
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
if tc.left.Equal(tc.right) {
t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
}
if tc.right.Equal(tc.left) {
t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
}
})
}
}
// TestConfigActionEqual
func TestConfigActionEqual(t *testing.T) {
actions := []ConfigAction{
{
RootModule,
Action{Type: "foo", Name: "bar"},
},
{
Module{"child"},
Action{Type: "the", Name: "bloop"},
},
}
for _, r := range actions {
t.Run(r.String(), func(t *testing.T) {
if !r.Equal(r) {
t.Fatalf("expected %#v to be equal to itself", r)
}
})
}
// not equal
testCases := []struct {
right ConfigAction
left ConfigAction
}{
{ // different name
ConfigAction{
RootModule,
Action{Type: "foo", Name: "bar"},
},
ConfigAction{
RootModule,
Action{Type: "foo", Name: "baz"},
},
},
// different type
{
ConfigAction{
RootModule,
Action{Type: "foo", Name: "bar"},
},
ConfigAction{
RootModule,
Action{Type: "baz", Name: "bar"},
},
},
// different Module
{
ConfigAction{
RootModule,
Action{Type: "foo", Name: "bar"},
},
ConfigAction{
Module{"mod"},
Action{Type: "foo", Name: "bar"},
},
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
if tc.left.Equal(tc.right) {
t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
}
if tc.right.Equal(tc.left) {
t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
}
})
}
}
// TestAbsActionUniqueKey
func TestAbsActionUniqueKey(t *testing.T) {
actionAddr1 := Action{
Type: "a",
Name: "b1",
}.Absolute(RootModuleInstance)
actionAddr2 := Action{
Type: "a",
Name: "b2",
}.Absolute(RootModuleInstance)
actionAddr3 := Action{
Type: "a",
Name: "in_module",
}.Absolute(RootModuleInstance.Child("boop", NoKey))
tests := []struct {
Receiver AbsAction
Other UniqueKeyer
WantEqual bool
}{
{
actionAddr1,
actionAddr1,
true,
},
{
actionAddr1,
actionAddr2,
false,
},
{
actionAddr1,
actionAddr3,
false,
},
{
actionAddr3,
actionAddr3,
true,
},
{
actionAddr1,
actionAddr1.Instance(NoKey),
false, // no-key instance key is distinct from its resource even though they have the same String result
},
{
actionAddr1,
actionAddr1.Instance(IntKey(1)),
false,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%s matches %T %s?", test.Receiver, test.Other, test.Other), func(t *testing.T) {
rKey := test.Receiver.UniqueKey()
oKey := test.Other.UniqueKey()
gotEqual := rKey == oKey
if gotEqual != test.WantEqual {
t.Errorf(
"wrong result\nreceiver: %s\nother: %s (%T)\ngot: %t\nwant: %t",
test.Receiver, test.Other, test.Other,
gotEqual, test.WantEqual,
)
}
})
}
}

View file

@ -1,251 +1,134 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"fmt"
import "fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// Check is the address of a check rule within a checkable object.
// Check is the address of a check block within a module.
//
// This represents the check rule globally within a configuration, and is used
// during graph evaluation to identify a condition result object to update with
// the result of check rule evaluation.
//
// The check address is not distinct from resource traversals, and check rule
// values are not intended to be available to the language, so the address is
// not Referenceable.
//
// Note also that the check address is only relevant within the scope of a run,
// as reordering check blocks between runs will result in their addresses
// changing. Check is therefore for internal use only and should not be exposed
// in durable artifacts such as state snapshots.
// For now, checks do not support meta arguments such as "count" or "for_each"
// so this address uniquely describes a single check within a module.
type Check struct {
Container Checkable
Type CheckType
Index int
}
func NewCheck(container Checkable, typ CheckType, index int) Check {
return Check{
Container: container,
Type: typ,
Index: index,
}
referenceable
Name string
}
func (c Check) String() string {
container := c.Container.String()
switch c.Type {
case ResourcePrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case ResourcePostcondition:
return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
case OutputPrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
default:
// This should not happen
return fmt.Sprintf("%s.condition[%d]", container, c.Index)
return fmt.Sprintf("check.%s", c.Name)
}
// InModule returns a ConfigCheck from the receiver and the given module
// address.
func (c Check) InModule(modAddr Module) ConfigCheck {
return ConfigCheck{
Module: modAddr,
Check: c,
}
}
// Absolute returns an AbsCheck from the receiver and the given module instance
// address.
func (c Check) Absolute(modAddr ModuleInstance) AbsCheck {
return AbsCheck{
Module: modAddr,
Check: c,
}
}
func (c Check) Equal(o Check) bool {
return c.Name == o.Name
}
func (c Check) UniqueKey() UniqueKey {
return checkKey{
ContainerKey: c.Container.UniqueKey(),
Type: c.Type,
Index: c.Index,
}
return c // A Check is its own UniqueKey
}
type checkKey struct {
ContainerKey UniqueKey
Type CheckType
Index int
}
func (c Check) uniqueKeySigil() {}
func (k checkKey) uniqueKeySigil() {}
// CheckType describes a category of check. We use this only to establish
// uniqueness for Check values, and do not expose this concept of "check types"
// (which is subject to change in future) in any durable artifacts such as
// state snapshots.
// ConfigCheck is an address for a check block within a configuration.
//
// (See [CheckableKind] for an enumeration that we _do_ use externally, to
// describe the type of object being checked rather than the type of the check
// itself.)
type CheckType int
// This contains a Check address and a Module address, meaning this describes
// a check block within the entire configuration.
type ConfigCheck struct {
Module Module
Check Check
}
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckType check.go
var _ ConfigCheckable = ConfigCheck{}
const (
InvalidCondition CheckType = 0
ResourcePrecondition CheckType = 1
ResourcePostcondition CheckType = 2
OutputPrecondition CheckType = 3
)
func (c ConfigCheck) UniqueKey() UniqueKey {
return configCheckUniqueKey(c.String())
}
// Description returns a human-readable description of the check type. This is
// presented in the user interface through a diagnostic summary.
func (c CheckType) Description() string {
switch c {
case ResourcePrecondition:
return "Resource precondition"
case ResourcePostcondition:
return "Resource postcondition"
case OutputPrecondition:
return "Module output value precondition"
default:
// This should not happen
return "Condition"
func (c ConfigCheck) configCheckableSigil() {}
func (c ConfigCheck) CheckableKind() CheckableKind {
return CheckableCheck
}
func (c ConfigCheck) String() string {
if len(c.Module) == 0 {
return c.Check.String()
}
return fmt.Sprintf("%s.%s", c.Module, c.Check)
}
// Checkable is an interface implemented by all address types that can contain
// condition blocks.
type Checkable interface {
UniqueKeyer
checkableSigil()
// Check returns the address of an individual check rule of a specified
// type and index within this checkable container.
Check(CheckType, int) Check
// ConfigCheckable returns the address of the configuration construct that
// this Checkable belongs to.
//
// Checkable objects can potentially be dynamically declared during a
// plan operation using constructs like resource for_each, and so
// ConfigCheckable gives us a way to talk about the static containers
// those dynamic objects belong to, in case we wish to group together
// dynamic checkable objects into their static checkable for reporting
// purposes.
ConfigCheckable() ConfigCheckable
CheckableKind() CheckableKind
String() string
}
var (
_ Checkable = AbsResourceInstance{}
_ Checkable = AbsOutputValue{}
)
// CheckableKind describes the different kinds of checkable objects.
type CheckableKind rune
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckableKind check.go
const (
CheckableKindInvalid CheckableKind = 0
CheckableResource CheckableKind = 'R'
CheckableOutputValue CheckableKind = 'O'
)
// ConfigCheckable is an interfaces implemented by address types that represent
// configuration constructs that can have Checkable addresses associated with
// them.
// AbsCheck is an absolute address for a check block under a given module path.
//
// This address type therefore in a sense represents a container for zero or
// more checkable objects all declared by the same configuration construct,
// so that we can talk about these groups of checkable objects before we're
// ready to decide how many checkable objects belong to each one.
type ConfigCheckable interface {
UniqueKeyer
configCheckableSigil()
CheckableKind() CheckableKind
String() string
// This contains an actual ModuleInstance address (compared to the Module within
// a ConfigCheck), meaning this uniquely describes a check block within the
// entire configuration after any "count" or "foreach" meta arguments have been
// evaluated on the containing module.
type AbsCheck struct {
Module ModuleInstance
Check Check
}
var (
_ ConfigCheckable = ConfigResource{}
_ ConfigCheckable = ConfigOutputValue{}
)
var _ Checkable = AbsCheck{}
// ParseCheckableStr attempts to parse the given string as a Checkable address
// of the given kind.
func (c AbsCheck) UniqueKey() UniqueKey {
return absCheckUniqueKey(c.String())
}
func (c AbsCheck) checkableSigil() {}
// CheckRule returns an address for a given rule type within the check block.
//
// This should be the opposite of Checkable.String for any Checkable address
// type, as long as "kind" is set to the value returned by the address's
// CheckableKind method.
//
// We do not typically expect users to write out checkable addresses as input,
// but we use them as part of some of our wire formats for persisting check
// results between runs.
func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(src), "", hcl.InitialPos)
diags = diags.Append(parseDiags)
if parseDiags.HasErrors() {
return nil, diags
}
path, remain, diags := parseModuleInstancePrefix(traversal)
if diags.HasErrors() {
return nil, diags
}
if remain.IsRelative() {
// (relative means that there's either nothing left or what's next isn't an identifier)
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Module path must be followed by either a resource instance address or an output value address.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
// We use "kind" to disambiguate here because unfortunately we've
// historically never reserved "output" as a possible resource type name
// and so it is in principle possible -- albeit unlikely -- that there
// might be a resource whose type is literally "output".
switch kind {
case CheckableResource:
riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
diags = diags.Append(moreDiags)
if diags.HasErrors() {
return nil, diags
}
return riAddr, diags
case CheckableOutputValue:
if len(remain) != 2 {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must have only one attribute part after the keyword 'output', giving the name of the output value.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
if remain.RootName() != "output" {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must follow the module address with the keyword 'output'.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
if step, ok := remain[1].(hcl.TraverseAttr); !ok {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must have only one attribute part after the keyword 'output', giving the name of the output value.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
} else {
return OutputValue{Name: step.Name}.Absolute(path), diags
}
default:
panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
// There will be at most one CheckDataResource rule within a check block (with
// an index of 0). There will be at least one, but potentially many,
// CheckAssertion rules within a check block.
func (c AbsCheck) CheckRule(typ CheckRuleType, i int) CheckRule {
return CheckRule{
Container: c,
Type: typ,
Index: i,
}
}
// ConfigCheckable returns the ConfigCheck address for this absolute reference.
func (c AbsCheck) ConfigCheckable() ConfigCheckable {
return ConfigCheck{
Module: c.Module.Module(),
Check: c.Check,
}
}
func (c AbsCheck) CheckableKind() CheckableKind {
return CheckableCheck
}
func (c AbsCheck) String() string {
if len(c.Module) == 0 {
return c.Check.String()
}
return fmt.Sprintf("%s.%s", c.Module, c.Check)
}
type configCheckUniqueKey string
func (k configCheckUniqueKey) uniqueKeySigil() {}
type absCheckUniqueKey string
func (k absCheckUniqueKey) uniqueKeySigil() {}

View file

@ -0,0 +1,117 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"fmt"
)
// CheckRule is the address of a check rule within a checkable object.
//
// This represents the check rule globally within a configuration, and is used
// during graph evaluation to identify a condition result object to update with
// the result of check rule evaluation.
//
// The check address is not distinct from resource traversals, and check rule
// values are not intended to be available to the language, so the address is
// not Referenceable.
//
// Note also that the check address is only relevant within the scope of a run,
// as reordering check blocks between runs will result in their addresses
// changing. CheckRule is therefore for internal use only and should not be
// exposed in durable artifacts such as state snapshots.
type CheckRule struct {
Container Checkable
Type CheckRuleType
Index int
}
func NewCheckRule(container Checkable, typ CheckRuleType, index int) CheckRule {
return CheckRule{
Container: container,
Type: typ,
Index: index,
}
}
func (c CheckRule) String() string {
container := c.Container.String()
switch c.Type {
case ResourcePrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case ResourcePostcondition:
return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
case OutputPrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case CheckDataResource:
return fmt.Sprintf("%s.data[%d]", container, c.Index)
case CheckAssertion:
return fmt.Sprintf("%s.assert[%d]", container, c.Index)
case InputValidation:
return fmt.Sprintf("%s.validation[%d]", container, c.Index)
default:
// This should not happen
return fmt.Sprintf("%s.condition[%d]", container, c.Index)
}
}
func (c CheckRule) UniqueKey() UniqueKey {
return checkRuleKey{
ContainerKey: c.Container.UniqueKey(),
Type: c.Type,
Index: c.Index,
}
}
type checkRuleKey struct {
ContainerKey UniqueKey
Type CheckRuleType
Index int
}
func (k checkRuleKey) uniqueKeySigil() {}
// CheckRuleType describes a category of check. We use this only to establish
// uniqueness for Check values, and do not expose this concept of "check types"
// (which is subject to change in future) in any durable artifacts such as
// state snapshots.
//
// (See [CheckableKind] for an enumeration that we _do_ use externally, to
// describe the type of object being checked rather than the type of the check
// itself.)
type CheckRuleType int
//go:generate go tool golang.org/x/tools/cmd/stringer -type=CheckRuleType check_rule.go
const (
InvalidCondition CheckRuleType = 0
ResourcePrecondition CheckRuleType = 1
ResourcePostcondition CheckRuleType = 2
OutputPrecondition CheckRuleType = 3
CheckDataResource CheckRuleType = 4
CheckAssertion CheckRuleType = 5
InputValidation CheckRuleType = 6
)
// Description returns a human-readable description of the check type. This is
// presented in the user interface through a diagnostic summary.
func (c CheckRuleType) Description() string {
switch c {
case ResourcePrecondition:
return "Resource precondition"
case ResourcePostcondition:
return "Resource postcondition"
case OutputPrecondition:
return "Module output value precondition"
case CheckDataResource:
return "Check block data resource"
case CheckAssertion:
return "Check block assertion"
case InputValidation:
return "Input variable validation"
default:
// This should not happen
return "Condition"
}
}

View file

@ -0,0 +1,73 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import "github.com/hashicorp/terraform/internal/tfdiags"
// DiagnosticExtraCheckRule provides an interface for diagnostic ExtraInfo to
// retrieve an embedded CheckRule from within a tfdiags.Diagnostic.
type DiagnosticExtraCheckRule interface {
// DiagnosticOriginatesFromCheckRule returns the CheckRule that the
// surrounding diagnostic originated from.
DiagnosticOriginatesFromCheckRule() CheckRule
}
// DiagnosticOriginatesFromCheckRule checks if the provided diagnostic contains
// a CheckRule as ExtraInfo and returns that CheckRule and true if it does. This
// function returns an empty CheckRule and false if the diagnostic does not
// contain a CheckRule.
func DiagnosticOriginatesFromCheckRule(diag tfdiags.Diagnostic) (CheckRule, bool) {
maybe := tfdiags.ExtraInfo[DiagnosticExtraCheckRule](diag)
if maybe == nil {
return CheckRule{}, false
}
return maybe.DiagnosticOriginatesFromCheckRule(), true
}
// CheckRuleDiagnosticExtra is an object that can be attached to diagnostics
// that originate from check rules.
//
// It implements the DiagnosticExtraCheckRule interface for retrieving the
// concrete CheckRule that spawned the diagnostic.
//
// It also implements the tfdiags.DiagnosticExtraDoNotConsolidate interface, to
// stop diagnostics created by check blocks being consolidated.
//
// It also implements the tfdiags.DiagnosticExtraUnwrapper interface, as nested
// data blocks will attach this struct but do want to lose any extra info
// embedded in the original diagnostic.
type CheckRuleDiagnosticExtra struct {
CheckRule CheckRule
wrapped interface{}
}
var (
_ DiagnosticExtraCheckRule = (*CheckRuleDiagnosticExtra)(nil)
_ tfdiags.DiagnosticExtraDoNotConsolidate = (*CheckRuleDiagnosticExtra)(nil)
_ tfdiags.DiagnosticExtraUnwrapper = (*CheckRuleDiagnosticExtra)(nil)
_ tfdiags.DiagnosticExtraWrapper = (*CheckRuleDiagnosticExtra)(nil)
)
func (c *CheckRuleDiagnosticExtra) UnwrapDiagnosticExtra() interface{} {
return c.wrapped
}
func (c *CheckRuleDiagnosticExtra) WrapDiagnosticExtra(inner interface{}) {
if c.wrapped != nil {
// This is a logical inconsistency, the caller should know whether they
// have already wrapped an extra or not.
panic("Attempted to wrap a diagnostic extra into a CheckRuleDiagnosticExtra that is already wrapping a different extra. This is a bug in Terraform, please report it.")
}
c.wrapped = inner
}
func (c *CheckRuleDiagnosticExtra) DoNotConsolidateDiagnostic() bool {
// Do not consolidate warnings from check blocks.
return c.CheckRule.Container.CheckableKind() == CheckableCheck
}
func (c *CheckRuleDiagnosticExtra) DiagnosticOriginatesFromCheckRule() CheckRule {
return c.CheckRule
}

View file

@ -0,0 +1,111 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/tfdiags"
)
func TestCheckRuleDiagnosticExtra_WrapsExtra(t *testing.T) {
var originals tfdiags.Diagnostics
originals = originals.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
Extra: "extra",
})
overridden := tfdiags.OverrideAll(originals, tfdiags.Warning, func() tfdiags.DiagnosticExtraWrapper {
return &CheckRuleDiagnosticExtra{}
})
if overridden[0].ExtraInfo().(*CheckRuleDiagnosticExtra).wrapped.(string) != "extra" {
t.Errorf("unexpected extra info: %v", overridden[0].ExtraInfo())
}
}
func TestCheckRuleDiagnosticExtra_Unwraps(t *testing.T) {
var originals tfdiags.Diagnostics
originals = originals.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
Extra: "extra",
})
overridden := tfdiags.OverrideAll(originals, tfdiags.Warning, func() tfdiags.DiagnosticExtraWrapper {
return &CheckRuleDiagnosticExtra{}
})
result := tfdiags.ExtraInfo[string](overridden[0])
if result != "extra" {
t.Errorf("unexpected extra info: %v", result)
}
}
func TestCheckRuleDiagnosticExtra_DoNotConsolidate(t *testing.T) {
var diags tfdiags.Diagnostics
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
Extra: &CheckRuleDiagnosticExtra{
CheckRule: NewCheckRule(AbsOutputValue{
Module: RootModuleInstance,
OutputValue: OutputValue{
Name: "output",
},
}, OutputPrecondition, 0),
},
})
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
Extra: &CheckRuleDiagnosticExtra{
CheckRule: NewCheckRule(AbsCheck{
Module: RootModuleInstance,
Check: Check{
Name: "check",
},
}, CheckAssertion, 0),
},
})
if tfdiags.DoNotConsolidateDiagnostic(diags[0]) {
t.Errorf("first diag should be consolidated but was not")
}
if !tfdiags.DoNotConsolidateDiagnostic(diags[1]) {
t.Errorf("second diag should not be consolidated but was")
}
}
func TestDiagnosticOriginatesFromCheckRule_Passes(t *testing.T) {
var diags tfdiags.Diagnostics
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
})
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "original error",
Detail: "this is an error",
Extra: &CheckRuleDiagnosticExtra{},
})
if _, ok := DiagnosticOriginatesFromCheckRule(diags[0]); ok {
t.Errorf("first diag did not originate from check rule but thinks it did")
}
if _, ok := DiagnosticOriginatesFromCheckRule(diags[1]); !ok {
t.Errorf("second diag did originate from check rule but this it did not")
}
}

194
internal/addrs/checkable.go Normal file
View file

@ -0,0 +1,194 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
import (
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// Checkable is an interface implemented by all address types that can contain
// condition blocks.
type Checkable interface {
UniqueKeyer
checkableSigil()
// CheckRule returns the address of an individual check rule of a specified
// type and index within this checkable container.
CheckRule(CheckRuleType, int) CheckRule
// ConfigCheckable returns the address of the configuration construct that
// this Checkable belongs to.
//
// Checkable objects can potentially be dynamically declared during a
// plan operation using constructs like resource for_each, and so
// ConfigCheckable gives us a way to talk about the static containers
// those dynamic objects belong to, in case we wish to group together
// dynamic checkable objects into their static checkable for reporting
// purposes.
ConfigCheckable() ConfigCheckable
CheckableKind() CheckableKind
String() string
}
var (
_ Checkable = AbsResourceInstance{}
_ Checkable = AbsOutputValue{}
)
// CheckableKind describes the different kinds of checkable objects.
type CheckableKind rune
//go:generate go tool golang.org/x/tools/cmd/stringer -type=CheckableKind checkable.go
const (
CheckableKindInvalid CheckableKind = 0
CheckableResource CheckableKind = 'R'
CheckableOutputValue CheckableKind = 'O'
CheckableCheck CheckableKind = 'C'
CheckableInputVariable CheckableKind = 'I'
)
// ConfigCheckable is an interfaces implemented by address types that represent
// configuration constructs that can have Checkable addresses associated with
// them.
//
// This address type therefore in a sense represents a container for zero or
// more checkable objects all declared by the same configuration construct,
// so that we can talk about these groups of checkable objects before we're
// ready to decide how many checkable objects belong to each one.
type ConfigCheckable interface {
UniqueKeyer
configCheckableSigil()
CheckableKind() CheckableKind
String() string
}
var (
_ ConfigCheckable = ConfigResource{}
_ ConfigCheckable = ConfigOutputValue{}
)
// ParseCheckableStr attempts to parse the given string as a Checkable address
// of the given kind.
//
// This should be the opposite of Checkable.String for any Checkable address
// type, as long as "kind" is set to the value returned by the address's
// CheckableKind method.
//
// We do not typically expect users to write out checkable addresses as input,
// but we use them as part of some of our wire formats for persisting check
// results between runs.
func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(src), "", hcl.InitialPos)
diags = diags.Append(parseDiags)
if parseDiags.HasErrors() {
return nil, diags
}
path, remain, diags := parseModuleInstancePrefix(traversal, false)
if diags.HasErrors() {
return nil, diags
}
if remain.IsRelative() {
// (relative means that there's either nothing left or what's next isn't an identifier)
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Module path must be followed by either a resource instance address or an output value address.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
getCheckableName := func(keyword string, descriptor string) (string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var name string
if len(remain) != 2 {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
Subject: remain.SourceRange().Ptr(),
})
}
if remain.RootName() != keyword {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must follow the module address with the keyword '%s'.", cases.Title(language.English, cases.NoLower).String(keyword), keyword),
Subject: remain.SourceRange().Ptr(),
})
}
if step, ok := remain[1].(hcl.TraverseAttr); !ok {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
Subject: remain.SourceRange().Ptr(),
})
} else {
name = step.Name
}
return name, diags
}
// We use "kind" to disambiguate here because unfortunately we've
// historically never reserved "output" as a possible resource type name
// and so it is in principle possible -- albeit unlikely -- that there
// might be a resource whose type is literally "output".
switch kind {
case CheckableResource:
riAddr, moreDiags := parseResourceInstanceUnderModule(path, false, remain)
diags = diags.Append(moreDiags)
if diags.HasErrors() {
return nil, diags
}
return riAddr, diags
case CheckableOutputValue:
name, nameDiags := getCheckableName("output", "output value")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return OutputValue{Name: name}.Absolute(path), diags
case CheckableCheck:
name, nameDiags := getCheckableName("check", "check block")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return Check{Name: name}.Absolute(path), diags
case CheckableInputVariable:
name, nameDiags := getCheckableName("var", "variable value")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return InputVariable{Name: name}.Absolute(path), diags
default:
panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
}
}

View file

@ -1,4 +1,4 @@
// Code generated by "stringer -type=CheckableKind check.go"; DO NOT EDIT.
// Code generated by "stringer -type=CheckableKind checkable.go"; DO NOT EDIT.
package addrs
@ -11,22 +11,30 @@ func _() {
_ = x[CheckableKindInvalid-0]
_ = x[CheckableResource-82]
_ = x[CheckableOutputValue-79]
_ = x[CheckableCheck-67]
_ = x[CheckableInputVariable-73]
}
const (
_CheckableKind_name_0 = "CheckableKindInvalid"
_CheckableKind_name_1 = "CheckableOutputValue"
_CheckableKind_name_2 = "CheckableResource"
_CheckableKind_name_1 = "CheckableCheck"
_CheckableKind_name_2 = "CheckableInputVariable"
_CheckableKind_name_3 = "CheckableOutputValue"
_CheckableKind_name_4 = "CheckableResource"
)
func (i CheckableKind) String() string {
switch {
case i == 0:
return _CheckableKind_name_0
case i == 79:
case i == 67:
return _CheckableKind_name_1
case i == 82:
case i == 73:
return _CheckableKind_name_2
case i == 79:
return _CheckableKind_name_3
case i == 82:
return _CheckableKind_name_4
default:
return "CheckableKind(" + strconv.FormatInt(int64(i), 10) + ")"
}

View file

@ -0,0 +1,29 @@
// Code generated by "stringer -type=CheckRuleType check_rule.go"; DO NOT EDIT.
package addrs
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[InvalidCondition-0]
_ = x[ResourcePrecondition-1]
_ = x[ResourcePostcondition-2]
_ = x[OutputPrecondition-3]
_ = x[CheckDataResource-4]
_ = x[CheckAssertion-5]
_ = x[InputValidation-6]
}
const _CheckRuleType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPreconditionCheckDataResourceCheckAssertionInputValidation"
var _CheckRuleType_index = [...]uint8{0, 16, 36, 57, 75, 92, 106, 121}
func (i CheckRuleType) String() string {
if i < 0 || i >= CheckRuleType(len(_CheckRuleType_index)-1) {
return "CheckRuleType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CheckRuleType_name[_CheckRuleType_index[i]:_CheckRuleType_index[i+1]]
}

View file

@ -1,26 +0,0 @@
// Code generated by "stringer -type=CheckType check.go"; DO NOT EDIT.
package addrs
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[InvalidCondition-0]
_ = x[ResourcePrecondition-1]
_ = x[ResourcePostcondition-2]
_ = x[OutputPrecondition-3]
}
const _CheckType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPrecondition"
var _CheckType_index = [...]uint8{0, 16, 36, 57, 75}
func (i CheckType) String() string {
if i < 0 || i >= CheckType(len(_CheckType_index)-1) {
return "CheckType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CheckType_name[_CheckType_index[i]:_CheckType_index[i+1]]
}

View file

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package addrs
// CountAttr is the address of an attribute of the "count" object in

View file

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
// Package addrs contains types that represent "addresses", which are
// references to specific objects within a Terraform configuration or
// state.

Some files were not shown because too many files have changed in this diff Show more