Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backend/remote: add the run ID to associate state #18818

Merged
merged 1 commit into from
Sep 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}