diff --git a/cmd/init.go b/cmd/init.go index 5257a35e..08f960b5 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -124,6 +124,7 @@ dapr init --runtime-path config := kubernetes.InitConfiguration{ Namespace: initNamespace, Version: runtimeVersion, + DashboardVersion: dashboardVersion, EnableMTLS: enableMTLS, EnableHA: enableHA, Args: values, @@ -205,7 +206,7 @@ func init() { InitCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The wait timeout for the Kubernetes installation") InitCmd.Flags().BoolVarP(&slimMode, "slim", "s", false, "Exclude placement service, Redis and Zipkin containers from self-hosted installation") InitCmd.Flags().StringVarP(&runtimeVersion, "runtime-version", "", defaultRuntimeVersion, "The version of the Dapr runtime to install, for example: 1.0.0") - InitCmd.Flags().StringVarP(&dashboardVersion, "dashboard-version", "", defaultDashboardVersion, "The version of the Dapr dashboard to install, for example: 1.0.0") + InitCmd.Flags().StringVarP(&dashboardVersion, "dashboard-version", "", defaultDashboardVersion, "The version of the Dapr dashboard to install, for example: 0.13.0") InitCmd.Flags().StringVarP(&initNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to install Dapr in") InitCmd.Flags().BoolVarP(&enableMTLS, "enable-mtls", "", true, "Enable mTLS in your cluster") InitCmd.Flags().BoolVarP(&enableHA, "enable-ha", "", false, "Enable high availability (HA) mode") diff --git a/cmd/upgrade.go b/cmd/upgrade.go index b58c6899..ee54a7e4 100644 --- a/cmd/upgrade.go +++ b/cmd/upgrade.go @@ -25,8 +25,9 @@ import ( ) var ( - upgradeRuntimeVersion string - upgradeImageVariant string + upgradeRuntimeVersion string + upgradeImageVariant string + upgradeDashboardVersion string ) var UpgradeCmd = &cobra.Command{ @@ -58,6 +59,7 @@ dapr upgrade -k } err = kubernetes.Upgrade(kubernetes.UpgradeConfig{ RuntimeVersion: upgradeRuntimeVersion, + DashboardVersion: upgradeDashboardVersion, Args: values, Timeout: timeout, ImageRegistryURI: imageRegistryURI, @@ -78,6 +80,7 @@ func init() { UpgradeCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Upgrade or downgrade Dapr in a Kubernetes cluster") UpgradeCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The timeout for the Kubernetes upgrade") UpgradeCmd.Flags().StringVarP(&upgradeRuntimeVersion, "runtime-version", "", "", "The version of the Dapr runtime to upgrade or downgrade to, for example: 1.0.0") + UpgradeCmd.Flags().StringVarP(&upgradeDashboardVersion, "dashboard-version", "", "", "The version of the Dapr dashboard to upgrade or downgrade to, for example: 0.13.0") UpgradeCmd.Flags().BoolP("help", "h", false, "Print this help message") UpgradeCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") UpgradeCmd.Flags().String("image-registry", "", "Custom/Private docker image repository URL") diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 0b737a4c..b0592fb5 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -36,13 +36,15 @@ import ( ) const ( - daprReleaseName = "dapr" - daprHelmRepo = "https://dapr.github.io/helm-charts" - latestVersion = "latest" + daprReleaseName = "dapr" + dashboardReleaseName = "dapr-dashboard" + daprHelmRepo = "https://dapr.github.io/helm-charts" + latestVersion = "latest" ) type InitConfiguration struct { Version string + DashboardVersion string Namespace string EnableMTLS bool EnableHA bool @@ -58,15 +60,38 @@ type InitConfiguration struct { // Init deploys the Dapr operator using the supplied runtime version. func Init(config InitConfiguration) error { - msg := "Deploying the Dapr control plane to your cluster..." - - stopSpinning := print.Spinner(os.Stdout, msg) - defer stopSpinning(print.Failure) - if err := install(config); err != nil { + err := installWithConsole(daprReleaseName, config.Version, "Dapr control plane", config) + if err != nil { return err } - stopSpinning(print.Success) + for _, dashboardClusterRole := range []string{"dashboard-reader", "dapr-dashboard"} { + // Detect Dapr Dashboard using a cluster-level resource (not dependent on namespace). + _, err = utils.RunCmdAndWait("kubectl", "describe", "clusterrole", dashboardClusterRole) + if err == nil { + // No need to install Dashboard since it is already present. + // Charts for versions < 1.11 contain Dashboard already. + return nil + } + } + + err = installWithConsole(dashboardReleaseName, config.DashboardVersion, "Dapr dashboard", config) + if err != nil { + return err + } + + return nil +} + +func installWithConsole(releaseName string, releaseVersion string, prettyName string, config InitConfiguration) error { + installSpinning := print.Spinner(os.Stdout, "Deploying the "+prettyName+" with "+releaseVersion+" version to your cluster...") + defer installSpinning(print.Failure) + + err := install(releaseName, releaseVersion, config) + if err != nil { + return err + } + installSpinning(print.Success) return nil } @@ -96,16 +121,23 @@ func helmConfig(namespace string) (*helm.Configuration, error) { return &ac, err } -func getVersion(version string) (string, error) { +func getVersion(releaseName string, version string) (string, error) { + actualVersion := version if version == latestVersion { var err error - version, err = cli_ver.GetDaprVersion() + if releaseName == daprReleaseName { + actualVersion, err = cli_ver.GetDaprVersion() + } else if releaseName == dashboardReleaseName { + actualVersion, err = cli_ver.GetDashboardVersion() + } else { + return "", fmt.Errorf("cannot get latest version for unknown chart: %s", releaseName) + } if err != nil { return "", fmt.Errorf("cannot get the latest release version: %w", err) } - version = strings.TrimPrefix(version, "v") + actualVersion = strings.TrimPrefix(actualVersion, "v") } - return version, nil + return actualVersion, nil } func createTempDir() (string, error) { @@ -124,7 +156,7 @@ func locateChartFile(dirPath string) (string, error) { return filepath.Join(dirPath, files[0].Name()), nil } -func daprChart(version string, config *helm.Configuration) (*chart.Chart, error) { +func daprChart(version string, releaseName string, config *helm.Configuration) (*chart.Chart, error) { pull := helm.NewPullWithOpts(helm.WithConfig(config)) pull.RepoURL = utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo) pull.Username = utils.GetEnv("DAPR_HELM_REPO_USERNAME", "") @@ -132,7 +164,7 @@ func daprChart(version string, config *helm.Configuration) (*chart.Chart, error) pull.Settings = &cli.EnvSettings{} - if version != latestVersion { + if version != latestVersion && releaseName == daprReleaseName { pull.Version = chartVersion(version) } @@ -144,7 +176,7 @@ func daprChart(version string, config *helm.Configuration) (*chart.Chart, error) pull.DestDir = dir - _, err = pull.Run(daprReleaseName) + _, err = pull.Run(releaseName) if err != nil { return nil, err } @@ -195,7 +227,7 @@ func chartValues(config InitConfiguration, version string) (map[string]interface return chartVals, nil } -func install(config InitConfiguration) error { +func install(releaseName string, releaseVersion string, config InitConfiguration) error { err := createNamespace(config.Namespace) if err != nil { return err @@ -206,23 +238,25 @@ func install(config InitConfiguration) error { return err } - daprChart, err := daprChart(config.Version, helmConf) + daprChart, err := daprChart(releaseVersion, releaseName, helmConf) if err != nil { return err } - version, err := getVersion(config.Version) + version, err := getVersion(releaseName, releaseVersion) if err != nil { return err } - err = applyCRDs(fmt.Sprintf("v%s", version)) - if err != nil { - return err + if releaseName == daprReleaseName { + err = applyCRDs(fmt.Sprintf("v%s", version)) + if err != nil { + return err + } } installClient := helm.NewInstall(helmConf) - installClient.ReleaseName = daprReleaseName + installClient.ReleaseName = releaseName installClient.Namespace = config.Namespace installClient.Wait = config.Wait installClient.Timeout = time.Duration(config.Timeout) * time.Second @@ -235,6 +269,7 @@ func install(config InitConfiguration) error { if _, err = installClient.Run(daprChart, values); err != nil { return err } + return nil } diff --git a/pkg/kubernetes/renew_certificate.go b/pkg/kubernetes/renew_certificate.go index 6efed9a7..9caf426b 100644 --- a/pkg/kubernetes/renew_certificate.go +++ b/pkg/kubernetes/renew_certificate.go @@ -112,7 +112,7 @@ func renewCertificate(rootCert, issuerCert, issuerKey []byte, timeout uint, imag return err } - daprChart, err := daprChart(daprVersion, helmConf) + daprChart, err := daprChart(daprVersion, "dapr", helmConf) if err != nil { return err } diff --git a/pkg/kubernetes/uninstall.go b/pkg/kubernetes/uninstall.go index e00a3a33..c66d07ab 100644 --- a/pkg/kubernetes/uninstall.go +++ b/pkg/kubernetes/uninstall.go @@ -42,6 +42,12 @@ func Uninstall(namespace string, uninstallAll bool, timeout uint) error { uninstallClient := helm.NewUninstall(config) uninstallClient.Timeout = time.Duration(timeout) * time.Second + + // Uninstall Dashboard as a best effort. + // Chart versions < 1.11 for Dapr will delete dashboard as part of the main chart. + // Deleting Dashboard here is for versions >= 1.11. + uninstallClient.Run(dashboardReleaseName) + _, err = uninstallClient.Run(daprReleaseName) if err != nil { diff --git a/pkg/kubernetes/upgrade.go b/pkg/kubernetes/upgrade.go index d94091a7..0e5f8610 100644 --- a/pkg/kubernetes/upgrade.go +++ b/pkg/kubernetes/upgrade.go @@ -20,6 +20,7 @@ import ( "time" helm "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" "k8s.io/helm/pkg/strvals" "github.com/hashicorp/go-version" @@ -46,6 +47,7 @@ var crdsFullResources = []string{ type UpgradeConfig struct { RuntimeVersion string + DashboardVersion string Args []string Timeout uint ImageRegistryURI string @@ -66,11 +68,19 @@ func Upgrade(conf UpgradeConfig) error { return err } - daprChart, err := daprChart(conf.RuntimeVersion, helmConf) + controlPlaneChart, err := daprChart(conf.RuntimeVersion, "dapr", helmConf) if err != nil { return err } + var dashboardChart *chart.Chart + if conf.DashboardVersion != "" { + dashboardChart, err = daprChart(conf.DashboardVersion, "dapr-dashboard", helmConf) + if err != nil { + return err + } + } + upgradeClient := helm.NewUpgrade(helmConf) upgradeClient.ResetValues = true upgradeClient.Namespace = status[0].Namespace @@ -121,9 +131,16 @@ func Upgrade(conf UpgradeConfig) error { return err } - if _, err = upgradeClient.Run(chart, daprChart, vals); err != nil { + if _, err = upgradeClient.Run(chart, controlPlaneChart, vals); err != nil { return err } + + if dashboardChart != nil { + if _, err = upgradeClient.Run(chart, dashboardChart, vals); err != nil { + return err + } + } + return nil } diff --git a/pkg/version/version.go b/pkg/version/version.go index eec049e7..be1c6b7a 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -150,6 +150,12 @@ func GetLatestReleaseHelmChart(helmChartURL string) (string, error) { } } + // Did not find a non-rc version, so we fallback to an RC. + // This is helpful to allow us to validate installation of new charts (Dashboard). + for _, release := range helmChartReleases.Entries.Dapr { + return release.Version, nil + } + return "", fmt.Errorf("no releases") }) } diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index 7f592918..0642e270 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -213,8 +213,8 @@ func TestGetVersionsHelm(t *testing.T) { ExpectedVer string }{ { - "RC releases are skipped", - "/rcs_are_skipped", + "Use RC releases if there isn't a full release yet", + "/fallback_to_rc", `apiVersion: v1 entries: dapr: @@ -268,8 +268,8 @@ entries: urls: - https://dapr.github.io/helm-charts/dapr-1.2.3-rc.1.tgz version: 1.2.3-rc.1 `, - "no releases", "", + "1.2.3-rc.1", }, } m := http.NewServeMux()