Skip to content

Commit 53dff40

Browse files
mikeb26shubham1172
andauthored
Support environments with broken $HOME (#1057)
* Support environments with broken $HOME Currently in standalone mode dapr cli will install the dapr runtime binaries into $HOME/.dapr. However, in some environments $HOME is readonly or os.UserHomeDir() can fail (e.g. AWS Lambda). To support dapr in these environments this change does 2 things: 1. Allows the user to set DAPR_PATH environment variable to indicate the location of the dapr runtime binaries. 2. Allows the user to optionally specify --dapr-path cli flag to indicate the location of the dapr runtime binaries. When both DAPR_PATH environment variable and --dapr-path CLI flag are present, the cli flag has higher precedence. When neither DAPR_PATH nor the --dapr-path CLI flag are present, we fallback to existing behavior of defaulting to $HOME/.dapr. Signed-off-by: Mike Brown <[email protected]> * Address comments Signed-off-by: Shubham Sharma <[email protected]> * Address comments Signed-off-by: Shubham Sharma <[email protected]> * Address comments Signed-off-by: Shubham Sharma <[email protected]> * Fix unit test Signed-off-by: Shubham Sharma <[email protected]> * Fix e2e test Signed-off-by: Shubham Sharma <[email protected]> * Fix lint Signed-off-by: Shubham Sharma <[email protected]> Signed-off-by: Mike Brown <[email protected]> Signed-off-by: Shubham Sharma <[email protected]> Co-authored-by: Shubham Sharma <[email protected]>
1 parent e253b91 commit 53dff40

File tree

20 files changed

+551
-88
lines changed

20 files changed

+551
-88
lines changed

cmd/buildinfo.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ package cmd
1515

1616
import (
1717
"fmt"
18+
"os"
1819

1920
"github.com/spf13/cobra"
2021

22+
"github.com/dapr/cli/pkg/print"
2123
"github.com/dapr/cli/pkg/standalone"
2224
)
2325

@@ -29,7 +31,12 @@ var BuildInfoCmd = &cobra.Command{
2931
dapr build-info
3032
`,
3133
Run: func(cmd *cobra.Command, args []string) {
32-
fmt.Println(standalone.GetBuildInfo(RootCmd.Version))
34+
out, err := standalone.GetBuildInfo(daprPath, RootCmd.Version)
35+
if err != nil {
36+
print.FailureStatusEvent(os.Stderr, "Error getting build info: %s", err.Error())
37+
os.Exit(1)
38+
}
39+
fmt.Println(out)
3340
},
3441
}
3542

cmd/dapr.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,20 @@ type daprVersion struct {
4949
var (
5050
daprVer daprVersion
5151
logAsJSON bool
52+
daprPath string
5253
)
5354

5455
// Execute adds all child commands to the root command.
5556
func Execute(version, apiVersion string) {
5657
RootCmd.Version = version
5758
api.RuntimeAPIVersion = apiVersion
5859

60+
// err intentionally ignored since daprd may not yet be installed.
61+
runtimeVer, _ := standalone.GetRuntimeVersion(daprPath)
62+
5963
daprVer = daprVersion{
6064
CliVersion: version,
61-
RuntimeVersion: strings.ReplaceAll(standalone.GetRuntimeVersion(), "\n", ""),
65+
RuntimeVersion: strings.ReplaceAll(runtimeVer, "\n", ""),
6266
}
6367

6468
cobra.OnInitialize(initConfig)
@@ -87,5 +91,6 @@ func initConfig() {
8791
}
8892

8993
func init() {
94+
RootCmd.PersistentFlags().StringVarP(&daprPath, "dapr-path", "", "", "The path to the dapr installation directory")
9095
RootCmd.PersistentFlags().BoolVarP(&logAsJSON, "log-as-json", "", false, "Log output in JSON format")
9196
}

cmd/dashboard.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ dapr dashboard -k -p 0
7979
`,
8080
Run: func(cmd *cobra.Command, args []string) {
8181
if dashboardVersionCmd {
82-
fmt.Println(standalone.GetDashboardVersion())
82+
dashboardVer, err := standalone.GetDashboardVersion(daprPath)
83+
if err != nil {
84+
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
85+
os.Exit(1)
86+
}
87+
88+
fmt.Println(dashboardVer)
8389
os.Exit(0)
8490
}
8591

@@ -179,9 +185,14 @@ dapr dashboard -k -p 0
179185
<-portForward.GetStop()
180186
} else {
181187
// Standalone mode.
182-
err := standalone.NewDashboardCmd(dashboardLocalPort).Run()
188+
dashboardCmd, err := standalone.NewDashboardCmd(daprPath, dashboardLocalPort)
183189
if err != nil {
184-
print.FailureStatusEvent(os.Stderr, "Dapr dashboard not found. Is Dapr installed?")
190+
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
191+
} else {
192+
err = dashboardCmd.Run()
193+
if err != nil {
194+
print.FailureStatusEvent(os.Stderr, "Dapr dashboard failed to run: %v", err)
195+
}
185196
}
186197
}
187198
},
@@ -199,5 +210,6 @@ func init() {
199210
DashboardCmd.Flags().IntVarP(&dashboardLocalPort, "port", "p", defaultLocalPort, "The local port on which to serve Dapr dashboard")
200211
DashboardCmd.Flags().StringVarP(&dashboardNamespace, "namespace", "n", daprSystemNamespace, "The namespace where Dapr dashboard is running")
201212
DashboardCmd.Flags().BoolP("help", "h", false, "Print this help message")
213+
202214
RootCmd.AddCommand(DashboardCmd)
203215
}

cmd/init.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ dapr init --from-dir <path-to-directory>
8181
# Initialize dapr with a particular image variant. Allowed values: "mariner"
8282
dapr init --image-variant <variant>
8383
84+
# Initialize Dapr to non-default install directory (default is $HOME/.dapr)
85+
dapr init --dapr-path <path-to-install-directory>
86+
8487
# See more at: https://docs.dapr.io/getting-started/
8588
`,
8689
Run: func(cmd *cobra.Command, args []string) {
@@ -92,6 +95,11 @@ dapr init --image-variant <variant>
9295
imageRegistryURI := ""
9396
var err error
9497

98+
if len(strings.TrimSpace(daprPath)) != 0 {
99+
print.FailureStatusEvent(os.Stderr, "--dapr-path is only valid for self-hosted mode")
100+
os.Exit(1)
101+
}
102+
95103
if len(imageRegistryFlag) != 0 {
96104
warnForPrivateRegFeat()
97105
imageRegistryURI = imageRegistryFlag
@@ -137,11 +145,12 @@ dapr init --image-variant <variant>
137145
if len(imageRegistryURI) != 0 {
138146
warnForPrivateRegFeat()
139147
}
148+
140149
if !utils.IsValidContainerRuntime(containerRuntime) {
141150
print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.")
142151
os.Exit(1)
143152
}
144-
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant)
153+
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprPath)
145154
if err != nil {
146155
print.FailureStatusEvent(os.Stderr, err.Error())
147156
os.Exit(1)
@@ -168,6 +177,7 @@ func init() {
168177
if dashboardVersionEnv != "" {
169178
defaultDashboardVersion = dashboardVersionEnv
170179
}
180+
171181
InitCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Deploy Dapr to a Kubernetes cluster")
172182
InitCmd.Flags().BoolVarP(&wait, "wait", "", false, "Wait for Kubernetes initialization to complete")
173183
InitCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The wait timeout for the Kubernetes installation")
@@ -184,5 +194,6 @@ func init() {
184194
InitCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
185195
InitCmd.Flags().String("image-registry", "", "Custom/private docker image repository URL")
186196
InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman")
197+
187198
RootCmd.AddCommand(InitCmd)
188199
}

cmd/run.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ dapr run --app-id myapp
8484
8585
# Run a gRPC application written in Go (listening on port 3000)
8686
dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
87+
88+
# Run sidecar only specifying dapr runtime installation directory
89+
dapr run --app-id myapp --dapr-path /usr/local/dapr
8790
`,
8891
Args: cobra.MinimumNArgs(0),
8992
PreRun: func(cmd *cobra.Command, args []string) {
@@ -94,6 +97,22 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
9497
fmt.Println(print.WhiteBold("WARNING: no application command found."))
9598
}
9699

100+
daprDirPath, err := standalone.GetDaprPath(daprPath)
101+
if err != nil {
102+
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
103+
os.Exit(1)
104+
}
105+
106+
// Fallback to default config file if not specified.
107+
if configFile == "" {
108+
configFile = standalone.GetDaprConfigPath(daprDirPath)
109+
}
110+
111+
// Fallback to default components directory if not specified.
112+
if componentsPath == "" {
113+
componentsPath = standalone.GetDaprComponentsPath(daprDirPath)
114+
}
115+
97116
if unixDomainSocket != "" {
98117
// TODO(@daixiang0): add Windows support.
99118
if runtime.GOOS == "windows" {
@@ -134,6 +153,7 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
134153
AppHealthThreshold: appHealthThreshold,
135154
EnableAPILogging: enableAPILogging,
136155
InternalGRPCPort: internalGRPCPort,
156+
DaprPathCmdFlag: daprPath,
137157
APIListenAddresses: apiListenAddresses,
138158
})
139159
if err != nil {
@@ -368,7 +388,7 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
368388
func init() {
369389
RunCmd.Flags().IntVarP(&appPort, "app-port", "p", -1, "The port your application is listening on")
370390
RunCmd.Flags().StringVarP(&appID, "app-id", "a", "", "The id for your application, used for service discovery")
371-
RunCmd.Flags().StringVarP(&configFile, "config", "c", standalone.DefaultConfigFilePath(), "Dapr configuration file")
391+
RunCmd.Flags().StringVarP(&configFile, "config", "c", "", "Dapr configuration file")
372392
RunCmd.Flags().IntVarP(&port, "dapr-http-port", "H", -1, "The HTTP port for Dapr to listen on")
373393
RunCmd.Flags().IntVarP(&grpcPort, "dapr-grpc-port", "G", -1, "The gRPC port for Dapr to listen on")
374394
RunCmd.Flags().IntVarP(&internalGRPCPort, "dapr-internal-grpc-port", "I", -1, "The gRPC port for the Dapr internal API to listen on")
@@ -377,7 +397,7 @@ func init() {
377397
RunCmd.Flags().StringVarP(&logLevel, "log-level", "", "info", "The log verbosity. Valid values are: debug, info, warn, error, fatal, or panic")
378398
RunCmd.Flags().IntVarP(&maxConcurrency, "app-max-concurrency", "", -1, "The concurrency level of the application, otherwise is unlimited")
379399
RunCmd.Flags().StringVarP(&protocol, "app-protocol", "P", "http", "The protocol (gRPC or HTTP) Dapr uses to talk to the application")
380-
RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", standalone.DefaultComponentsDirPath(), "The path for components directory")
400+
RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", "", "The path for components directory")
381401
RunCmd.Flags().StringVarP(&resourcesPath, "resources-path", "", "", "The path for resources directory")
382402
// TODO: Remove below line once the flag is removed in the future releases.
383403
// By marking this as deprecated, the flag will be hidden from the help menu, but will continue to work. It will show a warning message when used.

cmd/uninstall.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package cmd
1616
import (
1717
"fmt"
1818
"os"
19+
"strings"
1920

2021
"github.com/spf13/cobra"
2122
"github.com/spf13/viper"
@@ -46,6 +47,9 @@ dapr uninstall --all
4647
4748
# Uninstall from Kubernetes
4849
dapr uninstall -k
50+
51+
# Uninstall Dapr from non-default install directory (default is $HOME/.dapr)
52+
dapr uninstall --dapr-path <path-to-install-directory>
4953
`,
5054
PreRun: func(cmd *cobra.Command, args []string) {
5155
viper.BindPFlag("network", cmd.Flags().Lookup("network"))
@@ -55,6 +59,11 @@ dapr uninstall -k
5559
var err error
5660

5761
if uninstallKubernetes {
62+
if len(strings.TrimSpace(daprPath)) != 0 {
63+
print.FailureStatusEvent(os.Stderr, "--dapr-path is only valid for self-hosted mode")
64+
os.Exit(1)
65+
}
66+
5867
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your cluster...")
5968
err = kubernetes.Uninstall(uninstallNamespace, uninstallAll, timeout)
6069
} else {
@@ -64,7 +73,7 @@ dapr uninstall -k
6473
}
6574
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...")
6675
dockerNetwork := viper.GetString("network")
67-
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime)
76+
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime, daprPath)
6877
}
6978

7079
if err != nil {

pkg/standalone/common.go

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,54 @@ const (
2626
defaultConfigFileName = "config.yaml"
2727
)
2828

29-
func defaultDaprDirPath() string {
30-
homeDir, _ := os.UserHomeDir()
31-
return path_filepath.Join(homeDir, defaultDaprDirName)
29+
// GetDaprPath returns the dapr installation path.
30+
// The order of precedence is:
31+
// 1. From --dapr-path command line flag
32+
// 2. From DAPR_PATH environment variable
33+
// 3. $HOME/.dapr
34+
func GetDaprPath(inputInstallPath string) (string, error) {
35+
if inputInstallPath != "" {
36+
return inputInstallPath, nil
37+
}
38+
39+
envDaprDir := os.Getenv("DAPR_PATH")
40+
if envDaprDir != "" {
41+
return envDaprDir, nil
42+
}
43+
44+
homeDir, err := os.UserHomeDir()
45+
if err != nil {
46+
return "", err
47+
}
48+
49+
return path_filepath.Join(homeDir, defaultDaprDirName), nil
3250
}
3351

34-
func defaultDaprBinPath() string {
35-
return path_filepath.Join(defaultDaprDirPath(), defaultDaprBinDirName)
52+
func getDaprBinPath(daprDir string) string {
53+
return path_filepath.Join(daprDir, defaultDaprBinDirName)
3654
}
3755

38-
func binaryFilePath(binaryDir string, binaryFilePrefix string) string {
56+
func binaryFilePathWithDir(binaryDir string, binaryFilePrefix string) string {
3957
binaryPath := path_filepath.Join(binaryDir, binaryFilePrefix)
4058
if runtime.GOOS == daprWindowsOS {
4159
binaryPath += ".exe"
4260
}
4361
return binaryPath
4462
}
4563

46-
func DefaultComponentsDirPath() string {
47-
return path_filepath.Join(defaultDaprDirPath(), defaultComponentsDirName)
64+
func lookupBinaryFilePath(inputInstallPath string, binaryFilePrefix string) (string, error) {
65+
daprPath, err := GetDaprPath(inputInstallPath)
66+
if err != nil {
67+
return "", err
68+
}
69+
70+
return binaryFilePathWithDir(getDaprBinPath(daprPath), binaryFilePrefix), nil
71+
}
72+
73+
func GetDaprComponentsPath(daprDir string) string {
74+
return path_filepath.Join(daprDir, defaultComponentsDirName)
4875
}
4976

50-
func DefaultConfigFilePath() string {
51-
return path_filepath.Join(defaultDaprDirPath(), defaultConfigFileName)
77+
func GetDaprConfigPath(daprDir string) string {
78+
return path_filepath.Join(daprDir, defaultConfigFileName)
5279
}

pkg/standalone/dashboard.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,21 @@ import (
1717
"os"
1818
"os/exec"
1919
"path/filepath"
20-
"runtime"
2120
"strconv"
2221
)
2322

2423
// NewDashboardCmd creates the command to run dashboard.
25-
func NewDashboardCmd(port int) *exec.Cmd {
26-
// Use the default binary install location.
27-
dashboardPath := defaultDaprBinPath()
28-
binaryName := "dashboard"
29-
if runtime.GOOS == daprWindowsOS {
30-
binaryName = "dashboard.exe"
24+
func NewDashboardCmd(inputInstallPath string, port int) (*exec.Cmd, error) {
25+
dashboardPath, err := lookupBinaryFilePath(inputInstallPath, "dashboard")
26+
if err != nil {
27+
return nil, err
3128
}
3229

3330
// Construct command to run dashboard.
3431
return &exec.Cmd{
35-
Path: filepath.Join(dashboardPath, binaryName),
36-
Args: []string{binaryName, "--port", strconv.Itoa(port)},
37-
Dir: dashboardPath,
32+
Path: dashboardPath,
33+
Args: []string{filepath.Base(dashboardPath), "--port", strconv.Itoa(port)},
34+
Dir: filepath.Dir(dashboardPath),
3835
Stdout: os.Stdout,
39-
}
36+
}, nil
4037
}

pkg/standalone/dashboard_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import (
2121

2222
func TestDashboardRun(t *testing.T) {
2323
t.Run("build Cmd", func(t *testing.T) {
24-
cmd := NewDashboardCmd(9090)
24+
cmd, err := NewDashboardCmd("", 9090)
2525

26+
assert.NoError(t, err)
2627
assert.Contains(t, cmd.Args[0], "dashboard")
2728
assert.Equal(t, cmd.Args[1], "--port")
2829
assert.Equal(t, cmd.Args[2], "9090")

pkg/standalone/run.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type RunConfig struct {
6262
AppHealthTimeout int `arg:"app-health-probe-timeout" ifneq:"0"`
6363
AppHealthThreshold int `arg:"app-health-threshold" ifneq:"0"`
6464
EnableAPILogging bool `arg:"enable-api-logging"`
65+
DaprPathCmdFlag string
6566
}
6667

6768
func (meta *DaprMeta) newAppID() string {
@@ -309,7 +310,11 @@ type RunOutput struct {
309310
}
310311

311312
func getDaprCommand(config *RunConfig) (*exec.Cmd, error) {
312-
daprCMD := binaryFilePath(defaultDaprBinPath(), "daprd")
313+
daprCMD, err := lookupBinaryFilePath(config.DaprPathCmdFlag, "daprd")
314+
if err != nil {
315+
return nil, err
316+
}
317+
313318
args := config.getArgs()
314319
cmd := exec.Command(daprCMD, args...)
315320
return cmd, nil

0 commit comments

Comments
 (0)