Files
troubleshoot/cmd/collect/cli/postgres.go
Salah Al Saleh 2a87b280bf Add per-collector subcommands to the collect binary (#2071)
* Add per-collector subcommands to the collect binary

Add `collect http|postgres|mysql|mssql|redis` subcommands that run a single
collector and print its native result JSON to stdout, so a collector can run
inside a Pod via the troubleshoot image (e.g. as a runPod collector).

Each has its own flags mapping to the collector's spec fields and its own help.
The Kubernetes client (used only for TLS-from-Secret) is built to match the
production preflight/support-bundle path (QPS/Burst/UserAgent).

* Add clickhouse subcommand to the collect binary

Add `collect clickhouse`, matching the other per-collector subcommands, so the
clickhouse collector can run inside a Pod via the troubleshoot image (e.g. as a
runPod collector). Same flags as the other database collectors (--uri + --tls-*).

* Make global flags work on the collect subcommands

Register --debug and the Kubernetes flags (--kubeconfig, --context, etc.) as
persistent flags, and move the shared setup to PersistentPreRun/PersistentPostRun,
so the per-collector subcommands inherit the global flags and run the same
logger/profiling setup as `collect [url]`. Previously these were local flags with
setup in PreRun, so subcommands rejected --debug/--kubeconfig and ignored the setup.
2026-07-10 09:31:14 -07:00

89 lines
2.9 KiB
Go

package cli
import (
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// PostgresCmd runs the postgres collector against a single database and prints
// the native result JSON ({"isConnected":..,"version":..,"error":..}).
func PostgresCmd() *cobra.Command {
var (
uri string
skipVerify bool
caCert string
clientCert string
clientKey string
secretName string
secretNamespace string
)
cmd := &cobra.Command{
Use: "postgres",
Short: "Run the postgres collector against a database",
Long: `Run the postgres collector: connect to a PostgreSQL server, run "select version()",
and print the collector result as JSON.
--uri is a libpq/pgx connection URI:
postgres://user:password@host:5432/dbname?sslmode=disable
TLS material may be provided inline / by file path (--tls-cacert, --tls-client-cert,
--tls-client-key) or sourced from a Secret (--tls-secret-name), which requires
cluster access.
Example:
collect postgres --uri "postgres://user:pass@pg.default.svc:5432/app?sslmode=disable"`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
db := &troubleshootv1beta2.Database{
CollectorMeta: troubleshootv1beta2.CollectorMeta{CollectorName: "postgres"},
URI: uri,
}
var (
client kubernetes.Interface
cfg *rest.Config
)
if skipVerify || caCert != "" || clientCert != "" || clientKey != "" || secretName != "" {
tls := &troubleshootv1beta2.TLSParams{
SkipVerify: skipVerify,
CACert: caCert,
ClientCert: clientCert,
ClientKey: clientKey,
}
if secretName != "" {
tls.Secret = &troubleshootv1beta2.TLSSecret{Name: secretName, Namespace: secretNamespace}
var err error
client, cfg, err = k8sClientForCollectors()
if err != nil {
return err
}
}
db.TLS = tls
}
c := &collect.CollectPostgres{Collector: db, ClientConfig: cfg, Client: client, Context: cmd.Context()}
res, err := c.Collect(nil)
if err != nil {
return err
}
return printCollectorResult(res)
},
}
f := cmd.Flags()
f.StringVar(&uri, "uri", "", "PostgreSQL connection URI (required)")
cmd.MarkFlagRequired("uri")
f.BoolVar(&skipVerify, "tls-skip-verify", false, "skip TLS certificate verification")
f.StringVar(&caCert, "tls-cacert", "", "CA certificate (PEM contents or a file path)")
f.StringVar(&clientCert, "tls-client-cert", "", "client certificate (PEM contents or a file path)")
f.StringVar(&clientKey, "tls-client-key", "", "client key (PEM contents or a file path)")
f.StringVar(&secretName, "tls-secret-name", "", "name of a Secret holding TLS material (requires cluster access)")
f.StringVar(&secretNamespace, "tls-secret-namespace", "default", "namespace of the TLS Secret")
return cmd
}