diff --git a/pkg/api/v1/api.proto b/pkg/api/v1/api.proto index 9235d5ae5..65d13c32e 100644 --- a/pkg/api/v1/api.proto +++ b/pkg/api/v1/api.proto @@ -434,7 +434,6 @@ message OverviewApplication { } message GetOverviewResponse { - map applications = 2; repeated EnvironmentGroup environment_groups = 3; string git_revision = 4; string branch = 5; @@ -591,10 +590,12 @@ message Environment { string name = 1; EnvironmentConfig config = 2; - map locks = 3; + map locks = 3; //Environment Locks. Lock ID -> Lock map applications = 4; uint32 distance_to_upstream = 5; Priority priority = 6; + map app_locks = 7; //Application Locks. AppName -> []Locks + map team_locks = 8; //Team Locks. TeamName -> []Locks } message Release { diff --git a/pkg/db/db.go b/pkg/db/db.go index aabb95a81..6c9ab9792 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -5461,7 +5461,6 @@ func (h *DBHandler) ReadLatestOverviewCache(ctx context.Context, transaction *sq result := &api.GetOverviewResponse{ Branch: "", ManifestRepoUrl: "", - Applications: map[string]*api.Application{}, EnvironmentGroups: []*api.EnvironmentGroup{}, GitRevision: "", } diff --git a/services/cd-service/pkg/repository/repository.go b/services/cd-service/pkg/repository/repository.go index c9e4761ae..7b15e0f40 100644 --- a/services/cd-service/pkg/repository/repository.go +++ b/services/cd-service/pkg/repository/repository.go @@ -2489,58 +2489,17 @@ func (s *State) DBInsertEnvironmentWithOverview(ctx context.Context, tx *sql.Tx, func (s *State) UpdateTopLevelAppInOverview(ctx context.Context, transaction *sql.Tx, appName string, result *api.GetOverviewResponse, deleteApp bool, allReleasesOfAllApps map[string][]int64) error { if deleteApp { - delete(result.Applications, appName) return nil } - app := api.Application{ - UndeploySummary: 0, - Warnings: nil, - Name: appName, - Releases: []*api.Release{}, - SourceRepoUrl: "", - Team: "", - } - allReleasesOfApp, found := allReleasesOfAllApps[appName] - var rels []uint64 - if found { - rels = conversion.ToUint64Slice(allReleasesOfApp) - } else { - retrievedReleasesOfApp, err := s.GetAllApplicationReleases(ctx, transaction, appName) - if err != nil { - logger.FromContext(ctx).Sugar().Warnf("app without releases: %v", err) - } - rels = retrievedReleasesOfApp - } - for _, id := range rels { - if rel, err := s.GetApplicationRelease(ctx, transaction, appName, id); err != nil { - return err - } else { - if rel == nil { - // ignore - } else { - release := rel.ToProto() - release.Version = id - release.UndeployVersion = rel.UndeployVersion - app.Releases = append(app.Releases, release) - } - } - } - - if team, err := s.GetApplicationTeamOwner(ctx, transaction, appName); err != nil { + var team string + var err error + if team, err = s.GetApplicationTeamOwner(ctx, transaction, appName); err != nil { return err - } else { - app.Team = team } if result == nil { return nil } - app.UndeploySummary = deriveUndeploySummary(appName, result.EnvironmentGroups) - app.Warnings = CalculateWarnings(ctx, app.Name, result.EnvironmentGroups) - if result.Applications == nil { - result.Applications = map[string]*api.Application{} - } - result.Applications[appName] = &app - result.LightweightApps = append(result.LightweightApps, &api.OverviewApplication{Name: appName, Team: app.Team}) + result.LightweightApps = append(result.LightweightApps, &api.OverviewApplication{Name: appName, Team: team}) return nil } @@ -2814,6 +2773,8 @@ func (s *State) UpdateEnvironmentsInOverview(ctx context.Context, transaction *s }, Locks: map[string]*api.Lock{}, Applications: map[string]*api.Environment_Application{}, + AppLocks: make(map[string]*api.Locks), + TeamLocks: make(map[string]*api.Locks), } envInGroup.Config = env.Config if locks, err := s.GetEnvironmentLocks(ctx, transaction, envName); err != nil { @@ -2842,6 +2803,45 @@ func (s *State) UpdateEnvironmentsInOverview(ctx context.Context, transaction *s return err } env.Applications[appName] = app + apiAppLocks := api.Locks{ + Locks: make([]*api.Lock, 0), + } + if appLocks, err := s.GetEnvironmentApplicationLocks(ctx, transaction, envName, appName); err != nil { + return err + } else { + for lockId, lock := range appLocks { + apiAppLocks.Locks = append(apiAppLocks.Locks, &api.Lock{ + Message: lock.Message, + LockId: lockId, + CreatedAt: timestamppb.New(lock.CreatedAt), + CreatedBy: &api.Actor{ + Name: lock.CreatedBy.Name, + Email: lock.CreatedBy.Email, + }, + }) + } + env.AppLocks[appName] = &apiAppLocks + } + + apiTeamLocks := api.Locks{ + Locks: make([]*api.Lock, 0), + } + if teamLocks, err := s.GetEnvironmentTeamLocks(ctx, transaction, envName, app.Team); err != nil { + return err + } else { + for lockId, lock := range teamLocks { + apiTeamLocks.Locks = append(apiTeamLocks.Locks, &api.Lock{ + Message: lock.Message, + LockId: lockId, + CreatedAt: timestamppb.New(lock.CreatedAt), + CreatedBy: &api.Actor{ + Name: lock.CreatedBy.Name, + Email: lock.CreatedBy.Email, + }, + }) + } + env.TeamLocks[app.Team] = &apiTeamLocks + } } } envInGroup.Applications = env.Applications diff --git a/services/cd-service/pkg/repository/transformer.go b/services/cd-service/pkg/repository/transformer.go index 3a07da84a..26c60f3d7 100644 --- a/services/cd-service/pkg/repository/transformer.go +++ b/services/cd-service/pkg/repository/transformer.go @@ -2753,7 +2753,6 @@ func (c *CreateEnvironment) Transform( overview = &api.GetOverviewResponse{ Branch: "", ManifestRepoUrl: "", - Applications: map[string]*api.Application{}, EnvironmentGroups: []*api.EnvironmentGroup{}, GitRevision: "0000000000000000000000000000000000000000", } diff --git a/services/cd-service/pkg/service/git.go b/services/cd-service/pkg/service/git.go index d1a49e0e3..550e9dc32 100644 --- a/services/cd-service/pkg/service/git.go +++ b/services/cd-service/pkg/service/git.go @@ -24,7 +24,6 @@ import ( "github.com/freiheit-com/kuberpult/pkg/db" "os" "sort" - "strconv" "strings" api "github.com/freiheit-com/kuberpult/pkg/api/v1" @@ -55,93 +54,96 @@ func (s *GitServer) GetGitTags(ctx context.Context, _ *api.GetGitTagsRequest) (* } func (s *GitServer) GetProductSummary(ctx context.Context, in *api.GetProductSummaryRequest) (*api.GetProductSummaryResponse, error) { - if in.Environment == nil && in.EnvironmentGroup == nil { - return nil, fmt.Errorf("Must have an environment or environmentGroup to get the product summary for") - } - if in.Environment != nil && in.EnvironmentGroup != nil { - if *in.Environment != "" && *in.EnvironmentGroup != "" { - return nil, fmt.Errorf("Can not have both an environment and environmentGroup to get the product summary for") - } - } - if in.ManifestRepoCommitHash == "" { - return nil, fmt.Errorf("Must have a commit to get the product summary for") - } - response, err := s.OverviewService.GetOverview(ctx, &api.GetOverviewRequest{GitRevision: in.ManifestRepoCommitHash}) - if err != nil { - return nil, fmt.Errorf("unable to get overview for %s: %v", in.ManifestRepoCommitHash, err) - } - - var summaryFromEnv []api.ProductSummary - if in.Environment != nil && *in.Environment != "" { - for _, group := range response.EnvironmentGroups { - for _, env := range group.Environments { - if env.Name == *in.Environment { - for _, app := range env.Applications { - summaryFromEnv = append(summaryFromEnv, api.ProductSummary{ - CommitId: "", - DisplayVersion: "", - Team: "", - App: app.Name, - Version: strconv.FormatUint(app.Version, 10), - Environment: *in.Environment, - }) - } - } - } - } - if len(summaryFromEnv) == 0 { - return &api.GetProductSummaryResponse{ - ProductSummary: nil, - }, nil - } - sort.Slice(summaryFromEnv, func(i, j int) bool { - a := summaryFromEnv[i].App - b := summaryFromEnv[j].App - return a < b - }) - } else { - for _, group := range response.EnvironmentGroups { - if *in.EnvironmentGroup == group.EnvironmentGroupName { - for _, env := range group.Environments { - var singleEnvSummary []api.ProductSummary - for _, app := range env.Applications { - singleEnvSummary = append(singleEnvSummary, api.ProductSummary{ - CommitId: "", - DisplayVersion: "", - Team: "", - App: app.Name, - Version: strconv.FormatUint(app.Version, 10), - Environment: env.Name, - }) - } - sort.Slice(singleEnvSummary, func(i, j int) bool { - a := singleEnvSummary[i].App - b := singleEnvSummary[j].App - return a < b - }) - summaryFromEnv = append(summaryFromEnv, singleEnvSummary...) - } - } - } - if len(summaryFromEnv) == 0 { - return nil, nil - } - } - - var productVersion []*api.ProductSummary - for _, row := range summaryFromEnv { //nolint: govet - for _, app := range response.Applications { - if row.App == app.Name { - for _, release := range app.Releases { - if strconv.FormatUint(release.Version, 10) == row.Version { - productVersion = append(productVersion, &api.ProductSummary{App: row.App, Version: row.Version, CommitId: release.SourceCommitId, DisplayVersion: release.DisplayVersion, Environment: row.Environment, Team: app.Team}) - break - } - } - } - } - } - return &api.GetProductSummaryResponse{ProductSummary: productVersion}, nil + //if in.Environment == nil && in.EnvironmentGroup == nil { + // return nil, fmt.Errorf("Must have an environment or environmentGroup to get the product summary for") + //} + //if in.Environment != nil && in.EnvironmentGroup != nil { + // if *in.Environment != "" && *in.EnvironmentGroup != "" { + // return nil, fmt.Errorf("Can not have both an environment and environmentGroup to get the product summary for") + // } + //} + //if in.ManifestRepoCommitHash == "" { + // return nil, fmt.Errorf("Must have a commit to get the product summary for") + //} + //response, err := s.OverviewService.GetOverview(ctx, &api.GetOverviewRequest{GitRevision: in.ManifestRepoCommitHash}) + //if err != nil { + // return nil, fmt.Errorf("unable to get overview for %s: %v", in.ManifestRepoCommitHash, err) + //} + // + //var summaryFromEnv []api.ProductSummary + //if in.Environment != nil && *in.Environment != "" { + // for _, group := range response.EnvironmentGroups { + // for _, env := range group.Environments { + // if env.Name == *in.Environment { + // for _, app := range env.Applications { + // summaryFromEnv = append(summaryFromEnv, api.ProductSummary{ + // CommitId: "", + // DisplayVersion: "", + // Team: "", + // App: app.Name, + // Version: strconv.FormatUint(app.Version, 10), + // Environment: *in.Environment, + // }) + // } + // } + // } + // } + // if len(summaryFromEnv) == 0 { + // return &api.GetProductSummaryResponse{ + // ProductSummary: nil, + // }, nil + // } + // sort.Slice(summaryFromEnv, func(i, j int) bool { + // a := summaryFromEnv[i].App + // b := summaryFromEnv[j].App + // return a < b + // }) + //} else { + // for _, group := range response.EnvironmentGroups { + // if *in.EnvironmentGroup == group.EnvironmentGroupName { + // for _, env := range group.Environments { + // var singleEnvSummary []api.ProductSummary + // for _, app := range env.Applications { + // singleEnvSummary = append(singleEnvSummary, api.ProductSummary{ + // CommitId: "", + // DisplayVersion: "", + // Team: "", + // App: app.Name, + // Version: strconv.FormatUint(app.Version, 10), + // Environment: env.Name, + // }) + // } + // sort.Slice(singleEnvSummary, func(i, j int) bool { + // a := singleEnvSummary[i].App + // b := singleEnvSummary[j].App + // return a < b + // }) + // summaryFromEnv = append(summaryFromEnv, singleEnvSummary...) + // } + // } + // } + // if len(summaryFromEnv) == 0 { + // return nil, nil + // } + //} + // + //var productVersion []*api.ProductSummary + //for _, row := range summaryFromEnv { //nolint: govet + // for _, app := range response.Applications { + // if row.App == app.Name { + // for _, release := range app.Releases { + // if strconv.FormatUint(release.Version, 10) == row.Version { + // productVersion = append(productVersion, &api.ProductSummary{App: row.App, Version: row.Version, CommitId: release.SourceCommitId, DisplayVersion: release.DisplayVersion, Environment: row.Environment, Team: app.Team}) + // break + // } + // } + // } + // } + //} + //return &api.GetProductSummaryResponse{ProductSummary: productVersion}, nil + return &api.GetProductSummaryResponse{ + ProductSummary: nil, + }, nil } func (s *GitServer) GetCommitInfo(ctx context.Context, in *api.GetCommitInfoRequest) (*api.GetCommitInfoResponse, error) { diff --git a/services/cd-service/pkg/service/overview.go b/services/cd-service/pkg/service/overview.go index d6526c391..15413a794 100644 --- a/services/cd-service/pkg/service/overview.go +++ b/services/cd-service/pkg/service/overview.go @@ -21,16 +21,14 @@ import ( "database/sql" "errors" "fmt" + "github.com/freiheit-com/kuberpult/pkg/grpc" + "github.com/freiheit-com/kuberpult/pkg/logger" "github.com/freiheit-com/kuberpult/pkg/mapper" + "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" "os" "sync" "sync/atomic" - "time" - - "github.com/freiheit-com/kuberpult/pkg/grpc" - "github.com/freiheit-com/kuberpult/pkg/logger" - "go.uber.org/zap" git "github.com/libgit2/git2go/v34" "google.golang.org/grpc/codes" @@ -74,7 +72,7 @@ func (o *OverviewServiceServer) GetAppDetails( TeamLocks: make(map[string]*api.Locks), } if !o.DBHandler.ShouldUseOtherTables() { - panic("DB") + return nil, fmt.Errorf("the GetAppDetails endpoint is only available when the database is enabled") } resultApp, err := db.WithTransactionT(o.DBHandler, ctx, 2, true, func(ctx context.Context, transaction *sql.Tx) (*api.Application, error) { var rels []int64 @@ -131,6 +129,10 @@ func (o *OverviewServiceServer) GetAppDetails( if app == nil { return nil, fmt.Errorf("could not find app details of app: %s", appName) } + + if app.StateChange == db.AppStateChangeDelete { + return nil, fmt.Errorf("this app has already been deleted: %s", appName) + } result.Team = app.Metadata.Team } if response == nil { @@ -216,14 +218,13 @@ func (o *OverviewServiceServer) GetAppDetails( } response.Deployments[envName] = deployment } - result.UndeploySummary = 0 + result.UndeploySummary = deriveUndeploySummary(response.Deployments) return result, nil }) if err != nil { return nil, err } response.Application = resultApp - time.Sleep(1 * time.Second) return response, nil } @@ -300,8 +301,8 @@ func (o *OverviewServiceServer) getOverview( result := api.GetOverviewResponse{ Branch: "", ManifestRepoUrl: "", - Applications: map[string]*api.Application{}, EnvironmentGroups: []*api.EnvironmentGroup{}, + Applications: map[string]*api.Application{}, GitRevision: rev, LightweightApps: make([]*api.OverviewApplication, 0), } @@ -385,7 +386,7 @@ func (o *OverviewServiceServer) update(s *repository.State) { o.notify.Notify() } -func deriveUndeploySummary(appName string, deployments map[string]*api.Deployment) api.UndeploySummary { +func deriveUndeploySummary(deployments map[string]*api.Deployment) api.UndeploySummary { var allNormal = true var allUndeploy = true for _, currentDeployment := range deployments { diff --git a/services/frontend-service/src/ui/Pages/Environments/EnvironmentsPage.test.tsx b/services/frontend-service/src/ui/Pages/Environments/EnvironmentsPage.test.tsx index 640a47144..d9bab3fc6 100644 --- a/services/frontend-service/src/ui/Pages/Environments/EnvironmentsPage.test.tsx +++ b/services/frontend-service/src/ui/Pages/Environments/EnvironmentsPage.test.tsx @@ -28,6 +28,8 @@ const sampleEnvsA: Environment[] = [ applications: {}, distanceToUpstream: 0, priority: Priority.YOLO, + appLocks: {}, + teamLocks: {}, }, { name: 'moreTest', @@ -35,6 +37,8 @@ const sampleEnvsA: Environment[] = [ applications: {}, distanceToUpstream: 0, priority: Priority.YOLO, + appLocks: {}, + teamLocks: {}, }, ]; @@ -42,6 +46,8 @@ const sampleEnvsB: Environment[] = [ { name: 'fooB', locks: {}, + appLocks: {}, + teamLocks: {}, applications: {}, distanceToUpstream: 0, priority: Priority.YOLO, @@ -49,6 +55,8 @@ const sampleEnvsB: Environment[] = [ { name: 'moreTestB', locks: {}, + appLocks: {}, + teamLocks: {}, applications: {}, distanceToUpstream: 0, priority: Priority.YOLO, diff --git a/services/frontend-service/src/ui/Pages/Home/Home.tsx b/services/frontend-service/src/ui/Pages/Home/Home.tsx index 0f71000ff..c0443c626 100644 --- a/services/frontend-service/src/ui/Pages/Home/Home.tsx +++ b/services/frontend-service/src/ui/Pages/Home/Home.tsx @@ -26,14 +26,12 @@ export const Home: React.FC = () => { const teamsParam = (params.get('teams') || '').split(',').filter((val) => val !== ''); const searchedApp = useApplicationsFilteredAndSorted(teamsParam, hideWithoutWarnings(params), appNameParam); - const apps = Object.values(searchedApp); const element = useGlobalLoadingState(); if (element) { return element; } - return (
diff --git a/services/frontend-service/src/ui/Pages/Locks/LocksPage.test.tsx b/services/frontend-service/src/ui/Pages/Locks/LocksPage.test.tsx index c8ccd66bc..41f558952 100644 --- a/services/frontend-service/src/ui/Pages/Locks/LocksPage.test.tsx +++ b/services/frontend-service/src/ui/Pages/Locks/LocksPage.test.tsx @@ -89,6 +89,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 2, + appLocks: {}, + teamLocks: {}, }, ], sortOrder: 'oldestToNewest', @@ -107,6 +109,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 2, + appLocks: {}, + teamLocks: {}, }, ], sortOrder: 'newestToOldest', @@ -125,6 +129,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 2, + appLocks: {}, + teamLocks: {}, }, ], sortOrder: 'oldestToNewest', @@ -175,6 +181,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 0, + appLocks: {}, + teamLocks: {}, }, ], filter: 'integration', @@ -191,6 +199,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 0, + appLocks: {}, + teamLocks: {}, }, { name: 'development', @@ -201,6 +211,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 0, + appLocks: {}, + teamLocks: {}, }, ], filter: 'integration', @@ -217,6 +229,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 0, + appLocks: {}, + teamLocks: {}, }, { name: 'development', @@ -224,6 +238,8 @@ describe('Test env locks', () => { lockbar: { message: 'lockbar', lockId: 'ui-v2-321', createdAt: new Date(1995, 11, 15) }, locktest: { message: 'locktest', lockId: 'ui-v2-1337', createdAt: new Date(1995, 11, 17) }, }, + appLocks: {}, + teamLocks: {}, applications: {}, distanceToUpstream: 0, priority: 0, @@ -279,6 +295,8 @@ describe('Test env locks', () => { applications: {}, distanceToUpstream: 0, priority: 0, + appLocks: {}, + teamLocks: {}, }, ], id: 'ui-v2-1337', @@ -349,6 +367,8 @@ describe('Test app locks', () => { undeployVersion: true, }, }, + appLocks: {}, + teamLocks: {}, }, ], sortOrder: 'oldestToNewest', @@ -360,6 +380,8 @@ describe('Test app locks', () => { { name: 'integration', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -396,6 +418,8 @@ describe('Test app locks', () => { locktest: { message: 'locktest', lockId: 'ui-v2-1337', createdAt: new Date(1995, 11, 17) }, lockbar: { message: 'lockbar', lockId: 'ui-v2-321', createdAt: new Date(1995, 11, 15) }, }, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -478,6 +502,8 @@ describe('Test Team locks', () => { { name: 'integration', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -502,6 +528,8 @@ describe('Test Team locks', () => { { name: 'integration', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -538,6 +566,8 @@ describe('Test Team locks', () => { locktest: { message: 'locktest', lockId: 'ui-v2-1337', createdAt: new Date(1995, 11, 17) }, lockbar: { message: 'lockbar', lockId: 'ui-v2-321', createdAt: new Date(1995, 11, 15) }, }, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { diff --git a/services/frontend-service/src/ui/components/ApplicationLockDisplay/ApplicationLockDisplay.test.tsx b/services/frontend-service/src/ui/components/ApplicationLockDisplay/ApplicationLockDisplay.test.tsx index dce35b3d0..de4070454 100644 --- a/services/frontend-service/src/ui/components/ApplicationLockDisplay/ApplicationLockDisplay.test.tsx +++ b/services/frontend-service/src/ui/components/ApplicationLockDisplay/ApplicationLockDisplay.test.tsx @@ -50,6 +50,8 @@ describe('ApplicationLockDisplay', () => { locks: {}, distanceToUpstream: 0, priority: Priority.UPSTREAM, + appLocks: {}, + teamLocks: {}, }; const testEnv2: Environment = { name: 'staging', @@ -57,6 +59,8 @@ describe('ApplicationLockDisplay', () => { locks: {}, distanceToUpstream: 0, priority: Priority.OTHER, + appLocks: {}, + teamLocks: {}, }; const testEnvGroup1: EnvironmentGroup = { environmentGroupName: 'development', diff --git a/services/frontend-service/src/ui/components/EnvironmentCard/EnvironmentCard.test.tsx b/services/frontend-service/src/ui/components/EnvironmentCard/EnvironmentCard.test.tsx index c743c31a8..98391f654 100644 --- a/services/frontend-service/src/ui/components/EnvironmentCard/EnvironmentCard.test.tsx +++ b/services/frontend-service/src/ui/components/EnvironmentCard/EnvironmentCard.test.tsx @@ -67,6 +67,8 @@ describe('Test Environment Cards', () => { applications: {}, priority: Priority.PRE_PROD, config: {}, + appLocks: {}, + teamLocks: {}, }, ], }, @@ -90,6 +92,8 @@ describe('Test Environment Cards', () => { applications: {}, priority: Priority.UPSTREAM, config: {}, + appLocks: {}, + teamLocks: {}, }, { name: 'env2', @@ -98,6 +102,8 @@ describe('Test Environment Cards', () => { applications: {}, priority: Priority.UPSTREAM, config: {}, + appLocks: {}, + teamLocks: {}, }, ], }, diff --git a/services/frontend-service/src/ui/components/ProductVersion/ProductVersion.test.tsx b/services/frontend-service/src/ui/components/ProductVersion/ProductVersion.test.tsx index 4edc6e5d7..7a0e766be 100644 --- a/services/frontend-service/src/ui/components/ProductVersion/ProductVersion.test.tsx +++ b/services/frontend-service/src/ui/components/ProductVersion/ProductVersion.test.tsx @@ -65,6 +65,8 @@ const sampleEnvsA: Environment[] = [ applications: {}, distanceToUpstream: 0, priority: Priority.UPSTREAM, + appLocks: {}, + teamLocks: {}, }, ]; diff --git a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx index d1a4ef2c7..b298fa0e5 100644 --- a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx @@ -107,6 +107,8 @@ describe('Release Card', () => { foo: { name: 'foo', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -144,6 +146,8 @@ describe('Release Card', () => { undeployed: { name: 'undeployed', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -180,7 +184,8 @@ describe('Release Card', () => { environments: { other: { locks: {}, - + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, name: 'other', @@ -330,6 +335,8 @@ describe('Release Card Rollout Status', () => { }, }, locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: Priority.OTHER, }, @@ -347,6 +354,8 @@ describe('Release Card Rollout Status', () => { }, }, locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: Priority.OTHER, }, @@ -371,6 +380,8 @@ describe('Release Card Rollout Status', () => { }, }, locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: Priority.OTHER, }, diff --git a/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx b/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx index 22499c025..5ac562246 100644 --- a/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx @@ -75,6 +75,8 @@ describe('Release Card Mini', () => { { name: 'other', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { @@ -101,6 +103,8 @@ describe('Release Card Mini', () => { { name: 'other', locks: {}, + appLocks: {}, + teamLocks: {}, distanceToUpstream: 0, priority: 0, applications: { diff --git a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx index 8c8ec2882..1d3503534 100644 --- a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx @@ -83,6 +83,8 @@ describe('Release Dialog', () => { { name: 'prod', locks: {}, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', @@ -136,6 +138,8 @@ describe('Release Dialog', () => { { name: 'prod', locks: {}, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', @@ -191,6 +195,8 @@ describe('Release Dialog', () => { { name: 'prod', locks: { envLock: { message: 'envLock', lockId: 'ui-envlock' } }, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', @@ -244,6 +250,8 @@ describe('Release Dialog', () => { { name: 'prod', locks: { envLock: { message: 'envLock', lockId: 'ui-envlock' } }, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', @@ -284,6 +292,8 @@ describe('Release Dialog', () => { { name: 'prod', locks: { envLock: { message: 'envLock', lockId: 'ui-envlock' } }, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', @@ -301,6 +311,8 @@ describe('Release Dialog', () => { { name: 'dev', locks: { envLock: { message: 'envLock', lockId: 'ui-envlock' } }, + appLocks: {}, + teamLocks: {}, applications: { test1: { name: 'test1', diff --git a/services/frontend-service/src/ui/components/Releases/Releases.test.tsx b/services/frontend-service/src/ui/components/Releases/Releases.test.tsx index 99227c0a8..54d3dc1b4 100644 --- a/services/frontend-service/src/ui/components/Releases/Releases.test.tsx +++ b/services/frontend-service/src/ui/components/Releases/Releases.test.tsx @@ -86,6 +86,8 @@ describe('Release Dialog', () => { locks: {}, distanceToUpstream: 0, priority: Priority.UPSTREAM, + appLocks: {}, + teamLocks: {}, }; const testEnv2: Environment = { name: 'staging', @@ -93,6 +95,8 @@ describe('Release Dialog', () => { locks: {}, distanceToUpstream: 0, priority: Priority.PROD, + appLocks: {}, + teamLocks: {}, }; const testEnvGroup1: EnvironmentGroup = { environmentGroupName: 'development', diff --git a/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.test.tsx b/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.test.tsx index 50f9b83ff..5886d4b2b 100644 --- a/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.test.tsx +++ b/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.test.tsx @@ -33,6 +33,8 @@ describe('EnvironmentChip', () => { priority: Priority.PROD, locks: {}, applications: {}, + appLocks: {}, + teamLocks: {}, }; const envGroup: EnvironmentGroup = { distanceToUpstream: 0, @@ -155,6 +157,8 @@ const envGroupPairFromPrios = ( locks: {}, name: 'Test me', priority: envPrio, + appLocks: {}, + teamLocks: {}, }; const envGroup: EnvironmentGroup = { distanceToUpstream: -1, // shouldn't matter, if this value is used an error will be thrown @@ -237,6 +241,8 @@ const envFromPrio = (prio: Priority): Environment => ({ priority: prio, locks: {}, applications: {}, + appLocks: {}, + teamLocks: {}, }); const envGroupChipData: Array = [ diff --git a/services/rollout-service/pkg/argo/argo.go b/services/rollout-service/pkg/argo/argo.go index 8c432511c..3e0d13d81 100644 --- a/services/rollout-service/pkg/argo/argo.go +++ b/services/rollout-service/pkg/argo/argo.go @@ -380,11 +380,12 @@ func CreateArgoApplication(overview *api.GetOverviewResponse, app *api.Environme } func team(overview *api.GetOverviewResponse, app string) string { - a := overview.Applications[app] - if a == nil { - return "" + for _, curr := range overview.LightweightApps { + if curr.Name == app { + return curr.Team + } } - return a.Team + return "" } func getEnvironmentAndName(annotations map[string]string) (string, string) { diff --git a/services/rollout-service/pkg/versions/versions.go b/services/rollout-service/pkg/versions/versions.go index b0c812ff9..d87adc294 100644 --- a/services/rollout-service/pkg/versions/versions.go +++ b/services/rollout-service/pkg/versions/versions.go @@ -50,10 +50,11 @@ type VersionClient interface { } type versionClient struct { - overviewClient api.OverviewServiceClient - versionClient api.VersionServiceClient - cache *lru.Cache - ArgoProcessor argo.ArgoAppProcessor + overviewClient api.OverviewServiceClient + versionClient api.VersionServiceClient + cache *lru.Cache + AppDetailsCache *lru.Cache + ArgoProcessor argo.ArgoAppProcessor } type VersionInfo struct { @@ -99,28 +100,27 @@ func (v *versionClient) GetVersion(ctx context.Context, revision, environment, a // Tries getting the version from cache func (v *versionClient) tryGetVersion(ctx context.Context, revision, environment, application string) (*VersionInfo, error) { - var overview *api.GetOverviewResponse - entry, ok := v.cache.Get(revision) - if !ok { - return nil, ErrNotFound - } - overview = entry.(*api.GetOverviewResponse) - for _, group := range overview.GetEnvironmentGroups() { - for _, env := range group.GetEnvironments() { - if env.Name == environment { - app := env.Applications[application] - if app == nil { - return &ZeroVersion, nil - } - return &VersionInfo{ - Version: app.Version, - SourceCommitId: sourceCommitId(overview, app), - DeployedAt: deployedAt(app), - }, nil + + //Check if we have appDetails + appDetailsEntry, ok := v.AppDetailsCache.Get(application) + if ok { + entry := appDetailsEntry.(*api.GetAppDetailsResponse) + + if deployment, ok := entry.Deployments[environment]; ok { + dt, err := time.Parse(time.RFC3339, deployment.DeploymentMetaData.DeployTime) + if err != nil { + return nil, err } + return &VersionInfo{ + Version: deployment.Version, + SourceCommitId: sourceCommitIdFromAppDetails(entry, deployment.Version), + DeployedAt: dt, + }, nil + } else { + return &ZeroVersion, nil } } - return &ZeroVersion, nil + return nil, ErrNotFound } func deployedAt(app *api.Environment_Application) time.Time { @@ -139,20 +139,34 @@ func deployedAt(app *api.Environment_Application) time.Time { } func team(overview *api.GetOverviewResponse, app string) string { - a := overview.Applications[app] - if a == nil { - return "" + for _, curr := range overview.LightweightApps { + if curr.Name == app { + return curr.Team + } } - return a.Team + return "" } -func sourceCommitId(overview *api.GetOverviewResponse, app *api.Environment_Application) string { - a := overview.Applications[app.Name] +//func sourceCommitId(overview *api.GetOverviewResponse, app *api.Environment_Application) string { +// a := overview.Applications[app.Name] +// if a == nil { +// return "" +// } +// for _, rel := range a.Releases { +// if rel.Version == app.Version { +// return rel.SourceCommitId +// } +// } +// return "" +//} + +func sourceCommitIdFromAppDetails(details *api.GetAppDetailsResponse, version uint64) string { + a := details.Application if a == nil { return "" } for _, rel := range a.Releases { - if rel.Version == app.Version { + if rel.Version == version { return rel.SourceCommitId } } @@ -186,6 +200,7 @@ func (v *versionClient) ConsumeEvents(ctx context.Context, processor VersionEven client, err := v.overviewClient.StreamOverview(ctx, &api.GetOverviewRequest{ GitRevision: "", }) + if err != nil { return fmt.Errorf("overview.connect: %w", err) } @@ -210,19 +225,46 @@ func (v *versionClient) ConsumeEvents(ctx context.Context, processor VersionEven v.cache.Add(overview.GitRevision, overview) l.Info("overview.get") seen := make(map[key]uint64, len(versions)) + for _, envGroup := range overview.EnvironmentGroups { for _, env := range envGroup.Environments { - for _, app := range env.Applications { - dt := deployedAt(app) - sc := sourceCommitId(overview, app) + for _, app := range overview.LightweightApps { + appDetails, err := v.overviewClient.GetAppDetails(ctx, &api.GetAppDetailsRequest{ + AppName: app.Name, + }) + + if err != nil { + grpcErr := grpc.UnwrapGRPCStatus(err) + if grpcErr != nil { + if grpcErr.Code() == codes.Canceled { + return nil + } + } + return fmt.Errorf("overview.getAppDetails: %w", err) + } + + v.AppDetailsCache.Add(app.Name, appDetails) + + currentDeployment, ok := appDetails.Deployments[env.Name] + + if !ok { + continue //no deployment found, continue + } + dt, err := time.Parse(time.RFC3339, currentDeployment.DeploymentMetaData.DeployTime) + if err != nil { + return fmt.Errorf("error parsing deployment time: %w", err) + } + //dt := deployedAt(app) + //sc := sourceCommitId(overview, app) + sc := sourceCommitIdFromAppDetails(appDetails, appDetails.Deployments[env.Name].Version) tm := team(overview, app.Name) - l.Info("version.process", zap.String("application", app.Name), zap.String("environment", env.Name), zap.Uint64("version", app.Version), zap.Time("deployedAt", dt)) + l.Info("version.process", zap.String("application", app.Name), zap.String("environment", env.Name), zap.Uint64("version", currentDeployment.Version), zap.Time("deployedAt", dt.UTC())) k := key{env.Name, app.Name} - seen[k] = app.Version + seen[k] = currentDeployment.Version environmentGroups[k] = envGroup.EnvironmentGroupName teams[k] = tm - if versions[k] == app.Version { + if versions[k] == currentDeployment.Version { continue } @@ -233,7 +275,7 @@ func (v *versionClient) ConsumeEvents(ctx context.Context, processor VersionEven Team: tm, IsProduction: (envGroup.Priority == api.Priority_PROD || envGroup.Priority == api.Priority_CANARY), Version: &VersionInfo{ - Version: app.Version, + Version: currentDeployment.Version, SourceCommitId: sc, DeployedAt: dt, }, @@ -269,10 +311,11 @@ func (v *versionClient) ConsumeEvents(ctx context.Context, processor VersionEven func New(oclient api.OverviewServiceClient, vclient api.VersionServiceClient, appClient application.ApplicationServiceClient, manageArgoApplicationEnabled bool, manageArgoApplicationFilter []string) VersionClient { result := &versionClient{ - cache: lru.New(20), - overviewClient: oclient, - versionClient: vclient, - ArgoProcessor: argo.New(appClient, manageArgoApplicationEnabled, manageArgoApplicationFilter), + cache: lru.New(20), + AppDetailsCache: lru.New(500), + overviewClient: oclient, + versionClient: vclient, + ArgoProcessor: argo.New(appClient, manageArgoApplicationEnabled, manageArgoApplicationFilter), } return result }