Skip to content

Commit

Permalink
feat(cmd/get): basic get command
Browse files Browse the repository at this point in the history
Signed-off-by: Lorenzo Fontana <lo@linux.com>
  • Loading branch information
fntlnz committed Nov 22, 2018
1 parent dea645f commit 827c417
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 28 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Some of them will not yet work because we don't attach with a TTY already, sorry
To consider this project (ready) the goals are:

- [x] basic program run and attach
- [ ] list command to list running traces - command: `kubectl trace ls`
- [x] list command to list running traces - command: `kubectl trace get`
- [x] delete running traces
- [ ] run without attach
- [ ] attach command to attach only - command: `kubectl trace attach <program>`
Expand Down
17 changes: 9 additions & 8 deletions cmd/kubectl-trace/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
)

var deleteCmd = &cobra.Command{
Use: "delete TRACEID",
Use: "delete NAME",
Short: "Delete a trace execution from your system",
Long: `Delete all the running pods that are collecting your trace data using bpftrace for a given TRACEID
Long: `Delete all the running pods that are collecting your trace data using bpftrace for a given NAME
Example:
# Delete a specific trace
kubectl trace delete 656ee75a-ee3c-11e8-9e7a-8c164500a77e
kubectl trace delete kubectl-trace-d5314890-ee4f-11e8-9684-8c164500a77e-sm4t2<Paste>
Limitations:
This command does not implement yet a way to bulk delete traces.
Expand All @@ -29,9 +29,9 @@ func delete(cmd *cobra.Command, args []string) {
defer log.Sync()

if len(args) == 0 {
log.Fatal("TRACEID not provided")
log.Fatal("NAME not provided")
}
uuid := args[0]
name := args[0]

kubeconfig := viper.GetString("kubeconfig")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
Expand All @@ -45,18 +45,19 @@ func delete(cmd *cobra.Command, args []string) {
log.Fatal("cannot create kubernetes config from provider KUBECONFIG", zap.Error(err))
}

namespace := viper.GetString("namespace")
jobsClient := clientset.BatchV1().Jobs(namespace)

tc := &tracejob.TraceJobClient{
JobClient: jobsClient,
ConfigClient: clientset.CoreV1().ConfigMaps(namespace),
}

tj := tracejob.TraceJob{
ID: uuid,
tf := tracejob.TraceJobFilter{
Name: &name,
}

err = tc.DeleteJob(tj)
err = tc.DeleteJob(tf)

if err != nil {
log.Fatal("error deleting trace execution from cluster", zap.Error(err))
Expand Down
103 changes: 103 additions & 0 deletions cmd/kubectl-trace/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package main

import (
"fmt"
"os"

"text/tabwriter"

"github.com/fntlnz/kubectl-trace/pkg/tracejob"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

var getCmd = &cobra.Command{
Use: "get [TRACEID] [-n NAMESPACE]",
Short: "Get all the running traces in a kubernetes cluster",
Long: `Get all the running traces in a kubernetes cluster
Examples:
# Get all traces in a namespace
kubectl trace get -n mynamespace
# Get only a specific trace
kubectl trace get 656ee75a-ee3c-11e8-9e7a-8c164500a77e
# Get only a specific trace in a specific namespace
kubectl trace get 656ee75a-ee3c-11e8-9e7a-8c164500a77e -n mynamespace
Limitations:
- Currently work only with a single namespace at time
- It does not contain yet status and age for the trace
`,
Run: get,
}

func get(cmd *cobra.Command, args []string) {
log, _ := zap.NewProduction()
defer log.Sync()

kubeconfig := viper.GetString("kubeconfig")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)

if err != nil {
log.Fatal("cannot create kubernetes client from provider KUBECONFIG", zap.Error(err))
}

var uuid *string
if len(args) > 0 {
uuid = &args[0]
}

namespace := viper.GetString("namespace")

clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal("cannot create kubernetes config from provider KUBECONFIG", zap.Error(err))
}

jobsClient := clientset.BatchV1().Jobs(namespace)

tc := &tracejob.TraceJobClient{
JobClient: jobsClient,
ConfigClient: clientset.CoreV1().ConfigMaps(namespace),
}

tf := tracejob.TraceJobFilter{
ID: uuid,
}

jobs, err := tc.GetJob(tf)

if err != nil {
log.Fatal("error getting jobs with provided filter", zap.Error(err), zap.Any("filter", tf))
}

jobsTablePrint(jobs)

}

// TODO(fntlnz): This needs better printing, perhaps we could use the humanreadable table from k8s itself
// to be consistent with the main project.
func jobsTablePrint(jobs []tracejob.TraceJob) {
format := "%s\t%s\t%s\t%s\t%s\t"
if len(jobs) == 0 {
fmt.Println("No resources found.")
return
}
// initialize tabwriter
w := new(tabwriter.Writer)
// minwidth, tabwidth, padding, padchar, flags
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
defer w.Flush()

// TODO(fntlnz): Do the status and age fields, we don't have a way to get them now, so reporting
// them as missing.
fmt.Fprintf(w, format, "NAMESPACE", "NAME", "STATUS", "AGE", "HOSTNAME")
for _, j := range jobs {
fmt.Fprintf(w, "\n"+format, j.Namespace, j.Name, "<missing>", "<missing>", j.Hostname)
}
}
16 changes: 6 additions & 10 deletions cmd/kubectl-trace/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import (
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
apiv1 "k8s.io/api/core/v1"
//"k8s.io/cli-runtime/pkg/genericclioptions"
)

var cfgFile string

//var parentConfigFlags genericclioptions.ConfigFlags

var rootCmd = &cobra.Command{
Use: "trace",
Short: "Execute and manage bpftrace programs on your kubernetes cluster",
Expand All @@ -29,21 +28,18 @@ func Execute() {
func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kubectl-trace.yaml)")

// TODO(leodido): figure out how to use the flag from the main kubectl
// instead of having to recreate them like below
//parentConfigFlags = genericclioptions.ConfigFlags{}
//parentConfigFlags.AddFlags(rootCmd.PersistentFlags())

rootCmd.PersistentFlags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
viper.BindPFlag("kubeconfig", rootCmd.PersistentFlags().Lookup("kubeconfig"))
viper.BindEnv("kubeconfig", "KUBECONFIG")

rootCmd.PersistentFlags().StringP("namespace", "n", apiv1.NamespaceDefault, "If present, the namespace scope for this CLI request")
viper.BindPFlag("namespace", rootCmd.PersistentFlags().Lookup("namespace"))

rootCmd.AddCommand(runCmd)
rootCmd.AddCommand(deleteCmd)
rootCmd.AddCommand(getCmd)
}

// initConfig reads in config file and ENV variables if set.
Expand Down
11 changes: 8 additions & 3 deletions cmd/kubectl-trace/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/util/uuid"

apiv1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
Expand All @@ -29,18 +28,22 @@ Examples:
# Execute a program from file on a specific node
kubectl trace run kubernetes-node-emt8.c.myproject.internal -f read.bt
Limitations:
1. Right now this command lets you run bpftrace commands only on a specific node in your cluster,
the plan is to have this working for a node, a pod, a deployment, a statefulset.
2. Since there's no TTY attach (yet) it is not possible to run bpftrace commands that need an input
from the user in order to complete, like histograms, working on this is a priority for this project.
`,
Run: run,
}

var program string
var programfile string
var namespace string

func init() {
runCmd.Flags().StringVarP(&program, "program-literal", "e", "", "Literal string containing a bpftrace program")
runCmd.Flags().StringVarP(&programfile, "program-file", "f", "", "File containing a bpftrace program")
runCmd.Flags().StringVarP(&namespace, "namespace", "n", apiv1.NamespaceDefault, "Name of the node where to do the trace")
}

func run(cmd *cobra.Command, args []string) {
Expand All @@ -63,6 +66,8 @@ func run(cmd *cobra.Command, args []string) {
}
node := args[0]

namespace := viper.GetString("namespace")

ctx := context.Background()
ctx = signals.WithStandardSignals(ctx)

Expand Down
Loading

0 comments on commit 827c417

Please sign in to comment.