diff --git a/pkg/cmd/load.go b/pkg/cmd/load.go new file mode 100644 index 0000000..f16ab8b --- /dev/null +++ b/pkg/cmd/load.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "context" + "fmt" + "net/http" + "os" + + "github.com/gianarb/kube-profefe/pkg/profefe" + "github.com/google/pprof/profile" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +func NewLoadCmd() *cobra.Command { + var serviceName string + flags := pflag.NewFlagSet("load", pflag.ExitOnError) + cmd := &cobra.Command{ + Use: "load", + Short: "Load a profile you have locally to profefe", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return fmt.Errorf("You have to specify at least one profile as argument") + } + + pClient := profefe.NewClient(profefe.Config{ + HostPort: ProfefeHostPort, + }, http.Client{}) + + for _, path := range args { + file, err := os.Open(path) + if err != nil { + return fmt.Errorf("Error (%s): %s", path, err) + } + p, err := profile.Parse(file) + if err != nil { + return fmt.Errorf("Error (%s): %s", path, err) + } + + profefeType := profefe.NewProfileTypeFromString(p.PeriodType.Type) + if profefeType == profefe.UnknownProfile { + return fmt.Errorf("Error (%s) Unknown profile type it can not be sent to profefe. Skip this profile", path) + } + + req := profefe.SavePprofRequest{ + Profile: p, + Service: serviceName, + InstanceID: func() string { + h, err := os.Hostname() + if err != nil { + return "local" + } + return h + }(), + Type: profefeType, + } + saved, err := pClient.SavePprof(context.Background(), req) + if err != nil { + return fmt.Errorf("Error (%s): %s", err, path) + } else { + println(fmt.Sprintf("Profile (%s) stored in profefe: %s/api/0/profiles/%s", path, ProfefeHostPort, saved.Body.ID)) + } + } + return nil + }, + } + flags.StringVar(&ProfefeHostPort, "profefe-hostport", "http://localhost:10100", `where profefe is located`) + flags.StringVar(&serviceName, "service", "", `The service name`) + cmd.Flags().AddFlagSet(flags) + return cmd +} diff --git a/pkg/cmd/load_test.go b/pkg/cmd/load_test.go new file mode 100644 index 0000000..66775da --- /dev/null +++ b/pkg/cmd/load_test.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "context" + "fmt" + "testing" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +func TestLoadProfileTest(t *testing.T) { + ctx := context.Background() + req := testcontainers.ContainerRequest{ + Image: "profefe/profefe:git-10551f2", + ExposedPorts: []string{"10100/tcp"}, + WaitingFor: wait.ForLog("server is running"), + } + nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Error(err) + } + defer nginxC.Terminate(ctx) + ip, err := nginxC.Host(ctx) + if err != nil { + t.Error(err) + } + port, err := nginxC.MappedPort(ctx, "10100") + if err != nil { + t.Error(err) + } + + cmd := NewLoadCmd() + cmd.SetArgs([]string{ + "--profefe-hostport", + fmt.Sprintf("http://%s:%d", ip, port.Int()), + "--service", + "test", + "../../test/pprof.profefe.samples.cpu.001.pb.gz", + }) + err = cmd.Execute() + if err != nil { + t.Fatal(err) + } +} diff --git a/pkg/cmd/profefe.go b/pkg/cmd/profefe.go index 1c231d1..2bd7698 100644 --- a/pkg/cmd/profefe.go +++ b/pkg/cmd/profefe.go @@ -43,6 +43,7 @@ func NewProfefeCmd(logger *zap.Logger, streams genericclioptions.IOStreams) *cob captureCmd.Flags().AddFlagSet(flagsCapture) rootCmd.AddCommand(captureCmd) rootCmd.AddCommand(NewGetCmd()) + rootCmd.AddCommand(NewLoadCmd()) return rootCmd }