github.com/jzbruno/terraform@v0.10.3-0.20180104230435-18975d727047/backend/init/init.go (about)

     1  // Package init contains the list of backends that can be initialized and
     2  // basic helper functions for initializing those backends.
     3  package init
     4  
     5  import (
     6  	"sync"
     7  
     8  	"github.com/hashicorp/terraform/backend"
     9  	"github.com/hashicorp/terraform/terraform"
    10  
    11  	backendatlas "github.com/hashicorp/terraform/backend/atlas"
    12  	backendlegacy "github.com/hashicorp/terraform/backend/legacy"
    13  	backendlocal "github.com/hashicorp/terraform/backend/local"
    14  	backendAzure "github.com/hashicorp/terraform/backend/remote-state/azure"
    15  	backendconsul "github.com/hashicorp/terraform/backend/remote-state/consul"
    16  	backendetcdv3 "github.com/hashicorp/terraform/backend/remote-state/etcdv3"
    17  	backendGCS "github.com/hashicorp/terraform/backend/remote-state/gcs"
    18  	backendinmem "github.com/hashicorp/terraform/backend/remote-state/inmem"
    19  	backendManta "github.com/hashicorp/terraform/backend/remote-state/manta"
    20  	backendS3 "github.com/hashicorp/terraform/backend/remote-state/s3"
    21  	backendSwift "github.com/hashicorp/terraform/backend/remote-state/swift"
    22  )
    23  
    24  // backends is the list of available backends. This is a global variable
    25  // because backends are currently hardcoded into Terraform and can't be
    26  // modified without recompilation.
    27  //
    28  // To read an available backend, use the Backend function. This ensures
    29  // safe concurrent read access to the list of built-in backends.
    30  //
    31  // Backends are hardcoded into Terraform because the API for backends uses
    32  // complex structures and supporting that over the plugin system is currently
    33  // prohibitively difficult. For those wanting to implement a custom backend,
    34  // they can do so with recompilation.
    35  var backends map[string]func() backend.Backend
    36  var backendsLock sync.Mutex
    37  
    38  func init() {
    39  	// Our hardcoded backends. We don't need to acquire a lock here
    40  	// since init() code is serial and can't spawn goroutines.
    41  	backends = map[string]func() backend.Backend{
    42  		"atlas":  func() backend.Backend { return &backendatlas.Backend{} },
    43  		"local":  func() backend.Backend { return &backendlocal.Local{} },
    44  		"consul": func() backend.Backend { return backendconsul.New() },
    45  		"inmem":  func() backend.Backend { return backendinmem.New() },
    46  		"swift":  func() backend.Backend { return backendSwift.New() },
    47  		"s3":     func() backend.Backend { return backendS3.New() },
    48  		"azure": deprecateBackend(backendAzure.New(),
    49  			`Warning: "azure" name is deprecated, please use "azurerm"`),
    50  		"azurerm": func() backend.Backend { return backendAzure.New() },
    51  		"etcdv3":  func() backend.Backend { return backendetcdv3.New() },
    52  		"gcs":     func() backend.Backend { return backendGCS.New() },
    53  		"manta":   func() backend.Backend { return backendManta.New() },
    54  	}
    55  
    56  	// Add the legacy remote backends that haven't yet been convertd to
    57  	// the new backend API.
    58  	backendlegacy.Init(backends)
    59  }
    60  
    61  // Backend returns the initialization factory for the given backend, or
    62  // nil if none exists.
    63  func Backend(name string) func() backend.Backend {
    64  	backendsLock.Lock()
    65  	defer backendsLock.Unlock()
    66  	return backends[name]
    67  }
    68  
    69  // Set sets a new backend in the list of backends. If f is nil then the
    70  // backend will be removed from the map. If this backend already exists
    71  // then it will be overwritten.
    72  //
    73  // This method sets this backend globally and care should be taken to do
    74  // this only before Terraform is executing to prevent odd behavior of backends
    75  // changing mid-execution.
    76  func Set(name string, f func() backend.Backend) {
    77  	backendsLock.Lock()
    78  	defer backendsLock.Unlock()
    79  
    80  	if f == nil {
    81  		delete(backends, name)
    82  		return
    83  	}
    84  
    85  	backends[name] = f
    86  }
    87  
    88  // deprecatedBackendShim is used to wrap a backend and inject a deprecation
    89  // warning into the Validate method.
    90  type deprecatedBackendShim struct {
    91  	backend.Backend
    92  	Message string
    93  }
    94  
    95  // Validate the Backend then add the deprecation warning.
    96  func (b deprecatedBackendShim) Validate(c *terraform.ResourceConfig) ([]string, []error) {
    97  	warns, errs := b.Backend.Validate(c)
    98  	warns = append(warns, b.Message)
    99  	return warns, errs
   100  }
   101  
   102  // DeprecateBackend can be used to wrap a backend to retrun a deprecation
   103  // warning during validation.
   104  func deprecateBackend(b backend.Backend, message string) func() backend.Backend {
   105  	// Since a Backend wrapped by deprecatedBackendShim can no longer be
   106  	// asserted as an Enhanced or Local backend, disallow those types here
   107  	// entirely.  If something other than a basic backend.Backend needs to be
   108  	// deprecated, we can add that functionality to schema.Backend or the
   109  	// backend itself.
   110  	if _, ok := b.(backend.Enhanced); ok {
   111  		panic("cannot use DeprecateBackend on an Enhanced Backend")
   112  	}
   113  
   114  	if _, ok := b.(backend.Local); ok {
   115  		panic("cannot use DeprecateBackend on a Local Backend")
   116  	}
   117  
   118  	return func() backend.Backend {
   119  		return deprecatedBackendShim{
   120  			Backend: b,
   121  			Message: message,
   122  		}
   123  	}
   124  }