mirror of https://github.com/dapr/cli.git
				
				
				
			
		
			
				
	
	
		
			226 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
Copyright 2021 The Dapr Authors
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package cmd
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"os"
 | 
						|
	"os/signal"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	"github.com/pkg/browser"
 | 
						|
	"github.com/spf13/cobra"
 | 
						|
 | 
						|
	"github.com/dapr/cli/pkg/kubernetes"
 | 
						|
	"github.com/dapr/cli/pkg/print"
 | 
						|
	"github.com/dapr/cli/pkg/standalone"
 | 
						|
	"github.com/dapr/cli/utils"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	// dashboardSvc is the name of the dashboard service running in cluster.
 | 
						|
	dashboardSvc = "dapr-dashboard"
 | 
						|
 | 
						|
	// defaultHost is the default host used for port forwarding for `dapr dashboard`.
 | 
						|
	defaultHost = "localhost"
 | 
						|
 | 
						|
	// defaultLocalPort is the default local port used for port forwarding for `dapr dashboard`.
 | 
						|
	defaultLocalPort = 8080
 | 
						|
 | 
						|
	// daprSystemNamespace is the namespace "dapr-system" (recommended Dapr install namespace).
 | 
						|
	daprSystemNamespace = "dapr-system"
 | 
						|
 | 
						|
	// defaultNamespace is the default namespace (dapr init -k installation).
 | 
						|
	defaultNamespace = "default"
 | 
						|
 | 
						|
	// remotePort is the port dapr dashboard pod is listening on.
 | 
						|
	remotePort = 8080
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	dashboardNamespace  string
 | 
						|
	dashboardHost       string
 | 
						|
	dashboardLocalPort  int
 | 
						|
	dashboardVersionCmd bool
 | 
						|
)
 | 
						|
 | 
						|
