Skip to content

Commit f1aa1fc

Browse files
fix: Helm apps entries in Ea mode (#5652)
* added the ea apps entry app table * resolved the ea mode multiple rows error during configuration of app * modified the ea dockerfile in ca-certificates cmd * uncommented the code and left the ea helm app making way untouched * remodified the dockerfile as previous state * modified the docker file ea mode * dockerfile exit code 100 due to ap install alternative in ea mode dockerfile * execute make after main merge * modified changes in dockerfile ea mode * resolved comments after first level review * executed make after merging with develop branch
1 parent af3133d commit f1aa1fc

File tree

5 files changed

+150
-8
lines changed

5 files changed

+150
-8
lines changed

pkg/app/AppCrudOperationService.go

+73-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package app
1919
import (
2020
"context"
2121
"encoding/json"
22+
"errors"
2223
"fmt"
2324
"github.com/caarlos0/env"
2425
client "github.com/devtron-labs/devtron/api/helm-app/service"
@@ -457,13 +458,67 @@ func convertUrlToHttpsIfSshType(url string) string {
457458
return httpsURL
458459
}
459460

461+
// handleDuplicateAppEntries identifies and resolves duplicate app entries based on creation time.
462+
// It marks the most recent duplicate entry as inactive and updates the corresponding installed app.
463+
func (impl AppCrudOperationServiceImpl) handleDuplicateAppEntries(appNameUniqueIdentifier string) (*appRepository.App, error) {
464+
// Fetch app IDs by name
465+
appIds, err := impl.getAppIdsByName(appNameUniqueIdentifier)
466+
if err != nil {
467+
impl.logger.Errorw("error in fetching app Ids by appIdentifier", "appNameUniqueIdentifier", appNameUniqueIdentifier, "err", err)
468+
return nil, err
469+
}
470+
471+
// Fetch apps by IDs from App table for duplicated entries
472+
apps, err := impl.appRepository.FindByIds(appIds)
473+
if err != nil || errors.Is(err, pg.ErrNoRows) {
474+
impl.logger.Errorw("error in fetching app List by appIds", "appIds", appIds, "err", err)
475+
return nil, err
476+
}
477+
478+
// Identify the earliest and duplicated app entries
479+
earliestApp, duplicatedApp := identifyDuplicateApps(apps)
480+
481+
// Fetch the installed app associated with the duplicated app
482+
installedApp, err := impl.installedAppRepository.GetInstalledAppsByAppId(duplicatedApp.Id)
483+
if err != nil {
484+
impl.logger.Errorw("error in fetching installed app by appId", "appId", duplicatedApp.Id, "err", err)
485+
return nil, err
486+
}
487+
// Update duplicated app entries
488+
err = impl.installedAppDbService.UpdateDuplicatedEntriesInAppAndInstalledApps(earliestApp, duplicatedApp, &installedApp)
489+
if err != nil {
490+
impl.logger.Errorw("error in updating duplicated entries", "earliestApp", earliestApp, "duplicatedApp", duplicatedApp, "err", err)
491+
return nil, err
492+
}
493+
494+
impl.logger.Debug("Successfully resolved duplicate app entries", "earliestApp", earliestApp, "duplicatedApp", duplicatedApp)
495+
return earliestApp, nil
496+
497+
}
498+
499+
// getAppIdsByName fetches app IDs by the app name unique identifier [for duplicated active app]
500+
func (impl AppCrudOperationServiceImpl) getAppIdsByName(appNameUniqueIdentifier string) ([]*int, error) {
501+
slice := []string{appNameUniqueIdentifier}
502+
appIds, err := impl.appRepository.FindIdsByNames(slice)
503+
if err != nil {
504+
return nil, err
505+
}
506+
507+
// Convert each element to a pointer and store in a slice of pointers
508+
ids := make([]*int, len(appIds))
509+
for i := range appIds {
510+
ids[i] = &appIds[i]
511+
}
512+
return ids, nil
513+
}
514+
460515
// getAppAndProjectForAppIdentifier, returns app db model for an app unique identifier or from display_name if both exists else it throws pg.ErrNoRows
461516
func (impl AppCrudOperationServiceImpl) getAppAndProjectForAppIdentifier(appIdentifier *helmBean.AppIdentifier) (*appRepository.App, error) {
462517
app := &appRepository.App{}
463518
var err error
464519
appNameUniqueIdentifier := appIdentifier.GetUniqueAppNameIdentifier()
465520
app, err = impl.appRepository.FindAppAndProjectByAppName(appNameUniqueIdentifier)
466-
if err != nil && err != pg.ErrNoRows {
521+
if err != nil && !errors.Is(err, pg.ErrNoRows) && !errors.Is(err, pg.ErrMultiRows) {
467522
impl.logger.Errorw("error in fetching app meta data by unique app identifier", "appNameUniqueIdentifier", appNameUniqueIdentifier, "err", err)
468523
return app, err
469524
}
@@ -475,6 +530,14 @@ func (impl AppCrudOperationServiceImpl) getAppAndProjectForAppIdentifier(appIden
475530
return app, err
476531
}
477532
}
533+
if errors.Is(err, pg.ErrMultiRows) {
534+
535+
app, err = impl.handleDuplicateAppEntries(appNameUniqueIdentifier)
536+
if err != nil {
537+
impl.logger.Errorw("error in handling Duplicate entries in the app", "appNameUniqueIdentifier", appNameUniqueIdentifier, "err", err)
538+
return app, err
539+
}
540+
}
478541
return app, nil
479542
}
480543

@@ -532,17 +595,17 @@ func (impl AppCrudOperationServiceImpl) GetHelmAppMetaInfo(appId string) (*bean.
532595
return nil, err
533596
}
534597
// if app.DisplayName is empty then that app_name is not yet migrated to app name unique identifier
535-
if app.Id > 0 && len(app.DisplayName) == 0 {
598+
if app != nil && app.Id > 0 && len(app.DisplayName) == 0 {
536599
err = impl.updateAppNameToUniqueAppIdentifierInApp(app, appIdDecoded)
537600
if err != nil {
538601
impl.logger.Errorw("GetHelmAppMetaInfo, error in migrating displayName and appName to unique identifier for external apps", "appIdentifier", appIdDecoded, "err", err)
539602
//not returning from here as we need to show helm app metadata even if migration of app_name fails, then migration can happen on project update
540603
}
541604
}
542-
if app.Id == 0 {
605+
if app != nil && app.Id == 0 {
543606
app.AppName = appIdDecoded.ReleaseName
544607
}
545-
if util2.IsExternalChartStoreApp(app.DisplayName) {
608+
if app != nil && util2.IsExternalChartStoreApp(app.DisplayName) {
546609
displayName = app.DisplayName
547610
}
548611

@@ -568,9 +631,14 @@ func (impl AppCrudOperationServiceImpl) GetHelmAppMetaInfo(appId string) (*bean.
568631
displayName = InstalledApp.App.DisplayName
569632
}
570633
}
634+
// Safeguard against nil app cases
635+
if app == nil {
636+
impl.logger.Errorw("no rows found for the requested app", "appId", appId, "error", err)
637+
return nil, fmt.Errorf("no rows found for the requested app, %q", pg.ErrNoRows)
638+
}
571639

572640
user, err := impl.userRepository.GetByIdIncludeDeleted(app.CreatedBy)
573-
if err != nil && err != pg.ErrNoRows {
641+
if err != nil && !errors.Is(err, pg.ErrNoRows) {
574642
impl.logger.Errorw("error in fetching user for app meta info", "error", err)
575643
return nil, err
576644
}

pkg/app/helper.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package app
1818

19-
import "strings"
19+
import (
20+
appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app"
21+
"strings"
22+
)
2023

2124
// LabelMatchingRegex is the official k8s label matching regex, pls refer https://github.com/kubernetes/apimachinery/blob/bfd2aff97e594f6aad77acbe2cbbe190acc93cbc/pkg/util/validation/validation.go#L167
2225
const LabelMatchingRegex = "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$"
@@ -43,3 +46,21 @@ func sanitizeLabels(extraAppLabels map[string]string) map[string]string {
4346
}
4447
return extraAppLabels
4548
}
49+
50+
// identifyDuplicateApps identifies the earliest created app and the most recent duplicate app.
51+
func identifyDuplicateApps(apps []*appRepository.App) (earliestApp *appRepository.App, duplicatedApp *appRepository.App) {
52+
if len(apps) == 0 {
53+
return nil, nil
54+
}
55+
earliestApp = apps[0]
56+
duplicatedApp = apps[0]
57+
for _, app := range apps[1:] {
58+
if app.AuditLog.CreatedOn.Before(earliestApp.AuditLog.CreatedOn) {
59+
earliestApp = app
60+
}
61+
if app.AuditLog.CreatedOn.After(duplicatedApp.AuditLog.CreatedOn) {
62+
duplicatedApp = app
63+
}
64+
}
65+
return earliestApp, duplicatedApp
66+
}

pkg/appStore/installedApp/service/AppStoreDeploymentDBService.go

-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ func (impl *AppStoreDeploymentDBServiceImpl) AppStoreDeployOperationDB(installRe
133133
}
134134
// setting additional env data required in appStoreBean.InstallAppVersionDTO
135135
adapter.UpdateAdditionalEnvDetails(installRequest, environment)
136-
137136
impl.appStoreValidator.Validate(installRequest, environment)
138137

139138
// Stage 1: Create App in tx (Only if AppId is not set already)

pkg/appStore/installedApp/service/EAMode/InstalledAppDBService.go

+54
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type InstalledAppDBService interface {
5858
GetReleaseInfo(appIdentifier *helmBean.AppIdentifier) (*appStoreBean.InstallAppVersionDTO, error)
5959
IsExternalAppLinkedToChartStore(appId int) (bool, []*appStoreRepo.InstalledApps, error)
6060
CreateNewAppEntryForAllInstalledApps(installedApps []*appStoreRepo.InstalledApps) error
61+
UpdateDuplicatedEntriesInAppAndInstalledApps(earlyApp *app.App, duplicatedApp *app.App, installedApp *appStoreRepo.InstalledApps) error
6162
}
6263

6364
type InstalledAppDBServiceImpl struct {
@@ -399,6 +400,17 @@ func (impl *InstalledAppDBServiceImpl) CreateNewAppEntryForAllInstalledApps(inst
399400
// Rollback tx on error.
400401
defer tx.Rollback()
401402
for _, installedApp := range installedApps {
403+
404+
//check if there is any app from its appName is exits and active ...if yes then we will not insert any extra entry in the db
405+
appMetadataByAppName, err := impl.AppRepository.FindActiveByName(installedApp.App.AppName)
406+
if err != nil && !util.IsErrNoRows(err) {
407+
impl.Logger.Errorw("error in fetching app by unique app identifier", "appNameUniqueIdentifier", installedApp.GetUniqueAppNameIdentifier(), "err", err)
408+
return err
409+
}
410+
if appMetadataByAppName != nil && appMetadataByAppName.Id > 0 {
411+
//app already exists for this unique identifier hence not creating new app entry for this as it will get modified after this function
412+
continue
413+
}
402414
//check if for this unique identifier name an app already exists, if yes then continue
403415
appMetadata, err := impl.AppRepository.FindActiveByName(installedApp.GetUniqueAppNameIdentifier())
404416
if err != nil && !util.IsErrNoRows(err) {
@@ -437,3 +449,45 @@ func (impl *InstalledAppDBServiceImpl) CreateNewAppEntryForAllInstalledApps(inst
437449
tx.Commit()
438450
return nil
439451
}
452+
453+
// UpdateDuplicatedEntriesInAppAndInstalledApps performs the updation in app table and installedApps table for the cases when multiple active app found [typically two due to migration], here we are updating the db with its previous value in the installedApps table and early created app id
454+
func (impl *InstalledAppDBServiceImpl) UpdateDuplicatedEntriesInAppAndInstalledApps(earlyApp *app.App, duplicatedApp *app.App, installedApp *appStoreRepo.InstalledApps) error {
455+
// db operations
456+
dbConnection := impl.InstalledAppRepository.GetConnection()
457+
tx, err := dbConnection.Begin()
458+
if err != nil {
459+
return err
460+
}
461+
// Rollback tx on error.
462+
defer func(tx *pg.Tx) {
463+
err := tx.Rollback()
464+
if err != nil {
465+
impl.Logger.Errorw("Rollback error", "err", err)
466+
}
467+
}(tx)
468+
469+
//updated the app table with active column as false for the duplicated app
470+
duplicatedApp.Active = false
471+
duplicatedApp.CreateAuditLog(bean3.SystemUserId)
472+
err = impl.AppRepository.UpdateWithTxn(duplicatedApp, tx)
473+
if err != nil {
474+
impl.Logger.Errorw("error saving appModel", "err", err)
475+
return err
476+
}
477+
478+
// updating the installedApps table with its appId column with the previous app
479+
installedApp.AppId = earlyApp.Id
480+
installedApp.UpdateAuditLog(bean3.SystemUserId)
481+
_, err = impl.InstalledAppRepository.UpdateInstalledApp(installedApp, tx)
482+
if err != nil {
483+
impl.Logger.Errorw("error saving updating installed app with new appId", "installedAppId", installedApp.Id, "err", err)
484+
return err
485+
}
486+
487+
err = tx.Commit()
488+
if err != nil {
489+
impl.Logger.Errorw("error saving appModel", "err", err)
490+
return err
491+
}
492+
return nil
493+
}

wire_gen.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)