diff --git a/go.mod b/go.mod index 5dab7b6..7aaec00 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,12 @@ require ( github.com/breml/rootcerts v0.3.1 github.com/coder/coder/v2 v2.29.3 github.com/coder/quartz v0.3.0 + github.com/coder/serpent v0.13.0 github.com/coder/websocket v1.8.14 github.com/fatih/color v1.18.0 github.com/go-chi/chi/v5 v5.2.2 github.com/google/uuid v1.6.0 github.com/hashicorp/yamux v0.1.2 - github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 google.golang.org/protobuf v1.36.10 k8s.io/api v0.34.1 @@ -25,6 +25,7 @@ require ( ) require ( + cdr.dev/slog/v3 v3.0.0-rc1 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/DataDog/appsec-internal-go v1.11.2 // indirect @@ -85,7 +86,6 @@ require ( github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 // indirect github.com/coder/retry v1.5.1 // indirect - github.com/coder/serpent v0.12.0 // indirect github.com/coder/terraform-provider-coder/v2 v2.13.1 // indirect github.com/coreos/go-iptables v0.6.0 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect @@ -134,7 +134,6 @@ require ( github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02 // indirect github.com/illarion/gonotify v1.0.1 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect diff --git a/go.sum b/go.sum index 94a24de..d3296ea 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cdr.dev/slog v1.6.2-0.20250703074222-9df5e0a6c145 h1:Mk4axSLxKw3hjkf3PffBLQYta7nPVIWObuKCPDWgQLc= cdr.dev/slog v1.6.2-0.20250703074222-9df5e0a6c145/go.mod h1:NaoTA7KwopCrnaSb0JXTC0PTp/O/Y83Lndnq0OEV3ZQ= +cdr.dev/slog/v3 v3.0.0-rc1 h1:EN7Zim6GvTpAeHQjI0ERDEfqKbTyXRvgH4UhlzLpvWM= +cdr.dev/slog/v3 v3.0.0-rc1/go.mod h1:iO/OALX1VxlI03mkodCGdVP7pXzd2bRMvu3ePvlJ9ak= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= @@ -230,8 +232,8 @@ github.com/coder/quartz v0.3.0 h1:bUoSEJ77NBfKtUqv6CPSC0AS8dsjqAqqAv7bN02m1mg= github.com/coder/quartz v0.3.0/go.mod h1:BgE7DOj/8NfvRgvKw0jPLDQH/2Lya2kxcTaNJ8X0rZk= github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc= github.com/coder/retry v1.5.1/go.mod h1:blHMk9vs6LkoRT9ZHyuZo360cufXEhrxqvEzeMtRGoY= -github.com/coder/serpent v0.12.0 h1:fUu3qVjeRvVy3DB/C2EFFvOctm+f2HKyckyfA86O63Q= -github.com/coder/serpent v0.12.0/go.mod h1:mPEpD8Cq106E0glBs5ROAAGoALLtD5HAAMVZmjf4zO0= +github.com/coder/serpent v0.13.0 h1:6EoWjpEypkb8cS6i0eCF4qoAv9vrEVaX26RW+3FMMvo= +github.com/coder/serpent v0.13.0/go.mod h1:7OIvFBYMd+OqarMy5einBl8AtRr8LliopVU7pyrwucY= github.com/coder/tailscale v1.1.1-0.20250829055706-6eafe0f9199e h1:9RKGKzGLHtTvVBQublzDGtCtal3cXP13diCHoAIGPeI= github.com/coder/tailscale v1.1.1-0.20250829055706-6eafe0f9199e/go.mod h1:jU9T1vEs+DOs8NtGp1F2PT0/TOGVwtg/JCCKYRgvMOs= github.com/coder/terraform-provider-coder/v2 v2.13.1 h1:dtPaJUvueFm+XwBPUMWQCc5Z1QUQBW4B4RNyzX4h4y8= @@ -244,7 +246,6 @@ github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -488,8 +489,6 @@ github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJ github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/illarion/gonotify v1.0.1 h1:F1d+0Fgbq/sDWjj/r66ekjDG+IDeecQKUFH4wNwsoio= github.com/illarion/gonotify v1.0.1/go.mod h1:zt5pmDofZpU1f8aqlK0+95eQhoEAn/d4G4B/FjVW4jE= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= @@ -680,7 +679,6 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc= @@ -698,9 +696,6 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= -github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= -github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= diff --git a/main.go b/main.go index 4139a98..3dfa288 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" - "github.com/spf13/cobra" + "github.com/coder/serpent" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -17,13 +17,13 @@ import ( func main() { cmd := root() - err := cmd.Execute() + err := cmd.Invoke().WithOS().Run() if err != nil { os.Exit(1) } } -func root() *cobra.Command { +func root() *serpent.Command { var ( coderURL string fieldSelector string @@ -31,10 +31,50 @@ func root() *cobra.Command { namespacesStr string labelSelector string ) - cmd := &cobra.Command{ + cmd := &serpent.Command{ Use: "coder-logstream-kube", Short: "Stream Kubernetes Pod events to the Coder startup logs.", - RunE: func(cmd *cobra.Command, _ []string) error { + Options: serpent.OptionSet{ + { + Name: "coder-url", + Flag: "coder-url", + FlagShorthand: "u", + Env: "CODER_URL", + Value: serpent.StringOf(&coderURL), + Description: "URL of the Coder instance.", + }, + { + Name: "kubeconfig", + Flag: "kubeconfig", + FlagShorthand: "k", + Default: "~/.kube/config", + Value: serpent.StringOf(&kubeConfig), + Description: "Path to the kubeconfig file.", + }, + { + Name: "namespaces", + Flag: "namespaces", + FlagShorthand: "n", + Env: "CODER_NAMESPACES", + Value: serpent.StringOf(&namespacesStr), + Description: "List of namespaces to use when listing pods.", + }, + { + Name: "field-selector", + Flag: "field-selector", + FlagShorthand: "f", + Value: serpent.StringOf(&fieldSelector), + Description: "Field selector to use when listing pods.", + }, + { + Name: "label-selector", + Flag: "label-selector", + FlagShorthand: "l", + Value: serpent.StringOf(&labelSelector), + Description: "Label selector to use when listing pods.", + }, + }, + Handler: func(inv *serpent.Invocation) error { if coderURL == "" { return fmt.Errorf("--coder-url is required") } @@ -75,13 +115,13 @@ func root() *cobra.Command { } } - reporter, err := newPodEventLogger(cmd.Context(), podEventLoggerOptions{ + reporter, err := newPodEventLogger(inv.Context(), podEventLoggerOptions{ coderURL: parsedURL, client: client, namespaces: namespaces, fieldSelector: fieldSelector, labelSelector: labelSelector, - logger: slog.Make(sloghuman.Sink(cmd.ErrOrStderr())).Leveled(slog.LevelDebug), + logger: slog.Make(sloghuman.Sink(inv.Stderr)).Leveled(slog.LevelDebug), maxRetries: 15, // 15 retries is the default max retries for a log send failure. }) if err != nil { @@ -93,16 +133,11 @@ func root() *cobra.Command { select { case err := <-reporter.errChan: return fmt.Errorf("pod event reporter: %w", err) - case <-cmd.Context().Done(): + case <-inv.Context().Done(): } return nil }, } - cmd.Flags().StringVarP(&coderURL, "coder-url", "u", os.Getenv("CODER_URL"), "URL of the Coder instance") - cmd.Flags().StringVarP(&kubeConfig, "kubeconfig", "k", "~/.kube/config", "Path to the kubeconfig file") - cmd.Flags().StringVarP(&namespacesStr, "namespaces", "n", os.Getenv("CODER_NAMESPACES"), "List of namespaces to use when listing pods") - cmd.Flags().StringVarP(&fieldSelector, "field-selector", "f", "", "Field selector to use when listing pods") - cmd.Flags().StringVarP(&labelSelector, "label-selector", "l", "", "Label selector to use when listing pods") return cmd }