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  }