diff --git a/Makefile b/Makefile index 3bcc674c1..298c35d2d 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ e2e-build-run-k8s: build test-e2e-k8s ################################################################################ .PHONY: test-e2e-upgrade test-e2e-upgrade: test-deps - gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 30m -count=1 -tags=e2e ./tests/e2e/upgrade/... + gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 40m -count=1 -tags=e2e ./tests/e2e/upgrade/... ################################################################################ # Build, E2E Tests for Kubernetes Upgrade # diff --git a/README.md b/README.md index 27edc7b88..b5670956c 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Output should look like so: ℹ️ dapr_redis container is running. ℹ️ dapr_zipkin container is running. ℹ️ Use `docker ps` to check running containers. -✅ Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started +✅ Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started ``` > Note: To see that Dapr has been installed successfully, from a command prompt run the `docker ps` command and check that the `daprio/dapr:latest`, `dapr_redis` and `dapr_zipkin` container images are all running. @@ -120,7 +120,7 @@ Output should look like so: ℹ️ daprd binary has been installed to $HOME/.dapr/bin. ℹ️ placement binary has been installed. ℹ️ scheduler binary has been installed. -✅ Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started +✅ Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started ``` >Note: When initializing Dapr with the `--slim` flag only the Dapr runtime, placement, and scheduler service binaries are installed. An empty default components folder is created with no default configuration files. During `dapr run` user should use `--resources-path` (`--components-path` is deprecated and will be removed in future releases) to point to a components directory with custom configurations files or alternatively place these files in the default directory. For Linux/MacOS, the default components directory path is `$HOME/.dapr/components` and for Windows it is `%USERPROFILE%\.dapr\components`. @@ -289,7 +289,7 @@ Output should look like as follows: ℹ️ Note: To install Dapr using Helm, see here: https://docs.dapr.io/getting-started/install-dapr/#install-with-helm-advanced ✅ Deploying the Dapr control plane to your cluster... -✅ Success! Dapr has been installed to namespace dapr-system. To verify, run "dapr status -k" in your terminal. To get started, go here: https://aka.ms/dapr-getting-started +✅ Success! Dapr has been installed to namespace dapr-system. To verify, run "dapr status -k" in your terminal. To get started, go here: https://docs.dapr.io/getting-started ``` #### Supplying Helm values diff --git a/cmd/annotate.go b/cmd/annotate.go index a5e9b6472..ab77757ba 100644 --- a/cmd/annotate.go +++ b/cmd/annotate.go @@ -221,7 +221,6 @@ func readInputsFromFS(path string) ([]io.Reader, error) { inputs = append(inputs, file) return nil }) - if err != nil { return nil, err } diff --git a/cmd/init.go b/cmd/init.go index 86f785c66..e3b5c0d6e 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -45,6 +45,7 @@ var ( fromDir string containerRuntime string imageVariant string + schedulerVolume string ) var InitCmd = &cobra.Command{ @@ -146,7 +147,7 @@ dapr init --runtime-path print.FailureStatusEvent(os.Stderr, err.Error()) os.Exit(1) } - print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("Success! Dapr has been installed to namespace %s. To verify, run `dapr status -k' in your terminal. To get started, go here: https://aka.ms/dapr-getting-started", config.Namespace)) + print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("Success! Dapr has been installed to namespace %s. To verify, run `dapr status -k' in your terminal. To get started, go here: https://docs.dapr.io/getting-started", config.Namespace)) } else { dockerNetwork := "" imageRegistryURI := "" @@ -170,12 +171,12 @@ dapr init --runtime-path print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.") os.Exit(1) } - err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath) + err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath, &schedulerVolume) if err != nil { print.FailureStatusEvent(os.Stderr, err.Error()) os.Exit(1) } - print.SuccessStatusEvent(os.Stdout, "Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started") + print.SuccessStatusEvent(os.Stdout, "Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started") } }, } @@ -219,6 +220,7 @@ func init() { InitCmd.Flags().String("network", "", "The Docker network on which to deploy the Dapr runtime") InitCmd.Flags().StringVarP(&fromDir, "from-dir", "", "", "Use Dapr artifacts from local directory for self-hosted installation") InitCmd.Flags().StringVarP(&imageVariant, "image-variant", "", "", "The image variant to use for the Dapr runtime, for example: mariner") + InitCmd.Flags().StringVarP(&schedulerVolume, "scheduler-volume", "", "dapr_scheduler", "Self-hosted only. Specify a volume for the scheduler service data directory.") InitCmd.Flags().BoolP("help", "h", false, "Print this help message") InitCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") InitCmd.Flags().String("image-registry", "", "Custom/private docker image repository URL") diff --git a/cmd/run.go b/cmd/run.go index 4b5959ec0..f91c772e6 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "golang.org/x/mod/semver" + "github.com/spf13/cobra" "github.com/spf13/viper" @@ -38,34 +40,35 @@ import ( ) var ( - appPort int - profilePort int - appID string - configFile string - port int - grpcPort int - internalGRPCPort int - maxConcurrency int - enableProfiling bool - logLevel string - protocol string - componentsPath string - resourcesPaths []string - appSSL bool - metricsPort int - maxRequestBodySize int - readBufferSize int - unixDomainSocket string - enableAppHealth bool - appHealthPath string - appHealthInterval int - appHealthTimeout int - appHealthThreshold int - enableAPILogging bool - apiListenAddresses string - runFilePath string - appChannelAddress string - enableRunK8s bool + appPort int + profilePort int + appID string + configFile string + port int + grpcPort int + internalGRPCPort int + maxConcurrency int + enableProfiling bool + logLevel string + protocol string + componentsPath string + resourcesPaths []string + appSSL bool + metricsPort int + maxRequestBodySize int + readBufferSize int + unixDomainSocket string + enableAppHealth bool + appHealthPath string + appHealthInterval int + appHealthTimeout int + appHealthThreshold int + enableAPILogging bool + apiListenAddresses string + schedulerHostAddress string + runFilePath string + appChannelAddress string + enableRunK8s bool ) const ( @@ -120,7 +123,6 @@ dapr run --run-file /path/to/directory -k Args: cobra.MinimumNArgs(0), PreRun: func(cmd *cobra.Command, args []string) { viper.BindPFlag("placement-host-address", cmd.Flags().Lookup("placement-host-address")) - viper.BindPFlag("scheduler-host-address", cmd.Flags().Lookup("scheduler-host-address")) }, Run: func(cmd *cobra.Command, args []string) { if len(runFilePath) > 0 { @@ -166,26 +168,26 @@ dapr run --run-file /path/to/directory -k } sharedRunConfig := &standalone.SharedRunConfig{ - ConfigFile: configFile, - EnableProfiling: enableProfiling, - LogLevel: logLevel, - MaxConcurrency: maxConcurrency, - AppProtocol: protocol, - PlacementHostAddr: viper.GetString("placement-host-address"), - SchedulerHostAddr: viper.GetString("scheduler-host-address"), - ComponentsPath: componentsPath, - ResourcesPaths: resourcesPaths, - AppSSL: appSSL, - MaxRequestBodySize: maxRequestBodySize, - HTTPReadBufferSize: readBufferSize, - EnableAppHealth: enableAppHealth, - AppHealthPath: appHealthPath, - AppHealthInterval: appHealthInterval, - AppHealthTimeout: appHealthTimeout, - AppHealthThreshold: appHealthThreshold, - EnableAPILogging: enableAPILogging, - APIListenAddresses: apiListenAddresses, - DaprdInstallPath: daprRuntimePath, + ConfigFile: configFile, + EnableProfiling: enableProfiling, + LogLevel: logLevel, + MaxConcurrency: maxConcurrency, + AppProtocol: protocol, + PlacementHostAddr: viper.GetString("placement-host-address"), + ComponentsPath: componentsPath, + ResourcesPaths: resourcesPaths, + AppSSL: appSSL, + MaxRequestBodySize: maxRequestBodySize, + HTTPReadBufferSize: readBufferSize, + EnableAppHealth: enableAppHealth, + AppHealthPath: appHealthPath, + AppHealthInterval: appHealthInterval, + AppHealthTimeout: appHealthTimeout, + AppHealthThreshold: appHealthThreshold, + EnableAPILogging: enableAPILogging, + APIListenAddresses: apiListenAddresses, + SchedulerHostAddress: schedulerHostAddress, + DaprdInstallPath: daprRuntimePath, } output, err := runExec.NewOutput(&standalone.RunConfig{ AppID: appID, @@ -227,6 +229,15 @@ dapr run --run-file /path/to/directory -k output.DaprHTTPPort, output.DaprGRPCPort) } + + if semver.Compare(fmt.Sprintf("v%v", daprVer.RuntimeVersion), "v1.14.0-rc.1") == -1 { + print.InfoStatusEvent(os.Stdout, "The scheduler is only compatible with dapr runtime 1.14 onwards.") + for i, arg := range output.DaprCMD.Args { + if strings.HasPrefix(arg, "--scheduler-host-address") { + output.DaprCMD.Args[i] = "" + } + } + } print.InfoStatusEvent(os.Stdout, startInfo) output.DaprCMD.Stdout = os.Stdout @@ -456,7 +467,7 @@ func init() { // 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. RunCmd.Flags().MarkDeprecated("components-path", "This flag is deprecated and will be removed in the future releases. Use \"resources-path\" flag instead") RunCmd.Flags().String("placement-host-address", "localhost", "The address of the placement service. Format is either for default port or : for custom port") - RunCmd.Flags().String("scheduler-host-address", "localhost", "The address of the scheduler service. Format is either for default port or : for custom port") + RunCmd.Flags().StringVarP(&schedulerHostAddress, "scheduler-host-address", "", "localhost", "The address of the scheduler service. Format is either for default port or : for custom port") // TODO: Remove below flag once the flag is removed in runtime in future release. RunCmd.Flags().BoolVar(&appSSL, "app-ssl", false, "Enable https when Dapr invokes the application") RunCmd.Flags().MarkDeprecated("app-ssl", "This flag is deprecated and will be removed in the future releases. Use \"app-protocol\" flag with https or grpcs values instead") diff --git a/cmd/uninstall.go b/cmd/uninstall.go index b8b672a11..a2c91085b 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -99,7 +99,7 @@ func init() { UninstallCmd.Flags().BoolVarP(&uninstallKubernetes, "kubernetes", "k", false, "Uninstall Dapr from a Kubernetes cluster") UninstallCmd.Flags().BoolVarP(&uninstallDev, "dev", "", false, "Uninstall Dapr Redis and Zipking installations from Kubernetes cluster") UninstallCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The timeout for the Kubernetes uninstall") - UninstallCmd.Flags().BoolVar(&uninstallAll, "all", false, "Remove .dapr directory, Redis, Placement, Scheduler, and Zipkin containers on local machine, and CRDs on a Kubernetes cluster") + UninstallCmd.Flags().BoolVar(&uninstallAll, "all", false, "Remove .dapr directory, Redis, Placement, Scheduler (and default volume in self-hosted mode), and Zipkin containers on local machine, and CRDs on a Kubernetes cluster") UninstallCmd.Flags().String("network", "", "The Docker network from which to remove the Dapr runtime") UninstallCmd.Flags().StringVarP(&uninstallNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to uninstall Dapr from") UninstallCmd.Flags().BoolP("help", "h", false, "Print this help message") diff --git a/go.mod b/go.mod index ea59e3d7b..146089460 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,10 @@ require ( sigs.k8s.io/yaml v1.4.0 ) -require github.com/Masterminds/semver/v3 v3.2.0 +require ( + github.com/Masterminds/semver/v3 v3.2.0 + golang.org/x/mod v0.14.0 +) require ( github.com/alphadose/haxmap v1.3.1 // indirect @@ -61,7 +64,6 @@ require ( go.mongodb.org/mongo-driver v1.12.1 // indirect go.opentelemetry.io/otel/metric v1.23.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.14.0 // indirect golang.org/x/tools v0.17.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index f6bd78e5a..54f79a578 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -40,6 +40,7 @@ const ( daprReleaseName = "dapr" dashboardReleaseName = "dapr-dashboard" latestVersion = "latest" + bitnamiStableVersion = "17.14.5" // dev mode constants. thirdPartyDevNamespace = "default" @@ -47,7 +48,7 @@ const ( redisChartName = "redis" zipkinReleaseName = "dapr-dev-zipkin" redisReleaseName = "dapr-dev-redis" - redisVersion = "6.2" + redisVersion = "6.2.11" bitnamiHelmRepo = "https://charts.bitnami.com/bitnami" daprHelmRepo = "https://dapr.github.io/helm-charts" zipkinHelmRepo = "https://openzipkin.github.io/zipkin" @@ -99,9 +100,10 @@ func Init(config InitConfiguration) error { if config.EnableDev { redisChartVals := []string{ "image.tag=" + redisVersion, + "replica.replicaCount=0", } - err = installThirdPartyWithConsole(redisReleaseName, redisChartName, latestVersion, bitnamiHelmRepo, "Dapr Redis", redisChartVals, config) + err = installThirdPartyWithConsole(redisReleaseName, redisChartName, bitnamiStableVersion, bitnamiHelmRepo, "Dapr Redis", redisChartVals, config) if err != nil { return err } @@ -124,7 +126,7 @@ func installThirdPartyWithConsole(releaseName, chartName, releaseVersion, helmRe defer installSpinning(print.Failure) // releaseVersion of chart will always be latest version. - err := installThirdParty(releaseName, chartName, latestVersion, helmRepo, chartValues, config) + err := installThirdParty(releaseName, chartName, releaseVersion, helmRepo, chartValues, config) if err != nil { return err } @@ -214,7 +216,7 @@ func getHelmChart(version, releaseName, helmRepo string, config *helm.Configurat pull.Settings = &cli.EnvSettings{} - if version != latestVersion && (releaseName == daprReleaseName || releaseName == dashboardReleaseName) { + if version != latestVersion && (releaseName == daprReleaseName || releaseName == dashboardReleaseName || releaseName == redisChartName) { pull.Version = chartVersion(version) } diff --git a/pkg/kubernetes/renew_certificate.go b/pkg/kubernetes/renew_certificate.go index 8880a7eb3..28dd49e77 100644 --- a/pkg/kubernetes/renew_certificate.go +++ b/pkg/kubernetes/renew_certificate.go @@ -52,7 +52,6 @@ func RenewCertificate(conf RenewCertificateParams) error { conf.RootCertificateFilePath, conf.IssuerCertificateFilePath, conf.IssuerPrivateKeyFilePath) - if err != nil { return err } @@ -60,7 +59,6 @@ func RenewCertificate(conf RenewCertificateParams) error { rootCertBytes, issuerCertBytes, issuerKeyBytes, err = GenerateNewCertificates( conf.ValidUntil, conf.RootPrivateKeyFilePath) - if err != nil { return err } diff --git a/pkg/kubernetes/status.go b/pkg/kubernetes/status.go index acd4773c4..3d364c6ee 100644 --- a/pkg/kubernetes/status.go +++ b/pkg/kubernetes/status.go @@ -33,6 +33,7 @@ var controlPlaneLabels = []string{ "dapr-placement-server", "dapr-sidecar-injector", "dapr-dashboard", + "dapr-scheduler-server", } type StatusClient struct { diff --git a/pkg/kubernetes/status_test.go b/pkg/kubernetes/status_test.go index 3fc297ab4..a2f2778ab 100644 --- a/pkg/kubernetes/status_test.go +++ b/pkg/kubernetes/status_test.go @@ -233,6 +233,9 @@ func TestControlPlaneServices(t *testing.T) { {"dapr-sidecar-injector-74648c9dcb-5bsmn", "dapr-sidecar-injector", daprImageTag}, {"dapr-sidecar-injector-74648c9dcb-6bsmn", "dapr-sidecar-injector", daprImageTag}, {"dapr-sidecar-injector-74648c9dcb-7bsmn", "dapr-sidecar-injector", daprImageTag}, + {"dapr-scheduler-server-0", "dapr-scheduler-server", daprImageTag}, + {"dapr-scheduler-server-1", "dapr-scheduler-server", daprImageTag}, + {"dapr-scheduler-server-2", "dapr-scheduler-server", daprImageTag}, } expectedReplicas := map[string]int{} diff --git a/pkg/kubernetes/uninstall.go b/pkg/kubernetes/uninstall.go index 7a0240920..1ab874dd0 100644 --- a/pkg/kubernetes/uninstall.go +++ b/pkg/kubernetes/uninstall.go @@ -54,7 +54,6 @@ func Uninstall(namespace string, uninstallAll bool, uninstallDev bool, timeout u } _, err = uninstallClient.Run(daprReleaseName) - if err != nil { return err } diff --git a/pkg/standalone/common.go b/pkg/standalone/common.go index c47316ac0..5e2ee888e 100644 --- a/pkg/standalone/common.go +++ b/pkg/standalone/common.go @@ -17,7 +17,6 @@ import ( "os" path_filepath "path/filepath" "runtime" - "strconv" "strings" ) @@ -61,16 +60,6 @@ func getDaprBinPath(daprDir string) string { return path_filepath.Join(daprDir, defaultDaprBinDirName) } -// getSchedulerDataPath returns the data path of a given instance -// Receiving instanceID allows multiple instances of scheduler to run locally in the future. -func getSchedulerDataPath(daprDir string, instanceID int) string { - return path_filepath.Join( - daprDir, - defaultSchedulerDirName, - defaultSchedulerDataDirName, - strconv.Itoa(instanceID)) -} - func binaryFilePathWithDir(binaryDir string, binaryFilePrefix string) string { binaryPath := path_filepath.Join(binaryDir, binaryFilePrefix) if runtime.GOOS == daprWindowsOS { diff --git a/pkg/standalone/run.go b/pkg/standalone/run.go index 6f1f81127..8fc89e412 100644 --- a/pkg/standalone/run.go +++ b/pkg/standalone/run.go @@ -70,8 +70,6 @@ type SharedRunConfig struct { MaxConcurrency int `arg:"app-max-concurrency" annotation:"dapr.io/app-max-concurrerncy" yaml:"appMaxConcurrency" default:"-1"` // Speicifcally omitted from annotations similar to config file path above. PlacementHostAddr string `arg:"placement-host-address" yaml:"placementHostAddress"` - // Must use env for scheduler host address because using arg would cause a sidecar crash in older daprd versions. - SchedulerHostAddr string `env:"DAPR_SCHEDULER_HOST_ADDRESS" yaml:"schedulerHostAddress"` // Speicifcally omitted from annotations similar to config file path above. ComponentsPath string `arg:"components-path"` // Deprecated in run template file: use ResourcesPaths instead. // Speicifcally omitted from annotations similar to config file path above. @@ -89,10 +87,11 @@ type SharedRunConfig struct { AppHealthThreshold int `arg:"app-health-threshold" annotation:"dapr.io/app-health-threshold" ifneq:"0" yaml:"appHealthThreshold"` EnableAPILogging bool `arg:"enable-api-logging" annotation:"dapr.io/enable-api-logging" yaml:"enableApiLogging"` // Specifically omitted from annotations see https://github.com/dapr/cli/issues/1324 . - DaprdInstallPath string `yaml:"runtimePath"` - Env map[string]string `yaml:"env"` - DaprdLogDestination LogDestType `yaml:"daprdLogDestination"` - AppLogDestination LogDestType `yaml:"appLogDestination"` + DaprdInstallPath string `yaml:"runtimePath"` + Env map[string]string `yaml:"env"` + DaprdLogDestination LogDestType `yaml:"daprdLogDestination"` + AppLogDestination LogDestType `yaml:"appLogDestination"` + SchedulerHostAddress string `arg:"scheduler-host-address" yaml:"schedulerHostAddress"` } func (meta *DaprMeta) newAppID() string { @@ -139,10 +138,11 @@ func (config *RunConfig) validatePlacementHostAddr() error { } func (config *RunConfig) validateSchedulerHostAddr() error { - schedulerHostAddr := config.SchedulerHostAddr + schedulerHostAddr := config.SchedulerHostAddress if len(schedulerHostAddr) == 0 { - schedulerHostAddr = "localhost" + return nil } + if indx := strings.Index(schedulerHostAddr, ":"); indx == -1 { if runtime.GOOS == daprWindowsOS { schedulerHostAddr = fmt.Sprintf("%s:6060", schedulerHostAddr) @@ -150,7 +150,9 @@ func (config *RunConfig) validateSchedulerHostAddr() error { schedulerHostAddr = fmt.Sprintf("%s:50006", schedulerHostAddr) } } - config.SchedulerHostAddr = schedulerHostAddr + + config.SchedulerHostAddress = schedulerHostAddr + return nil } @@ -237,7 +239,6 @@ func (config *RunConfig) Validate() error { } err = config.validateSchedulerHostAddr() - if err != nil { return err } diff --git a/pkg/standalone/standalone.go b/pkg/standalone/standalone.go index f25bf9bfb..bc7fba008 100644 --- a/pkg/standalone/standalone.go +++ b/pkg/standalone/standalone.go @@ -143,6 +143,7 @@ type initInfo struct { imageRegistryURL string containerRuntime string imageVariant string + schedulerVolume *string } type daprImageInfo struct { @@ -176,11 +177,15 @@ func isSchedulerIncluded(runtimeVersion string) (bool, error) { return false, err } - return c.Check(v), nil + vNoPrerelease, err := v.SetPrerelease("") + if err != nil { + return false, err + } + return c.Check(&vNoPrerelease), nil } // Init installs Dapr on a local machine using the supplied runtimeVersion. -func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMode bool, imageRegistryURL string, fromDir string, containerRuntime string, imageVariant string, daprInstallPath string) error { +func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMode bool, imageRegistryURL string, fromDir string, containerRuntime string, imageVariant string, daprInstallPath string, schedulerVolume *string) error { var err error var bundleDet bundleDetails containerRuntime = strings.TrimSpace(containerRuntime) @@ -301,6 +306,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod imageRegistryURL: imageRegistryURL, containerRuntime: containerRuntime, imageVariant: imageVariant, + schedulerVolume: schedulerVolume, } for _, step := range initSteps { // Run init on the configurations and containers. @@ -411,7 +417,6 @@ func runZipkin(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) { args = append(args, imageName) } _, err = utils.RunCmdAndWait(runtimeCmd, args...) - if err != nil { runError := isContainerRunError(err) if !runError { @@ -477,7 +482,6 @@ func runRedis(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) { args = append(args, imageName) } _, err = utils.RunCmdAndWait(runtimeCmd, args...) - if err != nil { runError := isContainerRunError(err) if !runError { @@ -564,7 +568,6 @@ func runPlacementService(wg *sync.WaitGroup, errorChan chan<- error, info initIn args = append(args, image) _, err = utils.RunCmdAndWait(runtimeCmd, args...) - if err != nil { runError := isContainerRunError(err) if !runError { @@ -632,15 +635,24 @@ func runSchedulerService(wg *sync.WaitGroup, errorChan chan<- error, info initIn } } - // instanceID is 0 because we run one instance only for now. - schedulerDataDir := getSchedulerDataPath(info.installDir, 0) args := []string{ "run", "--name", schedulerContainerName, "--restart", "always", "-d", "--entrypoint", "./scheduler", - "--volume", fmt.Sprintf("%v:/data-default-dapr-scheduler-server-0", schedulerDataDir), + } + if info.schedulerVolume != nil { + // Don't touch this file location unless things start breaking. + // In Docker, when Docker creates a volume and mounts that volume. Docker + // assumes the file permissions of that directory if it exists in the container. + // If that directory didn't exist in the container previously, then Docker sets + // the permissions owned by root and not writeable. + // We are lucky in that the Dapr containers have a world writeable directory at + // /var/lock and can therefore mount the Docker volume here. + // TODO: update the Dapr scheduler dockerfile to create a scheduler user id writeable + // directory at /var/lib/dapr/scheduler, then update the path here. + args = append(args, "--volume", *info.schedulerVolume+":/var/lock") } if info.dockerNetwork != "" { @@ -661,10 +673,9 @@ func runSchedulerService(wg *sync.WaitGroup, errorChan chan<- error, info initIn ) } - args = append(args, image) + args = append(args, image, "--etcd-data-dir=/var/lock/dapr/scheduler") _, err = utils.RunCmdAndWait(runtimeCmd, args...) - if err != nil { runError := isContainerRunError(err) if !runError { diff --git a/pkg/standalone/standalone_test.go b/pkg/standalone/standalone_test.go index bf05b1f63..7f8ae5c0c 100644 --- a/pkg/standalone/standalone_test.go +++ b/pkg/standalone/standalone_test.go @@ -328,9 +328,31 @@ func TestInitLogActualContainerRuntimeName(t *testing.T) { t.Skip("Skipping test as container runtime is available") } - err := Init(latestVersion, latestVersion, "", false, "", "", test.containerRuntime, "", "") + err := Init(latestVersion, latestVersion, "", false, "", "", test.containerRuntime, "", "", nil) assert.NotNil(t, err) assert.Contains(t, err.Error(), test.containerRuntime) }) } } + +func TestIsSchedulerIncluded(t *testing.T) { + scenarios := []struct { + version string + isIncluded bool + }{ + {"1.13.0-rc.1", false}, + {"1.13.0", false}, + {"1.13.1", false}, + {"1.14.0", true}, + {"1.14.0-rc.1", true}, + {"1.14.0-mycompany.1", true}, + {"1.14.1", true}, + } + for _, scenario := range scenarios { + t.Run("isSchedulerIncludedIn"+scenario.version, func(t *testing.T) { + included, err := isSchedulerIncluded(scenario.version) + assert.NoError(t, err) + assert.Equal(t, scenario.isIncluded, included) + }) + } +} diff --git a/pkg/standalone/uninstall.go b/pkg/standalone/uninstall.go index 0162cbe43..7eb9fecbc 100644 --- a/pkg/standalone/uninstall.go +++ b/pkg/standalone/uninstall.go @@ -63,6 +63,20 @@ func removeDockerContainer(containerErrs []error, containerName, network, runtim return containerErrs } +func removeSchedulerVolume(containerErrs []error, runtimeCmd string) []error { + print.InfoStatusEvent(os.Stdout, "Removing volume if it exists: dapr_scheduler") + _, err := utils.RunCmdAndWait( + runtimeCmd, "volume", "rm", + "--force", + "dapr_scheduler") + if err != nil { + containerErrs = append( + containerErrs, + fmt.Errorf("could not remove dapr_scheduler volume: %w", err)) + } + return containerErrs +} + func removeDir(dirPath string) error { _, err := os.Stat(dirPath) if os.IsNotExist(err) { @@ -117,6 +131,10 @@ func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string, if err != nil { print.WarningStatusEvent(os.Stdout, "WARNING: could not delete dapr dir %s: %s", installDir, err) } + + if containerRuntimeAvailable { + containerErrs = removeSchedulerVolume(containerErrs, runtimeCmd) + } } err = errors.New("uninstall failed") diff --git a/tests/e2e/common/common.go b/tests/e2e/common/common.go index b6c1b5b4a..e52412944 100644 --- a/tests/e2e/common/common.go +++ b/tests/e2e/common/common.go @@ -1210,7 +1210,6 @@ func exportCurrentCertificate(daprPath string) error { os.RemoveAll("./certs") } _, err = spawn.Command(daprPath, "mtls", "export", "-o", "./certs") - if err != nil { return fmt.Errorf("error in exporting certificate %w", err) } diff --git a/tests/e2e/standalone/init_test.go b/tests/e2e/standalone/init_test.go index 14a688bc2..e07b405a6 100644 --- a/tests/e2e/standalone/init_test.go +++ b/tests/e2e/standalone/init_test.go @@ -18,12 +18,16 @@ package standalone_test import ( "context" + "net" "os" "path/filepath" "runtime" + "strconv" "strings" "testing" + "time" + "github.com/Masterminds/semver" "github.com/dapr/cli/tests/e2e/common" "github.com/dapr/cli/tests/e2e/spawn" "github.com/docker/docker/api/types" @@ -157,6 +161,48 @@ func TestStandaloneInit(t *testing.T) { verifyContainers(t, latestDaprRuntimeVersion) verifyBinaries(t, daprPath, latestDaprRuntimeVersion, latestDaprDashboardVersion) verifyConfigs(t, daprPath) + + placementPort := 50005 + if runtime.GOOS == "windows" { + placementPort = 6050 + } + + verifyTCPLocalhost(t, placementPort) + }) + + t.Run("init version with scheduler", func(t *testing.T) { + // Ensure a clean environment + must(t, cmdUninstall, "failed to uninstall Dapr") + + args := []string{ + "--runtime-version", "1.14.0-rc.3", + "--dev", + } + output, err := cmdInit(args...) + t.Log(output) + require.NoError(t, err, "init failed") + assert.Contains(t, output, "Success! Dapr is up and running.") + + homeDir, err := os.UserHomeDir() + require.NoError(t, err, "failed to get user home directory") + + daprPath := filepath.Join(homeDir, ".dapr") + require.DirExists(t, daprPath, "Directory %s does not exist", daprPath) + + _, latestDaprDashboardVersion := common.GetVersionsFromEnv(t, true) + verifyContainers(t, "1.14.0-rc.3") + verifyBinaries(t, daprPath, "1.14.0-rc.3", latestDaprDashboardVersion) + verifyConfigs(t, daprPath) + + placementPort := 50005 + schedulerPort := 50006 + if runtime.GOOS == "windows" { + placementPort = 6050 + schedulerPort = 6060 + } + + verifyTCPLocalhost(t, placementPort) + verifyTCPLocalhost(t, schedulerPort) }) t.Run("init without runtime-version flag with mariner images", func(t *testing.T) { @@ -187,10 +233,11 @@ func TestStandaloneInit(t *testing.T) { // Note, in case of slim installation, the containers are not installed and // this test is automatically skipped. func verifyContainers(t *testing.T, daprRuntimeVersion string) { + t.Helper() + t.Run("verifyContainers", func(t *testing.T) { if isSlimMode() { - t.Log("Skipping container verification because of slim installation") - return + t.Skip("Skipping container verification because of slim installation") } cli, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) @@ -205,6 +252,12 @@ func verifyContainers(t *testing.T, daprRuntimeVersion string) { "dapr_redis": "", } + v, err := semver.NewVersion(daprRuntimeVersion) + require.NoError(t, err) + if v.Major() >= 1 && v.Minor() >= 14 { + daprContainers["dapr_scheduler"] = daprRuntimeVersion + } + for _, container := range containers { t.Logf("Found container: %v %s %s\n", container.Names, container.Image, container.State) if container.State != "running" { @@ -233,6 +286,8 @@ func verifyContainers(t *testing.T, daprRuntimeVersion string) { // verifyBinaries ensures that the correct binaries are present in the correct path. func verifyBinaries(t *testing.T, daprPath, runtimeVersion, dashboardVersion string) { + t.Helper() + binPath := filepath.Join(daprPath, "bin") require.DirExists(t, binPath, "Directory %s does not exist", binPath) @@ -247,6 +302,8 @@ func verifyBinaries(t *testing.T, daprPath, runtimeVersion, dashboardVersion str for bin, version := range binaries { t.Run("verifyBinaries/"+bin, func(t *testing.T) { + t.Helper() + file := filepath.Join(binPath, bin) if runtime.GOOS == "windows" { file += ".exe" @@ -265,6 +322,8 @@ func verifyBinaries(t *testing.T, daprPath, runtimeVersion, dashboardVersion str // verifyConfigs ensures that the Dapr configuration and component YAMLs // are present in the correct path and have the correct values. func verifyConfigs(t *testing.T, daprPath string) { + t.Helper() + configSpec := map[interface{}]interface{}{} // tracing is not enabled in slim mode by default. if !isSlimMode() { @@ -353,3 +412,22 @@ func verifyConfigs(t *testing.T, daprPath string) { }) } } + +// verifyTCPLocalhost verifies a given localhost TCP port is being listened to. +func verifyTCPLocalhost(t *testing.T, port int) { + t.Helper() + + if isSlimMode() { + t.Skip("Skipping container verification because of slim installation") + } + + // Check that the server is up and can accept connections. + endpoint := "127.0.0.1:" + strconv.Itoa(port) + assert.EventuallyWithT(t, func(c *assert.CollectT) { + conn, err := net.Dial("tcp", endpoint) + //nolint:testifylint + if assert.NoError(c, err) { + conn.Close() + } + }, time.Second*10, time.Millisecond*10) +} diff --git a/tests/e2e/standalone/windows_run_template_test.go b/tests/e2e/standalone/windows_run_template_test.go index 28ccefed9..c570f94c7 100644 --- a/tests/e2e/standalone/windows_run_template_test.go +++ b/tests/e2e/standalone/windows_run_template_test.go @@ -115,7 +115,6 @@ func startAppsWithAppLogDestFile(t *testing.T, file string) { assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=emit-metrics") assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.") - } func startAppsWithAppLogDestConsole(t *testing.T, file string) { @@ -139,5 +138,4 @@ func startAppsWithAppLogDestConsole(t *testing.T, file string) { assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=emit-metrics") assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.") - }