diff --git a/cmd/dashboard.go b/cmd/dashboard.go index 8832502e..d0661d85 100644 --- a/cmd/dashboard.go +++ b/cmd/dashboard.go @@ -65,6 +65,9 @@ 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 @@ -99,6 +102,12 @@ dapr dashboard -k -p 0 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 { diff --git a/pkg/standalone/dashboard.go b/pkg/standalone/dashboard.go index 51b9a104..46c7a69e 100644 --- a/pkg/standalone/dashboard.go +++ b/pkg/standalone/dashboard.go @@ -18,10 +18,19 @@ import ( "os/exec" "path/filepath" "strconv" + + "github.com/phayes/freeport" ) // NewDashboardCmd creates the command to run dashboard. func NewDashboardCmd(inputInstallPath string, port int) (*exec.Cmd, error) { + if port == 0 { + freePort, err := freeport.GetFreePort() + if err != nil { + return nil, err + } + port = freePort + } dashboardPath, err := lookupBinaryFilePath(inputInstallPath, "dashboard") if err != nil { return nil, err diff --git a/pkg/standalone/dashboard_test.go b/pkg/standalone/dashboard_test.go index 9c4228bc..0913477d 100644 --- a/pkg/standalone/dashboard_test.go +++ b/pkg/standalone/dashboard_test.go @@ -28,4 +28,13 @@ func TestDashboardRun(t *testing.T) { assert.Equal(t, cmd.Args[1], "--port") assert.Equal(t, cmd.Args[2], "9090") }) + + t.Run("start dashboard on random free port", func(t *testing.T) { + cmd, err := NewDashboardCmd("", 0) + + assert.NoError(t, err) + assert.Contains(t, cmd.Args[0], "dashboard") + assert.Equal(t, cmd.Args[1], "--port") + assert.NotEqual(t, cmd.Args[2], "0") + }) } diff --git a/utils/utils.go b/utils/utils.go index f1749dae..8d612629 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -266,6 +266,16 @@ func IsAddressLegal(address string) bool { return isLegal } +// CheckIfPortAvailable returns an error if the port is not available else returns nil. +func CheckIfPortAvailable(port int) error { + ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + return err + } + ln.Close() + return nil +} + // GetEnv get value from environment variable. func GetEnv(envName string, defaultValue string) string { if val, ok := os.LookupEnv(envName); ok {