github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/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-svchost/disco" 9 "github.com/eliastor/durgaform/internal/backend" 10 "github.com/eliastor/durgaform/internal/tfdiags" 11 "github.com/zclconf/go-cty/cty" 12 13 backendLocal "github.com/eliastor/durgaform/internal/backend/local" 14 backendRemote "github.com/eliastor/durgaform/internal/backend/remote" 15 backendArtifactory "github.com/eliastor/durgaform/internal/backend/remote-state/artifactory" 16 backendAzure "github.com/eliastor/durgaform/internal/backend/remote-state/azure" 17 backendConsul "github.com/eliastor/durgaform/internal/backend/remote-state/consul" 18 backendCos "github.com/eliastor/durgaform/internal/backend/remote-state/cos" 19 backendGCS "github.com/eliastor/durgaform/internal/backend/remote-state/gcs" 20 backendHTTP "github.com/eliastor/durgaform/internal/backend/remote-state/http" 21 backendInmem "github.com/eliastor/durgaform/internal/backend/remote-state/inmem" 22 backendKubernetes "github.com/eliastor/durgaform/internal/backend/remote-state/kubernetes" 23 backendManta "github.com/eliastor/durgaform/internal/backend/remote-state/manta" 24 backendOSS "github.com/eliastor/durgaform/internal/backend/remote-state/oss" 25 backendPg "github.com/eliastor/durgaform/internal/backend/remote-state/pg" 26 backendS3 "github.com/eliastor/durgaform/internal/backend/remote-state/s3" 27 backendSwift "github.com/eliastor/durgaform/internal/backend/remote-state/swift" 28 backendCloud "github.com/eliastor/durgaform/internal/cloud" 29 ) 30 31 // backends is the list of available backends. This is a global variable 32 // because backends are currently hardcoded into Durgaform and can't be 33 // modified without recompilation. 34 // 35 // To read an available backend, use the Backend function. This ensures 36 // safe concurrent read access to the list of built-in backends. 37 // 38 // Backends are hardcoded into Durgaform because the API for backends uses 39 // complex structures and supporting that over the plugin system is currently 40 // prohibitively difficult. For those wanting to implement a custom backend, 41 // they can do so with recompilation. 42 var backends map[string]backend.InitFn 43 var backendsLock sync.Mutex 44 45 // RemovedBackends is a record of previously supported backends which have 46 // since been deprecated and removed. 47 var RemovedBackends map[string]string 48 49 // Init initializes the backends map with all our hardcoded backends. 50 func Init(services *disco.Disco) { 51 backendsLock.Lock() 52 defer backendsLock.Unlock() 53 54 backends = map[string]backend.InitFn{ 55 "local": func() backend.Backend { return backendLocal.New() }, 56 "remote": func() backend.Backend { return backendRemote.New(services) }, 57 58 // Remote State backends. 59 "azurerm": func() backend.Backend { return backendAzure.New() }, 60 "consul": func() backend.Backend { return backendConsul.New() }, 61 "cos": func() backend.Backend { return backendCos.New() }, 62 "gcs": func() backend.Backend { return backendGCS.New() }, 63 "http": func() backend.Backend { return backendHTTP.New() }, 64 "inmem": func() backend.Backend { return backendInmem.New() }, 65 "kubernetes": func() backend.Backend { return backendKubernetes.New() }, 66 "oss": func() backend.Backend { return backendOSS.New() }, 67 "pg": func() backend.Backend { return backendPg.New() }, 68 "s3": func() backend.Backend { return backendS3.New() }, 69 70 // Durgaform Cloud 'backend' 71 // This is an implementation detail only, used for the cloud package 72 "cloud": func() backend.Backend { return backendCloud.New(services) }, 73 74 // FIXME: remove deprecated backends for v1.3 75 // Deprecated backends. 76 "azure": func() backend.Backend { 77 return deprecateBackend( 78 backendAzure.New(), 79 `Warning: "azure" name is deprecated, please use "azurerm"`, 80 ) 81 }, 82 "artifactory": func() backend.Backend { 83 return deprecateBackend( 84 backendArtifactory.New(), 85 `Warning: "artifactory" backend is deprecated, and will be removed in a future release."`, 86 ) 87 }, 88 "manta": func() backend.Backend { 89 return deprecateBackend( 90 backendManta.New(), 91 `Warning: "manta" backend is deprecated, and will be removed in a future release."`, 92 ) 93 }, 94 "swift": func() backend.Backend { 95 return deprecateBackend( 96 backendSwift.New(), 97 `Warning: "swift" backend is deprecated, and will be removed in a future release."`, 98 ) 99 }, 100 } 101 102 RemovedBackends = map[string]string{ 103 "etcd": `The "etcd" backend is not supported in Durgaform v1.3 or later.`, 104 "etcdv3": `The "etcdv3" backend is not supported in Durgaform v1.3 or later.`, 105 } 106 } 107 108 // Backend returns the initialization factory for the given backend, or 109 // nil if none exists. 110 func Backend(name string) backend.InitFn { 111 backendsLock.Lock() 112 defer backendsLock.Unlock() 113 return backends[name] 114 } 115 116 // Set sets a new backend in the list of backends. If f is nil then the 117 // backend will be removed from the map. If this backend already exists 118 // then it will be overwritten. 119 // 120 // This method sets this backend globally and care should be taken to do 121 // this only before Durgaform is executing to prevent odd behavior of backends 122 // changing mid-execution. 123 func Set(name string, f backend.InitFn) { 124 backendsLock.Lock() 125 defer backendsLock.Unlock() 126 127 if f == nil { 128 delete(backends, name) 129 return 130 } 131 132 backends[name] = f 133 } 134 135 // deprecatedBackendShim is used to wrap a backend and inject a deprecation 136 // warning into the Validate method. 137 type deprecatedBackendShim struct { 138 backend.Backend 139 Message string 140 } 141 142 // PrepareConfig delegates to the wrapped backend to validate its config 143 // and then appends shim's deprecation warning. 144 func (b deprecatedBackendShim) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) { 145 newObj, diags := b.Backend.PrepareConfig(obj) 146 return newObj, diags.Append(tfdiags.SimpleWarning(b.Message)) 147 } 148 149 // DeprecateBackend can be used to wrap a backend to retrun a deprecation 150 // warning during validation. 151 func deprecateBackend(b backend.Backend, message string) backend.Backend { 152 // Since a Backend wrapped by deprecatedBackendShim can no longer be 153 // asserted as an Enhanced or Local backend, disallow those types here 154 // entirely. If something other than a basic backend.Backend needs to be 155 // deprecated, we can add that functionality to schema.Backend or the 156 // backend itself. 157 if _, ok := b.(backend.Enhanced); ok { 158 panic("cannot use DeprecateBackend on an Enhanced Backend") 159 } 160 161 if _, ok := b.(backend.Local); ok { 162 panic("cannot use DeprecateBackend on a Local Backend") 163 } 164 165 return deprecatedBackendShim{ 166 Backend: b, 167 Message: message, 168 } 169 }