update to warn if schemas aren't available

This commit is contained in:
Megan Bang 2022-08-26 14:17:37 -05:00
parent 4fab46749a
commit b8f2f81cd6
13 changed files with 91 additions and 48 deletions

4
go.mod
View File

@ -40,7 +40,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-plugin v1.4.3
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hashicorp/go-tfe v1.7.0
github.com/hashicorp/go-tfe v1.8.1-0.20220826155809-b28335218b42
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
@ -144,7 +144,7 @@ require (
github.com/hashicorp/go-msgpack v0.5.4 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-slug v0.9.1 // indirect
github.com/hashicorp/go-slug v0.10.0 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect
github.com/hashicorp/serf v0.9.5 // indirect

8
go.sum
View File

@ -370,13 +370,13 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-slug v0.9.1 h1:gYNVJ3t0jAWx8AT2eYZci3Xd7NBHyjayW9AR1DU4ki0=
github.com/hashicorp/go-slug v0.9.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-slug v0.10.0 h1:mh4DDkBJTh9BuEjY/cv8PTo7k9OjT4PcW8PgZnJ4jTY=
github.com/hashicorp/go-slug v0.10.0/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-tfe v1.7.0 h1:GELRhS5dizF6giwjZBqUC/xPaSuNYB+hWRtUnf6i8K8=
github.com/hashicorp/go-tfe v1.7.0/go.mod h1:E8a90lC4kjU5Lc2c0D+SnWhUuyuoCIVm4Ewzv3jCD3A=
github.com/hashicorp/go-tfe v1.8.1-0.20220826155809-b28335218b42 h1:3Ejb02U7WAl9NBRYArj8Hyw0dvHEB5NO1AsX06wbDq4=
github.com/hashicorp/go-tfe v1.8.1-0.20220826155809-b28335218b42/go.mod h1:uSWi2sPw7tLrqNIiASid9j3SprbbkPSJ/2s3X0mMemg=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=

View File

@ -137,6 +137,9 @@ func metaOverridesForProvider(p providers.Interface) *testingOverrides {
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(p),
addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp2", "test"): providers.FactoryFixed(p),
addrs.NewLegacyProvider("null"): providers.FactoryFixed(p),
addrs.NewLegacyProvider("azurerm"): providers.FactoryFixed(p),
addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acmecorp", "aws"): providers.FactoryFixed(p),
},
}
}

View File

@ -7,6 +7,16 @@ import (
"github.com/hashicorp/terraform/internal/tfdiags"
)
const failedToLoadSchemasMessage = `
Terraform failed to load schemas, which will in turn affect its ability to generate the
external JSON state file. This will not have any adverse effects on Terraforms ability
to maintain state information, but may have adverse effects on any external integrations
relying on this format. The file should be created on the next successful "terraform apply"
however, historic state information may be missing if the affected integration relies on that
%s
`
func getSchemas(c *Meta, state *states.State, config *configs.Config) (*terraform.Schemas, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics

View File

@ -251,10 +251,7 @@ func (c *ImportCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
schemas, diags := getSchemas(&c.Meta, newState, config)
if diags.HasErrors() {
// MBANG TODO - add warning that the schema could not be initialized
// and therefore the JSON state can not be created and may affect
// external applications relying on that data format
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
// Persist the final state

View File

@ -388,20 +388,17 @@ func (c *StateMvCommand) Run(args []string) int {
path, err := os.Getwd()
if err != nil {
// MBANG TODO - add warning here too?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, stateTo, config)
if diags.HasErrors() {
// MBANG TODO - is this the warning?
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
return 1
}

View File

@ -130,17 +130,17 @@ func (c *StatePushCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
path, err := os.Getwd()
if err != nil {
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
// MBANG TODO - add warnings here?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, srcStateFile.State, config)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load schemas: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
if err := stateMgr.WriteState(srcStateFile.State); err != nil {

View File

@ -164,19 +164,17 @@ func (c *StateReplaceProviderCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
path, err := os.Getwd()
if err != nil {
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
// MBANG TODO - add warnings here?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, state, config)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load schemas: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
// Write the updated state

View File

@ -2,7 +2,9 @@ package command
import (
"bytes"
"fmt"
"path/filepath"
"regexp"
"strings"
"testing"
@ -61,6 +63,46 @@ func TestStateReplaceProvider(t *testing.T) {
)
})
t.Run("Schemas not initialized and JSON output not generated", func(t *testing.T) {
statePath := testStateFile(t, state)
ui := new(cli.MockUi)
view, _ := testView(t)
c := &StateReplaceProviderCommand{
StateMeta{
Meta: Meta{
Ui: ui,
View: view,
},
},
}
inputBuf := &bytes.Buffer{}
ui.InputReader = inputBuf
inputBuf.WriteString("yes\n")
args := []string{
"-state", statePath,
"hashicorp/aws",
"acmecorp/aws",
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
// Check for the warning
actual := strings.TrimSpace(ui.ErrorWriter.String())
expected := strings.TrimSpace(fmt.Sprintf(failedToLoadSchemasMessage, ""))
re, err := regexp.Compile(expected)
if err != nil {
t.Fatalf("Error compiling regexp: %s", err)
}
if !re.MatchString(actual) {
t.Fatalf("wrong output\n expected: %s \n actual: %s", expected, actual)
}
})
t.Run("happy path", func(t *testing.T) {
statePath := testStateFile(t, state)

View File

@ -114,20 +114,17 @@ func (c *StateRmCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
path, err := os.Getwd()
if err != nil {
// MBANG TODO - add warnings here?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, state, config)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
if err := stateMgr.WriteState(state); err != nil {

View File

@ -129,20 +129,17 @@ func (c *TaintCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
path, err := os.Getwd()
if err != nil {
// MBANG TODO - add warnings here?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, state, config)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
ss := state.SyncWrapper()

View File

@ -2,10 +2,10 @@ package command
import (
"os"
"regexp"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/mitchellh/cli"
"github.com/hashicorp/terraform/internal/addrs"
@ -381,8 +381,13 @@ Resource instance test_instance.bar was not found, but this is not an error
because -allow-missing was set.
`)
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("wrong output\n%s", diff)
re, err := regexp.Compile(expected)
if err != nil {
t.Fatalf("Error compiling regexp: %s", err)
}
if !re.MatchString(actual) {
t.Fatalf("wrong output\n expected: %s \n actual: %s", expected, actual)
}
}

View File

@ -168,20 +168,17 @@ func (c *UntaintCommand) Run(args []string) int {
// Get schemas, if possible, before writing state
path, err := os.Getwd()
if err != nil {
// MBANG TODO - add warnings here?
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
config, diags := c.loadConfig(path)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
schemas, diags := getSchemas(&c.Meta, state, config)
if diags.HasErrors() {
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
return 1
c.Ui.Warn(fmt.Sprintf(failedToLoadSchemasMessage, err))
}
obj.Status = states.ObjectReady
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)