github.com/ctrox/terraform@v0.11.12-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  }