extension: add jaeger dashboard sub-command (#5291)

This branch adds `jaeger dashboard` sub-command which is used
to view the jaeger dashboard. This follows the same logic/pattern
of that of `linkerd-dashboard`. Also, provides the same flags.

Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>
This commit is contained in:
Tarun Pothulapati 2020-12-02 00:26:18 +05:30 committed by GitHub
parent 83241fef20
commit f5f5da0e7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 1 deletions

127
jaeger/cmd/dashboard.go Normal file
View File

@ -0,0 +1,127 @@
package cmd
import (
"fmt"
"os"
"os/signal"
"time"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/pkg/browser"
"github.com/spf13/cobra"
)
const (
// jaegerDeployment is the name of the jaeger deployment
jaegerDeployment = "jaeger"
// webPort is the http port of the jaeger deployment
webPort = 16686
// defaultHost is the default host used for port-forwarding via `jaeger dashboard`
defaultHost = "localhost"
// defaultPort is for port-forwarding via `jaeger dashboard`
defaultPort = 16686
)
// dashboardOptions holds values for command line flags that apply to the dashboard
// command.
type dashboardOptions struct {
host string
port int
showURL bool
wait time.Duration
}
// newDashboardOptions initializes dashboard options with default
// values for host, port. Also, set max wait time duration for
// 300 seconds for the dashboard to become available
//
// These options may be overridden on the CLI at run-time
func newDashboardOptions() *dashboardOptions {
return &dashboardOptions{
host: defaultHost,
port: defaultPort,
wait: 300 * time.Second,
}
}
// newCmdDashboard creates a new cobra command `dashboard` which contains commands for visualizing jaeger extension's dashboards.
// After validating flag values, it will use the Kubernetes API to portforward requests to the Jaeger deployment
// until the process gets killed/canceled
func newCmdDashboard() *cobra.Command {
options := newDashboardOptions()
cmd := &cobra.Command{
Use: "dashboard [flags]",
Short: "Open the Jaeger extension dashboard in a web browser",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
if options.port < 0 {
return fmt.Errorf("port must be greater than or equal to zero, was %d", options.port)
}
// TODO: Add a jaeger check here
k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
if err != nil {
return err
}
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
defer signal.Stop(signals)
portforward, err := k8s.NewPortForward(
cmd.Context(),
k8sAPI,
namespace,
jaegerDeployment,
options.host,
options.port,
webPort,
verbose,
)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize port-forward: %s\n", err)
os.Exit(1)
}
if err = portforward.Init(); err != nil {
// TODO: consider falling back to an ephemeral port if defaultPort is taken
fmt.Fprintf(os.Stderr, "Error running port-forward: %s\nCheck for `jaeger dashboard` running in other terminal sessions, or use the `--port` flag.\n", err)
os.Exit(1)
}
go func() {
<-signals
portforward.Stop()
}()
webURL := portforward.URLFor("")
fmt.Printf("Jaeger extension dashboard available at:\n%s\n", webURL)
if !options.showURL {
err = browser.OpenURL(webURL)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to open dashboard automatically")
fmt.Fprintf(os.Stderr, "Visit %s in your browser to view the dashboard\n", webURL)
}
}
<-portforward.GetStop()
return nil
},
}
// This is identical to what `kubectl proxy --help` reports, `--port 0` indicates a random port.
cmd.PersistentFlags().StringVar(&options.host, "address", options.host, "The address at which to serve requests")
cmd.PersistentFlags().IntVarP(&options.port, "port", "p", options.port, "The local port on which to serve requests (when set to 0, a random port will be used)")
cmd.PersistentFlags().BoolVar(&options.showURL, "show-url", options.showURL, "show only URL in the CLI, and do not open the browser")
cmd.PersistentFlags().DurationVar(&options.wait, "wait", options.wait, "Wait for dashboard to become available if it's not available when the command is run")
return cmd
}

View File

@ -10,11 +10,13 @@ import (
const (
defaultLinkerdNamespace = "linkerd"
defaultJaegerNamespace = "linkerd-jaeger"
)
var (
apiAddr string // An empty value means "use the Kubernetes configuration"
controlPlaneNamespace string
namespace string
kubeconfigPath string
kubeContext string
impersonate string
@ -48,7 +50,8 @@ func NewCmdJaeger() *cobra.Command {
},
}
jaegerCmd.PersistentFlags().StringVarP(&controlPlaneNamespace, "linkerd-namespace", "L", defaultLinkerdNamespace, "Namespace in which Linkerd is installed [$LINKERD_NAMESPACE]")
jaegerCmd.PersistentFlags().StringVarP(&controlPlaneNamespace, "linkerd-namespace", "L", defaultLinkerdNamespace, "Namespace in which Linkerd is installed")
jaegerCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", defaultJaegerNamespace, "Namespace in which Jaeger extension is installed")
jaegerCmd.PersistentFlags().StringVar(&kubeconfigPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests")
jaegerCmd.PersistentFlags().StringVar(&kubeContext, "context", "", "Name of the kubeconfig context to use")
jaegerCmd.PersistentFlags().StringVar(&impersonate, "as", "", "Username to impersonate for Kubernetes operations")
@ -56,6 +59,7 @@ func NewCmdJaeger() *cobra.Command {
jaegerCmd.PersistentFlags().StringVar(&apiAddr, "api-addr", "", "Override kubeconfig and communicate directly with the control plane at host:port (mostly for testing)")
jaegerCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Turn on debug logging")
jaegerCmd.AddCommand(newCmdInstall())
jaegerCmd.AddCommand(newCmdDashboard())
return jaegerCmd
}