diff --git a/e2e/README.md b/e2e/README.md index 45290b878f..9a29ccff33 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -44,17 +44,6 @@ make e2e \ KOTSADM_IMAGE_TAG=24h ``` -To run a helm-managed mode test: - -*Note the admin console helm chart is maintained in a [separate repo](https://github.com/replicatedhq/kots-helm)* - -```bash -make e2e \ - FOCUS="Helm Managed" - KOTS_HELM_CHART_URL=oci://ttl.sh/$USER/admin-console - KOTS_HELM_CHART_VERSION=$VERSION -``` - To run using a specific testim branch: ```bash make e2e \ diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index b0017131cf..250c399661 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -3,7 +3,6 @@ package e2e import ( "context" "flag" - "fmt" "os" "testing" "time" @@ -178,18 +177,8 @@ var _ = Describe("E2E", func() { prometheus.Install(helmCLI, c.GetKubeconfig()) } - var adminConsolePort string - if test.IsHelmManaged { - GinkgoWriter.Println("Installing KOTS Helm chart") - session, err := helmCLI.Install(c.GetKubeconfig(), "-n", test.Namespace, "admin-console", kotsHelmChartURL, "--set", fmt.Sprintf("password=%s", inventory.HelmPassword), "--version", kotsHelmChartVersion, "--create-namespace", "--wait") - Expect(err).WithOffset(1).Should(Succeed(), "helm install") - Eventually(session).WithOffset(1).WithTimeout(time.Minute).Should(gexec.Exit(0), "helm install failed with non-zero exit code") - - adminConsolePort = kotsInstaller.AdminConsolePortForward(c.GetKubeconfig(), test, kotsadmForwardPort) - } else { - GinkgoWriter.Println("Installing KOTS") - adminConsolePort = kotsInstaller.Install(c.GetKubeconfig(), test, kotsadmForwardPort) - } + GinkgoWriter.Println("Installing KOTS") + adminConsolePort := kotsInstaller.Install(c.GetKubeconfig(), test, kotsadmForwardPort) GinkgoWriter.Println("Running E2E tests") @@ -223,7 +212,6 @@ var _ = Describe("E2E", func() { Entry(nil, inventory.NewNoRequiredConfig()), Entry(nil, inventory.NewVersionHistoryPagination()), Entry(nil, inventory.NewChangeLicense()), - Entry(nil, inventory.NewHelmManagedMode()), Entry(nil, inventory.NewMinKotsVersion()), Entry(nil, inventory.NewTargetKotsVersion()), Entry(nil, inventory.NewRangeKotsVersion()), diff --git a/e2e/inventory/inventory.go b/e2e/inventory/inventory.go index e1607ec401..7b2affdff8 100644 --- a/e2e/inventory/inventory.go +++ b/e2e/inventory/inventory.go @@ -102,17 +102,6 @@ func NewChangeLicense() Test { } } -func NewHelmManagedMode() Test { - return Test{ - Name: "Helm Managed", - TestimSuite: "helm-managed", - Namespace: "helm-managed", - UpstreamURI: "helm-managed/automated", - IsHelmManaged: true, - Setup: SetupHelmManagedMode, - } -} - func NewMultiAppBackupAndRestoreTest() Test { return Test{ Name: "multi-app-backup-and-restore", @@ -197,10 +186,3 @@ func SetupRegressionTest(kubectlCLI *kubectl.CLI) TestimParams { Eventually(session).WithOffset(1).WithTimeout(30*time.Minute).Should(gexec.Exit(0), "Create registry-creds secret failed with non-zero exit code") return nil } - -func SetupHelmManagedMode(kubectlCLI *kubectl.CLI) TestimParams { - return TestimParams{ - "kotsadmPassword": HelmPassword, - "kotsadmNamespace": "helm-managed", - } -} diff --git a/e2e/inventory/test.go b/e2e/inventory/test.go index fdcab9a498..1fe11735d0 100644 --- a/e2e/inventory/test.go +++ b/e2e/inventory/test.go @@ -18,6 +18,5 @@ type Test struct { NeedsSnapshots bool NeedsMonitoring bool NeedsRegistry bool - IsHelmManaged bool Setup func(kubectlCLI *kubectl.CLI) TestimParams } diff --git a/pkg/api/handlers/types/types.go b/pkg/api/handlers/types/types.go index 6df5a0a619..9572c3e350 100644 --- a/pkg/api/handlers/types/types.go +++ b/pkg/api/handlers/types/types.go @@ -13,10 +13,6 @@ type ListAppsResponse struct { Apps []ResponseApp `json:"apps"` } -type ListAppsHelmResponse struct { - Apps []HelmResponseApp `json:"apps"` -} - type AppStatusResponse struct { AppStatus *appstatetypes.AppStatus `json:"appstatus"` } @@ -58,12 +54,6 @@ type Credentials struct { Password string `json:"password"` } -type HelmResponseApp struct { - ResponseApp - ChartPath string `json:"chartPath,omitempty"` - Credentials Credentials `json:"credentials"` -} - type ResponseDownstream struct { Name string `json:"name"` Links []versiontypes.RealizedLink `json:"links"` diff --git a/pkg/apiserver/bootstrap.go b/pkg/apiserver/bootstrap.go index 90d0a746ac..29d5f7ff49 100644 --- a/pkg/apiserver/bootstrap.go +++ b/pkg/apiserver/bootstrap.go @@ -9,7 +9,6 @@ import ( "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/store" - "github.com/replicatedhq/kots/pkg/util" ) type BootstrapParams struct { @@ -21,13 +20,11 @@ func bootstrap(params BootstrapParams) error { return errors.Wrap(err, "failed to init store") } - if !util.IsHelmManaged() { - if err := bootstrapClusterToken(params.AutoCreateClusterToken); err != nil { - return errors.Wrap(err, "failed to bootstrap cluster token") - } - if err := loadEncryptionKeys(); err != nil { - return errors.Wrap(err, "failed to load encryption keys") - } + if err := bootstrapClusterToken(params.AutoCreateClusterToken); err != nil { + return errors.Wrap(err, "failed to bootstrap cluster token") + } + if err := loadEncryptionKeys(); err != nil { + return errors.Wrap(err, "failed to load encryption keys") } return nil diff --git a/pkg/apiserver/server.go b/pkg/apiserver/server.go index e13962e0d2..9323aa32c2 100644 --- a/pkg/apiserver/server.go +++ b/pkg/apiserver/server.go @@ -15,12 +15,11 @@ import ( "github.com/replicatedhq/kots/pkg/binaries" "github.com/replicatedhq/kots/pkg/embeddedcluster" "github.com/replicatedhq/kots/pkg/handlers" - "github.com/replicatedhq/kots/pkg/helm" identitymigrate "github.com/replicatedhq/kots/pkg/identity/migrate" "github.com/replicatedhq/kots/pkg/informers" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/operator" - "github.com/replicatedhq/kots/pkg/operator/client" + operatorclient "github.com/replicatedhq/kots/pkg/operator/client" "github.com/replicatedhq/kots/pkg/persistence" "github.com/replicatedhq/kots/pkg/policy" "github.com/replicatedhq/kots/pkg/rbac" @@ -44,24 +43,20 @@ type APIServerParams struct { func Start(params *APIServerParams) { log.Printf("kotsadm version %s\n", params.Version) - if !util.IsHelmManaged() { - // set some persistence variables - persistence.InitDB(params.RqliteURI) + // set some persistence variables + persistence.InitDB(params.RqliteURI) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - if err := store.GetStore().WaitForReady(ctx); err != nil { - log.Println("error waiting for ready") - panic(err) - } - cancel() + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + if err := store.GetStore().WaitForReady(ctx); err != nil { + log.Println("error waiting for ready") + panic(err) } + cancel() // check if we need to migrate from postgres before doing anything else - if !util.IsHelmManaged() { - if err := persistence.MigrateFromPostgresToRqlite(); err != nil { - log.Println("error migrating from postgres to rqlite") - panic(err) - } + if err := persistence.MigrateFromPostgresToRqlite(); err != nil { + log.Println("error migrating from postgres to rqlite") + panic(err) } if err := bootstrap(BootstrapParams{ @@ -71,11 +66,9 @@ func Start(params *APIServerParams) { panic(err) } - if !util.IsHelmManaged() { - store.GetStore().RunMigrations() - if err := identitymigrate.RunMigrations(context.TODO(), util.PodNamespace); err != nil { - log.Println("Failed to run identity migrations: ", err) - } + store.GetStore().RunMigrations() + if err := identitymigrate.RunMigrations(context.TODO(), util.PodNamespace); err != nil { + log.Println("Failed to run identity migrations: ", err) } if err := binaries.InitKubectl(); err != nil { @@ -88,28 +81,27 @@ func Start(params *APIServerParams) { panic(err) } - if !util.IsHelmManaged() { - client := &client.Client{ - TargetNamespace: util.AppNamespace(), - ExistingHookInformers: map[string]bool{}, - HookStopChans: []chan struct{}{}, - } - store := store.GetStore() - k8sClientset, err := k8sutil.GetClientset() - if err != nil { - log.Println("error getting k8s clientset") - panic(err) - } - op := operator.Init(client, store, params.AutocreateClusterToken, k8sClientset) - if err := op.Start(); err != nil { - log.Println("error starting the operator") - panic(err) - } - defer op.Shutdown() + kotsStore := store.GetStore() - if err := embeddedcluster.InitClusterState(context.TODO(), k8sClientset, store); err != nil { - log.Println("Failed to initialize cluster state:", err) - } + operatorClient := &operatorclient.Client{ + TargetNamespace: util.AppNamespace(), + ExistingHookInformers: map[string]bool{}, + HookStopChans: []chan struct{}{}, + } + k8sClientset, err := k8sutil.GetClientset() + if err != nil { + log.Println("error getting k8s clientset") + panic(err) + } + op := operator.Init(operatorClient, kotsStore, params.AutocreateClusterToken, k8sClientset) + if err := op.Start(); err != nil { + log.Println("error starting the operator") + panic(err) + } + defer op.Shutdown() + + if err := embeddedcluster.InitClusterState(context.TODO(), k8sClientset, kotsStore); err != nil { + log.Println("Failed to initialize cluster state:", err) } if params.SharedPassword != "" { @@ -136,13 +128,11 @@ func Start(params *APIServerParams) { log.Println("Failed to start informers:", err) } - if !util.IsHelmManaged() { - if err := updatechecker.Start(); err != nil { - log.Println("Failed to start update checker:", err) - } - if err := snapshotscheduler.Start(); err != nil { - log.Println("Failed to start snapshot scheduler:", err) - } + if err := updatechecker.Start(); err != nil { + log.Println("Failed to start update checker:", err) + } + if err := snapshotscheduler.Start(); err != nil { + log.Println("Failed to start snapshot scheduler:", err) } if err := session.StartSessionPurgeCronJob(); err != nil { @@ -159,12 +149,6 @@ func Start(params *APIServerParams) { } } - if util.IsHelmManaged() { - if err := helm.Init(context.TODO()); err != nil { - log.Println("Failed to initialize helm data: ", err) - } - } - r := mux.NewRouter() r.Use(handlers.CorsMiddleware) @@ -178,8 +162,6 @@ func Start(params *APIServerParams) { handler := &handlers.Handler{} - kotsStore := store.GetStore() - /********************************************************************** * Unauthenticated routes **********************************************************************/ diff --git a/pkg/app/types/helm_app.go b/pkg/app/types/helm_app.go deleted file mode 100644 index 9d4df17407..0000000000 --- a/pkg/app/types/helm_app.go +++ /dev/null @@ -1,42 +0,0 @@ -package types - -import ( - "time" - - appstatetypes "github.com/replicatedhq/kots/pkg/appstate/types" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - helmrelease "helm.sh/helm/v3/pkg/release" -) - -type HelmApp struct { - Release helmrelease.Release - Labels map[string]string - Version int64 // populated from labels - Namespace string - IsConfigurable bool - ChartPath string - CreationTimestamp time.Time - Status appstatetypes.AppStatus - // TODO: This is values the user is editing on the Config screen. This is a temporary solution while we figure out the UX. - TempConfigValues map[string]kotsv1beta1.ConfigValue -} - -func (a *HelmApp) GetID() string { - return a.Release.Name -} - -func (a *HelmApp) GetSlug() string { - return a.Release.Name -} - -func (a *HelmApp) GetCurrentSequence() int64 { - return a.Version -} - -func (a *HelmApp) GetIsAirgap() bool { - return false // no airgap support yet -} - -func (a *HelmApp) GetNamespace() string { - return a.Namespace -} diff --git a/pkg/app/types/types.go b/pkg/app/types/types.go index 6dcc9d71f6..4f5b902913 100644 --- a/pkg/app/types/types.go +++ b/pkg/app/types/types.go @@ -18,11 +18,3 @@ const ( AutoDeploySemverMajorMinorPatch AutoDeploy = "semver-major-minor-patch" AutoDeploySequence AutoDeploy = "sequence" ) - -type AppType interface { - GetID() string - GetSlug() string - GetCurrentSequence() int64 - GetIsAirgap() bool - GetNamespace() string -} diff --git a/pkg/filestore/blob_store.go b/pkg/filestore/blob_store.go index f724519c7d..ce8744ea83 100644 --- a/pkg/filestore/blob_store.go +++ b/pkg/filestore/blob_store.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/pkg/errors" - "github.com/replicatedhq/kots/pkg/util" ) var ( @@ -20,16 +19,6 @@ type BlobStore struct { } func (s *BlobStore) Init() error { - if util.IsHelmManaged() { - // Helm managed mode does not have any persisten storage. - dir, err := ioutil.TempDir("", "kotsadmdata-archives-") - if err != nil { - return errors.Wrapf(err, "failed to create ephemeral archives directory") - } - ArchivesDir = dir - return nil - } - err := os.MkdirAll(ArchivesDir, 0755) if err != nil { return errors.Wrapf(err, "failed to create archives directory") diff --git a/pkg/handlers/app.go b/pkg/handlers/app.go index 7e33e63190..522bd33766 100644 --- a/pkg/handlers/app.go +++ b/pkg/handlers/app.go @@ -17,7 +17,6 @@ import ( apptypes "github.com/replicatedhq/kots/pkg/app/types" "github.com/replicatedhq/kots/pkg/embeddedcluster" "github.com/replicatedhq/kots/pkg/gitops" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/logger" @@ -42,11 +41,6 @@ func (h *Handler) GetPendingApp(w http.ResponseWriter, r *http.Request) { return } - if util.IsHelmManaged() { - w.WriteHeader(http.StatusNotFound) - return - } - papp, err := store.GetStore().GetPendingAirgapUploadApp() if err != nil { if store.GetStore().IsNotFound(err) { @@ -100,33 +94,6 @@ func (h *Handler) ListApps(w http.ResponseWriter, r *http.Request) { return } - responseApps := []types.ResponseApp{} - if util.IsHelmManaged() { - helmResponseApps := []types.HelmResponseApp{} - - for _, releaseName := range helm.GetCachedHelmApps() { - release := helm.GetHelmApp(releaseName) - if release == nil { - continue - } - - app, err := helm.ResponseAppFromHelmApp(release) - if err != nil { - logger.Error(errors.Wrap(err, "failed to convert release to app")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - helmResponseApps = append(helmResponseApps, *app) - } - - listAppsResponse := types.ListAppsHelmResponse{ - Apps: helmResponseApps, - } - - JSON(w, http.StatusOK, listAppsResponse) - return - } apps, err := store.GetStore().ListInstalledApps() if err != nil { logger.Error(err) @@ -134,6 +101,7 @@ func (h *Handler) ListApps(w http.ResponseWriter, r *http.Request) { return } + responseApps := []types.ResponseApp{} defaultRoles := rbac.DefaultRoles() // TODO (ethan): this should be set in the handler for _, a := range apps { @@ -188,31 +156,13 @@ func (h *Handler) GetAppStatus(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetApp(w http.ResponseWriter, r *http.Request) { appSlug := mux.Vars(r)["appSlug"] - responseApp := new(types.ResponseApp) - if util.IsHelmManaged() { - release := helm.GetHelmApp(appSlug) - if release == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - app, err := helm.ResponseAppFromHelmApp(release) - if err != nil { - logger.Error(errors.Wrap(err, "failed to convert release to app")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - JSON(w, http.StatusOK, app) - return - } a, err := store.GetStore().GetAppFromSlug(appSlug) if err != nil { logger.Error(err) w.WriteHeader(http.StatusInternalServerError) return } - responseApp, err = responseAppFromApp(a) + responseApp, err := responseAppFromApp(a) if err != nil { logger.Error(err) w.WriteHeader(http.StatusInternalServerError) @@ -432,87 +382,37 @@ func (h *Handler) GetAppVersionHistory(w http.ResponseWriter, r *http.Request) { } appSlug := mux.Vars(r)["appSlug"] - history := new(downstreamtypes.DownstreamVersionHistory) - if util.IsHelmManaged() { - release := helm.GetHelmApp(appSlug) - if release == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - history.NumOfRemainingVersions = 0 - chartUpdates := helm.GetDownloadedUpdates(release.ChartPath) - - installedReleases, err := helm.ListChartVersions(appSlug, release.Namespace) - if err != nil { - err = errors.Wrapf(err, "failed to get installed releases of %s", appSlug) - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - installedVersions := []*downstreamtypes.DownstreamVersion{} - for _, installedRelease := range installedReleases { - installedVersions = append(installedVersions, helmReleaseToDownsreamVersion(&installedRelease)) - } - - // Parity with Helm history output, which lists revisions sorted by revision number in descending order. - downstreamtypes.SortDownstreamVersions(installedVersions, false) - - lastInstalledSequence := 0 - if len(installedVersions) > 0 { - lastInstalledSequence = int(installedVersions[0].ParentSequence) - } - - newVersions := make([]*downstreamtypes.DownstreamVersion, len(chartUpdates), len(chartUpdates)) - nextUpdateSequence := lastInstalledSequence + 1 - for i := len(chartUpdates) - 1; i >= 0; i-- { - newVersions[i] = helm.HelmUpdateToDownsreamVersion(chartUpdates[i], int64(nextUpdateSequence)) - nextUpdateSequence = nextUpdateSequence + 1 - } - - numSkippedVersions := len(newVersions) - 1 // looks like this is what getLatestDeployableDownstreamVersion does - if pinLatestDeployable && len(newVersions) > 0 { - // TODO: this should be UI logic. the response here should have no duplicates on the list - newVersions = append([]*downstreamtypes.DownstreamVersion{newVersions[0]}, newVersions...) - } - versions := append(newVersions, installedVersions...) - - history.VersionHistory = versions - history.TotalCount = len(versions) - history.NumOfSkippedVersions = numSkippedVersions - } else { - foundApp, err := store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - err = errors.Wrap(err, "failed to get app from slug") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } + foundApp, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + err = errors.Wrap(err, "failed to get app from slug") + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } - downstreams, err := store.GetStore().ListDownstreamsForApp(foundApp.ID) - if err != nil { - err = errors.Wrap(err, "failed to list downstreams for app") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } else if len(downstreams) == 0 { - err = errors.New("no downstreams for app") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } + downstreams, err := store.GetStore().ListDownstreamsForApp(foundApp.ID) + if err != nil { + err = errors.Wrap(err, "failed to list downstreams for app") + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } else if len(downstreams) == 0 { + err = errors.New("no downstreams for app") + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } - clusterID := downstreams[0].ClusterID + clusterID := downstreams[0].ClusterID - history, err = store.GetStore().GetDownstreamVersionHistory(foundApp.ID, clusterID, currentPage, pageSize, pinLatest, pinLatestDeployable) - if err != nil { - err = errors.Wrap(err, "failed to get downstream versions") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } + history, err := store.GetStore().GetDownstreamVersionHistory(foundApp.ID, clusterID, currentPage, pageSize, pinLatest, pinLatestDeployable) + if err != nil { + err = errors.Wrap(err, "failed to get downstream versions") + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return } + response := GetAppVersionHistoryResponse{ DownstreamVersionHistory: *history, } @@ -714,39 +614,6 @@ func (h *Handler) GetLatestDeployableVersion(w http.ResponseWriter, r *http.Requ getLatestDeployableVersionResponse := GetLatestDeployableVersionResponse{} appSlug := mux.Vars(r)["appSlug"] - - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - availableUpdates := helm.GetCachedUpdates(helmApp.ChartPath) - if len(availableUpdates) == 0 { - JSON(w, http.StatusOK, getLatestDeployableVersionResponse) - return - } - - installedReleases, err := helm.ListChartVersions(appSlug, helmApp.Namespace) - if err != nil { - errMsg := "failed to get installed releases" - logger.Error(errors.Wrap(err, errMsg)) - getLatestDeployableVersionResponse.Error = errMsg - JSON(w, http.StatusInternalServerError, getLatestDeployableVersionResponse) - return - } - - getLatestDeployableVersionResponse.Error = "" - sequence := len(installedReleases) + len(availableUpdates) // helm revisions are 1-based - getLatestDeployableVersionResponse.LatestDeployableVersion = helm.HelmUpdateToDownsreamVersion(availableUpdates[0], int64(sequence)) - getLatestDeployableVersionResponse.NumOfSkippedVersions = 0 // TODO - getLatestDeployableVersionResponse.NumOfRemainingVersions = 0 // TODO - - JSON(w, http.StatusOK, getLatestDeployableVersionResponse) - return - } - a, err := store.GetStore().GetAppFromSlug(appSlug) if err != nil { errMsg := "failed to get app from slug" @@ -802,20 +669,3 @@ func (h *Handler) GetAutomatedInstallStatus(w http.ResponseWriter, r *http.Reque JSON(w, http.StatusOK, response) } - -func helmReleaseToDownsreamVersion(installedRelease *helm.InstalledRelease) *downstreamtypes.DownstreamVersion { - return &downstreamtypes.DownstreamVersion{ - VersionLabel: installedRelease.Version, - Semver: installedRelease.Semver, - UpdateCursor: installedRelease.Version, - CreatedOn: nil, - DeployedAt: installedRelease.DeployedOn, - UpstreamReleasedAt: installedRelease.ReleasedOn, - IsDeployable: false, // TODO: implement - NonDeployableCause: "already installed", // TODO: implement - HasConfig: true, // TODO: implement - ParentSequence: int64(installedRelease.Revision), - Sequence: int64(installedRelease.Revision), - Status: storetypes.DownstreamVersionStatus(installedRelease.Status.String()), - } -} diff --git a/pkg/handlers/config.go b/pkg/handlers/config.go index deb429784a..32bfa7c857 100644 --- a/pkg/handlers/config.go +++ b/pkg/handlers/config.go @@ -18,7 +18,6 @@ import ( "github.com/replicatedhq/kots/pkg/config" kotsconfig "github.com/replicatedhq/kots/pkg/config" "github.com/replicatedhq/kots/pkg/crypto" - "github.com/replicatedhq/kots/pkg/helm" kotsadmconfig "github.com/replicatedhq/kots/pkg/kotsadmconfig" configtypes "github.com/replicatedhq/kots/pkg/kotsadmconfig/types" configvalidation "github.com/replicatedhq/kots/pkg/kotsadmconfig/validation" @@ -29,7 +28,6 @@ import ( registrytypes "github.com/replicatedhq/kots/pkg/registry/types" "github.com/replicatedhq/kots/pkg/render" rendertypes "github.com/replicatedhq/kots/pkg/render/types" - "github.com/replicatedhq/kots/pkg/replicatedapp" "github.com/replicatedhq/kots/pkg/store" storetypes "github.com/replicatedhq/kots/pkg/store/types" "github.com/replicatedhq/kots/pkg/template" @@ -150,30 +148,6 @@ func (h *Handler) UpdateAppConfig(w http.ResponseWriter, r *http.Request) { return } - if util.IsHelmManaged() { - // TODO: will need to consider flow for when ConfigSpec changes - appSlug := mux.Vars(r)["appSlug"] - - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - requiredItems, requiredItemsTitles := getMissingRequiredConfig(updateAppConfigRequest.ConfigGroups) - if len(requiredItems) > 0 { - updateAppConfigResponse.RequiredItems = requiredItems - updateAppConfigResponse.Error = fmt.Sprintf("The following fields are required: %s", strings.Join(requiredItemsTitles, ", ")) - JSON(w, http.StatusBadRequest, updateAppConfigResponse) - return - } - - helmApp.TempConfigValues = updateAppConfigValues(helmApp.TempConfigValues, updateAppConfigRequest.ConfigGroups) - - JSON(w, http.StatusOK, UpdateAppConfigResponse{Success: true}) - return - } - foundApp, err := store.GetStore().GetAppFromSlug(mux.Vars(r)["appSlug"]) if err != nil { logger.Error(err) @@ -259,128 +233,76 @@ func (h *Handler) LiveAppConfig(w http.ResponseWriter, r *http.Request) { var kotsKinds *kotsutil.KotsKinds var nonRenderedConfig *kotsv1beta1.Config var appLicense *kotsv1beta1.License - var app apptypes.AppType var localRegistry registrytypes.RegistrySettings - createNewVersion := false configValues := configValuesFromConfigGroups(liveAppConfigRequest.ConfigGroups) - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - app = helmApp - - isPending, _ := strconv.ParseBool(r.URL.Query().Get("isPending")) - if !isPending { - k, err := helm.GetKotsKindsForRevision(helmApp.Release.Name, liveAppConfigRequest.Sequence, helmApp.Namespace) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kots kinds for helm")) - w.WriteHeader(http.StatusInternalServerError) - return - } - kotsKinds = &k - nonRenderedConfig = kotsKinds.Config - appLicense = kotsKinds.License - createNewVersion = true - } else { - licenseID := helm.GetKotsLicenseID(&helmApp.Release) - if licenseID == "" { - logger.Error(errors.Errorf("no license and no license ID found for release %s", helmApp.Release.Name)) - w.WriteHeader(http.StatusInternalServerError) - return - } - - k, err := helm.GetKotsKindsFromUpstreamChartVersion(helmApp, licenseID, r.URL.Query().Get("semver")) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kotskinds from upstream chart")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - licenseData, err := replicatedapp.GetLatestLicenseForHelm(licenseID) - if err != nil { - logger.Error(errors.Wrap(err, "failed to download license for chart archive")) - w.WriteHeader(http.StatusInternalServerError) - return - } - k.License = licenseData.License - - kotsKinds = &k - nonRenderedConfig = kotsKinds.Config - appLicense = kotsKinds.License - } - } else { - foundApp, err := store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - liveAppConfigResponse.Error = "failed to get app from app slug" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } - app = foundApp + foundApp, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + liveAppConfigResponse.Error = "failed to get app from app slug" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - appLicense, err = store.GetStore().GetLatestLicenseForApp(foundApp.ID) - if err != nil { - liveAppConfigResponse.Error = "failed to get license for app" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + appLicense, err = store.GetStore().GetLatestLicenseForApp(foundApp.ID) + if err != nil { + liveAppConfigResponse.Error = "failed to get license for app" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - archiveDir, err := os.MkdirTemp("", "kotsadm") - if err != nil { - liveAppConfigResponse.Error = "failed to create temp dir" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } - defer os.RemoveAll(archiveDir) + archiveDir, err := os.MkdirTemp("", "kotsadm") + if err != nil { + liveAppConfigResponse.Error = "failed to create temp dir" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } + defer os.RemoveAll(archiveDir) - err = store.GetStore().GetAppVersionArchive(foundApp.ID, liveAppConfigRequest.Sequence, archiveDir) - if err != nil { - liveAppConfigResponse.Error = "failed to get app version archive" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + err = store.GetStore().GetAppVersionArchive(foundApp.ID, liveAppConfigRequest.Sequence, archiveDir) + if err != nil { + liveAppConfigResponse.Error = "failed to get app version archive" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - kotsKinds, err = kotsutil.LoadKotsKinds(archiveDir) - if err != nil { - liveAppConfigResponse.Error = "failed to load kots kinds from path" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + kotsKinds, err = kotsutil.LoadKotsKinds(archiveDir) + if err != nil { + liveAppConfigResponse.Error = "failed to load kots kinds from path" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - // get the non-rendered config from the upstream directory because we have to re-render it with the new values - nonRenderedConfig, err = kotsutil.FindConfigInPath(filepath.Join(archiveDir, "upstream")) - if err != nil { - liveAppConfigResponse.Error = "failed to find non-rendered config" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + // get the non-rendered config from the upstream directory because we have to re-render it with the new values + nonRenderedConfig, err = kotsutil.FindConfigInPath(filepath.Join(archiveDir, "upstream")) + if err != nil { + liveAppConfigResponse.Error = "failed to find non-rendered config" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - registryInfo, err := store.GetStore().GetRegistryDetailsForApp(foundApp.ID) - if err != nil { - liveAppConfigResponse.Error = "failed to get app registry info" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + registryInfo, err := store.GetStore().GetRegistryDetailsForApp(foundApp.ID) + if err != nil { + liveAppConfigResponse.Error = "failed to get app registry info" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return + } - localRegistry = registryInfo + localRegistry = registryInfo - createNewVersion, err = shouldCreateNewAppVersion(archiveDir, foundApp.GetID(), liveAppConfigRequest.Sequence) - if err != nil { - liveAppConfigResponse.Error = "failed to check new version" - logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, liveAppConfigResponse) - return - } + createNewVersion, err := shouldCreateNewAppVersion(archiveDir, foundApp.GetID(), liveAppConfigRequest.Sequence) + if err != nil { + liveAppConfigResponse.Error = "failed to check new version" + logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, liveAppConfigResponse) + return } sequence := liveAppConfigRequest.Sequence @@ -388,9 +310,9 @@ func (h *Handler) LiveAppConfig(w http.ResponseWriter, r *http.Request) { sequence += 1 } - versionInfo := template.VersionInfoFromInstallationSpec(sequence, app.GetIsAirgap(), kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) - appInfo := template.ApplicationInfo{Slug: app.GetSlug()} - renderedConfig, err := kotsconfig.TemplateConfigObjects(nonRenderedConfig, configValues, appLicense, &kotsKinds.KotsApplication, localRegistry, &versionInfo, &appInfo, kotsKinds.IdentityConfig, app.GetNamespace(), false) + versionInfo := template.VersionInfoFromInstallationSpec(sequence, foundApp.IsAirgap, kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) + appInfo := template.ApplicationInfo{Slug: foundApp.Slug} + renderedConfig, err := kotsconfig.TemplateConfigObjects(nonRenderedConfig, configValues, appLicense, &kotsKinds.KotsApplication, localRegistry, &versionInfo, &appInfo, kotsKinds.IdentityConfig, foundApp.GetNamespace(), false) if err != nil { liveAppConfigResponse.Error = "failed to render templates" logger.Error(errors.Wrap(err, liveAppConfigResponse.Error)) @@ -484,168 +406,93 @@ func (h *Handler) CurrentAppConfig(w http.ResponseWriter, r *http.Request) { var nonRenderedConfig *kotsv1beta1.Config var license *kotsv1beta1.License var localRegistry registrytypes.RegistrySettings - var app apptypes.AppType var downstreamVersion *downstreamtypes.DownstreamVersion - createNewVersion := false - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - app = helmApp - - isPending, _ := strconv.ParseBool(r.URL.Query().Get("isPending")) - if !isPending { - installedRelease, err := helm.GetChartVersion(helmApp.Release.Name, sequence, helmApp.Namespace) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get helm release")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - if installedRelease == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - downstreamVersion = helmReleaseToDownsreamVersion(installedRelease) - - k, err := helm.GetKotsKindsForRevision(helmApp.Release.Name, sequence, helmApp.Namespace) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kots kinds for helm")) - w.WriteHeader(http.StatusInternalServerError) - return - } - kotsKinds = &k - nonRenderedConfig = kotsKinds.Config - license = kotsKinds.License - createNewVersion = true - } else { - appKotsKinds, err := helm.GetKotsKindsFromHelmApp(helmApp) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get app kotskinds")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - licenseID := helm.GetKotsLicenseID(&helmApp.Release) - if licenseID == "" { - logger.Error(errors.Errorf("no license and no license ID found for release %s", helmApp.Release.Name)) - w.WriteHeader(http.StatusInternalServerError) - return - } - - k, err := helm.GetKotsKindsFromUpstreamChartVersion(helmApp, licenseID, r.URL.Query().Get("semver")) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kotskinds from upstream chart")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - k.ConfigValues = appKotsKinds.ConfigValues.DeepCopy() - - licenseData, err := replicatedapp.GetLatestLicenseForHelm(licenseID) - if err != nil { - logger.Error(errors.Wrap(err, "failed to download license for chart archive")) - w.WriteHeader(http.StatusInternalServerError) - return - } - k.License = licenseData.License - - kotsKinds = &k - nonRenderedConfig = kotsKinds.Config - license = kotsKinds.License - } - } else { - foundApp, err := store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - currentAppConfigResponse.Error = "failed to get app from app slug" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } - app = foundApp - - status, err := store.GetStore().GetDownstreamVersionStatus(foundApp.ID, sequence) - if err != nil { - currentAppConfigResponse.Error = "failed to get downstream version status" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } - if status == storetypes.VersionPendingDownload { - err := errors.Errorf("not returning config for version %d because it's %s", sequence, status) - logger.Error(err) - currentAppConfigResponse.Error = err.Error() - JSON(w, http.StatusBadRequest, currentAppConfigResponse) - return - } + foundApp, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + currentAppConfigResponse.Error = "failed to get app from app slug" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - license, err = store.GetStore().GetLatestLicenseForApp(foundApp.ID) - if err != nil { - currentAppConfigResponse.Error = "failed to get license for app" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + status, err := store.GetStore().GetDownstreamVersionStatus(foundApp.ID, sequence) + if err != nil { + currentAppConfigResponse.Error = "failed to get downstream version status" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } + if status == storetypes.VersionPendingDownload { + err := errors.Errorf("not returning config for version %d because it's %s", sequence, status) + logger.Error(err) + currentAppConfigResponse.Error = err.Error() + JSON(w, http.StatusBadRequest, currentAppConfigResponse) + return + } - archiveDir, err := os.MkdirTemp("", "kotsadm") - if err != nil { - currentAppConfigResponse.Error = "failed to create temp dir" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } - defer os.RemoveAll(archiveDir) + license, err = store.GetStore().GetLatestLicenseForApp(foundApp.ID) + if err != nil { + currentAppConfigResponse.Error = "failed to get license for app" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - err = store.GetStore().GetAppVersionArchive(foundApp.ID, sequence, archiveDir) - if err != nil { - currentAppConfigResponse.Error = "failed to get app version archive" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + archiveDir, err := os.MkdirTemp("", "kotsadm") + if err != nil { + currentAppConfigResponse.Error = "failed to create temp dir" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } + defer os.RemoveAll(archiveDir) - kotsKinds, err = kotsutil.LoadKotsKinds(archiveDir) - if err != nil { - currentAppConfigResponse.Error = "failed to load kots kinds from path" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + err = store.GetStore().GetAppVersionArchive(foundApp.ID, sequence, archiveDir) + if err != nil { + currentAppConfigResponse.Error = "failed to get app version archive" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - // get the non-rendered config from the upstream directory because we have to re-render it with the new values - nonRenderedConfig, err = kotsutil.FindConfigInPath(filepath.Join(archiveDir, "upstream")) - if err != nil { - currentAppConfigResponse.Error = "failed to find non-rendered config" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + kotsKinds, err = kotsutil.LoadKotsKinds(archiveDir) + if err != nil { + currentAppConfigResponse.Error = "failed to load kots kinds from path" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - registryInfo, err := store.GetStore().GetRegistryDetailsForApp(foundApp.ID) - if err != nil { - currentAppConfigResponse.Error = "failed to get app registry info" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + // get the non-rendered config from the upstream directory because we have to re-render it with the new values + nonRenderedConfig, err = kotsutil.FindConfigInPath(filepath.Join(archiveDir, "upstream")) + if err != nil { + currentAppConfigResponse.Error = "failed to find non-rendered config" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - localRegistry = registryInfo + registryInfo, err := store.GetStore().GetRegistryDetailsForApp(foundApp.ID) + if err != nil { + currentAppConfigResponse.Error = "failed to get app registry info" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return + } - createNewVersion, err = shouldCreateNewAppVersion(archiveDir, foundApp.GetID(), sequence) - if err != nil { - currentAppConfigResponse.Error = "failed to check new version" - logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) - JSON(w, http.StatusInternalServerError, currentAppConfigResponse) - return - } + localRegistry = registryInfo - // TODO: set downstreamVersion + createNewVersion, err := shouldCreateNewAppVersion(archiveDir, foundApp.GetID(), sequence) + if err != nil { + currentAppConfigResponse.Error = "failed to check new version" + logger.Error(errors.Wrap(err, currentAppConfigResponse.Error)) + JSON(w, http.StatusInternalServerError, currentAppConfigResponse) + return } + // TODO: set downstreamVersion + // get values from saved app version configValues := map[string]template.ItemValue{} @@ -665,9 +512,9 @@ func (h *Handler) CurrentAppConfig(w http.ResponseWriter, r *http.Request) { sequence += 1 } - versionInfo := template.VersionInfoFromInstallationSpec(sequence, app.GetIsAirgap(), kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) - appInfo := template.ApplicationInfo{Slug: app.GetSlug()} - renderedConfig, err := kotsconfig.TemplateConfigObjects(nonRenderedConfig, configValues, license, &kotsKinds.KotsApplication, localRegistry, &versionInfo, &appInfo, kotsKinds.IdentityConfig, app.GetNamespace(), false) + versionInfo := template.VersionInfoFromInstallationSpec(sequence, foundApp.GetIsAirgap(), kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) + appInfo := template.ApplicationInfo{Slug: foundApp.GetSlug()} + renderedConfig, err := kotsconfig.TemplateConfigObjects(nonRenderedConfig, configValues, license, &kotsKinds.KotsApplication, localRegistry, &versionInfo, &appInfo, kotsKinds.IdentityConfig, foundApp.GetNamespace(), false) if err != nil { logger.Error(err) currentAppConfigResponse.Error = "failed to render templates" @@ -951,7 +798,7 @@ func updateAppConfigValues(values map[string]kotsv1beta1.ConfigValue, configGrou values[item.Name] = v } else if item.Value.Type == multitype.String { updatedValue := item.Value.String() - if item.Type == "password" && !util.IsHelmManaged() { // no encryption in helm mode + if item.Type == "password" { // encrypt using the key // if the decryption succeeds, don't encrypt again _, err := util.DecryptConfigValue(updatedValue) @@ -1182,8 +1029,8 @@ func (h *Handler) SetAppConfigValues(w http.ResponseWriter, r *http.Request) { return } - versionInfo := template.VersionInfoFromInstallationSpec(nextAppSequence, foundApp.IsAirgap, kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) - appInfo := template.ApplicationInfo{Slug: foundApp.Slug} + versionInfo := template.VersionInfoFromInstallationSpec(nextAppSequence, foundApp.GetIsAirgap(), kotsKinds.Installation.Spec) // sequence +1 because the sequence will be incremented on save (and we want the preview to be accurate) + appInfo := template.ApplicationInfo{Slug: foundApp.GetSlug()} renderedConfig, err := kotsconfig.TemplateConfigObjects(newConfig, configValueMap, kotsKinds.License, &kotsKinds.KotsApplication, registryInfo, &versionInfo, &appInfo, kotsKinds.IdentityConfig, util.PodNamespace, true) if err != nil { setAppConfigValuesResponse.Error = "failed to render templates" diff --git a/pkg/handlers/dashboard.go b/pkg/handlers/dashboard.go index 744309595a..6f6da0f0df 100644 --- a/pkg/handlers/dashboard.go +++ b/pkg/handlers/dashboard.go @@ -7,10 +7,8 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" appstatetypes "github.com/replicatedhq/kots/pkg/appstate/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/store" - "github.com/replicatedhq/kots/pkg/util" "github.com/replicatedhq/kots/pkg/version" ) @@ -24,30 +22,6 @@ type GetAppDashboardResponse struct { func (h *Handler) GetAppDashboard(w http.ResponseWriter, r *http.Request) { appSlug := mux.Vars(r)["appSlug"] clusterID := mux.Vars(r)["clusterId"] - appStatus := new(appstatetypes.AppStatus) - if util.IsHelmManaged() { - release := helm.GetHelmApp(appSlug) - if release == nil { - logger.Errorf("release for app: %s does not exist\n", appSlug) - w.WriteHeader(http.StatusNotFound) - return - } - - // we have received informer data - if len(release.Status.ResourceStates) > 0 { - getAppDashboardResponse := GetAppDashboardResponse{ - AppStatus: &release.Status, - Metrics: nil, - PrometheusAddress: "", - } - - JSON(w, 200, getAppDashboardResponse) - return - } - - w.WriteHeader(http.StatusNotFound) - return - } a, err := store.GetStore().GetAppFromSlug(appSlug) if err != nil { @@ -56,7 +30,7 @@ func (h *Handler) GetAppDashboard(w http.ResponseWriter, r *http.Request) { return } - appStatus, err = store.GetStore().GetAppStatus(a.ID) + appStatus, err := store.GetStore().GetAppStatus(a.ID) if err != nil { logger.Error(err) w.WriteHeader(500) diff --git a/pkg/handlers/downstream.go b/pkg/handlers/downstream.go index 0bcc693638..011cb72e46 100644 --- a/pkg/handlers/downstream.go +++ b/pkg/handlers/downstream.go @@ -5,11 +5,8 @@ import ( "strconv" "github.com/gorilla/mux" - "github.com/replicatedhq/kots/pkg/api/downstream/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/store" - "github.com/replicatedhq/kots/pkg/util" ) type GetDownstreamOutputResponse struct { @@ -29,47 +26,24 @@ func (h *Handler) GetDownstreamOutput(w http.ResponseWriter, r *http.Request) { appSlug := mux.Vars(r)["appSlug"] clusterID := mux.Vars(r)["clusterId"] sequence, err := strconv.Atoi(mux.Vars(r)["sequence"]) - output := new(types.DownstreamOutput) if err != nil { logger.Error(err) w.WriteHeader(http.StatusInternalServerError) return } - if util.IsHelmManaged() { - app := helm.GetHelmApp(appSlug) - if app == nil { - w.WriteHeader(http.StatusNotFound) - return - } - releaseSecret, err := helm.GetChartSecret(app.Release.Name, app.Release.Namespace, mux.Vars(r)["sequence"]) - if err != nil { - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - if releaseSecret != nil { - if releaseSecret.Info.Status != "failed" { - output.HelmStdout = releaseSecret.Info.Description - } else { - output.HelmStderr = releaseSecret.Info.Description - } - } - } else { - a, err := store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } + a, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } - output, err = store.GetStore().GetDownstreamOutput(a.ID, clusterID, int64(sequence)) - if err != nil { - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } + output, err := store.GetStore().GetDownstreamOutput(a.ID, clusterID, int64(sequence)) + if err != nil { + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return } downstreamLogs := DownstreamLogs{ diff --git a/pkg/handlers/handlers.go b/pkg/handlers/handlers.go index 582e9ed8cc..a0118b414e 100644 --- a/pkg/handlers/handlers.go +++ b/pkg/handlers/handlers.go @@ -59,8 +59,6 @@ func RegisterSessionAuthRoutes(r *mux.Router, kotsStore store.Store, handler KOT HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleRead, handler.DownloadSupportBundle)) // TODO: appSlug r.Name("CollectSupportBundle").Path("/api/v1/troubleshoot/supportbundle/app/{appId}/cluster/{clusterId}/collect").Methods("POST"). HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleWrite, handler.CollectSupportBundle)) - r.Name("CollectHelmSupportBundle").Path("/api/v1/troubleshoot/supportbundle/app/{appSlug}/collect").Methods("POST"). - HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleWrite, handler.CollectHelmSupportBundle)) r.Name("ShareSupportBundle").Path("/api/v1/troubleshoot/app/{appSlug}/supportbundle/{bundleId}/share").Methods("POST"). HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleWrite, handler.ShareSupportBundle)) r.Name("DeleteSupportBundle").Path("/api/v1/troubleshoot/app/{appSlug}/supportbundle/{bundleId}").Methods("DELETE"). @@ -313,12 +311,6 @@ func RegisterSessionAuthRoutes(r *mux.Router, kotsStore store.Store, handler KOT // Password change r.Name("ChangePassword").Path("/api/v1/password/change").Methods("PUT"). HandlerFunc(middleware.EnforceAccess(policy.PasswordChange, handler.ChangePassword)) - - // Helm - r.Name("IsHelmManaged").Path("/api/v1/is-helm-managed").Methods("GET"). - HandlerFunc(middleware.EnforceAccess(policy.IsHelmManaged, handler.IsHelmManaged)) - r.Name("GetAppValuesFile").Path("/api/v1/app/{appSlug}/values/{sequence}").Methods("GET"). - HandlerFunc(middleware.EnforceAccess(policy.GetAppValuesFile, handler.GetAppValuesFile)) } func JSON(w http.ResponseWriter, code int, payload interface{}) { diff --git a/pkg/handlers/handlers_test.go b/pkg/handlers/handlers_test.go index a12dadc083..18804302e8 100644 --- a/pkg/handlers/handlers_test.go +++ b/pkg/handlers/handlers_test.go @@ -176,17 +176,6 @@ var HandlerPolicyTests = map[string][]HandlerPolicyTest{ ExpectStatus: http.StatusOK, }, }, - "CollectHelmSupportBundle": { - { - Vars: map[string]string{"appSlug": "my-app"}, - Roles: []rbactypes.Role{rbac.ClusterAdminRole}, - SessionRoles: []string{rbac.ClusterAdminRoleID}, - Calls: func(storeRecorder *mock_store.MockStoreMockRecorder, handlerRecorder *mock_handlers.MockKOTSHandlerMockRecorder) { - handlerRecorder.CollectHelmSupportBundle(gomock.Any(), gomock.Any()) - }, - ExpectStatus: http.StatusOK, - }, - }, "ShareSupportBundle": { { Vars: map[string]string{"appSlug": "my-app", "bundleId": "234"}, @@ -1383,27 +1372,6 @@ var HandlerPolicyTests = map[string][]HandlerPolicyTest{ ExpectStatus: http.StatusOK, }, }, - "IsHelmManaged": { - { - Roles: []rbactypes.Role{rbac.ClusterAdminRole}, - SessionRoles: []string{rbac.ClusterAdminRoleID}, - Calls: func(storeRecorder *mock_store.MockStoreMockRecorder, handlerRecorder *mock_handlers.MockKOTSHandlerMockRecorder) { - handlerRecorder.IsHelmManaged(gomock.Any(), gomock.Any()) - }, - ExpectStatus: http.StatusOK, - }, - }, - "GetAppValuesFile": { - { - Vars: map[string]string{"appSlug": "123", "sequence": "1"}, - Roles: []rbactypes.Role{rbac.ClusterAdminRole}, - SessionRoles: []string{rbac.ClusterAdminRoleID}, - Calls: func(storeRecorder *mock_store.MockStoreMockRecorder, handlerRecorder *mock_handlers.MockKOTSHandlerMockRecorder) { - handlerRecorder.GetAppValuesFile(gomock.Any(), gomock.Any()) - }, - ExpectStatus: http.StatusOK, - }, - }, } type HandlerPolicyTest struct { diff --git a/pkg/handlers/helm.go b/pkg/handlers/helm.go deleted file mode 100644 index a878d7af79..0000000000 --- a/pkg/handlers/helm.go +++ /dev/null @@ -1,197 +0,0 @@ -package handlers - -import ( - "fmt" - "net/http" - "strconv" - - "github.com/gorilla/mux" - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" - kotshelm "github.com/replicatedhq/kots/pkg/helm" - "github.com/replicatedhq/kots/pkg/kotsutil" - "github.com/replicatedhq/kots/pkg/logger" - "github.com/replicatedhq/kots/pkg/replicatedapp" - "github.com/replicatedhq/kots/pkg/util" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - yaml "github.com/replicatedhq/yaml/v3" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// IsHelmManagedResponse - response body for the is helm managed endpoint -type IsHelmManagedResponse struct { - Success bool `json:"success"` - IsHelmManaged bool `json:"isHelmManaged"` -} - -// IsHelmManaged - report whether or not kots is running in helm managed mode -func (h *Handler) IsHelmManaged(w http.ResponseWriter, r *http.Request) { - helmManagedResponse := IsHelmManagedResponse{ - Success: true, - IsHelmManaged: util.IsHelmManaged(), - } - - JSON(w, http.StatusOK, helmManagedResponse) -} - -func (h *Handler) GetAppValuesFile(w http.ResponseWriter, r *http.Request) { - if !util.IsHelmManaged() { - logger.Errorf("values file can only be dowloaded in Helm managed mode") - w.WriteHeader(http.StatusInternalServerError) - return - } - - appSlug := mux.Vars(r)["appSlug"] - sequence, err := strconv.ParseInt(mux.Vars(r)["sequence"], 10, 64) - if err != nil { - logger.Error(errors.Wrap(err, "failed to parse app sequence")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - var kotsKinds *kotsutil.KotsKinds - var tmplVals map[string]interface{} - var helmChartFile []byte - - isPending, _ := strconv.ParseBool(r.URL.Query().Get("isPending")) - if isPending { - licenseID := helm.GetKotsLicenseID(&helmApp.Release) - if licenseID == "" { - logger.Error(errors.Errorf("no license and no license ID found for release %s", helmApp.Release.Name)) - w.WriteHeader(http.StatusInternalServerError) - return - } - - secret, err := helm.GetReplicatedSecretFromUpstreamChartVersion(helmApp, licenseID, r.URL.Query().Get("semver")) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get replicated secret from upstream chart")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - helmChartFile = secret.Data["chart"] - - k, err := helm.GetKotsKindsFromUpstreamChartVersion(helmApp, licenseID, r.URL.Query().Get("semver")) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kotskinds from upstream chart")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - licenseData, err := replicatedapp.GetLatestLicenseForHelm(licenseID) - if err != nil { - logger.Error(errors.Wrap(err, "failed to download license for chart archive")) - w.WriteHeader(http.StatusInternalServerError) - return - } - k.License = licenseData.License - - kotsKinds = &k - } else { - replicatedSecret, err := helm.GetReplicatedSecretForRevision(helmApp.Release.Name, sequence, helmApp.Namespace) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get secret")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - helmChartFile = replicatedSecret.Data["chart"] - - k, err := helm.GetKotsKindsForRevision(helmApp.Release.Name, sequence, helmApp.Namespace) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get kots kinds for helm")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - kotsKinds = &k - } - - helmChart, err := kotsutil.LoadV1Beta1HelmChartFromContents(helmChartFile) - if err != nil { - logger.Error(errors.Wrap(err, "failed to parse HelmChart file")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - tmplVals, err = helmChart.Spec.GetReplTmplValues(helmChart.Spec.Values) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get templated values")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - // keeping this assignment out of GetKotsKindsFromHelmApp because this is specific to file download endpoint - kotsKinds.ConfigValues = &kotsv1beta1.ConfigValues{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "kots.io/v1beta1", - Kind: "ConfigValues", - }, - Spec: kotsv1beta1.ConfigValuesSpec{ - Values: helmApp.TempConfigValues, - }, - } - - renderedValues, err := kotshelm.RenderValuesFromConfig(helmApp, kotsKinds, helmChartFile) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get render values from config")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - // get a intersected map containing tmplVals keys with renderedValues values - intersectVals := kotsv1beta1.GetMapIntersect(tmplVals, renderedValues) - - mergedHelmValues, err := kotshelm.GetMergedValues(helmApp.Release.Chart.Values, intersectVals) - if err != nil { - logger.Error(errors.Wrap(err, "failed to merge values with templated values")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - if kotsKinds.ConfigValues != nil { - v, err := kotshelm.GetConfigValuesMap(kotsKinds.ConfigValues) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get app config values sub-map")) - w.WriteHeader(http.StatusInternalServerError) - return - } - m, err := kotshelm.GetMergedValues(mergedHelmValues, v) - if err != nil { - logger.Error(errors.Wrap(err, "failed to merge app config to helm values")) - w.WriteHeader(http.StatusInternalServerError) - return - } - mergedHelmValues = m - } - - b, err := yaml.Marshal(mergedHelmValues) - if err != nil { - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s-values.yaml", appSlug)) - w.Header().Set("Content-Length", strconv.Itoa(len(b))) - w.WriteHeader(http.StatusOK) - w.Write(b) -} - -func getCompatibleAppFromHelmApp(helmApp *apptypes.HelmApp) (*apptypes.App, error) { - chartApp, err := helm.ResponseAppFromHelmApp(helmApp) - if err != nil { - return nil, errors.Wrap(err, "failed to convert release to app") - } - - foundApp := &apptypes.App{ID: chartApp.ID, Slug: chartApp.Slug, Name: chartApp.Name} - return foundApp, nil -} diff --git a/pkg/handlers/interface.go b/pkg/handlers/interface.go index f974be4eae..eef23d8939 100644 --- a/pkg/handlers/interface.go +++ b/pkg/handlers/interface.go @@ -20,7 +20,6 @@ type KOTSHandler interface { GetSupportBundleRedactions(w http.ResponseWriter, r *http.Request) // TODO: appSlug DownloadSupportBundle(w http.ResponseWriter, r *http.Request) // TODO: appSlug CollectSupportBundle(w http.ResponseWriter, r *http.Request) - CollectHelmSupportBundle(w http.ResponseWriter, r *http.Request) ShareSupportBundle(w http.ResponseWriter, r *http.Request) DeleteSupportBundle(w http.ResponseWriter, r *http.Request) GetPodDetailsFromSupportBundle(w http.ResponseWriter, r *http.Request) @@ -160,8 +159,4 @@ type KOTSHandler interface { // Password change ChangePassword(w http.ResponseWriter, r *http.Request) - - // Helm - IsHelmManaged(w http.ResponseWriter, r *http.Request) - GetAppValuesFile(w http.ResponseWriter, r *http.Request) } diff --git a/pkg/handlers/license.go b/pkg/handlers/license.go index dbac623b63..cc28386f00 100644 --- a/pkg/handlers/license.go +++ b/pkg/handlers/license.go @@ -12,7 +12,6 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/kotsadm" kotsadmtypes "github.com/replicatedhq/kots/pkg/kotsadm/types" @@ -118,80 +117,42 @@ func (h *Handler) SyncLicense(w http.ResponseWriter, r *http.Request) { } appSlug := mux.Vars(r)["appSlug"] - var latestLicense *kotsv1beta1.License - var foundApp *apptypes.App - var err error - var isSynced bool - - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - syncLicenseResponse.Error = "failed to get helm release for slug" - logger.Errorf(syncLicenseResponse.Error) - JSON(w, http.StatusNotFound, syncLicenseResponse) - return - } - - isSynced, err = helm.SyncLicense(helmApp) - if err != nil { - syncLicenseResponse.Error = "failed to sync helm license" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } - - latestLicense, err = helm.GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - syncLicenseResponse.Error = "failed to get license from secret" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } - foundApp, err = getCompatibleAppFromHelmApp(helmApp) - if err != nil { - syncLicenseResponse.Error = "failed to get app for helm app" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } - } else { - foundApp, err = store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - syncLicenseResponse.Error = "failed to get app from slug" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } + foundApp, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + syncLicenseResponse.Error = "failed to get app from slug" + logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) + JSON(w, http.StatusInternalServerError, syncLicenseResponse) + return + } - currentLicense, err := store.GetStore().GetLatestLicenseForApp(foundApp.ID) - if err != nil { - syncLicenseResponse.Error = "failed to get current license" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } + currentLicense, err := store.GetStore().GetLatestLicenseForApp(foundApp.ID) + if err != nil { + syncLicenseResponse.Error = "failed to get current license" + logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) + JSON(w, http.StatusInternalServerError, syncLicenseResponse) + return + } - latestLicense, isSynced, err = license.Sync(foundApp, syncLicenseRequest.LicenseData, true) - if err != nil { - syncLicenseResponse.Error = "failed to sync license" - logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, syncLicenseResponse) - return - } + latestLicense, isSynced, err := license.Sync(foundApp, syncLicenseRequest.LicenseData, true) + if err != nil { + syncLicenseResponse.Error = "failed to sync license" + logger.Error(errors.Wrap(err, syncLicenseResponse.Error)) + JSON(w, http.StatusInternalServerError, syncLicenseResponse) + return + } - if !foundApp.IsAirgap && currentLicense.Spec.ChannelID != latestLicense.Spec.ChannelID { - // channel changed and this is an online installation, fetch the latest release for the new channel - go func(appID string) { - opts := updatechecker.CheckForUpdatesOpts{ - AppID: appID, - } - _, err := updatechecker.CheckForUpdates(opts) - if err != nil { - logger.Error(errors.Wrap(err, "failed to fetch the latest release for the new channel")) - } - }(foundApp.ID) - } + if !foundApp.IsAirgap && currentLicense.Spec.ChannelID != latestLicense.Spec.ChannelID { + // channel changed and this is an online installation, fetch the latest release for the new channel + go func(appID string) { + opts := updatechecker.CheckForUpdatesOpts{ + AppID: appID, + } + _, err := updatechecker.CheckForUpdates(opts) + if err != nil { + logger.Error(errors.Wrap(err, "failed to fetch the latest release for the new channel")) + } + }(foundApp.ID) } licenseResponse, err := licenseResponseFromLicense(latestLicense, foundApp) @@ -215,56 +176,21 @@ func (h *Handler) GetLicense(w http.ResponseWriter, r *http.Request) { } appSlug := mux.Vars(r)["appSlug"] - license := new(kotsv1beta1.License) - foundApp := new(apptypes.App) - var err error - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - getLicenseResponse.Error = "failed to get helm release for slug" - logger.Errorf(getLicenseResponse.Error) - JSON(w, http.StatusNotFound, getLicenseResponse) - return - } - - currentLicense, err := helm.GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - getLicenseResponse.Error = "failed to get license from secret" - logger.Error(errors.Wrap(err, getLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, getLicenseResponse) - return - } - - if currentLicense == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - license = currentLicense - foundApp, err = getCompatibleAppFromHelmApp(helmApp) - if err != nil { - getLicenseResponse.Error = "failed to get app for helm app" - logger.Error(errors.Wrap(err, getLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, getLicenseResponse) - return - } - } else { - foundApp, err = store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - getLicenseResponse.Error = "failed to get app from slug" - logger.Error(errors.Wrap(err, getLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, getLicenseResponse) - return - } + foundApp, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + getLicenseResponse.Error = "failed to get app from slug" + logger.Error(errors.Wrap(err, getLicenseResponse.Error)) + JSON(w, http.StatusInternalServerError, getLicenseResponse) + return + } - license, err = store.GetStore().GetLatestLicenseForApp(foundApp.ID) - if err != nil { - getLicenseResponse.Error = "failed to get license for app" - logger.Error(errors.Wrap(err, getLicenseResponse.Error)) - JSON(w, http.StatusInternalServerError, getLicenseResponse) - return - } + license, err := store.GetStore().GetLatestLicenseForApp(foundApp.ID) + if err != nil { + getLicenseResponse.Error = "failed to get license for app" + logger.Error(errors.Wrap(err, getLicenseResponse.Error)) + JSON(w, http.StatusInternalServerError, getLicenseResponse) + return } licenseResponse, err := licenseResponseFromLicense(license, foundApp) diff --git a/pkg/handlers/metadata.go b/pkg/handlers/metadata.go index 013e5beb1e..1b5d0e4d69 100644 --- a/pkg/handlers/metadata.go +++ b/pkg/handlers/metadata.go @@ -107,9 +107,7 @@ func GetMetadataHandler(getK8sInfoFn MetadataK8sFn, kotsStore store.Store) http. } application := obj.(*kotsv1beta1.Application) metadataResponse.IconURI = application.Spec.Icon - if !util.IsHelmManaged() { - metadataResponse.Branding = getBrandingResponse(kotsStore, appID) - } + metadataResponse.Branding = getBrandingResponse(kotsStore, appID) metadataResponse.Name = application.Spec.Title metadataResponse.UpstreamURI = brandingConfigMap.Data[upstreamUriKey] metadataResponse.ConsoleFeatureFlags = application.Spec.ConsoleFeatureFlags diff --git a/pkg/handlers/mock/mock.go b/pkg/handlers/mock/mock.go index 1c56f5c7ba..3ffdb10508 100644 --- a/pkg/handlers/mock/mock.go +++ b/pkg/handlers/mock/mock.go @@ -130,18 +130,6 @@ func (mr *MockKOTSHandlerMockRecorder) CheckAirgapBundleChunk(w, r interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckAirgapBundleChunk", reflect.TypeOf((*MockKOTSHandler)(nil).CheckAirgapBundleChunk), w, r) } -// CollectHelmSupportBundle mocks base method. -func (m *MockKOTSHandler) CollectHelmSupportBundle(w http.ResponseWriter, r *http.Request) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "CollectHelmSupportBundle", w, r) -} - -// CollectHelmSupportBundle indicates an expected call of CollectHelmSupportBundle. -func (mr *MockKOTSHandlerMockRecorder) CollectHelmSupportBundle(w, r interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CollectHelmSupportBundle", reflect.TypeOf((*MockKOTSHandler)(nil).CollectHelmSupportBundle), w, r) -} - // CollectSupportBundle mocks base method. func (m *MockKOTSHandler) CollectSupportBundle(w http.ResponseWriter, r *http.Request) { m.ctrl.T.Helper() @@ -634,18 +622,6 @@ func (mr *MockKOTSHandlerMockRecorder) GetAppStatus(w, r interface{}) *gomock.Ca return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppStatus", reflect.TypeOf((*MockKOTSHandler)(nil).GetAppStatus), w, r) } -// GetAppValuesFile mocks base method. -func (m *MockKOTSHandler) GetAppValuesFile(w http.ResponseWriter, r *http.Request) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "GetAppValuesFile", w, r) -} - -// GetAppValuesFile indicates an expected call of GetAppValuesFile. -func (mr *MockKOTSHandlerMockRecorder) GetAppValuesFile(w, r interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppValuesFile", reflect.TypeOf((*MockKOTSHandler)(nil).GetAppValuesFile), w, r) -} - // GetAppVersionDownloadStatus mocks base method. func (m *MockKOTSHandler) GetAppVersionDownloadStatus(w http.ResponseWriter, r *http.Request) { m.ctrl.T.Helper() @@ -1114,18 +1090,6 @@ func (mr *MockKOTSHandlerMockRecorder) InitGitOpsConnection(w, r interface{}) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGitOpsConnection", reflect.TypeOf((*MockKOTSHandler)(nil).InitGitOpsConnection), w, r) } -// IsHelmManaged mocks base method. -func (m *MockKOTSHandler) IsHelmManaged(w http.ResponseWriter, r *http.Request) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "IsHelmManaged", w, r) -} - -// IsHelmManaged indicates an expected call of IsHelmManaged. -func (mr *MockKOTSHandlerMockRecorder) IsHelmManaged(w, r interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsHelmManaged", reflect.TypeOf((*MockKOTSHandler)(nil).IsHelmManaged), w, r) -} - // ListApps mocks base method. func (m *MockKOTSHandler) ListApps(w http.ResponseWriter, r *http.Request) { m.ctrl.T.Helper() diff --git a/pkg/handlers/troubleshoot.go b/pkg/handlers/troubleshoot.go index 456085ec1e..28239b9fce 100644 --- a/pkg/handlers/troubleshoot.go +++ b/pkg/handlers/troubleshoot.go @@ -11,7 +11,6 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/reporting" "github.com/replicatedhq/kots/pkg/store" @@ -171,18 +170,14 @@ func (h *Handler) GetSupportBundleFiles(w http.ResponseWriter, r *http.Request) func (h *Handler) ListSupportBundles(w http.ResponseWriter, r *http.Request) { appSlug := mux.Vars(r)["appSlug"] - appIDOrSlug := appSlug - if !util.IsHelmManaged() { - a, err := store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - appIDOrSlug = a.ID + a, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + logger.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return } - supportBundles, err := store.GetStore().ListSupportBundles(appIDOrSlug) + supportBundles, err := store.GetStore().ListSupportBundles(a.ID) if err != nil { logger.Error(err) w.WriteHeader(http.StatusInternalServerError) @@ -233,34 +228,6 @@ func (h *Handler) GetSupportBundleCommand(w http.ResponseWriter, r *http.Request return } - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - response.Command = []string{ - "curl https://krew.sh/support-bundle | bash", - "kubectl support-bundle --load-cluster-specs", - } - - opts := types.TroubleshootOptions{ - Origin: getSupportBundleCommandRequest.Origin, - InCluster: false, - } - - if _, err := supportbundle.CreateSupportBundleDependencies(helmApp, helmApp.GetCurrentSequence(), opts); err != nil { - logger.Error(errors.Wrap(err, "failed to create support bundle spec")) - JSON(w, http.StatusOK, response) - return - } - - response.Command = supportbundle.GetBundleCommand(helmApp.GetSlug()) - JSON(w, http.StatusOK, response) - return - } - response.Command = []string{ "curl https://krew.sh/support-bundle | bash", "kubectl support-bundle --load-cluster-specs", @@ -472,11 +439,6 @@ func (h *Handler) DeleteSupportBundle(w http.ResponseWriter, r *http.Request) { } func (h *Handler) CollectSupportBundle(w http.ResponseWriter, r *http.Request) { - if util.IsHelmManaged() { - w.WriteHeader(http.StatusBadRequest) - return - } - a, err := store.GetStore().GetApp(mux.Vars(r)["appId"]) if err != nil { logger.Error(err) @@ -500,35 +462,6 @@ func (h *Handler) CollectSupportBundle(w http.ResponseWriter, r *http.Request) { JSON(w, http.StatusAccepted, collectSupportBundlesResponse) } -func (h *Handler) CollectHelmSupportBundle(w http.ResponseWriter, r *http.Request) { - appSlug := mux.Vars(r)["appSlug"] - - if !util.IsHelmManaged() { - w.WriteHeader(http.StatusBadRequest) - return - } - - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - bundleID, err := supportbundle.CollectHelm(helmApp) - if err != nil { - logger.Error(errors.Wrap(err, "failed to collect helm support bundle")) - w.WriteHeader(http.StatusInternalServerError) - return - } - - collectSupportBundlesResponse := CollectSupportBundlesResponse{ - ID: bundleID, - Slug: bundleID, - } - - JSON(w, http.StatusAccepted, collectSupportBundlesResponse) -} - // UploadSupportBundle route is UNAUTHENTICATED // This request comes from the `kubectl support-bundle` command. func (h *Handler) UploadSupportBundle(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/handlers/update.go b/pkg/handlers/update.go index ecbe6d8af8..24aa6a48e8 100644 --- a/pkg/handlers/update.go +++ b/pkg/handlers/update.go @@ -15,8 +15,6 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/replicatedhq/kots/pkg/airgap" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/kotsadm" "github.com/replicatedhq/kots/pkg/kurl" @@ -57,25 +55,11 @@ func (h *Handler) AppUpdateCheck(w http.ResponseWriter, r *http.Request) { contentType := strings.Split(r.Header.Get("Content-Type"), ";")[0] contentType = strings.TrimSpace(contentType) - var app apptypes.AppType - var kotsApp *apptypes.App - var err error - - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(appSlug) - if helmApp == nil { - w.WriteHeader(http.StatusNotFound) - return - } - app = helmApp - } else { - kotsApp, err = store.GetStore().GetAppFromSlug(appSlug) - if err != nil { - logger.Error(errors.Wrapf(err, "failed to get app for slug %q", appSlug)) - w.WriteHeader(http.StatusNotFound) - return - } - app = kotsApp + app, err := store.GetStore().GetAppFromSlug(appSlug) + if err != nil { + logger.Error(errors.Wrapf(err, "failed to get app for slug %q", appSlug)) + w.WriteHeader(http.StatusNotFound) + return } if contentType == "application/json" { @@ -100,15 +84,12 @@ func (h *Handler) AppUpdateCheck(w http.ResponseWriter, r *http.Request) { return } - if !util.IsHelmManaged() { - // refresh the app to get the correct sequence - kotsApp, err = store.GetStore().GetApp(app.GetID()) - if err != nil { - logger.Error(errors.Wrap(err, "failed to get app")) - w.WriteHeader(http.StatusNotFound) - return - } - app = kotsApp + // refresh the app to get the correct sequence + app, err = store.GetStore().GetApp(app.GetID()) + if err != nil { + logger.Error(errors.Wrap(err, "failed to get app")) + w.WriteHeader(http.StatusNotFound) + return } var appUpdateCheckResponse AppUpdateCheckResponse @@ -147,7 +128,7 @@ func (h *Handler) AppUpdateCheck(w http.ResponseWriter, r *http.Request) { } if contentType == "multipart/form-data" { - if !kotsApp.IsAirgap { + if !app.IsAirgap { logger.Error(errors.New("not an airgap app")) w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Cannot update an online install using an airgap bundle")) @@ -203,7 +184,7 @@ func (h *Handler) AppUpdateCheck(w http.ResponseWriter, r *http.Request) { tasks.StartUpdateTaskMonitor("update-download", finishedChan) - err = airgap.UpdateAppFromPath(kotsApp, rootDir, "", deploy, skipPreflights, skipCompatibilityCheck) + err = airgap.UpdateAppFromPath(app, rootDir, "", deploy, skipPreflights, skipCompatibilityCheck) if err != nil { finishedChan <- err diff --git a/pkg/handlers/update_checker_spec.go b/pkg/handlers/update_checker_spec.go index d7417c53b0..5dbc2b163c 100644 --- a/pkg/handlers/update_checker_spec.go +++ b/pkg/handlers/update_checker_spec.go @@ -7,12 +7,10 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/store" "github.com/replicatedhq/kots/pkg/updatechecker" - "github.com/replicatedhq/kots/pkg/util" cron "github.com/robfig/cron/v3" ) @@ -42,52 +40,6 @@ func (h *Handler) SetAutomaticUpdatesConfig(w http.ResponseWriter, r *http.Reque return } - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(mux.Vars(r)["appSlug"]) - license, err := helm.GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - logger.Error(errors.Wrap(err, updateCheckerSpecResponse.Error)) - JSON(w, http.StatusInternalServerError, updateCheckerSpecResponse) - return - } - if license == nil { - w.WriteHeader(http.StatusNotFound) - return - } - - if helmApp.GetIsAirgap() { - updateCheckerSpecResponse.Error = "airgap scheduled update checks are not supported" - logger.Error(errors.New(updateCheckerSpecResponse.Error)) - JSON(w, http.StatusBadRequest, updateCheckerSpecResponse) - return - } - - // validate cron spec - cronSpec := configureAutomaticUpdatesRequest.UpdateCheckerSpec - if cronSpec != "@never" && cronSpec != "@default" { - _, err := cron.ParseStandard(cronSpec) - if err != nil { - updateCheckerSpecResponse.Error = "failed to parse cron spec" - logger.Error(errors.Wrap(err, updateCheckerSpecResponse.Error)) - JSON(w, http.StatusInternalServerError, updateCheckerSpecResponse) - return - } - } - - helm.SetUpdateCheckSpec(helmApp, cronSpec) - - // reconfigure update checker for the app - if err := updatechecker.Configure(helmApp, cronSpec); err != nil { - updateCheckerSpecResponse.Error = "failed to reconfigure update checker cron job" - logger.Error(errors.Wrap(err, updateCheckerSpecResponse.Error)) - JSON(w, http.StatusInternalServerError, updateCheckerSpecResponse) - return - } - - JSON(w, http.StatusNoContent, "") - return - } - foundApp, err := store.GetStore().GetAppFromSlug(mux.Vars(r)["appSlug"]) if err != nil { updateCheckerSpecResponse.Error = "failed to get app from slug" @@ -166,33 +118,15 @@ func (h *Handler) SetAutomaticUpdatesConfig(w http.ResponseWriter, r *http.Reque func (h *Handler) GetAutomaticUpdatesConfig(w http.ResponseWriter, r *http.Request) { getCheckerSpecResponse := &GetAutomaticUpdatesConfigResponse{} - if util.IsHelmManaged() { - helmApp := helm.GetHelmApp(mux.Vars(r)["appSlug"]) - if helmApp == nil { - JSON(w, http.StatusNotFound, getCheckerSpecResponse) - return - } - - spec, err := helm.GetUpdateCheckSpec(helmApp) - if err != nil { - getCheckerSpecResponse.Error = "failed to get schedule spec map" - logger.Error(errors.Wrap(err, getCheckerSpecResponse.Error)) - JSON(w, http.StatusInternalServerError, getCheckerSpecResponse) - return - } - - getCheckerSpecResponse.UpdateCheckerSpec = spec - } else { - foundApp, err := store.GetStore().GetAppFromSlug(mux.Vars(r)["appSlug"]) - if err != nil { - getCheckerSpecResponse.Error = "failed to get app from slug" - logger.Error(errors.Wrap(err, getCheckerSpecResponse.Error)) - JSON(w, http.StatusInternalServerError, getCheckerSpecResponse) - return - } - getCheckerSpecResponse.UpdateCheckerSpec = foundApp.UpdateCheckerSpec - getCheckerSpecResponse.AutoDeploy = foundApp.AutoDeploy + foundApp, err := store.GetStore().GetAppFromSlug(mux.Vars(r)["appSlug"]) + if err != nil { + getCheckerSpecResponse.Error = "failed to get app from slug" + logger.Error(errors.Wrap(err, getCheckerSpecResponse.Error)) + JSON(w, http.StatusInternalServerError, getCheckerSpecResponse) + return } + getCheckerSpecResponse.UpdateCheckerSpec = foundApp.UpdateCheckerSpec + getCheckerSpecResponse.AutoDeploy = foundApp.AutoDeploy JSON(w, http.StatusOK, getCheckerSpecResponse) } diff --git a/pkg/helm/cache.go b/pkg/helm/cache.go deleted file mode 100644 index 4b872d06ca..0000000000 --- a/pkg/helm/cache.go +++ /dev/null @@ -1,321 +0,0 @@ -package helm - -import ( - "context" - "io/ioutil" - "strconv" - "sync" - "time" - - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/k8sutil" - "github.com/replicatedhq/kots/pkg/kotsadmconfig" - "github.com/replicatedhq/kots/pkg/logger" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" - storetypes "github.com/replicatedhq/kots/pkg/store/types" - "github.com/replicatedhq/kots/pkg/util" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - helmrelease "helm.sh/helm/v3/pkg/release" - corev1 "k8s.io/api/core/v1" - kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/watch" -) - -// TODO: Support same releases names in different namespaces -var ( - helmAppCache = map[string]*apptypes.HelmApp{} - tmpValuesRoot string - appCacheLock sync.Mutex -) - -func Init(ctx context.Context) error { - tmpDir, err := ioutil.TempDir("", "helm-values-") - if err != nil { - return errors.Wrap(err, "failed to create temp dir") - } - tmpValuesRoot = tmpDir - - clientSet, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } - - namespacesToWatch := []string{} - if k8sutil.IsKotsadmClusterScoped(ctx, clientSet, util.PodNamespace) { - namespaces, err := clientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) - if err != nil { - return errors.Wrap(err, "failed to get namespaces") - } - for _, ns := range namespaces.Items { - namespacesToWatch = append(namespacesToWatch, ns.Name) - } - } else { - namespacesToWatch = []string{util.PodNamespace} - } - - for _, namespace := range namespacesToWatch { - secretsSelector := labels.SelectorFromSet(map[string]string{"owner": "helm"}).String() - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: secretsSelector, - }) - if err != nil { - if !kuberneteserrors.IsForbidden(err) && !kuberneteserrors.IsNotFound(err) { - logger.Warnf("failed to list secrets for namespace: %s", namespace) - } - continue - } - - initMonitor(clientSet, namespace) - for _, s := range secrets.Items { - if s.Labels == nil || s.Labels["status"] != helmrelease.StatusDeployed.String() { - continue - } - - releaseInfo, err := helmAppFromSecret(&s) - if err != nil { - logger.Errorf("failed to get helm release from secret %s: %v", s.Name, err) - continue - } - if releaseInfo == nil { - continue - } - if releaseInfo.Release.Chart.Values["replicated"] == nil { - continue - } - - AddHelmApp(releaseInfo.Release.Name, releaseInfo) - resumeHelmStatusInformers(releaseInfo.Release.Name) - } - - go func(namespace string) { - err := watchSecrets(ctx, namespace, secretsSelector) - if err != nil { - logger.Errorf("Faied to watch secrets in ns %s and application cache will not be updated: %v", err) - } - }(namespace) - } - - return nil -} - -func GetHelmApp(releaseName string) *apptypes.HelmApp { - appCacheLock.Lock() - defer appCacheLock.Unlock() - - return helmAppCache[releaseName] -} - -func GetCachedHelmApps() []string { - appCacheLock.Lock() - defer appCacheLock.Unlock() - - releases := []string{} - for k, _ := range helmAppCache { - releases = append(releases, k) - } - return releases -} - -func AddHelmApp(releaseName string, helmApp *apptypes.HelmApp) { - appCacheLock.Lock() - defer appCacheLock.Unlock() - helmAppCache[releaseName] = helmApp -} - -func RemoveHelmApp(releaseName string) { - appCacheLock.Lock() - defer appCacheLock.Unlock() - - delete(helmAppCache, releaseName) -} - -func helmAppFromSecret(secret *corev1.Secret) (*apptypes.HelmApp, error) { - helmRelease, err := HelmReleaseFromSecretData(secret.Data["release"]) - if err != nil { - return nil, errors.Wrap(err, "failed to get helm release from secret") - } - - version, err := strconv.ParseInt(secret.Labels["version"], 10, 64) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release version") - } - - helmApp := &apptypes.HelmApp{ - Release: *helmRelease, - Labels: secret.Labels, - Version: version, - CreationTimestamp: secret.CreationTimestamp.Time, - Namespace: secret.Namespace, - TempConfigValues: map[string]kotsv1beta1.ConfigValue{}, - } - - configSecret, err := GetChartConfigSecret(helmApp) - if err != nil && !kuberneteserrors.IsNotFound(err) { - return nil, errors.Wrap(err, "failed to get helm config secret") - } - - if configSecret == nil { - return helmApp, nil - } - - _, helmApp.IsConfigurable = configSecret.Data["config"] // TODO: also check if there are any config items - helmApp.ChartPath = string(configSecret.Data["chartPath"]) - - return helmApp, nil -} - -func GetKotsLicenseID(release *helmrelease.Release) string { - if release == nil { - return "" - } - - replValuesInterface := release.Chart.Values["replicated"] - if replValuesInterface == nil { - return "" - } - - replValues, ok := replValuesInterface.(map[string]interface{}) - if !ok { - return "" - } - - licenseIDInterface, ok := replValues["license_id"] - if !ok { - return "" - } - - licenseID, ok := licenseIDInterface.(string) - if !ok { - return "" - } - - return licenseID -} - -func watchSecrets(ctx context.Context, namespace string, labelSelector string) error { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } - - opts := metav1.ListOptions{ - LabelSelector: labelSelector, - Watch: true, - } - - secrets := clientSet.CoreV1().Secrets(namespace) - for { - w, err := secrets.Watch(ctx, opts) - if err != nil { - logger.Warnf("failed to list secrets %s for namespace %s: %v", labelSelector, namespace, err) - time.Sleep(time.Second * 20) - continue - } - logger.Debugf("watching for changes to secrets in ns %s", namespace) - for e := range w.ResultChan() { - switch e.Type { - case watch.Added, watch.Modified: - secret, ok := e.Object.(*corev1.Secret) - if !ok { - break - } - logger.Debugf("got event %s for secret %s in ns %s", e.Type, secret.Name, namespace) - if secret.Labels == nil || secret.Labels["status"] != helmrelease.StatusDeployed.String() { - continue - } - helmApp, err := helmAppFromSecret(secret) - if err != nil { - logger.Errorf("failed to create helm release info from secret %s in namespace %s: %s", secret.Name, namespace) - break - } - if helmApp == nil { - break - } - if helmApp.Release.Chart.Values["replicated"] == nil { - break - } - - if err := recalculateCachedUpdates(helmApp); err != nil { - logger.Errorf("failed to recalculate updates for helm release info from secret %s in namespace %s: %s", secret.Name, namespace, err) - // Continue here. Release has been installed and should show up up in Admin Console. - } - - logger.Debugf("adding secret %s to cache", secret.Name) - AddHelmApp(helmApp.Release.Name, helmApp) - resumeHelmStatusInformers(helmApp.Release.Name) - case watch.Deleted: - secret, ok := e.Object.(*corev1.Secret) - if !ok { - break - } - - helmRelease, err := HelmReleaseFromSecretData(secret.Data["release"]) - if err != nil { - logger.Errorf("failed to get helm release from secret in delete event", err) - break - } - - // Get app from cache because the config secret is likely gone now, and we can't construct this data from cluster - helmApp := GetHelmApp(helmRelease.Name) - if helmApp == nil { - break - } - - deleteUpdateCacheForChart(helmApp.ChartPath) - - RemoveHelmApp(helmApp.Release.Name) - default: - secret, ok := e.Object.(*corev1.Secret) - if !ok { - break - } - logger.Debugf("%v event ignored for secret %s in namespace %s", e.Type, secret.Name, namespace) - } - } - logger.Infof("watch of secrets in ns %s unexpectedly terminated. Reconnecting...\n", namespace) - time.Sleep(time.Second * 5) - } -} - -func recalculateCachedUpdates(newHelmApp *apptypes.HelmApp) error { - removeFromCachedUpdates(newHelmApp.ChartPath, newHelmApp.Release.Chart.Metadata.Version) - - currentHelmApp := GetHelmApp(newHelmApp.Release.Name) - if currentHelmApp == nil { - // no app installed yet - return nil - } - updates := GetCachedUpdates(currentHelmApp.ChartPath) - currentKotsKinds, err := GetKotsKindsFromHelmApp(currentHelmApp) - if err != nil { - return errors.Wrapf(err, "failed to get current config values") - } - - // Check if new configuration has been applied and now required items have been set in pending updates. - for _, update := range updates { - if update.Status != storetypes.VersionPendingConfig { - continue - } - - kotsKinds, err := GetKotsKindsFromUpstreamChartVersion(currentHelmApp, currentKotsKinds.License.Spec.LicenseID, update.Tag) - if err != nil { - return errors.Wrapf(err, "failed to pull update %s for chart", update.Version) - } - kotsKinds.ConfigValues = currentKotsKinds.ConfigValues.DeepCopy() - - sequence := int64(-1) // TODO: do something sensible, this value isn't used - registrySettings := registrytypes.RegistrySettings{} // TODO: private registries aren't supported yet - t, err := kotsadmconfig.NeedsConfiguration(currentHelmApp.GetSlug(), sequence, currentHelmApp.GetIsAirgap(), &kotsKinds, registrySettings) - if err != nil { - return errors.Wrap(err, "failed to check if version needs configuration") - } - if !t { - SetCachedUpdateStatus(currentHelmApp.ChartPath, update.Tag, storetypes.VersionPending) - } - } - - return nil -} diff --git a/pkg/helm/charts.go b/pkg/helm/charts.go deleted file mode 100644 index 63a6f6e6eb..0000000000 --- a/pkg/helm/charts.go +++ /dev/null @@ -1,582 +0,0 @@ -package helm - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "io/ioutil" - "sort" - "strconv" - "sync" - "text/template" - "time" - - "github.com/blang/semver" - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/k8sutil" - "github.com/replicatedhq/kots/pkg/kotsutil" - "github.com/replicatedhq/kots/pkg/logger" - "github.com/replicatedhq/kots/pkg/replicatedapp" - "github.com/replicatedhq/kots/pkg/util" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - kotsscheme "github.com/replicatedhq/kotskinds/client/kotsclientset/scheme" - helmrelease "helm.sh/helm/v3/pkg/release" - corev1 "k8s.io/api/core/v1" - kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes/scheme" -) - -var ( - configSecretMutex sync.Mutex -) - -// Secret labels from Helm v3 code: -// -// lbs.set("name", rls.Name) -// lbs.set("owner", owner) -// lbs.set("status", rls.Info.Status.String()) -// lbs.set("version", strconv.Itoa(rls.Version)) -type InstalledRelease struct { - ReleaseName string - Revision int - Version string - Semver *semver.Version - Status helmrelease.Status - DeployedOn *time.Time - ReleasedOn *time.Time -} - -type InstalledReleases []InstalledRelease - -func (v InstalledReleases) Len() int { - return len(v) -} - -func (v InstalledReleases) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} - -func (v InstalledReleases) Less(i, j int) bool { - return v[i].Version < v[j].Version -} - -func GetChartSecret(releaseName, namespace, version string) (*helmrelease.Release, error) { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "name": releaseName, - "version": version, - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), listOpts) - if err != nil { - if kuberneteserrors.IsNotFound(err) { - return nil, nil - } - return nil, errors.Wrap(err, "failed to list secrets") - } - if len(secrets.Items) > 1 { - return nil, errors.New("found multiple secrets for single release revision") - } - - helmRelease, err := HelmReleaseFromSecretData(secrets.Items[0].Data["release"]) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release info from secret") - } - - return helmRelease, nil -} - -func ListChartVersions(releaseName string, namespace string) ([]InstalledRelease, error) { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "name": releaseName, - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), listOpts) - if err != nil { - if kuberneteserrors.IsNotFound(err) { - return InstalledReleases{}, nil - } - return nil, errors.Wrap(err, "failed to list secrets") - } - - releases := InstalledReleases{} - for _, secret := range secrets.Items { - release, err := getChartVersionFromSecretData(&secret) - if err != nil { - logger.Warnf("failed to create release from secret chart %s revision number %v: %v", releaseName, secret.Labels["version"], err) - continue - } - - releases = append(releases, *release) - } - - sort.Sort(sort.Reverse(releases)) - - return releases, nil -} - -func GetChartVersion(releaseName string, revision int64, namespace string) (*InstalledRelease, error) { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "name": releaseName, - "version": fmt.Sprintf("%d", revision), - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), listOpts) - if err != nil { - return nil, errors.Wrap(err, "failed to list secrets") - } - - if len(secrets.Items) == 0 { - return nil, nil - } - - if len(secrets.Items) != 1 { - return nil, errors.Errorf("found %d secrets but expected 1", len(secrets.Items)) - } - - release, err := getChartVersionFromSecretData(&secrets.Items[0]) - if err != nil { - return nil, errors.Wrap(err, "failed to create release from secret") - } - - return release, nil -} - -func getChartVersionFromSecretData(secret *corev1.Secret) (*InstalledRelease, error) { - revision, err := strconv.Atoi(secret.Labels["version"]) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release version") - } - - helmRelease, err := HelmReleaseFromSecretData(secret.Data["release"]) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release data") - } - - release := InstalledRelease{ - ReleaseName: secret.Labels["releaseName"], - Revision: revision, - Status: helmrelease.Status(secret.Labels["status"]), - DeployedOn: &secret.CreationTimestamp.Time, - } - - createdAt := util.GetValueFromMapPath(helmRelease.Chart.Values, []string{"replicated", "created_at"}) - if s, ok := createdAt.(string); ok { - t, err := time.Parse(time.RFC3339, s) - if err == nil { - release.ReleasedOn = &t - } - } - - if helmRelease.Chart != nil && helmRelease.Chart.Metadata != nil { - release.Version = helmRelease.Chart.Metadata.Version - } - - sv, err := semver.ParseTolerant(release.Version) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release version") - } - release.Semver = &sv - - return &release, nil -} - -func HelmReleaseFromSecretData(data []byte) (*helmrelease.Release, error) { - base64Reader := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data)) - gzreader, err := gzip.NewReader(base64Reader) - if err != nil { - return nil, errors.Wrap(err, "failed to create gzip reader") - } - defer gzreader.Close() - - releaseData, err := ioutil.ReadAll(gzreader) - if err != nil { - return nil, errors.Wrap(err, "failed to read from gzip reader") - } - - release := &helmrelease.Release{} - err = json.Unmarshal(releaseData, &release) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal release data") - } - - return release, nil -} - -func GetChartConfigSecret(helmApp *apptypes.HelmApp) (*corev1.Secret, error) { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - - // Note that this is release name - chart name to support deploying multiple instances - secretName := fmt.Sprintf("kots-%s-%s-config", helmApp.Release.Chart.Name(), helmApp.Release.Name) - secret, err := clientSet.CoreV1().Secrets(helmApp.Namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) - if err != nil { - if kuberneteserrors.IsNotFound(err) { - return nil, nil - } - return nil, errors.Wrap(err, "failed to get secret") - } - - return secret, nil -} - -func GetChartLicenseFromSecretOrDownload(helmApp *apptypes.HelmApp) (*kotsv1beta1.License, error) { - configSecret, err := GetChartConfigSecret(helmApp) - if err != nil { - return nil, errors.Wrap(err, "failed to get helm config secret") - } - - if configSecret == nil { - return nil, errors.Errorf("no config secret found for release %s", helmApp.Release.Name) - } - - if licenseData := configSecret.Data["license"]; len(licenseData) > 0 { - decode := kotsscheme.Codecs.UniversalDeserializer().Decode - obj, gvk, err := decode(licenseData, nil, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to decode license data") - } - - if gvk.Group != "kots.io" || gvk.Version != "v1beta1" || gvk.Kind != "License" { - return nil, errors.Errorf("unexpected GVK: %s", gvk.String()) - } - - return obj.(*kotsv1beta1.License), nil - } - - license, err := downloadAppLicense(helmApp) - if err != nil { - return nil, errors.Wrap(err, "failed to download app license") - } - - return license, nil -} - -func downloadAppLicense(helmApp *apptypes.HelmApp) (*kotsv1beta1.License, error) { - licenseID := GetKotsLicenseID(&helmApp.Release) - if licenseID == "" { - return nil, errors.Errorf("no license and no license ID found for release %s", helmApp.Release.Name) - } - - licenseData, err := replicatedapp.GetLatestLicenseForHelm(licenseID) - if err != nil { - return nil, errors.Wrapf(err, "failed to get license for helm chart %s", helmApp.Release.Name) - } - - if err := SaveChartLicenseInSecret(helmApp, licenseData.LicenseBytes); err != nil { - return nil, errors.Wrapf(err, "failed save license in config for chart %s", helmApp.Release.Name) - } - - return licenseData.License, nil -} - -// Always save original data returned from the server without remarshaling. -func SaveChartLicenseInSecret(helmApp *apptypes.HelmApp, licenseData []byte) error { - configSecretMutex.Lock() - defer configSecretMutex.Unlock() - - secret, err := GetChartConfigSecret(helmApp) - if err != nil { - return errors.Wrap(err, "failed to get config secret for license update") - } - - if secret == nil { - return errors.Errorf("secret not found") - } - - secret.Data["license"] = licenseData - - clientSet, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } - - _, err = clientSet.CoreV1().Secrets(secret.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}) - if err != nil { - // TODO: retry on IsConflict - return errors.Wrap(err, "failed to update secret") - } - - return nil -} - -func GetKotsKindsFromHelmApp(helmApp *apptypes.HelmApp) (kotsutil.KotsKinds, error) { - kotsKinds := kotsutil.EmptyKotsKinds() - - secret, err := GetChartConfigSecret(helmApp) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get helm config secret") - } - - if secret == nil { - return kotsKinds, nil - } - - kotsKinds, err = GetKotsKindsFromReplicatedSecret(secret) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get kots kinds from secret") - } - - if kotsKinds.License == nil { - license, err := downloadAppLicense(helmApp) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to download license") - } - kotsKinds.License = license - } - - return kotsKinds, nil -} - -func GetKotsKindsFromReplicatedSecret(secret *corev1.Secret) (kotsutil.KotsKinds, error) { - kotsKinds := kotsutil.EmptyKotsKinds() - - licenseData := secret.Data["license"] - if len(licenseData) != 0 { - license, err := kotsutil.LoadLicenseFromBytes(licenseData) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to load license from data") - } - kotsKinds.License = license - } - - configData := secret.Data["config"] - if len(configData) != 0 { - config, err := kotsutil.LoadConfigFromBytes(configData) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to load config from data") - } - kotsKinds.Config = config - } - - configValuesData := secret.Data["configValues"] - if len(configValuesData) != 0 { - configValues, err := kotsutil.LoadConfigValuesFromBytes(configValuesData) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to load config values from data") - } - kotsKinds.ConfigValues = configValues - } - - appData := secret.Data["application"] - if len(appData) != 0 { - app, err := kotsutil.LoadApplicationFromBytes(appData) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to load application from data") - } - kotsKinds.KotsApplication = *app - } - - return kotsKinds, nil -} - -func GetKotsKindsForRevision(releaseName string, revision int64, namespace string) (kotsutil.KotsKinds, error) { - kotsKinds := kotsutil.EmptyKotsKinds() - - clientSet, err := k8sutil.GetClientset() - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "version": fmt.Sprintf("%d", revision), - "name": releaseName, - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), listOpts) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to list secrets") - } - - if len(secrets.Items) != 1 { - return kotsKinds, errors.Errorf("expected to match 1 secret, but found %d", len(secrets.Items)) - } - - chartSecret := secrets.Items[0] - helmApp, err := helmAppFromSecret(&chartSecret) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to convert secret to helm app") - } - - license, err := GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get license") - } - kotsKinds.License = license - - // "Config" object is in the template secret. - for _, template := range helmApp.Release.Chart.Templates { - if template.Name != "templates/_replicated/secret.yaml" { - continue - } - - secretData, err := removeHelmTemplate(template.Data) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to remove helm templates from replicated secret file") - } - - decode := scheme.Codecs.UniversalDeserializer().Decode - obj, gvk, err := decode(secretData, nil, nil) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to decode secret data") - } - - if gvk.Group != "" || gvk.Version != "v1" || gvk.Kind != "Secret" { - return kotsKinds, errors.Errorf("unexpected secret GVK: %s", gvk.String()) - } - - k, err := GetKotsKindsFromReplicatedSecret(obj.(*corev1.Secret)) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get kots kinds from secret") - } - - kotsKinds.Config = k.Config - kotsKinds.Application = k.Application - - break - } - - // If chart was deployed with --values, they will be in Config. Otherwise, get the default values injected by the registry - encodedConfigValues := util.GetValueFromMapPath(helmApp.Release.Config, []string{"replicated", "app", "configValues"}) - if encodedConfigValues == nil { - encodedConfigValues = util.GetValueFromMapPath(helmApp.Release.Chart.Values, []string{"replicated", "app", "configValues"}) - } - - if encodedConfigValues == nil { - return kotsKinds, errors.Errorf("failed to find configValues from release %s", helmApp.Release.Name) - } - - configValuesData, err := util.Base64DecodeInterface(encodedConfigValues) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to base64 decode config values from chart release") - } - - kotsKinds.ConfigValues, err = kotsutil.LoadConfigValuesFromBytes(configValuesData) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get config values from chart values") - } - - return kotsKinds, nil -} - -func GetReplicatedSecretForRevision(releaseName string, revision int64, namespace string) (*corev1.Secret, error) { - clientSet, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "version": fmt.Sprintf("%d", revision), - "name": releaseName, - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(namespace).List(context.TODO(), listOpts) - if err != nil { - return nil, errors.Wrap(err, "failed to list secrets") - } - - if len(secrets.Items) != 1 { - return nil, errors.Errorf("expected to match 1 secret, but found %d", len(secrets.Items)) - } - - chartSecret := secrets.Items[0] - helmApp, err := helmAppFromSecret(&chartSecret) - if err != nil { - return nil, errors.Wrap(err, "failed to convert secret to helm app") - } - - for _, template := range helmApp.Release.Chart.Templates { - if template.Name != "templates/_replicated/secret.yaml" { - continue - } - - secretData, err := removeHelmTemplate(template.Data) - if err != nil { - return nil, errors.Wrap(err, "failed to remove helm templates from replicated secret file") - } - - decode := scheme.Codecs.UniversalDeserializer().Decode - obj, gvk, err := decode(secretData, nil, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to decode secret data") - } - - if gvk.Group != "" || gvk.Version != "v1" || gvk.Kind != "Secret" { - return nil, errors.Errorf("unexpected secret GVK: %s", gvk.String()) - } - - return obj.(*corev1.Secret), nil - } - - return nil, errors.Errorf("replicated secret template not found for chart %q, revision %d, in ns %q", releaseName, revision, namespace) -} - -func removeHelmTemplate(doc []byte) ([]byte, error) { - type Inventory struct { - Material string - Count uint - } - replicatedValues := map[string]interface{}{ - "Values": map[string]interface{}{ - "replicated": map[string]interface{}{ - "app": map[string]interface{}{ - "configValues": base64.RawStdEncoding.EncodeToString(nil), - }, - }, - }, - } - tmpl, err := template.New("sanitize-helm").Parse(string(doc)) - if err != nil { - return nil, errors.Wrap(err, "failed to parse doc as template") - } - - b := bytes.NewBuffer(nil) - err = tmpl.Execute(b, replicatedValues) - if err != nil { - return nil, errors.Wrap(err, "failed to execute template") - } - - return b.Bytes(), nil -} diff --git a/pkg/helm/helm.go b/pkg/helm/helm.go deleted file mode 100644 index a86320d1b8..0000000000 --- a/pkg/helm/helm.go +++ /dev/null @@ -1,253 +0,0 @@ -package helm - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/blang/semver" - imagedocker "github.com/containers/image/v5/docker" - dockerref "github.com/containers/image/v5/docker/reference" - "github.com/pkg/errors" - downstreamtypes "github.com/replicatedhq/kots/pkg/api/downstream/types" - "github.com/replicatedhq/kots/pkg/api/handlers/types" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/docker/registry" - "github.com/replicatedhq/kots/pkg/kotsutil" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" - "github.com/replicatedhq/kots/pkg/render" - storetypes "github.com/replicatedhq/kots/pkg/store/types" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - helmval "helm.sh/helm/v3/pkg/cli/values" - "helm.sh/helm/v3/pkg/helmpath" - helmregistry "helm.sh/helm/v3/pkg/registry" - serializer "k8s.io/apimachinery/pkg/runtime/serializer/json" - "k8s.io/client-go/kubernetes/scheme" -) - -func RenderValuesFromConfig(helmApp *apptypes.HelmApp, kotsKinds *kotsutil.KotsKinds, chart []byte) (map[string]interface{}, error) { - builder, err := render.NewBuilder(kotsKinds, registrytypes.RegistrySettings{}, helmApp.GetSlug(), helmApp.GetCurrentSequence(), helmApp.GetIsAirgap(), helmApp.Namespace) - if err != nil { - return nil, errors.Wrap(err, "failed to make tempalate builder") - } - - renderedHelmManifest, err := builder.RenderTemplate("helm", string(chart)) - if err != nil { - return nil, err - } - - kotsHelmChart, err := kotsutil.LoadV1Beta1HelmChartFromContents([]byte(renderedHelmManifest)) - if err != nil { - return nil, err - } - - mergedValues := kotsHelmChart.Spec.Values - for _, optionalValues := range kotsHelmChart.Spec.OptionalValues { - include, err := strconv.ParseBool(optionalValues.When) - if err != nil { - return nil, err - } - if !include { - continue - } - if optionalValues.RecursiveMerge { - mergedValues = kotsv1beta1.MergeHelmChartValues(mergedValues, optionalValues.Values) - } else { - for k, v := range optionalValues.Values { - mergedValues[k] = v - } - } - } - - renderedValues, err := kotsHelmChart.Spec.GetHelmValues(mergedValues) - if err != nil { - return nil, err - } - - return renderedValues, nil -} - -func GetMergedValues(releasedValues, renderedValues map[string]interface{}) (map[string]interface{}, error) { - dir, err := ioutil.TempDir("", "helm-merged-values-") - if err != nil { - return nil, err - } - defer os.RemoveAll(dir) - - releasedB, err := json.Marshal(releasedValues) - if err != nil { - return nil, err - - } - renderedB, err := json.Marshal(renderedValues) - if err != nil { - return nil, err - } - releaseValsFilename := fmt.Sprintf("%s/releasevalues.yaml", dir) - renderedValsFilename := fmt.Sprintf("%s/renderedvalues.yaml", dir) - if err := ioutil.WriteFile(releaseValsFilename, releasedB, 0644); err != nil { - return nil, err - } - - if err := ioutil.WriteFile(renderedValsFilename, renderedB, 0644); err != nil { - return nil, err - } - - helmopts := &helmval.Options{ValueFiles: []string{releaseValsFilename, renderedValsFilename}} - mergedHelmVals, err := helmopts.MergeValues(nil) - if err != nil { - return nil, err - } - - return mergedHelmVals, nil -} - -func CreateHelmRegistryCreds(username string, password string, url string) error { - url = strings.TrimLeft(url, "oci://") - ref, err := imagedocker.ParseReference(fmt.Sprintf("//%s", url)) - if err != nil { - return errors.Wrapf(err, "failed to parse support bundle ref %q", url) - } - dockerRef := ref.DockerReference() - - registryHost := dockerref.Domain(dockerRef) - - dockercfgAuth := registry.DockercfgAuth{ - Auth: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password))), - } - - dockerCfgJSON := registry.DockerCfgJSON{ - Auths: map[string]registry.DockercfgAuth{ - registryHost: dockercfgAuth, - }, - } - data, err := json.MarshalIndent(dockerCfgJSON, "", " ") - if err != nil { - return errors.Wrap(err, "failed to marshal helm registry credentials") - } - - filename := helmpath.ConfigPath(helmregistry.CredentialsFileBasename) - - err = os.MkdirAll(filepath.Dir(filename), 0700) - if err != nil { - return errors.Wrap(err, "failed to create directory for helm registry credentials") - } - - err = ioutil.WriteFile(filename, data, 0600) - if err != nil { - return errors.Wrap(err, "failed to save helm registry credentials") - } - - return nil -} - -func GetConfigValuesMap(configValues *kotsv1beta1.ConfigValues) (map[string]interface{}, error) { - s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) - var configValuesBuffer bytes.Buffer - if err := s.Encode(configValues, &configValuesBuffer); err != nil { - return nil, errors.Wrap(err, "failed to encode config values") - } - - configValuesMap := map[string]interface{}{ - "replicated": map[string]interface{}{ - "app": map[string][]byte{ // "byte" for base64 encoding - "configValues": configValuesBuffer.Bytes(), - }, - }, - } - - return configValuesMap, nil -} - -func HelmUpdateToDownsreamVersion(update ChartUpdate, sequence int64) *downstreamtypes.DownstreamVersion { - return &downstreamtypes.DownstreamVersion{ - VersionLabel: update.Tag, - Semver: &update.Version, - UpdateCursor: update.Tag, - Sequence: sequence, - ParentSequence: sequence, - CreatedOn: update.CreatedOn, - UpstreamReleasedAt: update.CreatedOn, - IsDeployable: false, // TODO: implement - NonDeployableCause: "not implemented", // TODO: implement - HasConfig: true, // TODO: implement - Source: "Upstream Update", - Status: update.Status, - } -} - -func ResponseAppFromHelmApp(helmApp *apptypes.HelmApp) (*types.HelmResponseApp, error) { - unixIntValue, err := strconv.ParseInt(helmApp.Labels["modifiedAt"], 10, 64) - var updatedTs time.Time - if err == nil { - updatedTs = time.Unix(unixIntValue, 0) - } - - sv, err := semver.ParseTolerant(helmApp.Release.Chart.Metadata.Version) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release version into semver") - } - - iconURI := "https://cncf-branding.netlify.app/img/projects/helm/horizontal/color/helm-horizontal-color.png" - // use chart icon if it exists, if not use default helm icon - if helmApp.Release.Chart.Metadata.Icon != "" { - iconURI = helmApp.Release.Chart.Metadata.Icon - } - - revision, err := strconv.Atoi(helmApp.Labels["version"]) - if err != nil { - return nil, errors.Wrap(err, "failed to parse release revision number") - } - - downstreamVersion := &downstreamtypes.DownstreamVersion{ - VersionLabel: helmApp.Release.Chart.Metadata.Version, - Semver: &sv, - Sequence: int64(revision), - ParentSequence: int64(revision), - Status: storetypes.VersionDeployed, - CreatedOn: &helmApp.Release.Info.FirstDeployed.Time, - DeployedAt: &helmApp.Release.Info.LastDeployed.Time, - } - - var username, password string - if replVals := helmApp.Release.Chart.Values["replicated"].(map[string]interface{}); replVals != nil { - username, _ = replVals["username"].(string) - password, _ = replVals["license_id"].(string) - } - - chartUpdates := GetDownloadedUpdates(helmApp.ChartPath) - pendingVersions := make([]*downstreamtypes.DownstreamVersion, len(chartUpdates), len(chartUpdates)) - nextSequence := revision + 1 - for i := len(chartUpdates) - 1; i >= 0; i-- { - pendingVersions[i] = HelmUpdateToDownsreamVersion(chartUpdates[i], int64(nextSequence)) - nextSequence = nextSequence + 1 - } - - return &types.HelmResponseApp{ - ResponseApp: types.ResponseApp{ - Name: helmApp.Labels["name"], - Namespace: helmApp.Namespace, - Slug: helmApp.Labels["name"], - CreatedAt: helmApp.CreationTimestamp, - IsConfigurable: helmApp.IsConfigurable, - UpdatedAt: &updatedTs, - IconURI: iconURI, - Downstream: types.ResponseDownstream{ - CurrentVersion: downstreamVersion, - PendingVersions: pendingVersions, - }, - }, - Credentials: types.Credentials{ - Username: username, - Password: password, - }, - ChartPath: helmApp.ChartPath, - }, nil -} diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go deleted file mode 100644 index 2c43208d2d..0000000000 --- a/pkg/helm/helm_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package helm - -import ( - "reflect" - "testing" - - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/kotsutil" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - helmrelease "helm.sh/helm/v3/pkg/release" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func Test_GetMergedValues(t *testing.T) { - tests := []struct { - name string - releaseValues map[string]interface{} - renderedValues map[string]interface{} - expectedValues map[string]interface{} - }{ - { - name: "empty values", - releaseValues: map[string]interface{}{}, - renderedValues: map[string]interface{}{}, - expectedValues: map[string]interface{}{}, - }, - { - name: "top level override", - releaseValues: map[string]interface{}{ - "nameOverride": "", - "imageVersion": "0.1.2", - }, - renderedValues: map[string]interface{}{ - "nameOverride": "override", - }, - expectedValues: map[string]interface{}{ - "nameOverride": "override", - "imageVersion": "0.1.2", - }, - }, - { - name: "nested override", - releaseValues: map[string]interface{}{ - "name": map[string]interface{}{ - "override": "", - }, - "imageVersion": "0.1.2", - }, - renderedValues: map[string]interface{}{ - "name": map[string]interface{}{ - "override": "override", - }, - }, - expectedValues: map[string]interface{}{ - "name": map[string]interface{}{ - "override": "override", - }, - "imageVersion": "0.1.2", - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - mergedValues, err := GetMergedValues(test.releaseValues, test.renderedValues) - if !reflect.DeepEqual(mergedValues, test.expectedValues) { - t.Errorf("GetMergedValues() = %v, want %v", mergedValues, test.expectedValues) - } - if err != nil { - t.Errorf("GetMergedValues() threw an error = %v", err) - } - }) - } -} - -func Test_RenderValuesFromConfig(t *testing.T) { - app := &apptypes.HelmApp{ - Version: 1, - Release: helmrelease.Release{ - Name: "testapp", - }, - } - - license := &kotsv1beta1.License{ - Spec: kotsv1beta1.LicenseSpec{}, - } - - tests := []struct { - name string - app *apptypes.HelmApp - newConfigItems *kotsv1beta1.ConfigValues - chart []byte - expectedValues map[string]interface{} - }{ - { - name: "top level override", - app: app, - newConfigItems: &kotsv1beta1.ConfigValues{ - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigValues", - APIVersion: "kots.io/v1beta1", - }, - Spec: kotsv1beta1.ConfigValuesSpec{ - Values: map[string]kotsv1beta1.ConfigValue{ - "myhelmvalue": { - Value: "myValue", - }, - }, - }, - }, - chart: []byte(`apiVersion: kots.io/v1beta1 -kind: HelmChart -metadata: - name: test-chart -spec: - chart: - name: test-chart - chartVersion: 0.3.17 - helmVersion: v3 - useHelmInstall: true - values: - myHelmValue: repl{{ConfigOption "myhelmvalue"}} -builder: {}`), - expectedValues: map[string]interface{}{ - "myHelmValue": "myValue", - }, - }, - { - name: "nested override", - app: app, - newConfigItems: &kotsv1beta1.ConfigValues{ - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigValues", - APIVersion: "kots.io/v1beta1", - }, - Spec: kotsv1beta1.ConfigValuesSpec{ - Values: map[string]kotsv1beta1.ConfigValue{ - "myhelmvalue": { - Value: "myValue", - }, - }, - }, - }, - chart: []byte(`apiVersion: kots.io/v1beta1 -kind: HelmChart -metadata: - name: test-chart -spec: - chart: - name: test-chart - chartVersion: 0.3.17 - helmVersion: v3 - useHelmInstall: true - values: - myHelmValue: - toOverride: repl{{ConfigOption "myhelmvalue"}} -builder: {}`), - expectedValues: map[string]interface{}{ - "myHelmValue": map[string]interface{}{ - "toOverride": "myValue", - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - kotsKinds := kotsutil.EmptyKotsKinds() - kotsKinds.License = license - kotsKinds.ConfigValues = test.newConfigItems - - renderedValues, err := RenderValuesFromConfig(test.app, &kotsKinds, test.chart) - if !reflect.DeepEqual(renderedValues, test.expectedValues) { - t.Errorf("RenderValuesFromConfig() = %v, want %v", renderedValues, test.expectedValues) - } - if err != nil { - t.Errorf("RenderValuesFromConfig() threw an error = %v", err) - } - }) - } -} diff --git a/pkg/helm/informers.go b/pkg/helm/informers.go deleted file mode 100644 index c8a3044b4a..0000000000 --- a/pkg/helm/informers.go +++ /dev/null @@ -1,181 +0,0 @@ -package helm - -import ( - "encoding/json" - "fmt" - "sync" - "time" - - "github.com/mitchellh/hashstructure" - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/appstate" - appstatetypes "github.com/replicatedhq/kots/pkg/appstate/types" - identitydeploy "github.com/replicatedhq/kots/pkg/identity/deploy" - identitytypes "github.com/replicatedhq/kots/pkg/identity/types" - "github.com/replicatedhq/kots/pkg/kotsutil" - "github.com/replicatedhq/kots/pkg/logger" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" - "github.com/replicatedhq/kots/pkg/render" - "github.com/replicatedhq/kots/pkg/template" - "github.com/replicatedhq/kots/pkg/util" - "k8s.io/client-go/kubernetes" -) - -var monitorMap map[string]*appstate.Monitor -var monitorMux *sync.Mutex - -func initMonitor(clientset kubernetes.Interface, targetNamespace string) { - if monitorMap == nil { - monitorMap = make(map[string]*appstate.Monitor) - monitorMux = new(sync.Mutex) - } - - monitorMux.Lock() - if monitorMap[targetNamespace] == nil { - monitorMap[targetNamespace] = appstate.NewMonitor(clientset, targetNamespace) - } - nsMon := monitorMap[targetNamespace] - monitorMux.Unlock() - - go runAppStateMonitor(nsMon) -} - -func getMonitor(namespace string) *appstate.Monitor { - monitorMux.Lock() - defer monitorMux.Unlock() - return monitorMap[namespace] -} - -func resumeHelmStatusInformers(appName string) { - helmApp := GetHelmApp(appName) - app := &apptypes.App{ - ID: helmApp.GetID(), - Slug: helmApp.GetSlug(), - Name: helmApp.Release.Name, - IsAirgap: helmApp.GetIsAirgap(), - CurrentSequence: helmApp.GetCurrentSequence(), - UpdatedAt: &helmApp.CreationTimestamp, - CreatedAt: helmApp.CreationTimestamp, - LastUpdateCheckAt: &helmApp.CreationTimestamp, - IsConfigurable: helmApp.IsConfigurable, - } - - kotsKinds, err := GetKotsKindsFromHelmApp(helmApp) - if err != nil { - logger.Errorf("failed to get kots kinds from helm app: %v\n", err) - return - } - - settings := registrytypes.RegistrySettings{ - Namespace: util.PodNamespace, - } - builder, err := render.NewBuilder(&kotsKinds, settings, app.Slug, helmApp.GetCurrentSequence(), app.IsAirgap, util.PodNamespace) - if err != nil { - logger.Errorf("failed to create new builder: %v\n", err) - return - } - - // apply the informers for this app since they havent been applied yet - if err := applyStatusInformers(app, helmApp.GetCurrentSequence(), &kotsKinds, builder, helmApp.Namespace); err != nil { - logger.Errorf("failed to apply status informers: %v\n", err) - return - } -} - -func applyStatusInformers(a *apptypes.App, sequence int64, kotsKinds *kotsutil.KotsKinds, builder *template.Builder, namespace string) error { - renderedInformers := []appstatetypes.StatusInformerString{} - - // render status informers - for _, informer := range kotsKinds.KotsApplication.Spec.StatusInformers { - renderedInformer, err := builder.String(informer) - if err != nil { - logger.Errorf("failed to render status informer: %v\n", err) - continue - } - if renderedInformer == "" { - continue - } - renderedInformers = append(renderedInformers, appstatetypes.StatusInformerString(renderedInformer)) - } - - if identitydeploy.IsEnabled(kotsKinds.Identity, kotsKinds.IdentityConfig) { - renderedInformers = append(renderedInformers, appstatetypes.StatusInformerString(fmt.Sprintf("deployment/%s", identitytypes.DeploymentName(a.Slug)))) - } - - if len(renderedInformers) > 0 { - applyAppInformers(a.ID, sequence, renderedInformers, namespace) - } else { - // no informers, set state to ready - defaultReadyState := appstatetypes.ResourceStates{ - { - Kind: "EMPTY", - Name: "EMPTY", - Namespace: "EMPTY", - State: appstatetypes.StateReady, - }, - } - - release := GetHelmApp(a.ID) - appStatus := appstatetypes.AppStatus{ - AppID: a.ID, - ResourceStates: defaultReadyState, - Sequence: release.GetCurrentSequence(), - UpdatedAt: time.Now(), - } - release.Status = appStatus - release.Status.State = appstatetypes.GetState(defaultReadyState) - } - - return nil -} - -func applyAppInformers(appID string, sequence int64, informerStrings []appstatetypes.StatusInformerString, namespace string) { - logger.Infof("received an inform event for appID (%s) sequence (%d) with informerStrings (%+v)\n", appID, sequence, informerStrings) - - var informers []appstatetypes.StatusInformer - for _, str := range informerStrings { - informer, err := str.Parse() - if err != nil { - logger.Infof("failed to parse informer %s: %s", str, err.Error()) - continue // don't stop - } - informers = append(informers, informer) - } - if len(informers) > 0 { - if mon := getMonitor(namespace); mon != nil { - mon.Apply(appID, sequence, informers) - } - } -} - -func runAppStateMonitor(monitor *appstate.Monitor) error { - m := map[string]func(f func()){} - hash := map[string]uint64{} - var mtx sync.Mutex - - for appStatus := range monitor.AppStatusChan() { - throttled, ok := m[appStatus.AppID] - if !ok { - throttled = util.NewThrottle(time.Second) - m[appStatus.AppID] = throttled - } - throttled(func() { - mtx.Lock() - lastHash := hash[appStatus.AppID] - nextHash, _ := hashstructure.Hash(appStatus, nil) - hash[appStatus.AppID] = nextHash - mtx.Unlock() - if lastHash != nextHash { - b, _ := json.Marshal(appStatus) - logger.Infof("Updating app status %s", b) - } - - app := GetHelmApp(appStatus.AppID) - app.Status = appStatus - app.Status.State = appstatetypes.GetState(appStatus.ResourceStates) - }) - } - - return errors.New("app state monitor shutdown") -} diff --git a/pkg/helm/license.go b/pkg/helm/license.go deleted file mode 100644 index 1a1c83e44c..0000000000 --- a/pkg/helm/license.go +++ /dev/null @@ -1,46 +0,0 @@ -package helm - -import ( - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/replicatedapp" -) - -func SyncLicense(helmApp *apptypes.HelmApp) (bool, error) { - isSynced := false - - currentLicense, err := GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - return isSynced, errors.Wrap(err, "failed to get license from secret") - } - - licenseID := GetKotsLicenseID(&helmApp.Release) - - if currentLicense == nil && licenseID == "" { - return isSynced, errors.Errorf("no license found for release %s", helmApp.Release.Name) - } - - if licenseID == "" { - licenseID = currentLicense.Spec.LicenseID - } else if currentLicense != nil && licenseID != currentLicense.Spec.LicenseID { - return isSynced, errors.Errorf("license ID in the chart does not match license ID in secret for release %s", helmApp.Release.Name) - } - - latestLicenseData, err := replicatedapp.GetLatestLicenseForHelm(licenseID) - if err != nil { - return isSynced, errors.Wrap(err, "failed to get latest license for helm app") - } - - err = SaveChartLicenseInSecret(helmApp, latestLicenseData.LicenseBytes) - if err != nil { - return isSynced, errors.Wrap(err, "failed to update helm license") - } - - if currentLicense == nil { - isSynced = true - } else if currentLicense.Spec.LicenseSequence != latestLicenseData.License.Spec.LicenseSequence { - isSynced = true - } - - return isSynced, nil -} diff --git a/pkg/helm/update_release.go b/pkg/helm/update_release.go index 3877edcda2..2887cddebd 100644 --- a/pkg/helm/update_release.go +++ b/pkg/helm/update_release.go @@ -6,9 +6,11 @@ import ( "context" "encoding/base64" "encoding/json" + "io" "github.com/pkg/errors" "helm.sh/helm/v3/pkg/release" + helmrelease "helm.sh/helm/v3/pkg/release" corev1 "k8s.io/api/core/v1" kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -58,7 +60,7 @@ func MigrateExistingHelmReleaseSecrets(clientset kubernetes.Interface, releaseNa // moveHelmReleaseSecret will create a new secret in the releaseNamespace and delete the old one from the kotsadmNamespace func moveHelmReleaseSecret(clientset kubernetes.Interface, secret corev1.Secret, releaseNamespace string, kotsadmNamespace string) error { - release, err := HelmReleaseFromSecretData(secret.Data["release"]) + release, err := helmReleaseFromSecretData(secret.Data["release"]) if err != nil { return errors.Wrapf(err, "failed to get release from secret data") } @@ -105,3 +107,25 @@ func encodeRelease(helmRelease *release.Release) (string, error) { return base64.StdEncoding.EncodeToString(buf.Bytes()), nil } + +func helmReleaseFromSecretData(data []byte) (*helmrelease.Release, error) { + base64Reader := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data)) + gzreader, err := gzip.NewReader(base64Reader) + if err != nil { + return nil, errors.Wrap(err, "failed to create gzip reader") + } + defer gzreader.Close() + + releaseData, err := io.ReadAll(gzreader) + if err != nil { + return nil, errors.Wrap(err, "failed to read from gzip reader") + } + + release := &helmrelease.Release{} + err = json.Unmarshal(releaseData, &release) + if err != nil { + return nil, errors.Wrap(err, "failed to unmarshal release data") + } + + return release, nil +} diff --git a/pkg/helm/update_release_test.go b/pkg/helm/update_release_test.go index c1fa9a281c..87d8d23337 100644 --- a/pkg/helm/update_release_test.go +++ b/pkg/helm/update_release_test.go @@ -141,7 +141,7 @@ func TestMigrateExistingHelmReleaseSecrets(t *testing.T) { t.Errorf("expected helm release secret to be in namespace %s, but was in %s", tt.args.releaseNamespace, secret.Namespace) } - release, err := HelmReleaseFromSecretData(secret.Data["release"]) + release, err := helmReleaseFromSecretData(secret.Data["release"]) if err != nil { t.Errorf("failed to get helm release from secret data: %v", err) } diff --git a/pkg/helm/updates.go b/pkg/helm/updates.go deleted file mode 100644 index 6fdb57b682..0000000000 --- a/pkg/helm/updates.go +++ /dev/null @@ -1,455 +0,0 @@ -package helm - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - "sync" - "time" - - "github.com/blang/semver" - "github.com/containers/image/v5/docker" - imagetypes "github.com/containers/image/v5/types" - "github.com/pkg/errors" - apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/k8sutil" - kotsadmtypes "github.com/replicatedhq/kots/pkg/kotsadm/types" - "github.com/replicatedhq/kots/pkg/kotsutil" - "github.com/replicatedhq/kots/pkg/logger" - storetypes "github.com/replicatedhq/kots/pkg/store/types" - "github.com/replicatedhq/kots/pkg/util" - kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" - "go.uber.org/zap" - "gopkg.in/yaml.v3" - helmgetter "helm.sh/helm/v3/pkg/getter" - corev1 "k8s.io/api/core/v1" - kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" -) - -type ChartUpdate struct { - Tag string - Version semver.Version - Status storetypes.DownstreamVersionStatus - CreatedOn *time.Time - IsDownloaded bool -} - -type ReplicatedMeta struct { - LicenseID string `yaml:"license_id"` - Username string `yaml:"username"` - CreatedAt *time.Time `yaml:"created_at"` - // TODO "app": map[string][]byte -} - -type ChartUpdates []ChartUpdate - -var ( - updateCacheMutex sync.Mutex - updateCache map[string]ChartUpdates // available updates sorted in descending order for each chart -) - -func init() { - updateCache = make(map[string]ChartUpdates) -} - -func (v ChartUpdates) Len() int { - return len(v) -} - -func (v ChartUpdates) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} - -func (v ChartUpdates) Less(i, j int) bool { - return v[i].Version.LT(v[j].Version) -} - -func (u ChartUpdates) ToTagList() []string { - tags := []string{} - for _, update := range u { - tags = append(tags, update.Tag) - } - return tags -} - -func GetCachedUpdates(chartPath string) ChartUpdates { - updateCacheMutex.Lock() - defer updateCacheMutex.Unlock() - - return updateCache[chartPath] -} - -func GetDownloadedUpdates(chartPath string) ChartUpdates { - updateCacheMutex.Lock() - defer updateCacheMutex.Unlock() - - downloadedUpdates := ChartUpdates{} - for _, u := range updateCache[chartPath] { - if u.IsDownloaded { - downloadedUpdates = append(downloadedUpdates, u) - } - } - return downloadedUpdates -} - -func SetCachedUpdateStatus(chartPath string, tag string, status storetypes.DownstreamVersionStatus) { - updates := GetCachedUpdates(chartPath) - for i, u := range updates { - if u.Tag == tag { - updates[i].Status = status - break - } - } -} - -func SetCachedUpdateMetadata(chartPath string, tag string, meta *ReplicatedMeta) { - updates := GetCachedUpdates(chartPath) - for i, u := range updates { - if u.Tag == tag { - updates[i].IsDownloaded = true // Metadata is only known when version is downloaded - if meta != nil { - updates[i].CreatedOn = meta.CreatedAt - } - break - } - } -} - -func setCachedUpdates(chartPath string, updates ChartUpdates) { - updateCacheMutex.Lock() - defer updateCacheMutex.Unlock() - - updateCache[chartPath] = updates -} - -// Removes this tag from cache and also every tag that is less than this one according to semver ordering -func removeFromCachedUpdates(chartPath string, tag string) { - updateCacheMutex.Lock() - defer updateCacheMutex.Unlock() - - version, parseErr := semver.ParseTolerant(tag) - - existingList := updateCache[chartPath] - newList := ChartUpdates{} - for _, update := range existingList { - // If tag cannot be parsed, fall back on string comparison. - // This should never happen for versions that are on the list because we only include valid semvers and Helm chart versions are valid semvers. - if parseErr != nil { - if update.Tag != tag { - newList = append(newList, update) - } - } else if update.Version.GT(version) { - newList = append(newList, update) - } - } - updateCache[chartPath] = newList -} - -func deleteUpdateCacheForChart(chartPath string) { - updateCacheMutex.Lock() - defer updateCacheMutex.Unlock() - - delete(updateCache, chartPath) -} - -func CheckForUpdates(helmApp *apptypes.HelmApp, license *kotsv1beta1.License, currentVersion *semver.Version) (ChartUpdates, error) { - chartPath := helmApp.ChartPath - licenseID := license.Spec.LicenseID - - _, err := SyncLicense(helmApp) - if err != nil { - return nil, errors.Wrapf(err, "failed to sync license before update check") - } - - imageName := strings.TrimLeft(chartPath, "oci:") - ref, err := docker.ParseReference(imageName) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse image ref %q", imageName) - } - - sysCtx := &imagetypes.SystemContext{ - DockerInsecureSkipTLSVerify: imagetypes.OptionalBoolTrue, - DockerDisableV1Ping: true, - DockerAuthConfig: &imagetypes.DockerAuthConfig{ - Username: licenseID, - Password: licenseID, - }, - } - - tags, err := docker.GetRepositoryTags(context.TODO(), sysCtx, ref) - if err != nil { - return nil, errors.Wrapf(err, "failed to get repo tags") - } - - tags = removeDuplicates(tags) // registry should not be returning duplicate tags - - availableUpdates := ChartUpdates{} - for _, tag := range tags { - v, err := semver.ParseTolerant(tag) - if err != nil { - // TODO: log - continue - } - - if currentVersion != nil && v.LE(*currentVersion) { - continue - } - - availableUpdates = append(availableUpdates, ChartUpdate{ - Tag: tag, - Version: v, - IsDownloaded: false, - }) - } - - sort.Sort(sort.Reverse(ChartUpdates(availableUpdates))) - - setCachedUpdates(chartPath, availableUpdates) - - return availableUpdates, nil -} - -func removeDuplicates(tags []string) []string { - m := map[string]struct{}{} - for _, tag := range tags { - m[tag] = struct{}{} - } - - u := []string{} - for k := range m { - u = append(u, k) - } - - return u -} - -func GetKotsKindsFromUpstreamChartVersion(helmApp *apptypes.HelmApp, licenseID string, version string) (kotsutil.KotsKinds, error) { - secret, err := GetReplicatedSecretFromUpstreamChartVersion(helmApp, licenseID, version) - if err != nil { - return kotsutil.KotsKinds{}, errors.Wrap(err, "failed to get secret upstream archive") - } - - kotsKinds, err := GetKotsKindsFromReplicatedSecret(secret) - if err != nil { - return kotsKinds, errors.Wrap(err, "failed to get kots kinds from secret") - } - - return kotsKinds, nil -} - -func GetReplicatedSecretFromUpstreamChartVersion(helmApp *apptypes.HelmApp, licenseID string, version string) (*corev1.Secret, error) { - chartData, err := downloadChartReleaseIfNeeded(helmApp, licenseID, version) - if err != nil { - return nil, errors.Wrap(err, "failed to get chart data") - } - - templatedData, err := util.GetFileFromTGZArchive(chartData, "**/templates/_replicated/secret.yaml") - if err != nil { - return nil, errors.Wrap(err, "failed to get secret file from chart archive") - } - - secretData, err := removeHelmTemplate(templatedData.Bytes()) - if err != nil { - return nil, errors.Wrap(err, "failed to remove helm templates from replicated secret file") - } - - decode := scheme.Codecs.UniversalDeserializer().Decode - obj, gvk, err := decode(secretData, nil, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to decode secret data") - } - - if gvk.Group != "" || gvk.Version != "v1" || gvk.Kind != "Secret" { - return nil, errors.Errorf("unexpected secret GVK: %s", gvk.String()) - } - - return obj.(*corev1.Secret), nil -} - -func GetReplicatedMetadataFromUpstreamChartVersion(helmApp *apptypes.HelmApp, licenseID string, version string) (*ReplicatedMeta, error) { - chartData, err := downloadChartReleaseIfNeeded(helmApp, licenseID, version) - if err != nil { - return nil, errors.Wrap(err, "failed to get chart data") - } - - valuesData, err := util.GetFileFromTGZArchive(chartData, "**/values.yaml") - if err != nil { - return nil, errors.Wrap(err, "failed to get values.yaml from chart archive") - } - - b := valuesData.Bytes() - values := struct { - Replicated *ReplicatedMeta `yaml:"replicated,omitempty"` - }{} - err = yaml.Unmarshal(b, &values) - if err != nil { - return nil, errors.Wrap(err, "failed to decode values.yaml") - } - - return values.Replicated, nil -} - -func downloadChartReleaseIfNeeded(helmApp *apptypes.HelmApp, licenseID string, version string) (*bytes.Buffer, error) { - chartData, err := getUpdateChartFromCache(helmApp, version) - if err != nil { - return nil, errors.Wrap(err, "failed to get release from cache") - } - - if chartData != nil { - return chartData, nil - } - - err = CreateHelmRegistryCreds(licenseID, licenseID, helmApp.ChartPath) - if err != nil { - return nil, errors.Wrap(err, "failed to create helm credentials file") - } - chartGetter, err := helmgetter.NewOCIGetter() - if err != nil { - return nil, errors.Wrap(err, "failed to create chart getter") - } - - imageName := fmt.Sprintf("%s:%s", helmApp.ChartPath, version) - chartData, err = chartGetter.Get(imageName) - if err != nil { - return nil, errors.Wrapf(err, "failed to get chart %q", imageName) - } - - chartData, err = saveUpdateChartInCache(helmApp, version, chartData) - if err != nil { - logger.Info("failed to save chart in cache", zap.String("error", err.Error())) - } - - return chartData, nil -} - -var ( - updateCacheDir = "" -) - -func getUpdateChartFromCache(helmApp *apptypes.HelmApp, version string) (*bytes.Buffer, error) { - fileName := getUpdateChacheFileName(helmApp, version) - b, err := os.ReadFile(fileName) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, errors.Wrap(err, "failed to read file") - } - - return bytes.NewBuffer(b), nil -} - -func saveUpdateChartInCache(helmApp *apptypes.HelmApp, version string, data *bytes.Buffer) (*bytes.Buffer, error) { - b := data.Bytes() - newBuff := bytes.NewBuffer(b) - - if updateCacheDir == "" { - dirName, err := ioutil.TempDir("", "chart-updates-") - if err != nil { - return newBuff, errors.Wrap(err, "failed to create temp dir") - } - updateCacheDir = dirName - } - - fileName := getUpdateChacheFileName(helmApp, version) - - err := os.MkdirAll(filepath.Dir(fileName), 0755) - if err != nil { - return newBuff, errors.Wrap(err, "failed to create cache dir") - } - - err = ioutil.WriteFile(fileName, b, 0744) - if err != nil { - return newBuff, errors.Wrap(err, "failed to save cache file") - } - - return newBuff, nil -} - -func getUpdateChacheFileName(helmApp *apptypes.HelmApp, version string) string { - return filepath.Join(updateCacheDir, strings.TrimPrefix(helmApp.ChartPath, "oci://"), fmt.Sprintf("%s.tgz", version)) -} - -func GetUpdateCheckSpec(helmApp *apptypes.HelmApp) (string, error) { - clientset, err := k8sutil.GetClientset() - if err != nil { - return "", errors.Wrap(err, "failed to get clientset") - } - - spec := "@default" - - cm, err := clientset.CoreV1().ConfigMaps(util.PodNamespace).Get(context.TODO(), kotsadmtypes.KotsadmConfigMap, metav1.GetOptions{}) - if err != nil && !kuberneteserrors.IsNotFound(err) { - return "", errors.Wrap(err, "failed to get configmap") - } else if kuberneteserrors.IsNotFound(err) { - return spec, nil - } - - if cm.Data == nil { - return spec, nil - } - - key := fmt.Sprintf("update-schedule-%s", helmApp.GetID()) - if s := cm.Data[key]; s != "" { - spec = s - } - - return spec, nil -} - -var configMapMutex sync.Mutex - -func SetUpdateCheckSpec(helmApp *apptypes.HelmApp, updateSpec string) error { - configMapMutex.Lock() - defer configMapMutex.Unlock() - - clientset, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } - - key := fmt.Sprintf("update-schedule-%s", helmApp.GetID()) - - cm, err := clientset.CoreV1().ConfigMaps(util.PodNamespace).Get(context.TODO(), kotsadmtypes.KotsadmConfigMap, metav1.GetOptions{}) - if err != nil && !kuberneteserrors.IsNotFound(err) { - return errors.Wrap(err, "failed to get configmap") - } else if kuberneteserrors.IsNotFound(err) { - cm := &corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: kotsadmtypes.KotsadmConfigMap, - Namespace: util.PodNamespace, - Labels: kotsadmtypes.GetKotsadmLabels(), - }, - Data: map[string]string{ - key: updateSpec, - }, - } - _, err = clientset.CoreV1().ConfigMaps(util.PodNamespace).Create(context.Background(), cm, metav1.CreateOptions{}) - if err != nil { - return errors.Wrap(err, "failed to update config map") - } - } - - if cm.Data == nil { - cm.Data = map[string]string{} - } - cm.Data[key] = updateSpec - - _, err = clientset.CoreV1().ConfigMaps(util.PodNamespace).Update(context.Background(), cm, metav1.UpdateOptions{}) - if err != nil { - return errors.Wrap(err, "failed to update config map") - } - - return nil -} diff --git a/pkg/policy/getters.go b/pkg/policy/getters.go index 58e337b01b..3cb1d7dbbd 100644 --- a/pkg/policy/getters.go +++ b/pkg/policy/getters.go @@ -3,7 +3,6 @@ package policy import ( "github.com/pkg/errors" "github.com/replicatedhq/kots/pkg/store" - "github.com/replicatedhq/kots/pkg/util" ) func appSlugFromAppIDGetter(kotsStore store.Store, vars map[string]string) (map[string]string, error) { @@ -15,19 +14,13 @@ func appSlugFromAppIDGetter(kotsStore store.Store, vars map[string]string) (map[ return map[string]string{}, nil } - var appSlug string - if util.IsHelmManaged() { - appSlug = appIDOrSlug - } else { - app, err := kotsStore.GetApp(appIDOrSlug) - if err != nil { - return nil, errors.Wrap(err, "failed to get app") - } - appSlug = app.Slug + app, err := kotsStore.GetApp(appIDOrSlug) + if err != nil { + return nil, errors.Wrap(err, "failed to get app") } return map[string]string{ - "appSlug": appSlug, + "appSlug": app.Slug, }, nil } @@ -52,17 +45,12 @@ func appSlugFromSupportbundleGetter(kotsStore store.Store, vars map[string]strin return nil, nil } - var appSlug string - if util.IsHelmManaged() { - appSlug = appIDOrSlug - } else { - app, err := kotsStore.GetApp(appIDOrSlug) - if err != nil { - return nil, errors.Wrap(err, "failed to get app") - } - appSlug = app.Slug + app, err := kotsStore.GetApp(appIDOrSlug) + if err != nil { + return nil, errors.Wrap(err, "failed to get app") } + return map[string]string{ - "appSlug": appSlug, + "appSlug": app.Slug, }, nil } diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index 1848d666e0..dd6d360596 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -152,10 +152,3 @@ var ( AppDownstreamConfigRead = Must(NewPolicy(ActionRead, "app.{{.appSlug}}.downstream.config.")) AppDownstreamConfigWrite = Must(NewPolicy(ActionWrite, "app.{{.appSlug}}.downstream.config.")) ) - -// Helm - -var ( - IsHelmManaged = Must(NewPolicy(ActionRead, "")) - GetAppValuesFile = Must(NewPolicy(ActionRead, "")) -) diff --git a/pkg/redact/app.go b/pkg/redact/app.go index 49e8a02c8b..c7445b02ef 100644 --- a/pkg/redact/app.go +++ b/pkg/redact/app.go @@ -29,7 +29,7 @@ func GetAppRedactSpecURI(appSlug string) string { } // CreateRenderedAppRedactSpec creates a configmap that contains the redaction yaml spec included in the application release -func CreateRenderedAppRedactSpec(clientset kubernetes.Interface, app apptypes.AppType, sequence int64, kotsKinds *kotsutil.KotsKinds) error { +func CreateRenderedAppRedactSpec(clientset kubernetes.Interface, app *apptypes.App, sequence int64, kotsKinds *kotsutil.KotsKinds) error { builtRedactor := kotsKinds.Redactor.DeepCopy() if builtRedactor == nil { builtRedactor = &troubleshootv1beta2.Redactor{ diff --git a/pkg/render/helper/appfile.go b/pkg/render/helper/appfile.go index c8bb94b37a..74313e32df 100644 --- a/pkg/render/helper/appfile.go +++ b/pkg/render/helper/appfile.go @@ -4,16 +4,14 @@ import ( "github.com/pkg/errors" "github.com/replicatedhq/kots/pkg/app/types" "github.com/replicatedhq/kots/pkg/kotsutil" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" "github.com/replicatedhq/kots/pkg/render" rendertypes "github.com/replicatedhq/kots/pkg/render/types" "github.com/replicatedhq/kots/pkg/store" - "github.com/replicatedhq/kots/pkg/util" ) // RenderAppFile renders a single file using the current sequence of the provided app, or the overrideSequence (if provided) // it's here for now to avoid an import cycle between kotsadm/pkg/render and pkg/store -func RenderAppFile(a types.AppType, overrideSequence *int64, inputContent []byte, kotsKinds *kotsutil.KotsKinds, namespace string) ([]byte, error) { +func RenderAppFile(a *types.App, overrideSequence *int64, inputContent []byte, kotsKinds *kotsutil.KotsKinds, namespace string) ([]byte, error) { var sequence int64 if overrideSequence != nil { sequence = *overrideSequence @@ -25,13 +23,9 @@ func RenderAppFile(a types.AppType, overrideSequence *int64, inputContent []byte sequence = latestSequence } - var registrySettings registrytypes.RegistrySettings - if !util.IsHelmManaged() { - s, err := store.GetStore().GetRegistryDetailsForApp(a.GetID()) - if err != nil { - return nil, errors.Wrap(err, "failed to load registry settings") - } - registrySettings = s + registrySettings, err := store.GetStore().GetRegistryDetailsForApp(a.GetID()) + if err != nil { + return nil, errors.Wrap(err, "failed to load registry settings") } return render.RenderFile(rendertypes.RenderFileOptions{ diff --git a/pkg/replicatedapp/api.go b/pkg/replicatedapp/api.go index 9286617bd2..5d1863e3a8 100644 --- a/pkg/replicatedapp/api.go +++ b/pkg/replicatedapp/api.go @@ -51,16 +51,6 @@ func GetLatestLicense(license *kotsv1beta1.License) (*LicenseData, error) { return licenseData, nil } -func GetLatestLicenseForHelm(licenseID string) (*LicenseData, error) { - url := fmt.Sprintf("%s/license", util.GetReplicatedAPIEndpoint()) - licenseData, err := getLicenseFromAPI(url, licenseID) - if err != nil { - return nil, errors.Wrap(err, "failed to get helm license from api") - } - - return licenseData, nil -} - func getAppIdFromLicenseId(s store.Store, licenseID string) (string, error) { apps, err := s.ListInstalledApps() if err != nil { diff --git a/pkg/reporting/app.go b/pkg/reporting/app.go index 24feb8a4ea..f70cbd6441 100644 --- a/pkg/reporting/app.go +++ b/pkg/reporting/app.go @@ -1,10 +1,7 @@ package reporting import ( - "bytes" - "compress/gzip" "context" - "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -27,16 +24,9 @@ import ( "github.com/segmentio/ksuid" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" veleroclientv1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" - helmrelease "helm.sh/helm/v3/pkg/release" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" ) -var ( - clusterID string // set when in Helm managed mode -) - type SnapshotReport struct { Provider string FullSchedule string @@ -46,16 +36,9 @@ type SnapshotReport struct { } func Init() error { - if util.IsHelmManaged() { - err := initFromHelm() - if err != nil { - return errors.Wrap(err, "failed to init from Helm") - } - } else { - err := initFromDownstream() - if err != nil { - return errors.Wrap(err, "failed to init from downstream") - } + err := initFromDownstream() + if err != nil { + return errors.Wrap(err, "failed to init from downstream") } if kotsadm.IsAirgap() { @@ -74,69 +57,6 @@ func Init() error { return nil } -func initFromHelm() error { - // ClusterID in reporting will be the UID of the v1 of Admin Console secret - clientSet, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } - - selectorLabels := map[string]string{ - "owner": "helm", - "version": "1", - } - listOpts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(selectorLabels).String(), - } - - secrets, err := clientSet.CoreV1().Secrets(util.PodNamespace).List(context.TODO(), listOpts) - if err != nil { - return errors.Wrap(err, "failed to list secrets") - } - - for _, secret := range secrets.Items { - helmRelease, err := helmReleaseFromSecretData(secret.Data["release"]) - if err != nil { - logger.Warnf("failed to parse helm chart in secret %s: %v", &secret.ObjectMeta.Name, err) - continue - } - - if helmRelease.Chart == nil || helmRelease.Chart.Metadata == nil { - continue - } - if helmRelease.Chart.Metadata.Name != "admin-console" { - continue - } - - clusterID = string(secret.ObjectMeta.UID) - return nil - } - - return errors.New("admin-console secret v1 not found") -} - -func helmReleaseFromSecretData(data []byte) (*helmrelease.Release, error) { - base64Reader := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data)) - gzreader, err := gzip.NewReader(base64Reader) - if err != nil { - return nil, errors.Wrap(err, "failed to create gzip reader") - } - defer gzreader.Close() - - releaseData, err := ioutil.ReadAll(gzreader) - if err != nil { - return nil, errors.Wrap(err, "failed to read from gzip reader") - } - - release := &helmrelease.Release{} - err = json.Unmarshal(releaseData, &release) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal release data") - } - - return release, nil -} - func initFromDownstream() error { // Retrieve the ClusterID from store clusters, err := store.GetStore().ListClusters() @@ -208,19 +128,14 @@ func GetReportingInfo(appID string) *types.ReportingInfo { if err != nil { logger.Debugf("failed to get clientset: %v", err.Error()) } + r.ClusterID = k8sutil.GetKotsadmID(clientset) - if util.IsHelmManaged() { - r.ClusterID = clusterID - } else { - r.ClusterID = k8sutil.GetKotsadmID(clientset) - - di, err := getDownstreamInfo(appID) - if err != nil { - logger.Debugf("failed to get downstream info: %v", err.Error()) - } - if di != nil { - r.Downstream = *di - } + di, err := getDownstreamInfo(appID) + if err != nil { + logger.Debugf("failed to get downstream info: %v", err.Error()) + } + if di != nil { + r.Downstream = *di } // get kubernetes cluster version @@ -236,15 +151,11 @@ func GetReportingInfo(appID string) *types.ReportingInfo { } // get app status - if util.IsHelmManaged() { - logger.Infof("TODO: get app status in Helm managed mode") + appStatus, err := store.GetStore().GetAppStatus(appID) + if err != nil { + logger.Debugf("failed to get app status: %v", err.Error()) } else { - appStatus, err := store.GetStore().GetAppStatus(appID) - if err != nil { - logger.Debugf("failed to get app status: %v", err.Error()) - } else { - r.AppStatus = string(appStatus.State) - } + r.AppStatus = string(appStatus.State) } r.IsKurl, err = kurl.IsKurl(clientset) diff --git a/pkg/store/kotsstore/supportbundle_store.go b/pkg/store/kotsstore/supportbundle_store.go index 71c820597b..a3f4f88000 100644 --- a/pkg/store/kotsstore/supportbundle_store.go +++ b/pkg/store/kotsstore/supportbundle_store.go @@ -32,65 +32,9 @@ import ( ) var ( - // Used in Helm managed mode supportBundleSecretMtx sync.Mutex - supportBundlesByID = map[string]*types.SupportBundle{} - supportBundlesIDsByApp = map[string][]string{} ) -func addSupportBundleToCache(bundle *types.SupportBundle) { - supportBundleSecretMtx.Lock() - defer supportBundleSecretMtx.Unlock() - - _, exist := supportBundlesByID[bundle.ID] - supportBundlesByID[bundle.ID] = bundle - - if exist { - return - } - - _, ok := supportBundlesIDsByApp[bundle.AppID] - if ok { - supportBundlesIDsByApp[bundle.AppID] = append(supportBundlesIDsByApp[bundle.AppID], bundle.ID) - } else { - supportBundlesIDsByApp[bundle.AppID] = []string{bundle.ID} - } -} - -func getSupportBundleFromCache(id string) *types.SupportBundle { - supportBundleSecretMtx.Lock() - defer supportBundleSecretMtx.Unlock() - - bundle := supportBundlesByID[id] - if bundle != nil { - bundle.Status = getSupportBundleStatus(bundle.Status, bundle.UpdatedAt) - } - - return bundle -} - -func getSupportBundleIDsFromCache(appID string) []string { - supportBundleSecretMtx.Lock() - defer supportBundleSecretMtx.Unlock() - - return supportBundlesIDsByApp[appID] -} - -func deleteSupportBundleFromCache(id string, appID string) { - supportBundleSecretMtx.Lock() - defer supportBundleSecretMtx.Unlock() - delete(supportBundlesByID, id) - - oldSupportBundlesIDs := supportBundlesIDsByApp[appID] - newSupportBundlesIDs := []string{} - for _, sbID := range oldSupportBundlesIDs { - if sbID != id { - newSupportBundlesIDs = append(newSupportBundlesIDs, sbID) - } - } - supportBundlesIDsByApp[appID] = newSupportBundlesIDs -} - func (s *KOTSStore) migrateSupportBundlesFromRqlite() error { logger.Debug("migrating support bundles from rqlite") @@ -254,41 +198,31 @@ func (s *KOTSStore) migrateSupportBundlesFromRqlite() error { func (s *KOTSStore) ListSupportBundles(appID string) ([]*types.SupportBundle, error) { supportBundles := []*types.SupportBundle{} - if util.IsHelmManaged() { - ids := getSupportBundleIDsFromCache(appID) - for _, id := range ids { - bundle := getSupportBundleFromCache(id) - if bundle != nil { - supportBundles = append(supportBundles, bundle) - } - } - } else { - clientset, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } + clientset, err := k8sutil.GetClientset() + if err != nil { + return nil, errors.Wrap(err, "failed to get clientset") + } - labelSelector := metav1.LabelSelector{ - MatchLabels: map[string]string{ - "kots.io/kind": "supportbundle", - "kots.io/appid": appID, - }, - } + labelSelector := metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kots.io/kind": "supportbundle", + "kots.io/appid": appID, + }, + } - secrets, err := clientset.CoreV1().Secrets(util.PodNamespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: labels.Set(labelSelector.MatchLabels).String(), - }) - if err != nil { - return nil, errors.Wrap(err, "failed to list support bundles") - } + secrets, err := clientset.CoreV1().Secrets(util.PodNamespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + }) + if err != nil { + return nil, errors.Wrap(err, "failed to list support bundles") + } - for _, secret := range secrets.Items { - supportBundle, err := s.getSupportBundleFromSecretData(&secret) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal support bundle") - } - supportBundles = append(supportBundles, supportBundle) + for _, secret := range secrets.Items { + supportBundle, err := s.getSupportBundleFromSecretData(&secret) + if err != nil { + return nil, errors.Wrap(err, "failed to unmarshal support bundle") } + supportBundles = append(supportBundles, supportBundle) } // sort the bundles here by date, since we don't have a sort order otherwise @@ -299,23 +233,20 @@ func (s *KOTSStore) ListSupportBundles(appID string) ([]*types.SupportBundle, er func (s *KOTSStore) GetSupportBundle(id string) (*types.SupportBundle, error) { supportBundle := &types.SupportBundle{} - if util.IsHelmManaged() { - supportBundle = getSupportBundleFromCache(id) - } else { - clientset, err := k8sutil.GetClientset() - if err != nil { - return nil, errors.Wrap(err, "failed to get clientset") - } - secret, err := clientset.CoreV1().Secrets(util.PodNamespace).Get(context.TODO(), fmt.Sprintf("supportbundle-%s", id), metav1.GetOptions{}) - if err != nil { - return nil, errors.Wrap(err, "failed to get secret") - } + clientset, err := k8sutil.GetClientset() + if err != nil { + return nil, errors.Wrap(err, "failed to get clientset") + } - supportBundle, err = s.getSupportBundleFromSecretData(secret) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal") - } + secret, err := clientset.CoreV1().Secrets(util.PodNamespace).Get(context.TODO(), fmt.Sprintf("supportbundle-%s", id), metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrap(err, "failed to get secret") + } + + supportBundle, err = s.getSupportBundleFromSecretData(secret) + if err != nil { + return nil, errors.Wrap(err, "failed to unmarshal") } if supportBundle != nil { @@ -333,25 +264,20 @@ func (s *KOTSStore) GetSupportBundle(id string) (*types.SupportBundle, error) { } func (s *KOTSStore) DeleteSupportBundle(bundleID string, appID string) error { - if util.IsHelmManaged() { - // delete from cache - deleteSupportBundleFromCache(bundleID, appID) - } else { - clientset, err := k8sutil.GetClientset() - if err != nil { - return errors.Wrap(err, "failed to get clientset") - } + clientset, err := k8sutil.GetClientset() + if err != nil { + return errors.Wrap(err, "failed to get clientset") + } - // delete the secret - if err := clientset.CoreV1().Secrets(util.PodNamespace).Delete(context.TODO(), fmt.Sprintf("supportbundle-%s", bundleID), metav1.DeleteOptions{}); err != nil && !s.IsNotFound(err) { - return errors.Wrap(err, "failed to delete secret") - } + // delete the secret + if err := clientset.CoreV1().Secrets(util.PodNamespace).Delete(context.TODO(), fmt.Sprintf("supportbundle-%s", bundleID), metav1.DeleteOptions{}); err != nil && !s.IsNotFound(err) { + return errors.Wrap(err, "failed to delete secret") + } - // delete the archive - sbPath := filepath.Join("supportbundles", bundleID) - if err := filestore.GetStore().DeleteArchive(sbPath); err != nil { - return errors.Wrap(err, "failed to delete archive") - } + // delete the archive + sbPath := filepath.Join("supportbundles", bundleID) + if err := filestore.GetStore().DeleteArchive(sbPath); err != nil { + return errors.Wrap(err, "failed to delete archive") } return nil } @@ -365,11 +291,6 @@ func (s *KOTSStore) CreateInProgressSupportBundle(supportBundle *types.SupportBu supportBundle.CreatedAt = now supportBundle.UpdatedAt = &now - if util.IsHelmManaged() { - addSupportBundleToCache(supportBundle) - return nil - } - bundleMarshaled, err := json.Marshal(supportBundle) if err != nil { return errors.Wrap(err, "failed to marshal support bundle") @@ -441,11 +362,6 @@ func (s *KOTSStore) CreateSupportBundle(id string, appID string, archivePath str UpdatedAt: &now, } - if util.IsHelmManaged() { - addSupportBundleToCache(&supportBundle) - return &supportBundle, nil - } - bundleMarshaled, err := json.Marshal(supportBundle) if err != nil { return nil, errors.Wrap(err, "failed to marshal support bundle") @@ -489,11 +405,6 @@ func (s *KOTSStore) UpdateSupportBundle(bundle *types.SupportBundle) error { now := time.Now() bundle.UpdatedAt = &now - if util.IsHelmManaged() { - addSupportBundleToCache(bundle) - return nil - } - supportBundleSecretMtx.Lock() defer supportBundleSecretMtx.Unlock() @@ -561,14 +472,6 @@ func (s *KOTSStore) GetSupportBundleArchive(bundleID string) (string, error) { } func (s *KOTSStore) GetSupportBundleAnalysis(id string) (*types.SupportBundleAnalysis, error) { - if util.IsHelmManaged() { - bundle := getSupportBundleFromCache(id) - if bundle == nil { - return nil, nil - } - return bundle.Analysis, nil - } - clientset, err := k8sutil.GetClientset() if err != nil { return nil, errors.Wrap(err, "failed to get clientset") @@ -606,15 +509,6 @@ func (s *KOTSStore) SetSupportBundleAnalysis(id string, results []byte) error { Insights: insights, } - if util.IsHelmManaged() { - bundle := getSupportBundleFromCache(id) - if bundle == nil { - return ErrNotFound - } - bundle.Analysis = &a - return nil - } - supportBundleSecretMtx.Lock() defer supportBundleSecretMtx.Unlock() diff --git a/pkg/supportbundle/helm.go b/pkg/supportbundle/helm.go deleted file mode 100644 index ca3e293963..0000000000 --- a/pkg/supportbundle/helm.go +++ /dev/null @@ -1,69 +0,0 @@ -package supportbundle - -import ( - "github.com/pkg/errors" - "github.com/replicatedhq/kots/pkg/helm" - "github.com/replicatedhq/kots/pkg/logger" - "github.com/replicatedhq/kots/pkg/util" - "github.com/replicatedhq/kotskinds/client/kotsclientset/scheme" - troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" - troubleshootclientsetscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme" - "github.com/replicatedhq/troubleshoot/pkg/docrewrite" - troubleshootsb "github.com/replicatedhq/troubleshoot/pkg/supportbundle" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func getSupportBundleSpecFromOCI(licenseID string, url string) (*troubleshootv1beta2.SupportBundle, *troubleshootv1beta2.Redactor, error) { - err := helm.CreateHelmRegistryCreds(licenseID, licenseID, url) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to load collector spec") - } - - collectorContent, err := troubleshootsb.LoadSupportBundleSpec(url) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to load collector spec") - } - - multidocs := util.ConvertToSingleDocs(collectorContent) - - // we support both raw collector kinds and supportbundle kinds here - supportBundle, err := troubleshootsb.ParseSupportBundleFromDoc(multidocs[0]) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to parse collector") - } - - troubleshootclientsetscheme.AddToScheme(scheme.Scheme) - decode := scheme.Codecs.UniversalDeserializer().Decode - - redactors := &troubleshootv1beta2.Redactor{ - TypeMeta: metav1.TypeMeta{ - Kind: "Redactor", - APIVersion: "troubleshoot.sh/v1beta2", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "default-redactor", - }, - } - for i, additionalDoc := range multidocs { - if i == 0 { - continue - } - additionalDoc, err := docrewrite.ConvertToV1Beta2([]byte(additionalDoc)) - if err != nil { - logger.Infof("failed to convert doc %d to v1beta2: %v", i, err) - continue - } - obj, _, err := decode(additionalDoc, nil, nil) - if err != nil { - logger.Infof("failed to parse additional doc %d: %v", i, err) - continue - } - multidocRedactors, ok := obj.(*troubleshootv1beta2.Redactor) - if !ok { - continue - } - redactors.Spec.Redactors = append(redactors.Spec.Redactors, multidocRedactors.Spec.Redactors...) - } - - return supportBundle, redactors, nil -} diff --git a/pkg/supportbundle/spec.go b/pkg/supportbundle/spec.go index 181cff1d82..826651552a 100644 --- a/pkg/supportbundle/spec.go +++ b/pkg/supportbundle/spec.go @@ -17,14 +17,12 @@ import ( "github.com/pkg/errors" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/k8sutil" kotstypes "github.com/replicatedhq/kots/pkg/kotsadm/types" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/kurl" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/registry" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" "github.com/replicatedhq/kots/pkg/render/helper" "github.com/replicatedhq/kots/pkg/reporting" "github.com/replicatedhq/kots/pkg/snapshot" @@ -34,7 +32,6 @@ import ( "github.com/replicatedhq/kots/pkg/supportbundle/staticspecs" "github.com/replicatedhq/kots/pkg/supportbundle/types" "github.com/replicatedhq/kots/pkg/util" - "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" "github.com/replicatedhq/kotskinds/client/kotsclientset/scheme" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" sb "github.com/replicatedhq/troubleshoot/pkg/supportbundle" @@ -56,7 +53,7 @@ func init() { } // CreateRenderedSpec creates the support bundle specification from defaults and the kots app -func CreateRenderedSpec(app apptypes.AppType, sequence int64, kotsKinds *kotsutil.KotsKinds, opts types.TroubleshootOptions) (*troubleshootv1beta2.SupportBundle, error) { +func CreateRenderedSpec(app *apptypes.App, sequence int64, kotsKinds *kotsutil.KotsKinds, opts types.TroubleshootOptions) (*troubleshootv1beta2.SupportBundle, error) { builtBundle := kotsKinds.SupportBundle.DeepCopy() if builtBundle == nil { builtBundle = &troubleshootv1beta2.SupportBundle{ @@ -176,7 +173,7 @@ func mergeSupportBundleSpecs(builtBundles map[string]*troubleshootv1beta2.Suppor } // createSupportBundleSpecConfigMap creates a configmap containing the support bundle spec -func createSupportBundleSpecConfigMap(app apptypes.AppType, sequence int64, kotsKinds *kotsutil.KotsKinds, configMapName string, builtBundle *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, clientset kubernetes.Interface) error { +func createSupportBundleSpecConfigMap(app *apptypes.App, sequence int64, kotsKinds *kotsutil.KotsKinds, configMapName string, builtBundle *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, clientset kubernetes.Interface) error { s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) var b bytes.Buffer if err := s.Encode(builtBundle, &b); err != nil { @@ -197,13 +194,9 @@ func createSupportBundleSpecConfigMap(app apptypes.AppType, sequence int64, kots return errors.Wrap(err, "failed to unmarshal rendered support bundle spec") } - var registrySettings registrytypes.RegistrySettings - if !util.IsHelmManaged() { - s, err := store.GetStore().GetRegistryDetailsForApp(app.GetID()) - if err != nil { - return errors.Wrap(err, "failed to get registry settings for app") - } - registrySettings = s + registrySettings, err := store.GetStore().GetRegistryDetailsForApp(app.GetID()) + if err != nil { + return errors.Wrap(err, "failed to get registry settings for app") } collectors, err := registry.UpdateCollectorSpecsWithRegistryData(supportBundle.Spec.Collectors, registrySettings, kotsKinds.Installation, kotsKinds.License, &kotsKinds.KotsApplication) @@ -261,7 +254,7 @@ func createSupportBundleSpecConfigMap(app apptypes.AppType, sequence int64, kots } // createSupportBundleSpecSecret creates a secret containing the support bundle spec -func createSupportBundleSpecSecret(app apptypes.AppType, sequence int64, kotsKinds *kotsutil.KotsKinds, secretName string, builtBundle *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, clientset kubernetes.Interface) error { +func createSupportBundleSpecSecret(app *apptypes.App, sequence int64, kotsKinds *kotsutil.KotsKinds, secretName string, builtBundle *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, clientset kubernetes.Interface) error { s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) var b bytes.Buffer if err := s.Encode(builtBundle, &b); err != nil { @@ -282,13 +275,9 @@ func createSupportBundleSpecSecret(app apptypes.AppType, sequence int64, kotsKin return errors.Wrap(err, "failed to unmarshal rendered support bundle spec") } - var registrySettings registrytypes.RegistrySettings - if !util.IsHelmManaged() { - s, err := store.GetStore().GetRegistryDetailsForApp(app.GetID()) - if err != nil { - return errors.Wrap(err, "failed to get registry settings for app") - } - registrySettings = s + registrySettings, err := store.GetStore().GetRegistryDetailsForApp(app.GetID()) + if err != nil { + return errors.Wrap(err, "failed to get registry settings for app") } collectors, err := registry.UpdateCollectorSpecsWithRegistryData(supportBundle.Spec.Collectors, registrySettings, kotsKinds.Installation, kotsKinds.License, &kotsKinds.KotsApplication) @@ -346,7 +335,7 @@ func createSupportBundleSpecSecret(app apptypes.AppType, sequence int64, kotsKin } // addAfterCollectionSpec adds cluster specific and upload results URI to the support bundle -func addAfterCollectionSpec(app apptypes.AppType, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions) *troubleshootv1beta2.SupportBundle { +func addAfterCollectionSpec(app *apptypes.App, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions) *troubleshootv1beta2.SupportBundle { supportBundle := b.DeepCopy() // determine an upload URL @@ -398,7 +387,7 @@ func createVendorSpec(b *troubleshootv1beta2.SupportBundle) (*troubleshootv1beta } // createClusterSpecificSupportBundle creates a support bundle spec with only cluster specific collectors, analyzers and upload result URI. -func createClusterSpecificSpec(app apptypes.AppType, b *troubleshootv1beta2.SupportBundle, clientset kubernetes.Interface) (*troubleshootv1beta2.SupportBundle, error) { +func createClusterSpecificSpec(app *apptypes.App, b *troubleshootv1beta2.SupportBundle, clientset kubernetes.Interface) (*troubleshootv1beta2.SupportBundle, error) { supportBundle, err := staticspecs.GetClusterSpecificSpec() if err != nil { logger.Errorf("Failed to load cluster specific support bundle spec: %v", err) @@ -410,7 +399,7 @@ func createClusterSpecificSpec(app apptypes.AppType, b *troubleshootv1beta2.Supp } // createDefaultSpec creates a default support bundle spec that includes the default collectors and analyzers and add kurl specific collectors and analyzers if the cluster is a kurl cluster -func createDefaultSpec(app apptypes.AppType, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, namespacesToCollect []string, namespacesToAnalyze []string, clientset *kubernetes.Clientset) (*troubleshootv1beta2.SupportBundle, error) { +func createDefaultSpec(app *apptypes.App, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, namespacesToCollect []string, namespacesToAnalyze []string, clientset *kubernetes.Clientset) (*troubleshootv1beta2.SupportBundle, error) { supportBundle, err := staticspecs.GetDefaultSpec() if err != nil { logger.Errorf("Failed to load default support bundle spec: %v", err) @@ -456,7 +445,7 @@ func createDefaultSpec(app apptypes.AppType, b *troubleshootv1beta2.SupportBundl } func addDiscoveredSpecs( - supportBundle *troubleshootv1beta2.SupportBundle, app apptypes.AppType, clientset kubernetes.Interface, + supportBundle *troubleshootv1beta2.SupportBundle, app *apptypes.App, clientset kubernetes.Interface, ) *troubleshootv1beta2.SupportBundle { specs, err := findSupportBundleSpecs(clientset) if err != nil { @@ -725,29 +714,19 @@ func getDefaultAnalyzers(isKurl bool) []*troubleshootv1beta2.Analyze { // addDefaultDynamicTroubleshoot adds dynamic spec to the support bundle. // prefer addDefaultTroubleshoot unless absolutely necessary to encourage consistency across built-in and kots.io specs. -func addDefaultDynamicTroubleshoot(supportBundle *troubleshootv1beta2.SupportBundle, app apptypes.AppType, imageName string, pullSecret *troubleshootv1beta2.ImagePullSecrets) *troubleshootv1beta2.SupportBundle { +func addDefaultDynamicTroubleshoot(supportBundle *troubleshootv1beta2.SupportBundle, app *apptypes.App, imageName string, pullSecret *troubleshootv1beta2.ImagePullSecrets) *troubleshootv1beta2.SupportBundle { next := supportBundle.DeepCopy() next.Spec.Collectors = append(next.Spec.Collectors, getDefaultDynamicCollectors(app, imageName, pullSecret)...) next.Spec.Analyzers = append(next.Spec.Analyzers, getDefaultDynamicAnalyzers(app)...) return next } -func getDefaultDynamicCollectors(app apptypes.AppType, imageName string, pullSecret *troubleshootv1beta2.ImagePullSecrets) []*troubleshootv1beta2.Collect { +func getDefaultDynamicCollectors(app *apptypes.App, imageName string, pullSecret *troubleshootv1beta2.ImagePullSecrets) []*troubleshootv1beta2.Collect { collectors := make([]*troubleshootv1beta2.Collect, 0) - var err error - var license *v1beta1.License - switch a := app.(type) { - case *apptypes.App: - license, err = store.GetStore().GetLatestLicenseForApp(app.GetID()) - if err != nil { - logger.Errorf("Failed to load license data from store: %v", err) - } - case *apptypes.HelmApp: - license, err = helm.GetChartLicenseFromSecretOrDownload(a) - if err != nil { - logger.Errorf("Failed to load license data from helm: %v", err) - } + license, err := store.GetStore().GetLatestLicenseForApp(app.GetID()) + if err != nil { + logger.Errorf("Failed to load license data from store: %v", err) } if license != nil { @@ -829,25 +808,23 @@ func getDefaultDynamicCollectors(app apptypes.AppType, imageName string, pullSec collectors = append(collectors, makeVeleroCollectors()...) - if app, ok := app.(*apptypes.App); ok { - apps := []*apptypes.App{} - if app != nil { - apps = append(apps, app) - } else { - var err error - apps, err = store.GetStore().ListInstalledApps() - if err != nil { - logger.Errorf("Failed to list installed apps: %v", err) - } + apps := []*apptypes.App{} + if app != nil { + apps = append(apps, app) + } else { + var err error + apps, err = store.GetStore().ListInstalledApps() + if err != nil { + logger.Errorf("Failed to list installed apps: %v", err) } + } - if len(apps) > 0 { - appVersionArchiveCollectors, err := makeAppVersionArchiveCollectors(apps) - if err != nil { - logger.Errorf("Failed to make app version archive collectors: %v", err) - } - collectors = append(collectors, appVersionArchiveCollectors...) + if len(apps) > 0 { + appVersionArchiveCollectors, err := makeAppVersionArchiveCollectors(apps) + if err != nil { + logger.Errorf("Failed to make app version archive collectors: %v", err) } + collectors = append(collectors, appVersionArchiveCollectors...) } clientset, err := k8sutil.GetClientset() @@ -890,7 +867,7 @@ func getDefaultDynamicCollectors(app apptypes.AppType, imageName string, pullSec return collectors } -func getDefaultDynamicAnalyzers(app apptypes.AppType) []*troubleshootv1beta2.Analyze { +func getDefaultDynamicAnalyzers(app *apptypes.App) []*troubleshootv1beta2.Analyze { analyzers := make([]*troubleshootv1beta2.Analyze, 0) analyzers = append(analyzers, makeAPIReplicaAnalyzer()) diff --git a/pkg/supportbundle/supportbundle.go b/pkg/supportbundle/supportbundle.go index e6bf5410fa..188545eb1d 100644 --- a/pkg/supportbundle/supportbundle.go +++ b/pkg/supportbundle/supportbundle.go @@ -12,7 +12,6 @@ import ( "github.com/mholt/archiver/v3" "github.com/pkg/errors" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/kurl" @@ -71,29 +70,6 @@ func Collect(app *apptypes.App, clusterID string) (string, error) { return supportBundle.ID, nil } -func CollectHelm(app *apptypes.HelmApp) (string, error) { - opts := types.TroubleshootOptions{ - DisableUpload: true, - } - supportBundle, err := CreateSupportBundleDependencies(app, app.Version, opts) - if err != nil { - return "", errors.Wrap(err, "could not generate support bundle dependencies") - } - - supportBundle.ID = strings.ToLower(ksuid.New().String()) - supportBundle.Slug = supportBundle.ID - - err = store.GetStore().CreateInProgressSupportBundle(supportBundle) - if err != nil { - return "", errors.Wrap(err, "could not generate support bundle in progress") - } - - progressChan := executeUpdateRoutine(supportBundle) - executeSupportBundleCollectRoutine(supportBundle, progressChan) - - return supportBundle.ID, nil -} - // CreateBundle will create a support bundle in the store, attempting to use the // requestedID. This function uploads the archive and creates the record. func CreateBundle(requestedID string, appID string, archivePath string) (*types.SupportBundle, error) { @@ -137,23 +113,10 @@ func GetBundleCommand(appSlug string) []string { // CreateSupportBundleDependencies generates k8s secrets and configmaps for the support bundle spec and redactors. // These resources will be used when executing a support bundle collection -func CreateSupportBundleDependencies(app apptypes.AppType, sequence int64, opts types.TroubleshootOptions) (*types.SupportBundle, error) { - var kotsKinds *kotsutil.KotsKinds - switch a := app.(type) { - case *apptypes.App: - k, err := getKotsKindsForApp(a, sequence) - if err != nil { - return nil, errors.Wrap(err, "failed to get kots kinds for app") - } - kotsKinds = k - case *apptypes.HelmApp: - k, err := getKotsKindsForHelmApp(a) - if err != nil { - return nil, errors.Wrap(err, "failed to get kots kinds for helm") - } - kotsKinds = k - default: - return nil, errors.Errorf("cannot get kotskinds for app type %T", app) +func CreateSupportBundleDependencies(app *apptypes.App, sequence int64, opts types.TroubleshootOptions) (*types.SupportBundle, error) { + kotsKinds, err := getKotsKindsForApp(app, sequence) + if err != nil { + return nil, errors.Wrap(err, "failed to get kots kinds for app") } supportBundle, err := CreateRenderedSpec(app, sequence, kotsKinds, opts) @@ -219,32 +182,6 @@ func getKotsKindsForApp(app *apptypes.App, sequence int64) (*kotsutil.KotsKinds, return kotsKinds, nil } -func getKotsKindsForHelmApp(app *apptypes.HelmApp) (*kotsutil.KotsKinds, error) { - license, err := helm.GetChartLicenseFromSecretOrDownload(app) - if err != nil { - return nil, errors.Wrap(err, "failed to get license from secret") - } - - specURL := strings.TrimSuffix(app.ChartPath, fmt.Sprintf("/%s", app.Release.Chart.Name())) - upstreamSupportBundle, upstreamRedactors, err := getSupportBundleSpecFromOCI(license.Spec.LicenseID, specURL) - if err != nil { - // don't return; use default collectors/analyzers when spec cannot be downloaded - logger.Infof("failed to download support bundle spec from %s: %v", specURL, err) - } - - kotsKinds := kotsutil.EmptyKotsKinds() - kotsKinds.License = license - - if upstreamSupportBundle != nil { - kotsKinds.SupportBundle = upstreamSupportBundle - } - if upstreamRedactors != nil { - kotsKinds.Redactor = upstreamRedactors - } - - return &kotsKinds, nil -} - func getAnalysisFromBundle(archivePath string) ([]byte, error) { bundleDir, err := ioutil.TempDir("", "kots") if err != nil { diff --git a/pkg/updatechecker/updatechecker.go b/pkg/updatechecker/updatechecker.go index cb0508ac57..287eca9ebb 100644 --- a/pkg/updatechecker/updatechecker.go +++ b/pkg/updatechecker/updatechecker.go @@ -11,16 +11,12 @@ import ( downstreamtypes "github.com/replicatedhq/kots/pkg/api/downstream/types" "github.com/replicatedhq/kots/pkg/app" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/helm" - "github.com/replicatedhq/kots/pkg/kotsadmconfig" license "github.com/replicatedhq/kots/pkg/kotsadmlicense" upstream "github.com/replicatedhq/kots/pkg/kotsadmupstream" - kotslicense "github.com/replicatedhq/kots/pkg/license" "github.com/replicatedhq/kots/pkg/logger" "github.com/replicatedhq/kots/pkg/preflight" "github.com/replicatedhq/kots/pkg/preflight/types" kotspull "github.com/replicatedhq/kots/pkg/pull" - registrytypes "github.com/replicatedhq/kots/pkg/registry/types" "github.com/replicatedhq/kots/pkg/reporting" kotssemver "github.com/replicatedhq/kots/pkg/semver" storepkg "github.com/replicatedhq/kots/pkg/store" @@ -66,7 +62,7 @@ func Start() error { // if enabled, and a cron job was found, update the existing cron job with the latest cron spec // if disabled: stop the current running cron job (if exists) // no-op for airgap applications -func Configure(a apptypes.AppType, updateCheckerSpec string) error { +func Configure(a *apptypes.App, updateCheckerSpec string) error { appId := a.GetID() appSlug := a.GetSlug() isAirgap := a.GetIsAirgap() @@ -211,98 +207,15 @@ func CheckForUpdates(opts CheckForUpdatesOpts) (ucr *UpdateCheckResponse, finalE tasks.StartUpdateTaskMonitor("update-download", finishedChan) - if util.IsHelmManaged() { - ucr, finalError = checkForHelmAppUpdates(opts, finishedChan) - if finalError != nil { - finalError = errors.Wrap(finalError, "failed to get helm app updates") - return - } - } else { - ucr, finalError = checkForKotsAppUpdates(opts, finishedChan) - if finalError != nil { - finalError = errors.Wrap(finalError, "failed to get kots app updates") - return - } + ucr, finalError = checkForKotsAppUpdates(opts, finishedChan) + if finalError != nil { + finalError = errors.Wrap(finalError, "failed to get kots app updates") + return } return } -func checkForHelmAppUpdates(opts CheckForUpdatesOpts, finishedChan chan<- error) (*UpdateCheckResponse, error) { - helmApp := helm.GetHelmApp(opts.AppID) - - license, err := helm.GetChartLicenseFromSecretOrDownload(helmApp) - if err != nil { - return nil, errors.Wrap(err, "failed to get license for helm app") - } - - if license == nil { - return nil, errors.Wrap(err, "license not found for helm app") - } - - currentVersion, err := semver.ParseTolerant(helmApp.Release.Chart.Metadata.Version) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to get parse current version %s", helmApp.Release.Chart.Metadata.Version)) - } - - availableUpdateTags, err := helm.CheckForUpdates(helmApp, license, ¤tVersion) - if err != nil { - expiredErr := util.ActionableError{ - NoRetry: true, - Message: "License is expired", - } - isExpired := false - - newLicense, _ := helm.GetChartLicenseFromSecretOrDownload(helmApp) - if newLicense != nil { - isExpired, _ = kotslicense.LicenseIsExpired(newLicense) - } else { - isExpired, _ = kotslicense.LicenseIsExpired(license) - } - - if isExpired { - return nil, expiredErr - } - - return nil, errors.Wrap(err, "failed to get available updates") - } - - var updates []UpdateCheckRelease - for _, update := range availableUpdateTags { - updates = append(updates, UpdateCheckRelease{ - Sequence: 0, // TODO - Version: update.Tag, - }) - } - - ucr := UpdateCheckResponse{ - AvailableUpdates: int64(len(updates)), - AvailableReleases: updates, - DeployingRelease: nil, - } - - status := fmt.Sprintf("%d Updates available...", ucr.AvailableUpdates) - if err := store.SetTaskStatus("update-download", status, "running"); err != nil { - return nil, errors.Wrap(err, "failed to set task status") - } - - if opts.Wait { - if err := downloadHelmAppUpdates(opts, helmApp, license.Spec.LicenseID, updates); err != nil { - return nil, errors.Wrap(err, "failed to process updates") - } - } else if ucr.AvailableUpdates > 0 { - go func() { - defer close(finishedChan) - if err := downloadHelmAppUpdates(opts, helmApp, license.Spec.LicenseID, updates); err != nil { - logger.Error(errors.Wrap(err, "failed to process updates")) - } - finishedChan <- err - }() - } - - return &ucr, nil -} - func checkForKotsAppUpdates(opts CheckForUpdatesOpts, finishedChan chan<- error) (*UpdateCheckResponse, error) { a, err := store.GetApp(opts.AppID) if err != nil { @@ -403,13 +316,13 @@ func checkForKotsAppUpdates(opts CheckForUpdatesOpts, finishedChan chan<- error) } if opts.Wait { - if err := downloadKotsAppUpdates(opts, a.ID, d.ClusterID, filteredUpdates, updates.UpdateCheckTime); err != nil { + if err := downloadAppUpdates(opts, a.ID, d.ClusterID, filteredUpdates, updates.UpdateCheckTime); err != nil { return nil, errors.Wrap(err, "failed to download updates synchronously") } } else if ucr.AvailableUpdates > 0 { go func() { defer close(finishedChan) - err := downloadKotsAppUpdates(opts, a.ID, d.ClusterID, filteredUpdates, updates.UpdateCheckTime) + err := downloadAppUpdates(opts, a.ID, d.ClusterID, filteredUpdates, updates.UpdateCheckTime) if err != nil { logger.Error(errors.Wrap(err, "failed to download updates asynchronously")) } @@ -420,55 +333,7 @@ func checkForKotsAppUpdates(opts CheckForUpdatesOpts, finishedChan chan<- error) return &ucr, nil } -func downloadHelmAppUpdates(opts CheckForUpdatesOpts, helmApp *apptypes.HelmApp, licenseID string, updates []UpdateCheckRelease) error { - currentKotsKinds, err := helm.GetKotsKindsFromHelmApp(helmApp) - if err != nil { - return errors.Wrapf(err, "failed to get current config values") - } - - // Download in reverse order, from oldest to newest - for i := len(updates) - 1; i >= 0; i-- { - update := updates[i] - status := fmt.Sprintf("Downloading release %s...", update.Version) - if err := store.SetTaskStatus("update-download", status, "running"); err != nil { - logger.Info("failed to set task status", zap.String("error", err.Error())) - } - - kotsKinds, err := helm.GetKotsKindsFromUpstreamChartVersion(helmApp, licenseID, update.Version) - if err != nil { - return errors.Wrapf(err, "failed to pull update %s for chart", update.Version) - } - kotsKinds.ConfigValues = currentKotsKinds.ConfigValues.DeepCopy() - - downstreamStatus := storetypes.VersionPending - // TODO: preflight handling - // if kotsKinds.HasPreflights() { - // downstreamStatus = types.VersionPendingPreflight - // } - - sequence := int64(-1) // TODO: do something sensible, this value isn't used - registrySettings := registrytypes.RegistrySettings{} // TODO: private registries aren't supported yet - t, err := kotsadmconfig.NeedsConfiguration(helmApp.GetSlug(), sequence, helmApp.GetIsAirgap(), &kotsKinds, registrySettings) - if err != nil { - return errors.Wrap(err, "failed to check if version needs configuration") - } - if t { - downstreamStatus = storetypes.VersionPendingConfig - } - - replicatedMetadata, err := helm.GetReplicatedMetadataFromUpstreamChartVersion(helmApp, licenseID, update.Version) - if err != nil { - return errors.Wrap(err, "failed to replicated metadata") - } - - helm.SetCachedUpdateStatus(helmApp.ChartPath, update.Version, downstreamStatus) - helm.SetCachedUpdateMetadata(helmApp.ChartPath, update.Version, replicatedMetadata) - } - - return nil -} - -func downloadKotsAppUpdates(opts CheckForUpdatesOpts, appID string, clusterID string, updates []upstreamtypes.Update, updateCheckTime time.Time) error { +func downloadAppUpdates(opts CheckForUpdatesOpts, appID string, clusterID string, updates []upstreamtypes.Update, updateCheckTime time.Time) error { for index, update := range updates { appSequence, err := upstream.DownloadUpdate(appID, update, opts.SkipPreflights, opts.SkipCompatibilityCheck) if appSequence != nil { @@ -511,7 +376,7 @@ func ensureDesiredVersionIsDeployed(opts CheckForUpdatesOpts, clusterID string) return nil } - if !opts.IsAutomatic || util.IsHelmManaged() { + if !opts.IsAutomatic { return nil } diff --git a/pkg/util/util.go b/pkg/util/util.go index 0f2cb3ab79..2948ddce09 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -165,10 +165,6 @@ func HomeDir() string { return os.Getenv("USERPROFILE") } -func IsHelmManaged() bool { - return os.Getenv("IS_HELM_MANAGED") == "true" -} - func IsEmbeddedCluster() bool { return os.Getenv("EMBEDDED_CLUSTER_ID") != "" } diff --git a/web/src/Root.tsx b/web/src/Root.tsx index 2aa10be0e6..a6771247d3 100644 --- a/web/src/Root.tsx +++ b/web/src/Root.tsx @@ -99,7 +99,6 @@ type State = { featureFlags: object; fetchingMetadata: boolean; initSessionId: string | null; - isHelmManaged: boolean; selectedAppName: string | null; snapshotInProgressApps: string[]; themeState: ThemeState; @@ -124,7 +123,6 @@ const Root = () => { shouldShowClusterUpgradeModal: false, errLoggingOut: "", featureFlags: {}, - isHelmManaged: false, fetchingMetadata: false, initSessionId: Utilities.localStorageEnabled() ? localStorage.getItem(INIT_SESSION_ID_STORAGE_KEY) @@ -182,38 +180,6 @@ const Root = () => { setState({ initSessionId }); }; - // TODO: delete if not used - // const handleActiveInitSessionCompleted = () => { - // if (Utilities.localStorageEnabled()) { - // localStorage.removeItem(INIT_SESSION_ID_STORAGE_KEY); - // } - // setState({ initSessionId: "" }); - // }; - - const checkIsHelmManaged = async () => { - try { - const res = await fetch(`${process.env.API_ENDPOINT}/is-helm-managed`, { - headers: { - "Content-Type": "application/json", - }, - method: "GET", - credentials: "include", - }); - if (res.ok && res.status === 200) { - const response = await res.json(); - setState({ isHelmManaged: response.isHelmManaged }); - return response.isHelmManaged; - } else { - setState({ isHelmManaged: false }); - } - return false; - } catch (err) { - console.log(err); - setState({ isHelmManaged: false }); - return false; - } - }; - const getPendingApp = async () => { try { const res = await fetch(`${process.env.API_ENDPOINT}/pendingapp`, { @@ -360,7 +326,6 @@ const Root = () => { fetchKotsAppMetadata(); if (Utilities.isLoggedIn()) { ping(); - checkIsHelmManaged(); getAppsList().then((appsList) => { if (appsList?.length > 0 && window.location.pathname === "/apps") { const { slug } = appsList[0]; @@ -479,7 +444,6 @@ const Root = () => { onLogoutError={onLogoutError} isSnapshotsSupported={isSnapshotsSupported()} errLoggingOut={state.errLoggingOut} - isHelmManaged={state.isHelmManaged} />
diff --git a/web/src/components/apps/AppVersionHistory.tsx b/web/src/components/apps/AppVersionHistory.tsx
index 69fff01985..a7418bff5f 100644
--- a/web/src/components/apps/AppVersionHistory.tsx
+++ b/web/src/components/apps/AppVersionHistory.tsx
@@ -30,8 +30,6 @@ import { Repeater } from "../../utilities/repeater";
import { AirgapUploader } from "../../utilities/airgapUploader";
import ReactTooltip from "react-tooltip";
import Pager from "../shared/Pager";
-import { HelmDeployModal } from "../shared/modals/HelmDeployModal";
-import { UseDownloadValues } from "../hooks";
import { KotsPageTitle } from "@components/Head";
import "@src/scss/components/apps/AppVersionHistory.scss";
@@ -64,7 +62,6 @@ type Props = {
app: App;
displayErrorModal: boolean;
isBundleUploading: boolean;
- isHelmManaged: boolean;
makeCurrentVersion: (
slug: string,
version: Version | null,
@@ -132,8 +129,6 @@ type State = {
showDeployWarningModal: boolean;
showDiffErrModal: boolean;
showDiffOverlay: boolean;
- showHelmDeployModalForSequence: number | null;
- showHelmDeployModalForVersionLabel: string;
showLogsModal: boolean;
showNoChangesModal: boolean;
showSkipModal: boolean;
@@ -153,13 +148,6 @@ type State = {
yamlErrorDetails: string[];
};
-const filterNonHelmTabs = (tab: string, isHelmManaged: boolean) => {
- if (isHelmManaged) {
- return tab.startsWith("helm");
- }
- return true;
-};
-
class AppVersionHistory extends Component
- Configure how often you would like to automatically check for updates. -
- ); - } else if (gitopsIsConnected) { + if (gitopsIsConnected) { configureText = (
Configure how often you would like to automatically check for updates.
@@ -367,7 +355,7 @@ export default class AutomaticUpdatesModal extends Component
Automatically deploy new versions
diff --git a/web/src/components/shared/EditConfigIcon.tsx b/web/src/components/shared/EditConfigIcon.tsx
index 76e505edec..f96002965d 100644
--- a/web/src/components/shared/EditConfigIcon.tsx
+++ b/web/src/components/shared/EditConfigIcon.tsx
@@ -1,7 +1,6 @@
import { useSelectedApp } from "@features/App";
import { Version } from "@types";
import { Link } from "react-router-dom";
-import { useIsHelmManaged } from "@src/components//hooks";
import Icon from "@components/Icon";
import ReactTooltip from "react-tooltip";
@@ -12,8 +11,6 @@ const EditConfigIcon = ({
version: Version | null;
isPending: boolean;
}) => {
- const { data: isHelmManagedResponse } = useIsHelmManaged();
- const isHelmManaged = isHelmManagedResponse || {};
const selectedApp = useSelectedApp();
if (!version) {
@@ -31,7 +28,7 @@ const EditConfigIcon = ({
}
let url = `/app/${selectedApp?.slug}/config/${version.sequence}`;
- if (isHelmManaged && version.status.startsWith("pending")) {
+ if (version.status.startsWith("pending")) {
url = `${url}?isPending=${isPending}&semver=${version.semver}`;
}
diff --git a/web/src/components/shared/NavBar.tsx b/web/src/components/shared/NavBar.tsx
index 4495573810..3521d6eb3c 100644
--- a/web/src/components/shared/NavBar.tsx
+++ b/web/src/components/shared/NavBar.tsx
@@ -16,7 +16,6 @@ type Props = {
errLoggingOut: string;
fetchingMetadata: boolean;
isGitOpsSupported: boolean;
- isHelmManaged: boolean;
isIdentityServiceSupported: boolean;
isKurlEnabled: boolean;
isEmbeddedClusterEnabled: boolean;
@@ -291,7 +290,6 @@ export class NavBar extends PureComponent setShowModal(true)}>Change password Add new application {subtitle}
- Ensure you replace
- {sequenceLabel} {version.sequence}
-
+ Sequence {version.sequence}
+
{" "}
diff --git a/web/src/features/AppVersionHistory/api/getVersions.tsx b/web/src/features/AppVersionHistory/api/getVersions.tsx
index 22891372cb..16e084f8d2 100644
--- a/web/src/features/AppVersionHistory/api/getVersions.tsx
+++ b/web/src/features/AppVersionHistory/api/getVersions.tsx
@@ -4,7 +4,6 @@ import { Utilities } from "../../../utilities/utilities";
import { useParams } from "react-router-dom";
import { useSelectedApp } from "@features/App";
import { useMetadata } from "@src/stores";
-import { useIsHelmManaged } from "@src/components/hooks";
import { App, KotsParams, Metadata, Version } from "@types";
async function getVersions({
@@ -125,62 +124,18 @@ function getVersionsSelectorForAirgapped({
return getVersionsSelectorForKotsManaged({ versions, selectedApp, metadata });
}
-function getVersionsSelectorForHelmManaged({
- versions,
-}: {
- versions: { versionHistory: Version[] };
-}) {
- const deployedSequence = versions?.versionHistory?.find(
- (v) => v.status === "deployed"
- )?.sequence;
-
- const versionHistory = versions?.versionHistory.map((version) => {
- let statusLabel = "Redeploy";
-
- if (deployedSequence === undefined)
- return {
- ...version,
- statusLabel,
- };
-
- if (version.sequence > deployedSequence) {
- statusLabel = "Deploy";
- }
-
- if (version.sequence < deployedSequence) {
- statusLabel = "Rollback";
- }
- return {
- ...version,
- statusLabel,
- };
- });
-
- return {
- ...versions,
- versionHistory,
- };
-}
-
function chooseVersionsSelector({
isAirgap,
isKurl,
- isHelmManaged,
}: {
isAirgap?: boolean;
isKurl?: boolean;
- isHelmManaged?: boolean;
}) {
// if airgapped
if (isAirgap && isKurl) {
return getVersionsSelectorForAirgapped;
}
- // if helm managed
- if (isHelmManaged) {
- return getVersionsSelectorForHelmManaged;
- }
-
// if kots managed
return getVersionsSelectorForKotsManaged;
}
@@ -195,12 +150,10 @@ function useVersions({
let { slug } = useParams{title}
- {"
with
- the path to your saved file.
-
- {sequenceLabel} {currentVersion?.sequence} + Sequence {currentVersion?.sequence}
- Sequence {latestDeployableVersion.sequence} -
- )} ++ Sequence {latestDeployableVersion.sequence} +
{latestDeployableVersion.isRequired && ( {" "} @@ -1498,11 +1457,6 @@ const DashboardVersionCard = (props: Props) => { ); } - let isPending = false; - if (isHelmManaged && latestDeployableVersion?.status?.startsWith("pending")) { - isPending = true; - } - return (