Skip to content

Commit

Permalink
feat: Description for cluster and apps (#4154)
Browse files Browse the repository at this point in the history
* wip

* updated description provision in app update api used for labels

* added api for getting app meta info for helm app

* updated app meta info api for helm app chart used data support

* corrected api method

* fixed validation for cluster description update api

* added icon

* refactored query for better viewing

* enhanced env listing query for app overview to support new required data at FE

* review comments

* updated sql script no

* added code source info

* fixed ea wiring

* updated params in other-env api

* updated api for fetching other env data

* fixed import

* fix

* wip

* wip

* wip

* added pipeline deleted condition - fetch other env

* updated sql script no.
  • Loading branch information
kartik-579 committed Nov 3, 2023
1 parent e79a6a0 commit 0098c4f
Show file tree
Hide file tree
Showing 32 changed files with 313 additions and 75 deletions.
3 changes: 2 additions & 1 deletion api/appStore/AppStoreRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ func (router AppStoreRouterImpl) Init(configRouter *mux.Router) {
chartProviderSubRouter := configRouter.PathPrefix("/chart-provider").Subrouter()
router.chartProviderRouter.Init(chartProviderSubRouter)
// chart provider router ends

configRouter.Path("/overview").Queries("installedAppId", "{installedAppId}").
HandlerFunc(router.deployRestHandler.FetchAppOverview).Methods("GET")
configRouter.Path("/application/exists").
HandlerFunc(router.deployRestHandler.CheckAppExists).Methods("POST")
configRouter.Path("/group/install").
Expand Down
44 changes: 43 additions & 1 deletion api/appStore/InstalledAppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/devtron-labs/devtron/internal/constants"
"github.com/devtron-labs/devtron/internal/middleware"
util2 "github.com/devtron-labs/devtron/internal/util"
app2 "github.com/devtron-labs/devtron/pkg/app"
appStoreBean "github.com/devtron-labs/devtron/pkg/appStore/bean"
"github.com/devtron-labs/devtron/pkg/appStore/deployment/repository"
"github.com/devtron-labs/devtron/pkg/appStore/deployment/service"
Expand All @@ -53,6 +54,7 @@ import (
)

type InstalledAppRestHandler interface {
FetchAppOverview(w http.ResponseWriter, r *http.Request)
GetAllInstalledApp(w http.ResponseWriter, r *http.Request)
DeployBulk(w http.ResponseWriter, r *http.Request)
CheckAppExists(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -82,6 +84,7 @@ type InstalledAppRestHandlerImpl struct {
cdApplicationStatusUpdateHandler cron.CdApplicationStatusUpdateHandler
installedAppRepository repository.InstalledAppRepository
K8sApplicationService application2.K8sApplicationService
appCrudOperationService app2.AppCrudOperationService
}

func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService user.UserService,
Expand All @@ -91,7 +94,7 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u
argoUserService argo.ArgoUserService,
cdApplicationStatusUpdateHandler cron.CdApplicationStatusUpdateHandler,
installedAppRepository repository.InstalledAppRepository,
) *InstalledAppRestHandlerImpl {
appCrudOperationService app2.AppCrudOperationService) *InstalledAppRestHandlerImpl {
return &InstalledAppRestHandlerImpl{
Logger: Logger,
userAuthService: userAuthService,
Expand All @@ -108,8 +111,47 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u
argoUserService: argoUserService,
cdApplicationStatusUpdateHandler: cdApplicationStatusUpdateHandler,
installedAppRepository: installedAppRepository,
appCrudOperationService: appCrudOperationService,
}
}
func (handler *InstalledAppRestHandlerImpl) FetchAppOverview(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userAuthService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, nil, http.StatusUnauthorized)
return
}

vars := mux.Vars(r)
installedAppId, err := strconv.Atoi(vars["installedAppId"])
if err != nil {
handler.Logger.Errorw("request err, FetchAppOverview", "err", err, "installedAppId", installedAppId)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
token := r.Header.Get("token")
handler.Logger.Infow("request payload, FindAppOverview", "installedAppId", installedAppId)
installedApp, err := handler.installedAppService.CheckAppExistsByInstalledAppId(installedAppId)
appOverview, err := handler.appCrudOperationService.GetAppMetaInfo(installedApp.AppId, installedAppId, installedApp.EnvironmentId)
if err != nil {
handler.Logger.Errorw("service err, FetchAppOverview", "err", err, "appId", installedApp.AppId, "installedAppId", installedAppId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}

//rbac block starts from here
object, object2 := handler.enforcerUtil.GetHelmObject(appOverview.AppId, installedApp.EnvironmentId)
var ok bool
if object2 == "" {
ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object)
} else {
ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object2)
}
if !ok {
common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden)
return
}
common.WriteJsonResp(w, nil, appOverview, http.StatusOK)
}

