diff --git a/.github/workflows/functional-test-cloud.yaml b/.github/workflows/functional-test-cloud.yaml index 0f776f3f8f..7017dc7c11 100644 --- a/.github/workflows/functional-test-cloud.yaml +++ b/.github/workflows/functional-test-cloud.yaml @@ -55,9 +55,6 @@ env: HELM_VER: "v3.12.0" # KinD cluster version KIND_VER: "v0.20.0" - # Dapr version - DAPR_VER: "1.12.0" - DAPR_DASHBOARD_VER: "0.14.0" # Kubectl version KUBECTL_VER: "v1.25.0" # Azure Keyvault CSI driver chart version @@ -595,10 +592,6 @@ jobs: service-account-private-key-file: /etc/kubernetes/pki/sa.key EOF - - name: Install dapr into cluster - run: | - wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash -s ${{ env.DAPR_VER }} - dapr init -k --wait --timeout 600 --runtime-version ${{ env.DAPR_VER }} --dashboard-version ${{ env.DAPR_DASHBOARD_VER }} - name: Install Azure Keyvault CSI driver chart run: | diff --git a/.github/workflows/functional-test-noncloud.yaml b/.github/workflows/functional-test-noncloud.yaml index 9397313d3b..7560b7aa38 100644 --- a/.github/workflows/functional-test-noncloud.yaml +++ b/.github/workflows/functional-test-noncloud.yaml @@ -51,10 +51,6 @@ env: HELM_VER: "v3.15.3" # KinD cluster version KIND_VER: "v0.23.0" - # Dapr version - DAPR_VER: "1.12.0" - # Dapr dashboard version - DAPR_DASHBOARD_VER: "0.14.0" # Kubectl version KUBECTL_VER: "v1.30.0" @@ -263,11 +259,6 @@ jobs: registry-server: ${{ env.LOCAL_REGISTRY_SERVER }} registry-port: ${{ env.LOCAL_REGISTRY_PORT }} - - name: Install dapr into cluster - run: | - wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash -s ${{ env.DAPR_VER }} - dapr init -k --wait --timeout 600 --runtime-version ${{ env.DAPR_VER }} --dashboard-version ${{ env.DAPR_DASHBOARD_VER }} - - name: Install Radius run: | export PATH=$GITHUB_WORKSPACE/bin:$PATH diff --git a/pkg/cli/cmd/install/kubernetes/kubernetes.go b/pkg/cli/cmd/install/kubernetes/kubernetes.go index ed9628b678..242812c108 100644 --- a/pkg/cli/cmd/install/kubernetes/kubernetes.go +++ b/pkg/cli/cmd/install/kubernetes/kubernetes.go @@ -119,7 +119,7 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { // to the cli version. It then returns any errors that occur during the installation. func (r *Runner) Run(ctx context.Context) error { cliOptions := helm.CLIClusterOptions{ - Radius: helm.RadiusOptions{ + Radius: helm.ChartOptions{ Reinstall: r.Reinstall, ChartPath: r.Chart, SetArgs: r.Set, @@ -132,13 +132,13 @@ func (r *Runner) Run(ctx context.Context) error { return err } - if state.Installed && !r.Reinstall { + if state.RadiusInstalled && !r.Reinstall { r.Output.LogInfo("Found existing Radius installation. Use '--reinstall' to force reinstallation.") return nil } version := version.Version() - if state.Installed { + if state.RadiusInstalled { r.Output.LogInfo("Reinstalling Radius version %s to namespace: %s...", version, helm.RadiusSystemNamespace) } else { r.Output.LogInfo("Installing Radius version %s to namespace: %s...", version, helm.RadiusSystemNamespace) diff --git a/pkg/cli/cmd/install/kubernetes/kubernetes_test.go b/pkg/cli/cmd/install/kubernetes/kubernetes_test.go index 62b5a745e5..916e480186 100644 --- a/pkg/cli/cmd/install/kubernetes/kubernetes_test.go +++ b/pkg/cli/cmd/install/kubernetes/kubernetes_test.go @@ -73,7 +73,7 @@ func Test_Run(t *testing.T) { Times(1) expectedOptions := helm.PopulateDefaultClusterOptions(helm.CLIClusterOptions{ - Radius: helm.RadiusOptions{ + Radius: helm.ChartOptions{ ChartPath: "test-chart", SetArgs: []string{"foo=bar", "bar=baz"}, }, @@ -109,7 +109,7 @@ func Test_Run(t *testing.T) { } helmMock.EXPECT().CheckRadiusInstall("test-context"). - Return(helm.InstallState{Installed: true, Version: "test-version"}, nil). + Return(helm.InstallState{RadiusInstalled: true, RadiusVersion: "test-version"}, nil). Times(1) err := runner.Run(ctx) @@ -139,11 +139,11 @@ func Test_Run(t *testing.T) { } helmMock.EXPECT().CheckRadiusInstall("test-context"). - Return(helm.InstallState{Installed: true, Version: "test-version"}, nil). + Return(helm.InstallState{RadiusInstalled: true, RadiusVersion: "test-version"}, nil). Times(1) expectedOptions := helm.PopulateDefaultClusterOptions(helm.CLIClusterOptions{ - Radius: helm.RadiusOptions{ + Radius: helm.ChartOptions{ ChartPath: "test-chart", SetArgs: []string{"foo=bar", "bar=baz"}, Reinstall: true, diff --git a/pkg/cli/cmd/radinit/cluster.go b/pkg/cli/cmd/radinit/cluster.go index 955b5c114e..14de87625d 100644 --- a/pkg/cli/cmd/radinit/cluster.go +++ b/pkg/cli/cmd/radinit/cluster.go @@ -39,11 +39,11 @@ func (r *Runner) enterClusterOptions(options *initOptions) error { if err != nil { return clierrors.MessageWithCause(err, "Unable to verify Radius installation.") } - options.Cluster.Install = !state.Installed + options.Cluster.Install = !state.RadiusInstalled || !state.DaprInstalled - if state.Installed { + if state.RadiusInstalled && state.DaprInstalled { options.Cluster.Install = false - options.Cluster.Version = state.Version + options.Cluster.Version = state.RadiusVersion } if options.Cluster.Install { diff --git a/pkg/cli/cmd/radinit/init.go b/pkg/cli/cmd/radinit/init.go index dc623db825..7c64cf2c2b 100644 --- a/pkg/cli/cmd/radinit/init.go +++ b/pkg/cli/cmd/radinit/init.go @@ -214,7 +214,7 @@ func (r *Runner) Run(ctx context.Context) error { if r.Options.Cluster.Install { cliOptions := helm.CLIClusterOptions{ - Radius: helm.RadiusOptions{ + Radius: helm.ChartOptions{ SetArgs: r.Options.SetValues, }, } diff --git a/pkg/cli/cmd/radinit/init_test.go b/pkg/cli/cmd/radinit/init_test.go index 24b1008695..4f060d4965 100644 --- a/pkg/cli/cmd/radinit/init_test.go +++ b/pkg/cli/cmd/radinit/init_test.go @@ -1064,13 +1064,13 @@ func initSelectCloudProvider(prompter *prompt.MockInterface, value string) { func initHelmMockRadiusInstalled(helmMock *helm.MockInterface) { helmMock.EXPECT(). CheckRadiusInstall(gomock.Any()). - Return(helm.InstallState{Installed: true, Version: "test-version"}, nil).Times(1) + Return(helm.InstallState{RadiusInstalled: true, RadiusVersion: "test-version", DaprInstalled: true, DaprVersion: "test-version"}, nil).Times(1) } func initHelmMockRadiusNotInstalled(helmMock *helm.MockInterface) { helmMock.EXPECT(). CheckRadiusInstall(gomock.Any()). - Return(helm.InstallState{Installed: false}, nil).Times(1) + Return(helm.InstallState{RadiusInstalled: false}, nil).Times(1) } func setExistingEnvironments(clientMock *clients.MockApplicationsManagementClient, environments []corerp.EnvironmentResource) { diff --git a/pkg/cli/cmd/uninstall/kubernetes/kubernetes.go b/pkg/cli/cmd/uninstall/kubernetes/kubernetes.go index 2388b6b555..63d29a930f 100644 --- a/pkg/cli/cmd/uninstall/kubernetes/kubernetes.go +++ b/pkg/cli/cmd/uninstall/kubernetes/kubernetes.go @@ -18,6 +18,7 @@ package kubernetes import ( "context" + "github.com/radius-project/radius/pkg/cli/kubernetes" "github.com/radius-project/radius/pkg/cli/cmd/commonflags" @@ -91,13 +92,23 @@ func (r *Runner) Run(ctx context.Context) error { if err != nil { return err } - if !state.Installed { + if !state.RadiusInstalled { r.Output.LogInfo("Radius is not installed on the Kubernetes cluster") return nil } r.Output.LogInfo("Uninstalling Radius...") - err = r.Helm.UninstallRadius(ctx, r.KubeContext) + err = r.Helm.UninstallRadius(ctx, helm.ClusterOptions{ + Radius: helm.ChartOptions{ + Namespace: helm.RadiusSystemNamespace, + ReleaseName: helm.NewDefaultClusterOptions().Radius.ReleaseName, + }, + Dapr: helm.ChartOptions{ + Namespace: helm.DaprSystemNamespace, + ReleaseName: helm.NewDefaultClusterOptions().Dapr.ReleaseName, + }, + }, r.KubeContext) + if err != nil { return err } diff --git a/pkg/cli/cmd/uninstall/kubernetes/kubernetes_test.go b/pkg/cli/cmd/uninstall/kubernetes/kubernetes_test.go index 68a1c7275a..17d7bf4b83 100644 --- a/pkg/cli/cmd/uninstall/kubernetes/kubernetes_test.go +++ b/pkg/cli/cmd/uninstall/kubernetes/kubernetes_test.go @@ -18,9 +18,10 @@ package kubernetes import ( "context" - "github.com/radius-project/radius/pkg/cli/kubernetes" "testing" + "github.com/radius-project/radius/pkg/cli/kubernetes" + "github.com/radius-project/radius/pkg/cli/helm" "github.com/radius-project/radius/pkg/cli/output" "github.com/radius-project/radius/test/radcli" @@ -68,10 +69,19 @@ func Test_Run(t *testing.T) { } helmMock.EXPECT().CheckRadiusInstall("test-context"). - Return(helm.InstallState{Installed: true, Version: "test-version"}, nil). + Return(helm.InstallState{RadiusInstalled: true, RadiusVersion: "test-version", DaprInstalled: true, DaprVersion: "test-version"}, nil). Times(1) - helmMock.EXPECT().UninstallRadius(ctx, "test-context"). + helmMock.EXPECT().UninstallRadius(ctx, helm.ClusterOptions{ + Radius: helm.ChartOptions{ + Namespace: "radius-system", + ReleaseName: "radius", + }, + Dapr: helm.ChartOptions{ + Namespace: "dapr-system", + ReleaseName: "dapr", + }, + }, "test-context"). Return(nil). Times(1) @@ -116,7 +126,7 @@ func Test_Run(t *testing.T) { } require.Equal(t, expectedWrites, outputMock.Writes) }) - t.Run("Success: Installed -> Uninstalled -> Purge)", func(t *testing.T) { + t.Run("Success: Installed -> Uninstalled -> Purge", func(t *testing.T) { ctrl := gomock.NewController(t) helmMock := helm.NewMockInterface(ctrl) outputMock := &output.MockOutput{} @@ -133,10 +143,19 @@ func Test_Run(t *testing.T) { } helmMock.EXPECT().CheckRadiusInstall("test-context"). - Return(helm.InstallState{Installed: true, Version: "test-version"}, nil). + Return(helm.InstallState{RadiusInstalled: true, RadiusVersion: "test-version", DaprInstalled: true, DaprVersion: "test-version"}, nil). Times(1) - helmMock.EXPECT().UninstallRadius(ctx, "test-context"). + helmMock.EXPECT().UninstallRadius(ctx, helm.ClusterOptions{ + Radius: helm.ChartOptions{ + Namespace: "radius-system", + ReleaseName: "radius", + }, + Dapr: helm.ChartOptions{ + Namespace: "dapr-system", + ReleaseName: "dapr", + }, + }, "test-context"). Return(nil). Times(1) diff --git a/pkg/cli/cmd/workspace/create/create.go b/pkg/cli/cmd/workspace/create/create.go index c83f662c7f..64e77f154b 100644 --- a/pkg/cli/cmd/workspace/create/create.go +++ b/pkg/cli/cmd/workspace/create/create.go @@ -127,7 +127,7 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { } state, err := r.HelmInterface.CheckRadiusInstall(context) - if !state.Installed || err != nil { + if !state.RadiusInstalled || err != nil { return fmt.Errorf("unable to create workspace %q. Radius control plane not installed on target platform. Run 'rad install' and try again", workspaceName) } diff --git a/pkg/cli/cmd/workspace/create/create_test.go b/pkg/cli/cmd/workspace/create/create_test.go index 2d3afccffa..7929acfbc8 100644 --- a/pkg/cli/cmd/workspace/create/create_test.go +++ b/pkg/cli/cmd/workspace/create/create_test.go @@ -70,7 +70,7 @@ func Test_Validate(t *testing.T) { ConfigureMocks: func(mocks radcli.ValidateMocks) { // We have a valid kubernetes context, but Radius is not installed mocks.Kubernetes.EXPECT().GetKubeContext().Return(getTestKubeConfig(), nil).Times(1) - mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{Installed: false}, nil).Times(1) + mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{RadiusInstalled: false}, nil).Times(1) }, }, { @@ -84,7 +84,7 @@ func Test_Validate(t *testing.T) { ConfigureMocks: func(mocks radcli.ValidateMocks) { // We have a valid kubernetes context with Radius installed mocks.Kubernetes.EXPECT().GetKubeContext().Return(getTestKubeConfig(), nil).Times(1) - mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{Installed: true}, nil).Times(1) + mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{RadiusInstalled: true}, nil).Times(1) // Resource group does not exist mocks.ApplicationManagementClient.EXPECT().GetResourceGroup(gomock.Any(), "local", "rg1").Return(ucp.ResourceGroupResource{}, errors.New("group does not exist")).Times(1) @@ -101,7 +101,7 @@ func Test_Validate(t *testing.T) { ConfigureMocks: func(mocks radcli.ValidateMocks) { // We have a valid kubernetes context with Radius installed mocks.Kubernetes.EXPECT().GetKubeContext().Return(getTestKubeConfig(), nil).Times(1) - mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{Installed: true}, nil).Times(1) + mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{RadiusInstalled: true}, nil).Times(1) // Resource group exists but environment does not mocks.ApplicationManagementClient.EXPECT().GetResourceGroup(gomock.Any(), "local", "rg1").Return(ucp.ResourceGroupResource{}, nil).Times(1) @@ -119,7 +119,7 @@ func Test_Validate(t *testing.T) { ConfigureMocks: func(mocks radcli.ValidateMocks) { // We have a valid kubernetes context with Radius installed mocks.Kubernetes.EXPECT().GetKubeContext().Return(getTestKubeConfig(), nil).Times(1) - mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{Installed: true}, nil).Times(1) + mocks.Helm.EXPECT().CheckRadiusInstall(gomock.Any()).Return(helm.InstallState{RadiusInstalled: true}, nil).Times(1) // Resource group and environment exist mocks.ApplicationManagementClient.EXPECT().GetResourceGroup(gomock.Any(), "local", "rg1").Return(ucp.ResourceGroupResource{}, nil).Times(1) diff --git a/pkg/cli/helm/cluster.go b/pkg/cli/helm/cluster.go index 1b918071b8..c4e07a872f 100644 --- a/pkg/cli/helm/cluster.go +++ b/pkg/cli/helm/cluster.go @@ -31,15 +31,17 @@ import ( const ( ContourChartDefaultVersion = "11.1.1" + DaprChartDefaultVersion = "1.14.4" ) type CLIClusterOptions struct { - Radius RadiusOptions + Radius ChartOptions } type ClusterOptions struct { Contour ContourOptions - Radius RadiusOptions + Radius ChartOptions + Dapr ChartOptions } // NewDefaultClusterOptions sets the default values for the ClusterOptions struct, using the chart version that matches @@ -56,8 +58,17 @@ func NewDefaultClusterOptions() ClusterOptions { Contour: ContourOptions{ ChartVersion: ContourChartDefaultVersion, }, - Radius: RadiusOptions{ + Radius: ChartOptions{ ChartVersion: chartVersion, + Namespace: RadiusSystemNamespace, + ReleaseName: radiusReleaseName, + ChartRepo: radiusHelmRepo, + }, + Dapr: ChartOptions{ + ChartVersion: DaprChartDefaultVersion, + Namespace: DaprSystemNamespace, + ReleaseName: daprReleaseName, + ChartRepo: daprHelmRepo, }, } } @@ -87,49 +98,44 @@ func PopulateDefaultClusterOptions(cliOptions CLIClusterOptions) ClusterOptions return options } -// InstallRadius installs Radius on the cluster, based on the specified Kubernetes context. -// - // Install takes in a context, clusterOptions and kubeContext and returns a boolean and an error. If an // error is encountered, it is returned. func Install(ctx context.Context, clusterOptions ClusterOptions, kubeContext string) (bool, error) { - foundExisting, err := InstallOnCluster(ctx, clusterOptions, kubeContext) - if err != nil { - return false, err - } - - return foundExisting, nil -} - -// InstallOnCluster applies the Helm charts for Radius and Contour to the cluster, and returns whether an existing -// installation was found. If an error occurs, it is returned. -func InstallOnCluster(ctx context.Context, options ClusterOptions, kubeContext string) (bool, error) { // Do note: the namespace passed in to rad install kubernetes // doesn't match the namespace where we deploy radius. // The RPs and other resources are all deployed to the // 'radius-system' namespace. The namespace passed in will be // where pods/services/deployments will be put for rad deploy. - foundExisting, err := ApplyRadiusHelmChart(options.Radius, kubeContext) + radiusFound, err := ApplyHelmChart(clusterOptions.Radius, kubeContext) if err != nil { return false, err } - err = ApplyContourHelmChart(options.Contour, kubeContext) + // Install Dapr + daprFound, err := ApplyHelmChart(clusterOptions.Dapr, kubeContext) if err != nil { return false, err } - return foundExisting, err + err = ApplyContourHelmChart(clusterOptions.Contour, kubeContext) + if err != nil { + return false, err + } + // If both Radius and Dapr are installed, return true + if radiusFound && daprFound { + return true, err + } else { + return false, err + } } // UninstallOnCluster retrieves the Helm configuration and runs the Contour and Radius Helm uninstall commands to remove // the Helm releases from the cluster. -func UninstallOnCluster(kubeContext string) error { +func UninstallOnCluster(kubeContext string, clusterOptions ClusterOptions) error { var helmOutput strings.Builder - namespace := RadiusSystemNamespace flags := genericclioptions.ConfigFlags{ - Namespace: &namespace, + Namespace: &clusterOptions.Radius.Namespace, Context: &kubeContext, } @@ -143,7 +149,23 @@ func UninstallOnCluster(kubeContext string) error { return err } - err = RunRadiusHelmUninstall(helmConf) + // Uninstall Radius + err = RunHelmUninstall(helmConf, clusterOptions.Radius) + if err != nil { + return err + } + + // Uninstall Dapr + daprFlags := genericclioptions.ConfigFlags{ + Namespace: &clusterOptions.Dapr.Namespace, + Context: &kubeContext, + } + + daprHelmConf, err := HelmConfig(&helmOutput, &daprFlags) + if err != nil { + return fmt.Errorf("failed to get helm config, err: %w, helm output: %s", err, helmOutput.String()) + } + err = RunHelmUninstall(daprHelmConf, clusterOptions.Dapr) if err != nil { return err } @@ -151,15 +173,12 @@ func UninstallOnCluster(kubeContext string) error { return nil } -// CheckRadiusInstall checks whether Radius is installed on the cluster, based on the specified Kubernetes context. -// - -// CheckRadiusInstall checks if the Radius release is installed in the given kubeContext and returns an InstallState object -// with the version of the release if installed, or an error if an error occurs while checking. -func CheckRadiusInstall(kubeContext string) (InstallState, error) { +// queryRelease checks to see if a release is deployed to a namespace for a given kubecontext. +// If the release is found, it returns true and the version of the release. If the release is not found, it returns false. +// If an error occurs, it returns an error. +func queryRelease(kubeContext, namespace, releaseName string) (bool, string, error) { var helmOutput strings.Builder - namespace := RadiusSystemNamespace flags := genericclioptions.ConfigFlags{ Namespace: &namespace, Context: &kubeContext, @@ -167,31 +186,54 @@ func CheckRadiusInstall(kubeContext string) (InstallState, error) { helmConf, err := HelmConfig(&helmOutput, &flags) if err != nil { - return InstallState{}, fmt.Errorf("failed to get helm config, err: %w, helm output: %s", err, helmOutput.String()) + return false, "", fmt.Errorf("failed to get helm config, err: %w, helm output: %s", err, helmOutput.String()) } histClient := helmaction.NewHistory(helmConf) histClient.Max = 1 // Only need to check if at least 1 exists - releases, err := histClient.Run(radiusReleaseName) + releases, err := histClient.Run(releaseName) if errors.Is(err, driver.ErrReleaseNotFound) { - return InstallState{}, nil + return false, "", nil } else if err != nil { - return InstallState{}, err + return false, "", err } else if len(releases) == 0 { - return InstallState{}, nil + return false, "", nil + } + + return true, releases[0].Chart.Metadata.Version, nil +} + +// CheckRadiusInstall checks if the Radius release is installed in the given kubeContext and returns an InstallState object +// with the version of the release if installed, or an error if an error occurs while checking. +func CheckRadiusInstall(kubeContext string) (InstallState, error) { + // Check if Radius is installed + radiusInstalled, radiusVersion, err := queryRelease(kubeContext, RadiusSystemNamespace, radiusReleaseName) + if err != nil { + return InstallState{}, err } - version := releases[0].Chart.Metadata.Version - return InstallState{Installed: true, Version: version}, nil + // Check is Dapr is installed + daprInstalled, daprVersion, err := queryRelease(kubeContext, DaprSystemNamespace, daprReleaseName) + if err != nil { + return InstallState{}, err + } + + return InstallState{RadiusInstalled: radiusInstalled, RadiusVersion: radiusVersion, DaprInstalled: daprInstalled, DaprVersion: daprVersion}, nil } // InstallState represents the state of the Radius helm chart installation on a Kubernetes cluster. type InstallState struct { - // Installed denotes whether the Radius helm chart is installed on the cluster. - Installed bool + // RadiusInstalled denotes whether the Radius helm chart is installed on the cluster. + RadiusInstalled bool + + // RadiusVersion is the version of the Radius helm chart installed on the cluster. Will be blank if Radius is not installed. + RadiusVersion string + + // DaprInstalled denotes whether the Dapr helm chart is installed on the cluster. + DaprInstalled bool - // Version is the version of the Radius helm chart installed on the cluster. Will be blank if Radius is not installed. - Version string + // DaprVersion is the version of the Dapr helm chart installed on the cluster. Will be blank if Dapr is not installed. + DaprVersion string } //go:generate mockgen -typed -destination=./mock_cluster.go -package=helm -self_package github.com/radius-project/radius/pkg/cli/helm github.com/radius-project/radius/pkg/cli/helm Interface @@ -205,7 +247,7 @@ type Interface interface { InstallRadius(ctx context.Context, clusterOptions ClusterOptions, kubeContext string) (bool, error) // UninstallRadius uninstalls Radius from the cluster based on the specified Kubernetes context. Will succeed regardless of whether Radius is installed. - UninstallRadius(ctx context.Context, kubeContext string) error + UninstallRadius(ctx context.Context, clusterOptions ClusterOptions, kubeContext string) error } type Impl struct { @@ -222,6 +264,6 @@ func (i *Impl) InstallRadius(ctx context.Context, clusterOptions ClusterOptions, } // UninstallRadius uninstalls RADIUS from the specified Kubernetes cluster, and returns an error if it fails. -func (i *Impl) UninstallRadius(ctx context.Context, kubeContext string) error { - return UninstallOnCluster(kubeContext) +func (i *Impl) UninstallRadius(ctx context.Context, clusterOptions ClusterOptions, kubeContext string) error { + return UninstallOnCluster(kubeContext, clusterOptions) } diff --git a/pkg/cli/helm/cluster_test.go b/pkg/cli/helm/cluster_test.go index fe82ba5a31..467c3f8b62 100644 --- a/pkg/cli/helm/cluster_test.go +++ b/pkg/cli/helm/cluster_test.go @@ -25,7 +25,7 @@ import ( func Test_CanSetCLIOptions(t *testing.T) { cliOptions := CLIClusterOptions{ - Radius: RadiusOptions{ + Radius: ChartOptions{ ChartPath: "chartpath", Reinstall: true, }, diff --git a/pkg/cli/helm/radiusclient.go b/pkg/cli/helm/helmclient.go similarity index 73% rename from pkg/cli/helm/radiusclient.go rename to pkg/cli/helm/helmclient.go index 9b616b1000..91a31f1cb6 100644 --- a/pkg/cli/helm/radiusclient.go +++ b/pkg/cli/helm/helmclient.go @@ -38,10 +38,23 @@ const ( radiusReleaseName = "radius" radiusHelmRepo = "oci://ghcr.io/radius-project/helm-chart" RadiusSystemNamespace = "radius-system" + + daprReleaseName = "dapr" + daprHelmRepo = "https://dapr.github.io/helm-charts" + DaprSystemNamespace = "dapr-system" ) -// RadiusOptions describes the options for the Radius helm chart. -type RadiusOptions struct { +// ChartOptions describes the options for the a helm chart. +type ChartOptions struct { + // Target namespace for deployment + Namespace string + + // ReleaseName specifies the release name for the helm chart. + ReleaseName string + + // ChartRepo specifies the helm chart repository. + ChartRepo string + // Reinstall specifies whether to reinstall the chart (helm upgrade). Reinstall bool @@ -59,18 +72,15 @@ type RadiusOptions struct { SetFileArgs []string } -// Apply the radius helm chart. -// - -// ApplyRadiusHelmChart checks if a Helm chart is already installed, and if not, installs it or upgrades it if the +// ApplyHelmChart checks if a Helm chart is already installed, and if not, installs it or upgrades it if the // "Reinstall" option is set. It returns a boolean indicating if the chart was already installed and an error if one occurred. -func ApplyRadiusHelmChart(options RadiusOptions, kubeContext string) (bool, error) { +func ApplyHelmChart(options ChartOptions, kubeContext string) (bool, error) { // For capturing output from helm. var helmOutput strings.Builder alreadyInstalled := false - namespace := RadiusSystemNamespace + flags := genericclioptions.ConfigFlags{ - Namespace: &namespace, + Namespace: &options.Namespace, Context: &kubeContext, } @@ -81,7 +91,7 @@ func ApplyRadiusHelmChart(options RadiusOptions, kubeContext string) (bool, erro var helmChart *chart.Chart if options.ChartPath == "" { - helmChart, err = helmChartFromContainerRegistry(options.ChartVersion, helmConf, radiusHelmRepo, radiusReleaseName) + helmChart, err = helmChartFromContainerRegistry(options.ChartVersion, helmConf, options.ChartRepo, options.ReleaseName) } else { helmChart, err = loader.Load(options.ChartPath) } @@ -90,7 +100,7 @@ func ApplyRadiusHelmChart(options RadiusOptions, kubeContext string) (bool, erro return false, fmt.Errorf("failed to load Helm chart, err: %w, Helm output: %s", err, helmOutput.String()) } - err = AddRadiusValues(helmChart, &options) + err = AddValues(helmChart, &options) if err != nil { return false, fmt.Errorf("failed to add Radius values, err: %w, Helm output: %s", err, helmOutput.String()) } @@ -107,14 +117,14 @@ func ApplyRadiusHelmChart(options RadiusOptions, kubeContext string) (bool, erro // See: https://github.com/helm/helm/blob/281380f31ccb8eb0c86c84daf8bcbbd2f82dc820/cmd/helm/upgrade.go#L99 // The upgrade client's install option doesn't seem to work, so we have to check the history of releases manually // and invoke the install client. - _, err = histClient.Run(radiusReleaseName) + _, err = histClient.Run(options.ReleaseName) if errors.Is(err, driver.ErrReleaseNotFound) { - err = runRadiusHelmInstall(helmConf, helmChart) + err = runHelmInstall(helmConf, helmChart, options) if err != nil { return false, fmt.Errorf("failed to run Radius Helm install, err: \n%w\nHelm output:\n%s", err, helmOutput.String()) } } else if options.Reinstall { - err = runRadiusHelmUpgrade(helmConf, radiusReleaseName, helmChart) + err = runHelmUpgrade(helmConf, options.ReleaseName, helmChart, options) if err != nil { return false, fmt.Errorf("failed to run Radius Helm upgrade, err: \n%w\nHelm output:\n%s", err, helmOutput.String()) } @@ -124,14 +134,9 @@ func ApplyRadiusHelmChart(options RadiusOptions, kubeContext string) (bool, erro return alreadyInstalled, err } -// AddRadiusValues adds values to the helm chart. It overrides the default values in following order: -// 1. lowest priority: Values from the helm chart default values.yaml -// 2. highest priority: Values by the --set flag potentially overwriting values from step 1 and 2 -// - -// AddRadiusValues parses the --set arguments in order and adds them to the helm chart values, returning an error if any of +// AddValues parses the --set arguments in order and adds them to the helm chart values, returning an error if any of // the arguments are invalid. -func AddRadiusValues(helmChart *chart.Chart, options *RadiusOptions) error { +func AddValues(helmChart *chart.Chart, options *ChartOptions) error { values := helmChart.Values // Parse --set arguments in order so that the last one wins. @@ -161,35 +166,35 @@ func AddRadiusValues(helmChart *chart.Chart, options *RadiusOptions) error { return nil } -func runRadiusHelmInstall(helmConf *helm.Configuration, helmChart *chart.Chart) error { +func runHelmInstall(helmConf *helm.Configuration, helmChart *chart.Chart, options ChartOptions) error { installClient := helm.NewInstall(helmConf) - installClient.ReleaseName = radiusReleaseName - installClient.Namespace = RadiusSystemNamespace + installClient.ReleaseName = options.ReleaseName + installClient.Namespace = options.Namespace installClient.CreateNamespace = true installClient.Wait = true installClient.Timeout = installTimeout return runInstall(installClient, helmChart) } -func runRadiusHelmUpgrade(helmConf *helm.Configuration, releaseName string, helmChart *chart.Chart) error { +func runHelmUpgrade(helmConf *helm.Configuration, releaseName string, helmChart *chart.Chart, options ChartOptions) error { installClient := helm.NewUpgrade(helmConf) - installClient.Namespace = RadiusSystemNamespace + installClient.Namespace = options.Namespace installClient.Wait = true installClient.Timeout = installTimeout installClient.Recreate = true //force recreating radius pods on adding or modfying azprovider - return runUpgrade(installClient, releaseName, helmChart) + return runUpgrade(installClient, options.ReleaseName, helmChart) } // RunRadiusHelmUninstall attempts to uninstall Radius from the Radius system namespace // using a helm configuration, and returns an error if the uninstall fails. -func RunRadiusHelmUninstall(helmConf *helm.Configuration) error { - output.LogInfo("Uninstalling Radius from namespace: %s", RadiusSystemNamespace) +func RunHelmUninstall(helmConf *helm.Configuration, options ChartOptions) error { + output.LogInfo("Uninstalling %s from namespace: %s", options.ReleaseName, options.Namespace) uninstallClient := helm.NewUninstall(helmConf) uninstallClient.Timeout = uninstallTimeout uninstallClient.Wait = true - _, err := uninstallClient.Run(radiusReleaseName) + _, err := uninstallClient.Run(options.ReleaseName) if errors.Is(err, driver.ErrReleaseNotFound) { - output.LogInfo("Radius not found") + output.LogInfo("%s not found", options.ReleaseName) return nil } return err diff --git a/pkg/cli/helm/radiusclient_test.go b/pkg/cli/helm/helmclient_test.go similarity index 93% rename from pkg/cli/helm/radiusclient_test.go rename to pkg/cli/helm/helmclient_test.go index de85a80c60..8e35bba167 100644 --- a/pkg/cli/helm/radiusclient_test.go +++ b/pkg/cli/helm/helmclient_test.go @@ -24,15 +24,15 @@ import ( "helm.sh/helm/v3/pkg/chart" ) -func Test_AddRadiusValues(t *testing.T) { +func Test_AddValues(t *testing.T) { var helmChart chart.Chart helmChart.Values = map[string]any{} - options := &RadiusOptions{ + options := &ChartOptions{ SetArgs: []string{"global.zipkin.url=url,global.prometheus.path=path"}, SetFileArgs: []string{"global.rootCA.cert=./testdata/fake-ca-cert.crt"}, } - err := AddRadiusValues(&helmChart, options) + err := AddValues(&helmChart, options) require.Equal(t, err, nil) values := helmChart.Values @@ -62,11 +62,11 @@ func Test_AddRadiusValues(t *testing.T) { func Test_AddRadiusValuesOverrideWithSet(t *testing.T) { var helmChart chart.Chart helmChart.Values = map[string]any{} - options := &RadiusOptions{ + options := &ChartOptions{ SetArgs: []string{"rp.image=ghcr.io/radius-project/applications-rp,rp.tag=latest", "global.zipkin.url=url,global.prometheus.path=path"}, } - err := AddRadiusValues(&helmChart, options) + err := AddValues(&helmChart, options) require.Equal(t, err, nil) values := helmChart.Values diff --git a/pkg/cli/helm/mock_cluster.go b/pkg/cli/helm/mock_cluster.go index 4a0a1e05e8..c4d2e9053c 100644 --- a/pkg/cli/helm/mock_cluster.go +++ b/pkg/cli/helm/mock_cluster.go @@ -118,17 +118,17 @@ func (c *MockInterfaceInstallRadiusCall) DoAndReturn(f func(context.Context, Clu } // UninstallRadius mocks base method. -func (m *MockInterface) UninstallRadius(arg0 context.Context, arg1 string) error { +func (m *MockInterface) UninstallRadius(arg0 context.Context, arg1 ClusterOptions, arg2 string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallRadius", arg0, arg1) + ret := m.ctrl.Call(m, "UninstallRadius", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // UninstallRadius indicates an expected call of UninstallRadius. -func (mr *MockInterfaceMockRecorder) UninstallRadius(arg0, arg1 any) *MockInterfaceUninstallRadiusCall { +func (mr *MockInterfaceMockRecorder) UninstallRadius(arg0, arg1, arg2 any) *MockInterfaceUninstallRadiusCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallRadius", reflect.TypeOf((*MockInterface)(nil).UninstallRadius), arg0, arg1) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallRadius", reflect.TypeOf((*MockInterface)(nil).UninstallRadius), arg0, arg1, arg2) return &MockInterfaceUninstallRadiusCall{Call: call} } @@ -144,13 +144,13 @@ func (c *MockInterfaceUninstallRadiusCall) Return(arg0 error) *MockInterfaceUnin } // Do rewrite *gomock.Call.Do -func (c *MockInterfaceUninstallRadiusCall) Do(f func(context.Context, string) error) *MockInterfaceUninstallRadiusCall { +func (c *MockInterfaceUninstallRadiusCall) Do(f func(context.Context, ClusterOptions, string) error) *MockInterfaceUninstallRadiusCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockInterfaceUninstallRadiusCall) DoAndReturn(f func(context.Context, string) error) *MockInterfaceUninstallRadiusCall { +func (c *MockInterfaceUninstallRadiusCall) DoAndReturn(f func(context.Context, ClusterOptions, string) error) *MockInterfaceUninstallRadiusCall { c.Call = c.Call.DoAndReturn(f) return c }