Only show the full policy output when it fails

If the policy passes, only show that instead of the full check output to prevent cluttering the output. So a passing policy will only show:

-----------------------------------------------
Organization policy check: passed
-----------------------------------------------
This commit is contained in:
Sander van Harmelen 2018-10-01 12:00:23 +02:00
parent c1fe05ec75
commit 37f5ab3500
4 changed files with 78 additions and 53 deletions

View File

@ -7,6 +7,7 @@ import (
"fmt"
"log"
"strings"
"time"
tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/terraform/backend"
@ -146,21 +147,30 @@ func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operati
return r, nil
}
func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) (err error) {
if b.CLI != nil {
b.CLI.Output("\n------------------------------------------------------------------------\n")
}
for _, pc := range r.PolicyChecks {
logs, err := b.client.PolicyChecks.Logs(stopCtx, pc.ID)
if err != nil {
return generalError("error retrieving policy check logs", err)
}
scanner := bufio.NewScanner(logs)
// Loop until the context is canceled or the policy check is finished.
for {
pc, err = b.client.PolicyChecks.Read(stopCtx, pc.ID)
if err != nil {
return generalError("error retrieving policy check", err)
}
// Retrieve the policy check to get its current status.
pc, err := b.client.PolicyChecks.Read(stopCtx, pc.ID)
if err != nil {
return generalError("error retrieving policy check", err)
switch pc.Status {
case tfe.PolicyPending, tfe.PolicyQueued:
select {
case <-stopCtx.Done():
return generalError("error retrieving policy check", stopCtx.Err())
case <-time.After(500 * time.Millisecond):
continue
}
}
// Break if the policy check is finished.
break
}
var msgPrefix string
@ -173,10 +183,25 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope
msgPrefix = fmt.Sprintf("Unknown policy check (%s)", pc.Scope)
}
// Don't show the full policy output if the policy passed.
if pc.Status == tfe.PolicyPasses {
if b.CLI != nil {
b.CLI.Output(b.Colorize().Color(msgPrefix + ": passed\n"))
b.CLI.Output("------------------------------------------------------------------------")
}
continue
}
if b.CLI != nil {
b.CLI.Output(b.Colorize().Color(msgPrefix + ":\n"))
}
logs, err := b.client.PolicyChecks.Logs(stopCtx, pc.ID)
if err != nil {
return generalError("error retrieving policy check logs", err)
}
scanner := bufio.NewScanner(logs)
for scanner.Scan() {
if b.CLI != nil {
b.CLI.Output(b.Colorize().Color(scanner.Text()))
@ -187,11 +212,6 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope
}
switch pc.Status {
case tfe.PolicyPasses:
if b.CLI != nil {
b.CLI.Output("\n------------------------------------------------------------------------")
}
continue
case tfe.PolicyErrored:
return fmt.Errorf(msgPrefix + " errored.")
case tfe.PolicyHardFailed:
@ -215,13 +235,13 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope
return err
}
if b.CLI != nil {
b.CLI.Output("------------------------------------------------------------------------")
}
if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
return generalError("error overriding policy check", err)
}
if b.CLI != nil {
b.CLI.Output("------------------------------------------------------------------------")
}
}
return nil

View File

@ -441,8 +441,8 @@ func TestRemote_applyPolicyPass(t *testing.T) {
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
t.Fatalf("missing plan summery in output: %s", output)
}
if !strings.Contains(output, "Sentinel Result: true") {
t.Fatalf("missing Sentinel result in output: %s", output)
if !strings.Contains(output, "policy check: passed") {
t.Fatalf("missing polic check result in output: %s", output)
}
if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
t.Fatalf("missing apply summery in output: %s", output)
@ -486,7 +486,7 @@ func TestRemote_applyPolicyHardFail(t *testing.T) {
t.Fatalf("missing plan summery in output: %s", output)
}
if !strings.Contains(output, "Sentinel Result: false") {
t.Fatalf("missing Sentinel result in output: %s", output)
t.Fatalf("missing policy check result in output: %s", output)
}
if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
t.Fatalf("unexpected apply summery in output: %s", output)
@ -529,7 +529,7 @@ func TestRemote_applyPolicySoftFail(t *testing.T) {
t.Fatalf("missing plan summery in output: %s", output)
}
if !strings.Contains(output, "Sentinel Result: false") {
t.Fatalf("missing Sentinel result in output: %s", output)
t.Fatalf("missing policy check result in output: %s", output)
}
if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
t.Fatalf("missing apply summery in output: %s", output)
@ -572,7 +572,7 @@ func TestRemote_applyPolicySoftFailAutoApprove(t *testing.T) {
t.Fatalf("missing plan summery in output: %s", output)
}
if !strings.Contains(output, "Sentinel Result: false") {
t.Fatalf("missing Sentinel result in output: %s", output)
t.Fatalf("missing policy check result in output: %s", output)
}
if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
t.Fatalf("missing apply summery in output: %s", output)

View File

@ -471,6 +471,38 @@ func (m *mockPolicyChecks) Read(ctx context.Context, policyCheckID string) (*tfe
if !ok {
return nil, tfe.ErrResourceNotFound
}
logfile, ok := m.logs[pc.ID]
if !ok {
return nil, tfe.ErrResourceNotFound
}
if _, err := os.Stat(logfile); os.IsNotExist(err) {
return nil, fmt.Errorf("logfile does not exist")
}
logs, err := ioutil.ReadFile(logfile)
if err != nil {
return nil, err
}
switch {
case bytes.Contains(logs, []byte("Sentinel Result: true")):
pc.Status = tfe.PolicyPasses
case bytes.Contains(logs, []byte("Sentinel Result: false")):
switch {
case bytes.Contains(logs, []byte("hard-mandatory")):
pc.Status = tfe.PolicyHardFailed
case bytes.Contains(logs, []byte("soft-mandatory")):
pc.Actions.IsOverridable = true
pc.Permissions.CanOverride = true
pc.Status = tfe.PolicySoftFailed
}
default:
// As this is an unexpected state, we say the policy errored.
pc.Status = tfe.PolicyErrored
}
return pc, nil
}
@ -495,7 +527,7 @@ func (m *mockPolicyChecks) Logs(ctx context.Context, policyCheckID string) (io.R
}
if _, err := os.Stat(logfile); os.IsNotExist(err) {
return bytes.NewBufferString("logfile does not exist"), nil
return nil, fmt.Errorf("logfile does not exist")
}
logs, err := ioutil.ReadFile(logfile)
@ -503,23 +535,6 @@ func (m *mockPolicyChecks) Logs(ctx context.Context, policyCheckID string) (io.R
return nil, err
}
switch {
case bytes.Contains(logs, []byte("Sentinel Result: true")):
pc.Status = tfe.PolicyPasses
case bytes.Contains(logs, []byte("Sentinel Result: false")):
switch {
case bytes.Contains(logs, []byte("hard-mandatory")):
pc.Status = tfe.PolicyHardFailed
case bytes.Contains(logs, []byte("soft-mandatory")):
pc.Actions.IsOverridable = true
pc.Permissions.CanOverride = true
pc.Status = tfe.PolicySoftFailed
}
default:
// As this is an unexpected state, we say the policy errored.
pc.Status = tfe.PolicyErrored
}
return bytes.NewBuffer(logs), nil
}

View File

@ -1,12 +1,2 @@
# This line is here only for the mock!
Sentinel Result: true
This result means that Sentinel policies returned true and the protected
behavior is allowed by Sentinel policies.
1 policies evaluated.
## Policy 1: Passthrough.sentinel (soft-mandatory)
Result: true
TRUE - Passthrough.sentinel:1:1 - Rule "main"