Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hashicorp/terraform
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.3
Choose a base ref
...
head repository: hashicorp/terraform
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.0.4
Choose a head ref

Commits on May 28, 2021

  1. backport of commit e5fb84a

    remilapeyre committed May 28, 2021
    Copy the full SHA
    d76c5e6 View commit details
  2. backport of commit 5f444a6

    remilapeyre committed May 28, 2021
    Copy the full SHA
    e6cd3fc View commit details

Commits on Jul 7, 2021

  1. Copy the full SHA
    e7683f5 View commit details
  2. Copy the full SHA
    07e65c3 View commit details
  3. Copy the full SHA
    6c0925f View commit details
  4. Copy the full SHA
    f7d7067 View commit details
  5. Copy the full SHA
    f1558f0 View commit details
  6. Copy the full SHA
    f6be38c View commit details
  7. Copy the full SHA
    4dab58e View commit details
  8. Copy the full SHA
    7757b3c View commit details
  9. Copy the full SHA
    63c5f21 View commit details
  10. Copy the full SHA
    32ccca4 View commit details
  11. Copy the full SHA
    23cba59 View commit details
  12. Copy the full SHA
    36f0e59 View commit details
  13. Copy the full SHA
    03fb1fa View commit details
  14. Copy the full SHA
    32bac6a View commit details
  15. Copy the full SHA
    e4d0e71 View commit details
  16. Copy the full SHA
    a15acde View commit details
  17. Copy the full SHA
    b7f82a9 View commit details
  18. Copy the full SHA
    e5f90bc View commit details
  19. Copy the full SHA
    7c303ad View commit details
  20. Copy the full SHA
    cb2c350 View commit details

Commits on Jul 9, 2021

  1. Copy the full SHA
    739648c View commit details
  2. Copy the full SHA
    2f0e443 View commit details

Commits on Jul 21, 2021

  1. Copy the full SHA
    757160c View commit details
  2. Merge pull request #29214 from hashicorp/backport/description-metadat…

    …a-language-docs/frankly-desired-penguin
    
    Backport of Description metadata -  language docs into v1.0
    laurapacilio authored Jul 21, 2021
    Copy the full SHA
    cbbaaf8 View commit details
  3. backport of commit 591bc1e

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    e613b35 View commit details
  4. backport of commit b18298c

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    26b0288 View commit details
  5. backport of commit 1c2559f

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    c5edc21 View commit details
  6. backport of commit 1243ae8

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    1eccc13 View commit details
  7. backport of commit 5f0a4a0

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    fe77268 View commit details
  8. backport of commit 6f7056e

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    cfa20d8 View commit details
  9. backport of commit f465294

    laurapacilio committed Jul 21, 2021
    Copy the full SHA
    8d34cc1 View commit details

