Structured Plan Renderer: Read the data source schemas from the right place (#32532)

* read the data source schemas from the right place

* address comments and add test
This commit is contained in:
Liam Cervante 2023-01-19 15:37:02 +01:00 committed by GitHub
parent 7a019fa767
commit 6dc49150b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 141 additions and 6 deletions

View File

@ -43,7 +43,7 @@ func precomputeDiffs(plan Plan, mode plans.Mode) diffs {
continue
}
schema := plan.ProviderSchemas[drift.ProviderName].ResourceSchemas[drift.Type]
schema := plan.GetSchema(drift)
diffs.drift = append(diffs.drift, diff{
change: drift,
diff: differ.FromJsonChange(drift.Change, relevantAttrs).ComputeDiffForBlock(schema.Block),
@ -51,7 +51,7 @@ func precomputeDiffs(plan Plan, mode plans.Mode) diffs {
}
for _, change := range plan.ResourceChanges {
schema := plan.ProviderSchemas[change.ProviderName].ResourceSchemas[change.Type]
schema := plan.GetSchema(change)
diffs.changes = append(diffs.changes, diff{
change: change,
diff: differ.FromJsonChange(change.Change, attribute_path.AlwaysMatcher()).ComputeDiffForBlock(schema.Block),

View File

@ -39,6 +39,17 @@ type Plan struct {
ProviderSchemas map[string]*jsonprovider.Provider `json:"provider_schemas"`
}
func (plan Plan) GetSchema(change jsonplan.ResourceChange) *jsonprovider.Schema {
switch change.Mode {
case jsonplan.ManagedResourceMode:
return plan.ProviderSchemas[change.ProviderName].ResourceSchemas[change.Type]
case jsonplan.DataResourceMode:
return plan.ProviderSchemas[change.ProviderName].DataSourceSchemas[change.Type]
default:
panic("found unrecognized resource mode: " + change.Mode)
}
}
type Renderer struct {
Streams *terminal.Streams
Colorize *colorstring.Colorize
@ -78,7 +89,7 @@ func (r Renderer) RenderHumanPlan(plan Plan, mode plans.Mode, opts ...RendererOp
// Don't show anything for NoOp changes.
continue
}
if action == plans.Delete && diff.change.Mode != "managed" {
if action == plans.Delete && diff.change.Mode != jsonplan.ManagedResourceMode {
// Don't render anything for deleted data sources.
continue
}
@ -464,7 +475,7 @@ func resourceChangeComment(resource jsonplan.ResourceChange, action plans.Action
func resourceChangeHeader(change jsonplan.ResourceChange) string {
mode := "resource"
if change.Mode != "managed" {
if change.Mode != jsonplan.ManagedResourceMode {
mode = "data"
}
return fmt.Sprintf("%s \"%s\" \"%s\"", mode, change.Type, change.Name)

View File

@ -39,6 +39,9 @@ const (
ResourceInstanceDeleteBecauseNoMoveTarget = "delete_because_no_move_target"
ResourceInstanceReadBecauseConfigUnknown = "read_because_config_unknown"
ResourceInstanceReadBecauseDependencyPending = "read_because_dependency_pending"
ManagedResourceMode = "managed"
DataResourceMode = "data"
)
// Plan is the top-level representation of the json format of a plan. It includes
@ -445,9 +448,9 @@ func MarshalResourceChanges(resources []*plans.ResourceInstanceChangeSrc, schema
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
r.Mode = "managed"
r.Mode = ManagedResourceMode
case addrs.DataResourceMode:
r.Mode = "data"
r.Mode = DataResourceMode
default:
return nil, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
}

View File

@ -356,6 +356,78 @@ Plan: 1 to add, 0 to change, 0 to destroy.
}
}
func TestOperation_planWithDatasource(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
v := NewOperation(arguments.ViewHuman, true, NewView(streams))
plan := testPlanWithDatasource(t)
schemas := testSchemas()
v.Plan(plan, schemas)
want := `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
# data.test_data_source.bar will be read during apply
<= data "test_data_source" "bar" {
+ bar = "foo"
+ id = "C6743020-40BD-4591-81E6-CD08494341D3"
}
# test_resource.foo will be created
+ resource "test_resource" "foo" {
+ foo = "bar"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
`
if got := done(t).Stdout(); got != want {
t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s", got, want)
}
}
func TestOperation_planWithDatasourceAndDrift(t *testing.T) {
streams, done := terminal.StreamsForTesting(t)
v := NewOperation(arguments.ViewHuman, true, NewView(streams))
plan := testPlanWithDatasource(t)
schemas := testSchemas()
v.Plan(plan, schemas)
want := `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
# data.test_data_source.bar will be read during apply
<= data "test_data_source" "bar" {
+ bar = "foo"
+ id = "C6743020-40BD-4591-81E6-CD08494341D3"
}
# test_resource.foo will be created
+ resource "test_resource" "foo" {
+ foo = "bar"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
`
if got := done(t).Stdout(); got != want {
t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s", got, want)
}
}
func TestOperation_planNextStep(t *testing.T) {
testCases := map[string]struct {
path string

View File

@ -88,6 +88,45 @@ func testPlan(t *testing.T) *plans.Plan {
}
}
func testPlanWithDatasource(t *testing.T) *plans.Plan {
plan := testPlan(t)
addr := addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "test_data_source",
Name: "bar",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
dataVal := cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("C6743020-40BD-4591-81E6-CD08494341D3"),
"bar": cty.StringVal("foo"),
})
priorValRaw, err := plans.NewDynamicValue(cty.NullVal(dataVal.Type()), dataVal.Type())
if err != nil {
t.Fatal(err)
}
plannedValRaw, err := plans.NewDynamicValue(dataVal, dataVal.Type())
if err != nil {
t.Fatal(err)
}
plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
Addr: addr,
PrevRunAddr: addr,
ProviderAddr: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
ChangeSrc: plans.ChangeSrc{
Action: plans.Read,
Before: priorValRaw,
After: plannedValRaw,
},
})
return plan
}
func testSchemas() *terraform.Schemas {
provider := testProvider()
return &terraform.Schemas{
@ -123,5 +162,15 @@ func testProviderSchema() *providers.GetProviderSchemaResponse {
},
},
},
DataSources: map[string]providers.Schema{
"test_data_source": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Required: true},
"bar": {Type: cty.String, Optional: true},
},
},
},
},
}
}