Files
gateway/internal/plugin/cobra/dumper/dumper.go
zeekayandHanzo Dev 53350699b6 deps(vendor): fold the krakend/lura module set into internal/
Every import in this module now resolves to github.com/hanzoai/gateway/v2.
The 34 github.com/krakend/* + github.com/luraproject/lura modules that
supplied the engine and its components are vendored under internal/ and
their 91 packages rewritten onto our own path.

Why fold rather than mirror into 34 hanzoai/* repos:

  - It removes the exposure outright. 34 rows leave 34 rows of go.sum to
    reason about; zero modules leave nothing. `go list -m all` and go.sum
    now contain no krakend/lura entry at all.
  - Cross-references cannot go wrong. 28 of the 34 import lura (97 files
    inside lura self-reference it). Mirroring means rewriting every one of
    those to our lura, and a single miss silently links a SECOND copy of
    lura into the binary. With one module that is structurally impossible.
  - It creates no duplicates. These are lura-coupled gateway glue with no
    consumer outside this binary; publishing 34 repos would be 34 new
    things to maintain for zero second caller. internal/ makes that
    guarantee mechanical — Go forbids importing it from outside this
    module, so none of it can become a competing public package. Verified
    no repo outside gateway imports any hanzoai/gateway/v2 subpackage.

Layout mirrors provenance so an upstream re-sync stays a diff:

  luraproject/lura/v2  -> internal/lura         (the engine, 20 pkgs)
  krakend/krakend-<x>  -> internal/plugin/<x>   (28 components)
  krakend/<x>          -> internal/pkg/<x>      (6 standalone libs)

This commit is PURELY MECHANICAL: 196 of the 197 vendored files are
byte-identical to their upstream original once the import rewrite is
applied. The single exception is bloomfilter's subpackage, which upstream
names `krakend` — the one package name that could not survive as-is; it
becomes internal/pkg/bloomfilter/register. Hand edits land separately in
the next commit so they are readable on their own.

Per `go mod vendor` semantics, dependencies' _test.go files are not
vendored. They test upstream code at a pinned version that we do not
modify, several cannot run at all from a module distribution (they need
TLS certs and compiled .so plugins upstream generates but never ships),
and one is a 100k-request stress test that exhausts the ephemeral port
range and fails every package running beside it. Fold integrity is proven
by the byte-diff above instead, which is the stronger check.

Preserved deliberately — each of these is behaviour, not branding:
  - the `github.com/devopsfaith/krakend*` extra_config namespace strings
    (35 of them). These are config-surface keys, not import paths;
    renaming one silently stops that component finding its config. The
    jose validator namespace backs `auth/validator` on 212 endpoints.
  - core.KrakendVersion / KrakendUserAgent / the X-KRAKEND consts, whose
    VALUES rebrand.go overwrites — that seam is unchanged.
  - the KRAKEND_ koanf env prefix (a hardcoded upstream const).
  - every vendored module's LICENSE (34 files, Apache-2.0/MIT).

The Makefile/CI -X paths move with the engine. An -X naming a symbol that
does not exist is silently ignored by the linker, so a stale path here
would have shipped an "undefined" version in the backend User-Agent and
X-Api-Version with a perfectly green build. Verified live:
`gateway version` reports 2.13.0, not undefined.

Verification (GOWORK=off CGO_ENABLED=0, both tag modes):
  go build ./...              OK      go build -tags legacy ./...   OK
  go vet ./...                clean   go vet -tags legacy ./...     clean
  go test ./...               6/6 ok  go test -tags legacy          5/5 ok
  tests/ integration harness  47 fixtures pass
  gateway check -c configs/{hanzo,lux}/gateway.json  -> Syntax OK!
  go list -m all | grep -iE 'krakend|lura'  -> empty
  go mod verify -> all modules verified

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-25 14:57:19 -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]interface{}:
for i, v := range s {
c.cmd.Printf("\t%s%s: %+v\n", prefix, i, v)
}
case []interface{}:
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"
)