pkg/skoop/cmd/app.go (175 lines of code) (raw):

package cmd import ( "flag" "fmt" "os" "strings" "github.com/alibaba/kubeskoop/version" "github.com/alibaba/kubeskoop/pkg/skoop/context" "github.com/alibaba/kubeskoop/pkg/skoop/model" "github.com/alibaba/kubeskoop/pkg/skoop/provider" "github.com/alibaba/kubeskoop/pkg/skoop/ui" "github.com/spf13/cobra" cliflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/term" "k8s.io/klog/v2" ) func NewSkoopCmd() *cobra.Command { cmd := &cobra.Command{ Use: "skoop", Long: "Skoop is an one-shot kubernetes network diagnose tool.", PreRunE: func(_ *cobra.Command, _ []string) error { if context.SkoopContext.MiscConfig().Version { version.PrintVersion() os.Exit(0) } if err := context.SkoopContext.Validate(); err != nil { return err } if err := context.SkoopContext.BuildCluster(); err != nil { return err } return context.SkoopContext.BuildTask() }, RunE: func(_ *cobra.Command, _ []string) error { prvd, err := provider.GetProvider(context.SkoopContext.ClusterConfig().CloudProvider) if err != nil { klog.Fatalf("error get service provider: %v", err) } network, err := prvd.CreateNetwork(context.SkoopContext) if err != nil { klog.Fatalf("error create network: %v", err) } globalSuspicion, packetPath, err := network.Diagnose(context.SkoopContext, context.SkoopContext.TaskConfig().SourceEndpoint, context.SkoopContext.TaskConfig().DstEndpoint) if err != nil { //TODO error的情况下,如果已经有部分结果,应该将结果输出 klog.Fatalf("diagnose error: %v", err) } if context.SkoopContext.UIConfig().HTTP { klog.Fatalf("http server exited: %s", serveWebUI(globalSuspicion, packetPath)) } if context.SkoopContext.UIConfig().Format != "" { switch context.SkoopContext.UIConfig().Format { case "svg", "d2": err = saveGraphFile(packetPath) if err != nil { klog.Fatalf("save graph file error: %v", err) } case "json": err = saveJSONFile(globalSuspicion, packetPath) if err != nil { klog.Fatalf("save json file error: %v", err) } return nil } } else { fmt.Printf("Packet path:\n%+v\n", packetPath.Paths()) } suspicions := formatSuspicions(globalSuspicion, packetPath) if len(suspicions) != 0 { fmt.Printf("\n%s", suspicions) } return nil }, } fs := cmd.Flags() fss := cliflag.NamedFlagSets{} context.SkoopContext.BindNamedFlags(&fss) logFs := flag.NewFlagSet("", flag.ExitOnError) klog.InitFlags(logFs) logPfs := fss.FlagSet("Log") logPfs.AddGoFlagSet(logFs) for _, f := range fss.FlagSets { fs.AddFlagSet(f) } cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) cliflag.SetUsageAndHelpFunc(cmd, fss, cols) return cmd } func saveGraphFile(p *model.PacketPath) error { g, err := ui.NewD2(p) if err != nil { return err } var data []byte switch context.SkoopContext.UIConfig().Format { case "svg": data, err = g.ToSvg() if err != nil { return err } case "d2": data, err = g.ToD2() if err != nil { return err } } fileName := context.SkoopContext.UIConfig().Output if fileName == "" { fileName = fmt.Sprintf("output.%s", context.SkoopContext.UIConfig().Format) } if fileName == "-" { // write to stdout _, err = os.Stdout.Write(data) if err != nil { return err } } else { err = os.WriteFile(fileName, data, 0666) if err != nil { return err } klog.V(0).Infof("File has been saved to %s.", fileName) } return nil } func saveJSONFile(globalSuspicions []model.Suspicion, p *model.PacketPath) error { formatter := ui.NewJSONFormatter(globalSuspicions, p) data, err := formatter.ToJSON() if err != nil { return err } fileName := context.SkoopContext.UIConfig().Output if fileName == "" { fileName = "output.json" } if fileName == "-" { // write to stdout _, err = os.Stdout.Write(data) if err != nil { return err } } else { err = os.WriteFile(fileName, data, 0666) if err != nil { return err } klog.V(0).Infof("File has been saved to %s.", fileName) } return err } func serveWebUI(globalSuspicions []model.Suspicion, p *model.PacketPath) error { web, err := ui.NewWebUI(context.SkoopContext, globalSuspicions, p, context.SkoopContext.UIConfig().HTTPAddress) if err != nil { return err } return web.Serve() } func formatSuspicions(globalSuspicion []model.Suspicion, packetPath *model.PacketPath) string { var builder strings.Builder if len(globalSuspicion) > 0 { builder.WriteString("Suspicions on cluster:\n") for _, s := range globalSuspicion { builder.WriteString(fmt.Sprintf("[%s] %s\n", s.Level, s.Message)) } } nodes := packetPath.Nodes() for _, n := range nodes { suspicions := n.GetSuspicions() if len(suspicions) > 0 { builder.WriteString(fmt.Sprintf("Suspicions on node %q\n", n.GetID())) for _, s := range suspicions { builder.WriteString(fmt.Sprintf("[%s] %s\n", s.Level, s.Message)) } builder.WriteString("\n") } } return builder.String() }