diff --git a/backend/backend.go b/backend/backend.go index da2e6daf1..527c29385 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -27,13 +27,22 @@ type Backend interface { // to load the state. If the state.State is a state.Locker, it's up to the // caller to call Lock and Unlock as needed. State() (state.State, error) +} +// MultiState is an interface that a backend can implement to allow changing +// between named states depending on the configured environment. +type MultiState interface { // States returns a list of configured named states and the current state. States() ([]string, string, error) - // ChangeState changes to the named state. If this doesn't exist it'll be - // created. + // ChangeState changes to the named state. If the named state doesn't exist + // it will be created. ChangeState(name string) error + + // DeleteState removes the named state if it exists. If the current state is + // deleted, the backend should change to the default state. It is an error + // to delete the default state. + DeleteState(name string) error } // Enhanced implements additional behavior on top of a normal backend. diff --git a/backend/local/backend.go b/backend/local/backend.go index 541596983..966f5e82d 100644 --- a/backend/local/backend.go +++ b/backend/local/backend.go @@ -27,6 +27,8 @@ const ( DefaultBackupExtension = ".backup" ) +var ErrEnvNotSupported = errors.New("environments not supported") + // Local is an implementation of EnhancedBackend that performs all operations // locally. This is the "default" backend and implements normal Terraform // behavior as it is well known. @@ -117,6 +119,15 @@ func (b *Local) Configure(c *terraform.ResourceConfig) error { } func (b *Local) States() ([]string, string, error) { + // If we have a backend handling state, defer to that. + if b.Backend != nil { + if b, ok := b.Backend.(backend.MultiState); ok { + return b.States() + } else { + return nil, "", ErrEnvNotSupported + } + } + // the listing always start with "default" envs := []string{backend.DefaultStateName} @@ -154,6 +165,15 @@ func (b *Local) States() ([]string, string, error) { // DeleteState removes a named state. // The "default" state cannot be removed. func (b *Local) DeleteState(name string) error { + // If we have a backend handling state, defer to that. + if b.Backend != nil { + if b, ok := b.Backend.(backend.MultiState); ok { + return b.DeleteState(name) + } else { + return ErrEnvNotSupported + } + } + if name == "" { return errors.New("empty state name") } @@ -174,6 +194,15 @@ func (b *Local) DeleteState(name string) error { // Change to the named state, creating it if it doesn't exist. func (b *Local) ChangeState(name string) error { + // If we have a backend handling state, defer to that. + if b.Backend != nil { + if b, ok := b.Backend.(backend.MultiState); ok { + return b.ChangeState(name) + } else { + return ErrEnvNotSupported + } + } + name = strings.TrimSpace(name) if name == "" { return errors.New("state name cannot be empty")