Commits on Jul 22, 2021

  1. Backport of configs/configschema: extend block.AttributeByPath to des…

    …cend into Objects into v1.0 (#29224)
    
    * backport of commit 9ae65ac
    
    * backport of commit bb87395
    
    Co-authored-by: Kristin Laemmert <mildwonkey@users.noreply.github.com>
    teamterraform and mildwonkey authored Jul 22, 2021
    Copy the full SHA
    21c6659 View commit details

Commits on Jul 23, 2021

  1. backport of commit b37eab6

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    f1ec5ba View commit details
  2. backport of commit a8b8f4c

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    62c3db6 View commit details
  3. backport of commit 733655e

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    cc144bb View commit details
  4. backport of commit 72181df

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    121538c View commit details
  5. backport of commit d41ee62

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    3252890 View commit details
  6. backport of commit 46b56f4

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    d7194ea View commit details
  7. backport of commit a8ffd11

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    6501bc2 View commit details
  8. backport of commit 585b609

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    eb46a5c View commit details
  9. backport of commit e432d85

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    6cce723 View commit details
  10. backport of commit 2ef3299

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    aa23a9c View commit details
  11. backport of commit 749d5ce

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    aa9a4ef View commit details
  12. backport of commit 5399376

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    dad549a View commit details
  13. backport of commit 03e1818

    laurapacilio committed Jul 23, 2021
    Copy the full SHA
    94ea49c View commit details

Commits on Jul 30, 2021

  1. command/views/json: Never generate invalid diagnostic snippet offsets

    Because our snippet generator is trying to select whole lines to include
    in the snippet, it has some edge cases for odd situations where the
    relevant source range starts or ends directly at a newline, which were
    previously causing this logic to return out-of-bounds offsets into the
    code snippet string.
    
    Although arguably it'd be better for the original diagnostics to report
    more reasonable source ranges, it's better for us to report a
    slightly-inaccurate snippet than to crash altogether, and so we'll extend
    our existing range checks to check both bounds of the string and thus
    avoid downstreams having to deal with out-of-bounds indices.
    
    For completeness here I also added some similar logic to the
    human-oriented diagnostic formatter, which consumes the result of the
    JSON diagnostic builder. That's not really needed with the additional
    checks in the JSON diagnostic builder, but it's nice to reinforce that
    this code can't panic (in this way, at least) even if its input isn't
    valid.
    apparentlymart authored and jbardin committed Jul 30, 2021
    Copy the full SHA
    a167ded View commit details
  2. Merge pull request #29277 from hashicorp/jbardin/backport-29048

    command/views/json: Never generate invalid diagnostic snippet offsets
    jbardin authored Jul 30, 2021
    Copy the full SHA
    2268858 View commit details
  3. Merge pull request #29280 from hashicorp/backport/consul-size-limit/a…

    …mazingly-innocent-python
    
    Backport of Fix handling large states in the Consul backend into v1.0
    jbardin authored Jul 30, 2021
    Copy the full SHA
    089b25a View commit details
Showing with 405 additions and 142 deletions.
  1. +8 −0 CHANGELOG.md
  2. +72 −52 internal/backend/remote-state/consul/client.go
  3. +13 −5 internal/backend/remote-state/consul/client_test.go
  4. +15 −0 internal/command/format/diagnostic.go
  5. +13 −2 internal/command/views/json/diagnostic.go
  6. +47 −1 internal/command/views/json/diagnostic_test.go
  7. +26 −0 internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json
  8. +28 −2 internal/configs/configschema/path.go
  9. +108 −0 internal/configs/configschema/path_test.go
  10. +1 −1 version/version.go
  11. +1 −0 website/docs/cli/auth/index.html.md
  12. +1 −0 website/docs/cli/code/index.html.md
  13. +1 −2 website/docs/cli/commands/apply.html.md
  14. +2 −3 website/docs/cli/commands/console.html.md
  15. +1 −3 website/docs/cli/commands/destroy.html.md
  16. +1 −2 website/docs/cli/commands/env.html.md
  17. +1 −2 website/docs/cli/commands/fmt.html.md
  18. +1 −2 website/docs/cli/commands/force-unlock.html.md
  19. +1 −2 website/docs/cli/commands/get.html.md
  20. +1 −2 website/docs/cli/commands/graph.html.md
  21. +1 −2 website/docs/cli/commands/import.html.md
  22. +1 −2 website/docs/cli/commands/index.html.md
  23. +2 −3 website/docs/cli/commands/init.html.md
  24. +1 −2 website/docs/cli/commands/plan.html.md
  25. +1 −3 website/docs/cli/commands/providers.html.md
  26. +3 −4 website/docs/cli/commands/version.html.md
  27. +2 −2 website/docs/cli/commands/workspace/index.html.md
  28. +5 −3 website/docs/cli/config/config-file.html.md
  29. +1 −2 website/docs/cli/config/environment-variables.html.md
  30. +1 −0 website/docs/cli/config/index.html.md
  31. +1 −4 website/docs/cli/import/index.html.md
  32. +1 −2 website/docs/cli/index.html.md
  33. +1 −0 website/docs/cli/init/index.html.md
  34. +1 −0 website/docs/cli/inspect/index.html.md
  35. +1 −0 website/docs/cli/plugins/index.html.md
  36. +1 −2 website/docs/cli/plugins/signing.html.md
  37. +1 −0 website/docs/cli/run/index.html.md
  38. +1 −0 website/docs/cli/state/index.html.md
  39. +1 −0 website/docs/cli/state/inspect.html.md
  40. +1 −0 website/docs/cli/state/move.html.md
  41. +1 −0 website/docs/cli/state/recover.html.md
  42. +1 −0 website/docs/cli/state/taint.html.md
  43. +1 −0 website/docs/cli/workspaces/index.html.md
  44. +1 −2 website/docs/internals/index.html.md
  45. +1 −0 website/docs/language/dependency-lock.html.md
  46. +1 −0 website/docs/language/expressions/dynamic-blocks.html.md
  47. +1 −0 website/docs/language/expressions/for.html.md
  48. +2 −0 website/docs/language/files/index.html.md
  49. +1 −2 website/docs/language/files/override.html.md
  50. +2 −0 website/docs/language/index.html.md
  51. +1 −0 website/docs/language/meta-arguments/count.html.md
  52. +1 −0 website/docs/language/meta-arguments/depends_on.html.md
  53. +1 −0 website/docs/language/meta-arguments/for_each.html.md
  54. +1 −0 website/docs/language/meta-arguments/lifecycle.html.md
  55. +1 −0 website/docs/language/meta-arguments/module-providers.html.md
  56. +1 −1 website/docs/language/meta-arguments/resource-provider.html.md
  57. +1 −1 website/docs/language/modules/sources.html.md
  58. +1 −2 website/docs/language/providers/configuration.html.md
  59. +1 −0 website/docs/language/resources/behavior.html.md
  60. +1 −0 website/docs/language/resources/index.html.md
  61. +2 −3 website/docs/language/resources/provisioners/connection.html.md
  62. +2 −0 website/docs/language/resources/provisioners/index.html.md
  63. +1 −3 website/docs/language/resources/provisioners/null_resource.html.md
  64. +2 −2 website/docs/language/resources/provisioners/syntax.html.md
  65. +1 −3 website/docs/language/resources/syntax.html.md
  66. +1 −3 website/docs/language/settings/index.html.md
  67. +1 −3 website/docs/language/syntax/configuration.html.md
  68. +1 −0 website/docs/language/syntax/index.html.md
  69. +1 −2 website/docs/language/syntax/json.html.md
  70. +1 −3 website/docs/language/syntax/style.html.md
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.0.4 (August 04, 2021)


BUG FIXES:

* backend/consul: Fix a bug where the state value may be too large for consul to accept ([#28838](https://github.com/hashicorp/terraform/issues/28838))
* cli: Fixed a crashing bug with some edge-cases when reporting syntax errors that happen to be reported at the position of a newline. ([#29048](https://github.com/hashicorp/terraform/issues/29048))

## 1.0.3 (July 21, 2021)

ENHANCEMENTS
124 changes: 72 additions & 52 deletions internal/backend/remote-state/consul/client.go
Original file line number Diff line number Diff line change
@@ -198,72 +198,92 @@ func (c *RemoteClient) Put(data []byte) error {
verb = consulapi.KVSet
}

// If the payload is too large we first write the chunks and replace it
// 524288 is the default value, we just hope the user did not set a smaller
// one but there is really no reason for them to do so, if they changed it
// it is certainly to set a larger value.
limit := 524288
if len(payload) > limit {
md5 := md5.Sum(data)
chunks := split(payload, limit)
chunkPaths := make([]string, 0)

// First we write the new chunks
for i, p := range chunks {
path := strings.TrimRight(c.Path, "/") + fmt.Sprintf("/tfstate.%x/%d", md5, i)
chunkPaths = append(chunkPaths, path)
_, err := kv.Put(&consulapi.KVPair{
Key: path,
Value: p,
}, nil)

if err != nil {
return err
}
// The payload may be too large to store in a single KV entry in Consul. We
// could try to determine whether it will fit or not before sending the
// request but since we are using the Transaction API and not the KV API,
// it grows by about a 1/3 when it is base64 encoded plus the overhead of
// the fields specific to the Transaction API.
// Rather than trying to calculate the overhead (which could change from
// one version of Consul to another, and between Consul Community Edition
// and Consul Enterprise), we try to send the whole state in one request, if
// it fails because it is too big we then split it in chunks and send each
// chunk separately.
// When splitting in chunks, we make each chunk 524288 bits, which is the
// default max size for raft. If the user changed it, we still may send
// chunks too big and fail but this is not a setting that should be fiddled
// with anyway.

store := func(payload []byte) error {
// KV.Put doesn't return the new index, so we use a single operation
// transaction to get the new index with a single request.
txOps := consulapi.KVTxnOps{
&consulapi.KVTxnOp{
Verb: verb,
Key: c.Path,
Value: payload,
Index: c.modifyIndex,
},
}

// We update the link to point to the new chunks
payload, err = json.Marshal(map[string]interface{}{
"current-hash": fmt.Sprintf("%x", md5),
"chunks": chunkPaths,
})
ok, resp, _, err := kv.Txn(txOps, nil)
if err != nil {
return err
}
}
// transaction was rolled back
if !ok {
return fmt.Errorf("consul CAS failed with transaction errors: %v", resp.Errors)
}

var txOps consulapi.KVTxnOps
// KV.Put doesn't return the new index, so we use a single operation
// transaction to get the new index with a single request.
txOps = consulapi.KVTxnOps{
&consulapi.KVTxnOp{
Verb: verb,
Key: c.Path,
Value: payload,
Index: c.modifyIndex,
},
if len(resp.Results) != 1 {
// this probably shouldn't happen
return fmt.Errorf("expected on 1 response value, got: %d", len(resp.Results))
}

c.modifyIndex = resp.Results[0].ModifyIndex

// We remove all the old chunks
cleanupOldChunks()

return nil
}

ok, resp, _, err := kv.Txn(txOps, nil)
if err != nil {
if err = store(payload); err == nil {
// The payload was small enough to be stored
return nil
} else if !strings.Contains(err.Error(), "too large") {
// We failed for some other reason, report this to the user
return err
}
// transaction was rolled back
if !ok {
return fmt.Errorf("consul CAS failed with transaction errors: %v", resp.Errors)
}

if len(resp.Results) != 1 {
// this probably shouldn't happen
return fmt.Errorf("expected on 1 response value, got: %d", len(resp.Results))
}
// The payload was too large so we split it in multiple chunks

c.modifyIndex = resp.Results[0].ModifyIndex
md5 := md5.Sum(data)
chunks := split(payload, 524288)
chunkPaths := make([]string, 0)

// We remove all the old chunks
cleanupOldChunks()
// First we write the new chunks
for i, p := range chunks {
path := strings.TrimRight(c.Path, "/") + fmt.Sprintf("/tfstate.%x/%d", md5, i)
chunkPaths = append(chunkPaths, path)
_, err := kv.Put(&consulapi.KVPair{
Key: path,
Value: p,
}, nil)

return nil
if err != nil {
return err
}
}

// Then we update the link to point to the new chunks
payload, err = json.Marshal(map[string]interface{}{
"current-hash": fmt.Sprintf("%x", md5),
"chunks": chunkPaths,
})
if err != nil {
return err
}
return store(payload)
}

func (c *RemoteClient) Delete() error {
18 changes: 13 additions & 5 deletions internal/backend/remote-state/consul/client_test.go
Original file line number Diff line number Diff line change
@@ -136,11 +136,6 @@ func TestConsul_largeState(t *testing.T) {
t.Fatal(err)
}

// md5 := md5.Sum(payload)
// if !bytes.Equal(md5[:], remote.MD5) {
// t.Fatal("the md5 sums do not match")
// }

if !bytes.Equal(payload, remote.Data) {
t.Fatal("the data do not match")
}
@@ -161,6 +156,19 @@ func TestConsul_largeState(t *testing.T) {
},
)

// This payload is just short enough to be stored but will be bigger when
// going through the Transaction API as it will be base64 encoded
testPayload(
t,
map[string]string{
"foo": strings.Repeat("a", 524288-10),
},
[]string{
"tf-unit/test-large-state",
"tf-unit/test-large-state/tfstate.4f407ace136a86521fd0d366972fe5c7/0",
},
)

// We try to replace the payload with a small one, the old chunks should be removed
testPayload(
t,
15 changes: 15 additions & 0 deletions internal/command/format/diagnostic.go
Original file line number Diff line number Diff line change
@@ -250,6 +250,21 @@ func appendSourceSnippets(buf *bytes.Buffer, diag *viewsjson.Diagnostic, color *
}
}

// If either start or end is out of range for the code buffer then
// we'll cap them at the bounds just to avoid a panic, although
// this would happen only if there's a bug in the code generating
// the snippet objects.
if start < 0 {
start = 0
} else if start > len(code) {
start = len(code)
}
if end < 0 {
end = 0
} else if end > len(code) {
end = len(code)
}

before, highlight, after := code[0:start], code[start:end], code[end:]
code = fmt.Sprintf(color.Color("%s[underline]%s[reset]%s"), before, highlight, after)

15 changes: 13 additions & 2 deletions internal/command/views/json/diagnostic.go
Original file line number Diff line number Diff line change
@@ -220,12 +220,23 @@ func NewDiagnostic(diag tfdiags.Diagnostic, sources map[string][]byte) *Diagnost
// to the code snippet string.
start := highlightRange.Start.Byte - codeStartByte
end := start + (highlightRange.End.Byte - highlightRange.Start.Byte)
if start > len(codeStr) {

// We can end up with some quirky results here in edge cases like
// when a source range starts or ends at a newline character,
// so we'll cap the results at the bounds of the highlight range
// so that consumers of this data don't need to contend with
// out-of-bounds errors themselves.
if start < 0 {
start = 0
} else if start > len(codeStr) {
start = len(codeStr)
}
if end > len(codeStr) {
if end < 0 {
end = 0
} else if end > len(codeStr) {
end = len(codeStr)
}

diagnostic.Snippet.HighlightStartOffset = start
diagnostic.Snippet.HighlightEndOffset = end

48 changes: 47 additions & 1 deletion internal/command/views/json/diagnostic_test.go
Original file line number Diff line number Diff line change
@@ -28,7 +28,8 @@ func TestNewDiagnostic(t *testing.T) {
}
}
`),
"short.tf": []byte("bad source code"),
"short.tf": []byte("bad source code"),
"odd-comment.tf": []byte("foo\n\n#\n"),
"values.tf": []byte(`[
var.a,
var.b,
@@ -284,6 +285,51 @@ func TestNewDiagnostic(t *testing.T) {
},
},
},
"error whose range starts at a newline": {
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid newline",
Detail: "How awkward!",
Subject: &hcl.Range{
Filename: "odd-comment.tf",
Start: hcl.Pos{Line: 2, Column: 5, Byte: 4},
End: hcl.Pos{Line: 3, Column: 1, Byte: 6},
},
},
&Diagnostic{
Severity: "error",
Summary: "Invalid newline",
Detail: "How awkward!",
Range: &DiagnosticRange{
Filename: "odd-comment.tf",
Start: Pos{
Line: 2,
Column: 5,
Byte: 4,
},
End: Pos{
Line: 3,
Column: 1,
Byte: 6,
},
},
Snippet: &DiagnosticSnippet{
Code: `#`,
StartLine: 2,
Values: []DiagnosticExpressionValue{},

// Due to the range starting at a newline on a blank
// line, we end up stripping off the initial newline
// to produce only a one-line snippet. That would
// therefore cause the start offset to naturally be
// -1, just before the Code we returned, but then we
// force it to zero so that the result will still be
// in range for a byte-oriented slice of Code.
HighlightStartOffset: 0,
HighlightEndOffset: 1,
},
},
},
"error with source code subject and known expression": {
&hcl.Diagnostic{
Severity: hcl.DiagError,
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"severity": "error",
"summary": "Invalid newline",
"detail": "How awkward!",
"range": {
"filename": "odd-comment.tf",
"start": {
"line": 2,
"column": 5,
"byte": 4
},
"end": {
"line": 3,
"column": 1,
"byte": 6
}
},
"snippet": {
"context": null,
"code": "#",
"start_line": 2,
"highlight_start_offset": 0,
"highlight_end_offset": 1,
"values": []
}
}
30 changes: 28 additions & 2 deletions internal/configs/configschema/path.go
Original file line number Diff line number Diff line change
@@ -7,13 +7,19 @@ import (
// AttributeByPath looks up the Attribute schema which corresponds to the given
// cty.Path. A nil value is returned if the given path does not correspond to a
// specific attribute.
// TODO: this will need to be updated for nested attributes
func (b *Block) AttributeByPath(path cty.Path) *Attribute {
block := b
for _, step := range path {
for i, step := range path {
switch step := step.(type) {
case cty.GetAttrStep:
if attr := block.Attributes[step.Name]; attr != nil {
// If the Attribute is defined with a NestedType and there's
// more to the path, descend into the NestedType
if attr.NestedType != nil && i < len(path)-1 {
return attr.NestedType.AttributeByPath(path[i+1:])
} else if i < len(path)-1 { // There's more to the path, but not more to this Attribute.
return nil
}
return attr
}

@@ -27,3 +33,23 @@ func (b *Block) AttributeByPath(path cty.Path) *Attribute {
}
return nil
}

// AttributeByPath recurses through a NestedType to look up the Attribute scheme
// which corresponds to the given cty.Path. A nil value is returned if the given
// path does not correspond to a specific attribute.
func (o *Object) AttributeByPath(path cty.Path) *Attribute {
for i, step := range path {
switch step := step.(type) {
case cty.GetAttrStep:
if attr := o.Attributes[step.Name]; attr != nil {
if attr.NestedType != nil && i < len(path)-1 {
return attr.NestedType.AttributeByPath(path[i+1:])
} else if i < len(path)-1 { // There's more to the path, but not more to this Attribute.
return nil
}
return attr
}
}
}
return nil
}
Loading