Skip to content

Commit

Permalink
backend/remote: add the run ID to associate state
Browse files Browse the repository at this point in the history
If a run ID is available, we need to make sure we pass that when creating a new state version so the state will be properly associated with the run.
  • Loading branch information
Sander van Harmelen committed Sep 9, 2018
1 parent cd8fcf7 commit cd6d75b
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 1 deletion.
4 changes: 4 additions & 0 deletions backend/remote/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net/url"
"os"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -278,6 +279,9 @@ func (b *Remote) State(workspace string) (state.State, error) {
client: b.client,
organization: b.organization,
workspace: workspace,

// This is optionally set during Terraform Enterprise runs.
runID: os.Getenv("TFE_RUN_ID"),
}

return &remote.State{Client: client}, nil
Expand Down
5 changes: 5 additions & 0 deletions backend/remote/backend_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,13 @@ func (m *mockStateVersions) List(ctx context.Context, options tfe.StateVersionLi

func (m *mockStateVersions) Create(ctx context.Context, workspaceID string, options tfe.StateVersionCreateOptions) (*tfe.StateVersion, error) {
id := generateID("sv-")
runID := os.Getenv("TFE_RUN_ID")
url := fmt.Sprintf("https://app.terraform.io/_archivist/%s", id)

if runID != "" && (options.Run == nil || runID != options.Run.ID) {
return nil, fmt.Errorf("option.Run.ID does not contain the ID exported by TFE_RUN_ID")
}

sv := &tfe.StateVersion{
ID: id,
DownloadURL: url,
Expand Down
9 changes: 8 additions & 1 deletion backend/remote/backend_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
type remoteClient struct {
client *tfe.Client
organization string
runID string
workspace string
}

Expand Down Expand Up @@ -70,7 +71,7 @@ func (r *remoteClient) Put(state []byte) error {
return fmt.Errorf("Error retrieving workspace: %v", err)
}

// the state into a buffer.
// Read the raw state into a Terraform state.
tfState, err := terraform.ReadState(bytes.NewReader(state))
if err != nil {
return fmt.Errorf("Error reading state: %s", err)
Expand All @@ -83,6 +84,12 @@ func (r *remoteClient) Put(state []byte) error {
State: tfe.String(base64.StdEncoding.EncodeToString(state)),
}

// If we have a run ID, make sure to add it to the options
// so the state will be properly associated with the run.
if r.runID != "" {
options.Run = &tfe.Run{ID: r.runID}
}

// Create the new state.
_, err = r.client.StateVersions.Create(ctx, w.ID, options)
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions backend/remote/backend_state_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package remote

import (
"bytes"
"os"
"testing"

"github.com/hashicorp/terraform/state/remote"
"github.com/hashicorp/terraform/terraform"
)

func TestRemoteClient_impl(t *testing.T) {
Expand All @@ -14,3 +17,25 @@ func TestRemoteClient(t *testing.T) {
client := testRemoteClient(t)
remote.TestClient(t, client)
}

func TestRemoteClient_withRunID(t *testing.T) {
// Set the TFE_RUN_ID environment variable before creating the client!
if err := os.Setenv("TFE_RUN_ID", generateID("run-")); err != nil {
t.Fatalf("error setting env var TFE_RUN_ID: %v", err)
}

// Create a new test client.
client := testRemoteClient(t)

// Create a new empty state.
state := bytes.NewBuffer(nil)
if err := terraform.WriteState(terraform.NewState(), state); err != nil {
t.Fatalf("expected no error, got: %v", err)
}

// Store the new state to verify (this will be done
// by the mock that is used) that the run ID is set.
if err := client.Put(state.Bytes()); err != nil {
t.Fatalf("expected no error, got %v", err)
}
}

0 comments on commit cd6d75b

Please sign in to comment.