backend/remote: Handle cost estimation skipped due to targeting
The remote server might choose to skip running cost estimation for a targeted plan, in which case we'll show a note about it in the UI and then move on, rather than returning an "invalid status" error. This new status isn't yet available in the go-tfe library as a constant, so for now we have the string directly in our switch statement. This is a pragmatic way to expedite getting the "critical path" of this feature in place without blocking on changes to ancillary codebases. A subsequent commit should switch this over to tfe.CostEstimateSkippedDueToTargeting once that's available in a go-tfe release.
This commit is contained in:
parent
0eea4e7c62
commit
8e1615a802
|
@ -316,6 +316,10 @@ func (b *Remote) costEstimate(stopCtx, cancelCtx context.Context, op *backend.Op
|
||||||
b.CLI.Output(b.Colorize().Color("Waiting for cost estimate to complete..." + elapsed + "\n"))
|
b.CLI.Output(b.Colorize().Color("Waiting for cost estimate to complete..." + elapsed + "\n"))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
case "skipped_due_to_targeting": // TEMP: not available in the go-tfe library yet; will update this to be tfe.CostEstimateSkippedDueToTargeting once that's available.
|
||||||
|
b.CLI.Output("Not available for this plan, because it was created with the -target option.")
|
||||||
|
b.CLI.Output("\n------------------------------------------------------------------------")
|
||||||
|
return nil
|
||||||
case tfe.CostEstimateErrored:
|
case tfe.CostEstimateErrored:
|
||||||
return fmt.Errorf(msgPrefix + " errored.")
|
return fmt.Errorf(msgPrefix + " errored.")
|
||||||
case tfe.CostEstimateCanceled:
|
case tfe.CostEstimateCanceled:
|
||||||
|
|
|
@ -696,6 +696,11 @@ type mockRuns struct {
|
||||||
client *mockClient
|
client *mockClient
|
||||||
runs map[string]*tfe.Run
|
runs map[string]*tfe.Run
|
||||||
workspaces map[string][]*tfe.Run
|
workspaces map[string][]*tfe.Run
|
||||||
|
|
||||||
|
// If modifyNewRun is non-nil, the create method will call it just before
|
||||||
|
// saving a new run in the runs map, so that a calling test can mimic
|
||||||
|
// side-effects that a real server might apply in certain situations.
|
||||||
|
modifyNewRun func(client *mockClient, options tfe.RunCreateOptions, run *tfe.Run)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockRuns(client *mockClient) *mockRuns {
|
func newMockRuns(client *mockClient) *mockRuns {
|
||||||
|
@ -780,6 +785,12 @@ func (m *mockRuns) Create(ctx context.Context, options tfe.RunCreateOptions) (*t
|
||||||
w.CurrentRun = r
|
w.CurrentRun = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.modifyNewRun != nil {
|
||||||
|
// caller-provided callback may modify the run in-place to mimic
|
||||||
|
// side-effects that a real server might take in some situations.
|
||||||
|
m.modifyNewRun(m.client, options, r)
|
||||||
|
}
|
||||||
|
|
||||||
m.runs[r.ID] = r
|
m.runs[r.ID] = r
|
||||||
m.workspaces[options.Workspace.ID] = append(m.workspaces[options.Workspace.ID], r)
|
m.workspaces[options.Workspace.ID] = append(m.workspaces[options.Workspace.ID], r)
|
||||||
|
|
||||||
|
|
|
@ -270,6 +270,29 @@ func TestRemote_planWithTarget(t *testing.T) {
|
||||||
b, bCleanup := testBackendDefault(t)
|
b, bCleanup := testBackendDefault(t)
|
||||||
defer bCleanup()
|
defer bCleanup()
|
||||||
|
|
||||||
|
// When the backend code creates a new run, we'll tweak it so that it
|
||||||
|
// has a cost estimation object with the "skipped_due_to_targeting" status,
|
||||||
|
// emulating how a real server is expected to behave in that case.
|
||||||
|
b.client.Runs.(*mockRuns).modifyNewRun = func(client *mockClient, options tfe.RunCreateOptions, run *tfe.Run) {
|
||||||
|
const fakeID = "fake"
|
||||||
|
// This is the cost estimate object embedded in the run itself which
|
||||||
|
// the backend will use to learn the ID to request from the cost
|
||||||
|
// estimates endpoint. It's pending to simulate what a freshly-created
|
||||||
|
// run is likely to look like.
|
||||||
|
run.CostEstimate = &tfe.CostEstimate{
|
||||||
|
ID: fakeID,
|
||||||
|
Status: "pending",
|
||||||
|
}
|
||||||
|
// The backend will then use the main cost estimation API to retrieve
|
||||||
|
// the same ID indicated in the object above, where we'll then return
|
||||||
|
// the status "skipped_due_to_targeting" to trigger the special skip
|
||||||
|
// message in the backend output.
|
||||||
|
client.CostEstimates.estimations[fakeID] = &tfe.CostEstimate{
|
||||||
|
ID: fakeID,
|
||||||
|
Status: "skipped_due_to_targeting",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
op, configCleanup := testOperationPlan(t, "./testdata/plan")
|
op, configCleanup := testOperationPlan(t, "./testdata/plan")
|
||||||
defer configCleanup()
|
defer configCleanup()
|
||||||
|
|
||||||
|
@ -291,6 +314,13 @@ func TestRemote_planWithTarget(t *testing.T) {
|
||||||
t.Fatalf("expected plan to be non-empty")
|
t.Fatalf("expected plan to be non-empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testBackendDefault above attached a "mock UI" to our backend, so we
|
||||||
|
// can retrieve its non-error output via the OutputWriter in-memory buffer.
|
||||||
|
gotOutput := b.CLI.(*cli.MockUi).OutputWriter.String()
|
||||||
|
if wantOutput := "Not available for this plan, because it was created with the -target option."; !strings.Contains(gotOutput, wantOutput) {
|
||||||
|
t.Errorf("missing message about skipped cost estimation\ngot:\n%s\nwant substring: %s", gotOutput, wantOutput)
|
||||||
|
}
|
||||||
|
|
||||||
// We should find a run inside the mock client that has the same
|
// We should find a run inside the mock client that has the same
|
||||||
// target address we requested above.
|
// target address we requested above.
|
||||||
runsAPI := b.client.Runs.(*mockRuns)
|
runsAPI := b.client.Runs.(*mockRuns)
|
||||||
|
@ -303,7 +333,7 @@ func TestRemote_planWithTarget(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(run.Message, "using -target") {
|
if !strings.Contains(run.Message, "using -target") {
|
||||||
t.Fatalf("incorrrect Message on the created run: %s", run.Message)
|
t.Errorf("incorrect Message on the created run: %s", run.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue