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