Add mcp dns and mcp node routes commands
mcp dns queries MCNS via an agent to list all zones and DNS records. mcp node routes queries mc-proxy on each node for listener/route status, matching the mcproxyctl status output format. New agent RPCs: ListDNSRecords, ListProxyRoutes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
87
cmd/mcp/dns.go
Normal file
87
cmd/mcp/dns.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
mcpv1 "git.wntrmute.dev/mc/mcp/gen/mcp/v1"
|
||||
"git.wntrmute.dev/mc/mcp/internal/config"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func dnsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "dns",
|
||||
Short: "List all DNS zones and records from MCNS",
|
||||
RunE: runDNS,
|
||||
}
|
||||
}
|
||||
|
||||
func runDNS(_ *cobra.Command, _ []string) error {
|
||||
cfg, err := config.LoadCLIConfig(cfgPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load config: %w", err)
|
||||
}
|
||||
|
||||
// DNS is centralized — query the first reachable agent.
|
||||
resp, nodeName, err := queryDNS(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.GetZones()) == 0 {
|
||||
fmt.Println("no DNS zones configured")
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = nodeName
|
||||
for i, zone := range resp.GetZones() {
|
||||
if i > 0 {
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Printf("ZONE: %s\n", zone.GetName())
|
||||
|
||||
if len(zone.GetRecords()) == 0 {
|
||||
fmt.Println(" (no records)")
|
||||
continue
|
||||
}
|
||||
|
||||
w := newTable()
|
||||
_, _ = fmt.Fprintln(w, " NAME\tTYPE\tVALUE\tTTL")
|
||||
for _, r := range zone.GetRecords() {
|
||||
_, _ = fmt.Fprintf(w, " %s\t%s\t%s\t%d\n",
|
||||
r.GetName(), r.GetType(), r.GetValue(), r.GetTtl())
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// queryDNS tries each configured agent and returns the first successful
|
||||
// DNS listing. DNS is centralized so any agent with MCNS configured works.
|
||||
func queryDNS(cfg *config.CLIConfig) (*mcpv1.ListDNSRecordsResponse, string, error) {
|
||||
for _, node := range cfg.Nodes {
|
||||
client, conn, err := dialAgent(node.Address, cfg)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "warning: %s: %v\n", node.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := client.ListDNSRecords(ctx, &mcpv1.ListDNSRecordsRequest{})
|
||||
cancel()
|
||||
_ = conn.Close()
|
||||
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "warning: %s: list DNS: %v\n", node.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
return resp, node.Name, nil
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("no reachable agent with DNS configured")
|
||||
}
|
||||
@@ -52,6 +52,7 @@ func main() {
|
||||
root.AddCommand(purgeCmd())
|
||||
root.AddCommand(logsCmd())
|
||||
root.AddCommand(editCmd())
|
||||
root.AddCommand(dnsCmd())
|
||||
|
||||
if err := root.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
@@ -40,10 +40,62 @@ func nodeCmd() *cobra.Command {
|
||||
RunE: runNodeRemove,
|
||||
}
|
||||
|
||||
cmd.AddCommand(list, add, remove)
|
||||
routes := &cobra.Command{
|
||||
Use: "routes",
|
||||
Short: "List mc-proxy routes on all nodes",
|
||||
RunE: runNodeRoutes,
|
||||
}
|
||||
|
||||
cmd.AddCommand(list, add, remove, routes)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runNodeRoutes(_ *cobra.Command, _ []string) error {
|
||||
first := true
|
||||
return forEachNode(func(node config.NodeConfig, client mcpv1.McpAgentServiceClient) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
resp, err := client.ListProxyRoutes(ctx, &mcpv1.ListProxyRoutesRequest{})
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "warning: %s: list routes: %v\n", node.Name, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !first {
|
||||
fmt.Println()
|
||||
}
|
||||
first = false
|
||||
|
||||
fmt.Printf("NODE: %s\n", node.Name)
|
||||
fmt.Printf("mc-proxy %s\n", resp.GetVersion())
|
||||
if resp.GetStartedAt() != nil {
|
||||
uptime := time.Since(resp.GetStartedAt().AsTime()).Truncate(time.Second)
|
||||
fmt.Printf("uptime: %s\n", uptime)
|
||||
}
|
||||
fmt.Printf("connections: %d\n", resp.GetTotalConnections())
|
||||
fmt.Println()
|
||||
|
||||
for _, ls := range resp.GetListeners() {
|
||||
fmt.Printf(" %s routes=%d active=%d\n",
|
||||
ls.GetAddr(), ls.GetRouteCount(), ls.GetActiveConnections())
|
||||
for _, r := range ls.GetRoutes() {
|
||||
mode := r.GetMode()
|
||||
if mode == "" {
|
||||
mode = "l4"
|
||||
}
|
||||
extra := ""
|
||||
if r.GetBackendTls() {
|
||||
extra = " (re-encrypt)"
|
||||
}
|
||||
fmt.Printf(" %s %s → %s%s\n", mode, r.GetHostname(), r.GetBackend(), extra)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func runNodeList(_ *cobra.Command, _ []string) error {
|
||||
cfg, err := config.LoadCLIConfig(cfgPath)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user