From 20b06c890806d500325dbcbc68f341e5a3f891a6 Mon Sep 17 00:00:00 2001 From: Vikram Singh Date: Tue, 6 Jul 2021 16:06:18 +0530 Subject: [PATCH 1/3] deployed chart listing added filters --- .../AppStoreDeploymentRestHandler.go | 43 +++++++++++++++++- .../AppStoreApplicationVersionRepository.go | 2 + .../appstore/AppStoreDeploymentRepository.go | 45 ++++++++++++++----- pkg/appstore/AppStoreDeploymentService.go | 6 +-- 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/api/restHandler/AppStoreDeploymentRestHandler.go b/api/restHandler/AppStoreDeploymentRestHandler.go index d588044766..ffb59d10d1 100644 --- a/api/restHandler/AppStoreDeploymentRestHandler.go +++ b/api/restHandler/AppStoreDeploymentRestHandler.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + appstore2 "github.com/devtron-labs/devtron/internal/sql/repository/appstore" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/appstore" @@ -233,9 +234,10 @@ func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWri writeJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } + v := r.URL.Query() token := r.Header.Get("token") var envs []int - envsQueryParam := r.URL.Query().Get("envs") + envsQueryParam := v.Get("envs") if envsQueryParam != "" { envsStr := strings.Split(envsQueryParam, ",") for _, t := range envsStr { @@ -248,8 +250,45 @@ func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWri envs = append(envs, env) } } + deprecated := false + deprecatedStr := v.Get("includeDeprecated") + if len(deprecatedStr) > 0 { + deprecated, err = strconv.ParseBool(deprecatedStr) + if err != nil { + deprecated = false + } + } + + var chartRepoIds []int + chartRepoIdsStr := v.Get("chartRepoId") + if len(chartRepoIdsStr) > 0 { + chartRepoIdStrArr := strings.Split(chartRepoIdsStr, ",") + for _, chartRepoIdStr := range chartRepoIdStrArr { + chartRepoId, err := strconv.Atoi(chartRepoIdStr) + if err == nil { + chartRepoIds = append(chartRepoIds, chartRepoId) + } + } + } + appStoreName := v.Get("appStoreName") + appName := v.Get("appName") + offset := 0 + offsetStr := v.Get("offset") + if len(offsetStr) > 0 { + offset, _ = strconv.Atoi(offsetStr) + } + size := 0 + sizeStr := v.Get("size") + if len(sizeStr) > 0 { + size, _ = strconv.Atoi(sizeStr) + } + filter := &appstore2.AppStoreFilter{IncludeDeprecated: deprecated, ChartRepoId: chartRepoIds, AppStoreName: appStoreName, EnvIds: envs, AppName: appName} + if size > 0 { + filter.Size = size + filter.Offset = offset + } handler.Logger.Infow("request payload, GetAllInstalledApp", "envsQueryParam", envsQueryParam) - res, err := handler.installedAppService.GetAll(envs) + res, err := handler.installedAppService.GetAll(filter) if err != nil { handler.Logger.Errorw("service err, GetAllInstalledApp", "err", err, "envsQueryParam", envsQueryParam) writeJsonResp(w, err, nil, http.StatusInternalServerError) diff --git a/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go b/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go index cc31025895..ac109c9bf7 100644 --- a/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go +++ b/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go @@ -87,9 +87,11 @@ type AppStoreWithVersion struct { type AppStoreFilter struct { ChartRepoId []int `json:"chartRepoId"` AppStoreName string `json:"appStoreName"` + AppName string `json:"appName"` IncludeDeprecated bool `json:"includeDeprecated"` Offset int `json:"offset"` Size int `json:"size"` + EnvIds []int `json:"envIds"` } type ChartRepoSearch struct { diff --git a/internal/sql/repository/appstore/AppStoreDeploymentRepository.go b/internal/sql/repository/appstore/AppStoreDeploymentRepository.go index 5de5ec3681..4e84bbb68b 100644 --- a/internal/sql/repository/appstore/AppStoreDeploymentRepository.go +++ b/internal/sql/repository/appstore/AppStoreDeploymentRepository.go @@ -35,7 +35,7 @@ type InstalledAppRepository interface { GetInstalledApp(id int) (*InstalledApps, error) GetInstalledAppVersion(id int) (*InstalledAppVersions, error) GetInstalledAppVersionAny(id int) (*InstalledAppVersions, error) - GetAllInstalledApps(envIds []int) ([]InstalledAppsWithChartDetails, error) + GetAllInstalledApps(filter *AppStoreFilter) ([]InstalledAppsWithChartDetails, error) GetAllIntalledAppsByAppStoreId(appStoreId int) ([]InstalledAppAndEnvDetails, error) GetInstalledAppVersionByInstalledAppIdAndEnvId(installedAppId int, envId int) (*InstalledAppVersions, error) GetInstalledAppVersionByAppStoreId(appStoreId int) ([]*InstalledAppVersions, error) @@ -217,17 +217,42 @@ func (impl InstalledAppRepositoryImpl) GetInstalledAppVersionAny(id int) (*Insta return model, err } -func (impl InstalledAppRepositoryImpl) GetAllInstalledApps(envIds []int) ([]InstalledAppsWithChartDetails, error) { +func (impl InstalledAppRepositoryImpl) GetAllInstalledApps(filter *AppStoreFilter) ([]InstalledAppsWithChartDetails, error) { var installedAppsWithChartDetails []InstalledAppsWithChartDetails - var queryTemp string - if len(envIds) > 0 { - queryTemp = "select iav.updated_on, iav.id as installed_app_version_id, ch.name as chart_repo_name, env.environment_name, env.id as environment_id, a.app_name, asav.icon, asav.name as app_store_application_name, asav.id as app_store_application_version_id, ia.id " + - ", asav.deprecated from installed_app_versions iav inner join installed_apps ia on iav.installed_app_id = ia.id inner join app a on a.id = ia.app_id inner join environment env on ia.environment_id = env.id inner join app_store_application_version asav on iav.app_store_application_version_id = asav.id inner join app_store aps on aps.id = asav.app_store_id inner join chart_repo ch on ch.id = aps.chart_repo_id where ia.active=true and env.id in (" + sqlIntSeq(envIds) + ") and iav.active=true" - } else { - queryTemp = "select iav.updated_on, iav.id as installed_app_version_id, ch.name as chart_repo_name, env.environment_name, env.id as environment_id, a.app_name, asav.icon, asav.name as app_store_application_name, asav.id as app_store_application_version_id, ia.id " + - ", asav.deprecated from installed_app_versions iav inner join installed_apps ia on iav.installed_app_id = ia.id inner join app a on a.id = ia.app_id inner join environment env on ia.environment_id = env.id inner join app_store_application_version asav on iav.app_store_application_version_id = asav.id inner join app_store aps on aps.id = asav.app_store_id inner join chart_repo ch on ch.id = aps.chart_repo_id where ia.active=true and iav.active=true" + var query string + query = "select iav.updated_on, iav.id as installed_app_version_id, ch.name as chart_repo_name," + query = query + " env.environment_name, env.id as environment_id, a.app_name, asav.icon, asav.name as app_store_application_name," + query = query + " asav.id as app_store_application_version_id, ia.id , asav.deprecated" + query = query + " from installed_app_versions iav" + query = query + " inner join installed_apps ia on iav.installed_app_id = ia.id" + query = query + " inner join app a on a.id = ia.app_id" + query = query + " inner join environment env on ia.environment_id = env.id" + query = query + " inner join app_store_application_version asav on iav.app_store_application_version_id = asav.id" + query = query + " inner join app_store aps on aps.id = asav.app_store_id" + query = query + " inner join chart_repo ch on ch.id = aps.chart_repo_id" + query = query + " where ia.active = true and iav.active = true" + if !filter.IncludeDeprecated { + query = query + " AND asav.deprecated = FALSE" + } + if len(filter.AppStoreName) > 0 { + query = query + " AND aps.name LIKE '%" + filter.AppStoreName + "%'" + } + if len(filter.AppName) > 0 { + query = query + " AND a.app_name LIKE '%" + filter.AppName + "%'" + } + if len(filter.ChartRepoId) > 0 { + query = query + " AND ch.id IN (" + sqlIntSeq(filter.ChartRepoId) + ")" + } + if len(filter.EnvIds) > 0 { + query = query + " AND env.id IN (" + sqlIntSeq(filter.EnvIds) + ")" + } + query = query + " ORDER BY aps.name ASC" + if filter.Size > 0 { + query = query + " OFFSET " + strconv.Itoa(filter.Offset) + " LIMIT " + strconv.Itoa(filter.Size) + "" } - _, err := impl.dbConnection.Query(&installedAppsWithChartDetails, queryTemp) + query = query + ";" + var err error + _, err = impl.dbConnection.Query(&installedAppsWithChartDetails, query) if err != nil { return nil, err } diff --git a/pkg/appstore/AppStoreDeploymentService.go b/pkg/appstore/AppStoreDeploymentService.go index 2a4f3c8c5c..c06c2b0f54 100644 --- a/pkg/appstore/AppStoreDeploymentService.go +++ b/pkg/appstore/AppStoreDeploymentService.go @@ -69,7 +69,7 @@ type InstalledAppService interface { UpdateInstalledApp(ctx context.Context, installAppVersionRequest *InstallAppVersionDTO) (*InstallAppVersionDTO, error) GetInstalledApp(id int) (*InstallAppVersionDTO, error) GetInstalledAppVersion(id int) (*InstallAppVersionDTO, error) - GetAll(environments []int) ([]InstalledAppsResponse, error) + GetAll(filter *appstore.AppStoreFilter) ([]InstalledAppsResponse, error) GetAllInstalledAppsByAppStoreId(w http.ResponseWriter, r *http.Request, token string, appStoreId int) ([]InstalledAppsResponse, error) DeleteInstalledApp(ctx context.Context, installAppVersionRequest *InstallAppVersionDTO) (*InstallAppVersionDTO, error) @@ -460,8 +460,8 @@ func (impl InstalledAppServiceImpl) GetInstalledAppVersion(id int) (*InstallAppV return installAppVersion, err } -func (impl InstalledAppServiceImpl) GetAll(environments []int) ([]InstalledAppsResponse, error) { - installedApps, err := impl.installedAppRepository.GetAllInstalledApps(environments) +func (impl InstalledAppServiceImpl) GetAll(filter *appstore.AppStoreFilter) ([]InstalledAppsResponse, error) { + installedApps, err := impl.installedAppRepository.GetAllInstalledApps(filter) if err != nil && !util.IsErrNoRows(err) { impl.logger.Error(err) return nil, err From af1bb4276b8e617555c9ac1e447f0cab0de030f4 Mon Sep 17 00:00:00 2001 From: Vikram Singh Date: Mon, 19 Jul 2021 20:34:39 +0530 Subject: [PATCH 2/3] deployed chart listing filter change for deprecated filter --- api/restHandler/AppStoreDeploymentRestHandler.go | 10 +++++----- .../appstore/AppStoreApplicationVersionRepository.go | 1 + .../appstore/AppStoreDeploymentRepository.go | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/api/restHandler/AppStoreDeploymentRestHandler.go b/api/restHandler/AppStoreDeploymentRestHandler.go index ffb59d10d1..46c452fe05 100644 --- a/api/restHandler/AppStoreDeploymentRestHandler.go +++ b/api/restHandler/AppStoreDeploymentRestHandler.go @@ -250,12 +250,12 @@ func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWri envs = append(envs, env) } } - deprecated := false - deprecatedStr := v.Get("includeDeprecated") + onlyDeprecated := false + deprecatedStr := v.Get("onlyDeprecated") if len(deprecatedStr) > 0 { - deprecated, err = strconv.ParseBool(deprecatedStr) + onlyDeprecated, err = strconv.ParseBool(deprecatedStr) if err != nil { - deprecated = false + onlyDeprecated = false } } @@ -282,7 +282,7 @@ func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWri if len(sizeStr) > 0 { size, _ = strconv.Atoi(sizeStr) } - filter := &appstore2.AppStoreFilter{IncludeDeprecated: deprecated, ChartRepoId: chartRepoIds, AppStoreName: appStoreName, EnvIds: envs, AppName: appName} + filter := &appstore2.AppStoreFilter{OnlyDeprecated: onlyDeprecated, ChartRepoId: chartRepoIds, AppStoreName: appStoreName, EnvIds: envs, AppName: appName} if size > 0 { filter.Size = size filter.Offset = offset diff --git a/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go b/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go index ac109c9bf7..5ee6260696 100644 --- a/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go +++ b/internal/sql/repository/appstore/AppStoreApplicationVersionRepository.go @@ -92,6 +92,7 @@ type AppStoreFilter struct { Offset int `json:"offset"` Size int `json:"size"` EnvIds []int `json:"envIds"` + OnlyDeprecated bool `json:"onlyDeprecated"` } type ChartRepoSearch struct { diff --git a/internal/sql/repository/appstore/AppStoreDeploymentRepository.go b/internal/sql/repository/appstore/AppStoreDeploymentRepository.go index 4e84bbb68b..caef6f0bd2 100644 --- a/internal/sql/repository/appstore/AppStoreDeploymentRepository.go +++ b/internal/sql/repository/appstore/AppStoreDeploymentRepository.go @@ -231,8 +231,8 @@ func (impl InstalledAppRepositoryImpl) GetAllInstalledApps(filter *AppStoreFilte query = query + " inner join app_store aps on aps.id = asav.app_store_id" query = query + " inner join chart_repo ch on ch.id = aps.chart_repo_id" query = query + " where ia.active = true and iav.active = true" - if !filter.IncludeDeprecated { - query = query + " AND asav.deprecated = FALSE" + if filter.OnlyDeprecated { + query = query + " AND asav.deprecated = TRUE" } if len(filter.AppStoreName) > 0 { query = query + " AND aps.name LIKE '%" + filter.AppStoreName + "%'" From 414ad5751bd02f50fc69c259ef4ba987ec66b80a Mon Sep 17 00:00:00 2001 From: Vikram Singh Date: Tue, 20 Jul 2021 16:31:32 +0530 Subject: [PATCH 3/3] api spec added deployed chart listing --- specs/charts.yaml | 175 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 specs/charts.yaml diff --git a/specs/charts.yaml b/specs/charts.yaml new file mode 100644 index 0000000000..78f67691f6 --- /dev/null +++ b/specs/charts.yaml @@ -0,0 +1,175 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Devtron Labs +paths: + /orchestrator/app-store/installed-app: + get: + description: deployed chart listing, with search filters + parameters: + - name: envs + in: query + description: environment ids + required: false + schema: + type: array + items: + type: string + - name: chartRepoId + in: query + description: chart repo ids + required: false + schema: + type: array + items: + type: string + - name: appStoreName + in: query + description: chart name + required: false + schema: + type: string + - name: appName + in: query + description: chart name as app name for devtron + required: false + schema: + type: string + - name: onlyDeprecated + in: query + description: show only deprecated or all + required: false + schema: + type: boolean + - name: offset + in: query + description: offset for result set + required: false + schema: + type: integer + - name: size + in: query + description: total request size. + required: false + schema: + type: integer + responses: + '200': + description: deployed chart listing, with search filters + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: array + description: deployed chart listing, with search filters + items: + $ref: '#/components/schemas/ChartInfo' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +# components mentioned below +components: + schemas: + ChartInfo: + type: object + required: + - installedAppId + - environmentId + - installedAppVersionId + - appStoreApplicationVersionId + - appStoreApplicationName + - status + - appName + - environmentName + - deployedAt + - deployedBy + - readme + - deprecated + properties: + installedAppId: + type: integer + description: installed chart id + environmentId: + type: integer + description: environment id + installedAppVersionId: + type: integer + description: installed chart version id + appStoreApplicationVersionId: + type: integer + description: team/project id + appStoreApplicationName: + type: string + description: chart name externally + chartName: + type: string + description: chart repo name + icon: + type: string + description: image + status: + type: string + description: status of deployed chart + appName: + type: string + description: chart name is app name for devtron + environmentName: + type: string + description: env name + deployedAt: + type: string + description: deployement time + deployedBy: + type: string + description: user + readme: + type: string + description: readme + deprecated: + type: boolean + description: is deprecated or not + + ErrorResponse: + required: + - code + - status + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + errors: + type: array + description: errors + items: + $ref: '#/components/schemas/Error' + + Error: + required: + - code + - status + properties: + code: + type: integer + format: int32 + description: Error internal code + internalMessage: + type: string + description: Error internal message + userMessage: + type: string + description: Error user message \ No newline at end of file