github.com/pdecat/terraform@v0.11.9-beta1/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 "os" 7 "sync" 8 9 "github.com/hashicorp/terraform/backend" 10 "github.com/hashicorp/terraform/svchost/disco" 11 "github.com/hashicorp/terraform/terraform" 12 13 backendAtlas "github.com/hashicorp/terraform/backend/atlas" 14 backendLegacy "github.com/hashicorp/terraform/backend/legacy" 15 backendLocal "github.com/hashicorp/terraform/backend/local" 16 backendRemote "github.com/hashicorp/terraform/backend/remote" 17 backendAzure "github.com/hashicorp/terraform/backend/remote-state/azure" 18 backendConsul "github.com/hashicorp/terraform/backend/remote-state/consul" 19 backendEtcdv3 "github.com/hashicorp/terraform/backend/remote-state/etcdv3" 20 backendGCS "github.com/hashicorp/terraform/backend/remote-state/gcs" 21 backendInmem "github.com/hashicorp/terraform/backend/remote-state/inmem" 22 backendManta "github.com/hashicorp/terraform/backend/remote-state/manta" 23 backendS3 "github.com/hashicorp/terraform/backend/remote-state/s3" 24 backendSwift "github.com/hashicorp/terraform/backend/remote-state/swift" 25 ) 26 27 // backends is the list of available backends. This is a global variable 28 // because backends are currently hardcoded into Terraform and can't be 29 // modified without recompilation. 30 // 31 // To read an available backend, use the Backend function. This ensures 32 // safe concurrent read access to the list of built-in backends. 33 // 34 // Backends are hardcoded into Terraform because the API for backends uses 35 // complex structures and supporting that over the plugin system is currently 36 // prohibitively difficult. For those wanting to implement a custom backend, 37 // they can do so with recompilation. 38 var backends map[string]backend.InitFn 39 var backendsLock sync.Mutex 40 41 // Init initializes the backends map with all our hardcoded backends. 42 func Init(services *disco.Disco) { 43 backendsLock.Lock() 44 defer backendsLock.Unlock() 45 46 backends = map[string]backend.InitFn{ 47 // Enhanced backends. 48 "local": func() backend.Backend { return backendLocal.New() }, 49 "remote": func() backend.Backend { 50 b := backendRemote.New(services) 51 if os.Getenv("TF_FORCE_LOCAL_BACKEND") != "" { 52 return backendLocal.NewWithBackend(b) 53 } 54 return b 55 }, 56 57 // Remote State backends. 58 "atlas": func() backend.Backend { return backendAtlas.New() }, 59 "azurerm": func() backend.Backend { return backendAzure.New() }, 60 "consul": func() backend.Backend { return backendConsul.New() }, 61 "etcdv3": func() backend.Backend { return backendEtcdv3.New() }, 62 "gcs": func() backend.Backend { return backendGCS.New() }, 63 "inmem": func() backend.Backend { return backendInmem.New() }, 64 "manta": func() backend.Backend { return backendManta.New() }, 65 "s3": func() backend.Backend { return backendS3.New() }, 66 "swift": func() backend.Backend { return backendSwift.New() }, 67 68 // Deprecated backends. 69 "azure": deprecateBackend(backendAzure.New(), 70 `Warning: "azure" name is deprecated, please use "azurerm"`), 71 } 72 73 // Add the legacy remote backends that haven't yet been converted to 74 // the new backend API. 75 backendLegacy.Init(backends) 76 } 77 78 // Backend returns the initialization factory for the given backend, or 79 // nil if none exists. 80 func Backend(name string) backend.InitFn { 81 backendsLock.Lock() 82 defer backendsLock.Unlock() 83 return backends[name] 84 } 85 86 // Set sets a new backend in the list of backends. If f is nil then the 87 // backend will be removed from the map. If this backend already exists 88 // then it will be overwritten. 89 // 90 // This method sets this backend globally and care should be taken to do 91 // this only before Terraform is executing to prevent odd behavior of backends 92 // changing mid-execution. 93 func Set(name string, f backend.InitFn) { 94 backendsLock.Lock() 95 defer backendsLock.Unlock() 96 97 if f == nil { 98 delete(backends, name) 99 return 100 } 101 102 backends[name] = f 103 } 104 105 // deprecatedBackendShim is used to wrap a backend and inject a deprecation 106 // warning into the Validate method. 107 type deprecatedBackendShim struct { 108 backend.Backend 109 Message string 110 } 111 112 // Validate the Backend then add the deprecation warning. 113 func (b deprecatedBackendShim) Validate(c *terraform.ResourceConfig) ([]string, []error) { 114 warns, errs := b.Backend.Validate(c) 115 warns = append(warns, b.Message) 116 return warns, errs 117 } 118 119 // DeprecateBackend can be used to wrap a backend to retrun a deprecation 120 // warning during validation. 121 func deprecateBackend(b backend.Backend, message string) backend.InitFn { 122 // Since a Backend wrapped by deprecatedBackendShim can no longer be 123 // asserted as an Enhanced or Local backend, disallow those types here 124 // entirely. If something other than a basic backend.Backend needs to be 125 // deprecated, we can add that functionality to schema.Backend or the 126 // backend itself. 127 if _, ok := b.(backend.Enhanced); ok { 128 panic("cannot use DeprecateBackend on an Enhanced Backend") 129 } 130 131 if _, ok := b.(backend.Local); ok { 132 panic("cannot use DeprecateBackend on a Local Backend") 133 } 134 135 return func() backend.Backend { 136 return deprecatedBackendShim{ 137 Backend: b, 138 Message: message, 139 } 140 } 141 }