mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Plannable import: Generate config for imported resources during the plan. (#33153)
* command: keep our promises * remove some nil config checks Remove some of the safety checks that ensure plan nodes have config attached at the appropriate time. * add GeneratedConfig to plan changes objects Add a new GeneratedConfig field alongside Importing in plan changes. * add config generation package The genconfig package implements HCL config generation from provider state values. Thanks to @mildwonkey whose implementation of terraform add is the basis for this package. * generate config during plan If a resource is being imported and does not already have config, attempt to generate that config during planning. The config is generated from the state as an HCL string, and then parsed back into an hcl.Body to attach to the plan graph node. The generated config string is attached to the change emitted by the plan. * complete config generation prototype, and add tests --------- Co-authored-by: Katy Moe <katy@katy.moe>
This commit is contained in:
parent
9904f62bfd
commit
79f7f59155
@ -297,14 +297,6 @@ Usage: terraform [global options] import [options] ADDR ID
|
||||
determine the ID syntax to use. It typically matches directly to the ID
|
||||
that the provider uses.
|
||||
|
||||
The current implementation of Terraform import can only import resources
|
||||
into the state. It does not generate configuration. A future version of
|
||||
Terraform will also generate configuration.
|
||||
|
||||
Because of this, prior to running terraform import it is necessary to write
|
||||
a resource configuration block for the resource manually, to which the
|
||||
imported object will be attached.
|
||||
|
||||
This command will not modify your infrastructure, but it will make
|
||||
network requests to inspect parts of your infrastructure relevant to
|
||||
the resource being imported.
|
||||
|
@ -394,6 +394,19 @@ func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse
|
||||
}
|
||||
reqs[fqn] = nil
|
||||
}
|
||||
for _, i := range c.Module.Import {
|
||||
implied, err := addrs.ParseProviderPart(i.To.Resource.Resource.ImpliedProvider())
|
||||
if err == nil {
|
||||
provider := c.Module.ImpliedProviderForUnqualifiedType(implied)
|
||||
if _, exists := reqs[provider]; exists {
|
||||
// Explicit dependency already present
|
||||
continue
|
||||
}
|
||||
reqs[provider] = nil
|
||||
}
|
||||
// We don't return a diagnostic here, because the invalid address will
|
||||
// have been caught elsewhere.
|
||||
}
|
||||
|
||||
// "provider" block can also contain version constraints
|
||||
for _, provider := range c.Module.ProviderConfigs {
|
||||
|
@ -34,6 +34,7 @@ func TestConfigProviderTypes(t *testing.T) {
|
||||
got = cfg.ProviderTypes()
|
||||
want := []addrs.Provider{
|
||||
addrs.NewDefaultProvider("aws"),
|
||||
addrs.NewDefaultProvider("local"),
|
||||
addrs.NewDefaultProvider("null"),
|
||||
addrs.NewDefaultProvider("template"),
|
||||
addrs.NewDefaultProvider("test"),
|
||||
|
57
internal/configs/configschema/filter.go
Normal file
57
internal/configs/configschema/filter.go
Normal file
@ -0,0 +1,57 @@
|
||||
package configschema
|
||||
|
||||
type FilterT[T any] func(string, T) bool
|
||||
|
||||
var (
|
||||
FilterReadOnlyAttributes = func(name string, attribute *Attribute) bool {
|
||||
return attribute.Computed && !attribute.Optional
|
||||
}
|
||||
|
||||
FilterDeprecatedAttribute = func(name string, attribute *Attribute) bool {
|
||||
return attribute.Deprecated
|
||||
}
|
||||
|
||||
FilterDeprecatedBlock = func(name string, block *NestedBlock) bool {
|
||||
return block.Deprecated
|
||||
}
|
||||
)
|
||||
|
||||
func FilterOr[T any](one, two FilterT[T]) FilterT[T] {
|
||||
return func(name string, value T) bool {
|
||||
return one(name, value) || two(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Block) Filter(filterAttribute FilterT[*Attribute], filterBlock FilterT[*NestedBlock]) *Block {
|
||||
ret := &Block{
|
||||
Description: b.Description,
|
||||
DescriptionKind: b.DescriptionKind,
|
||||
Deprecated: b.Deprecated,
|
||||
}
|
||||
|
||||
if b.Attributes != nil {
|
||||
ret.Attributes = make(map[string]*Attribute, len(b.Attributes))
|
||||
}
|
||||
for name, attrS := range b.Attributes {
|
||||
if filterAttribute == nil || !filterAttribute(name, attrS) {
|
||||
ret.Attributes[name] = attrS
|
||||
}
|
||||
}
|
||||
|
||||
if b.BlockTypes != nil {
|
||||
ret.BlockTypes = make(map[string]*NestedBlock, len(b.BlockTypes))
|
||||
}
|
||||
for name, blockS := range b.BlockTypes {
|
||||
if filterBlock == nil || !filterBlock(name, blockS) {
|
||||
block := blockS.Filter(filterAttribute, filterBlock)
|
||||
ret.BlockTypes[name] = &NestedBlock{
|
||||
Block: *block,
|
||||
Nesting: blockS.Nesting,
|
||||
MinItems: blockS.MinItems,
|
||||
MaxItems: blockS.MaxItems,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
@ -14,6 +14,11 @@ resource "null_resource" "foo" {
|
||||
|
||||
}
|
||||
|
||||
import {
|
||||
id = "directory/filename"
|
||||
to = local_file.foo
|
||||
}
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
test = {
|
||||
|
2
internal/genconfig/doc.go
Normal file
2
internal/genconfig/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package genconfig implements config generation from provided state values.
|
||||
package genconfig
|
564
internal/genconfig/generate_config.go
Normal file
564
internal/genconfig/generate_config.go
Normal file
@ -0,0 +1,564 @@
|
||||
package genconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// GenerateResourceContents generates HCL configuration code for the provided
|
||||
// resource and state value.
|
||||
//
|
||||
// If you want tot generate actual valid Terraform code you should follow this
|
||||
// call up with a call to WrapResourceContents, which will place a Terraform
|
||||
// resource header around the attributes and blocks returned by this function.
|
||||
func GenerateResourceContents(addr addrs.AbsResourceInstance,
|
||||
schema *configschema.Block,
|
||||
pc addrs.LocalProviderConfig,
|
||||
stateVal cty.Value) (string, tfdiags.Diagnostics) {
|
||||
var buf strings.Builder
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if pc.LocalName != addr.Resource.Resource.ImpliedProvider() || pc.Alias != "" {
|
||||
buf.WriteString(strings.Repeat(" ", 2))
|
||||
buf.WriteString(fmt.Sprintf("provider = %s\n", pc.StringCompact()))
|
||||
}
|
||||
|
||||
stateVal = omitUnknowns(stateVal)
|
||||
if stateVal.RawEquals(cty.NilVal) {
|
||||
diags = diags.Append(writeConfigAttributes(addr, &buf, schema.Attributes, 2))
|
||||
diags = diags.Append(writeConfigBlocks(addr, &buf, schema.BlockTypes, 2))
|
||||
} else {
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, &buf, stateVal, schema.Attributes, 2))
|
||||
diags = diags.Append(writeConfigBlocksFromExisting(addr, &buf, stateVal, schema.BlockTypes, 2))
|
||||
}
|
||||
|
||||
// The output better be valid HCL which can be parsed and formatted.
|
||||
formatted := hclwrite.Format([]byte(buf.String()))
|
||||
return string(formatted), diags
|
||||
}
|
||||
|
||||
func WrapResourceContents(addr addrs.AbsResourceInstance, config string) string {
|
||||
var buf strings.Builder
|
||||
|
||||
buf.WriteString(fmt.Sprintf("resource %q %q {\n", addr.Resource.Resource.Type, addr.Resource.Resource.Name))
|
||||
buf.WriteString(config)
|
||||
buf.WriteString("}")
|
||||
|
||||
// The output better be valid HCL which can be parsed and formatted.
|
||||
formatted := hclwrite.Format([]byte(buf.String()))
|
||||
return string(formatted)
|
||||
}
|
||||
|
||||
func writeConfigAttributes(addr addrs.AbsResourceInstance, buf *strings.Builder, attrs map[string]*configschema.Attribute, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if len(attrs) == 0 {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted attribute names so the output will be consistent between runs.
|
||||
keys := make([]string, 0, len(attrs))
|
||||
for k := range attrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := range keys {
|
||||
name := keys[i]
|
||||
attrS := attrs[name]
|
||||
if attrS.NestedType != nil {
|
||||
diags = diags.Append(writeConfigNestedTypeAttribute(addr, buf, name, attrS, indent))
|
||||
continue
|
||||
}
|
||||
if attrS.Required {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = ", name))
|
||||
tok := hclwrite.TokensForValue(attrS.EmptyValue())
|
||||
if _, err := tok.WriteTo(buf); err != nil {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Skipped part of config generation",
|
||||
Detail: fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
|
||||
Extra: err,
|
||||
})
|
||||
continue
|
||||
}
|
||||
writeAttrTypeConstraint(buf, attrS)
|
||||
} else if attrS.Optional {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = ", name))
|
||||
tok := hclwrite.TokensForValue(attrS.EmptyValue())
|
||||
if _, err := tok.WriteTo(buf); err != nil {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Skipped part of config generation",
|
||||
Detail: fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
|
||||
Extra: err,
|
||||
})
|
||||
continue
|
||||
}
|
||||
writeAttrTypeConstraint(buf, attrS)
|
||||
}
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
func writeConfigAttributesFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, stateVal cty.Value, attrs map[string]*configschema.Attribute, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
if len(attrs) == 0 {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted attribute names so the output will be consistent between runs.
|
||||
keys := make([]string, 0, len(attrs))
|
||||
for k := range attrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := range keys {
|
||||
name := keys[i]
|
||||
attrS := attrs[name]
|
||||
if attrS.NestedType != nil {
|
||||
writeConfigNestedTypeAttributeFromExisting(addr, buf, name, attrS, stateVal, indent)
|
||||
continue
|
||||
}
|
||||
|
||||
// Exclude computed-only attributes
|
||||
if attrS.Required || attrS.Optional {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = ", name))
|
||||
|
||||
var val cty.Value
|
||||
if stateVal.Type().HasAttribute(name) {
|
||||
val = stateVal.GetAttr(name)
|
||||
} else {
|
||||
val = attrS.EmptyValue()
|
||||
}
|
||||
if val.Type() == cty.String {
|
||||
// SHAMELESS HACK: If we have "" for an optional value, assume
|
||||
// it is actually null, due to the legacy SDK.
|
||||
if !val.IsNull() && attrS.Optional && len(val.AsString()) == 0 {
|
||||
val = attrS.EmptyValue()
|
||||
}
|
||||
}
|
||||
if attrS.Sensitive || val.IsMarked() {
|
||||
buf.WriteString("null # sensitive")
|
||||
} else {
|
||||
tok := hclwrite.TokensForValue(val)
|
||||
if _, err := tok.WriteTo(buf); err != nil {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Skipped part of config generation",
|
||||
Detail: fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
|
||||
Extra: err,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
func writeConfigBlocks(addr addrs.AbsResourceInstance, buf *strings.Builder, blocks map[string]*configschema.NestedBlock, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if len(blocks) == 0 {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted block names so the output will be consistent between runs.
|
||||
names := make([]string, 0, len(blocks))
|
||||
for k := range blocks {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for i := range names {
|
||||
name := names[i]
|
||||
blockS := blocks[name]
|
||||
diags = diags.Append(writeConfigNestedBlock(addr, buf, name, blockS, indent))
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
func writeConfigNestedBlock(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.NestedBlock, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
switch schema.Nesting {
|
||||
case configschema.NestingSingle, configschema.NestingGroup:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s {", name))
|
||||
writeBlockTypeConstraint(buf, schema)
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
case configschema.NestingList, configschema.NestingSet:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s {", name))
|
||||
writeBlockTypeConstraint(buf, schema)
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
case configschema.NestingMap:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
// we use an arbitrary placeholder key (block label) "key"
|
||||
buf.WriteString(fmt.Sprintf("%s \"key\" {", name))
|
||||
writeBlockTypeConstraint(buf, schema)
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
default:
|
||||
// This should not happen, the above should be exhaustive.
|
||||
panic(fmt.Errorf("unsupported NestingMode %s", schema.Nesting.String()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeConfigNestedTypeAttribute(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.Attribute, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = ", name))
|
||||
|
||||
switch schema.NestedType.Nesting {
|
||||
case configschema.NestingSingle:
|
||||
buf.WriteString("{")
|
||||
writeAttrTypeConstraint(buf, schema)
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+2))
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
case configschema.NestingList, configschema.NestingSet:
|
||||
buf.WriteString("[{")
|
||||
writeAttrTypeConstraint(buf, schema)
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+2))
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}]\n")
|
||||
return diags
|
||||
case configschema.NestingMap:
|
||||
buf.WriteString("{")
|
||||
writeAttrTypeConstraint(buf, schema)
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
// we use an arbitrary placeholder key "key"
|
||||
buf.WriteString("key = {\n")
|
||||
diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+4))
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString("}\n")
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
default:
|
||||
// This should not happen, the above should be exhaustive.
|
||||
panic(fmt.Errorf("unsupported NestingMode %s", schema.NestedType.Nesting.String()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeConfigBlocksFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, stateVal cty.Value, blocks map[string]*configschema.NestedBlock, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if len(blocks) == 0 {
|
||||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted block names so the output will be consistent between runs.
|
||||
names := make([]string, 0, len(blocks))
|
||||
for k := range blocks {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for _, name := range names {
|
||||
blockS := blocks[name]
|
||||
// This shouldn't happen in real usage; state always has all values (set
|
||||
// to null as needed), but it protects against panics in tests (and any
|
||||
// really weird and unlikely cases).
|
||||
if !stateVal.Type().HasAttribute(name) {
|
||||
continue
|
||||
}
|
||||
blockVal := stateVal.GetAttr(name)
|
||||
diags = diags.Append(writeConfigNestedBlockFromExisting(addr, buf, name, blockS, blockVal, indent))
|
||||
}
|
||||
|
||||
return diags
|
||||
}
|
||||
|
||||
func writeConfigNestedTypeAttributeFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.Attribute, stateVal cty.Value, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
switch schema.NestedType.Nesting {
|
||||
case configschema.NestingSingle:
|
||||
if schema.Sensitive || stateVal.IsMarked() {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = {} # sensitive\n", name))
|
||||
return diags
|
||||
}
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = {\n", name))
|
||||
|
||||
// This shouldn't happen in real usage; state always has all values (set
|
||||
// to null as needed), but it protects against panics in tests (and any
|
||||
// really weird and unlikely cases).
|
||||
if !stateVal.Type().HasAttribute(name) {
|
||||
return diags
|
||||
}
|
||||
nestedVal := stateVal.GetAttr(name)
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, nestedVal, schema.NestedType.Attributes, indent+2))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
|
||||
case configschema.NestingList, configschema.NestingSet:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = [", name))
|
||||
|
||||
if schema.Sensitive || stateVal.IsMarked() {
|
||||
buf.WriteString("] # sensitive\n")
|
||||
return diags
|
||||
}
|
||||
|
||||
buf.WriteString("\n")
|
||||
|
||||
listVals := ctyCollectionValues(stateVal.GetAttr(name))
|
||||
for i := range listVals {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
|
||||
// The entire element is marked.
|
||||
if listVals[i].IsMarked() {
|
||||
buf.WriteString("{}, # sensitive\n")
|
||||
continue
|
||||
}
|
||||
|
||||
buf.WriteString("{\n")
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, listVals[i], schema.NestedType.Attributes, indent+4))
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString("},\n")
|
||||
}
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("]\n")
|
||||
return diags
|
||||
|
||||
case configschema.NestingMap:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = {", name))
|
||||
|
||||
if schema.Sensitive || stateVal.IsMarked() {
|
||||
buf.WriteString(" } # sensitive\n")
|
||||
return diags
|
||||
}
|
||||
|
||||
buf.WriteString("\n")
|
||||
|
||||
vals := stateVal.GetAttr(name).AsValueMap()
|
||||
keys := make([]string, 0, len(vals))
|
||||
for key := range vals {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(fmt.Sprintf("%s = {", key))
|
||||
|
||||
// This entire value is marked
|
||||
if vals[key].IsMarked() {
|
||||
buf.WriteString("} # sensitive\n")
|
||||
continue
|
||||
}
|
||||
|
||||
buf.WriteString("\n")
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, vals[key], schema.NestedType.Attributes, indent+4))
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString("}\n")
|
||||
}
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
|
||||
default:
|
||||
// This should not happen, the above should be exhaustive.
|
||||
panic(fmt.Errorf("unsupported NestingMode %s", schema.NestedType.Nesting.String()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeConfigNestedBlockFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.NestedBlock, stateVal cty.Value, indent int) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
switch schema.Nesting {
|
||||
case configschema.NestingSingle, configschema.NestingGroup:
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s {", name))
|
||||
|
||||
// If the entire value is marked, don't print any nested attributes
|
||||
if stateVal.IsMarked() {
|
||||
buf.WriteString("} # sensitive\n")
|
||||
return diags
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, stateVal, schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, stateVal, schema.BlockTypes, indent+2))
|
||||
buf.WriteString("}\n")
|
||||
return diags
|
||||
case configschema.NestingList, configschema.NestingSet:
|
||||
if stateVal.IsMarked() {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s {} # sensitive\n", name))
|
||||
return diags
|
||||
}
|
||||
listVals := ctyCollectionValues(stateVal)
|
||||
for i := range listVals {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s {\n", name))
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, listVals[i], schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, listVals[i], schema.BlockTypes, indent+2))
|
||||
buf.WriteString("}\n")
|
||||
}
|
||||
return diags
|
||||
case configschema.NestingMap:
|
||||
// If the entire value is marked, don't print any nested attributes
|
||||
if stateVal.IsMarked() {
|
||||
buf.WriteString(fmt.Sprintf("%s {} # sensitive\n", name))
|
||||
return diags
|
||||
}
|
||||
|
||||
vals := stateVal.AsValueMap()
|
||||
keys := make([]string, 0, len(vals))
|
||||
for key := range vals {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s %q {", name, key))
|
||||
// This entire map element is marked
|
||||
if vals[key].IsMarked() {
|
||||
buf.WriteString("} # sensitive\n")
|
||||
return diags
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, vals[key], schema.Attributes, indent+2))
|
||||
diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, vals[key], schema.BlockTypes, indent+2))
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString("}\n")
|
||||
}
|
||||
return diags
|
||||
default:
|
||||
// This should not happen, the above should be exhaustive.
|
||||
panic(fmt.Errorf("unsupported NestingMode %s", schema.Nesting.String()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeAttrTypeConstraint(buf *strings.Builder, schema *configschema.Attribute) {
|
||||
if schema.Required {
|
||||
buf.WriteString(" # REQUIRED ")
|
||||
} else {
|
||||
buf.WriteString(" # OPTIONAL ")
|
||||
}
|
||||
|
||||
if schema.NestedType != nil {
|
||||
buf.WriteString(fmt.Sprintf("%s\n", schema.NestedType.ImpliedType().FriendlyName()))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("%s\n", schema.Type.FriendlyName()))
|
||||
}
|
||||
}
|
||||
|
||||
func writeBlockTypeConstraint(buf *strings.Builder, schema *configschema.NestedBlock) {
|
||||
if schema.MinItems > 0 {
|
||||
buf.WriteString(" # REQUIRED block\n")
|
||||
} else {
|
||||
buf.WriteString(" # OPTIONAL block\n")
|
||||
}
|
||||
}
|
||||
|
||||
// copied from command/format/diff
|
||||
func ctyCollectionValues(val cty.Value) []cty.Value {
|
||||
if !val.IsKnown() || val.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var len int
|
||||
if val.IsMarked() {
|
||||
val, _ = val.Unmark()
|
||||
len = val.LengthInt()
|
||||
} else {
|
||||
len = val.LengthInt()
|
||||
}
|
||||
|
||||
ret := make([]cty.Value, 0, len)
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
_, value := it.Element()
|
||||
ret = append(ret, value)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// omitUnknowns recursively walks the src cty.Value and returns a new cty.Value,
|
||||
// omitting any unknowns.
|
||||
//
|
||||
// The result also normalizes some types: all sequence types are turned into
|
||||
// tuple types and all mapping types are converted to object types, since we
|
||||
// assume the result of this is just going to be serialized as JSON (and thus
|
||||
// lose those distinctions) anyway.
|
||||
func omitUnknowns(val cty.Value) cty.Value {
|
||||
ty := val.Type()
|
||||
switch {
|
||||
case val.IsNull():
|
||||
return val
|
||||
case !val.IsKnown():
|
||||
return cty.NilVal
|
||||
case ty.IsPrimitiveType():
|
||||
return val
|
||||
case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
|
||||
var vals []cty.Value
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, v := it.Element()
|
||||
newVal := omitUnknowns(v)
|
||||
if newVal != cty.NilVal {
|
||||
vals = append(vals, newVal)
|
||||
} else if newVal == cty.NilVal {
|
||||
// element order is how we correlate unknownness, so we must
|
||||
// replace unknowns with nulls
|
||||
vals = append(vals, cty.NullVal(v.Type()))
|
||||
}
|
||||
}
|
||||
// We use tuple types always here, because the work we did above
|
||||
// may have caused the individual elements to have different types,
|
||||
// and we're doing this work to produce JSON anyway and JSON marshalling
|
||||
// represents all of these sequence types as an array.
|
||||
return cty.TupleVal(vals)
|
||||
case ty.IsMapType() || ty.IsObjectType():
|
||||
vals := make(map[string]cty.Value)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
k, v := it.Element()
|
||||
newVal := omitUnknowns(v)
|
||||
if newVal != cty.NilVal {
|
||||
vals[k.AsString()] = newVal
|
||||
}
|
||||
}
|
||||
// We use object types always here, because the work we did above
|
||||
// may have caused the individual elements to have different types,
|
||||
// and we're doing this work to produce JSON anyway and JSON marshalling
|
||||
// represents both of these mapping types as an object.
|
||||
return cty.ObjectVal(vals)
|
||||
default:
|
||||
// Should never happen, since the above should cover all types
|
||||
panic(fmt.Sprintf("omitUnknowns cannot handle %#v", val))
|
||||
}
|
||||
}
|
308
internal/genconfig/generate_config_test.go
Normal file
308
internal/genconfig/generate_config_test.go
Normal file
@ -0,0 +1,308 @@
|
||||
package genconfig
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
)
|
||||
|
||||
func TestConfigGeneration(t *testing.T) {
|
||||
tcs := map[string]struct {
|
||||
schema *configschema.Block
|
||||
addr addrs.AbsResourceInstance
|
||||
provider addrs.LocalProviderConfig
|
||||
value cty.Value
|
||||
expected string
|
||||
}{
|
||||
"simple_resource": {
|
||||
schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"list_block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"nested_value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
addr: addrs.AbsResourceInstance{
|
||||
Module: nil,
|
||||
Resource: addrs.ResourceInstance{
|
||||
Resource: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "tfcoremock_simple_resource",
|
||||
Name: "empty",
|
||||
},
|
||||
Key: nil,
|
||||
},
|
||||
},
|
||||
provider: addrs.LocalProviderConfig{
|
||||
LocalName: "tfcoremock",
|
||||
},
|
||||
value: cty.NilVal,
|
||||
expected: `
|
||||
resource "tfcoremock_simple_resource" "empty" {
|
||||
value = null # OPTIONAL string
|
||||
list_block { # OPTIONAL block
|
||||
nested_value = null # OPTIONAL string
|
||||
}
|
||||
}`,
|
||||
},
|
||||
"simple_resource_with_state": {
|
||||
schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"list_block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"nested_value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
addr: addrs.AbsResourceInstance{
|
||||
Module: nil,
|
||||
Resource: addrs.ResourceInstance{
|
||||
Resource: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "tfcoremock_simple_resource",
|
||||
Name: "empty",
|
||||
},
|
||||
Key: nil,
|
||||
},
|
||||
},
|
||||
provider: addrs.LocalProviderConfig{
|
||||
LocalName: "tfcoremock",
|
||||
},
|
||||
value: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("D2320658"),
|
||||
"value": cty.StringVal("Hello, world!"),
|
||||
"list_block": cty.ObjectVal(map[string]cty.Value{
|
||||
"nested_value": cty.StringVal("Hello, solar system!"),
|
||||
}),
|
||||
}),
|
||||
expected: `
|
||||
resource "tfcoremock_simple_resource" "empty" {
|
||||
value = "Hello, world!"
|
||||
list_block {
|
||||
nested_value = "Hello, solar system!"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
"simple_resource_with_partial_state": {
|
||||
schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"list_block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"nested_value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
addr: addrs.AbsResourceInstance{
|
||||
Module: nil,
|
||||
Resource: addrs.ResourceInstance{
|
||||
Resource: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "tfcoremock_simple_resource",
|
||||
Name: "empty",
|
||||
},
|
||||
Key: nil,
|
||||
},
|
||||
},
|
||||
provider: addrs.LocalProviderConfig{
|
||||
LocalName: "tfcoremock",
|
||||
},
|
||||
value: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("D2320658"),
|
||||
"list_block": cty.ObjectVal(map[string]cty.Value{
|
||||
"nested_value": cty.StringVal("Hello, solar system!"),
|
||||
}),
|
||||
}),
|
||||
expected: `
|
||||
resource "tfcoremock_simple_resource" "empty" {
|
||||
value = null
|
||||
list_block {
|
||||
nested_value = "Hello, solar system!"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
"simple_resource_with_alternate_provider": {
|
||||
schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"list_block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"nested_value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
addr: addrs.AbsResourceInstance{
|
||||
Module: nil,
|
||||
Resource: addrs.ResourceInstance{
|
||||
Resource: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "tfcoremock_simple_resource",
|
||||
Name: "empty",
|
||||
},
|
||||
Key: nil,
|
||||
},
|
||||
},
|
||||
provider: addrs.LocalProviderConfig{
|
||||
LocalName: "mock",
|
||||
},
|
||||
value: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("D2320658"),
|
||||
"value": cty.StringVal("Hello, world!"),
|
||||
"list_block": cty.ObjectVal(map[string]cty.Value{
|
||||
"nested_value": cty.StringVal("Hello, solar system!"),
|
||||
}),
|
||||
}),
|
||||
expected: `
|
||||
resource "tfcoremock_simple_resource" "empty" {
|
||||
provider = mock
|
||||
value = "Hello, world!"
|
||||
list_block {
|
||||
nested_value = "Hello, solar system!"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
"simple_resource_with_aliased_provider": {
|
||||
schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"list_block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"nested_value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
addr: addrs.AbsResourceInstance{
|
||||
Module: nil,
|
||||
Resource: addrs.ResourceInstance{
|
||||
Resource: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "tfcoremock_simple_resource",
|
||||
Name: "empty",
|
||||
},
|
||||
Key: nil,
|
||||
},
|
||||
},
|
||||
provider: addrs.LocalProviderConfig{
|
||||
LocalName: "tfcoremock",
|
||||
Alias: "alternate",
|
||||
},
|
||||
value: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("D2320658"),
|
||||
"value": cty.StringVal("Hello, world!"),
|
||||
"list_block": cty.ObjectVal(map[string]cty.Value{
|
||||
"nested_value": cty.StringVal("Hello, solar system!"),
|
||||
}),
|
||||
}),
|
||||
expected: `
|
||||
resource "tfcoremock_simple_resource" "empty" {
|
||||
provider = tfcoremock.alternate
|
||||
value = "Hello, world!"
|
||||
list_block {
|
||||
nested_value = "Hello, solar system!"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
}
|
||||
for name, tc := range tcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
contents, diags := GenerateResourceContents(tc.addr, tc.schema, tc.provider, tc.value)
|
||||
if len(diags) > 0 {
|
||||
t.Errorf("expected no diagnostics but found %s", diags)
|
||||
}
|
||||
|
||||
got := WrapResourceContents(tc.addr, contents)
|
||||
want := strings.TrimSpace(tc.expected)
|
||||
if diff := cmp.Diff(got, want); len(diff) > 0 {
|
||||
t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -308,10 +308,11 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||
Private: rc.Private,
|
||||
ProviderAddr: rc.ProviderAddr,
|
||||
Change: Change{
|
||||
Action: Delete,
|
||||
Before: rc.Before,
|
||||
After: cty.NullVal(rc.Before.Type()),
|
||||
Importing: rc.Importing,
|
||||
Action: Delete,
|
||||
Before: rc.Before,
|
||||
After: cty.NullVal(rc.Before.Type()),
|
||||
Importing: rc.Importing,
|
||||
GeneratedConfig: rc.GeneratedConfig,
|
||||
},
|
||||
}
|
||||
default:
|
||||
@ -321,10 +322,11 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||
Private: rc.Private,
|
||||
ProviderAddr: rc.ProviderAddr,
|
||||
Change: Change{
|
||||
Action: NoOp,
|
||||
Before: rc.Before,
|
||||
After: rc.Before,
|
||||
Importing: rc.Importing,
|
||||
Action: NoOp,
|
||||
Before: rc.Before,
|
||||
After: rc.Before,
|
||||
Importing: rc.Importing,
|
||||
GeneratedConfig: rc.GeneratedConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -337,10 +339,11 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||
Private: rc.Private,
|
||||
ProviderAddr: rc.ProviderAddr,
|
||||
Change: Change{
|
||||
Action: NoOp,
|
||||
Before: rc.Before,
|
||||
After: rc.Before,
|
||||
Importing: rc.Importing,
|
||||
Action: NoOp,
|
||||
Before: rc.Before,
|
||||
After: rc.Before,
|
||||
Importing: rc.Importing,
|
||||
GeneratedConfig: rc.GeneratedConfig,
|
||||
},
|
||||
}
|
||||
case CreateThenDelete, DeleteThenCreate:
|
||||
@ -350,10 +353,11 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||
Private: rc.Private,
|
||||
ProviderAddr: rc.ProviderAddr,
|
||||
Change: Change{
|
||||
Action: Create,
|
||||
Before: cty.NullVal(rc.After.Type()),
|
||||
After: rc.After,
|
||||
Importing: rc.Importing,
|
||||
Action: Create,
|
||||
Before: cty.NullVal(rc.After.Type()),
|
||||
After: rc.After,
|
||||
Importing: rc.Importing,
|
||||
GeneratedConfig: rc.GeneratedConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -533,6 +537,12 @@ type Change struct {
|
||||
// Use the simple presence of this field to detect if a ChangeSrc is to be
|
||||
// imported, the contents of this structure may be modified going forward.
|
||||
Importing *Importing
|
||||
|
||||
// GeneratedConfig contains any HCL config generated for this resource
|
||||
// during planning, as a string. If GeneratedConfig is populated, Importing
|
||||
// should be true. However, not all Importing changes contain generated
|
||||
// config.
|
||||
GeneratedConfig string
|
||||
}
|
||||
|
||||
// Encode produces a variant of the reciever that has its change values
|
||||
@ -572,11 +582,12 @@ func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) {
|
||||
}
|
||||
|
||||
return &ChangeSrc{
|
||||
Action: c.Action,
|
||||
Before: beforeDV,
|
||||
After: afterDV,
|
||||
BeforeValMarks: beforeVM,
|
||||
AfterValMarks: afterVM,
|
||||
Importing: importing,
|
||||
Action: c.Action,
|
||||
Before: beforeDV,
|
||||
After: afterDV,
|
||||
BeforeValMarks: beforeVM,
|
||||
AfterValMarks: afterVM,
|
||||
Importing: importing,
|
||||
GeneratedConfig: c.GeneratedConfig,
|
||||
}, nil
|
||||
}
|
||||
|
@ -218,6 +218,12 @@ type ChangeSrc struct {
|
||||
// Use the simple presence of this field to detect if a ChangeSrc is to be
|
||||
// imported, the contents of this structure may be modified going forward.
|
||||
Importing *ImportingSrc
|
||||
|
||||
// GeneratedConfig contains any HCL config generated for this resource
|
||||
// during planning, as a string. If GeneratedConfig is populated, Importing
|
||||
// should be true. However, not all Importing changes contain generated
|
||||
// config.
|
||||
GeneratedConfig string
|
||||
}
|
||||
|
||||
// Decode unmarshals the raw representations of the before and after values
|
||||
@ -251,9 +257,10 @@ func (cs *ChangeSrc) Decode(ty cty.Type) (*Change, error) {
|
||||
}
|
||||
|
||||
return &Change{
|
||||
Action: cs.Action,
|
||||
Before: before.MarkWithPaths(cs.BeforeValMarks),
|
||||
After: after.MarkWithPaths(cs.AfterValMarks),
|
||||
Importing: importing,
|
||||
Action: cs.Action,
|
||||
Before: before.MarkWithPaths(cs.BeforeValMarks),
|
||||
After: after.MarkWithPaths(cs.AfterValMarks),
|
||||
Importing: importing,
|
||||
GeneratedConfig: cs.GeneratedConfig,
|
||||
}, nil
|
||||
}
|
||||
|
@ -621,6 +621,9 @@ type Change struct {
|
||||
// Importing, if true, specifies that the resource is being imported as part
|
||||
// of the change.
|
||||
Importing *Importing `protobuf:"bytes,5,opt,name=importing,proto3" json:"importing,omitempty"`
|
||||
// GeneratedConfig contains any configuration that was generated as part of
|
||||
// the change, as an HCL string.
|
||||
GeneratedConfig string `protobuf:"bytes,6,opt,name=generated_config,json=generatedConfig,proto3" json:"generated_config,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Change) Reset() {
|
||||
@ -690,6 +693,13 @@ func (x *Change) GetImporting() *Importing {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Change) GetGeneratedConfig() string {
|
||||
if x != nil {
|
||||
return x.GeneratedConfig
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ResourceInstanceChange struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -1391,7 +1401,7 @@ var file_planfile_proto_rawDesc = []byte{
|
||||
0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
|
||||
0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73,
|
||||
0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x95, 0x02, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xc0, 0x02, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75,
|
||||
@ -1408,125 +1418,127 @@ var file_planfile_proto_rawDesc = []byte{
|
||||
0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x2f, 0x0a, 0x09,
|
||||
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xd3, 0x02,
|
||||
0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72,
|
||||
0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x22, 0x0a, 0x0d,
|
||||
0x70, 0x72, 0x65, 0x76, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0e, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x52, 0x75, 0x6e, 0x41, 0x64, 0x64, 0x72,
|
||||
0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x4b, 0x65,
|
||||
0x79, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a,
|
||||
0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
||||
0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12,
|
||||
0x37, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c,
|
||||
0x61, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c,
|
||||
0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
|
||||
0x64, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61,
|
||||
0x73, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
||||
0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0xe8, 0x03,
|
||||
0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x33,
|
||||
0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74,
|
||||
0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c,
|
||||
0x74, 0x73, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b,
|
||||
0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x64,
|
||||
0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x41, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68,
|
||||
0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x62, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x66, 0x70,
|
||||
0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
|
||||
0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x6f,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x1a, 0x8f, 0x01, 0x0a, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63,
|
||||
0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63,
|
||||
0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61,
|
||||
0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a,
|
||||
0x10, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
|
||||
0x08, 0x0a, 0x04, 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49,
|
||||
0x4c, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x48,
|
||||
0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b,
|
||||
0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a,
|
||||
0x08, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f,
|
||||
0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a,
|
||||
0x05, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x03, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61,
|
||||
0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70,
|
||||
0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x22, 0xa5, 0x01, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73,
|
||||
0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70,
|
||||
0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73,
|
||||
0x74, 0x65, 0x70, 0x73, 0x1a, 0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e,
|
||||
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70,
|
||||
0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x48, 0x00, 0x52, 0x0a, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a,
|
||||
0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12,
|
||||
0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44,
|
||||
0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52,
|
||||
0x45, 0x53, 0x48, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45,
|
||||
0x41, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12,
|
||||
0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41,
|
||||
0x54, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54,
|
||||
0x48, 0x45, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0xc8, 0x03, 0x0a,
|
||||
0x1c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a,
|
||||
0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41,
|
||||
0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54,
|
||||
0x45, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f,
|
||||
0x42, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d,
|
||||
0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f,
|
||||
0x43, 0x41, 0x4e, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12,
|
||||
0x25, 0x0a, 0x21, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53,
|
||||
0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f,
|
||||
0x4e, 0x46, 0x49, 0x47, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
|
||||
0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52,
|
||||
0x45, 0x50, 0x45, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44,
|
||||
0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f,
|
||||
0x55, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44,
|
||||
0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41,
|
||||
0x43, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45,
|
||||
0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f,
|
||||
0x44, 0x55, 0x4c, 0x45, 0x10, 0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43,
|
||||
0x45, 0x5f, 0x42, 0x59, 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12,
|
||||
0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f,
|
||||
0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a,
|
||||
0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45,
|
||||
0x5f, 0x44, 0x45, 0x50, 0x45, 0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44,
|
||||
0x49, 0x4e, 0x47, 0x10, 0x0b, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45,
|
||||
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54,
|
||||
0x45, 0x44, 0x10, 0x0d, 0x12, 0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42,
|
||||
0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54,
|
||||
0x41, 0x52, 0x47, 0x45, 0x54, 0x10, 0x0c, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
|
||||
0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
0x6e, 0x67, 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a,
|
||||
0x10, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
|
||||
0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xd3, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f,
|
||||
0x72, 0x75, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||
0x70, 0x72, 0x65, 0x76, 0x52, 0x75, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x64,
|
||||
0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61,
|
||||
0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x10, 0x72, 0x65,
|
||||
0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x0b,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61,
|
||||
0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c,
|
||||
0x61, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65,
|
||||
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66, 0x70,
|
||||
0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x68,
|
||||
0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65,
|
||||
0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73,
|
||||
0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x33, 0x0a, 0x04, 0x6b, 0x69, 0x6e,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
||||
0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x4f, 0x62,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1f,
|
||||
0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x64, 0x64, 0x72, 0x12,
|
||||
0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
|
||||
0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18,
|
||||
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43,
|
||||
0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x4f, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x73, 0x1a, 0x8f, 0x01, 0x0a, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x75,
|
||||
0x6c, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64,
|
||||
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41,
|
||||
0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x66, 0x61, 0x69, 0x6c,
|
||||
0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x41,
|
||||
0x53, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x09,
|
||||
0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x48, 0x0a, 0x0a, 0x4f, 0x62, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45,
|
||||
0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x4f,
|
||||
0x55, 0x52, 0x43, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54,
|
||||
0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43,
|
||||
0x4b, 0x10, 0x03, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x22, 0xa5, 0x01,
|
||||
0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50,
|
||||
0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a,
|
||||
0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||
0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44,
|
||||
0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x65,
|
||||
0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
||||
0x69, 0x64, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f,
|
||||
0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f,
|
||||
0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f,
|
||||
0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||
0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45,
|
||||
0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12,
|
||||
0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44,
|
||||
0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54,
|
||||
0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12,
|
||||
0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44,
|
||||
0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0xc8, 0x03, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45,
|
||||
0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45,
|
||||
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12,
|
||||
0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, 0x45,
|
||||
0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, 0x41,
|
||||
0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, 0x4f,
|
||||
0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x44, 0x45,
|
||||
0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f,
|
||||
0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
|
||||
0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41,
|
||||
0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x54, 0x49,
|
||||
0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
|
||||
0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x49,
|
||||
0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
|
||||
0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x4b, 0x45,
|
||||
0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45,
|
||||
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10,
|
||||
0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f,
|
||||
0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45,
|
||||
0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49,
|
||||
0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12, 0x23, 0x0a, 0x1f, 0x52,
|
||||
0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x45,
|
||||
0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0b,
|
||||
0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45,
|
||||
0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12,
|
||||
0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53,
|
||||
0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54,
|
||||
0x10, 0x0c, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c,
|
||||
0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61,
|
||||
0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -147,6 +147,10 @@ message Change {
|
||||
// Importing, if true, specifies that the resource is being imported as part
|
||||
// of the change.
|
||||
Importing importing = 5;
|
||||
|
||||
// GeneratedConfig contains any configuration that was generated as part of
|
||||
// the change, as an HCL string.
|
||||
string generated_config = 6;
|
||||
}
|
||||
|
||||
// ResourceInstanceActionReason sometimes provides some additional user-facing
|
||||
|
@ -4361,3 +4361,158 @@ import {
|
||||
t.Error("ReadResource called multiple times for import")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_importIntoModuleWithGeneratedConfig(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
import {
|
||||
to = test_object.a
|
||||
id = "123"
|
||||
}
|
||||
|
||||
import {
|
||||
to = module.mod.test_object.a
|
||||
id = "456"
|
||||
}
|
||||
|
||||
module "mod" {
|
||||
source = "./mod"
|
||||
}
|
||||
`,
|
||||
"./mod/main.tf": `
|
||||
resource "test_object" "a" {
|
||||
test_string = "bar"
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := simpleMockProvider()
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
p.ReadResourceResponse = &providers.ReadResourceResponse{
|
||||
NewState: cty.ObjectVal(map[string]cty.Value{
|
||||
"test_string": cty.StringVal("foo"),
|
||||
}),
|
||||
}
|
||||
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
|
||||
ImportedResources: []providers.ImportedResource{
|
||||
{
|
||||
TypeName: "test_object",
|
||||
State: cty.ObjectVal(map[string]cty.Value{
|
||||
"test_string": cty.StringVal("foo"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
|
||||
ImportedResources: []providers.ImportedResource{
|
||||
{
|
||||
TypeName: "test_object",
|
||||
State: cty.ObjectVal(map[string]cty.Value{
|
||||
"test_string": cty.StringVal("foo"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
|
||||
}
|
||||
|
||||
one := mustResourceInstanceAddr("test_object.a")
|
||||
two := mustResourceInstanceAddr("module.mod.test_object.a")
|
||||
|
||||
onePlan := plan.Changes.ResourceInstance(one)
|
||||
twoPlan := plan.Changes.ResourceInstance(two)
|
||||
|
||||
// This test is just to make sure things work e2e with modules and generated
|
||||
// config, so we're not too careful about the actual responses - we're just
|
||||
// happy nothing panicked. See the other import tests for actual validation
|
||||
// of responses and the like.
|
||||
if twoPlan.Action != plans.Update {
|
||||
t.Errorf("expected nested item to be updated but was %s", twoPlan.Action)
|
||||
}
|
||||
|
||||
if len(onePlan.GeneratedConfig) == 0 {
|
||||
t.Errorf("expected root item to generate config but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_importResourceConfigGen(t *testing.T) {
|
||||
addr := mustResourceInstanceAddr("test_object.a")
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
import {
|
||||
to = test_object.a
|
||||
id = "123"
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := simpleMockProvider()
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
p.ReadResourceResponse = &providers.ReadResourceResponse{
|
||||
NewState: cty.ObjectVal(map[string]cty.Value{
|
||||
"test_string": cty.StringVal("foo"),
|
||||
}),
|
||||
}
|
||||
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
|
||||
ImportedResources: []providers.ImportedResource{
|
||||
{
|
||||
TypeName: "test_object",
|
||||
State: cty.ObjectVal(map[string]cty.Value{
|
||||
"test_string": cty.StringVal("foo"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
|
||||
}
|
||||
|
||||
t.Run(addr.String(), func(t *testing.T) {
|
||||
instPlan := plan.Changes.ResourceInstance(addr)
|
||||
if instPlan == nil {
|
||||
t.Fatalf("no plan for %s at all", addr)
|
||||
}
|
||||
|
||||
if got, want := instPlan.Addr, addr; !got.Equal(want) {
|
||||
t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
|
||||
t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := instPlan.Action, plans.NoOp; got != want {
|
||||
t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
||||
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if instPlan.Importing.ID != "123" {
|
||||
t.Errorf("expected import change from \"123\", got non-import change")
|
||||
}
|
||||
|
||||
want := `resource "test_object" "a" {
|
||||
test_bool = null
|
||||
test_list = null
|
||||
test_map = null
|
||||
test_number = null
|
||||
test_string = "foo"
|
||||
}`
|
||||
got := instPlan.GeneratedConfig
|
||||
if diff := cmp.Diff(want, got); len(diff) > 0 {
|
||||
t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -111,6 +111,10 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||
skip: b.Operation == walkPlanDestroy,
|
||||
|
||||
importTargets: b.ImportTargets,
|
||||
|
||||
// We only want to generate config during a plan operation.
|
||||
// TODO: add a dedicated flag for this?
|
||||
generateConfigForImportTargets: b.Operation == walkPlan,
|
||||
},
|
||||
|
||||
// Add dynamic values
|
||||
|
@ -360,7 +360,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
|
||||
expander := ctx.InstanceExpander()
|
||||
|
||||
switch {
|
||||
case n.Config.Count != nil:
|
||||
case n.Config != nil && n.Config.Count != nil:
|
||||
count, countDiags := evaluateCountExpression(n.Config.Count, ctx)
|
||||
diags = diags.Append(countDiags)
|
||||
if countDiags.HasErrors() {
|
||||
@ -370,7 +370,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
|
||||
state.SetResourceProvider(addr, n.ResolvedProvider)
|
||||
expander.SetResourceCount(addr.Module, n.Addr.Resource, count)
|
||||
|
||||
case n.Config.ForEach != nil:
|
||||
case n.Config != nil && n.Config.ForEach != nil:
|
||||
forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx)
|
||||
diags = diags.Append(forEachDiags)
|
||||
if forEachDiags.HasErrors() {
|
||||
|
@ -9,12 +9,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/checks"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/genconfig"
|
||||
"github.com/hashicorp/terraform/internal/instances"
|
||||
"github.com/hashicorp/terraform/internal/plans"
|
||||
"github.com/hashicorp/terraform/internal/plans/objchange"
|
||||
@ -648,19 +650,69 @@ func (n *NodeAbstractResourceInstance) plan(
|
||||
plannedChange *plans.ResourceInstanceChange,
|
||||
currentState *states.ResourceInstanceObject,
|
||||
createBeforeDestroy bool,
|
||||
forceReplace []addrs.AbsResourceInstance) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
|
||||
forceReplace []addrs.AbsResourceInstance,
|
||||
generateConfig bool,
|
||||
) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
var state *states.ResourceInstanceObject
|
||||
var plan *plans.ResourceInstanceChange
|
||||
var keyData instances.RepetitionData
|
||||
var generatedConfig *configs.Resource
|
||||
|
||||
config := *n.Config
|
||||
resource := n.Addr.Resource.Resource
|
||||
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
|
||||
if err != nil {
|
||||
return plan, state, keyData, diags.Append(err)
|
||||
}
|
||||
|
||||
if providerSchema == nil {
|
||||
diags = diags.Append(fmt.Errorf("provider schema is unavailable for %s", n.Addr))
|
||||
return plan, state, keyData, diags
|
||||
}
|
||||
schema, _ := providerSchema.SchemaForResourceAddr(resource)
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", resource.Type))
|
||||
return plan, state, keyData, diags
|
||||
}
|
||||
|
||||
// If we're importing and generating config, generate it now.
|
||||
var generatedHCL string
|
||||
if generateConfig {
|
||||
var generatedDiags tfdiags.Diagnostics
|
||||
|
||||
if n.Config != nil {
|
||||
return plan, state, keyData, diags.Append(fmt.Errorf("tried to generate config for %s, but it already exists", n.Addr))
|
||||
}
|
||||
|
||||
// Generate the HCL string first, then parse the HCL body from it.
|
||||
// First we generate the contents of the resource block for use within
|
||||
// the planning node. Then we wrap it in an enclosing resource block to
|
||||
// pass into the plan for rendering.
|
||||
generatedHCLAttributes, generatedDiags := n.generateHCLStringAttributes(n.Addr, currentState, schema)
|
||||
diags = diags.Append(generatedDiags)
|
||||
|
||||
generatedHCL = genconfig.WrapResourceContents(n.Addr, generatedHCLAttributes)
|
||||
|
||||
// parse the "file" as HCL to get the hcl.Body
|
||||
synthHCLFile, hclDiags := hclsyntax.ParseConfig([]byte(generatedHCLAttributes), "generated_resources.tf", hcl.Pos{Byte: 0, Line: 1, Column: 1})
|
||||
if hclDiags.HasErrors() {
|
||||
return plan, state, keyData, diags.Append(hclDiags)
|
||||
}
|
||||
|
||||
generatedConfig = &configs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: n.Addr.Resource.Resource.Type,
|
||||
Name: n.Addr.Resource.Resource.Name,
|
||||
Config: synthHCLFile.Body,
|
||||
Managed: &configs.ManagedResource{},
|
||||
Provider: n.ResolvedProvider.Provider,
|
||||
}
|
||||
n.Config = generatedConfig
|
||||
}
|
||||
|
||||
config := *n.Config
|
||||
|
||||
checkRuleSeverity := tfdiags.Error
|
||||
if n.preDestroyRefresh {
|
||||
checkRuleSeverity = tfdiags.Warning
|
||||
@ -671,18 +723,7 @@ func (n *NodeAbstractResourceInstance) plan(
|
||||
createBeforeDestroy = plannedChange.Action == plans.CreateThenDelete
|
||||
}
|
||||
|
||||
if providerSchema == nil {
|
||||
diags = diags.Append(fmt.Errorf("provider schema is unavailable for %s", n.Addr))
|
||||
return plan, state, keyData, diags
|
||||
}
|
||||
|
||||
// Evaluate the configuration
|
||||
schema, _ := providerSchema.SchemaForResourceAddr(resource)
|
||||
if schema == nil {
|
||||
// Should be caught during validation, so we don't bother with a pretty error here
|
||||
diags = diags.Append(fmt.Errorf("provider does not support resource type %q", resource.Type))
|
||||
return plan, state, keyData, diags
|
||||
}
|
||||
|
||||
forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx)
|
||||
|
||||
@ -1124,7 +1165,8 @@ func (n *NodeAbstractResourceInstance) plan(
|
||||
// Pass the marked planned value through in our change
|
||||
// to propogate through evaluation.
|
||||
// Marks will be removed when encoding.
|
||||
After: plannedNewVal,
|
||||
After: plannedNewVal,
|
||||
GeneratedConfig: generatedHCL,
|
||||
},
|
||||
ActionReason: actionReason,
|
||||
RequiredReplace: reqRep,
|
||||
@ -1146,6 +1188,21 @@ func (n *NodeAbstractResourceInstance) plan(
|
||||
return plan, state, keyData, diags
|
||||
}
|
||||
|
||||
// generateHCLStringAttributes produces a string in HCL format for the given
|
||||
// resource state and schema without the surrounding block.
|
||||
func (n *NodeAbstractResource) generateHCLStringAttributes(addr addrs.AbsResourceInstance, state *states.ResourceInstanceObject, schema *configschema.Block) (string, tfdiags.Diagnostics) {
|
||||
filteredSchema := schema.Filter(
|
||||
configschema.FilterOr(configschema.FilterReadOnlyAttributes, configschema.FilterDeprecatedAttribute),
|
||||
configschema.FilterDeprecatedBlock)
|
||||
|
||||
providerAddr := addrs.LocalProviderConfig{
|
||||
LocalName: n.ResolvedProvider.Provider.Type,
|
||||
Alias: n.ResolvedProvider.Alias,
|
||||
}
|
||||
|
||||
return genconfig.GenerateResourceContents(addr, filteredSchema, providerAddr, state.Value)
|
||||
}
|
||||
|
||||
func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) {
|
||||
// ignore_changes only applies when an object already exists, since we
|
||||
// can't ignore changes to a thing we've not created yet.
|
||||
|
@ -274,7 +274,7 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
|
||||
// Make a new diff, in case we've learned new values in the state
|
||||
// during apply which we can now incorporate.
|
||||
diffApply, _, repeatData, planDiags := n.plan(ctx, diff, state, false, n.forceReplace)
|
||||
diffApply, _, repeatData, planDiags := n.plan(ctx, diff, state, false, n.forceReplace, false)
|
||||
diags = diags.Append(planDiags)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
|
@ -5,7 +5,6 @@ package terraform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -200,12 +199,6 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, er
|
||||
func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalContext, resAddr addrs.AbsResource, g *Graph, instAddrs addrs.Set[addrs.Checkable]) error {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if n.Config == nil {
|
||||
// Nothing to do, then.
|
||||
log.Printf("[TRACE] nodeExpandPlannableResource: no configuration present for %s", n.Name())
|
||||
return diags.ErrWithWarnings()
|
||||
}
|
||||
|
||||
// The rest of our work here needs to know which module instance it's
|
||||
// working in, so that it can evaluate expressions in the appropriate scope.
|
||||
moduleCtx := globalCtx.WithPath(resAddr.Module)
|
||||
|
@ -135,6 +135,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
|
||||
var change *plans.ResourceInstanceChange
|
||||
var instanceRefreshState *states.ResourceInstanceObject
|
||||
var generateConfig bool
|
||||
|
||||
checkRuleSeverity := tfdiags.Error
|
||||
if n.skipPlanChanges || n.preDestroyRefresh {
|
||||
@ -147,9 +148,11 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
return diags
|
||||
}
|
||||
|
||||
diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
if config != nil {
|
||||
diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
importing := n.importTarget.ID != ""
|
||||
@ -157,6 +160,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
// If the resource is to be imported, we now ask the provider for an Import
|
||||
// and a Refresh, and save the resulting state to instanceRefreshState.
|
||||
if importing {
|
||||
if n.Config == nil || n.Config.Managed == nil {
|
||||
generateConfig = true
|
||||
}
|
||||
instanceRefreshState, diags = n.importState(ctx, addr, provider)
|
||||
} else {
|
||||
var readDiags tfdiags.Diagnostics
|
||||
@ -239,7 +245,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
}
|
||||
|
||||
change, instancePlanState, repeatData, planDiags := n.plan(
|
||||
ctx, change, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace,
|
||||
ctx, change, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace, generateConfig,
|
||||
)
|
||||
diags = diags.Append(planDiags)
|
||||
if diags.HasErrors() {
|
||||
@ -361,6 +367,9 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||
// instance address is added to forceReplace
|
||||
func (n *NodePlannableResourceInstance) replaceTriggered(ctx EvalContext, repData instances.RepetitionData) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
if n.Config == nil {
|
||||
return diags
|
||||
}
|
||||
|
||||
for _, expr := range n.Config.TriggersReplacement {
|
||||
ref, replace, evalDiags := ctx.EvaluateReplaceTriggeredBy(expr, repData)
|
||||
|
@ -44,6 +44,10 @@ func (n *NodeValidatableResource) Path() addrs.ModuleInstance {
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||
if n.Config == nil {
|
||||
return diags
|
||||
}
|
||||
|
||||
diags = diags.Append(n.validateResource(ctx))
|
||||
|
||||
diags = diags.Append(n.validateCheckRules(ctx, n.Config))
|
||||
|
@ -35,8 +35,18 @@ type ConfigTransformer struct {
|
||||
// Do not apply this transformer.
|
||||
skip bool
|
||||
|
||||
// configuration resources that are to be imported
|
||||
// importTargets specifies a slice of addresses that will have state
|
||||
// imported for them.
|
||||
importTargets []*ImportTarget
|
||||
|
||||
// generateConfigForImportTargets tells the graph to generate config for any
|
||||
// import targets that are not contained within config.
|
||||
//
|
||||
// If this is false and an import target has no config, the graph will
|
||||
// simply import the state for the target and any follow-up operations will
|
||||
// try to delete the imported resource unless the config is updated
|
||||
// manually.
|
||||
generateConfigForImportTargets bool
|
||||
}
|
||||
|
||||
func (t *ConfigTransformer) Transform(g *Graph) error {
|
||||
@ -50,23 +60,23 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
|
||||
}
|
||||
|
||||
// Start the transformation process
|
||||
return t.transform(g, t.Config)
|
||||
return t.transform(g, t.Config, t.generateConfigForImportTargets)
|
||||
}
|
||||
|
||||
func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
|
||||
func (t *ConfigTransformer) transform(g *Graph, config *configs.Config, generateConfig bool) error {
|
||||
// If no config, do nothing
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add our resources
|
||||
if err := t.transformSingle(g, config); err != nil {
|
||||
if err := t.transformSingle(g, config, generateConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Transform all the children.
|
||||
// Transform all the children without generating config.
|
||||
for _, c := range config.Children {
|
||||
if err := t.transform(g, c); err != nil {
|
||||
if err := t.transform(g, c, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -74,7 +84,7 @@ func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error {
|
||||
func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config, generateConfig bool) error {
|
||||
path := config.Path
|
||||
module := config.Module
|
||||
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
|
||||
@ -87,6 +97,10 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
|
||||
allResources = append(allResources, r)
|
||||
}
|
||||
|
||||
// Take a copy of the import targets, so we can edit them as we go.
|
||||
var importTargets []*ImportTarget
|
||||
importTargets = append(importTargets, t.importTargets...)
|
||||
|
||||
for _, r := range allResources {
|
||||
relAddr := r.Addr()
|
||||
|
||||
@ -99,12 +113,28 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
|
||||
// filter them down to the applicable addresses.
|
||||
var imports []*ImportTarget
|
||||
configAddr := relAddr.InModule(path)
|
||||
for _, i := range t.importTargets {
|
||||
|
||||
var matchedIndices []int
|
||||
for ix, i := range importTargets {
|
||||
if target := i.Addr.ContainingResource().Config(); target.Equal(configAddr) {
|
||||
// This import target has been claimed by an actual resource,
|
||||
// let's make a note of this to remove it from the targets.
|
||||
matchedIndices = append(matchedIndices, ix)
|
||||
imports = append(imports, i)
|
||||
}
|
||||
}
|
||||
|
||||
for ix := len(matchedIndices) - 1; ix >= 0; ix-- {
|
||||
tIx := matchedIndices[ix]
|
||||
|
||||
// We do this backwards, since it means we don't have to adjust the
|
||||
// later indices as we change the length of import targets.
|
||||
//
|
||||
// We need to do this separately, as a single resource could match
|
||||
// multiple import targets.
|
||||
importTargets = append(importTargets[:tIx], importTargets[tIx+1:]...)
|
||||
}
|
||||
|
||||
abstract := &NodeAbstractResource{
|
||||
Addr: addrs.ConfigResource{
|
||||
Resource: relAddr,
|
||||
@ -121,5 +151,29 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
|
||||
g.Add(node)
|
||||
}
|
||||
|
||||
if generateConfig {
|
||||
// If any import targets were not claimed by resources, then we will
|
||||
// generate config for them.
|
||||
for _, i := range importTargets {
|
||||
if !i.Addr.Module.IsRoot() {
|
||||
// We only generate config for resources imported into the root
|
||||
// module.
|
||||
continue
|
||||
}
|
||||
|
||||
abstract := &NodeAbstractResource{
|
||||
Addr: i.Addr.ConfigResource(),
|
||||
importTargets: []*ImportTarget{i},
|
||||
}
|
||||
|
||||
var node dag.Vertex = abstract
|
||||
if f := t.Concrete; f != nil {
|
||||
node = f(abstract)
|
||||
}
|
||||
|
||||
g.Add(node)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user