mirror of https://github.com/hashicorp/terraform
Emit warnings for certain run events in cloud backend (#33020)
The cloud backend, which communicates with TFC like APIs, can create runs which may have one more configuration parameters altered. These alterations are emitted as run-events on the run so that API clients can consume and display them to users. This commit adds a step in plan operation to query the run-events once a run is created and then emit specific run-event descriptions to the console as warnings for the user.pull/21655/merge
parent
c10a07f3b2
commit
7e2e834aff
@ -0,0 +1,46 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
)
|
||||
|
||||
const (
|
||||
changedPolicyEnforcementAction = "changed_policy_enforcements"
|
||||
changedTaskEnforcementAction = "changed_task_enforcements"
|
||||
ignoredPolicySetAction = "ignored_policy_sets"
|
||||
)
|
||||
|
||||
func (b *Cloud) renderRunWarnings(ctx context.Context, client *tfe.Client, runId string) error {
|
||||
if b.CLI == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result, err := client.RunEvents.List(ctx, runId, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't have to worry about paging as the API doesn't support it yet
|
||||
for _, re := range result.Items {
|
||||
switch re.Action {
|
||||
case changedPolicyEnforcementAction, changedTaskEnforcementAction, ignoredPolicySetAction:
|
||||
if re.Description != "" {
|
||||
b.CLI.Warn(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
|
||||
runWarningHeader, re.Description)) + "\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const runWarningHeader = `
|
||||
[reset][yellow]Warning:[reset] %s
|
||||
`
|
||||
@ -0,0 +1,153 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/hashicorp/go-tfe"
|
||||
tfemocks "github.com/hashicorp/go-tfe/mocks"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func MockAllRunEvents(t *testing.T, client *tfe.Client) (fullRunID string, emptyRunID string) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
fullRunID = "run-full"
|
||||
emptyRunID = "run-empty"
|
||||
|
||||
mockRunEventsAPI := tfemocks.NewMockRunEvents(ctrl)
|
||||
|
||||
emptyList := tfe.RunEventList{
|
||||
Items: []*tfe.RunEvent{},
|
||||
}
|
||||
fullList := tfe.RunEventList{
|
||||
Items: []*tfe.RunEvent{
|
||||
{
|
||||
Action: "created",
|
||||
CreatedAt: time.Now(),
|
||||
Description: "",
|
||||
},
|
||||
{
|
||||
Action: "changed_task_enforcements",
|
||||
CreatedAt: time.Now(),
|
||||
Description: "The enforcement level for task 'MockTask' was changed to 'advisory' because the run task limit was exceeded.",
|
||||
},
|
||||
{
|
||||
Action: "changed_policy_enforcements",
|
||||
CreatedAt: time.Now(),
|
||||
Description: "The enforcement level for policy 'MockPolicy' was changed to 'advisory' because the policy limit was exceeded.",
|
||||
},
|
||||
{
|
||||
Action: "ignored_policy_sets",
|
||||
CreatedAt: time.Now(),
|
||||
Description: "The policy set 'MockPolicySet' was ignored because the versioned policy set limit was exceeded.",
|
||||
},
|
||||
{
|
||||
Action: "queued",
|
||||
CreatedAt: time.Now(),
|
||||
Description: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
// Mock Full Request
|
||||
mockRunEventsAPI.
|
||||
EXPECT().
|
||||
List(gomock.Any(), fullRunID, gomock.Any()).
|
||||
Return(&fullList, nil).
|
||||
AnyTimes()
|
||||
|
||||
// Mock Full Request
|
||||
mockRunEventsAPI.
|
||||
EXPECT().
|
||||
List(gomock.Any(), emptyRunID, gomock.Any()).
|
||||
Return(&emptyList, nil).
|
||||
AnyTimes()
|
||||
|
||||
// Mock a bad Read response
|
||||
mockRunEventsAPI.
|
||||
EXPECT().
|
||||
List(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return(nil, tfe.ErrInvalidRunID).
|
||||
AnyTimes()
|
||||
|
||||
// Wire up the mock interfaces
|
||||
client.RunEvents = mockRunEventsAPI
|
||||
return
|
||||
}
|
||||
|
||||
func TestRunEventWarningsAll(t *testing.T) {
|
||||
b, bCleanup := testBackendWithName(t)
|
||||
defer bCleanup()
|
||||
|
||||
config := &tfe.Config{
|
||||
Token: "not-a-token",
|
||||
}
|
||||
client, _ := tfe.NewClient(config)
|
||||
fullRunID, _ := MockAllRunEvents(t, client)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
err := b.renderRunWarnings(ctx, client, fullRunID)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to not error but received %s", err)
|
||||
}
|
||||
|
||||
output := b.CLI.(*cli.MockUi).ErrorWriter.String()
|
||||
testString := "The enforcement level for task 'MockTask'"
|
||||
if !strings.Contains(output, testString) {
|
||||
t.Fatalf("Expected %q to contain %q but it did not", output, testString)
|
||||
}
|
||||
testString = "The enforcement level for policy 'MockPolicy'"
|
||||
if !strings.Contains(output, testString) {
|
||||
t.Fatalf("Expected %q to contain %q but it did not", output, testString)
|
||||
}
|
||||
testString = "The policy set 'MockPolicySet'"
|
||||
if !strings.Contains(output, testString) {
|
||||
t.Fatalf("Expected %q to contain %q but it did not", output, testString)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEventWarningsEmpty(t *testing.T) {
|
||||
b, bCleanup := testBackendWithName(t)
|
||||
defer bCleanup()
|
||||
|
||||
config := &tfe.Config{
|
||||
Token: "not-a-token",
|
||||
}
|
||||
client, _ := tfe.NewClient(config)
|
||||
_, emptyRunID := MockAllRunEvents(t, client)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
err := b.renderRunWarnings(ctx, client, emptyRunID)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to not error but received %s", err)
|
||||
}
|
||||
|
||||
output := b.CLI.(*cli.MockUi).ErrorWriter.String()
|
||||
if output != "" {
|
||||
t.Fatalf("Expected %q to be empty but it was not", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEventWarningsWithError(t *testing.T) {
|
||||
b, bCleanup := testBackendWithName(t)
|
||||
defer bCleanup()
|
||||
|
||||
config := &tfe.Config{
|
||||
Token: "not-a-token",
|
||||
}
|
||||
client, _ := tfe.NewClient(config)
|
||||
MockAllRunEvents(t, client)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
err := b.renderRunWarnings(ctx, client, "bad run id")
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected to error but did not")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue