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.8
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.9
Choose a head ref
  • 14 commits
  • 10 files changed
  • 4 contributors

Commits on Sep 29, 2021

  1. Verified

    This commit was signed with the committer’s verified signature.
    AVVS Vitaly Aminev
    Copy the full SHA
    a4dcaaa View commit details
  2. Update publish.html.md

    Updated language around contributing modules with overlapping features in the Publishing Modules section: "We welcome..." (all contributions)
    solutiongeek authored and laurapacilio committed Sep 29, 2021

    Verified

    This commit was signed with the committer’s verified signature.
    AVVS Vitaly Aminev
    Copy the full SHA
    4788c29 View commit details

Commits on Oct 4, 2021

  1. backport of commit 18d3542

    jbardin committed Oct 4, 2021
    Copy the full SHA
    4535f23 View commit details

Commits on Oct 5, 2021

  1. backport of commit 58d85fc

    jbardin committed Oct 5, 2021
    Copy the full SHA
    c8fdc22 View commit details
  2. Merge pull request #29704 from hashicorp/backport/jbardin/proposed-ne…

    …w-null-objs/previously-infinite-midge
    
    Backport of objchange: fix ProposedNew from null objects into v1.0
    jbardin authored Oct 5, 2021
    Copy the full SHA
    cd5271d View commit details
  3. update CHANGELOG.md

    jbardin committed Oct 5, 2021
    Copy the full SHA
    c3bb77c View commit details

Commits on Oct 8, 2021

  1. skip refreshing deposed during destroy plan

    The destroy plan should not require a configured provider (the complete
    configuration is not evaluated, so they cannot be configured).
    
    Deposed instances were being refreshed during the destroy plan, because
    this instance type is only ever destroyed and shares the same
    implementation between plan and walkPlanDestroy. Skip refreshing during
    walkPlanDestroy.
    
    add comment about when we call ConfigureProvider
    jbardin committed Oct 8, 2021
    Copy the full SHA
    93eb396 View commit details
  2. backport of commit 3f4b680

    jbardin committed Oct 8, 2021
    Copy the full SHA
    b9d966a View commit details

Commits on Oct 12, 2021

  1. Merge pull request #29722 from hashicorp/jbardin/backport-29720

    v1.0 backport of #29720: skip refreshing deposed during destroy plan
    jbardin authored Oct 12, 2021
    Copy the full SHA
    eb81061 View commit details
  2. update CHANGELOG.md

    jbardin committed Oct 12, 2021
    Copy the full SHA
    5fe7978 View commit details
  3. Update CHANGELOG.md

    alisdair authored Oct 12, 2021
    Copy the full SHA
    75ebb3e View commit details
  4. Merge pull request #29735 from hashicorp/backport/jbardin/missing-cha…

    …nge/admittedly-neutral-jawfish
    
    Backport of Check for nil change during apply into v1.0
    jbardin authored Oct 12, 2021
    Copy the full SHA
    5cc4ab5 View commit details

Commits on Oct 13, 2021

  1. update CHANGELOG.md

    jbardin committed Oct 13, 2021
    Copy the full SHA
    2a80bf1 View commit details
  2. Release v1.0.9

    hc-github-team-tf-core committed Oct 13, 2021
    Copy the full SHA
    cdf8299 View commit details
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.0.9 (October 13, 2021)

BUG FIXES:

* core: Fix panic when planning new resources with nested object attributes ([#29701](https://github.com/hashicorp/terraform/issues/29701))
* core: Do not refresh deposed instances when the provider is not configured during destroy ([#29720](https://github.com/hashicorp/terraform/issues/29720))
* core: Prevent panic when encountering a missing change when destroying a resource ([#29734](https://github.com/hashicorp/terraform/issues/29734))

## 1.0.8 (September 29, 2021)

BUG FIXES:
33 changes: 0 additions & 33 deletions internal/plans/objchange/all_null.go

This file was deleted.

16 changes: 11 additions & 5 deletions internal/plans/objchange/objchange.go
Original file line number Diff line number Diff line change
@@ -37,7 +37,10 @@ func ProposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value
// similar to the result of decoding an empty configuration block,
// which simplifies our handling of the top-level attributes/blocks
// below by giving us one non-null level of object to pull values from.
prior = AllBlockAttributesNull(schema)
//
// "All attributes null" happens to be the definition of EmptyValue for
// a Block, so we can just delegate to that
prior = schema.EmptyValue()
}
return proposedNew(schema, prior, config)
}
@@ -258,12 +261,15 @@ func proposedNewNestedBlock(schema *configschema.NestedBlock, prior, config cty.
}

func proposedNewAttributes(attrs map[string]*configschema.Attribute, prior, config cty.Value) map[string]cty.Value {
if prior.IsNull() {
prior = AllAttributesNull(attrs)
}
newAttrs := make(map[string]cty.Value, len(attrs))
for name, attr := range attrs {
priorV := prior.GetAttr(name)
var priorV cty.Value
if prior.IsNull() {
priorV = cty.NullVal(prior.Type().AttributeType(name))
} else {
priorV = prior.GetAttr(name)
}

configV := config.GetAttr(name)
var newV cty.Value
switch {
152 changes: 152 additions & 0 deletions internal/plans/objchange/objchange_test.go
Original file line number Diff line number Diff line change
@@ -1536,6 +1536,158 @@ func TestProposedNew(t *testing.T) {
}),
}),
},
"prior null nested objects": {
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"single": {
NestedType: &configschema.Object{
Nesting: configschema.NestingSingle,
Attributes: map[string]*configschema.Attribute{
"list": {
NestedType: &configschema.Object{
Nesting: configschema.NestingList,
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: cty.String,
},
},
},
Optional: true,
},
},
},
Optional: true,
},
"map": {
NestedType: &configschema.Object{
Nesting: configschema.NestingMap,
Attributes: map[string]*configschema.Attribute{
"map": {
NestedType: &configschema.Object{
Nesting: configschema.NestingList,
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: cty.String,
},
},
},
Optional: true,
},
},
},
Optional: true,
},
},
},
cty.NullVal(cty.Object(map[string]cty.Type{
"single": cty.Object(map[string]cty.Type{
"list": cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
}),
"map": cty.Map(cty.Object(map[string]cty.Type{
"list": cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
})),
})),
cty.ObjectVal(map[string]cty.Value{
"single": cty.ObjectVal(map[string]cty.Value{
"list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("b"),
}),
}),
}),
"map": cty.MapVal(map[string]cty.Value{
"one": cty.ObjectVal(map[string]cty.Value{
"list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("b"),
}),
}),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"single": cty.ObjectVal(map[string]cty.Value{
"list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("b"),
}),
}),
}),
"map": cty.MapVal(map[string]cty.Value{
"one": cty.ObjectVal(map[string]cty.Value{
"list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("b"),
}),
}),
}),
}),
}),
},

// data sources are planned with an unknown value
"unknown prior nested objects": {
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"list": {
NestedType: &configschema.Object{
Nesting: configschema.NestingList,
Attributes: map[string]*configschema.Attribute{
"list": {
NestedType: &configschema.Object{
Nesting: configschema.NestingList,
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: cty.String,
},
},
},
Computed: true,
},
},
},
Computed: true,
},
},
},
cty.UnknownVal(cty.Object(map[string]cty.Type{
"List": cty.List(cty.Object(map[string]cty.Type{
"list": cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
})),
})),
cty.NullVal(cty.Object(map[string]cty.Type{
"List": cty.List(cty.Object(map[string]cty.Type{
"list": cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
})),
})),
cty.UnknownVal(cty.Object(map[string]cty.Type{
"List": cty.List(cty.Object(map[string]cty.Type{
"list": cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
})),
})),
},
}

for name, test := range tests {
48 changes: 48 additions & 0 deletions internal/terraform/context_apply2_test.go
Original file line number Diff line number Diff line change
@@ -573,3 +573,51 @@ resource "test_object" "y" {
}
}
}

func TestContext2Apply_destroyWithDeposed(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_object" "x" {
test_string = "ok"
lifecycle {
create_before_destroy = true
}
}`,
})

p := simpleMockProvider()

deposedKey := states.NewDeposedKey()

state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("test_object.x").Resource,
deposedKey,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectTainted,
AttrsJSON: []byte(`{"test_string":"deposed"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)

ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
State: state,
Config: m,
PlanMode: plans.DestroyMode,
})

_, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatalf("plan: %s", diags.Err())
}

// backported from v1.1, but the apply will error in in v1.0
//_, diags = ctx.Apply(plan, m)
//if diags.HasErrors() {
// t.Fatalf("apply: %s", diags.Err())
//}
}
3 changes: 3 additions & 0 deletions internal/terraform/node_provider.go
Original file line number Diff line number Diff line change
@@ -37,6 +37,9 @@ func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diag
case walkValidate:
return diags.Append(n.ValidateProvider(ctx, provider))
case walkPlan, walkApply, walkDestroy:
// walkPlanDestroy is purposely skipped here, since the config is not
// evaluated, and the provider is not needed to create delete actions
// for all instances.
return diags.Append(n.ConfigureProvider(ctx, provider, false))
case walkImport:
return diags.Append(n.ConfigureProvider(ctx, provider, true))
2 changes: 1 addition & 1 deletion internal/terraform/node_resource_destroy.go
Original file line number Diff line number Diff line change
@@ -166,7 +166,7 @@ func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (d

changeApply, err = n.readDiff(ctx, providerSchema)
diags = diags.Append(err)
if diags.HasErrors() {
if changeApply == nil || diags.HasErrors() {
return diags
}

7 changes: 6 additions & 1 deletion internal/terraform/node_resource_destroy_deposed.go
Original file line number Diff line number Diff line change
@@ -95,7 +95,12 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk
return diags
}

if !n.skipRefresh {
// We don't refresh during the planDestroy walk, since that is only adding
// the destroy changes to the plan and the provider will not be configured
// at this point. The other nodes use separate types for plan and destroy,
// while deposed instances are always a destroy operation, so the logic
// here is a bit overloaded.
if !n.skipRefresh && op != walkPlanDestroy {
// Refresh this object even though it is going to be destroyed, in
// case it's already been deleted outside of Terraform. If this is a
// normal plan, providers expect a Read request to remove missing
2 changes: 1 addition & 1 deletion version/version.go
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import (
)

// The main version number that is being run at the moment.
var Version = "1.0.8"
var Version = "1.0.9"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
3 changes: 3 additions & 0 deletions website/docs/language/modules/develop/publish.html.md
Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@ If you do not wish to publish your modules in the public registry, you can
instead use a [private registry](/docs/registry/private.html) to get
the same benefits.

We welcome contributions of Terraform modules from our community members, partners, and customers. Our ecosystem is made richer by each new module created or an existing one updated, as they reflect the wide range of experience and technical requirements of the community that uses them. Our cloud provider partners often seek to develop specific modules for popular or challenging use cases on their platform and utilize them as valuable learning experiences to empathize with their users. Similarly, our community module developers incorporate a variety of opinions and use cases from the broader Terraform community. Both types of modules have their place in the Terraform registry, accessible to practitioners who can decide which modules best fit their requirements.


## Distribution via other sources

Although the registry is the native mechanism for distributing re-usable