func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userAuthService.GetLoggedInUser(r)
Expand Down
4 changes: 4 additions & 0 deletions api/bean/AppView.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,14 @@ type Environment struct {
Prod bool `json:"prod"`
ChartRefId int `json:"chartRefId"`
LastDeployed string `json:"lastDeployed"`
LastDeployedBy string `json:"lastDeployedBy"`
LastDeployedImage string `json:"lastDeployedImage"`
DeploymentAppDeleteRequest bool `json:"deploymentAppDeleteRequest"`
Description string `json:"description" validate:"max=40"`
IsVirtualEnvironment bool `json:"isVirtualEnvironment"`
ClusterId int `json:"clusterId"`
PipelineId int `json:"pipelineId"`
LatestCdWorkflowRunnerId int `json:"latestCdWorkflowRunnerId,omitempty"`
}

type InstanceDetail struct {
Expand Down
40 changes: 40 additions & 0 deletions api/cluster/ClusterRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type ClusterRestHandler interface {
FindById(w http.ResponseWriter, r *http.Request)
FindNoteByClusterId(w http.ResponseWriter, r *http.Request)
Update(w http.ResponseWriter, r *http.Request)
UpdateClusterDescription(w http.ResponseWriter, r *http.Request)
UpdateClusterNote(w http.ResponseWriter, r *http.Request)
FindAllForAutoComplete(w http.ResponseWriter, r *http.Request)
DeleteCluster(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -453,6 +454,45 @@ func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request
common.WriteJsonResp(w, err, bean, http.StatusOK)
}

func (impl ClusterRestHandlerImpl) UpdateClusterDescription(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")
decoder := json.NewDecoder(r.Body)
userId, err := impl.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
impl.logger.Errorw("service err, Update", "error", err, "userId", userId)
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
return
}
var bean cluster.ClusterBean
err = decoder.Decode(&bean)
if err != nil {
impl.logger.Errorw("request err, UpdateClusterDescription", "error", err, "payload", bean)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
impl.logger.Infow("request payload, UpdateClusterDescription", "payload", bean)
//TODO: add apt validation
clusterDescription, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(bean.Id)
if err != nil {
impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.Id)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
// RBAC enforcer applying
if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, strings.ToLower(clusterDescription.ClusterName)); !ok {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
// RBAC enforcer ends
err = impl.clusterService.UpdateClusterDescription(&bean, userId)
if err != nil {
impl.logger.Errorw("service err, UpdateClusterDescription", "error", err, "payload", bean)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
common.WriteJsonResp(w, err, "Cluster description updated successfully", http.StatusOK)
}

func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")
decoder := json.NewDecoder(r.Body)
Expand Down
6 changes: 5 additions & 1 deletion api/cluster/ClusterRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) {
Methods("PUT").
HandlerFunc(impl.clusterRestHandler.Update)

clusterRouter.Path("/description").
clusterRouter.Path("/note").
Methods("PUT").
HandlerFunc(impl.clusterRestHandler.UpdateClusterNote)

Expand All @@ -89,4 +89,8 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) {
clusterRouter.Path("/auth-list").
Methods("GET").
HandlerFunc(impl.clusterRestHandler.FindAllForClusterPermission)

clusterRouter.Path("/description").
Methods("PUT").
HandlerFunc(impl.clusterRestHandler.UpdateClusterDescription)
}
6 changes: 3 additions & 3 deletions api/restHandler/AppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type AppRestHandler interface {
UpdateApp(w http.ResponseWriter, r *http.Request)
UpdateProjectForApps(w http.ResponseWriter, r *http.Request)
GetAppListByTeamIds(w http.ResponseWriter, r *http.Request)
UpdateAppDescription(w http.ResponseWriter, r *http.Request)
UpdateAppNote(w http.ResponseWriter, r *http.Request)
}

type AppRestHandlerImpl struct {
Expand Down Expand Up @@ -123,7 +123,7 @@ func (handler AppRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *http.
}
//rback implementation ends here

res, err := handler.appService.GetAppMetaInfo(appId)
res, err := handler.appService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID)
if err != nil {
handler.logger.Errorw("service err, GetAppMetaInfo", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -343,7 +343,7 @@ func (handler AppRestHandlerImpl) GetAppListByTeamIds(w http.ResponseWriter, r *
common.WriteJsonResp(w, err, projectWiseApps, http.StatusOK)
}

func (handler AppRestHandlerImpl) UpdateAppDescription(w http.ResponseWriter, r *http.Request) {
func (handler AppRestHandlerImpl) UpdateAppNote(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")
decoder := json.NewDecoder(r.Body)
userId, err := handler.userAuthService.GetLoggedInUser(r)
Expand Down
6 changes: 3 additions & 3 deletions api/restHandler/CoreAppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R
func (handler CoreAppRestHandlerImpl) buildAppMetadata(appId int) (*appBean.AppMetadata, error, int) {
handler.logger.Debugw("Getting app detail - meta data", "appId", appId)

appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId)
appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID)
if err != nil {
handler.logger.Errorw("service err, GetAppMetaInfo in GetAppAllDetail", "err", err, "appId", appId)
return nil, err, http.StatusInternalServerError
Expand Down Expand Up @@ -2328,7 +2328,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflow(w http.ResponseWriter, r *h
token := r.Header.Get("token")

// get app metadata for appId
appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId)
appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID)
if err != nil {
handler.logger.Errorw("service err, GetAppMetaInfo in GetAppWorkflow", "appId", appId, "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -2379,7 +2379,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflowAndOverridesSample(w http.Re
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
app, err := handler.appCrudOperationService.GetAppMetaInfo(appId)
app, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID)
if err != nil {
handler.logger.Errorw("service err, GetAppMetaInfo in GetAppAllDetail", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
Expand Down
4 changes: 2 additions & 2 deletions api/router/AppRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (router AppRouterImpl) InitAppRouter(appRouter *mux.Router) {

appRouter.Path("/min").HandlerFunc(router.handler.GetAppListByTeamIds).Methods("GET")

appRouter.Path("/description").
appRouter.Path("/note").
Methods("PUT").
HandlerFunc(router.handler.UpdateAppDescription)
HandlerFunc(router.handler.UpdateAppNote)
}
2 changes: 2 additions & 0 deletions cmd/external-app/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ func InitializeApp() (*App, error) {
telemetry.NewPosthogClient,
delete2.NewDeleteServiceImpl,

pipelineConfig.NewMaterialRepositoryImpl,
wire.Bind(new(pipelineConfig.MaterialRepository), new(*pipelineConfig.MaterialRepositoryImpl)),
//appStatus
appStatus.NewAppStatusRepositoryImpl,
wire.Bind(new(appStatus.AppStatusRepository), new(*appStatus.AppStatusRepositoryImpl)),
Expand Down
3 changes: 2 additions & 1 deletion cmd/external-app/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 19 additions & 9 deletions internal/sql/repository/AppListingRepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,19 +632,29 @@ func (impl AppListingRepositoryImpl) makeAppStageStatus(stage int, stageName str
}

func (impl AppListingRepositoryImpl) FetchOtherEnvironment(appId int) ([]*bean.Environment, error) {
impl.Logger.Debug("reached at FetchOtherEnvironment:")

// other environment tab
//TODO : create new optimised query and need to use explain analyse for both queries
var otherEnvironments []*bean.Environment
query := "select OE.*,B.status as app_status " +
"FROM " +
"(SELECT p.environment_id,env.environment_name,env.description, p.last_deployed, env_app_m.app_metrics, env.default as prod, env_app_m.infra_metrics, p.deployment_app_delete_request from ( SELECT pl.id,pl.app_id,pl.environment_id,pl.deleted, pl.deployment_app_delete_request,MAX(pco.created_on) as last_deployed from pipeline pl LEFT JOIN pipeline_config_override pco on pco.pipeline_id = pl.id WHERE pl.app_id = ? and pl.deleted = FALSE GROUP BY pl.id) p INNER JOIN environment env on env.id=p.environment_id LEFT JOIN env_level_app_metrics env_app_m on env.id=env_app_m.env_id and p.app_id = env_app_m.app_id where p.app_id=? and p.deleted = FALSE AND env.active = TRUE GROUP BY 1,2,3,4,5,6,7,8) OE " +
" LEFT JOIN app_status B ON OE.environment_id = B.env_id AND B.app_id = ? ;"
impl.Logger.Debugw("other env query:", query)
_, err := impl.dbConnection.Query(&otherEnvironments, query, appId, appId, appId)
query := `select pcwr.pipeline_id, pcwr.last_deployed, pcwr.latest_cd_workflow_runner_id, pcwr.environment_id, pcwr.deployment_app_delete_request,
e.cluster_id, e.environment_name, e.default as prod, e.description, ca.image as last_deployed_image,
u.email_id as last_deployed_by, elam.app_metrics, elam.infra_metrics, ap.status as app_status
from (select *
from (select p.id as pipeline_id, p.app_id, cwr.started_on as last_deployed, cwr.triggered_by, cwr.id as latest_cd_workflow_runner_id,
cw.ci_artifact_id, p.environment_id, p.deployment_app_delete_request,
row_number() over (partition by p.id order by cwr.started_on desc) as max_started_on_rank
from (select * from pipeline where app_id = ? and deleted=?) as p
left join cd_workflow cw on cw.pipeline_id = p.id
left join cd_workflow_runner cwr on cwr.cd_workflow_id = cw.id
where cwr.workflow_type = ? or cwr.workflow_type is null) pcwrraw
where max_started_on_rank = 1) pcwr
INNER JOIN environment e on e.id = pcwr.environment_id
LEFT JOIN ci_artifact ca on ca.id = pcwr.ci_artifact_id
LEFT JOIN users u on u.id = pcwr.triggered_by
LEFT JOIN env_level_app_metrics elam on pcwr.environment_id = elam.env_id and pcwr.app_id = elam.app_id
LEFT JOIN app_status ap ON pcwr.environment_id = ap.env_id and pcwr.app_id=ap.app_id;`
_, err := impl.dbConnection.Query(&otherEnvironments, query, appId, false, "DEPLOY")
if err != nil {
impl.Logger.Error("error in fetching other environment", "error", err)
return nil, err
}
return otherEnvironments, nil
}
Expand Down
9 changes: 9 additions & 0 deletions internal/sql/repository/app/AppRepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/devtron-labs/devtron/pkg/team"
"github.com/go-pg/pg"
"go.uber.org/zap"
"time"
)

type App struct {
Expand All @@ -45,6 +46,7 @@ type AppRepository interface {
SaveWithTxn(pipelineGroup *App, tx *pg.Tx) error
Update(app *App) error
UpdateWithTxn(app *App, tx *pg.Tx) error
SetDescription(id int, description string, userId int32) error
FindActiveByName(appName string) (pipelineGroup *App, err error)
FindJobByDisplayName(appName string) (pipelineGroup *App, err error)
FindActiveListByName(appName string) ([]*App, error)
Expand Down Expand Up @@ -116,6 +118,13 @@ func (repo AppRepositoryImpl) UpdateWithTxn(app *App, tx *pg.Tx) error {
return err
}

func (repo AppRepositoryImpl) SetDescription(id int, description string, userId int32) error {
_, err := repo.dbConnection.Model((*App)(nil)).
Set("description = ?", description).Set("updated_by = ?", userId).Set("updated_on = ?", time.Now()).
Where("id = ?", id).Update()
return err
}

func (repo AppRepositoryImpl) FindActiveByName(appName string) (*App, error) {
pipelineGroup := &App{}
err := repo.dbConnection.
Expand Down
2 changes: 1 addition & 1 deletion internal/util/ArgoUtil/ArgoClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (session *ArgoSession) DoRequest(clientRequest *ClientRequest) (resBody []b

func NewArgoSession(config *ArgoConfig, logger *zap.SugaredLogger) (session *ArgoSession, err error) {
/*location := "/api/v1/session"
baseUrl, err := url.Parse(config.Url)
baseUrl, err := url.Parse(config.RedirectionUrl)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/util/GitService.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (

const (
GIT_WORKING_DIR = "/tmp/gitops/"
GetRepoUrlStage = "Get Repo Url"
GetRepoUrlStage = "Get Repo RedirectionUrl"
CreateRepoStage = "Create Repo"
CloneHttpStage = "Clone Http"
CreateReadmeStage = "Create Readme"
Expand Down

0 comments on commit 0098c4f

Please sign in to comment.