Merge pull request #12352 from hashicorp/f-atlas-backend
backend/atlas: convert to new style
This commit is contained in:
commit
e7a88ce089
|
@ -0,0 +1,163 @@
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/backend"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/state"
|
||||||
|
"github.com/hashicorp/terraform/state/remote"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/mitchellh/colorstring"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Backend is an implementation of EnhancedBackend that performs all operations
|
||||||
|
// in Atlas. State must currently also be stored in Atlas, although it is worth
|
||||||
|
// investigating in the future if state storage can be external as well.
|
||||||
|
type Backend struct {
|
||||||
|
// CLI and Colorize control the CLI output. If CLI is nil then no CLI
|
||||||
|
// output will be done. If CLIColor is nil then no coloring will be done.
|
||||||
|
CLI cli.Ui
|
||||||
|
CLIColor *colorstring.Colorize
|
||||||
|
|
||||||
|
// ContextOpts are the base context options to set when initializing a
|
||||||
|
// Terraform context. Many of these will be overridden or merged by
|
||||||
|
// Operation. See Operation for more details.
|
||||||
|
ContextOpts *terraform.ContextOpts
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
// Internal fields, do not set
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
// stateClient is the legacy state client, setup in Configure
|
||||||
|
stateClient *stateClient
|
||||||
|
|
||||||
|
// schema is the schema for configuration, set by init
|
||||||
|
schema *schema.Backend
|
||||||
|
once sync.Once
|
||||||
|
|
||||||
|
// opLock locks operations
|
||||||
|
opLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) Input(
|
||||||
|
ui terraform.UIInput, c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
|
||||||
|
b.once.Do(b.init)
|
||||||
|
return b.schema.Input(ui, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
||||||
|
b.once.Do(b.init)
|
||||||
|
return b.schema.Validate(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) Configure(c *terraform.ResourceConfig) error {
|
||||||
|
b.once.Do(b.init)
|
||||||
|
return b.schema.Configure(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) States() ([]string, error) {
|
||||||
|
return nil, backend.ErrNamedStatesNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) DeleteState(name string) error {
|
||||||
|
return backend.ErrNamedStatesNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) State(name string) (state.State, error) {
|
||||||
|
if name != backend.DefaultStateName {
|
||||||
|
return nil, backend.ErrNamedStatesNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
return &remote.State{Client: b.stateClient}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colorize returns the Colorize structure that can be used for colorizing
|
||||||
|
// output. This is gauranteed to always return a non-nil value and so is useful
|
||||||
|
// as a helper to wrap any potentially colored strings.
|
||||||
|
func (b *Backend) Colorize() *colorstring.Colorize {
|
||||||
|
if b.CLIColor != nil {
|
||||||
|
return b.CLIColor
|
||||||
|
}
|
||||||
|
|
||||||
|
return &colorstring.Colorize{
|
||||||
|
Colors: colorstring.DefaultColors,
|
||||||
|
Disable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) init() {
|
||||||
|
b.schema = &schema.Backend{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: schemaDescriptions["name"],
|
||||||
|
},
|
||||||
|
|
||||||
|
"access_token": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: schemaDescriptions["access_token"],
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("ATLAS_TOKEN", nil),
|
||||||
|
},
|
||||||
|
|
||||||
|
"address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: defaultAtlasServer,
|
||||||
|
Description: schemaDescriptions["address"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigureFunc: b.schemaConfigure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) schemaConfigure(ctx context.Context) error {
|
||||||
|
d := schema.FromContextBackendConfig(ctx)
|
||||||
|
|
||||||
|
// Parse the address
|
||||||
|
addr := d.Get("address").(string)
|
||||||
|
addrUrl, err := url.Parse(addr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error parsing 'address': %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the org/env
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
parts := strings.Split(name, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("malformed name '%s', expected format '<org>/<name>'", name)
|
||||||
|
}
|
||||||
|
org := parts[0]
|
||||||
|
env := parts[1]
|
||||||
|
|
||||||
|
// Setup the client
|
||||||
|
b.stateClient = &stateClient{
|
||||||
|
Server: addr,
|
||||||
|
ServerURL: addrUrl,
|
||||||
|
AccessToken: d.Get("access_token").(string),
|
||||||
|
User: org,
|
||||||
|
Name: env,
|
||||||
|
|
||||||
|
// This is optionally set during Atlas Terraform runs.
|
||||||
|
RunId: os.Getenv("ATLAS_RUN_ID"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var schemaDescriptions = map[string]string{
|
||||||
|
"name": "Full name of the environment in Atlas, such as 'hashicorp/myenv'",
|
||||||
|
"access_token": "Access token to use to access Atlas. If ATLAS_TOKEN is set then\n" +
|
||||||
|
"this will override any saved value for this.",
|
||||||
|
"address": "Address to your Atlas installation. This defaults to the publicly\n" +
|
||||||
|
"hosted version at 'https://atlas.hashicorp.com/'. This address\n" +
|
||||||
|
"should contain the full HTTP scheme to use.",
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImpl(t *testing.T) {
|
||||||
|
var _ backend.Backend = new(Backend)
|
||||||
|
var _ backend.CLI = new(Backend)
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
// backend.CLI impl.
|
||||||
|
func (b *Backend) CLIInit(opts *backend.CLIOpts) error {
|
||||||
|
b.CLI = opts.CLI
|
||||||
|
b.CLIColor = opts.CLIColor
|
||||||
|
b.ContextOpts = opts.ContextOpts
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package remote
|
package atlas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -13,11 +13,11 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-cleanhttp"
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
"github.com/hashicorp/go-retryablehttp"
|
"github.com/hashicorp/go-retryablehttp"
|
||||||
"github.com/hashicorp/go-rootcerts"
|
"github.com/hashicorp/go-rootcerts"
|
||||||
|
"github.com/hashicorp/terraform/state/remote"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,55 +27,8 @@ const (
|
||||||
atlasTokenHeader = "X-Atlas-Token"
|
atlasTokenHeader = "X-Atlas-Token"
|
||||||
)
|
)
|
||||||
|
|
||||||
func atlasFactory(conf map[string]string) (Client, error) {
|
|
||||||
var client AtlasClient
|
|
||||||
|
|
||||||
server, ok := conf["address"]
|
|
||||||
if !ok || server == "" {
|
|
||||||
server = defaultAtlasServer
|
|
||||||
}
|
|
||||||
|
|
||||||
url, err := url.Parse(server)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
token, ok := conf["access_token"]
|
|
||||||
if token == "" {
|
|
||||||
token = os.Getenv("ATLAS_TOKEN")
|
|
||||||
ok = true
|
|
||||||
}
|
|
||||||
if !ok || token == "" {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"missing 'access_token' configuration or ATLAS_TOKEN environmental variable")
|
|
||||||
}
|
|
||||||
|
|
||||||
name, ok := conf["name"]
|
|
||||||
if !ok || name == "" {
|
|
||||||
return nil, fmt.Errorf("missing 'name' configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(name, "/")
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return nil, fmt.Errorf("malformed name '%s', expected format '<account>/<name>'", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it exists, add the `ATLAS_RUN_ID` environment
|
|
||||||
// variable as a param, which is injected during Atlas Terraform
|
|
||||||
// runs. This is completely optional.
|
|
||||||
client.RunId = os.Getenv("ATLAS_RUN_ID")
|
|
||||||
|
|
||||||
client.Server = server
|
|
||||||
client.ServerURL = url
|
|
||||||
client.AccessToken = token
|
|
||||||
client.User = parts[0]
|
|
||||||
client.Name = parts[1]
|
|
||||||
|
|
||||||
return &client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtlasClient implements the Client interface for an Atlas compatible server.
|
// AtlasClient implements the Client interface for an Atlas compatible server.
|
||||||
type AtlasClient struct {
|
type stateClient struct {
|
||||||
Server string
|
Server string
|
||||||
ServerURL *url.URL
|
ServerURL *url.URL
|
||||||
User string
|
User string
|
||||||
|
@ -87,7 +40,7 @@ type AtlasClient struct {
|
||||||
conflictHandlingAttempted bool
|
conflictHandlingAttempted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) Get() (*Payload, error) {
|
func (c *stateClient) Get() (*remote.Payload, error) {
|
||||||
// Make the HTTP request
|
// Make the HTTP request
|
||||||
req, err := retryablehttp.NewRequest("GET", c.url().String(), nil)
|
req, err := retryablehttp.NewRequest("GET", c.url().String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -134,7 +87,7 @@ func (c *AtlasClient) Get() (*Payload, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the payload
|
// Create the payload
|
||||||
payload := &Payload{
|
payload := &remote.Payload{
|
||||||
Data: buf.Bytes(),
|
Data: buf.Bytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +112,7 @@ func (c *AtlasClient) Get() (*Payload, error) {
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) Put(state []byte) error {
|
func (c *stateClient) Put(state []byte) error {
|
||||||
// Get the target URL
|
// Get the target URL
|
||||||
base := c.url()
|
base := c.url()
|
||||||
|
|
||||||
|
@ -203,7 +156,7 @@ func (c *AtlasClient) Put(state []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) Delete() error {
|
func (c *stateClient) Delete() error {
|
||||||
// Make the HTTP request
|
// Make the HTTP request
|
||||||
req, err := retryablehttp.NewRequest("DELETE", c.url().String(), nil)
|
req, err := retryablehttp.NewRequest("DELETE", c.url().String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -237,7 +190,7 @@ func (c *AtlasClient) Delete() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) readBody(b io.Reader) string {
|
func (c *stateClient) readBody(b io.Reader) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if _, err := io.Copy(&buf, b); err != nil {
|
if _, err := io.Copy(&buf, b); err != nil {
|
||||||
return fmt.Sprintf("Error reading body: %s", err)
|
return fmt.Sprintf("Error reading body: %s", err)
|
||||||
|
@ -251,7 +204,7 @@ func (c *AtlasClient) readBody(b io.Reader) string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) url() *url.URL {
|
func (c *stateClient) url() *url.URL {
|
||||||
values := url.Values{}
|
values := url.Values{}
|
||||||
|
|
||||||
values.Add("atlas_run_id", c.RunId)
|
values.Add("atlas_run_id", c.RunId)
|
||||||
|
@ -264,7 +217,7 @@ func (c *AtlasClient) url() *url.URL {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AtlasClient) http() (*retryablehttp.Client, error) {
|
func (c *stateClient) http() (*retryablehttp.Client, error) {
|
||||||
if c.HTTPClient != nil {
|
if c.HTTPClient != nil {
|
||||||
return c.HTTPClient, nil
|
return c.HTTPClient, nil
|
||||||
}
|
}
|
||||||
|
@ -314,7 +267,7 @@ func (c *AtlasClient) http() (*retryablehttp.Client, error) {
|
||||||
//
|
//
|
||||||
// In other words, in this situation Terraform can override Atlas's detected
|
// In other words, in this situation Terraform can override Atlas's detected
|
||||||
// conflict by asserting that the state it is pushing is indeed correct.
|
// conflict by asserting that the state it is pushing is indeed correct.
|
||||||
func (c *AtlasClient) handleConflict(msg string, state []byte) error {
|
func (c *stateClient) handleConflict(msg string, state []byte) error {
|
||||||
log.Printf("[DEBUG] Handling Atlas conflict response: %s", msg)
|
log.Printf("[DEBUG] Handling Atlas conflict response: %s", msg)
|
||||||
|
|
||||||
if c.conflictHandlingAttempted {
|
if c.conflictHandlingAttempted {
|
|
@ -1,4 +1,4 @@
|
||||||
package remote
|
package atlas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -13,15 +13,28 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/backend"
|
||||||
"github.com/hashicorp/terraform/helper/acctest"
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/state/remote"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAtlasClient_impl(t *testing.T) {
|
func testStateClient(t *testing.T, c map[string]interface{}) remote.Client {
|
||||||
var _ Client = new(AtlasClient)
|
b := backend.TestBackendConfig(t, &Backend{}, c)
|
||||||
|
raw, err := b.State(backend.DefaultStateName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := raw.(*remote.State)
|
||||||
|
return s.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient(t *testing.T) {
|
func TestStateClient_impl(t *testing.T) {
|
||||||
|
var _ remote.Client = new(stateClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateClient(t *testing.T) {
|
||||||
acctest.RemoteTestPrecheck(t)
|
acctest.RemoteTestPrecheck(t)
|
||||||
|
|
||||||
token := os.Getenv("ATLAS_TOKEN")
|
token := os.Getenv("ATLAS_TOKEN")
|
||||||
|
@ -29,30 +42,24 @@ func TestAtlasClient(t *testing.T) {
|
||||||
t.Skipf("skipping, ATLAS_TOKEN must be set")
|
t.Skipf("skipping, ATLAS_TOKEN must be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := atlasFactory(map[string]string{
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": token,
|
"access_token": token,
|
||||||
"name": "hashicorp/test-remote-state",
|
"name": "hashicorp/test-remote-state",
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testClient(t, client)
|
remote.TestClient(t, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient_noRetryOnBadCerts(t *testing.T) {
|
func TestStateClient_noRetryOnBadCerts(t *testing.T) {
|
||||||
acctest.RemoteTestPrecheck(t)
|
acctest.RemoteTestPrecheck(t)
|
||||||
|
|
||||||
client, err := atlasFactory(map[string]string{
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": "NOT_REQUIRED",
|
"access_token": "NOT_REQUIRED",
|
||||||
"name": "hashicorp/test-remote-state",
|
"name": "hashicorp/test-remote-state",
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ac := client.(*AtlasClient)
|
ac := client.(*stateClient)
|
||||||
// trigger the AtlasClient to build the http client and assign HTTPClient
|
// trigger the StateClient to build the http client and assign HTTPClient
|
||||||
httpClient, err := ac.http()
|
httpClient, err := ac.http()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -87,18 +94,16 @@ func TestAtlasClient_noRetryOnBadCerts(t *testing.T) {
|
||||||
t.Fatalf("expected x509.UnknownAuthorityError, got %v", err)
|
t.Fatalf("expected x509.UnknownAuthorityError, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient_ReportedConflictEqualStates(t *testing.T) {
|
func TestStateClient_ReportedConflictEqualStates(t *testing.T) {
|
||||||
fakeAtlas := newFakeAtlas(t, testStateModuleOrderChange)
|
fakeAtlas := newFakeAtlas(t, testStateModuleOrderChange)
|
||||||
srv := fakeAtlas.Server()
|
srv := fakeAtlas.Server()
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
client, err := atlasFactory(map[string]string{
|
|
||||||
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": "sometoken",
|
"access_token": "sometoken",
|
||||||
"name": "someuser/some-test-remote-state",
|
"name": "someuser/some-test-remote-state",
|
||||||
"address": srv.URL,
|
"address": srv.URL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, err := terraform.ReadState(bytes.NewReader(testStateModuleOrderChange))
|
state, err := terraform.ReadState(bytes.NewReader(testStateModuleOrderChange))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -114,18 +119,16 @@ func TestAtlasClient_ReportedConflictEqualStates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient_NoConflict(t *testing.T) {
|
func TestStateClient_NoConflict(t *testing.T) {
|
||||||
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
||||||
srv := fakeAtlas.Server()
|
srv := fakeAtlas.Server()
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
client, err := atlasFactory(map[string]string{
|
|
||||||
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": "sometoken",
|
"access_token": "sometoken",
|
||||||
"name": "someuser/some-test-remote-state",
|
"name": "someuser/some-test-remote-state",
|
||||||
"address": srv.URL,
|
"address": srv.URL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -144,18 +147,16 @@ func TestAtlasClient_NoConflict(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient_LegitimateConflict(t *testing.T) {
|
func TestStateClient_LegitimateConflict(t *testing.T) {
|
||||||
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
||||||
srv := fakeAtlas.Server()
|
srv := fakeAtlas.Server()
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
client, err := atlasFactory(map[string]string{
|
|
||||||
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": "sometoken",
|
"access_token": "sometoken",
|
||||||
"name": "someuser/some-test-remote-state",
|
"name": "someuser/some-test-remote-state",
|
||||||
"address": srv.URL,
|
"address": srv.URL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -181,7 +182,7 @@ func TestAtlasClient_LegitimateConflict(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlasClient_UnresolvableConflict(t *testing.T) {
|
func TestStateClient_UnresolvableConflict(t *testing.T) {
|
||||||
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
fakeAtlas := newFakeAtlas(t, testStateSimple)
|
||||||
|
|
||||||
// Something unexpected causes Atlas to conflict in a way that we can't fix.
|
// Something unexpected causes Atlas to conflict in a way that we can't fix.
|
||||||
|
@ -189,14 +190,12 @@ func TestAtlasClient_UnresolvableConflict(t *testing.T) {
|
||||||
|
|
||||||
srv := fakeAtlas.Server()
|
srv := fakeAtlas.Server()
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
client, err := atlasFactory(map[string]string{
|
|
||||||
|
client := testStateClient(t, map[string]interface{}{
|
||||||
"access_token": "sometoken",
|
"access_token": "sometoken",
|
||||||
"name": "someuser/some-test-remote-state",
|
"name": "someuser/some-test-remote-state",
|
||||||
"address": srv.URL,
|
"address": srv.URL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
state, err := terraform.ReadState(bytes.NewReader(testStateSimple))
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
|
|
||||||
|
backendatlas "github.com/hashicorp/terraform/backend/atlas"
|
||||||
backendlegacy "github.com/hashicorp/terraform/backend/legacy"
|
backendlegacy "github.com/hashicorp/terraform/backend/legacy"
|
||||||
backendlocal "github.com/hashicorp/terraform/backend/local"
|
backendlocal "github.com/hashicorp/terraform/backend/local"
|
||||||
backendconsul "github.com/hashicorp/terraform/backend/remote-state/consul"
|
backendconsul "github.com/hashicorp/terraform/backend/remote-state/consul"
|
||||||
|
@ -31,6 +32,7 @@ func init() {
|
||||||
// Our hardcoded backends. We don't need to acquire a lock here
|
// Our hardcoded backends. We don't need to acquire a lock here
|
||||||
// since init() code is serial and can't spawn goroutines.
|
// since init() code is serial and can't spawn goroutines.
|
||||||
backends = map[string]func() backend.Backend{
|
backends = map[string]func() backend.Backend{
|
||||||
|
"atlas": func() backend.Backend { return &backendatlas.Backend{} },
|
||||||
"local": func() backend.Backend { return &backendlocal.Local{} },
|
"local": func() backend.Backend { return &backendlocal.Local{} },
|
||||||
"consul": func() backend.Backend { return backendconsul.New() },
|
"consul": func() backend.Backend { return backendconsul.New() },
|
||||||
"inmem": func() backend.Backend { return backendinmem.New() },
|
"inmem": func() backend.Backend { return backendinmem.New() },
|
||||||
|
|
|
@ -46,7 +46,6 @@ func NewClient(t string, conf map[string]string) (Client, error) {
|
||||||
// NewClient.
|
// NewClient.
|
||||||
var BuiltinClients = map[string]Factory{
|
var BuiltinClients = map[string]Factory{
|
||||||
"artifactory": artifactoryFactory,
|
"artifactory": artifactoryFactory,
|
||||||
"atlas": atlasFactory,
|
|
||||||
"azure": azureFactory,
|
"azure": azureFactory,
|
||||||
"etcd": etcdFactory,
|
"etcd": etcdFactory,
|
||||||
"gcs": gcsFactory,
|
"gcs": gcsFactory,
|
||||||
|
|
Loading…
Reference in New Issue