var DashboardCmd = &cobra.Command{
 | 
						|
	Use:   "dashboard",
 | 
						|
	Short: "Start Dapr dashboard. Supported platforms: Kubernetes and self-hosted",
 | 
						|
	Example: `
 | 
						|
# Start dashboard locally
 | 
						|
dapr dashboard
 | 
						|
 | 
						|
# Start dashboard locally in a specified port
 | 
						|
dapr dashboard -p 9999
 | 
						|
 | 
						|
# Start dashboard locally on a random port which is free.
 | 
						|
dapr dashboard -p 0
 | 
						|
 | 
						|
# Port forward to dashboard in Kubernetes
 | 
						|
dapr dashboard -k
 | 
						|
 | 
						|
# Port forward to dashboard in Kubernetes on all addresses in a specified port
 | 
						|
dapr dashboard -k -p 9999 -a 0.0.0.0
 | 
						|
 | 
						|
# Port forward to dashboard in Kubernetes using a port
 | 
						|
dapr dashboard -k -p 9999
 | 
						|
 | 
						|
# Port forward to dashboard in Kubernetes using a random port which is free.
 | 
						|
dapr dashboard -k -p 0
 | 
						|
`,
 | 
						|
	Run: func(cmd *cobra.Command, args []string) {
 | 
						|
		if dashboardVersionCmd {
 | 
						|
			dashboardVer, err := standalone.GetDashboardVersion(daprRuntimePath)
 | 
						|
			if err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
 | 
						|
			fmt.Println(dashboardVer)
 | 
						|
			os.Exit(0)
 | 
						|
		}
 | 
						|
 | 
						|
		if !utils.IsAddressLegal(dashboardHost) {
 | 
						|
			print.FailureStatusEvent(os.Stdout, "Invalid address: %s", dashboardHost)
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
 | 
						|
		if dashboardLocalPort < 0 {
 | 
						|
			print.FailureStatusEvent(os.Stderr, "Invalid port: %v", dashboardLocalPort)
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := utils.CheckIfPortAvailable(dashboardLocalPort); err != nil {
 | 
						|
			print.FailureStatusEvent(os.Stderr, "Please select a different port with %q flag: %s", "-p", err)
 | 
						|
			print.InfoStatusEvent(os.Stdout, "You can also use port 0 to select a random free port.")
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
 | 
						|
		if kubernetesMode {
 | 
						|
			config, client, err := kubernetes.GetKubeConfigClient()
 | 
						|
			if err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "Failed to initialize kubernetes client: %s", err.Error())
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
 | 
						|
			// search for dashboard service namespace in order:
 | 
						|
			// user-supplied namespace, dapr-system, default.
 | 
						|
			namespaces := []string{dashboardNamespace}
 | 
						|
			if dashboardNamespace != daprSystemNamespace {
 | 
						|
				namespaces = append(namespaces, daprSystemNamespace)
 | 
						|
			}
 | 
						|
			if dashboardNamespace != defaultNamespace {
 | 
						|
				namespaces = append(namespaces, defaultNamespace)
 | 
						|
			}
 | 
						|
 | 
						|
			foundNamespace := ""
 | 
						|
			for _, namespace := range namespaces {
 | 
						|
				ok, _ := kubernetes.CheckPodExists(client, namespace, nil, dashboardSvc)
 | 
						|
				if ok {
 | 
						|
					foundNamespace = namespace
 | 
						|
					break
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// if the service is not found, try to search all pods.
 | 
						|
			if foundNamespace == "" {
 | 
						|
				ok, nspace := kubernetes.CheckPodExists(client, "", nil, dashboardSvc)
 | 
						|
 | 
						|
				// if the service is found, tell the user to try with the found namespace.
 | 
						|
				// if the service is still not found, throw an error.
 | 
						|
				if ok {
 | 
						|
					print.InfoStatusEvent(os.Stdout, "Dapr dashboard found in namespace: %s. Run dapr dashboard -k -n %s to use this namespace.", nspace, nspace)
 | 
						|
				} else {
 | 
						|
					print.FailureStatusEvent(os.Stderr, "Failed to find Dapr dashboard in cluster. Check status of dapr dashboard in the cluster.")
 | 
						|
				}
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
 | 
						|
			// manage termination of port forwarding connection on interrupt.
 | 
						|
			signals := make(chan os.Signal, 1)
 | 
						|
			signal.Notify(signals, os.Interrupt)
 | 
						|
			defer signal.Stop(signals)
 | 
						|
 | 
						|
			portForward, err := kubernetes.NewPortForward(
 | 
						|
				config,
 | 
						|
				foundNamespace,
 | 
						|
				dashboardSvc,
 | 
						|
				dashboardHost,
 | 
						|
				dashboardLocalPort,
 | 
						|
				remotePort,
 | 
						|
				false,
 | 
						|
			)
 | 
						|
			if err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "%s\n", err)
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
 | 
						|
			// initialize port forwarding.
 | 
						|
			if err = portForward.Init(); err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "Error in port forwarding: %s\nCheck for `dapr dashboard` running in other terminal sessions, or use the `--port` flag to use a different port.\n", err)
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
 | 
						|
			// block until interrupt signal is received.
 | 
						|
			go func() {
 | 
						|
				<-signals
 | 
						|
				portForward.Stop()
 | 
						|
			}()
 | 
						|
 | 
						|
			// url for dashboard after port forwarding.
 | 
						|
			webURL := fmt.Sprintf("http://%s", net.JoinHostPort(dashboardHost, strconv.Itoa(portForward.LocalPort)))
 | 
						|
 | 
						|
			print.InfoStatusEvent(os.Stdout, "Dapr dashboard found in namespace:\t"+foundNamespace)
 | 
						|
			print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Dapr dashboard available at:\t%s\n", webURL))
 | 
						|
 | 
						|
			err = browser.OpenURL(webURL)
 | 
						|
			if err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "Failed to start Dapr dashboard in browser automatically")
 | 
						|
				print.FailureStatusEvent(os.Stderr, fmt.Sprintf("Visit %s in your browser to view the dashboard", webURL))
 | 
						|
			}
 | 
						|
 | 
						|
			<-portForward.GetStop()
 | 
						|
		} else {
 | 
						|
			// Standalone mode.
 | 
						|
			dashboardCmd, err := standalone.NewDashboardCmd(daprRuntimePath, dashboardLocalPort)
 | 
						|
			if err != nil {
 | 
						|
				print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install	directory: %v", err)
 | 
						|
			} else {
 | 
						|
				err = dashboardCmd.Run()
 | 
						|
				if err != nil {
 | 
						|
					print.FailureStatusEvent(os.Stderr, "Dapr dashboard failed to run: %v", err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	},
 | 
						|
	PostRun: func(cmd *cobra.Command, args []string) {
 | 
						|
		if kubernetesMode {
 | 
						|
			kubernetes.CheckForCertExpiry()
 | 
						|
		}
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
func init() {
 | 
						|
	DashboardCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Opens Dapr dashboard in local browser via local proxy to Kubernetes cluster")
 | 
						|
	DashboardCmd.Flags().BoolVarP(&dashboardVersionCmd, "version", "v", false, "Print the version for Dapr dashboard")
 | 
						|
	DashboardCmd.Flags().StringVarP(&dashboardHost, "address", "a", defaultHost, "Address to listen on. Only accepts IP address or localhost as a value")
 | 
						|
	DashboardCmd.Flags().IntVarP(&dashboardLocalPort, "port", "p", defaultLocalPort, "The local port on which to serve Dapr dashboard")
 | 
						|
	DashboardCmd.Flags().StringVarP(&dashboardNamespace, "namespace", "n", daprSystemNamespace, "The namespace where Dapr dashboard is running")
 | 
						|
	DashboardCmd.Flags().BoolP("help", "h", false, "Print this help message")
 | 
						|
 | 
						|
	RootCmd.AddCommand(DashboardCmd)
 | 
						|
}
 |