// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package policy import ( "bytes" "encoding/json" "fmt" "strings" "github.com/hashicorp/consul/api" ) const ( PrettyFormat string = "pretty" JSONFormat string = "json" ) // Formatter defines methods provided by policy command output formatter type Formatter interface { FormatPolicy(policy *api.ACLPolicy) (string, error) FormatPolicyList(policies []*api.ACLPolicyListEntry) (string, error) } // GetSupportedFormats returns supported formats func GetSupportedFormats() []string { return []string{PrettyFormat, JSONFormat} } // NewFormatter returns Formatter implementation func NewFormatter(format string, showMeta bool) (formatter Formatter, err error) { switch format { case PrettyFormat: formatter = newPrettyFormatter(showMeta) case JSONFormat: formatter = newJSONFormatter(showMeta) default: err = fmt.Errorf("Unknown format: %s", format) } return formatter, err } func newPrettyFormatter(showMeta bool) Formatter { return &prettyFormatter{showMeta} } type prettyFormatter struct { showMeta bool } func (f *prettyFormatter) FormatPolicy(policy *api.ACLPolicy) (string, error) { var buffer bytes.Buffer buffer.WriteString(fmt.Sprintf("ID: %s\n", policy.ID)) buffer.WriteString(fmt.Sprintf("Name: %s\n", policy.Name)) if policy.Partition != "" { buffer.WriteString(fmt.Sprintf("Partition: %s\n", policy.Partition)) } if policy.Namespace != "" { buffer.WriteString(fmt.Sprintf("Namespace: %s\n", policy.Namespace)) } buffer.WriteString(fmt.Sprintf("Description: %s\n", policy.Description)) buffer.WriteString(fmt.Sprintf("Datacenters: %s\n", strings.Join(policy.Datacenters, ", "))) if f.showMeta { buffer.WriteString(fmt.Sprintf("Hash: %x\n", policy.Hash)) buffer.WriteString(fmt.Sprintf("Create Index: %d\n", policy.CreateIndex)) buffer.WriteString(fmt.Sprintf("Modify Index: %d\n", policy.ModifyIndex)) } buffer.WriteString(fmt.Sprintln("Rules:")) buffer.WriteString(policy.Rules) return buffer.String(), nil } func (f *prettyFormatter) FormatPolicyList(policies []*api.ACLPolicyListEntry) (string, error) { var buffer bytes.Buffer for _, policy := range policies { buffer.WriteString(f.formatPolicyListEntry(policy)) } return buffer.String(), nil } func (f *prettyFormatter) formatPolicyListEntry(policy *api.ACLPolicyListEntry) string { var buffer bytes.Buffer buffer.WriteString(fmt.Sprintf("%s:\n", policy.Name)) buffer.WriteString(fmt.Sprintf(" ID: %s\n", policy.ID)) if policy.Partition != "" { buffer.WriteString(fmt.Sprintf(" Partition: %s\n", policy.Partition)) } if policy.Namespace != "" { buffer.WriteString(fmt.Sprintf(" Namespace: %s\n", policy.Namespace)) } buffer.WriteString(fmt.Sprintf(" Description: %s\n", policy.Description)) buffer.WriteString(fmt.Sprintf(" Datacenters: %s\n", strings.Join(policy.Datacenters, ", "))) if f.showMeta { buffer.WriteString(fmt.Sprintf(" Hash: %x\n", policy.Hash)) buffer.WriteString(fmt.Sprintf(" Create Index: %d\n", policy.CreateIndex)) buffer.WriteString(fmt.Sprintf(" Modify Index: %d\n", policy.ModifyIndex)) } return buffer.String() } func newJSONFormatter(showMeta bool) Formatter { return &jsonFormatter{showMeta} } type jsonFormatter struct { showMeta bool } func (f *jsonFormatter) FormatPolicy(policy *api.ACLPolicy) (string, error) { b, err := json.MarshalIndent(policy, "", " ") if err != nil { return "", fmt.Errorf("Failed to marshal policy: %v", err) } return string(b), nil } func (f *jsonFormatter) FormatPolicyList(policies []*api.ACLPolicyListEntry) (string, error) { b, err := json.MarshalIndent(policies, "", " ") if err != nil { return "", fmt.Errorf("Failed to marshal policies: %v", err) } return string(b), nil }