/
githubmirror
/
terraform
Обзор
Документация
Войти
/
githubmirror
/
terraform
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
internal/command/views/json_view.go
241 строка
6 KB
Sebastian Rivera
views/query: rename queryPolicyPolicyResult, replace copyIdentity, fix log level, add doc comments
11 авг 2026, 17:04
11 авг 2026, 17:04
8559a7c
Код
Авторство
О чём код?
// Copyright IBM Corp. 2014, 2026 // SPDX-License-Identifier: BUSL-1.1 package views import ( encJson "encoding/json" "fmt" "github.com/hashicorp/go-hclog" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/internal/command/views/json" "github.com/hashicorp/terraform/internal/policy" "github.com/hashicorp/terraform/internal/tfdiags" tfversion "github.com/hashicorp/terraform/version" ) // This version describes the schema of JSON UI messages. This version must be // updated after making any changes to this view, the jsonHook, or any of the // command/views/json package. const JSON_UI_VERSION = "1.3" func NewJSONView(view *View) *JSONView { log := hclog.New(&hclog.LoggerOptions{ Name: "terraform.ui", Output: view.streams.Stdout.File, JSONFormat: true, }) jv := &JSONView{ log: log, view: view, } jv.Version() return jv } type JSONView struct { // hclog is used for all output in JSON UI mode. The logger has an internal // mutex to ensure that messages are not interleaved. log hclog.Logger // We hold a reference to the view entirely to allow us to access the // ConfigSources function pointer, in order to render source snippets into // diagnostics. This is even more unfortunate than the same reference in the // view. // // Do not be tempted to dereference the configSource value upon logger init, // as it will likely be updated later. view *View } func (v *JSONView) Version() { version := tfversion.String() v.log.Info( fmt.Sprintf("Terraform %s", version), "type", json.MessageVersion, "terraform", version, "ui", JSON_UI_VERSION, ) } func (v *JSONView) Log(message string) { v.log.Info(message, "type", json.MessageLog) } func (v *JSONView) StateDump(state string) { v.log.Info( "Emergency state dump", "type", json.MessageLog, "state", encJson.RawMessage(state), ) } func (v *JSONView) Diagnostics(diags tfdiags.Diagnostics, metadata ...interface{}) { sources := v.view.configSources() for _, diag := range diags { diagnostic := json.NewDiagnostic(diag, sources) args := []interface{}{"type", json.MessageDiagnostic, "diagnostic", diagnostic} args = append(args, metadata...) switch diag.Severity() { case tfdiags.Warning: v.log.Warn(fmt.Sprintf("Warning: %s", diag.Description().Summary), args...) default: v.log.Error(fmt.Sprintf("Error: %s", diag.Description().Summary), args...) } } } func (v *JSONView) PlannedChange(c *json.ResourceInstanceChange) { v.log.Info( c.String(), "type", json.MessagePlannedChange, "change", c, ) } func (v *JSONView) PlannedActionInvocation(action *json.ActionInvocation) { v.log.Info( fmt.Sprintf("planned action invocation: %s", action.Action.Action), "type", json.MessagePlannedActionInvocation, "invocation", action, ) } func (v *JSONView) ResourceDrift(c *json.ResourceInstanceChange) { v.log.Info( fmt.Sprintf("%s: Drift detected (%s)", c.Resource.Addr, c.Action), "type", json.MessageResourceDrift, "change", c, ) } func (v *JSONView) ChangeSummary(cs *json.ChangeSummary) { v.log.Info( cs.String(), "type", json.MessageChangeSummary, "changes", cs, ) } func (v *JSONView) Hook(h json.Hook) { v.log.Info( h.String(), "type", h.HookType(), "hook", h, ) } func (v *JSONView) Outputs(outputs json.Outputs) { v.log.Info( outputs.String(), "type", json.MessageOutputs, "outputs", outputs, ) } func (v *JSONView) logPolicyResult(addr string, resp policy.EvaluationResponse) { // Log all the info messages for _, enforcement := range resp.Enforcements { if enforcement.Message == "" { continue } var src []byte if enforcement.LocalRange != nil { src = v.view.configSources()[enforcement.LocalRange.Filename] } info := json.NewPolicyInfo(src, enforcement) args := []any{ "type", json.MessagePolicyInfo, "target_address", addr, json.MessagePolicyInfo, info, "@policy", "true", "result", enforcement.Result.String(), } if enforcement.Policy != nil { args = append(args, "policy_metadata", json.MetadataFromEnforcement(enforcement)) } v.log.Info("Policy info", args...) } for _, diag := range resp.Diagnostics { v.logPolicyDiagnostic(diag, "target_address", addr) } for _, policy := range resp.Policies { v.log.Info( "Policy Result", "type", json.MessagePolicyEvaluationResult, "result", policy.Result.String(), "target_address", addr, "policy_address", policy.Address, "@policy", "true", "policy_metadata", json.MetadataFromPolicy(*policy), ) } } func (v *JSONView) logPolicyQuerySummary(summary queryPolicySummary) { v.log.Info( "Policy query summary", "type", json.MessagePolicyQuerySummary, "@policy", "true", "list_block_address", summary.ListBlockAddress, "overall_result", summary.OverallResult, "results", summary.Results, "passed_policies", summary.PassedPolicies, ) } func (v *JSONView) PolicyResult(addr string, resp policy.EvaluationResponse) { v.logPolicyResult(addr, resp) } // PolicyDiagnostics logs policy diagnostics that are not tied to a specific // target, such as setup diagnostics (e.g. a failure to connect to the policy // engine), so no target address is attached. func (v *JSONView) PolicyDiagnostics(diags policy.Diagnostics) { for _, diag := range diags { v.logPolicyDiagnostic(diag) } } // logPolicyDiagnostic logs the policy diagnostics. These are emitted as `policy_diagnostic` messages, // not standard Terraform `diagnostic` messages. We use the severity level only to // set the log level for that policy-specific output. func (v *JSONView) logPolicyDiagnostic(diag tfdiags.Diagnostic, extraArgs ...any) { sources := v.view.configSources() diagnostic := json.NewDiagnostic(diag, sources) args := []any{ "type", json.MessagePolicyDiagnostic, "@policy", "true", json.MessagePolicyDiagnostic, diagnostic, } args = append(args, extraArgs...) extra := tfdiags.ExtraInfo[*policy.PolicyExtra](diag) if extra != nil { policyMetadata := json.MetadataFromPolicy(extra.Policy) if extra.EnforceIndex != nil { policyMetadata.EnforceIndex = extra.EnforceIndex } args = append(args, "policy_metadata", policyMetadata) args = append(args, "result", extra.Result.String()) } switch extra.Severity { case hcl.DiagWarning: v.log.Warn(fmt.Sprintf("Warning: %s", diag.Description().Summary), args...) default: v.log.Error(fmt.Sprintf("Error: %s", diag.Description().Summary), args...) } } var _ Spacer = (*JSONView)(nil) // Spacer is a no-op for JSON view, as empty lines are not needed to space-out logs in machine-readable output. func (v *JSONView) Spacer() { // do nothing }