Files
zeekayandHanzo Dev a5c5cc019e Go 1.27.1, and the code it can say more simply
Modules declare go 1.27.1 and the build images follow. go fix applied the
modernizers; omitzero is not applied, since it changes what the JSON says.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 22:42:15 -07:00

288 lines
11 KiB
Go

package dumper
import (
"net/http"
"sort"
"github.com/hanzoai/gateway/v2/internal/lura/config"
"github.com/spf13/cobra"
)
func New(cmd *cobra.Command, prefix string, verboseLevel int) Dumper {
return NewWithColors(cmd, prefix, verboseLevel, true)
}
func NewWithColors(cmd *cobra.Command, prefix string, verboseLevel int, enableColors bool) Dumper {
d := Dumper{
cmd: cmd,
checkDumpPrefix: prefix,
verboseLevel: verboseLevel,
}
if !enableColors {
return d
}
d.colorRed = ColorRed
d.colorGreen = ColorGreen
d.colorReset = ColorReset
d.colorBlue = ColorBlue
d.colorCyan = ColorCyan
d.colorYellow = ColorYellow
d.colorMagenta = ColorMagenta
d.colorWhite = ColorWhite
return d
}
type Dumper struct {
cmd *cobra.Command
checkDumpPrefix string
verboseLevel int
colorRed string
colorGreen string
colorReset string
colorBlue string
colorCyan string
colorYellow string
colorMagenta string
colorWhite string
}
func (c Dumper) Dump(v config.ServiceConfig) error {
c.cmd.Printf("%sGlobal settings%s\n", c.colorGreen, c.colorReset)
c.cmd.Printf("%sName: %s\n", c.checkDumpPrefix, v.Name)
c.cmd.Printf("%sVersion: %d\n", c.checkDumpPrefix, v.Version)
c.cmd.Printf("%sAddress: %s\n", c.checkDumpPrefix, v.Address)
c.cmd.Printf("%sPort: %d\n", c.checkDumpPrefix, v.Port)
if c.verboseLevel > 1 {
c.cmd.Printf("%sDefault cache TTL: %s\n", c.checkDumpPrefix, v.CacheTTL.String())
c.cmd.Printf("%sDefault timeout: %s\n", c.checkDumpPrefix, v.Timeout.String())
}
if len(v.Host) > 0 || c.verboseLevel > 1 {
c.cmd.Printf("%sDefault backend hosts: %v\n", c.checkDumpPrefix, v.Host)
}
if c.verboseLevel > 2 {
c.cmd.Printf("%sRead timeout: %s\n", c.checkDumpPrefix, v.ReadTimeout.String())
c.cmd.Printf("%sWrite timeout: %s\n", c.checkDumpPrefix, v.WriteTimeout.String())
c.cmd.Printf("%sIdle timeout: %s\n", c.checkDumpPrefix, v.IdleTimeout.String())
c.cmd.Printf("%sRead header timeout: %s\n", c.checkDumpPrefix, v.ReadHeaderTimeout.String())
c.cmd.Printf("%sIdle connection timeout: %s\n", c.checkDumpPrefix, v.IdleConnTimeout.String())
c.cmd.Printf("%sResponse header timeout: %s\n", c.checkDumpPrefix, v.ResponseHeaderTimeout.String())
c.cmd.Printf("%sExpect continue timeout: %s\n", c.checkDumpPrefix, v.ExpectContinueTimeout.String())
c.cmd.Printf("%sDialer timeout: %s\n", c.checkDumpPrefix, v.DialerTimeout.String())
c.cmd.Printf("%sDialer fallback delay: %s\n", c.checkDumpPrefix, v.DialerFallbackDelay.String())
c.cmd.Printf("%sDialer keep alive: %s\n", c.checkDumpPrefix, v.DialerKeepAlive.String())
c.cmd.Printf("%sDisable keep alives: %v\n", c.checkDumpPrefix, v.DisableKeepAlives)
c.cmd.Printf("%sDisable compression: %v\n", c.checkDumpPrefix, v.DisableCompression)
c.cmd.Printf("%sMax idle connections: %d\n", c.checkDumpPrefix, v.MaxIdleConns)
c.cmd.Printf("%sMax idle connections per host: %d\n", c.checkDumpPrefix, v.MaxIdleConnsPerHost)
c.cmd.Printf("%sSequential start: %t\n", c.checkDumpPrefix, v.SequentialStart)
c.cmd.Printf("%sMax header bytes: %d\n", c.checkDumpPrefix, v.MaxHeaderBytes)
c.cmd.Printf("%sEcho endpoint enabled: %t\n", c.checkDumpPrefix, v.Echo)
c.cmd.Printf("%sDefault encoding strategy: %s\n", c.checkDumpPrefix, v.OutputEncoding)
c.cmd.Printf("%sDisable strict REST: %t\n", c.checkDumpPrefix, v.DisableStrictREST)
c.cmd.Printf("%sRun lura in debug mode: %t\n", c.checkDumpPrefix, v.Debug)
c.cmd.Printf("%sAllow insecure connections: %t\n", c.checkDumpPrefix, v.AllowInsecureConnections)
c.cmd.Printf("%sUseH2C: %t\n", c.checkDumpPrefix, v.UseH2C)
}
if v.TLS != nil {
c.cmd.Printf("%sTLS Disabled: %t\n", c.checkDumpPrefix, v.TLS.IsDisabled)
// TODO: update this with the new field `Keys`:
c.cmd.Printf("%sTLS Public key: %s\n", c.checkDumpPrefix, v.TLS.PublicKey)
c.cmd.Printf("%sTLS Private key: %s\n", c.checkDumpPrefix, v.TLS.PrivateKey)
c.cmd.Printf("%sTLS Enable MTLS: %t\n", c.checkDumpPrefix, v.TLS.EnableMTLS)
c.cmd.Printf("%sTLS Disable System CA Pool: %v\n", c.checkDumpPrefix, v.TLS.DisableSystemCaPool)
if c.verboseLevel > 1 {
c.cmd.Printf("%sTLS Min version: %s\n", c.checkDumpPrefix, v.TLS.MinVersion)
c.cmd.Printf("%sTLS Max version: %s\n", c.checkDumpPrefix, v.TLS.MaxVersion)
}
if c.verboseLevel > 2 {
c.cmd.Printf("%sTLS Curve preferences: %v\n", c.checkDumpPrefix, v.TLS.CurvePreferences)
c.cmd.Printf("%sTLS Prefer server cipher suites: %v\n", c.checkDumpPrefix, v.TLS.PreferServerCipherSuites)
c.cmd.Printf("%sTLS Cipher suites: %v\n", c.checkDumpPrefix, v.TLS.CipherSuites)
}
} else if c.verboseLevel > 1 {
c.cmd.Printf("%s%sNo TLS section defined%s\n", c.checkDumpPrefix, c.colorRed, c.colorReset)
}
if v.ClientTLS != nil {
c.cmd.Printf("%sClient TLS Allow Insecure Connections: %v\n", c.checkDumpPrefix, v.ClientTLS.AllowInsecureConnections)
c.cmd.Printf("%sClient TLS Disable System CA Pool: %v\n", c.checkDumpPrefix, v.ClientTLS.DisableSystemCaPool)
if c.verboseLevel > 1 {
c.cmd.Printf("%sClient TLS Min version: %s\n", c.checkDumpPrefix, v.ClientTLS.MinVersion)
c.cmd.Printf("%sClient TLS Max version: %s\n", c.checkDumpPrefix, v.ClientTLS.MaxVersion)
}
if c.verboseLevel > 2 {
c.cmd.Printf("%sClient TLS Curve preferences: %v\n", c.checkDumpPrefix, v.ClientTLS.CurvePreferences)
c.cmd.Printf("%sClient TLS Cipher suites: %v\n", c.checkDumpPrefix, v.ClientTLS.CipherSuites)
}
}
if v.Plugin != nil {
c.cmd.Printf("%sFolder: %s\n", c.checkDumpPrefix, v.Plugin.Folder)
c.cmd.Printf("%sPattern: %s\n", c.checkDumpPrefix, v.Plugin.Pattern)
} else if c.verboseLevel > 1 {
c.cmd.Printf("%s%sNo Plugin section defined%s\n", c.checkDumpPrefix, c.colorRed, c.colorReset)
}
if c.verboseLevel > 1 || len(v.ExtraConfig) > 0 {
c.cmd.Printf("%s%d global component configuration(s):%s\n", c.colorGreen, len(v.ExtraConfig), c.colorReset)
c.dumpExtraConfig(v.ExtraConfig, "")
}
c.cmd.Printf("%s%d API endpoint(s):%s\n", c.colorGreen, len(v.Endpoints), c.colorReset)
for _, endpoint := range v.Endpoints {
c.dumpEndpoint(endpoint)
}
c.cmd.Printf("%s%d async agent(s):%s\n", c.colorGreen, len(v.AsyncAgents), c.colorReset)
for _, agent := range v.AsyncAgents {
c.dumpAgent(agent)
}
return nil
}
func (c Dumper) dumpAgent(agent *config.AsyncAgent) {
c.cmd.Printf("%s- %s%s%s\n", c.checkDumpPrefix, c.colorCyan, agent.Name, c.colorReset)
if c.verboseLevel > 1 {
c.cmd.Printf("%sEncoding: %s\n", c.checkDumpPrefix, agent.Encoding)
c.cmd.Printf("%sConsumer Timeout: %s\n", c.checkDumpPrefix, agent.Consumer.Timeout.String())
c.cmd.Printf("%sConsumer Workers: %d\n", c.checkDumpPrefix, agent.Consumer.Workers)
c.cmd.Printf("%sConsumer Topic: %s\n", c.checkDumpPrefix, agent.Consumer.Topic)
c.cmd.Printf("%sConsumer Max Rate: %f\n", c.checkDumpPrefix, agent.Consumer.MaxRate)
c.cmd.Printf("%sConnection Max Retries: %d\n", c.checkDumpPrefix, agent.Connection.MaxRetries)
c.cmd.Printf("%sConnection Backoff Strategy: %s\n", c.checkDumpPrefix, agent.Connection.BackoffStrategy)
c.cmd.Printf("%sConnection Health Interval: %s\n", c.checkDumpPrefix, agent.Connection.HealthInterval.String())
}
if c.verboseLevel > 1 || len(agent.ExtraConfig) > 0 {
c.cmd.Printf("%s%s%d agent component configuration(s):%s\n", c.checkDumpPrefix, c.colorGreen, len(agent.ExtraConfig), c.colorReset)
c.dumpExtraConfig(agent.ExtraConfig, c.checkDumpPrefix)
}
c.cmd.Printf("%s%sConnecting to %d backend(s):%s\n", c.checkDumpPrefix, c.colorGreen, len(agent.Backend), c.colorReset)
for _, backend := range agent.Backend {
c.dumpBackend(backend)
}
}
func (c Dumper) dumpEndpoint(endpoint *config.EndpointConfig) {
c.cmd.Printf("%s- %s%s%s %s%s\n", c.checkDumpPrefix, c.methodColor(endpoint.Method), endpoint.Method, c.colorCyan, endpoint.Endpoint, c.colorReset)
c.cmd.Printf("%sTimeout: %s\n", c.checkDumpPrefix, endpoint.Timeout.String())
if c.verboseLevel > 1 || len(endpoint.QueryString) > 0 {
c.cmd.Printf("%sQueryString: %v\n", c.checkDumpPrefix, endpoint.QueryString)
}
if c.verboseLevel > 1 {
c.cmd.Printf("%sCacheTTL: %s\n", c.checkDumpPrefix, endpoint.CacheTTL.String())
c.cmd.Printf("%sHeaders to pass: %v\n", c.checkDumpPrefix, endpoint.HeadersToPass)
c.cmd.Printf("%sOutputEncoding: %s\n", c.checkDumpPrefix, endpoint.OutputEncoding)
}
if c.verboseLevel > 1 || endpoint.ConcurrentCalls > 1 {
c.cmd.Printf("%sConcurrent calls: %d\n", c.checkDumpPrefix, endpoint.ConcurrentCalls)
}
if c.verboseLevel > 1 || len(endpoint.ExtraConfig) > 0 {
c.cmd.Printf("%s%s%d endpoint component configuration(s):%s\n", c.checkDumpPrefix, c.colorGreen, len(endpoint.ExtraConfig), c.colorReset)
c.dumpExtraConfig(endpoint.ExtraConfig, c.checkDumpPrefix)
}
c.cmd.Printf("%s%sConnecting to %d backend(s):%s\n", c.checkDumpPrefix, c.colorGreen, len(endpoint.Backend), c.colorReset)
for _, backend := range endpoint.Backend {
c.dumpBackend(backend)
}
}
func (c Dumper) dumpBackend(backend *config.Backend) {
prefix := c.checkDumpPrefix + c.checkDumpPrefix
c.cmd.Printf("%s[+] %s%s%s %s%s\n", prefix, c.methodColor(backend.Method), backend.Method, c.colorCyan, backend.URLPattern, c.colorReset)
c.cmd.Printf("%sTimeout: %s\n", prefix, backend.Timeout.String())
c.cmd.Printf("%sHosts: %v\n", prefix, backend.Host)
if c.verboseLevel > 1 {
c.cmd.Printf("%sConcurrent calls: %d\n", prefix, backend.ConcurrentCalls)
c.cmd.Printf("%sHost sanitization disabled: %v\n", prefix, backend.HostSanitizationDisabled)
c.cmd.Printf("%sTarget: %s\n", prefix, backend.Target)
c.cmd.Printf("%sDeny: %v, Allow: %v\n", prefix, backend.DenyList, backend.AllowList)
c.cmd.Printf("%sMapping: %+v\n", prefix, backend.Mapping)
c.cmd.Printf("%sGroup: %s\n", prefix, backend.Group)
c.cmd.Printf("%sEncoding: %s\n", prefix, backend.Encoding)
c.cmd.Printf("%sIs collection: %+v\n", prefix, backend.IsCollection)
c.cmd.Printf("%sSD: %+v\n", prefix, backend.SD)
c.cmd.Printf("%sSD scheme: %s\n", prefix, backend.SDScheme)
c.cmd.Printf("%sHeaders to pass: %v\n", prefix, backend.HeadersToPass)
c.cmd.Printf("%sQuery strings to pass: %v\n", prefix, backend.QueryStringsToPass)
}
if c.verboseLevel > 1 || len(backend.ExtraConfig) > 0 {
c.cmd.Printf("%s%s%d backend component configuration(s):%s\n", prefix, c.colorGreen, len(backend.ExtraConfig), c.colorReset)
c.dumpExtraConfig(backend.ExtraConfig, prefix)
}
c.cmd.Println("")
}
func (c Dumper) dumpExtraConfig(cfg config.ExtraConfig, prefix string) {
var keys []string
for k := range cfg {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
c.cmd.Printf("%s%s- %s%s\n", prefix, c.colorYellow, k, c.colorReset)
if c.verboseLevel > 1 {
switch s := cfg[k].(type) {
case map[string]any:
for i, v := range s {
c.cmd.Printf("\t%s%s: %+v\n", prefix, i, v)
}
case []any:
c.cmd.Printf("\t%s: %+v\n", prefix, s)
default:
c.cmd.Printf("\t%s: %+v\n", prefix, s)
}
}
}
}
func (c Dumper) methodColor(s string) string {
switch s {
case http.MethodGet:
return c.colorBlue
case http.MethodPost:
return c.colorCyan
case http.MethodPut:
return c.colorYellow
case http.MethodDelete:
return c.colorRed
case http.MethodPatch:
return c.colorGreen
case http.MethodHead:
return c.colorMagenta
case http.MethodOptions:
return c.colorWhite
}
return ""
}
const (
ColorGreen = "\033[32;1m"
ColorWhite = "\033[37;1m"
ColorYellow = "\033[33;1m"
ColorRed = "\033[31;1m"
ColorBlue = "\033[34;1m"
ColorMagenta = "\033[36;1m"
ColorCyan = "\033[36;1m"
ColorReset = "\033[0m"
)