Skip to content

Commit 7b5b22b

Browse files
committed
backport of commit 5c0310c
1 parent 837b88c commit 7b5b22b

File tree

70 files changed

+996
-448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+996
-448
lines changed

.go-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.19.4
1+
1.19.6

CHANGELOG.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,64 @@
1-
## 1.5.0 (Unreleased)
1+
## 1.4.0 (Unreleased)
2+
3+
UPGRADE NOTES:
4+
5+
- config: The `textencodebase64` function when called with encoding "GB18030" will now encode the euro symbol € as the two-byte sequence `0xA2,0xE3`, as required by the GB18030 standard, before applying base64 encoding.
6+
- config: The `textencodebase64` function when called with encoding "GBK" or "CP936" will now encode the euro symbol € as the single byte `0x80` before applying base64 encoding. This matches the behavior of the Windows API when encoding to this Windows-specific character encoding.
7+
- `terraform init`: When interpreting the hostname portion of a provider source address or the address of a module in a module registry, Terraform will now use _non-transitional_ IDNA2008 mapping rules instead of the transitional mapping rules previously used.
8+
9+
This matches a change to [the WHATWG URL spec's rules for interpreting non-ASCII domain names](https://url.spec.whatwg.org/#concept-domain-to-ascii) which is being gradually adopted by web browsers. Terraform aims to follow the interpretation of hostnames used by web browsers for consistency. For some hostnames containing non-ASCII characters this may cause Terraform to now request a different "punycode" hostname when resolving.
10+
- The Terraform plan renderer has been completely rewritten to aid with future Terraform Cloud integration. Users should not see any material change in the plan output between 1.3 and 1.4. Users are encouraged to file reports if they notice material differences, or encounter any bugs or panics during their normal execution of Terraform.
11+
12+
The diff computation and the rendering are now split into separate packages, while previously the rendering was handled as the diff was computed. Going forward, making small changes to the format of the plan will be easier and introducing new types of renderer will be simplified.
13+
14+
BUG FIXES:
15+
16+
* The module installer will now record in its manifest a correct module source URL after normalization when the URL given as input contains both a query string portion and a subdirectory portion. Terraform itself doesn't currently make use of this information and so this is just a cosmetic fix to make the recorded metadata more correct. ([#31636](https://github.com/hashicorp/terraform/issues/31636))
17+
* config: The `yamldecode` function now correctly handles entirely-nil YAML documents. Previously it would incorrectly return an unknown value instead of a null value. It will now return a null value as documented. ([#32151](https://github.com/hashicorp/terraform/issues/32151))
18+
* Ensure correct ordering between data sources and the deletion of managed resource dependencies. ([#32209](https://github.com/hashicorp/terraform/issues/32209))
19+
* Fix Terraform creating objects that should not exist in variables that specify default attributes in optional objects. ([#32178](https://github.com/hashicorp/terraform/issues/32178))
20+
* Fix several Terraform crashes that are caused by HCL creating objects that should not exist in variables that specify default attributes in optional objects within collections. ([#32178](https://github.com/hashicorp/terraform/issues/32178))
21+
* Fix inconsistent behaviour in empty vs null collections. ([#32178](https://github.com/hashicorp/terraform/issues/32178))
22+
* `terraform workspace` now returns a non-zero exit when given an invalid argument ([#31318](https://github.com/hashicorp/terraform/issues/31318))
23+
* Terraform would always plan changes when using a nested set attribute ([#32536](https://github.com/hashicorp/terraform/issues/32536))
24+
* Terraform can now better detect when complex optional+computed object attributes are removed from configuration ([#32551](https://github.com/hashicorp/terraform/issues/32551))
25+
* A new methodology for planning set elements can now better detect optional+computed changes within sets ([#32563](https://github.com/hashicorp/terraform/issues/32563))
26+
* Fix state locking and releasing messages when in `-json` mode, messages will now be written in JSON format ([#32451](https://github.com/hashicorp/terraform/issues/32451))
27+
228

329
ENHANCEMENTS:
4-
* Terraform CLI's local operations mode will now attempt to persist state snapshots to the state storage backend periodically during the apply step, thereby reducing the window for lost data if the Terraform process is aborted unexpectedly. [GH-32680]
5-
* If Terraform CLI recieves SIGINT (or its equivalent on non-Unix platforms) during the apply step then it will immediately try to persist the latest state snapshot to the state storage backend, with the assumption that a graceful shutdown request often typically followed by a hard abort some time later if the graceful shutdown doesn't complete fast enough. [GH-32680]
30+
31+
* `terraform plan` can now store a plan file even when encountering errors, which can later be inspected to help identify the source of the failures ([#32395](https://github.com/hashicorp/terraform/issues/32395))
32+
* `terraform_data` is a new builtin managed resource type, which can replace the use of `null_resource`, and can store data of any type ([#31757](https://github.com/hashicorp/terraform/issues/31757))
33+
* `terraform init` will now ignore entries in the optional global provider cache directory unless they match a checksum already tracked in the current configuration's dependency lock file. This therefore avoids the long-standing problem that when installing a new provider for the first time from the cache we can't determine the full set of checksums to include in the lock file. Once the lock file has been updated to include a checksum covering the item in the global cache, Terraform will then use the cache entry for subsequent installation of the same provider package. There is an interim CLI configuration opt-out for those who rely on the previous incorrect behavior. ([#32129](https://github.com/hashicorp/terraform/issues/32129))
34+
* Interactive input for sensitive variables is now masked in the UI ([#29520](https://github.com/hashicorp/terraform/issues/29520))
35+
* A new `-or-create` flag was added to `terraform workspace select`, to aid in creating workspaces in automated situations ([#31633](https://github.com/hashicorp/terraform/issues/31633))
36+
* A new command was added for exporting Terraform function signatures in machine-readable format: `terraform metadata functions -json` ([#32487](https://github.com/hashicorp/terraform/issues/32487))
37+
* The "Failed to install provider" error message now includes the reason a provider could not be installed. ([#31898](https://github.com/hashicorp/terraform/issues/31898))
38+
* backend/gcs: Add `kms_encryption_key` argument, to allow encryption of state files using Cloud KMS keys. ([#24967](https://github.com/hashicorp/terraform/issues/24967))
39+
* backend/gcs: Add `storage_custom_endpoint` argument, to allow communication with the backend via a Private Service Connect endpoint. ([#28856](https://github.com/hashicorp/terraform/issues/28856))
40+
* backend/gcs: Update documentation for usage of `gcs` with `terraform_remote_state` ([#32065](https://github.com/hashicorp/terraform/issues/32065))
41+
* backend/gcs: Update storage package to v1.28.0 ([#29656](https://github.com/hashicorp/terraform/issues/29656))
42+
* When removing a workspace from the `cloud` backend `terraform workspace delete` will use Terraform Cloud's [Safe Delete](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#safe-delete-a-workspace) API if the `-force` flag is not provided. ([#31949](https://github.com/hashicorp/terraform/pull/31949))
43+
* backend/oss: More robustly handle endpoint retrieval error ([#32295](https://github.com/hashicorp/terraform/issues/32295))
44+
* local-exec provisioner: Added `quiet` argument. If `quiet` is set to `true`, Terraform will not print the entire command to stdout during plan. ([#32116](https://github.com/hashicorp/terraform/issues/32116))
45+
* backend/http: Add support for mTLS authentication. ([#31699](https://github.com/hashicorp/terraform/issues/31699))
46+
* cloud: Add support for using the [generic hostname](https://developer.hashicorp.com/terraform/cloud-docs/registry/using#generic-hostname-terraform-enterprise) localterraform.com in module and provider sources as a substitute for the currently configured cloud backend hostname. This enhancement was also applied to the remote backend.
47+
* `terraform show` will now print an explanation when called on a Terraform workspace with empty state detailing why no resources are shown. ([#32629](https://github.com/hashicorp/terraform/issues/32629))
48+
* backend/gcs: Added support for `GOOGLE_BACKEND_IMPERSONATE_SERVICE_ACCOUNT` env var to allow impersonating a different service account when `GOOGLE_IMPERSONATE_SERVICE_ACCOUNT` is configured for the GCP provider. ([#32557](https://github.com/hashicorp/terraform/issues/32557))
49+
* backend/cos: Add support for the `assume_role` authentication method with the `tencentcloud` provider. This can be configured via the Terraform config or environment variables.
50+
* backend/cos: Add support for the `security_token` authentication method with the `tencentcloud` provider. This can be configured via the Terraform config or environment variables.
51+
52+
EXPERIMENTS:
53+
54+
* Since its introduction the `yamlencode` function's documentation carried a warning that it was experimental. This predated our more formalized idea of language experiments and so wasn't guarded by an explicit opt-in, but the intention was to allow for small adjustments to its behavior if we learned it was producing invalid YAML in some cases, due to the relative complexity of the YAML specification.
55+
56+
From Terraform v1.4 onwards, `yamlencode` is no longer documented as experimental and is now subject to the Terraform v1.x Compatibility Promises. There are no changes to its previous behavior in v1.3 and so no special action is required when upgrading.
657

758
## Previous Releases
859

960
For information on prior major and minor releases, see their changelogs:
1061

11-
* [v1.4](https://github.com/hashicorp/terraform/blob/v1.4/CHANGELOG.md)
1262
* [v1.3](https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md)
1363
* [v1.2](https://github.com/hashicorp/terraform/blob/v1.2/CHANGELOG.md)
1464
* [v1.1](https://github.com/hashicorp/terraform/blob/v1.1/CHANGELOG.md)

docs/resource-instance-change-lifecycle.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@ The various object values used in different parts of this process are:
3333
which a provider may use as a starting point for its planning operation.
3434

3535
The built-in logic primarily deals with the expected behavior for attributes
36-
marked in the schema as "computed". If an attribute is only "computed",
37-
Terraform expects the value to only be chosen by the provider and it will
38-
preserve any Prior State. If an attribute is marked as "computed" and
39-
"optional", this means that the user may either set it or may leave it
40-
unset to allow the provider to choose a value.
36+
marked in the schema as both "optional" _and_ "computed", which means that
37+
the user may either set it or may leave it unset to allow the provider
38+
to choose a value instead.
4139

4240
Terraform Core therefore constructs the proposed new state by taking the
4341
attribute value from Configuration if it is non-null, and then using the

internal/backend/local/backend_apply.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"log"
8-
"time"
98

109
"github.com/hashicorp/terraform/internal/backend"
1110
"github.com/hashicorp/terraform/internal/command/views"
@@ -75,10 +74,6 @@ func (b *Local) opApply(
7574
op.ReportResult(runningOp, diags)
7675
return
7776
}
78-
// stateHook uses schemas for when it periodically persists state to the
79-
// persistent storage backend.
80-
stateHook.Schemas = schemas
81-
stateHook.PersistInterval = 20 * time.Second // arbitrary interval that's hopefully a sweet spot
8277

8378
var plan *plans.Plan
8479
// If we weren't given a plan, then we refresh/plan
Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package local
22

33
import (
4-
"log"
54
"sync"
6-
"time"
75

86
"github.com/hashicorp/terraform/internal/states"
97
"github.com/hashicorp/terraform/internal/states/statemgr"
@@ -17,21 +15,6 @@ type StateHook struct {
1715
sync.Mutex
1816

1917
StateMgr statemgr.Writer
20-
21-
// If PersistInterval is nonzero then for any new state update after
22-
// the duration has elapsed we'll try to persist a state snapshot
23-
// to the persistent backend too.
24-
// That's only possible if field Schemas is valid, because the
25-
// StateMgr.PersistState function for some backends needs schemas.
26-
PersistInterval time.Duration
27-
28-
// Schemas are the schemas to use when persisting state due to
29-
// PersistInterval. This is ignored if PersistInterval is zero,
30-
// and PersistInterval is ignored if this is nil.
31-
Schemas *terraform.Schemas
32-
33-
lastPersist time.Time
34-
forcePersist bool
3518
}
3619

3720
var _ terraform.Hook = (*StateHook)(nil)
@@ -40,56 +23,11 @@ func (h *StateHook) PostStateUpdate(new *states.State) (terraform.HookAction, er
4023
h.Lock()
4124
defer h.Unlock()
4225

43-
if h.lastPersist.IsZero() {
44-
// The first PostStateUpdate starts the clock for intermediate
45-
// calls to PersistState.
46-
h.lastPersist = time.Now()
47-
}
48-
4926
if h.StateMgr != nil {
5027
if err := h.StateMgr.WriteState(new); err != nil {
5128
return terraform.HookActionHalt, err
5229
}
53-
if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.PersistInterval != 0 && h.Schemas != nil {
54-
if h.forcePersist || time.Since(h.lastPersist) >= h.PersistInterval {
55-
err := mgrPersist.PersistState(h.Schemas)
56-
if err != nil {
57-
return terraform.HookActionHalt, err
58-
}
59-
h.lastPersist = time.Now()
60-
}
61-
}
6230
}
6331

6432
return terraform.HookActionContinue, nil
6533
}
66-
67-
func (h *StateHook) Stopping() {
68-
h.Lock()
69-
defer h.Unlock()
70-
71-
// If Terraform has been asked to stop then that might mean that a hard
72-
// kill signal will follow shortly in case Terraform doesn't stop
73-
// quickly enough, and so we'll try to persist the latest state
74-
// snapshot in the hope that it'll give the user less recovery work to
75-
// do if they _do_ subsequently hard-kill Terraform during an apply.
76-
77-
if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.Schemas != nil {
78-
err := mgrPersist.PersistState(h.Schemas)
79-
if err != nil {
80-
// This hook can't affect Terraform Core's ongoing behavior,
81-
// but it's a best effort thing anyway so we'll just emit a
82-
// log to aid with debugging.
83-
log.Printf("[ERROR] Failed to persist state after interruption: %s", err)
84-
}
85-
86-
// While we're in the stopping phase we'll try to persist every
87-
// new state update to maximize every opportunity we get to avoid
88-
// losing track of objects that have been created or updated.
89-
// Terraform Core won't start any new operations after it's been
90-
// stopped, so at most we should see one more PostStateUpdate
91-
// call per already-active request.
92-
h.forcePersist = true
93-
}
94-
95-
}
Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
package local
22

33
import (
4-
"fmt"
54
"testing"
6-
"time"
75

8-
"github.com/google/go-cmp/cmp"
9-
"github.com/hashicorp/terraform/internal/states"
106
"github.com/hashicorp/terraform/internal/states/statemgr"
117
"github.com/hashicorp/terraform/internal/terraform"
128
)
@@ -31,125 +27,3 @@ func TestStateHook(t *testing.T) {
3127
t.Fatalf("bad state: %#v", is.State())
3228
}
3329
}
34-
35-
func TestStateHookStopping(t *testing.T) {
36-
is := &testPersistentState{}
37-
hook := &StateHook{
38-
StateMgr: is,
39-
Schemas: &terraform.Schemas{},
40-
PersistInterval: 4 * time.Hour,
41-
lastPersist: time.Now(),
42-
}
43-
44-
s := statemgr.TestFullInitialState()
45-
action, err := hook.PostStateUpdate(s)
46-
if err != nil {
47-
t.Fatalf("unexpected error from PostStateUpdate: %s", err)
48-
}
49-
if got, want := action, terraform.HookActionContinue; got != want {
50-
t.Fatalf("wrong hookaction %#v; want %#v", got, want)
51-
}
52-
if is.Written == nil || !is.Written.Equal(s) {
53-
t.Fatalf("mismatching state written")
54-
}
55-
if is.Persisted != nil {
56-
t.Fatalf("persisted too soon")
57-
}
58-
59-
// We'll now force lastPersist to be long enough ago that persisting
60-
// should be due on the next call.
61-
hook.lastPersist = time.Now().Add(-5 * time.Hour)
62-
hook.PostStateUpdate(s)
63-
if is.Written == nil || !is.Written.Equal(s) {
64-
t.Fatalf("mismatching state written")
65-
}
66-
if is.Persisted == nil || !is.Persisted.Equal(s) {
67-
t.Fatalf("mismatching state persisted")
68-
}
69-
hook.PostStateUpdate(s)
70-
if is.Written == nil || !is.Written.Equal(s) {
71-
t.Fatalf("mismatching state written")
72-
}
73-
if is.Persisted == nil || !is.Persisted.Equal(s) {
74-
t.Fatalf("mismatching state persisted")
75-
}
76-
77-
gotLog := is.CallLog
78-
wantLog := []string{
79-
// Initial call before we reset lastPersist
80-
"WriteState",
81-
82-
// Write and then persist after we reset lastPersist
83-
"WriteState",
84-
"PersistState",
85-
86-
// Final call when persisting wasn't due yet.
87-
"WriteState",
88-
}
89-
if diff := cmp.Diff(wantLog, gotLog); diff != "" {
90-
t.Fatalf("wrong call log so far\n%s", diff)
91-
}
92-
93-
// We'll reset the log now before we try seeing what happens after
94-
// we use "Stopped".
95-
is.CallLog = is.CallLog[:0]
96-
is.Persisted = nil
97-
98-
hook.Stopping()
99-
if is.Persisted == nil || !is.Persisted.Equal(s) {
100-
t.Fatalf("mismatching state persisted")
101-
}
102-
103-
is.Persisted = nil
104-
hook.PostStateUpdate(s)
105-
if is.Persisted == nil || !is.Persisted.Equal(s) {
106-
t.Fatalf("mismatching state persisted")
107-
}
108-
is.Persisted = nil
109-
hook.PostStateUpdate(s)
110-
if is.Persisted == nil || !is.Persisted.Equal(s) {
111-
t.Fatalf("mismatching state persisted")
112-
}
113-
114-
gotLog = is.CallLog
115-
wantLog = []string{
116-
// "Stopping" immediately persisted
117-
"PersistState",
118-
119-
// PostStateUpdate then writes and persists on every call,
120-
// on the assumption that we're now bailing out after
121-
// being cancelled and trying to save as much state as we can.
122-
"WriteState",
123-
"PersistState",
124-
"WriteState",
125-
"PersistState",
126-
}
127-
if diff := cmp.Diff(wantLog, gotLog); diff != "" {
128-
t.Fatalf("wrong call log once in stopping mode\n%s", diff)
129-
}
130-
}
131-
132-
type testPersistentState struct {
133-
CallLog []string
134-
135-
Written *states.State
136-
Persisted *states.State
137-
}
138-
139-
var _ statemgr.Writer = (*testPersistentState)(nil)
140-
var _ statemgr.Persister = (*testPersistentState)(nil)
141-
142-
func (sm *testPersistentState) WriteState(state *states.State) error {
143-
sm.CallLog = append(sm.CallLog, "WriteState")
144-
sm.Written = state
145-
return nil
146-
}
147-
148-
func (sm *testPersistentState) PersistState(schemas *terraform.Schemas) error {
149-
if schemas == nil {
150-
return fmt.Errorf("no schemas")
151-
}
152-
sm.CallLog = append(sm.CallLog, "PersistState")
153-
sm.Persisted = sm.Written
154-
return nil
155-
}

internal/builtin/providers/terraform/provider.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ func (p *Provider) ApplyResourceChange(req providers.ApplyResourceChangeRequest)
119119
}
120120

121121
// ImportResourceState requests that the given resource be imported.
122-
func (p *Provider) ImportResourceState(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
122+
func (p *Provider) ImportResourceState(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
123+
if req.TypeName == "terraform_data" {
124+
return importDataStore(req)
125+
}
126+
123127
panic("unimplemented - terraform_remote_state has no resources")
124128
}
125129

internal/builtin/providers/terraform/resource_data.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,24 @@ func applyDataStoreResourceChange(req providers.ApplyResourceChangeRequest) (res
146146

147147
return resp
148148
}
149+
150+
// TODO: This isn't very useful even for examples, because terraform_data has
151+
// no way to refresh the full resource value from only the import ID. This
152+
// minimal implementation allows the import to succeed, and can be extended
153+
// once the configuration is available during import.
154+
func importDataStore(req providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
155+
schema := dataStoreResourceSchema()
156+
v := cty.ObjectVal(map[string]cty.Value{
157+
"id": cty.StringVal(req.ID),
158+
})
159+
state, err := schema.Block.CoerceValue(v)
160+
resp.Diagnostics = resp.Diagnostics.Append(err)
161+
162+
resp.ImportedResources = []providers.ImportedResource{
163+
{
164+
TypeName: req.TypeName,
165+
State: state,
166+
},
167+
}
168+
return resp
169+
}

internal/terraform/context.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,6 @@ func (c *Context) Stop() {
193193
c.runContextCancel = nil
194194
}
195195

196-
// Notify all of the hooks that we're stopping, in case they want to try
197-
// to flush in-memory state to disk before a subsequent hard kill.
198-
for _, hook := range c.hooks {
199-
hook.Stopping()
200-
}
201-
202196
// Grab the condition var before we exit
203197
if cond := c.runCond; cond != nil {
204198
log.Printf("[INFO] terraform: waiting for graceful stop to complete")

0 commit comments

Comments
 (0)