Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

account for deposed in terraform show #22149

Merged
merged 1 commit into from
Jul 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 89 additions & 56 deletions command/format/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,78 +98,111 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf
// Go through each resource and begin building up the output.
for _, key := range names {
for k, v := range m.Resources[key].Instances {
// keep these in order to keep the current object first, and
// provide deterministic output for the deposed objects
type obj struct {
header string
instance *states.ResourceInstanceObjectSrc
}
instances := []obj{}

addr := m.Resources[key].Addr

taintStr := ""
if v.Current.Status == 'T' {
if v.Current != nil && v.Current.Status == 'T' {
taintStr = " (tainted)"
}
p.buf.WriteString(fmt.Sprintf("# %s:%s\n", addr.Absolute(m.Addr).Instance(k), taintStr))

var schema *configschema.Block
provider := m.Resources[key].ProviderConfig.ProviderConfig.StringCompact()
if _, exists := schemas.Providers[provider]; !exists {
// This should never happen in normal use because we should've
// loaded all of the schemas and checked things prior to this
// point. We can't return errors here, but since this is UI code
// we will try to do _something_ reasonable.
p.buf.WriteString(fmt.Sprintf("# missing schema for provider %q\n\n", provider))
continue

instances = append(instances,
obj{fmt.Sprintf("# %s:%s\n", addr.Absolute(m.Addr).Instance(k), taintStr), v.Current})

for dk, v := range v.Deposed {
instances = append(instances,
obj{fmt.Sprintf("# %s: (deposed object %s)\n", addr.Absolute(m.Addr).Instance(k), dk), v})
}

switch addr.Mode {
case addrs.ManagedResourceMode:
schema, _ = schemas.ResourceTypeConfig(
provider,
addr.Mode,
addr.Type,
)
if schema == nil {
p.buf.WriteString(fmt.Sprintf(
"# missing schema for provider %q resource type %s\n\n", provider, addr.Type))
// Sort the instances for consistent output.
// Starting the sort from the second index, so the current instance
// is always first.
sort.Slice(instances[1:], func(i, j int) bool {
pselle marked this conversation as resolved.
Show resolved Hide resolved
return instances[i+1].header < instances[j+1].header
})

for _, obj := range instances {
header := obj.header
instance := obj.instance
p.buf.WriteString(header)
if instance == nil {
pselle marked this conversation as resolved.
Show resolved Hide resolved
// this shouldn't happen, but there's nothing to do here so
// don't panic below.
continue
}

p.buf.WriteString(fmt.Sprintf(
"resource %q %q {",
addr.Type,
addr.Name,
))
case addrs.DataResourceMode:
schema, _ = schemas.ResourceTypeConfig(
provider,
addr.Mode,
addr.Type,
)
if schema == nil {
p.buf.WriteString(fmt.Sprintf(
"# missing schema for provider %q data source %s\n\n", provider, addr.Type))
var schema *configschema.Block
provider := m.Resources[key].ProviderConfig.ProviderConfig.StringCompact()
if _, exists := schemas.Providers[provider]; !exists {
// This should never happen in normal use because we should've
// loaded all of the schemas and checked things prior to this
// point. We can't return errors here, but since this is UI code
// we will try to do _something_ reasonable.
p.buf.WriteString(fmt.Sprintf("# missing schema for provider %q\n\n", provider))
continue
}

p.buf.WriteString(fmt.Sprintf(
"data %q %q {",
addr.Type,
addr.Name,
))
default:
// should never happen, since the above is exhaustive
p.buf.WriteString(addr.String())
}
switch addr.Mode {
case addrs.ManagedResourceMode:
schema, _ = schemas.ResourceTypeConfig(
provider,
addr.Mode,
addr.Type,
)
if schema == nil {
p.buf.WriteString(fmt.Sprintf(
"# missing schema for provider %q resource type %s\n\n", provider, addr.Type))
continue
}

val, err := v.Current.Decode(schema.ImpliedType())
if err != nil {
fmt.Println(err.Error())
break
}
p.buf.WriteString(fmt.Sprintf(
"resource %q %q {",
addr.Type,
addr.Name,
))
case addrs.DataResourceMode:
schema, _ = schemas.ResourceTypeConfig(
provider,
addr.Mode,
addr.Type,
)
if schema == nil {
p.buf.WriteString(fmt.Sprintf(
"# missing schema for provider %q data source %s\n\n", provider, addr.Type))
continue
}

path := make(cty.Path, 0, 3)
bodyWritten := p.writeBlockBodyDiff(schema, val.Value, val.Value, 2, path)
if bodyWritten {
p.buf.WriteString("\n")
}
p.buf.WriteString(fmt.Sprintf(
"data %q %q {",
addr.Type,
addr.Name,
))
default:
// should never happen, since the above is exhaustive
p.buf.WriteString(addr.String())
}

val, err := instance.Decode(schema.ImpliedType())
if err != nil {
fmt.Println(err.Error())
break
}

path := make(cty.Path, 0, 3)
bodyWritten := p.writeBlockBodyDiff(schema, val.Value, val.Value, 2, path)
if bodyWritten {
p.buf.WriteString("\n")
}

p.buf.WriteString("}\n\n")
p.buf.WriteString("}\n\n")
}
}
}
p.buf.WriteString("\n")
Expand Down
119 changes: 119 additions & 0 deletions command/format/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ func TestState(t *testing.T) {
},
nestedStateOutput,
},
{
&StateOpts{
State: deposedState(t),
Color: disabledColorize,
Schemas: testSchemas(),
},
deposedNestedStateOutput,
},
{
&StateOpts{
State: onlyDeposedState(t),
Color: disabledColorize,
Schemas: testSchemas(),
},
onlyDeposedOutput,
},
{
&StateOpts{
State: stateWithMoreOutputs(t),
Expand Down Expand Up @@ -152,6 +168,43 @@ resource "test_resource" "baz" {
}
}`

const deposedNestedStateOutput = `# test_resource.baz[0]:
resource "test_resource" "baz" {
woozles = "confuzles"

nested {
value = "42"
}
}

# test_resource.baz[0]: (deposed object 1234)
resource "test_resource" "baz" {
woozles = "confuzles"

nested {
value = "42"
}
}`

const onlyDeposedOutput = `# test_resource.baz[0]:
# test_resource.baz[0]: (deposed object 1234)
resource "test_resource" "baz" {
woozles = "confuzles"

nested {
value = "42"
}
}

# test_resource.baz[0]: (deposed object 5678)
resource "test_resource" "baz" {
woozles = "confuzles"

nested {
value = "42"
}
}`

const stateWithMoreOutputsOutput = `# test_resource.baz[0]:
resource "test_resource" "baz" {
woozles = "confuzles"
Expand Down Expand Up @@ -272,3 +325,69 @@ func nestedState(t *testing.T) *states.State {
)
return state
}

func deposedState(t *testing.T) *states.State {
state := nestedState(t)
rootModule := state.RootModule()
rootModule.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "baz",
}.Instance(addrs.IntKey(0)),
states.DeposedKey("1234"),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
SchemaVersion: 1,
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
},
addrs.ProviderConfig{
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
return state
}

// replicate a corrupt resource where only a deposed exists
func onlyDeposedState(t *testing.T) *states.State {
state := states.NewState()

rootModule := state.RootModule()
if rootModule == nil {
t.Errorf("root module is nil; want valid object")
}

rootModule.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "baz",
}.Instance(addrs.IntKey(0)),
states.DeposedKey("1234"),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
SchemaVersion: 1,
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
},
addrs.ProviderConfig{
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
rootModule.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "baz",
}.Instance(addrs.IntKey(0)),
states.DeposedKey("5678"),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
SchemaVersion: 1,
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
},
addrs.ProviderConfig{
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
return state
}