feature: fall back to reading entire state when detailed-type is not available

This commit is contained in:
Brandon Croft 2022-07-25 17:17:24 -06:00
parent e1fa690879
commit 0139e75a1a
No known key found for this signature in database
GPG Key ID: B01E32423322EB9D

View File

@ -25,10 +25,13 @@ type State struct {
delegate remote.State delegate remote.State
} }
const ErrStateVersionOutputUpgrade = ` var ErrNotEnoughOutputsTypeInformation = errors.New("not enough type information to read outputs")
The remote state version was created by a version of terraform older than var ErrStateVersionOutputsUpgradeState = errors.New(strings.TrimSpace(`
1.3.0 and must be updated before outputs can be read by terraform. You are not authorized to read the full state version containing outputs.
` State versions created by terraform v1.3.0 and newer do not require this level
of authorization and therefore this error can be fixed by upgrading the remote
state version.
`))
// Proof that cloud State is a statemgr.Persistent interface // Proof that cloud State is a statemgr.Persistent interface
var _ statemgr.Persistent = (*State)(nil) var _ statemgr.Persistent = (*State)(nil)
@ -70,6 +73,22 @@ func (s *State) WriteState(state *states.State) error {
return s.delegate.WriteState(state) return s.delegate.WriteState(state)
} }
func (s *State) fallbackReadOutputsFromFullState() (map[string]*states.OutputValue, error) {
if err := s.RefreshState(); err != nil {
if strings.HasSuffix(err.Error(), "failed to retrieve state: forbidden") {
return nil, ErrStateVersionOutputsUpgradeState
}
return nil, fmt.Errorf("failed to load state: %w", err)
}
state := s.State()
if state == nil {
state = states.NewState()
}
return state.RootModule().OutputValues, nil
}
// GetRootOutputValues fetches output values from Terraform Cloud // GetRootOutputValues fetches output values from Terraform Cloud
func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) { func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
ctx := context.Background() ctx := context.Background()
@ -84,7 +103,11 @@ func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
for _, output := range so.Items { for _, output := range so.Items {
if output.DetailedType == nil { if output.DetailedType == nil {
return nil, errors.New(strings.TrimSpace(ErrStateVersionOutputUpgrade)) // If there is no detailed type information available, this state was probably created
// with a version of terraform < 1.3.0. In this case, we'll eject completely from this
// function and fall back to the old behavior of reading the entire state file, which
// requires a higher level of authorization.
return s.fallbackReadOutputsFromFullState()
} }
if output.Sensitive { if output.Sensitive {