diff --git a/api/apiToken/ApiTokenRestHandler.go b/api/apiToken/ApiTokenRestHandler.go index 0ff8901f1a..1663493b6c 100644 --- a/api/apiToken/ApiTokenRestHandler.go +++ b/api/apiToken/ApiTokenRestHandler.go @@ -62,7 +62,7 @@ func NewApiTokenRestHandlerImpl(logger *zap.SugaredLogger, apiTokenService apiTo func (impl ApiTokenRestHandlerImpl) GetAllApiTokens(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -86,7 +86,7 @@ func (impl ApiTokenRestHandlerImpl) GetAllApiTokens(w http.ResponseWriter, r *ht func (impl ApiTokenRestHandlerImpl) CreateApiToken(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -132,7 +132,7 @@ func (impl ApiTokenRestHandlerImpl) CreateApiToken(w http.ResponseWriter, r *htt func (impl ApiTokenRestHandlerImpl) UpdateApiToken(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -182,7 +182,7 @@ func (impl ApiTokenRestHandlerImpl) UpdateApiToken(w http.ResponseWriter, r *htt func (impl ApiTokenRestHandlerImpl) DeleteApiToken(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -221,7 +221,7 @@ func (handler ApiTokenRestHandlerImpl) checkManagerAuth(resource, token, object func (impl ApiTokenRestHandlerImpl) GetAllApiTokensForWebhook(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/appStore/InstalledAppRestHandler.go b/api/appStore/InstalledAppRestHandler.go index 3c39da689e..73a8620117 100644 --- a/api/appStore/InstalledAppRestHandler.go +++ b/api/appStore/InstalledAppRestHandler.go @@ -177,7 +177,7 @@ func (handler *InstalledAppRestHandlerImpl) FetchAppOverview(w http.ResponseWrit func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } v := r.URL.Query() @@ -343,7 +343,7 @@ func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWri func (handler *InstalledAppRestHandlerImpl) DeployBulk(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -512,7 +512,7 @@ func (handler *InstalledAppRestHandlerImpl) getChartGroupInstallMetadata(req *ch func (handler *InstalledAppRestHandlerImpl) CheckAppExists(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -538,7 +538,7 @@ func (impl *InstalledAppRestHandlerImpl) DefaultComponentInstallation(w http.Res userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.Logger.Errorw("service err, DefaultComponentInstallation", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -885,7 +885,7 @@ func (handler *InstalledAppRestHandlerImpl) fetchResourceTreeWithHibernateForACD func (handler *InstalledAppRestHandlerImpl) MigrateDeploymentTypeForChartStore(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -929,7 +929,7 @@ func (handler *InstalledAppRestHandlerImpl) MigrateDeploymentTypeForChartStore(w func (handler *InstalledAppRestHandlerImpl) TriggerChartStoreAppAfterMigration(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/appStore/chartGroup/ChartGroupRestHandler.go b/api/appStore/chartGroup/ChartGroupRestHandler.go index 199ce00bec..d8c35a16e6 100644 --- a/api/appStore/chartGroup/ChartGroupRestHandler.go +++ b/api/appStore/chartGroup/ChartGroupRestHandler.go @@ -26,7 +26,6 @@ import ( "github.com/devtron-labs/devtron/pkg/appStore/chartGroup" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/auth/user" - "github.com/gorilla/mux" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" ) @@ -67,7 +66,7 @@ type ChartGroupRestHandler interface { func (impl *ChartGroupRestHandlerImpl) CreateChartGroup(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -112,7 +111,7 @@ func (impl *ChartGroupRestHandlerImpl) CreateChartGroup(w http.ResponseWriter, r func (impl *ChartGroupRestHandlerImpl) UpdateChartGroup(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -153,7 +152,7 @@ func (impl *ChartGroupRestHandlerImpl) UpdateChartGroup(w http.ResponseWriter, r func (impl *ChartGroupRestHandlerImpl) SaveChartGroupEntries(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -187,14 +186,14 @@ func (impl *ChartGroupRestHandlerImpl) SaveChartGroupEntries(w http.ResponseWrit func (impl *ChartGroupRestHandlerImpl) GetChartGroupWithChartMetaData(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - chartGroupId, err := strconv.Atoi(vars["chartGroupId"]) + + // Use enhanced parameter parsing with context + chartGroupId, err := common.ExtractIntPathParamWithContext(w, r, "chartGroupId", "chart group") if err != nil { - impl.Logger.Errorw("request err, GetChartGroupWithChartMetaData", "err", err, "chartGroupId", chartGroupId) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } @@ -219,14 +218,14 @@ func (impl *ChartGroupRestHandlerImpl) GetChartGroupWithChartMetaData(w http.Res func (impl *ChartGroupRestHandlerImpl) GetChartGroupInstallationDetail(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - chartGroupId, err := strconv.Atoi(vars["chartGroupId"]) + + // Use enhanced parameter parsing with context + chartGroupId, err := common.ExtractIntPathParamWithContext(w, r, "chartGroupId", "chart group") if err != nil { - impl.Logger.Errorw("request err, GetChartGroupInstallationDetail", "err", err, "chartGroupId", chartGroupId) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } @@ -251,7 +250,7 @@ func (impl *ChartGroupRestHandlerImpl) GetChartGroupInstallationDetail(w http.Re func (impl *ChartGroupRestHandlerImpl) GetChartGroupList(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -286,7 +285,7 @@ func (impl *ChartGroupRestHandlerImpl) GetChartGroupList(w http.ResponseWriter, func (impl *ChartGroupRestHandlerImpl) GetChartGroupListMin(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -321,7 +320,7 @@ func (impl *ChartGroupRestHandlerImpl) GetChartGroupListMin(w http.ResponseWrite func (impl *ChartGroupRestHandlerImpl) DeleteChartGroup(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/appStore/deployment/AppStoreDeploymentRestHandler.go b/api/appStore/deployment/AppStoreDeploymentRestHandler.go index 9aa316460c..119c74e157 100644 --- a/api/appStore/deployment/AppStoreDeploymentRestHandler.go +++ b/api/appStore/deployment/AppStoreDeploymentRestHandler.go @@ -93,7 +93,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) InstallApp(w http.ResponseWrite decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request appStoreBean.InstallAppVersionDTO @@ -179,7 +179,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) InstallApp(w http.ResponseWrite func (handler AppStoreDeploymentRestHandlerImpl) GetInstalledAppsByAppStoreId(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -232,7 +232,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) DeleteInstalledApp(w http.Respo userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -364,7 +364,7 @@ func (handler *AppStoreDeploymentRestHandlerImpl) LinkHelmApplicationToChartStor userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -395,7 +395,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) UpdateInstalledApp(w http.Respo decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request appStoreBean.InstallAppVersionDTO @@ -474,7 +474,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) UpdateInstalledApp(w http.Respo func (handler AppStoreDeploymentRestHandlerImpl) GetInstalledAppVersion(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -520,7 +520,7 @@ func (handler AppStoreDeploymentRestHandlerImpl) GetInstalledAppVersion(w http.R func (handler AppStoreDeploymentRestHandlerImpl) UpdateProjectHelmApp(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/appStore/deployment/CommonDeploymentRestHandler.go b/api/appStore/deployment/CommonDeploymentRestHandler.go index e3ee4fba45..019fcaa51d 100644 --- a/api/appStore/deployment/CommonDeploymentRestHandler.go +++ b/api/appStore/deployment/CommonDeploymentRestHandler.go @@ -134,7 +134,7 @@ func (handler *CommonDeploymentRestHandlerImpl) getAppOfferingMode(installedAppI func (handler *CommonDeploymentRestHandlerImpl) GetDeploymentHistory(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } v := r.URL.Query() @@ -181,7 +181,7 @@ func (handler *CommonDeploymentRestHandlerImpl) GetDeploymentHistory(w http.Resp func (handler *CommonDeploymentRestHandlerImpl) GetDeploymentHistoryValues(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -251,7 +251,7 @@ func (handler *CommonDeploymentRestHandlerImpl) GetDeploymentHistoryValues(w htt func (handler *CommonDeploymentRestHandlerImpl) RollbackApplication(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } request := &openapi2.RollbackReleaseRequest{} diff --git a/api/appStore/values/AppStoreValuesRestHandler.go b/api/appStore/values/AppStoreValuesRestHandler.go index f5894612a0..0c86ce7263 100644 --- a/api/appStore/values/AppStoreValuesRestHandler.go +++ b/api/appStore/values/AppStoreValuesRestHandler.go @@ -59,7 +59,7 @@ func (handler AppStoreValuesRestHandlerImpl) CreateAppStoreVersionValues(w http. decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request appStoreBean.AppStoreVersionValuesDTO @@ -84,7 +84,7 @@ func (handler AppStoreValuesRestHandlerImpl) UpdateAppStoreVersionValues(w http. decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request appStoreBean.AppStoreVersionValuesDTO @@ -108,7 +108,7 @@ func (handler AppStoreValuesRestHandlerImpl) UpdateAppStoreVersionValues(w http. func (handler AppStoreValuesRestHandlerImpl) FindValuesById(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -161,7 +161,7 @@ func (handler AppStoreValuesRestHandlerImpl) DeleteAppStoreVersionValues(w http. func (handler AppStoreValuesRestHandlerImpl) FindValuesByAppStoreIdAndReferenceType(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -185,7 +185,7 @@ func (handler AppStoreValuesRestHandlerImpl) FindValuesByAppStoreIdAndReferenceT func (handler AppStoreValuesRestHandlerImpl) FetchTemplateValuesByAppStoreId(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -221,7 +221,7 @@ func (handler AppStoreValuesRestHandlerImpl) FetchTemplateValuesByAppStoreId(w h func (handler AppStoreValuesRestHandlerImpl) GetSelectedChartMetadata(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/auth/sso/SsoLoginHandler.go b/api/auth/sso/SsoLoginHandler.go index 6044df9995..9b6e14d574 100644 --- a/api/auth/sso/SsoLoginHandler.go +++ b/api/auth/sso/SsoLoginHandler.go @@ -59,7 +59,7 @@ func NewSsoLoginRestHandlerImpl(validator *validator.Validate, func (handler SsoLoginRestHandlerImpl) CreateSSOLoginConfig(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -91,7 +91,7 @@ func (handler SsoLoginRestHandlerImpl) CreateSSOLoginConfig(w http.ResponseWrite func (handler SsoLoginRestHandlerImpl) UpdateSSOLoginConfig(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -134,7 +134,7 @@ func (handler SsoLoginRestHandlerImpl) GetAllSSOLoginConfig(w http.ResponseWrite func (handler SsoLoginRestHandlerImpl) GetSSOLoginConfig(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -164,7 +164,7 @@ func (handler SsoLoginRestHandlerImpl) GetSSOLoginConfig(w http.ResponseWriter, func (handler SsoLoginRestHandlerImpl) GetSSOLoginConfigByName(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/auth/user/RbacRoleRestHandler.go b/api/auth/user/RbacRoleRestHandler.go index e509095861..d604fbaf60 100644 --- a/api/auth/user/RbacRoleRestHandler.go +++ b/api/auth/user/RbacRoleRestHandler.go @@ -59,7 +59,7 @@ func NewRbacRoleHandlerImpl(logger *zap.SugaredLogger, func (handler *RbacRoleRestHandlerImpl) GetAllDefaultRoles(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } handler.logger.Debugw("request payload, GetAllDefaultRoles") diff --git a/api/auth/user/UserRestHandler.go b/api/auth/user/UserRestHandler.go index 9c7610f310..9fac7e4c98 100644 --- a/api/auth/user/UserRestHandler.go +++ b/api/auth/user/UserRestHandler.go @@ -98,7 +98,7 @@ func (handler UserRestHandlerImpl) CreateUser(w http.ResponseWriter, r *http.Req decoder := json.NewDecoder(r.Body) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var userInfo bean2.UserInfo @@ -162,7 +162,7 @@ func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Req decoder := json.NewDecoder(r.Body) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var userInfo bean2.UserInfo @@ -205,21 +205,22 @@ func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Req func (handler UserRestHandlerImpl) GetById(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - /* #nosec */ - id, err := strconv.Atoi(vars["id"]) + + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "user") if err != nil { - handler.logger.Errorw("request err, GetById", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } + res, err := handler.userService.GetByIdWithoutGroupClaims(int32(id)) if err != nil { - handler.logger.Errorw("service err, GetById", "err", err, "id", id) - common.WriteJsonResp(w, err, "Failed to get by id", http.StatusInternalServerError) + handler.logger.Errorw("Failed to get user by ID", "userId", id, "err", err) + // Use enhanced error response with resource context + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "user", id) return } @@ -237,7 +238,7 @@ func (handler UserRestHandlerImpl) GetAllV2(w http.ResponseWriter, r *http.Reque var decoder = schema.NewDecoder() userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -274,7 +275,7 @@ func (handler UserRestHandlerImpl) GetAllV2(w http.ResponseWriter, r *http.Reque func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -303,7 +304,7 @@ func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request func (handler UserRestHandlerImpl) GetAllDetailedUsers(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -328,21 +329,22 @@ func (handler UserRestHandlerImpl) GetAllDetailedUsers(w http.ResponseWriter, r func (handler UserRestHandlerImpl) DeleteUser(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - /* #nosec */ - id, err := strconv.Atoi(vars["id"]) + + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "user") if err != nil { - handler.logger.Errorw("request err, DeleteUser", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } - handler.logger.Infow("request payload, DeleteUser", "err", err, "id", id) + + handler.logger.Infow("Delete user request", "userId", id, "requestedBy", userId) user, err := handler.userService.GetByIdWithoutGroupClaims(int32(id)) if err != nil { - common.WriteJsonResp(w, err, "", http.StatusInternalServerError) + handler.logger.Errorw("Failed to get user for deletion", "userId", id, "err", err) + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "user", id) return } @@ -376,7 +378,7 @@ func (handler UserRestHandlerImpl) DeleteUser(w http.ResponseWriter, r *http.Req func (handler UserRestHandlerImpl) BulkDeleteUsers(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -424,18 +426,17 @@ func (handler UserRestHandlerImpl) BulkDeleteUsers(w http.ResponseWriter, r *htt } func (handler UserRestHandlerImpl) FetchRoleGroupById(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - /* #nosec */ - id, err := strconv.Atoi(vars["id"]) + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "role group") if err != nil { - handler.logger.Errorw("request err, FetchRoleGroupById", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } + res, err := handler.roleGroupService.FetchRoleGroupsById(int32(id)) if err != nil { - handler.logger.Errorw("service err, FetchRoleGroupById", "err", err, "id", id) - common.WriteJsonResp(w, err, "Failed to get by id", http.StatusInternalServerError) + handler.logger.Errorw("Failed to fetch role group by ID", "roleGroupId", id, "err", err) + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "role group", id) return } @@ -454,7 +455,7 @@ func (handler UserRestHandlerImpl) CreateRoleGroup(w http.ResponseWriter, r *htt decoder := json.NewDecoder(r.Body) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request bean2.RoleGroup @@ -507,7 +508,7 @@ func (handler UserRestHandlerImpl) UpdateRoleGroup(w http.ResponseWriter, r *htt decoder := json.NewDecoder(r.Body) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request bean2.RoleGroup @@ -552,7 +553,7 @@ func (handler UserRestHandlerImpl) FetchRoleGroupsV2(w http.ResponseWriter, r *h var decoder = schema.NewDecoder() userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -588,7 +589,7 @@ func (handler UserRestHandlerImpl) FetchRoleGroupsV2(w http.ResponseWriter, r *h func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -615,7 +616,7 @@ func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *htt func (handler UserRestHandlerImpl) FetchDetailedRoleGroups(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -640,7 +641,7 @@ func (handler UserRestHandlerImpl) FetchDetailedRoleGroups(w http.ResponseWriter func (handler UserRestHandlerImpl) FetchRoleGroupsByName(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -658,7 +659,7 @@ func (handler UserRestHandlerImpl) FetchRoleGroupsByName(w http.ResponseWriter, func (handler UserRestHandlerImpl) DeleteRoleGroup(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -701,7 +702,7 @@ func (handler UserRestHandlerImpl) DeleteRoleGroup(w http.ResponseWriter, r *htt func (handler UserRestHandlerImpl) BulkDeleteRoleGroups(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -745,7 +746,7 @@ func (handler UserRestHandlerImpl) BulkDeleteRoleGroups(w http.ResponseWriter, r func (handler UserRestHandlerImpl) CheckUserRoles(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } roles, err := handler.userService.CheckUserRoles(userId, "") @@ -804,7 +805,7 @@ func (handler UserRestHandlerImpl) CheckUserRoles(w http.ResponseWriter, r *http func (handler UserRestHandlerImpl) SyncOrchestratorToCasbin(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } userEmailId, err := handler.userService.GetActiveEmailById(userId) @@ -830,7 +831,7 @@ func (handler UserRestHandlerImpl) UpdateTriggerPolicyForTerminalAccess(w http.R userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { handler.logger.Errorw("unauthorized user, UpdateTriggerPolicyForTerminalAccess", "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/chartRepo/ChartRepositoryRestHandler.go b/api/chartRepo/ChartRepositoryRestHandler.go index 11a48a296d..ccd417827d 100644 --- a/api/chartRepo/ChartRepositoryRestHandler.go +++ b/api/chartRepo/ChartRepositoryRestHandler.go @@ -21,7 +21,6 @@ import ( "errors" "mime/multipart" "net/http" - "strconv" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/util" @@ -30,7 +29,6 @@ import ( "github.com/devtron-labs/devtron/pkg/auth/user" "github.com/devtron-labs/devtron/pkg/chartRepo" delete2 "github.com/devtron-labs/devtron/pkg/delete" - "github.com/gorilla/mux" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" ) @@ -82,21 +80,22 @@ func NewChartRepositoryRestHandlerImpl(Logger *zap.SugaredLogger, userAuthServic func (handler *ChartRepositoryRestHandlerImpl) GetChartRepoById(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, nil, http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) + + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "chart repository") if err != nil { - handler.Logger.Errorw("request err, GetChartRepoById", "err", err, "chart repo id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } - handler.Logger.Infow("request payload, GetChartRepoById, app store", "chart repo id", id) + + handler.Logger.Infow("Get chart repository request", "chartRepoId", id, "userId", userId) res, err := handler.chartRepositoryService.GetChartRepoById(id) if err != nil { - handler.Logger.Errorw("service err, GetChartRepoById, app store", "err", err, "userId", userId) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + handler.Logger.Errorw("Failed to get chart repository", "chartRepoId", id, "userId", userId, "err", err) + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "chart repository", id) return } common.WriteJsonResp(w, err, res, http.StatusOK) @@ -147,7 +146,7 @@ func (handler *ChartRepositoryRestHandlerImpl) CreateChartRepo(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request *chartRepo.ChartRepoDto @@ -191,7 +190,7 @@ func (handler *ChartRepositoryRestHandlerImpl) UpdateChartRepo(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request *chartRepo.ChartRepoDto @@ -235,7 +234,7 @@ func (handler *ChartRepositoryRestHandlerImpl) ValidateChartRepo(w http.Response decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request *chartRepo.ChartRepoDto @@ -292,7 +291,7 @@ func (handler *ChartRepositoryRestHandlerImpl) DeleteChartRepo(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request *chartRepo.ChartRepoDto diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 2d2f946cb9..c400a34f7a 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -106,7 +106,7 @@ func (impl ClusterRestHandlerImpl) SaveClusters(w http.ResponseWriter, r *http.R decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } beans := []*bean2.ClusterBean{} @@ -169,7 +169,7 @@ func (impl ClusterRestHandlerImpl) Save(w http.ResponseWriter, r *http.Request) decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } bean := new(bean2.ClusterBean) @@ -230,7 +230,7 @@ func (impl ClusterRestHandlerImpl) ValidateKubeconfig(w http.ResponseWriter, r * decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } bean := &bean2.Kubeconfig{} @@ -352,18 +352,18 @@ func (impl ClusterRestHandlerImpl) FindByIds(w http.ResponseWriter, r *http.Requ } func (impl ClusterRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - id := vars["id"] - i, err := strconv.Atoi(id) + // Use enhanced parameter parsing with context + clusterId, err := common.ExtractIntPathParamWithContext(w, r, "id", "cluster") if err != nil { - impl.logger.Errorw("request err, FindById", "error", err, "clusterId", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } - bean, err := impl.clusterService.FindByIdWithoutConfig(i) + + bean, err := impl.clusterService.FindByIdWithoutConfig(clusterId) if err != nil { - impl.logger.Errorw("service err, FindById", "err", err, "clusterId", id) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to find cluster", "clusterId", clusterId, "err", err) + // Use enhanced error response with resource context + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "cluster", clusterId) return } @@ -381,7 +381,7 @@ func (impl ClusterRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Reque func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -425,7 +425,7 @@ func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request 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) + common.HandleUnauthorized(w, r) return } var bean bean2.ClusterBean @@ -478,7 +478,7 @@ func (impl ClusterRestHandlerImpl) UpdateClusterDescription(w http.ResponseWrite 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) + common.HandleUnauthorized(w, r) return } var bean bean2.ClusterBean @@ -518,7 +518,7 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h 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) + common.HandleUnauthorized(w, r) return } var bean repository.GenericNote @@ -608,7 +608,7 @@ func (impl ClusterRestHandlerImpl) DeleteCluster(w http.ResponseWriter, r *http. userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.logger.Errorw("service err, Delete", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean2.DeleteClusterBean @@ -647,7 +647,7 @@ func (impl ClusterRestHandlerImpl) GetAllClusterNamespaces(w http.ResponseWriter userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.logger.Errorw("err, GetAllClusterNamespaces", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } clusterNamespaces := impl.clusterService.GetAllClusterNamespaces() @@ -709,7 +709,7 @@ func (impl ClusterRestHandlerImpl) GetClusterNamespaces(w http.ResponseWriter, r userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.logger.Errorw("user not authorized", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -743,7 +743,7 @@ func (impl ClusterRestHandlerImpl) FindAllForClusterPermission(w http.ResponseWr userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.logger.Errorw("user not authorized", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/cluster/EnvironmentRestHandler.go b/api/cluster/EnvironmentRestHandler.go index 9189ba28ea..1ce898bd5d 100644 --- a/api/cluster/EnvironmentRestHandler.go +++ b/api/cluster/EnvironmentRestHandler.go @@ -110,7 +110,7 @@ func (impl EnvironmentRestHandlerImpl) Create(w http.ResponseWriter, r *http.Req decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean2.EnvironmentBean @@ -206,7 +206,7 @@ func (impl EnvironmentRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Req userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -261,7 +261,7 @@ func (impl EnvironmentRestHandlerImpl) Update(w http.ResponseWriter, r *http.Req decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -303,16 +303,18 @@ func (impl EnvironmentRestHandlerImpl) Update(w http.ResponseWriter, r *http.Req } func (impl EnvironmentRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - envId, err := strconv.Atoi(vars["id"]) + // Use enhanced parameter parsing with context + envId, err := common.ExtractIntPathParamWithContext(w, r, "id", "environment") if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } + bean, err := impl.environmentClusterMappingsService.FindById(envId) if err != nil { - impl.logger.Errorw("service err, FindById", "err", err, "envId", envId) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to find environment", "envId", envId, "err", err) + // Use enhanced error response with resource context + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "environment", envId) return } @@ -330,7 +332,7 @@ func (impl EnvironmentRestHandlerImpl) FindById(w http.ResponseWriter, r *http.R func (impl EnvironmentRestHandlerImpl) GetEnvironmentListForAutocomplete(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } start := time.Now() @@ -363,7 +365,7 @@ func (impl EnvironmentRestHandlerImpl) GetEnvironmentListForAutocomplete(w http. func (impl EnvironmentRestHandlerImpl) GetCombinedEnvironmentListForDropDown(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -385,7 +387,7 @@ func (impl EnvironmentRestHandlerImpl) DeleteEnvironment(w http.ResponseWriter, decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean2.EnvironmentBean @@ -423,7 +425,7 @@ func (impl EnvironmentRestHandlerImpl) DeleteEnvironment(w http.ResponseWriter, func (impl EnvironmentRestHandlerImpl) GetCombinedEnvironmentListForDropDownByClusterIds(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } v := r.URL.Query() @@ -468,7 +470,7 @@ func (impl EnvironmentRestHandlerImpl) GetEnvironmentConnection(w http.ResponseW userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { impl.logger.Errorw("user not authorized", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } bean, err := impl.environmentClusterMappingsService.FindById(envId) diff --git a/api/externalLink/ExternalLinkRestHandler.go b/api/externalLink/ExternalLinkRestHandler.go index cbf6783371..2c24ef6ebd 100644 --- a/api/externalLink/ExternalLinkRestHandler.go +++ b/api/externalLink/ExternalLinkRestHandler.go @@ -67,7 +67,7 @@ func NewExternalLinkRestHandlerImpl(logger *zap.SugaredLogger, func (impl ExternalLinkRestHandlerImpl) roleCheckHelper(w http.ResponseWriter, r *http.Request, action string) (int32, string, error) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return userId, "", fmt.Errorf("unauthorized error") } userRole := "" @@ -78,8 +78,9 @@ func (impl ExternalLinkRestHandlerImpl) roleCheckHelper(w http.ResponseWriter, r if v.Has("appId") { id, err := strconv.Atoi(appId) if err != nil { - impl.logger.Errorw("error occurred while converting appId to integer", "err", err, "appId", appId) - common.WriteJsonResp(w, errors.New("Invalid request"), nil, http.StatusBadRequest) + impl.logger.Errorw("Invalid appId query parameter", "err", err, "appId", appId) + // Use enhanced error handling for query parameter validation + common.HandleParameterError(w, r, "appId", appId) return userId, "", fmt.Errorf("invalid request query param appId = %s", appId) } object := impl.enforcerUtil.GetAppRBACNameByAppId(id) @@ -122,7 +123,7 @@ func (impl ExternalLinkRestHandlerImpl) CreateExternalLinks(w http.ResponseWrite func (impl ExternalLinkRestHandlerImpl) GetExternalLinkMonitoringTools(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -139,7 +140,7 @@ func (impl ExternalLinkRestHandlerImpl) GetExternalLinkMonitoringTools(w http.Re func (impl ExternalLinkRestHandlerImpl) GetExternalLinks(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -198,7 +199,7 @@ func (impl ExternalLinkRestHandlerImpl) GetExternalLinks(w http.ResponseWriter, func (impl ExternalLinkRestHandlerImpl) GetExternalLinksV2(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/helm-app/HelmAppRestHandler.go b/api/helm-app/HelmAppRestHandler.go index bb4343a530..49c2da7c14 100644 --- a/api/helm-app/HelmAppRestHandler.go +++ b/api/helm-app/HelmAppRestHandler.go @@ -116,8 +116,9 @@ func (handler *HelmAppRestHandlerImpl) ListApplications(w http.ResponseWriter, r } j, err := strconv.Atoi(is) if err != nil { - handler.logger.Errorw("request err, CreateUser", "err", err, "payload", clusterIds) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + handler.logger.Errorw("Invalid cluster ID in list", "err", err, "clusterId", is, "clusterIdString", clusterIdString) + // Use enhanced error handling for parameter validation + common.HandleParameterError(w, r, "clusterIds", clusterIdString) return } clusterIds = append(clusterIds, j) @@ -190,7 +191,8 @@ func (handler *HelmAppRestHandlerImpl) Hibernate(w http.ResponseWriter, r *http. } else { appType, err = strconv.Atoi(appTypeString) if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + handler.logger.Errorw("Invalid app type parameter", "err", err, "appType", appTypeString) + common.HandleParameterError(w, r, "appType", appTypeString) return } } @@ -446,7 +448,7 @@ func (handler *HelmAppRestHandlerImpl) GetDesiredManifest(w http.ResponseWriter, func (handler *HelmAppRestHandlerImpl) DeleteApplication(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -529,7 +531,7 @@ func (handler *HelmAppRestHandlerImpl) UpdateApplication(w http.ResponseWriter, func (handler *HelmAppRestHandlerImpl) TemplateChart(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } request := &openapi2.TemplateChartRequest{} diff --git a/api/infraConfig/restHandler.go b/api/infraConfig/restHandler.go index 6d7b550fc2..a98f0cb234 100644 --- a/api/infraConfig/restHandler.go +++ b/api/infraConfig/restHandler.go @@ -71,7 +71,7 @@ func NewInfraConfigRestHandlerImpl(logger *zap.SugaredLogger, infraProfileServic func (handler *InfraConfigRestHandlerImpl) GetProfile(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -129,7 +129,7 @@ func (handler *InfraConfigRestHandlerImpl) GetProfile(w http.ResponseWriter, r * func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfile(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -176,7 +176,7 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfile(w http.ResponseWri func (handler *InfraConfigRestHandlerImpl) GetProfileV0(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -238,7 +238,7 @@ func (handler *InfraConfigRestHandlerImpl) GetProfileV0(w http.ResponseWriter, r func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfileV0(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/k8s/application/k8sApplicationRestHandler.go b/api/k8s/application/k8sApplicationRestHandler.go index 7c92322f60..830895dd38 100644 --- a/api/k8s/application/k8sApplicationRestHandler.go +++ b/api/k8s/application/k8sApplicationRestHandler.go @@ -466,7 +466,7 @@ func (handler *K8sApplicationRestHandlerImpl) handleRbac(r *http.Request, w http func (handler *K8sApplicationRestHandlerImpl) DeleteResource(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request bean3.ResourceRequestBean @@ -771,7 +771,7 @@ func (handler *K8sApplicationRestHandlerImpl) GetTerminalSession(w http.Response token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } request, resourceRequestBean, err := handler.k8sApplicationService.ValidateTerminalRequestQuery(r) @@ -837,7 +837,7 @@ func (handler *K8sApplicationRestHandlerImpl) GetTerminalSession(w http.Response func (handler *K8sApplicationRestHandlerImpl) GetResourceInfo(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -856,7 +856,7 @@ func (handler *K8sApplicationRestHandlerImpl) GetResourceInfo(w http.ResponseWri func (handler *K8sApplicationRestHandlerImpl) GetAllApiResourceGVKWithoutAuthorization(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -883,7 +883,7 @@ func (handler *K8sApplicationRestHandlerImpl) GetAllApiResourceGVKWithoutAuthori func (handler *K8sApplicationRestHandlerImpl) GetAllApiResources(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -991,7 +991,7 @@ func (handler *K8sApplicationRestHandlerImpl) CreateEphemeralContainer(w http.Re token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -1041,7 +1041,7 @@ func (handler *K8sApplicationRestHandlerImpl) DeleteEphemeralContainer(w http.Re token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/k8s/capacity/k8sCapacityRestHandler.go b/api/k8s/capacity/k8sCapacityRestHandler.go index 2dee3457f9..75f9254392 100644 --- a/api/k8s/capacity/k8sCapacityRestHandler.go +++ b/api/k8s/capacity/k8sCapacityRestHandler.go @@ -87,7 +87,7 @@ func NewK8sCapacityRestHandlerImpl(logger *zap.SugaredLogger, func (handler *K8sCapacityRestHandlerImpl) GetClusterListRaw(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -129,7 +129,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterListRaw(w http.ResponseWrit func (handler *K8sCapacityRestHandlerImpl) GetClusterListWithDetail(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -169,7 +169,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterDetail(w http.ResponseWrite vars := mux.Vars(r) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } clusterId, err := strconv.Atoi(vars["clusterId"]) @@ -209,7 +209,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeList(w http.ResponseWriter, r vars := r.URL.Query() userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } clusterId, err := strconv.Atoi(vars.Get("clusterId")) @@ -244,7 +244,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeDetail(w http.ResponseWriter, vars := r.URL.Query() userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } clusterId, err := strconv.Atoi(vars.Get("clusterId")) @@ -292,7 +292,7 @@ func (handler *K8sCapacityRestHandlerImpl) UpdateNodeManifest(w http.ResponseWri } userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -327,7 +327,7 @@ func (handler *K8sCapacityRestHandlerImpl) DeleteNode(w http.ResponseWriter, r * } userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -371,7 +371,7 @@ func (handler *K8sCapacityRestHandlerImpl) CordonOrUnCordonNode(w http.ResponseW } userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -415,7 +415,7 @@ func (handler *K8sCapacityRestHandlerImpl) DrainNode(w http.ResponseWriter, r *h userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -450,7 +450,7 @@ func (handler *K8sCapacityRestHandlerImpl) EditNodeTaints(w http.ResponseWriter, } userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying diff --git a/api/middleware/ErrorHandlingMiddleware.go b/api/middleware/ErrorHandlingMiddleware.go new file mode 100644 index 0000000000..a1309c5fb6 --- /dev/null +++ b/api/middleware/ErrorHandlingMiddleware.go @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package middleware + +import ( + "context" + "fmt" + "github.com/devtron-labs/devtron/internal/util" + "github.com/gorilla/mux" + "go.uber.org/zap" + "net/http" + "strconv" + "time" +) + +// ErrorHandlingMiddleware provides enhanced error handling and logging for REST handlers +type ErrorHandlingMiddleware struct { + logger *zap.SugaredLogger +} + +// NewErrorHandlingMiddleware creates a new error handling middleware +func NewErrorHandlingMiddleware(logger *zap.SugaredLogger) *ErrorHandlingMiddleware { + return &ErrorHandlingMiddleware{ + logger: logger, + } +} + +// RequestContext holds information about the current request for better error handling +type RequestContext struct { + RequestID string + StartTime time.Time + Method string + Path string + ResourceType string + ResourceID string + UserID int +} + +// ContextKey is used for storing request context in the request context +type ContextKey string + +const RequestContextKey ContextKey = "request_context" + +// WithRequestContext middleware adds request context for better error handling +func (m *ErrorHandlingMiddleware) WithRequestContext(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Generate request ID for correlation + requestID := fmt.Sprintf("%d", time.Now().UnixNano()) + + // Extract resource information from path + vars := mux.Vars(r) + resourceType, resourceID := extractResourceFromPath(r.URL.Path, vars) + + // Create request context + reqCtx := &RequestContext{ + RequestID: requestID, + StartTime: time.Now(), + Method: r.Method, + Path: r.URL.Path, + ResourceType: resourceType, + ResourceID: resourceID, + } + + // Add to request context + ctx := context.WithValue(r.Context(), RequestContextKey, reqCtx) + r = r.WithContext(ctx) + + // Add request ID to response headers for debugging + w.Header().Set("X-Request-ID", requestID) + + // Log request start + m.logger.Infow("Request started", + "requestId", requestID, + "method", r.Method, + "path", r.URL.Path, + "resourceType", resourceType, + "resourceId", resourceID, + ) + + next.ServeHTTP(w, r) + + // Log request completion + duration := time.Since(reqCtx.StartTime) + m.logger.Infow("Request completed", + "requestId", requestID, + "duration", duration, + "method", r.Method, + "path", r.URL.Path, + ) + }) +} + +// extractResourceFromPath attempts to extract resource type and ID from the request path +func extractResourceFromPath(path string, vars map[string]string) (resourceType, resourceID string) { + // Common resource type mappings based on path patterns + resourceMappings := map[string]string{ + "/api/v1/team/": "team", + "/api/v1/cluster/": "cluster", + "/api/v1/env/": "environment", + "/api/v1/app/": "application", + "/api/v1/docker/": "docker registry", + "/api/v1/git/": "git provider", + "/api/v1/pipeline/": "pipeline", + "/api/v1/webhook/": "webhook", + "/orchestrator/team/": "team", + "/orchestrator/app/": "application", + "/orchestrator/env/": "environment", + } + + // Try to match path patterns + for pathPrefix, resType := range resourceMappings { + if len(path) > len(pathPrefix) && path[:len(pathPrefix)] == pathPrefix { + resourceType = resType + break + } + } + + // Try to extract ID from common parameter names + if id, exists := vars["id"]; exists { + resourceID = id + } else if id, exists := vars["teamId"]; exists { + resourceID = id + } else if id, exists := vars["appId"]; exists { + resourceID = id + } else if id, exists := vars["clusterId"]; exists { + resourceID = id + } else if id, exists := vars["envId"]; exists { + resourceID = id + } else if id, exists := vars["gitHostId"]; exists { + resourceID = id + } + + return resourceType, resourceID +} + +// GetRequestContext retrieves the request context from the HTTP request +func GetRequestContext(r *http.Request) *RequestContext { + if ctx := r.Context().Value(RequestContextKey); ctx != nil { + if reqCtx, ok := ctx.(*RequestContext); ok { + return reqCtx + } + } + return nil +} + +// LogError logs an error with request context for better debugging +func (m *ErrorHandlingMiddleware) LogError(r *http.Request, err error, operation string) { + reqCtx := GetRequestContext(r) + if reqCtx != nil { + m.logger.Errorw("Request error", + "requestId", reqCtx.RequestID, + "operation", operation, + "error", err, + "method", reqCtx.Method, + "path", reqCtx.Path, + "resourceType", reqCtx.ResourceType, + "resourceId", reqCtx.ResourceID, + ) + } else { + m.logger.Errorw("Request error", + "operation", operation, + "error", err, + "method", r.Method, + "path", r.URL.Path, + ) + } +} + +// ValidateIntPathParam validates and extracts an integer path parameter with enhanced error handling +func ValidateIntPathParam(r *http.Request, paramName string) (int, *util.ApiError) { + vars := mux.Vars(r) + paramValue := vars[paramName] + + if paramValue == "" { + return 0, util.NewMissingRequiredFieldError(paramName) + } + + id, err := strconv.Atoi(paramValue) + if err != nil { + return 0, util.NewInvalidPathParameterError(paramName, paramValue) + } + + if id <= 0 { + return 0, util.NewValidationErrorForField(paramName, "must be a positive integer") + } + + return id, nil +} diff --git a/api/module/ModuleRestHandler.go b/api/module/ModuleRestHandler.go index 664cae0322..58649ae68a 100644 --- a/api/module/ModuleRestHandler.go +++ b/api/module/ModuleRestHandler.go @@ -64,7 +64,7 @@ func NewModuleRestHandlerImpl(logger *zap.SugaredLogger, func (impl ModuleRestHandlerImpl) GetModuleConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -90,7 +90,7 @@ func (impl ModuleRestHandlerImpl) GetModuleInfo(w http.ResponseWriter, r *http.R // check if user is logged in or not userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -121,7 +121,7 @@ func (impl ModuleRestHandlerImpl) HandleModuleAction(w http.ResponseWriter, r *h // check if user is logged in or not userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -171,7 +171,7 @@ func (impl ModuleRestHandlerImpl) EnableModule(w http.ResponseWriter, r *http.Re // check if user is logged in or not userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/resourceScan/resourceScanRestHandler.go b/api/resourceScan/resourceScanRestHandler.go index f15747e4ec..e3c1bc746a 100644 --- a/api/resourceScan/resourceScanRestHandler.go +++ b/api/resourceScan/resourceScanRestHandler.go @@ -99,7 +99,7 @@ func getResourceScanQueryParams(w http.ResponseWriter, r *http.Request) (*bean.R func (impl ScanningResultRestHandlerImpl) ScanResults(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } resourceScanQueryParams, err := getResourceScanQueryParams(w, r) diff --git a/api/restHandler/AttributesRestHandlder.go b/api/restHandler/AttributesRestHandlder.go index 0eed5eef87..767bc2d1ff 100644 --- a/api/restHandler/AttributesRestHandlder.go +++ b/api/restHandler/AttributesRestHandlder.go @@ -60,7 +60,7 @@ func NewAttributesRestHandlerImpl(logger *zap.SugaredLogger, enforcer casbin.Enf func (handler AttributesRestHandlerImpl) AddAttributes(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -91,7 +91,7 @@ func (handler AttributesRestHandlerImpl) AddAttributes(w http.ResponseWriter, r func (handler AttributesRestHandlerImpl) UpdateAttributes(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -123,7 +123,7 @@ func (handler AttributesRestHandlerImpl) UpdateAttributes(w http.ResponseWriter, func (handler AttributesRestHandlerImpl) GetAttributesById(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -151,7 +151,7 @@ func (handler AttributesRestHandlerImpl) GetAttributesById(w http.ResponseWriter func (handler AttributesRestHandlerImpl) GetAttributesActiveList(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -173,7 +173,7 @@ func (handler AttributesRestHandlerImpl) GetAttributesActiveList(w http.Response func (handler AttributesRestHandlerImpl) GetAttributesByKey(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -197,7 +197,7 @@ func (handler AttributesRestHandlerImpl) GetAttributesByKey(w http.ResponseWrite func (handler AttributesRestHandlerImpl) AddDeploymentEnforcementConfig(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/restHandler/BatchOperationRestHandler.go b/api/restHandler/BatchOperationRestHandler.go index f9df83eeed..c1f3adb535 100644 --- a/api/restHandler/BatchOperationRestHandler.go +++ b/api/restHandler/BatchOperationRestHandler.go @@ -66,7 +66,7 @@ func (handler BatchOperationRestHandlerImpl) Operate(w http.ResponseWriter, r *h decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var data map[string]interface{} diff --git a/api/restHandler/BulkUpdateRestHandler.go b/api/restHandler/BulkUpdateRestHandler.go index d02a8be6b8..782bddd7bb 100644 --- a/api/restHandler/BulkUpdateRestHandler.go +++ b/api/restHandler/BulkUpdateRestHandler.go @@ -229,7 +229,7 @@ func (handler BulkUpdateRestHandlerImpl) CheckAuthForBulkUpdate(AppId int, EnvId func (handler BulkUpdateRestHandlerImpl) BulkEdit(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -300,7 +300,7 @@ func (handler BulkUpdateRestHandlerImpl) BulkHibernate(w http.ResponseWriter, r func (handler BulkUpdateRestHandlerImpl) decodeAndValidateBulkRequest(w http.ResponseWriter, r *http.Request) (*bean.BulkApplicationForEnvironmentPayload, error) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return nil, err } @@ -339,7 +339,7 @@ func (handler BulkUpdateRestHandlerImpl) BulkDeploy(w http.ResponseWriter, r *ht token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -370,7 +370,7 @@ func (handler BulkUpdateRestHandlerImpl) BulkDeploy(w http.ResponseWriter, r *ht func (handler BulkUpdateRestHandlerImpl) BulkBuildTrigger(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -420,7 +420,7 @@ func (handler BulkUpdateRestHandlerImpl) HandleCdPipelineBulkAction(w http.Respo decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var cdPipelineBulkActionReq bean.CdBulkActionRequestDto diff --git a/api/restHandler/CommonRestHanlder.go b/api/restHandler/CommonRestHanlder.go index 5527aa2f4a..6ffb772695 100644 --- a/api/restHandler/CommonRestHanlder.go +++ b/api/restHandler/CommonRestHanlder.go @@ -50,7 +50,7 @@ func NewCommonRestHandlerImpl( func (impl CommonRestHandlerImpl) GlobalChecklist(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } res, err := impl.commonService.GlobalChecklist() @@ -66,7 +66,7 @@ func (impl CommonRestHandlerImpl) GlobalChecklist(w http.ResponseWriter, r *http func (impl CommonRestHandlerImpl) EnvironmentVariableList(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // TODO: ADD RBAC (if required) diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index 85d57e2784..bd4278662b 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -101,7 +101,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalAddUpdate(w http.ResponseWriter, decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var configMapRequest bean.ConfigDataRequest @@ -140,7 +140,7 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentAddUpdate(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var configMapRequest bean.ConfigDataRequest @@ -185,7 +185,7 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentAddUpdate(w http.ResponseWr func (handler ConfigMapRestHandlerImpl) CMGlobalFetch(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -218,7 +218,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetch(w http.ResponseWriter, r * func (handler ConfigMapRestHandlerImpl) CMGlobalFetchForEdit(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -255,7 +255,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetchForEdit(w http.ResponseWrit func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetchForEdit(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -306,7 +306,7 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetchForEdit(w http.Respons func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetch(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -346,7 +346,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalAddUpdate(w http.ResponseWriter, decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var configMapRequest bean.ConfigDataRequest @@ -385,7 +385,7 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentAddUpdate(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var configMapRequest bean.ConfigDataRequest @@ -431,7 +431,7 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentAddUpdate(w http.ResponseWr func (handler ConfigMapRestHandlerImpl) CSGlobalFetch(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -464,7 +464,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetch(w http.ResponseWriter, r * func (handler ConfigMapRestHandlerImpl) CSEnvironmentFetch(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -503,7 +503,7 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentFetch(w http.ResponseWriter func (handler ConfigMapRestHandlerImpl) CMGlobalDelete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -551,7 +551,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalDelete(w http.ResponseWriter, r func (handler ConfigMapRestHandlerImpl) CMEnvironmentDelete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -613,7 +613,7 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentDelete(w http.ResponseWrite func (handler ConfigMapRestHandlerImpl) CSGlobalDelete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -661,7 +661,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalDelete(w http.ResponseWriter, r func (handler ConfigMapRestHandlerImpl) CSEnvironmentDelete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -723,7 +723,7 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentDelete(w http.ResponseWrite func (handler ConfigMapRestHandlerImpl) CSGlobalFetchForEdit(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -764,7 +764,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetchForEdit(w http.ResponseWrit func (handler ConfigMapRestHandlerImpl) CSEnvironmentFetchForEdit(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -820,7 +820,7 @@ func (handler ConfigMapRestHandlerImpl) ConfigSecretBulkPatch(w http.ResponseWri decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -863,7 +863,7 @@ func (handler ConfigMapRestHandlerImpl) AddEnvironmentToJob(w http.ResponseWrite decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -899,7 +899,7 @@ func (handler ConfigMapRestHandlerImpl) RemoveEnvironmentFromJob(w http.Response decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -934,7 +934,7 @@ func (handler ConfigMapRestHandlerImpl) RemoveEnvironmentFromJob(w http.Response func (handler ConfigMapRestHandlerImpl) GetEnvironmentsForJob(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/CoreAppRestHandler.go b/api/restHandler/CoreAppRestHandler.go index 277405a08b..39e1934f00 100644 --- a/api/restHandler/CoreAppRestHandler.go +++ b/api/restHandler/CoreAppRestHandler.go @@ -21,6 +21,11 @@ import ( "encoding/json" "errors" "fmt" + "net/http" + "strconv" + "strings" + "time" + app2 "github.com/devtron-labs/devtron/api/restHandler/app/pipeline/configure" "github.com/devtron-labs/devtron/internal/sql/constants" appWorkflowBean "github.com/devtron-labs/devtron/pkg/appWorkflow/bean" @@ -34,10 +39,6 @@ import ( read5 "github.com/devtron-labs/devtron/pkg/chart/read" "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" read3 "github.com/devtron-labs/devtron/pkg/team/read" - "net/http" - "strconv" - "strings" - "time" appBean "github.com/devtron-labs/devtron/api/appbean" "github.com/devtron-labs/devtron/api/restHandler/common" @@ -150,15 +151,15 @@ func (handler CoreAppRestHandlerImpl) GetAppAllDetail(w http.ResponseWriter, r * userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.WriteUnauthorizedError(w) return } vars := mux.Vars(r) appId, err := strconv.Atoi(vars["appId"]) if err != nil { - handler.logger.Errorw("request err, GetAppAllDetail", "err", err, "appId", appId) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + handler.logger.Errorw("request err, GetAppAllDetail", "err", err, "appId", vars["appId"]) + common.WriteInvalidAppIdError(w, vars["appId"]) return } @@ -167,7 +168,7 @@ func (handler CoreAppRestHandlerImpl) GetAppAllDetail(w http.ResponseWriter, r * object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { handler.logger.Errorw("Unauthorized User for app update action", "err", err, "appId", appId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + common.WriteForbiddenError(w, "update", "application") return } //rbac implementation ends here for app @@ -260,7 +261,7 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -447,13 +448,17 @@ func (handler CoreAppRestHandlerImpl) buildAppMetadata(appId int) (*appBean.AppM 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) + // Check if it's a "not found" error + if util2.IsErrNoRows(err) { + return nil, err, http.StatusNotFound + } return nil, err, http.StatusInternalServerError } if appMetaInfo == nil { err = errors.New("invalid appId - appMetaInfo is null") handler.logger.Errorw("Validation error ", "err", err, "appId", appId) - return nil, err, http.StatusBadRequest + return nil, err, http.StatusNotFound } var appLabelsRes []*appBean.AppLabel @@ -2243,7 +2248,7 @@ func (handler CoreAppRestHandlerImpl) CreateAppWorkflow(w http.ResponseWriter, r decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -2321,7 +2326,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflow(w http.ResponseWriter, r *h userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -2377,7 +2382,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflowAndOverridesSample(w http.Re userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/DeploymentGroupRestHandler.go b/api/restHandler/DeploymentGroupRestHandler.go index a9e6aa2dc9..77d592fc9b 100644 --- a/api/restHandler/DeploymentGroupRestHandler.go +++ b/api/restHandler/DeploymentGroupRestHandler.go @@ -65,7 +65,7 @@ func (impl *DeploymentGroupRestHandlerImpl) CreateDeploymentGroup(w http.Respons decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean deploymentGroup.DeploymentGroupRequest @@ -109,7 +109,7 @@ func (impl *DeploymentGroupRestHandlerImpl) CreateDeploymentGroup(w http.Respons func (impl *DeploymentGroupRestHandlerImpl) FetchParentCiForDG(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -145,7 +145,7 @@ func (impl *DeploymentGroupRestHandlerImpl) FetchParentCiForDG(w http.ResponseWr func (impl *DeploymentGroupRestHandlerImpl) FetchEnvApplicationsForDG(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -196,7 +196,7 @@ func (impl *DeploymentGroupRestHandlerImpl) FetchEnvApplicationsForDG(w http.Res func (impl *DeploymentGroupRestHandlerImpl) FetchAllDeploymentGroups(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -230,7 +230,7 @@ func (impl *DeploymentGroupRestHandlerImpl) FetchAllDeploymentGroups(w http.Resp func (impl *DeploymentGroupRestHandlerImpl) DeleteDeploymentGroup(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -270,7 +270,7 @@ func (impl *DeploymentGroupRestHandlerImpl) DeleteDeploymentGroup(w http.Respons func (impl *DeploymentGroupRestHandlerImpl) TriggerReleaseForDeploymentGroup(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean *deploymentGroup.DeploymentGroupTriggerRequest @@ -318,7 +318,7 @@ func (impl *DeploymentGroupRestHandlerImpl) UpdateDeploymentGroup(w http.Respons decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean deploymentGroup.DeploymentGroupRequest diff --git a/api/restHandler/DockerRegRestHandler.go b/api/restHandler/DockerRegRestHandler.go index f76705ba72..96e696cdeb 100644 --- a/api/restHandler/DockerRegRestHandler.go +++ b/api/restHandler/DockerRegRestHandler.go @@ -196,7 +196,7 @@ func (impl DockerRegRestHandlerImpl) SaveDockerRegistryConfig(w http.ResponseWri decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean types.DockerArtifactStoreBean @@ -295,7 +295,7 @@ func (impl DockerRegRestHandlerImpl) ValidateDockerRegistryConfig(w http.Respons decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean types.DockerArtifactStoreBean @@ -428,12 +428,21 @@ func (impl DockerRegRestHandlerExtendedImpl) FetchAllDockerAccounts(w http.Respo } func (impl DockerRegRestHandlerImpl) FetchOneDockerAccounts(w http.ResponseWriter, r *http.Request) { + // Use enhanced error response builder + errorBuilder := common.NewErrorResponseBuilder(w, r). + WithOperation("fetch docker registry"). + WithResource("docker registry", "") + params := mux.Vars(r) id := params["id"] + + // Update resource context with actual ID + errorBuilder = errorBuilder.WithResource("docker registry", id) + res, err := impl.dockerRegistryConfig.FetchOneDockerAccount(id) if err != nil { - impl.logger.Errorw("service err, FetchOneDockerAccounts", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to fetch docker registry", "registryId", id, "err", err) + errorBuilder.HandleError(err) return } res.DisabledFields = make([]types.DisabledFields, 0) @@ -446,12 +455,13 @@ func (impl DockerRegRestHandlerImpl) FetchOneDockerAccounts(w http.ResponseWrite // RBAC enforcer applying token := r.Header.Get("token") if ok := impl.enforcer.Enforce(token, casbin.ResourceDocker, casbin.ActionGet, res.Id); !ok { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + impl.logger.Warnw("Unauthorized access to docker registry", "registryId", id, "userId", token) + common.HandleForbidden(w, r, "docker registry") return } //RBAC enforcer Ends - common.WriteJsonResp(w, err, res, http.StatusOK) + errorBuilder.HandleSuccess(res) } func (impl DockerRegRestHandlerExtendedImpl) FetchOneDockerAccounts(w http.ResponseWriter, r *http.Request) { @@ -488,7 +498,7 @@ func (impl DockerRegRestHandlerImpl) UpdateDockerRegistryConfig(w http.ResponseW decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean types.DockerArtifactStoreBean @@ -597,7 +607,7 @@ func (impl DockerRegRestHandlerImpl) DeleteDockerRegistryConfig(w http.ResponseW decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean types.DockerArtifactStoreBean @@ -636,7 +646,7 @@ func (impl DockerRegRestHandlerExtendedImpl) DeleteDockerRegistryConfig(w http.R decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean types.DockerArtifactStoreBean diff --git a/api/restHandler/GitHostRestHandler.go b/api/restHandler/GitHostRestHandler.go index 1aae1e6141..833f84fd1c 100644 --- a/api/restHandler/GitHostRestHandler.go +++ b/api/restHandler/GitHostRestHandler.go @@ -77,7 +77,7 @@ func (impl GitHostRestHandlerImpl) GetGitHosts(w http.ResponseWriter, r *http.Re // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -107,7 +107,7 @@ func (impl GitHostRestHandlerImpl) GetGitHostById(w http.ResponseWriter, r *http // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -136,7 +136,7 @@ func (impl GitHostRestHandlerImpl) CreateGitHost(w http.ResponseWriter, r *http. // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -182,7 +182,7 @@ func (impl GitHostRestHandlerImpl) GetAllWebhookEventConfig(w http.ResponseWrite // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -224,7 +224,7 @@ func (impl GitHostRestHandlerImpl) GetWebhookEventConfig(w http.ResponseWriter, // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -258,7 +258,7 @@ func (impl GitHostRestHandlerImpl) GetWebhookDataMetaConfig(w http.ResponseWrite // check if user is logged in or not userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/GitOpsConfigRestHandler.go b/api/restHandler/GitOpsConfigRestHandler.go index 1f70424635..740e0eca1b 100644 --- a/api/restHandler/GitOpsConfigRestHandler.go +++ b/api/restHandler/GitOpsConfigRestHandler.go @@ -77,7 +77,7 @@ func (impl GitOpsConfigRestHandlerImpl) CreateGitOpsConfig(w http.ResponseWriter decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -116,7 +116,7 @@ func (impl GitOpsConfigRestHandlerImpl) UpdateGitOpsConfig(w http.ResponseWriter decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -164,7 +164,7 @@ func (impl GitOpsConfigRestHandlerImpl) GetGitOpsConfigById(w http.ResponseWrite vars := mux.Vars(r) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } id, err := strconv.Atoi(vars["id"]) @@ -194,7 +194,7 @@ func (impl GitOpsConfigRestHandlerImpl) GetGitOpsConfigById(w http.ResponseWrite func (impl GitOpsConfigRestHandlerImpl) GitOpsConfigured(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } result, err := impl.gitOpsConfigService.GetAllGitOpsConfig() @@ -223,7 +223,7 @@ func (impl GitOpsConfigRestHandlerImpl) GitOpsConfigured(w http.ResponseWriter, func (impl GitOpsConfigRestHandlerImpl) GetAllGitOpsConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } result, err := impl.gitOpsConfigService.GetAllGitOpsConfig() @@ -247,7 +247,7 @@ func (impl GitOpsConfigRestHandlerImpl) GetAllGitOpsConfig(w http.ResponseWriter func (impl GitOpsConfigRestHandlerImpl) GetGitOpsConfigByProvider(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -274,7 +274,7 @@ func (impl GitOpsConfigRestHandlerImpl) GitOpsValidator(w http.ResponseWriter, r decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying diff --git a/api/restHandler/GitProviderRestHandler.go b/api/restHandler/GitProviderRestHandler.go index 55b7ea1bae..84c92eddf7 100644 --- a/api/restHandler/GitProviderRestHandler.go +++ b/api/restHandler/GitProviderRestHandler.go @@ -81,7 +81,7 @@ func (impl GitProviderRestHandlerImpl) SaveGitRepoConfig(w http.ResponseWriter, decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean.GitRegistry @@ -110,8 +110,9 @@ func (impl GitProviderRestHandlerImpl) SaveGitRepoConfig(w http.ResponseWriter, res, err := impl.gitRegistryConfig.Create(&bean) if err != nil { - impl.logger.Errorw("service err, SaveGitRepoConfig", "err", err, "payload", bean) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to create git provider", "gitProviderName", bean.Name, "err", err) + // Use enhanced error response with resource context + common.WriteJsonRespWithResourceContext(w, err, nil, 0, "git provider", bean.Name) return } common.WriteJsonResp(w, err, res, http.StatusOK) @@ -120,8 +121,9 @@ func (impl GitProviderRestHandlerImpl) SaveGitRepoConfig(w http.ResponseWriter, func (impl GitProviderRestHandlerImpl) GetGitProviders(w http.ResponseWriter, r *http.Request) { res, err := impl.gitProviderReadService.GetAll() if err != nil { - impl.logger.Errorw("service err, GetGitProviders", "err", err) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to get git providers", "err", err) + // Use enhanced error response for service errors + common.WriteJsonRespWithResourceContext(w, err, nil, 0, "git providers", "all") return } @@ -174,7 +176,7 @@ func (impl GitProviderRestHandlerImpl) UpdateGitRepoConfig(w http.ResponseWriter decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean.GitRegistry @@ -213,7 +215,7 @@ func (impl GitProviderRestHandlerImpl) DeleteGitRepoConfig(w http.ResponseWriter decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean.GitRegistry diff --git a/api/restHandler/GlobalCMCSRestHandler.go b/api/restHandler/GlobalCMCSRestHandler.go index 6936bafa7b..f15f7a95a6 100644 --- a/api/restHandler/GlobalCMCSRestHandler.go +++ b/api/restHandler/GlobalCMCSRestHandler.go @@ -66,7 +66,7 @@ func (handler *GlobalCMCSRestHandlerImpl) CreateGlobalCMCSConfig(w http.Response decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean pipelineBean.GlobalCMCSDto @@ -106,7 +106,7 @@ func (handler *GlobalCMCSRestHandlerImpl) UpdateGlobalCMCSDataById(w http.Respon decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean pipeline.GlobalCMCSDataUpdateDto @@ -146,7 +146,7 @@ func (handler *GlobalCMCSRestHandlerImpl) GetGlobalCMCSDataByConfigTypeAndName(w userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -174,7 +174,7 @@ func (handler *GlobalCMCSRestHandlerImpl) GetGlobalCMCSDataByConfigTypeAndName(w func (handler *GlobalCMCSRestHandlerImpl) GetAllGlobalCMCSData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -205,7 +205,7 @@ func (handler *GlobalCMCSRestHandlerImpl) DeleteByID(w http.ResponseWriter, r *h userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/restHandler/GlobalPluginRestHandler.go b/api/restHandler/GlobalPluginRestHandler.go index 2b5ee0d9fb..36a19a9fbc 100644 --- a/api/restHandler/GlobalPluginRestHandler.go +++ b/api/restHandler/GlobalPluginRestHandler.go @@ -84,7 +84,7 @@ func (handler *GlobalPluginRestHandlerImpl) patchPlugin(w http.ResponseWriter, r decoder := json.NewDecoder(r.Body) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var pluginDataDto bean.PluginMetadataDto @@ -115,7 +115,7 @@ func (handler *GlobalPluginRestHandlerImpl) patchPlugin(w http.ResponseWriter, r func (handler *GlobalPluginRestHandlerImpl) GetDetailedPluginInfoByPluginId(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -144,7 +144,7 @@ func (handler *GlobalPluginRestHandlerImpl) GetDetailedPluginInfoByPluginId(w ht func (handler *GlobalPluginRestHandlerImpl) GetAllDetailedPluginInfo(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // RBAC enforcer applying @@ -442,7 +442,7 @@ func (handler *GlobalPluginRestHandlerImpl) MigratePluginData(w http.ResponseWri func (handler *GlobalPluginRestHandlerImpl) CreatePlugin(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/restHandler/ImageScanRestHandler.go b/api/restHandler/ImageScanRestHandler.go index 087d53d3a4..e28c286cee 100644 --- a/api/restHandler/ImageScanRestHandler.go +++ b/api/restHandler/ImageScanRestHandler.go @@ -73,7 +73,7 @@ func NewImageScanRestHandlerImpl(logger *zap.SugaredLogger, func (impl ImageScanRestHandlerImpl) ScanExecutionList(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -209,7 +209,7 @@ func (impl ImageScanRestHandlerImpl) getAuthorisedImageScanDeployInfoIds(token s func (impl ImageScanRestHandlerImpl) FetchExecutionDetail(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } v := r.URL.Query() @@ -360,7 +360,7 @@ func (impl ImageScanRestHandlerImpl) FetchMinScanResultByAppIdAndEnvId(w http.Re func (impl ImageScanRestHandlerImpl) VulnerabilityExposure(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/NotificationRestHandler.go b/api/restHandler/NotificationRestHandler.go index d7ddbd76ff..621d615d15 100644 --- a/api/restHandler/NotificationRestHandler.go +++ b/api/restHandler/NotificationRestHandler.go @@ -120,7 +120,7 @@ func NewNotificationRestHandlerImpl(dockerRegistryConfig pipeline.DockerRegistry func (impl NotificationRestHandlerImpl) SaveNotificationSettingsV2(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var notificationSetting beans.NotificationRequest @@ -159,7 +159,7 @@ func (impl NotificationRestHandlerImpl) SaveNotificationSettingsV2(w http.Respon func (impl NotificationRestHandlerImpl) UpdateNotificationSettings(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var notificationSetting beans.NotificationUpdateRequest @@ -219,17 +219,16 @@ func (impl NotificationRestHandlerImpl) DeleteNotificationSettings(w http.Respon } func (impl NotificationRestHandlerImpl) GetAllNotificationSettings(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - size, err := strconv.Atoi(vars["size"]) + // Use enhanced parameter parsing with context + size, err := common.ExtractIntPathParamWithContext(w, r, "size", "pagination") if err != nil { - impl.logger.Errorw("request err, GetAllNotificationSettings", "err", err, "payload", size) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } - offset, err := strconv.Atoi(vars["offset"]) + + offset, err := common.ExtractIntPathParamWithContext(w, r, "offset", "pagination") if err != nil { - impl.logger.Errorw("request err, GetAllNotificationSettings", "err", err, "payload", offset) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } @@ -265,7 +264,7 @@ func (impl NotificationRestHandlerImpl) GetAllNotificationSettings(w http.Respon func (impl NotificationRestHandlerImpl) SaveNotificationChannelConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -430,7 +429,7 @@ type ChannelResponseDTO struct { func (impl NotificationRestHandlerImpl) FindAllNotificationConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -518,14 +517,14 @@ func (impl NotificationRestHandlerImpl) FindAllNotificationConfig(w http.Respons func (impl NotificationRestHandlerImpl) FindSESConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) + + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "SES config") if err != nil { - impl.logger.Errorw("request err, FindSESConfig", "err", err) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } token := r.Header.Get("token") @@ -547,14 +546,14 @@ func (impl NotificationRestHandlerImpl) FindSESConfig(w http.ResponseWriter, r * func (impl NotificationRestHandlerImpl) FindSlackConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - id, err := strconv.Atoi(vars["id"]) + + // Use enhanced parameter parsing with context + id, err := common.ExtractIntPathParamWithContext(w, r, "id", "Slack config") if err != nil { - impl.logger.Errorw("request err, FindSlackConfig", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } @@ -572,7 +571,7 @@ func (impl NotificationRestHandlerImpl) FindSlackConfig(w http.ResponseWriter, r func (impl NotificationRestHandlerImpl) FindSMTPConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -599,7 +598,7 @@ func (impl NotificationRestHandlerImpl) FindSMTPConfig(w http.ResponseWriter, r func (impl NotificationRestHandlerImpl) FindWebhookConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -623,7 +622,7 @@ func (impl NotificationRestHandlerImpl) FindWebhookConfig(w http.ResponseWriter, func (impl NotificationRestHandlerImpl) GetWebhookVariables(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -641,7 +640,7 @@ func (impl NotificationRestHandlerImpl) GetWebhookVariables(w http.ResponseWrite func (impl NotificationRestHandlerImpl) RecipientListingSuggestion(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -671,7 +670,7 @@ func (impl NotificationRestHandlerImpl) RecipientListingSuggestion(w http.Respon func (impl NotificationRestHandlerImpl) FindAllNotificationConfigAutocomplete(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -749,7 +748,7 @@ func (impl NotificationRestHandlerImpl) GetOptionsForNotificationSettings(w http decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request repository.SearchRequest @@ -783,7 +782,7 @@ func (impl NotificationRestHandlerImpl) GetOptionsForNotificationSettings(w http func (impl NotificationRestHandlerImpl) DeleteNotificationChannelConfig(w http.ResponseWriter, r *http.Request) { userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/PProfRestHandler.go b/api/restHandler/PProfRestHandler.go index 5728602cf2..6231d8a5a0 100644 --- a/api/restHandler/PProfRestHandler.go +++ b/api/restHandler/PProfRestHandler.go @@ -55,7 +55,7 @@ func NewPProfRestHandler(userService user.UserService, func (p PProfRestHandlerImpl) Index(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -70,7 +70,7 @@ func (p PProfRestHandlerImpl) Index(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Cmdline(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -85,7 +85,7 @@ func (p PProfRestHandlerImpl) Cmdline(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Profile(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -100,7 +100,7 @@ func (p PProfRestHandlerImpl) Profile(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Symbol(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -115,7 +115,7 @@ func (p PProfRestHandlerImpl) Symbol(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Trace(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -130,7 +130,7 @@ func (p PProfRestHandlerImpl) Trace(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Goroutine(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -145,7 +145,7 @@ func (p PProfRestHandlerImpl) Goroutine(w http.ResponseWriter, r *http.Request) func (p PProfRestHandlerImpl) Threadcreate(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -160,7 +160,7 @@ func (p PProfRestHandlerImpl) Threadcreate(w http.ResponseWriter, r *http.Reques func (p PProfRestHandlerImpl) Heap(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -175,7 +175,7 @@ func (p PProfRestHandlerImpl) Heap(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Block(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -190,7 +190,7 @@ func (p PProfRestHandlerImpl) Block(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Mutex(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -205,7 +205,7 @@ func (p PProfRestHandlerImpl) Mutex(w http.ResponseWriter, r *http.Request) { func (p PProfRestHandlerImpl) Allocs(w http.ResponseWriter, r *http.Request) { userId, err := p.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") diff --git a/api/restHandler/PolicyRestHandler.go b/api/restHandler/PolicyRestHandler.go index 2678207843..c10ca49e68 100644 --- a/api/restHandler/PolicyRestHandler.go +++ b/api/restHandler/PolicyRestHandler.go @@ -71,7 +71,7 @@ func (impl PolicyRestHandlerImpl) SavePolicy(w http.ResponseWriter, r *http.Requ decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var req bean.CreateVulnerabilityPolicyRequest @@ -135,7 +135,7 @@ func (impl PolicyRestHandlerImpl) UpdatePolicy(w http.ResponseWriter, r *http.Re decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var req bean.UpdatePolicyParams @@ -204,7 +204,7 @@ func (impl PolicyRestHandlerImpl) UpdatePolicy(w http.ResponseWriter, r *http.Re func (impl PolicyRestHandlerImpl) GetPolicy(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } req := bean.FetchPolicyParams{} diff --git a/api/restHandler/ReleaseMetricsRestHandler.go b/api/restHandler/ReleaseMetricsRestHandler.go index f9de1c48c2..a69d4ab652 100644 --- a/api/restHandler/ReleaseMetricsRestHandler.go +++ b/api/restHandler/ReleaseMetricsRestHandler.go @@ -76,7 +76,7 @@ func (impl *ReleaseMetricsRestHandlerImpl) ResetDataForAppEnvironment(w http.Res decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var req MetricsRequest diff --git a/api/restHandler/ResourceGroupRestHandler.go b/api/restHandler/ResourceGroupRestHandler.go index 735f05d563..6a8fa991c0 100644 --- a/api/restHandler/ResourceGroupRestHandler.go +++ b/api/restHandler/ResourceGroupRestHandler.go @@ -103,7 +103,7 @@ func (handler ResourceGroupRestHandlerImpl) GetActiveResourceGroupList(w http.Re // func (handler ResourceGroupRestHandlerImpl) GetApplicationsForResourceGroup(w http.ResponseWriter, r *http.Request) { // userId, err := handler.userService.GetLoggedInUser(r) // if userId == 0 || err != nil { -// common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) +// common.HandleUnauthorized(w, r) // return // } // token := r.Header.Get("token") @@ -129,7 +129,7 @@ func (handler ResourceGroupRestHandlerImpl) CreateResourceGroup(w http.ResponseW token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -193,7 +193,7 @@ func (handler ResourceGroupRestHandlerImpl) UpdateResourceGroup(w http.ResponseW token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -266,7 +266,7 @@ func (handler ResourceGroupRestHandlerImpl) CheckResourceGroupPermissions(w http userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/restHandler/TelemetryRestHandler.go b/api/restHandler/TelemetryRestHandler.go index 4894132a87..2a16472e2a 100644 --- a/api/restHandler/TelemetryRestHandler.go +++ b/api/restHandler/TelemetryRestHandler.go @@ -65,7 +65,7 @@ func (handler TelemetryRestHandlerImpl) GetTelemetryMetaInfo(w http.ResponseWrit func (handler TelemetryRestHandlerImpl) SendTelemetryData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) diff --git a/api/restHandler/UserAttributesRestHandler.go b/api/restHandler/UserAttributesRestHandler.go index 3a2187677b..e88dee6e5a 100644 --- a/api/restHandler/UserAttributesRestHandler.go +++ b/api/restHandler/UserAttributesRestHandler.go @@ -112,7 +112,7 @@ func (handler *UserAttributesRestHandlerImpl) PatchUserAttributes(w http.Respons func (handler *UserAttributesRestHandlerImpl) validateUserAttributesRequest(w http.ResponseWriter, r *http.Request, operation string) (*bean.UserAttributesDto, bool) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return nil, false } @@ -147,7 +147,7 @@ func (handler *UserAttributesRestHandlerImpl) validateUserAttributesRequest(w ht func (handler *UserAttributesRestHandlerImpl) GetUserAttribute(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/WebhookEventHandler.go b/api/restHandler/WebhookEventHandler.go index 922a53ad8f..d8ca3bd844 100644 --- a/api/restHandler/WebhookEventHandler.go +++ b/api/restHandler/WebhookEventHandler.go @@ -69,23 +69,27 @@ func (impl WebhookEventHandlerImpl) OnWebhookEvent(w http.ResponseWriter, r *htt var err error var gitHostName string var gitHost *bean3.GitHostRequest + + // Try to parse gitHostId as integer first, fallback to name-based lookup if gitHostId, err = strconv.Atoi(vars["gitHostId"]); err != nil { gitHostName = vars["gitHostId"] - // get git host from DB + // get git host from DB by name gitHost, err = impl.gitHostReadService.GetByName(gitHostName) if err != nil { - impl.logger.Errorw("Error in getting git host from DB by Name", "err", err, "gitHostName", gitHostName) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Git host not found by name", "err", err, "gitHostName", gitHostName) + // Use enhanced error handling with resource context + common.WriteJsonRespWithResourceContext(w, err, nil, 0, "git host", gitHostName) return } gitHostId = gitHost.Id } else { - // get git host from DB + // get git host from DB by ID gitHost, err = impl.gitHostReadService.GetById(gitHostId) if err != nil { - impl.logger.Errorw("Error in getting git host from DB by Id", "err", err, "gitHostId", gitHostId) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Git host not found by ID", "err", err, "gitHostId", gitHostId) + // Use enhanced error handling with resource context + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "git host", gitHostId) return } } diff --git a/api/restHandler/app/appInfo/AppInfoRestHandler.go b/api/restHandler/app/appInfo/AppInfoRestHandler.go index e6ba47a5a8..b389ae364a 100644 --- a/api/restHandler/app/appInfo/AppInfoRestHandler.go +++ b/api/restHandler/app/appInfo/AppInfoRestHandler.go @@ -84,7 +84,7 @@ func NewAppInfoRestHandlerImpl(logger *zap.SugaredLogger, appService app.AppCrud func (handler AppInfoRestHandlerImpl) GetAllLabels(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } propagatedLabelsOnlyStr := r.URL.Query().Get("showPropagatedOnly") @@ -122,14 +122,13 @@ func (handler AppInfoRestHandlerImpl) GetAllLabels(w http.ResponseWriter, r *htt func (handler AppInfoRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } - vars := mux.Vars(r) - appId, err := strconv.Atoi(vars["appId"]) + // Use enhanced parameter parsing with context + appId, err := common.ExtractIntPathParamWithContext(w, r, "appId", "application") if err != nil { - handler.logger.Errorw("request err, GetAppMetaInfo", "err", err, "appId", appId) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } @@ -155,7 +154,7 @@ func (handler AppInfoRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *h func (handler AppInfoRestHandlerImpl) GetHelmAppMetaInfo(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -208,7 +207,7 @@ func (handler AppInfoRestHandlerImpl) GetHelmAppMetaInfo(w http.ResponseWriter, func (handler AppInfoRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -262,7 +261,7 @@ func (handler AppInfoRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.R func (handler AppInfoRestHandlerImpl) UpdateProjectForApps(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -306,7 +305,7 @@ func (handler AppInfoRestHandlerImpl) UpdateProjectForApps(w http.ResponseWriter func (handler AppInfoRestHandlerImpl) GetAppListByTeamIds(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } //vars := mux.Vars(r) @@ -349,7 +348,7 @@ func (handler AppInfoRestHandlerImpl) UpdateAppNote(w http.ResponseWriter, r *ht userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { handler.logger.Errorw("service err, Update", "error", err, "userId", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean repository.GenericNote diff --git a/api/restHandler/app/appList/AppFilteringRestHandler.go b/api/restHandler/app/appList/AppFilteringRestHandler.go index bff8f84a06..ba28ef4d92 100644 --- a/api/restHandler/app/appList/AppFilteringRestHandler.go +++ b/api/restHandler/app/appList/AppFilteringRestHandler.go @@ -82,7 +82,7 @@ func NewAppFilteringRestHandlerImpl(logger *zap.SugaredLogger, func (handler AppFilteringRestHandlerImpl) GetClusterTeamAndEnvListForAutocomplete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } clusterMapping := make(map[string]bean3.ClusterBean) diff --git a/api/restHandler/app/appList/AppListingRestHandler.go b/api/restHandler/app/appList/AppListingRestHandler.go index 8f52a64b9c..8c15bee342 100644 --- a/api/restHandler/app/appList/AppListingRestHandler.go +++ b/api/restHandler/app/appList/AppListingRestHandler.go @@ -149,7 +149,7 @@ func (handler AppListingRestHandlerImpl) FetchAllDevtronManagedApps(w http.Respo token := r.Header.Get("token") userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } handler.logger.Infow("got request to fetch all devtron managed apps ", "userId", userId) @@ -168,7 +168,7 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { handler.logger.Errorw("request err, userId", "err", err, "payload", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -241,7 +241,7 @@ func (handler AppListingRestHandlerImpl) FetchJobOverviewCiPipelines(w http.Resp userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { handler.logger.Errorw("request err, userId", "err", err, "payload", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -287,7 +287,7 @@ func (handler AppListingRestHandlerImpl) FetchAppsByEnvironmentV2(w http.Respons userId, err := handler.userService.GetLoggedInUser(r) span.End() if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } newCtx, span = otel.Tracer("userService").Start(newCtx, "GetById") @@ -411,7 +411,7 @@ func (handler AppListingRestHandlerImpl) FetchOverviewAppsByEnvironment(w http.R vars := mux.Vars(r) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -475,7 +475,7 @@ func (handler AppListingRestHandlerImpl) FetchOverviewAppsByEnvironment(w http.R func (handler AppListingRestHandlerImpl) FetchAppDetailsV2(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go b/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go index b7030aa496..bf6b099ef2 100644 --- a/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go +++ b/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go @@ -50,7 +50,7 @@ func NewDeploymentConfigurationRestHandlerImpl(logger *zap.SugaredLogger, func (handler *DeploymentConfigurationRestHandlerImpl) ConfigAutoComplete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } appId, err := common.ExtractIntQueryParam(w, r, "appId", 0) @@ -84,7 +84,7 @@ func (handler *DeploymentConfigurationRestHandlerImpl) ConfigAutoComplete(w http func (handler *DeploymentConfigurationRestHandlerImpl) GetConfigData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } configDataQueryParams, err := getConfigDataQueryParams(r) @@ -122,7 +122,7 @@ func (handler *DeploymentConfigurationRestHandlerImpl) GetConfigData(w http.Resp func (handler *DeploymentConfigurationRestHandlerImpl) GetManifest(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -191,7 +191,7 @@ func getConfigDataQueryParams(r *http.Request) (*bean.ConfigDataQueryParams, err func (handler *DeploymentConfigurationRestHandlerImpl) CompareCategoryWiseConfigData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/app/pipeline/AutoCompleteRestHandler.go b/api/restHandler/app/pipeline/AutoCompleteRestHandler.go index 8bae0d4b8e..ee4895af9a 100644 --- a/api/restHandler/app/pipeline/AutoCompleteRestHandler.go +++ b/api/restHandler/app/pipeline/AutoCompleteRestHandler.go @@ -85,7 +85,7 @@ func NewDevtronAppAutoCompleteRestHandlerImpl( func (handler DevtronAppAutoCompleteRestHandlerImpl) GetAppListForAutocomplete(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -244,10 +244,10 @@ func (handler DevtronAppAutoCompleteRestHandlerImpl) GitListAutocomplete(w http. func (handler DevtronAppAutoCompleteRestHandlerImpl) RegistriesListAutocomplete(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") - vars := mux.Vars(r) - appId, err := strconv.Atoi(vars["appId"]) + // Use enhanced parameter parsing with context + appId, err := common.ExtractIntPathParamWithContext(w, r, "appId", "application") if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } v := r.URL.Query() diff --git a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go index d0172e714a..dded6fd4a2 100644 --- a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go +++ b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go @@ -21,6 +21,12 @@ import ( "encoding/json" "errors" "fmt" + "io" + "net/http" + "regexp" + "strconv" + "strings" + apiBean "github.com/devtron-labs/devtron/api/restHandler/app/pipeline/configure/bean" "github.com/devtron-labs/devtron/internal/sql/constants" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" @@ -29,11 +35,6 @@ import ( constants2 "github.com/devtron-labs/devtron/pkg/pipeline/constants" "github.com/devtron-labs/devtron/util/stringsUtil" "golang.org/x/exp/maps" - "io" - "net/http" - "regexp" - "strconv" - "strings" "github.com/devtron-labs/devtron/util/response/pagination" "github.com/gorilla/schema" @@ -240,7 +241,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateBranchCiPipelinesWithRegex(w func (handler *PipelineConfigRestHandlerImpl) parseSourceChangeRequest(w http.ResponseWriter, r *http.Request) (*bean.CiMaterialPatchRequest, int32, error) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return nil, 0, err } @@ -259,7 +260,7 @@ func (handler *PipelineConfigRestHandlerImpl) parseSourceChangeRequest(w http.Re func (handler *PipelineConfigRestHandlerImpl) parseBulkSourceChangeRequest(w http.ResponseWriter, r *http.Request) (*bean.CiMaterialBulkPatchRequest, int32, error) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return nil, 0, err } @@ -358,7 +359,7 @@ func (handler *PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var patchRequest bean.CiPatchRequest @@ -683,19 +684,25 @@ func (handler *PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseW return } + // Validate required fields + if ciTriggerRequest.PipelineId == 0 { + common.WriteMissingRequiredFieldError(w, "pipelineId") + return + } + token := r.Header.Get("token") // RBAC block starts err := handler.validateCiTriggerRBAC(token, ciTriggerRequest.PipelineId, ciTriggerRequest.EnvironmentId) if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + handler.Logger.Errorw("RBAC validation failed for CI trigger", "err", err, "pipelineId", ciTriggerRequest.PipelineId) + common.WriteForbiddenError(w, "trigger", "CI pipeline") return } // RBAC block ends if !handler.validForMultiMaterial(ciTriggerRequest) { handler.Logger.Errorw("invalid req, commit hash not present for multi-git", "payload", ciTriggerRequest) - common.WriteJsonResp(w, errors.New("invalid req, commit hash not present for multi-git"), - nil, http.StatusBadRequest) + common.WriteValidationError(w, "ciPipelineMaterials", "Commit hash is required for multi-git repositories") return } @@ -706,18 +713,18 @@ func (handler *PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseW resp, err := handler.ciHandlerService.HandleCIManual(ciTriggerRequest) if errors.Is(err, bean1.ErrImagePathInUse) { handler.Logger.Errorw("service err duplicate image tag, TriggerCiPipeline", "err", err, "payload", ciTriggerRequest) - common.WriteJsonResp(w, err, err, http.StatusConflict) + common.WriteSpecificErrorResponse(w, "IMAGE_TAG_IN_USE", "Image tag is already in use", []string{"The specified image tag is already being used by another pipeline"}, http.StatusConflict) return } if err != nil { handler.Logger.Errorw("service err, TriggerCiPipeline", "err", err, "payload", ciTriggerRequest) - common.WriteJsonResp(w, err, response, http.StatusInternalServerError) + common.WriteSpecificErrorResponse(w, "CI_TRIGGER_FAILED", "Failed to trigger CI pipeline", []string{err.Error()}, http.StatusInternalServerError) return } response["apiResponse"] = strconv.Itoa(resp) - common.WriteJsonResp(w, err, response, http.StatusOK) + common.WriteJsonResp(w, nil, response, http.StatusOK) } func (handler *PipelineConfigRestHandlerImpl) FetchMaterials(w http.ResponseWriter, r *http.Request) { @@ -740,7 +747,12 @@ func (handler *PipelineConfigRestHandlerImpl) FetchMaterials(w http.ResponseWrit ciPipeline, err := handler.ciPipelineRepository.FindById(pipelineId) if err != nil { handler.Logger.Errorw("service err, FindById", "err", err, "pipelineId", pipelineId) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + // Check if it's a "not found" error + if util.IsErrNoRows(err) { + common.WritePipelineNotFoundError(w, pipelineId) + } else { + common.WriteDatabaseError(w, "fetch CI pipeline", err) + } return } @@ -753,7 +765,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchMaterials(w http.ResponseWrit resp, err := handler.ciHandler.FetchMaterialsByPipelineId(pipelineId, showAll) if err != nil { handler.Logger.Errorw("service err", "err", err, "context", "FetchMaterials", "data", map[string]interface{}{"pipelineId": pipelineId}) - common.WriteJsonResp(w, err, resp, http.StatusInternalServerError) + common.WriteSpecificErrorResponse(w, "FETCH_MATERIALS_FAILED", "Failed to fetch materials for pipeline", []string{err.Error()}, http.StatusInternalServerError) return } common.WriteJsonResp(w, nil, resp, http.StatusOK) @@ -991,7 +1003,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetHistoricBuildLogs(w http.Respon func (handler *PipelineConfigRestHandlerImpl) GetBuildHistory(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1078,7 +1090,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildHistory(w http.ResponseWri func (handler *PipelineConfigRestHandlerImpl) GetBuildLogs(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1157,7 +1169,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildLogs(w http.ResponseWriter func (handler *PipelineConfigRestHandlerImpl) FetchMaterialInfo(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1320,7 +1332,7 @@ func (handler *PipelineConfigRestHandlerImpl) CreateMaterial(w http.ResponseWrit decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var createMaterialDto bean.CreateMaterialDTO @@ -1373,7 +1385,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateMaterial(w http.ResponseWrit decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var updateMaterialDto bean.UpdateMaterialDTO @@ -1423,7 +1435,7 @@ func (handler *PipelineConfigRestHandlerImpl) DeleteMaterial(w http.ResponseWrit decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var deleteMaterial bean.UpdateMaterialDTO @@ -1506,7 +1518,7 @@ func (handler *PipelineConfigRestHandlerImpl) ValidateGitMaterialUrl(gitProvider func (handler *PipelineConfigRestHandlerImpl) CancelWorkflow(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } queryVars := r.URL.Query() @@ -1590,7 +1602,7 @@ func (handler *PipelineConfigRestHandlerImpl) CancelWorkflow(w http.ResponseWrit func (handler *PipelineConfigRestHandlerImpl) FetchChanges(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1648,7 +1660,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchChanges(w http.ResponseWriter func (handler *PipelineConfigRestHandlerImpl) GetCommitMetadataForPipelineMaterial(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1694,7 +1706,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCommitMetadataForPipelineMateri func (handler *PipelineConfigRestHandlerImpl) FetchWorkflowDetails(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1745,7 +1757,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchWorkflowDetails(w http.Respon func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForCiJob(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1792,7 +1804,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCiPipelineByEnvironment(w http. token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) @@ -1850,7 +1862,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCiPipelineByEnvironmentMin(w ht token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) @@ -1907,7 +1919,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetExternalCiByEnvironment(w http. token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) @@ -1964,7 +1976,7 @@ func (handler *PipelineConfigRestHandlerImpl) CreateUpdateImageTagging(w http.Re token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } isSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionCreate, "*") @@ -2057,7 +2069,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetImageTaggingData(w http.Respons token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } artifactId, err := strconv.Atoi(vars["artifactId"]) @@ -2169,7 +2181,7 @@ func (handler *PipelineConfigRestHandlerImpl) checkAppSpecificAccess(token, acti func (handler *PipelineConfigRestHandlerImpl) GetSourceCiDownStreamFilters(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -2206,7 +2218,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetSourceCiDownStreamInfo(w http.R decoder := schema.NewDecoder() userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -2262,7 +2274,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetAppMetadataListByEnvironment(w token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) diff --git a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandlerHelper.go b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandlerHelper.go index d3bbd75d0f..cd06626581 100644 --- a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandlerHelper.go +++ b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandlerHelper.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" + "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/bean" "net/http" @@ -33,18 +34,27 @@ import ( func (handler *PipelineConfigRestHandlerImpl) getUserIdOrUnauthorized(w http.ResponseWriter, r *http.Request) (int32, bool) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return 0, false } return userId, true } // getIntPathParam gets an integer path parameter from the request +// DEPRECATED: Use common.ExtractIntPathParamWithContext() for new code func (handler *PipelineConfigRestHandlerImpl) getIntPathParam(w http.ResponseWriter, vars map[string]string, paramName string) (int, bool) { paramValue, err := strconv.Atoi(vars[paramName]) if err != nil { - handler.Logger.Errorw("request err, invalid path param", "err", err, "paramName", paramName) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Use enhanced error handling + apiErr := util.NewInvalidPathParameterError(paramName, vars[paramName]) + handler.Logger.Errorw("Invalid path parameter", "paramName", paramName, "paramValue", vars[paramName], "err", err) + common.WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) + return 0, false + } + if paramValue <= 0 { + apiErr := util.NewValidationErrorForField(paramName, "must be a positive integer") + handler.Logger.Errorw("Invalid path parameter value", "paramName", paramName, "paramValue", paramValue) + common.WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) return 0, false } return paramValue, true diff --git a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go index 04124d8221..552027152b 100644 --- a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go +++ b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go @@ -127,7 +127,7 @@ func (handler *PipelineConfigRestHandlerImpl) ConfigureDeploymentTemplateForApp( decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var templateRequest bean3.TemplateRequest @@ -194,7 +194,7 @@ func (handler *PipelineConfigRestHandlerImpl) CreateCdPipeline(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var cdPipeline bean.CdPipelines @@ -280,7 +280,7 @@ func (handler *PipelineConfigRestHandlerImpl) PatchCdPipeline(w http.ResponseWri decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var cdPipeline bean.CDPatchRequest @@ -373,7 +373,7 @@ func (handler *PipelineConfigRestHandlerImpl) HandleChangeDeploymentRequest(w ht // Auth check userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -436,7 +436,7 @@ func (handler *PipelineConfigRestHandlerImpl) HandleChangeDeploymentTypeRequest( userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -491,7 +491,7 @@ func (handler *PipelineConfigRestHandlerImpl) HandleTriggerDeploymentAfterTypeCh userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -548,7 +548,7 @@ func (handler *PipelineConfigRestHandlerImpl) HandleTriggerDeploymentAfterTypeCh func (handler *PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -618,7 +618,7 @@ func (handler *PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWrit func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideCreate(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -696,7 +696,7 @@ func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideUpdate(w http.Res // userId := getLoggedInUser(r) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var envConfigProperties pipelineBean.EnvironmentProperties @@ -810,7 +810,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetTemplateComparisonMetadata(w ht vars := mux.Vars(r) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -865,7 +865,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentTemplateData(w http.R userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { handler.Logger.Errorw("request err, userId", "err", err, "payload", userId) - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } isSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*") @@ -887,7 +887,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentTemplateData(w http.R func (handler *PipelineConfigRestHandlerImpl) GetRestartWorkloadData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := common.ExtractIntQueryParam(w, r, "envId", 0) @@ -1097,7 +1097,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1297,7 +1297,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateAppOverride(w http.ResponseW decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -1363,7 +1363,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateAppOverride(w http.ResponseW func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1449,7 +1449,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.Res func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideReset(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1508,7 +1508,7 @@ func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideReset(w http.Resp func (handler *PipelineConfigRestHandlerImpl) ListDeploymentHistory(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1583,7 +1583,7 @@ func (handler *PipelineConfigRestHandlerImpl) ListDeploymentHistory(w http.Respo func (handler *PipelineConfigRestHandlerImpl) GetPrePostDeploymentLogs(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1667,7 +1667,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetPrePostDeploymentLogs(w http.Re func (handler *PipelineConfigRestHandlerImpl) FetchCdWorkflowDetails(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1719,7 +1719,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchCdWorkflowDetails(w http.Resp func (handler *PipelineConfigRestHandlerImpl) DownloadArtifacts(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1779,7 +1779,7 @@ func (handler *PipelineConfigRestHandlerImpl) DownloadArtifacts(w http.ResponseW func (handler *PipelineConfigRestHandlerImpl) GetStageStatus(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -1826,7 +1826,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetStageStatus(w http.ResponseWrit func (handler *PipelineConfigRestHandlerImpl) GetConfigmapSecretsForDeploymentStages(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -1898,7 +1898,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelineById(w http.ResponseW func (handler *PipelineConfigRestHandlerImpl) CancelStage(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -2013,7 +2013,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetDefaultDeploymentPipelineStrate func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideCreateNamespace(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -2106,7 +2106,7 @@ func (handler *PipelineConfigRestHandlerImpl) IsReadyToTrigger(w http.ResponseWr func (handler *PipelineConfigRestHandlerImpl) UpgradeForAllApps(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -2211,7 +2211,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelinesByEnvironment(w http token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) @@ -2268,7 +2268,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelinesByEnvironmentMin(w h vars := mux.Vars(r) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -2339,7 +2339,7 @@ func (handler *PipelineConfigRestHandlerImpl) SaveGitOpsConfiguration(w http.Res decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var appGitOpsConfigRequest devtronAppGitOpConfigBean.AppGitOpsConfigRequest @@ -2387,7 +2387,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetGitOpsConfiguration(w http.Resp userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -2446,7 +2446,7 @@ func (handler *PipelineConfigRestHandlerImpl) ValidateExternalAppLinkRequest(w h decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var request pipelineBean.MigrateReleaseValidationRequest diff --git a/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go b/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go index 74ecde9387..ab8a097f6f 100644 --- a/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go +++ b/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go @@ -241,7 +241,7 @@ func (handler *PipelineConfigRestHandlerImpl) DeleteApp(w http.ResponseWriter, r token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -283,7 +283,7 @@ func (handler *PipelineConfigRestHandlerImpl) DeleteACDAppWithNonCascade(w http. token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -358,7 +358,7 @@ func (handler *PipelineConfigRestHandlerImpl) CreateApp(w http.ResponseWriter, r decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var createRequest bean.CreateAppDTO @@ -591,7 +591,7 @@ func (handler *PipelineConfigRestHandlerImpl) sendData(event []byte, w http.Resp func (handler *PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerView(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -691,7 +691,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerVi token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -808,7 +808,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetApplicationsByEnvironment(w htt token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } envId, err := strconv.Atoi(vars["envId"]) @@ -862,7 +862,7 @@ func (handler *PipelineConfigRestHandlerImpl) FetchAppDeploymentStatusForEnviron token := r.Header.Get("token") userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/app/pipeline/history/PipelineHistoryRestHandler.go b/api/restHandler/app/pipeline/history/PipelineHistoryRestHandler.go index 7a759af09c..d454cb4452 100644 --- a/api/restHandler/app/pipeline/history/PipelineHistoryRestHandler.go +++ b/api/restHandler/app/pipeline/history/PipelineHistoryRestHandler.go @@ -79,7 +79,7 @@ func NewPipelineHistoryRestHandlerImpl(logger *zap.SugaredLogger, userAuthServic func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedConfigurationsForWorkflow(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -124,7 +124,7 @@ func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedConfigurationsForWor func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedHistoryComponentList(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -183,7 +183,7 @@ func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedHistoryComponentList func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedHistoryComponentDetail(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -246,7 +246,7 @@ func (handler *PipelineHistoryRestHandlerImpl) FetchDeployedHistoryComponentDeta func (handler *PipelineHistoryRestHandlerImpl) GetAllDeployedConfigurationHistoryForLatestWfrIdForPipeline(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -290,7 +290,7 @@ func (handler *PipelineHistoryRestHandlerImpl) GetAllDeployedConfigurationHistor // trigger is mapped by wfr (help for method name) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) diff --git a/api/restHandler/app/pipeline/status/PipelineStatusTimelineRestHandler.go b/api/restHandler/app/pipeline/status/PipelineStatusTimelineRestHandler.go index 0d1f5cc6a0..1ab1865af1 100644 --- a/api/restHandler/app/pipeline/status/PipelineStatusTimelineRestHandler.go +++ b/api/restHandler/app/pipeline/status/PipelineStatusTimelineRestHandler.go @@ -117,7 +117,7 @@ func (handler *PipelineStatusTimelineRestHandlerImpl) ManualSyncAcdPipelineDeplo vars := mux.Vars(r) userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } appId, err := strconv.Atoi(vars["appId"]) diff --git a/api/restHandler/app/pipeline/trigger/PipelineTriggerRestHandler.go b/api/restHandler/app/pipeline/trigger/PipelineTriggerRestHandler.go index d7a7e1015f..6adbe072ec 100644 --- a/api/restHandler/app/pipeline/trigger/PipelineTriggerRestHandler.go +++ b/api/restHandler/app/pipeline/trigger/PipelineTriggerRestHandler.go @@ -113,7 +113,7 @@ func (handler PipelineTriggerRestHandlerImpl) OverrideConfig(w http.ResponseWrit decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var overrideRequest bean.ValuesOverrideRequest @@ -163,7 +163,7 @@ func (handler PipelineTriggerRestHandlerImpl) RotatePods(w http.ResponseWriter, decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var podRotateRequest bean2.PodRotateRequest @@ -212,7 +212,7 @@ func (handler PipelineTriggerRestHandlerImpl) StartStopApp(w http.ResponseWriter decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var overrideRequest bean2.StopAppRequest @@ -266,7 +266,7 @@ func (handler PipelineTriggerRestHandlerImpl) StartStopDeploymentGroup(w http.Re userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var stopDeploymentGroupRequest bean4.StopDeploymentGroupRequest @@ -325,7 +325,7 @@ func (handler PipelineTriggerRestHandlerImpl) ReleaseStatusUpdate(w http.Respons decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var releaseStatusUpdateRequest bean.ReleaseStatusUpdateRequest @@ -354,7 +354,7 @@ func (handler PipelineTriggerRestHandlerImpl) ReleaseStatusUpdate(w http.Respons func (handler PipelineTriggerRestHandlerImpl) GetAllLatestDeploymentConfiguration(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } handler.logger.Infow("request payload, GetAllLatestDeploymentConfiguration") diff --git a/api/restHandler/app/pipeline/webhook/WebhookDataRestHandler.go b/api/restHandler/app/pipeline/webhook/WebhookDataRestHandler.go index b0cf40a3a2..bd05afb624 100644 --- a/api/restHandler/app/pipeline/webhook/WebhookDataRestHandler.go +++ b/api/restHandler/app/pipeline/webhook/WebhookDataRestHandler.go @@ -65,7 +65,7 @@ func (impl WebhookDataRestHandlerImpl) GetWebhookPayloadDataForPipelineMaterialI userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } @@ -134,7 +134,7 @@ func (impl WebhookDataRestHandlerImpl) GetWebhookPayloadFilterDataForPipelineMat userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/app/workflow/AppWorkflowRestHandler.go b/api/restHandler/app/workflow/AppWorkflowRestHandler.go index b4251d2630..bcad863c97 100644 --- a/api/restHandler/app/workflow/AppWorkflowRestHandler.go +++ b/api/restHandler/app/workflow/AppWorkflowRestHandler.go @@ -306,7 +306,7 @@ func (impl AppWorkflowRestHandlerImpl) FindAllWorkflowsForApps(w http.ResponseWr decoder := json.NewDecoder(r.Body) userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } token := r.Header.Get("token") @@ -337,7 +337,7 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflowByEnvironment(w http.Respo token := r.Header.Get("token") userId, err := impl.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/restHandler/common/EnhancedErrorResponse.go b/api/restHandler/common/EnhancedErrorResponse.go new file mode 100644 index 0000000000..d70109adc0 --- /dev/null +++ b/api/restHandler/common/EnhancedErrorResponse.go @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "github.com/devtron-labs/devtron/api/middleware" + "github.com/devtron-labs/devtron/internal/util" + "net/http" + "strconv" +) + +// ErrorResponseBuilder provides a fluent interface for building error responses +type ErrorResponseBuilder struct { + request *http.Request + writer http.ResponseWriter + operation string + resourceType string + resourceID string +} + +// NewErrorResponseBuilder creates a new error response builder +func NewErrorResponseBuilder(w http.ResponseWriter, r *http.Request) *ErrorResponseBuilder { + // Try to extract resource context from request + reqCtx := middleware.GetRequestContext(r) + resourceType := "" + resourceID := "" + + if reqCtx != nil { + resourceType = reqCtx.ResourceType + resourceID = reqCtx.ResourceID + } + + return &ErrorResponseBuilder{ + request: r, + writer: w, + resourceType: resourceType, + resourceID: resourceID, + } +} + +// WithOperation sets the operation context for better error messages +func (erb *ErrorResponseBuilder) WithOperation(operation string) *ErrorResponseBuilder { + erb.operation = operation + return erb +} + +// WithResource sets the resource context for better error messages +func (erb *ErrorResponseBuilder) WithResource(resourceType, resourceID string) *ErrorResponseBuilder { + erb.resourceType = resourceType + erb.resourceID = resourceID + return erb +} + +// WithResourceFromId sets the resource context with an integer ID +func (erb *ErrorResponseBuilder) WithResourceFromId(resourceType string, resourceID int) *ErrorResponseBuilder { + erb.resourceType = resourceType + erb.resourceID = strconv.Itoa(resourceID) + return erb +} + +// HandleError processes an error and writes an appropriate response +func (erb *ErrorResponseBuilder) HandleError(err error) { + if err == nil { + return + } + + // If it's already an ApiError, use it directly + if apiErr, ok := err.(*util.ApiError); ok { + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) + return + } + + // Handle database errors + if util.IsErrNoRows(err) { + if erb.resourceType != "" && erb.resourceID != "" { + apiErr := util.NewResourceNotFoundError(erb.resourceType, erb.resourceID) + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) + } else { + apiErr := util.NewGenericResourceNotFoundError() + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) + } + return + } + + // Handle validation errors + if isValidationError(err) { + apiErr := util.NewApiError(http.StatusBadRequest, "Validation failed", err.Error()). + WithCode("11004") + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) + return + } + + // Handle business logic errors (check for common patterns) + if isBusinessLogicError(err) { + apiErr := util.NewApiError(http.StatusConflict, "Operation failed", err.Error()). + WithCode("11008") + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) + return + } + + // Default to internal server error + operation := erb.operation + if operation == "" { + operation = "operation" + } + + apiErr := util.NewApiError(http.StatusInternalServerError, + fmt.Sprintf("Internal server error during %s", operation), + err.Error()).WithCode("11009") + WriteJsonResp(erb.writer, apiErr, nil, apiErr.HttpStatusCode) +} + +// HandleSuccess writes a successful response +func (erb *ErrorResponseBuilder) HandleSuccess(data interface{}) { + WriteJsonResp(erb.writer, nil, data, http.StatusOK) +} + +// isValidationError checks if the error is a validation error +func isValidationError(err error) bool { + errMsg := err.Error() + // Common validation error patterns + validationPatterns := []string{ + "validation failed", + "invalid input", + "required field", + "invalid format", + "constraint violation", + } + + for _, pattern := range validationPatterns { + if contains(errMsg, pattern) { + return true + } + } + return false +} + +// isBusinessLogicError checks if the error is a business logic error +func isBusinessLogicError(err error) bool { + errMsg := err.Error() + // Common business logic error patterns + businessPatterns := []string{ + "already exists", + "duplicate", + "conflict", + "not allowed", + "permission denied", + "unauthorized", + "forbidden", + } + + for _, pattern := range businessPatterns { + if contains(errMsg, pattern) { + return true + } + } + return false +} + +// contains checks if a string contains a substring (case-insensitive) +func contains(s, substr string) bool { + return len(s) >= len(substr) && + (s == substr || + (len(s) > len(substr) && + (s[:len(substr)] == substr || + s[len(s)-len(substr):] == substr || + containsSubstring(s, substr)))) +} + +// containsSubstring checks if a string contains a substring anywhere +func containsSubstring(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} + +// Convenience functions for common error scenarios + +// HandleParameterError handles path parameter validation errors +func HandleParameterError(w http.ResponseWriter, r *http.Request, paramName, paramValue string) { + apiErr := util.NewInvalidPathParameterError(paramName, paramValue) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +// HandleResourceNotFound handles resource not found errors +func HandleResourceNotFound(w http.ResponseWriter, r *http.Request, resourceType, resourceID string) { + apiErr := util.NewResourceNotFoundError(resourceType, resourceID) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +// HandleUnauthorized handles unauthorized access errors +func HandleUnauthorized(w http.ResponseWriter, r *http.Request) { + apiErr := util.NewApiError(http.StatusUnauthorized, "Unauthorized access", "unauthorized"). + WithCode("11010") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +// HandleForbidden handles forbidden access errors +func HandleForbidden(w http.ResponseWriter, r *http.Request, resource string) { + apiErr := util.NewApiError(http.StatusForbidden, + fmt.Sprintf("Access denied for %s", resource), + "forbidden").WithCode("11011") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +// HandleValidationError handles validation errors +func HandleValidationError(w http.ResponseWriter, r *http.Request, fieldName, message string) { + apiErr := util.NewValidationErrorForField(fieldName, message) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} diff --git a/api/restHandler/common/ParamParserUtils.go b/api/restHandler/common/ParamParserUtils.go index e4e60328e2..0d7b93c8ff 100644 --- a/api/restHandler/common/ParamParserUtils.go +++ b/api/restHandler/common/ParamParserUtils.go @@ -17,6 +17,7 @@ package common import ( + "github.com/devtron-labs/devtron/internal/util" "github.com/gorilla/mux" "net/http" "strconv" @@ -35,6 +36,17 @@ func ExtractIntPathParam(w http.ResponseWriter, r *http.Request, paramName strin return paramIntValue, nil } +// ExtractIntPathParamWithContext provides enhanced error messages with resource context +func ExtractIntPathParamWithContext(w http.ResponseWriter, r *http.Request, paramName string, resourceType string) (int, error) { + vars := mux.Vars(r) + paramValue := vars[paramName] + paramIntValue, err := convertToIntWithContext(w, paramValue, paramName, resourceType) + if err != nil { + return 0, err + } + return paramIntValue, nil +} + func convertToInt(w http.ResponseWriter, paramValue string) (int, error) { paramIntValue, err := strconv.Atoi(paramValue) if err != nil { @@ -44,6 +56,30 @@ func convertToInt(w http.ResponseWriter, paramValue string) (int, error) { return paramIntValue, nil } +// convertToIntWithContext provides better error messages for parameter conversion +func convertToIntWithContext(w http.ResponseWriter, paramValue, paramName, resourceType string) (int, error) { + if paramValue == "" { + apiErr := util.NewMissingRequiredFieldError(paramName) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) + return 0, apiErr + } + + paramIntValue, err := strconv.Atoi(paramValue) + if err != nil { + apiErr := util.NewInvalidPathParameterError(paramName, paramValue) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) + return 0, apiErr + } + + if paramIntValue <= 0 { + apiErr := util.NewValidationErrorForField(paramName, "must be a positive integer") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) + return 0, apiErr + } + + return paramIntValue, nil +} + func convertToIntArray(paramValue string) ([]int, error) { var paramValues []int splittedParamValues := strings.Split(paramValue, ",") diff --git a/api/restHandler/common/ResourceContextExtractor.go b/api/restHandler/common/ResourceContextExtractor.go new file mode 100644 index 0000000000..623e8bc02a --- /dev/null +++ b/api/restHandler/common/ResourceContextExtractor.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package common + +import ( + "fmt" + "github.com/devtron-labs/devtron/internal/util" + "net/http" + "strconv" + "strings" +) + +// extractResourceContext tries to extract resource type and ID from response body +func extractResourceContext(respBody interface{}) (resourceType, resourceId string) { + // Try to extract from response body if it contains context + if respBody == nil { + return "", "" + } + + // Check if respBody is a map with resource context + if contextMap, ok := respBody.(map[string]interface{}); ok { + if rt, exists := contextMap["resourceType"]; exists { + resourceType = fmt.Sprintf("%v", rt) + } + if ri, exists := contextMap["resourceId"]; exists { + resourceId = fmt.Sprintf("%v", ri) + } + } + + return resourceType, resourceId +} + +// WriteJsonRespWithResourceContext enhances error response with resource context +// This function provides better error messages for database errors by including resource context +func WriteJsonRespWithResourceContext(w http.ResponseWriter, err error, respBody interface{}, + status int, resourceType, resourceId string) { + + if err != nil && util.IsErrNoRows(err) { + // Override respBody with resource context for better error handling + respBody = map[string]interface{}{ + "resourceType": resourceType, + "resourceId": resourceId, + } + } + WriteJsonResp(w, err, respBody, status) +} + +// WriteJsonRespWithResourceContextFromId is a convenience function for integer IDs +func WriteJsonRespWithResourceContextFromId(w http.ResponseWriter, err error, respBody interface{}, + status int, resourceType string, resourceId int) { + WriteJsonRespWithResourceContext(w, err, respBody, status, resourceType, strconv.Itoa(resourceId)) +} + +// Convenience functions for common error scenarios (to fix build errors) +func WriteMissingRequiredFieldError(w http.ResponseWriter, fieldName string) { + apiErr := util.NewMissingRequiredFieldError(fieldName) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteForbiddenError(w http.ResponseWriter, operation string, resource string) { + apiErr := util.NewApiError(http.StatusForbidden, + fmt.Sprintf("Access denied for %s operation on %s", operation, resource), + "forbidden").WithCode("11008") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteValidationError(w http.ResponseWriter, fieldName string, message string) { + apiErr := util.NewValidationErrorForField(fieldName, message) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteSpecificErrorResponse(w http.ResponseWriter, errorCode string, message string, details []string, statusCode int) { + apiErr := util.NewApiError(statusCode, message, fmt.Sprintf("Error: %s", errorCode)). + WithCode(errorCode). + WithUserDetailMessage(fmt.Sprintf("Details: %s", strings.Join(details, "; "))) + WriteJsonResp(w, apiErr, nil, statusCode) +} + +func WritePipelineNotFoundError(w http.ResponseWriter, pipelineId int) { + apiErr := util.NewResourceNotFoundError("pipeline", strconv.Itoa(pipelineId)) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteDatabaseError(w http.ResponseWriter, operation string, err error) { + apiErr := util.NewApiError(http.StatusInternalServerError, + fmt.Sprintf("Database operation failed: %s", operation), + err.Error()).WithCode("11009") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteUnauthorizedError(w http.ResponseWriter) { + apiErr := util.NewApiError(http.StatusUnauthorized, "Unauthorized access", "unauthorized"). + WithCode("11010") + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} + +func WriteInvalidAppIdError(w http.ResponseWriter, appId string) { + apiErr := util.NewInvalidPathParameterError("appId", appId) + WriteJsonResp(w, apiErr, nil, apiErr.HttpStatusCode) +} diff --git a/api/restHandler/common/apiError.go b/api/restHandler/common/apiError.go index 7c1d4755c8..1ba6693827 100644 --- a/api/restHandler/common/apiError.go +++ b/api/restHandler/common/apiError.go @@ -52,15 +52,17 @@ func WriteJsonResp(w http.ResponseWriter, err error, respBody interface{}, statu response.Errors = valErrors } else if util.IsErrNoRows(err) { status = http.StatusNotFound - apiErr := &util.ApiError{} - apiErr.Code = "000" // 000=unknown - apiErr.InternalMessage = errors.Details(err) - if respBody != nil { - apiErr.UserMessage = respBody + // Try to extract resource context from respBody for better error messages + resourceType, resourceId := extractResourceContext(respBody) + if resourceType != "" && resourceId != "" { + // Create context-aware resource not found error + apiErr := util.NewResourceNotFoundError(resourceType, resourceId) + response.Errors = []*util.ApiError{apiErr} } else { - apiErr.UserMessage = err.Error() + // Fallback to generic not found error (no more "pg: no rows in result set") + apiErr := util.NewGenericResourceNotFoundError() + response.Errors = []*util.ApiError{apiErr} } - response.Errors = []*util.ApiError{apiErr} } else if multiErr, ok := err.(*multierror.Error); ok { var errorsResp []*util.ApiError for _, e := range multiErr.Errors { diff --git a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go index fdd1d60fc7..5a8ed20c4d 100644 --- a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go +++ b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go @@ -73,7 +73,7 @@ func (handler *ScopedVariableRestHandlerImpl) CreateVariables(w http.ResponseWri decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } request := models.VariableRequest{} @@ -168,7 +168,7 @@ func (handler *ScopedVariableRestHandlerImpl) GetScopedVariables(w http.Response func (handler *ScopedVariableRestHandlerImpl) GetJsonForVariables(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } // not logging bean object as it contains sensitive data diff --git a/api/server/ServerRestHandler.go b/api/server/ServerRestHandler.go index 2927d6448d..20bd951a65 100644 --- a/api/server/ServerRestHandler.go +++ b/api/server/ServerRestHandler.go @@ -62,7 +62,7 @@ func (impl ServerRestHandlerImpl) GetServerInfo(w http.ResponseWriter, r *http.R // check if user is logged in or not userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } showServerStatus := true @@ -89,7 +89,7 @@ func (impl ServerRestHandlerImpl) HandleServerAction(w http.ResponseWriter, r *h // check if user is logged in or not userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/team/TeamRestHandler.go b/api/team/TeamRestHandler.go index 136b8d7825..c99e967392 100644 --- a/api/team/TeamRestHandler.go +++ b/api/team/TeamRestHandler.go @@ -21,7 +21,6 @@ import ( "fmt" bean2 "github.com/devtron-labs/devtron/pkg/team/bean" "net/http" - "strconv" "strings" "time" @@ -32,7 +31,6 @@ import ( user2 "github.com/devtron-labs/devtron/pkg/auth/user" delete2 "github.com/devtron-labs/devtron/pkg/delete" "github.com/devtron-labs/devtron/pkg/team" - "github.com/gorilla/mux" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" ) @@ -91,7 +89,7 @@ func (impl TeamRestHandlerImpl) SaveTeam(w http.ResponseWriter, r *http.Request) decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean2.TeamRequest @@ -145,19 +143,18 @@ func (impl TeamRestHandlerImpl) FetchAll(w http.ResponseWriter, r *http.Request) } func (impl TeamRestHandlerImpl) FetchOne(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - id := params["id"] - idi, err := strconv.Atoi(id) + // Use enhanced parameter parsing with context + teamId, err := common.ExtractIntPathParamWithContext(w, r, "id", "team") if err != nil { - impl.logger.Errorw("request err, FetchOne", "err", err, "id", id) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + // Error already written by ExtractIntPathParamWithContext return } - res, err := impl.teamService.FetchOne(idi) + res, err := impl.teamService.FetchOne(teamId) if err != nil { - impl.logger.Errorw("service err, FetchOne", "err", err, "id", idi) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + impl.logger.Errorw("Failed to fetch team", "teamId", teamId, "err", err) + // Use enhanced error response with resource context + common.WriteJsonRespWithResourceContextFromId(w, err, nil, 0, "team", teamId) return } @@ -174,7 +171,7 @@ func (impl TeamRestHandlerImpl) UpdateTeam(w http.ResponseWriter, r *http.Reques decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var bean bean2.TeamRequest @@ -210,7 +207,7 @@ func (impl TeamRestHandlerImpl) DeleteTeam(w http.ResponseWriter, r *http.Reques decoder := json.NewDecoder(r.Body) userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } var deleteRequest bean2.TeamRequest @@ -247,7 +244,7 @@ func (impl TeamRestHandlerImpl) DeleteTeam(w http.ResponseWriter, r *http.Reques func (impl TeamRestHandlerImpl) FetchForAutocomplete(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } start := time.Now() diff --git a/api/terminal/UserTerminalAccessRestHandler.go b/api/terminal/UserTerminalAccessRestHandler.go index befa62e123..0d4f9ac570 100644 --- a/api/terminal/UserTerminalAccessRestHandler.go +++ b/api/terminal/UserTerminalAccessRestHandler.go @@ -77,7 +77,7 @@ func NewUserTerminalAccessRestHandlerImpl(logger *zap.SugaredLogger, userTermina func (handler UserTerminalAccessRestHandlerImpl) ValidateShell(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -113,7 +113,7 @@ func (handler UserTerminalAccessRestHandlerImpl) ValidateShell(w http.ResponseWr func (handler UserTerminalAccessRestHandlerImpl) StartTerminalSession(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -155,7 +155,7 @@ func (handler UserTerminalAccessRestHandlerImpl) StartTerminalSession(w http.Res func (handler UserTerminalAccessRestHandlerImpl) UpdateTerminalSession(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -197,7 +197,7 @@ func (handler UserTerminalAccessRestHandlerImpl) UpdateTerminalSession(w http.Re func (handler UserTerminalAccessRestHandlerImpl) UpdateTerminalShellSession(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -238,7 +238,7 @@ func (handler UserTerminalAccessRestHandlerImpl) UpdateTerminalShellSession(w ht func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalStatus(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -275,7 +275,7 @@ func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalStatus(w http.Resp func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalPodEvents(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -310,7 +310,7 @@ func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalPodEvents(w http.R func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalPodManifest(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -345,7 +345,7 @@ func (handler UserTerminalAccessRestHandlerImpl) FetchTerminalPodManifest(w http func (handler UserTerminalAccessRestHandlerImpl) DisconnectTerminalSession(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -379,7 +379,7 @@ func (handler UserTerminalAccessRestHandlerImpl) DisconnectTerminalSession(w htt func (handler UserTerminalAccessRestHandlerImpl) StopTerminalSession(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } vars := mux.Vars(r) @@ -408,7 +408,7 @@ func (handler UserTerminalAccessRestHandlerImpl) StopTerminalSession(w http.Resp func (handler UserTerminalAccessRestHandlerImpl) DisconnectAllTerminalSessionAndRetry(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } decoder := json.NewDecoder(r.Body) @@ -451,7 +451,7 @@ func (handler UserTerminalAccessRestHandlerImpl) DisconnectAllTerminalSessionAnd func (handler UserTerminalAccessRestHandlerImpl) EditPodManifest(w http.ResponseWriter, r *http.Request) { userId, err := handler.UserService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/api/userResource/UserResourceRestHandler.go b/api/userResource/UserResourceRestHandler.go index b410373ad5..84e3492793 100644 --- a/api/userResource/UserResourceRestHandler.go +++ b/api/userResource/UserResourceRestHandler.go @@ -34,7 +34,7 @@ func NewUserResourceRestHandler(logger *zap.SugaredLogger, func (handler *RestHandlerImpl) GetResourceOptions(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + common.HandleUnauthorized(w, r) return } diff --git a/internal/constants/InternalErrorCode.go b/internal/constants/InternalErrorCode.go index 70710974a5..48579d5eb0 100644 --- a/internal/constants/InternalErrorCode.go +++ b/internal/constants/InternalErrorCode.go @@ -169,6 +169,21 @@ const ( // Feasibility Errors End ---------------- ) +const ( + // Generic API Errors Start -------------- + // Sequence 11000-11999 + + InvalidPathParameter string = "11001" + InvalidRequestBody string = "11002" + InvalidQueryParameter string = "11003" + ValidationFailed string = "11004" + MissingRequiredField string = "11005" + ResourceNotFound string = "11006" + DuplicateResource string = "11007" + + // Generic API Errors End ---------------- +) + const ( // Not Processed Internal Errors Start --- // Sequence 11000-11999 diff --git a/internal/util/ResourceErrorFactory.go b/internal/util/ResourceErrorFactory.go new file mode 100644 index 0000000000..91042fef01 --- /dev/null +++ b/internal/util/ResourceErrorFactory.go @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + "fmt" + "github.com/devtron-labs/devtron/internal/constants" + "net/http" +) + +// ResourceContext holds information about the resource for better error messages +type ResourceContext struct { + ResourceType string + ResourceId string + Operation string +} + +// NewResourceNotFoundError creates a user-friendly error for resource not found scenarios +// Leverages existing util.NewApiError() function +func NewResourceNotFoundError(resourceType, resourceId string) *ApiError { + return NewApiError( + http.StatusNotFound, + fmt.Sprintf("%s with ID '%s' not found", resourceType, resourceId), + fmt.Sprintf("%s not found: %s", resourceType, resourceId), + ).WithCode(constants.ResourceNotFound). + WithUserDetailMessage(fmt.Sprintf("The requested %s does not exist or has been deleted.", resourceType)) +} + +// NewDuplicateResourceError creates a user-friendly error for duplicate resource scenarios +func NewDuplicateResourceError(resourceType, resourceName string) *ApiError { + return NewApiError( + http.StatusConflict, + fmt.Sprintf("%s with name '%s' already exists", resourceType, resourceName), + fmt.Sprintf("duplicate %s: %s", resourceType, resourceName), + ).WithCode(constants.DuplicateResource). + WithUserDetailMessage(fmt.Sprintf("A %s with this name already exists. Please choose a different name.", resourceType)) +} + +// NewValidationErrorForField creates a user-friendly error for field validation failures +func NewValidationErrorForField(fieldName, reason string) *ApiError { + return NewApiError( + http.StatusBadRequest, + fmt.Sprintf("Validation failed for field '%s': %s", fieldName, reason), + fmt.Sprintf("validation failed for %s: %s", fieldName, reason), + ).WithCode(constants.ValidationFailed). + WithUserDetailMessage("Please check the field value and try again.") +} + +// NewInvalidPathParameterError creates a user-friendly error for invalid path parameters +func NewInvalidPathParameterError(paramName, paramValue string) *ApiError { + return NewApiError( + http.StatusBadRequest, + fmt.Sprintf("Invalid path parameter '%s'", paramName), + fmt.Sprintf("invalid path parameter %s: %s", paramName, paramValue), + ).WithCode(constants.InvalidPathParameter). + WithUserDetailMessage("Please check the parameter format and try again.") +} + +// NewMissingRequiredFieldError creates a user-friendly error for missing required fields +func NewMissingRequiredFieldError(fieldName string) *ApiError { + return NewApiError( + http.StatusBadRequest, + fmt.Sprintf("Required field '%s' is missing", fieldName), + fmt.Sprintf("missing required field: %s", fieldName), + ).WithCode(constants.MissingRequiredField). + WithUserDetailMessage("Please provide all required fields and try again.") +} + +// NewGenericResourceNotFoundError creates a generic not found error when resource context is unknown +func NewGenericResourceNotFoundError() *ApiError { + return NewApiError( + http.StatusNotFound, + "Requested resource not found", + "resource not found", + ).WithCode(constants.ResourceNotFound). + WithUserDetailMessage("The requested resource does not exist or has been deleted.") +} diff --git a/specs/app-labels.yaml b/specs/app-labels.yaml deleted file mode 100644 index 6ed965f725..0000000000 --- a/specs/app-labels.yaml +++ /dev/null @@ -1,257 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: http://localhost/orchestrator - description: Local development server -security: - - ApiKeyAuth: [] -paths: - /orchestrator/app/labels/list: - get: - summary: List all app labels - description: This API will return all the labels available in the database. - operationId: listAppLabels - security: - - ApiKeyAuth: [] - parameters: [ ] - responses: - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - '200': - description: list response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - allOf: - - type: object - properties: - appId: - type: integer - description: unique application id - required: - - appId - - $ref: '#/components/schemas/AppLabel' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - - /orchestrator/app/meta/info/{appId}: - get: - summary: Get application meta info - description: Application basic info, projects and labels - operationId: getAppMetaInfo - security: - - ApiKeyAuth: [] - parameters: - - name: appId - in: path - description: application id - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: application basic info, projects and labels - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: meta info project name and labels - $ref: '#/components/schemas/AppMetaInfo' - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - /orchestrator/helm/meta/info/{appId}: - get: - summary: Get Helm application meta info - description: Application info for all types of Helm apps - operationId: getHelmAppMetaInfo - security: - - ApiKeyAuth: [] - parameters: - - name: appId - in: path - description: application id - required: true - schema: - type: string - responses: - '200': - description: Helm application basic info - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: meta info project name and labels - $ref: '#/components/schemas/AppMetaInfo' - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - -# components mentioned below -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - schemas: - AppLabel: - type: object - required: - - key - - value - properties: - key: - type: string - description: label key - value: - type: string - description: label value - propagate: - type: boolean - description: Whether to propagate to kubernetes resources - - AppLabels: - type: object - required: - - appId - - labels - properties: - appId: - type: integer - description: application id - labels: - type: array - items: - $ref: '#/components/schemas/AppLabel' - - AppMetaInfo: - type: object - required: - - appId - - projectId - - appName - - projectName - - createdOn - - createdBy - - labels - properties: - appId: - type: integer - description: app id - projectId: - type: integer - description: team/project id - appName: - type: string - description: app name - projectName: - type: string - description: team/project name - labels: - type: array - items: - $ref: '#/components/schemas/AppLabel' - createdOn: - type: string - description: app creation date - createdBy: - type: string - description: app created by - - ErrorResponse: - type: object - properties: - code: - type: integer - format: int32 - status: - type: string - result: - type: object - nullable: true - errors: - type: array - items: - type: object - properties: - userMessage: - type: string - nullable: true - internalMessage: - type: string - nullable: true - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message diff --git a/specs/app-store.yaml b/specs/app-store.yaml index c9e72bf01f..a89f54f546 100644 --- a/specs/app-store.yaml +++ b/specs/app-store.yaml @@ -1,95 +1,405 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron Labs + title: App Store Management + description: Devtron API for app store management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 paths: - /orchestrator/app-store/discover/: + /orchestrator/app-store/discover: get: - description: this api will return all the charts from charts repos. - parameters: [ ] + description: Get all charts from chart repositories + parameters: + - name: includeDeprecated + in: query + description: Include deprecated charts + required: false + schema: + type: boolean + - name: chartRepoId + in: query + description: Chart repository IDs (comma separated) + required: false + schema: + type: string + - name: registryId + in: query + description: Registry IDs (comma separated) + required: false + schema: + type: string + - name: appStoreName + in: query + description: App store name filter + required: false + schema: + type: string + - name: offset + in: query + description: Offset for pagination + required: false + schema: + type: integer + - name: size + in: query + description: Size for pagination + required: false + schema: + type: integer + - name: chartCategoryId + in: query + description: Chart category IDs (comma separated) + required: false + schema: + type: string responses: '200': - description: list response + description: List of app store applications with versions content: application/json: schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - allOf: - - type: object - properties: - appId: - type: integer - description: unique application id - required: - - appId - - $ref: '#/components/schemas/AppStore' - default: - description: unexpected error + $ref: '#/components/schemas/AppStoreListingResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + /orchestrator/app-store/discover/application/{id}: + get: + description: Get chart details for a specific version + parameters: + - name: id + in: path + required: true + schema: + type: integer + description: App store application version ID + responses: + '200': + description: Chart details + content: + application/json: + schema: + $ref: '#/components/schemas/AppStoreApplicationVersion' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/app-store/discover/application/{appStoreId}/version/autocomplete: + get: + description: Get chart versions for an app store application + parameters: + - name: appStoreId + in: path + required: true + schema: + type: integer + description: App store application ID + responses: + '200': + description: List of chart versions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AppStoreApplicationVersion' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/app-store/discover/application/chartInfo/{appStoreApplicationVersionId}: + get: + description: Get chart information for a specific version + parameters: + - name: appStoreApplicationVersionId + in: path + required: true + schema: + type: integer + description: App store application version ID + responses: + '200': + description: Chart information + content: + application/json: + schema: + $ref: '#/components/schemas/ChartInfo' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/app-store/discover/search: + get: + description: Search app store charts by name + parameters: + - name: chartName + in: query + required: true + schema: + type: string + description: Chart name to search for + responses: + '200': + description: List of matching charts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AppStoreApplication' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' - -# components mentioned below components: schemas: - AppStore: + AppStoreApplication: type: object - required: - - id - - name properties: id: type: integer - description: app store id + description: App store application ID name: type: string - description: app store name - appStoreApplicationVersionId: + description: App store application name + chartRepoId: type: integer - description: app store version id - chart_git_location: + description: Chart repository ID + active: + type: boolean + description: Whether the application is active + chartGitLocation: + type: string + description: Chart Git repository location + createdOn: type: string - description: chart git repo location - chart_name: + format: date-time + description: Creation timestamp + updatedOn: type: string - description: chart name - chart_repo_id: + format: date-time + description: Last update timestamp + appStoreApplicationVersions: + type: array + items: + $ref: '#/components/schemas/AppStoreApplicationVersion' + description: List of application versions + + AppStoreApplicationVersion: + type: object + properties: + id: type: integer - description: app store and chart repo link id + description: Version ID + version: + type: string + description: Version number + appVersion: + type: string + description: Application version + created: + type: string + format: date-time + description: Creation timestamp deprecated: type: boolean - description: deprecated app store flag + description: Whether the version is deprecated description: type: string - description: app store description, short summary + description: Version description + digest: + type: string + description: Chart digest icon: type: string - description: app store icon link - created_on: + description: Icon URL + name: type: string - description: created on - updated_on: + description: Chart name + chartName: type: string - description: modification date - version: + description: Chart name + appStoreApplicationName: type: string - description: app store version - active: + description: App store application name + home: + type: string + description: Home URL + source: + type: string + description: Source URL + valuesYaml: + type: string + description: Values YAML + chartYaml: + type: string + description: Chart YAML + appStoreId: + type: integer + description: App store ID + latest: type: boolean - description: active app store + description: Whether this is the latest version + createdOn: + type: string + format: date-time + description: Creation timestamp + rawValues: + type: string + description: Raw values + readme: + type: string + description: README content + valuesSchemaJson: + type: string + description: Values schema in JSON format + notes: + type: string + description: Release notes + + ChartInfo: + type: object + properties: + chartName: + type: string + description: Chart name + chartVersion: + type: string + description: Chart version + valuesYaml: + type: string + description: Values YAML + chartYaml: + type: string + description: Chart YAML + readme: + type: string + description: README content + notes: + type: string + description: Release notes + + AppStoreListingResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: array + items: + $ref: '#/components/schemas/AppStoreApplication' + description: List of app store applications ErrorResponse: required: @@ -105,7 +415,7 @@ components: description: Error message errors: type: array - description: errors + description: List of errors items: $ref: '#/components/schemas/Error' diff --git a/specs/application.yaml b/specs/application.yaml deleted file mode 100644 index 6cab55e0ac..0000000000 --- a/specs/application.yaml +++ /dev/null @@ -1,450 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: https://api.yourdomain.com - description: Production server -security: - - ApiKeyAuth: [] -paths: - /orchestrator/app: - post: - summary: Create a new application - operationId: createApplication - description: create new application - security: - - ApiKeyAuth: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/App' - responses: - '200': - description: App create response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - allOf: - - type: object - properties: - id: - type: integer - description: unique application id - required: - - id - - $ref: '#/components/schemas/App' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - /orchestrator/app/edit: - post: - summary: Update application projects and labels - operationId: updateApplicationProjectsAndLabels - description: update application projects and labels - security: - - ApiKeyAuth: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/App' - responses: - '200': - description: App update response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - allOf: - - type: object - properties: - id: - type: integer - description: unique application id - required: - - id - - $ref: '#/components/schemas/App' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - - /orchestrator/app/list: - post: - summary: List applications - operationId: listApplications - description: app listing, collection of deployed applications or undeployed or incomplete configured apps. - security: - - ApiKeyAuth: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AppListingRequest' - responses: - '200': - description: App create response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - required: - - appCount - - appContainers - - deploymentGroup - properties: - appCount: - type: integer - description: app count, total number of apps available based on filter provided in request. - appContainers: - type: array - description: app containers - items: - $ref: '#/components/schemas/AppContainer' - deploymentGroup: - type: object - description: deployment group - $ref: '#/components/schemas/DeploymentGroup' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - - /orchestrator/app/edit/projects: - post: - summary: Update project for app - operationId: updateProjectForApp - description: update project for app - security: - - ApiKeyAuth: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AppProjectUpdateRequest' - responses: - '200': - description: App update response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - $ref: '#/components/schemas/AppProjectUpdateRequest' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' -# components mentioned below -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - schemas: - AppLabel: - type: object - required: - - key - - value - properties: - key: - type: string - description: label key - value: - type: string - description: label value - propagate: - type: boolean - description: Whether to propagate to kubernetes resources - - App: - type: object - required: - - appName - - teamId - - templateId - properties: - appName: - type: string - description: app name - teamId: - type: integer - description: project id - templateId: - type: integer - description: reference app id, used for clone, set default value 0 for blank app. - labels: - type: array - description: each apps may have multiple labels. these are optional. - items: - $ref: '#/components/schemas/AppLabel' - AppProjectUpdateRequest: - type: object - required: - - teamId - - appId - properties: - teamId: - type: integer - description: project id - appId: - type: array - description: team id, teams ids are projects ids - items: - type: integer - - AppListingRequest: - type: object - required: - - offset - - size - properties: - appNameSearch: - type: string - description: app name search, wildcard match - offset: - type: integer - description: offset - size: - type: integer - description: result size - sortBy: - type: string - description: sort by - sortOrder: - type: string - description: sort order - environments: - type: array - description: environment id - items: - type: integer - teams: - type: array - description: team id, teams ids are projects ids - items: - type: integer - labels: - type: array - description: app labels - items: - type: string - statuses: - type: array - description: status - items: - type: string - - AppContainer: - type: object - required: - - appId - - appName - - environments - properties: - appId: - type: integer - description: app id - appName: - type: string - description: app name - environments: - type: array - items: - $ref: '#/components/schemas/EnvContainer' - - EnvContainer: - type: object - required: - - appId - - appName - - environmentId - - environmentName - properties: - appId: - type: integer - description: app id - appName: - type: string - description: app name - cdStageStatus: - type: string - description: app name - dataSource: - type: string - description: app name - ciArtifactId: - type: integer - description: app name - deleted: - type: boolean - description: app name - environmentId: - type: integer - description: app name - environmentName: - type: string - description: app name - status: - type: string - description: app name - appStatus: - type: string - description: app status for this environment - postStageStatus: - type: string - description: app name - preStageStatus: - type: string - description: app name - lastDeployedTime: - type: string - description: deployed time - materialInfo: - type: array - items: - type: object - - DeploymentGroup: - type: object - required: - - id - properties: - id: - type: integer - description: id - ciPipelineId: - type: integer - description: ciPipelineId - environmentId: - type: integer - description: environmentId - appCount: - type: integer - description: appCount - name: - type: string - description: name - noOfApps: - type: string - description: noOfApps - - - ErrorResponse: - type: object - properties: - code: - type: integer - format: int32 - status: - type: string - result: - type: object - nullable: true - errors: - type: array - items: - type: object - properties: - userMessage: - type: string - nullable: true - internalMessage: - type: string - nullable: true - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message diff --git a/specs/application/core.yaml b/specs/application/core.yaml new file mode 100644 index 0000000000..4d13c2315e --- /dev/null +++ b/specs/application/core.yaml @@ -0,0 +1,526 @@ +openapi: 3.0.3 +info: + version: 1.0.0 + title: Devtron Application Management API + description: | + This API provides functionality for managing applications in Devtron, including + creating, updating, and listing applications, as well as managing application + configurations, environments, and deployments. + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication + schemas: + ApiResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + description: Response result data + + ErrorResponse: + type: object + properties: + code: + type: integer + description: Error code + status: + type: string + description: Error status + errors: + type: array + items: + type: string + description: List of error messages + + AppLabel: + type: object + required: + - key + - value + properties: + key: + type: string + description: Label key + value: + type: string + description: Label value + propagate: + type: boolean + description: Whether to propagate to kubernetes resources + + App: + type: object + required: + - appName + properties: + id: + type: integer + format: int64 + description: Application ID + appName: + type: string + description: Name of the application + teamId: + type: integer + format: int64 + description: Team ID + labels: + type: array + items: + $ref: '#/components/schemas/AppLabel' + description: Application labels + description: + type: string + description: Application description + projectIds: + type: array + items: + type: integer + format: int64 + description: IDs of projects this application belongs to + + CreateAppRequest: + type: object + required: + - metadata + properties: + metadata: + $ref: '#/components/schemas/App' + appWorkflows: + type: array + description: App workflows + items: + type: object + environmentOverrides: + type: array + description: Environment overrides + items: + type: object + + AppListingRequest: + type: object + properties: + teamIds: + type: array + items: + type: integer + format: int64 + description: Filter by team IDs + environmentIds: + type: array + items: + type: integer + format: int64 + description: Filter by environment IDs + statuses: + type: array + items: + type: string + enum: [Healthy, Degraded, Failed, Progressing] + description: Filter by application statuses + appNameSearch: + type: string + description: Search term for application name + offset: + type: integer + description: Pagination offset + size: + type: integer + description: Page size + projectIds: + type: array + items: + type: integer + format: int64 + description: Filter by project IDs + + AppListResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + appCount: + type: integer + description: Total number of applications matching the filters + appContainers: + type: array + items: + $ref: '#/components/schemas/AppContainer' + deploymentGroup: + $ref: '#/components/schemas/DeploymentGroup' + + AppContainer: + type: object + properties: + appId: + type: integer + format: int64 + description: Application ID + appName: + type: string + description: Application name + environments: + type: array + items: + $ref: '#/components/schemas/AppEnvironment' + description: Environments where the application is deployed + + AppEnvironment: + type: object + properties: + environmentId: + type: integer + format: int64 + description: Environment ID + environmentName: + type: string + description: Environment name + status: + type: string + enum: [Healthy, Degraded, Failed, Progressing] + description: Application status in this environment + lastDeployed: + type: string + format: date-time + description: Last deployment timestamp + + DeploymentGroup: + type: object + properties: + id: + type: integer + format: int64 + description: Deployment group ID + name: + type: string + description: Deployment group name + applications: + type: array + items: + type: integer + format: int64 + description: IDs of applications in this deployment group + + AppDetails: + type: object + properties: + app: + $ref: '#/components/schemas/App' + environments: + type: array + items: + $ref: '#/components/schemas/AppEnvironment' + description: Environments where the application is deployed + ciConfig: + type: object + description: CI configuration + cdConfig: + type: object + description: CD configuration + + AppProjectUpdateRequest: + type: object + required: + - appId + - projectIds + properties: + appId: + type: integer + format: int64 + description: Application ID + projectIds: + type: array + items: + type: integer + format: int64 + description: IDs of projects to associate with the application + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Application not found in the system"] + +tags: + - name: Applications + description: Operations related to application management + - name: Environments + description: Operations related to application environments + - name: Deployments + description: Operations related to application deployments + +paths: + /orchestrator/core/v1beta1/application: + post: + tags: + - Applications + summary: Create a new application + description: Creates a new application in the Devtron system with the provided configuration. + operationId: createApplication + security: + - bearerAuth: [] + requestBody: + description: Application creation request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAppRequest' + responses: + '200': + description: Application created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '400': + description: Invalid request format or missing required fields + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '409': + description: Application with the same name already exists + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + + /app/edit: + post: + tags: + - Applications + summary: Update application + description: Updates an existing application's configuration including projects and labels. + operationId: updateApplication + requestBody: + description: Application update request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/App' + responses: + '200': + description: Application updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '400': + description: Invalid request format or missing required fields + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Application not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + security: + - bearerAuth: [] + + /app/list: + post: + tags: + - Applications + summary: List applications + description: | + Retrieves a paginated list of applications based on the provided filters. + Can return deployed applications, undeployed applications, or applications with incomplete configurations. + operationId: listApplications + requestBody: + description: Application listing filters + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AppListingRequest' + responses: + '200': + description: List of applications retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/AppListResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + security: + - bearerAuth: [] + + /app/details/{appId}: + get: + tags: + - Applications + summary: Get application details + description: Retrieves detailed information about a specific application including its configurations and status. + operationId: getApplicationDetails + parameters: + - name: appId + in: path + description: ID of the application to retrieve + required: true + schema: + type: integer + format: int64 + minimum: 1 + example: 12345 + responses: + '200': + description: Application details retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/AppDetails' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Application not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + security: + - bearerAuth: [] + + /app/edit/projects: + post: + tags: + - Applications + summary: Update application projects + description: Updates the projects associated with an application + operationId: updateApplicationProjects + requestBody: + description: Application project update request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AppProjectUpdateRequest' + responses: + '200': + description: Projects updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '400': + description: Invalid request format or missing required fields + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Application not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + security: + - bearerAuth: [] + +# components section diff --git a/specs/app_create_api.yaml b/specs/application/creation.yaml similarity index 97% rename from specs/app_create_api.yaml rename to specs/application/creation.yaml index ca95476cc9..3d1239eba2 100644 --- a/specs/app_create_api.yaml +++ b/specs/application/creation.yaml @@ -108,7 +108,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/core/v1beta1/application: + /core/v1beta1/application: post: description: Creates a new app for the configurations provided. The input json object is the same we get in response of GET method for fetching all details of an app operationId: CreateApp @@ -121,11 +121,21 @@ paths: $ref: '#/components/schemas/AppDetail' responses: '200': - description: Successfully return a message stating the operation is successful. + description: Successfully created the application content: application/json: schema: - type: string + type: object + properties: + code: + type: integer + description: HTTP status code + status: + type: string + description: Status message + result: + type: string + description: Success message '400': description: Bad Request. Validation error/wrong request body. content: diff --git a/specs/application/labels.yaml b/specs/application/labels.yaml new file mode 100644 index 0000000000..f8696a7a7a --- /dev/null +++ b/specs/application/labels.yaml @@ -0,0 +1,328 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Application Labels Management + description: API for managing application labels and metadata + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + +paths: + /app/labels/list: + get: + summary: List Application Labels + description: | + Retrieves a list of application labels. By default, returns all labels. + Use the `showPropagatedOnly` parameter to filter for labels where propagate = true. + + **Required Token Permission:** + - Must have **View** access to the applications in scope. + operationId: getAppLabels + security: + - bearerAuth: [] + parameters: + - name: showPropagatedOnly + in: query + description: | + If true, only returns labels where propagate = true. + If false or not provided, all labels are returned. + required: false + schema: + type: boolean + default: false + example: false + responses: + '200': + description: Successfully retrieved labels list + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: HTTP status code + example: 200 + status: + type: string + description: Response status message + example: OK + result: + type: array + description: Array of label objects + items: + allOf: + - type: object + properties: + appId: + type: integer + description: unique application id + appName: + type: string + description: The name of the application + required: + - appId + - appName + - $ref: '../common/schemas.yaml#/components/schemas/AppLabel' + examples: + all_labels: + summary: All labels response + description: Example response when showPropagatedOnly is false or not provided + value: + code: 200 + status: OK + result: + - key: environment + value: production + propagate: true + appId: 1234 + appName: web-service + - key: team + value: backend + propagate: false + appId: 1234 + appName: web-service + propagated_only: + summary: Propagated labels only + description: Example response when showPropagatedOnly is true + value: + code: 200 + status: OK + result: + - key: environment + value: production + propagate: true + appId: 1234 + appName: web-service + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Authentication required or token invalid + content: + application/json: + schema: + type: object + properties: + code: + type: integer + example: 401 + status: + type: string + example: Unauthorized + message: + type: string + example: Authentication token is required + '403': + description: Insufficient permissions to access the resource + content: + application/json: + schema: + type: object + properties: + code: + type: integer + example: 403 + status: + type: string + example: Forbidden + message: + type: string + example: Token does not have View access to the applications in scope + '404': + description: Not found + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + type: object + properties: + code: + type: integer + example: 500 + status: + type: string + example: Internal Server Error + message: + type: string + example: An unexpected error occurred + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Application Labels + + /app/meta/info/{appId}: + get: + summary: Get Application Meta Info + description: Retrieves application basic info, projects and labels + operationId: getAppMetaInfo + security: + - bearerAuth: [] + parameters: + - name: appId + in: path + description: Application ID + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Application basic info, projects and labels + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + allOf: + - $ref: '../common/schemas.yaml#/components/schemas/AppMetaInfo' + - type: object + properties: + gitMaterials: + type: array + items: + $ref: '../common/schemas.yaml#/components/schemas/GitMaterialMeta' + templateConfig: + $ref: '../common/schemas.yaml#/components/schemas/TemplateConfig' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '404': + description: Application not found + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Application Metadata + + /helm/meta/info/{appId}: + get: + summary: Get Helm Application Meta Info + description: Retrieves application info for all types of Helm apps + operationId: getHelmAppMetaInfo + security: + - bearerAuth: [] + parameters: + - name: appId + in: path + description: Application ID + required: true + schema: + type: string + responses: + '200': + description: Helm application basic info + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + allOf: + - $ref: '../common/schemas.yaml#/components/schemas/AppMetaInfo' + - type: object + properties: + chartUsed: + $ref: '../common/schemas.yaml#/components/schemas/ChartUsed' + gitMaterials: + type: array + items: + $ref: '../common/schemas.yaml#/components/schemas/GitMaterialMeta' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '404': + description: Application not found + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Helm Application Metadata + +tags: + - name: Application Labels + description: Operations related to application labels + - name: Application Metadata + description: Operations related to application metadata + - name: Helm Application Metadata + description: Operations related to Helm application metadata \ No newline at end of file diff --git a/specs/application/listing.yaml b/specs/application/listing.yaml new file mode 100644 index 0000000000..0c6ca1061f --- /dev/null +++ b/specs/application/listing.yaml @@ -0,0 +1,158 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Application Listing & Discovery +paths: + /orchestrator/app/autocomplete: + get: + description: list of namespaces group by clusters + parameters: + - in: query + name: appName + example: "abc" + description: app name, wildcard query + required: false + allowEmptyValue: true + schema: + type: string + - in: query + name: teamId + example: "1" + description: project id + required: false + allowEmptyValue: false + schema: + type: integer + responses: + '200': + description: list response + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: array + description: app list + items: + $ref: '#/components/schemas/App' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +# components mentioned below +components: + schemas: + App: + type: object + properties: + id: + type: integer + description: app id + name: + type: string + description: app name + teamId: + type: integer + description: project id + teamName: + type: string + description: project name + active: + type: boolean + description: whether app is active + createdOn: + type: string + format: date-time + description: creation timestamp + createdBy: + type: string + description: creator's name + updatedOn: + type: string + format: date-time + description: last update timestamp + material: + type: array + description: git materials + items: + $ref: '#/components/schemas/GitMaterial' + labels: + type: array + description: app labels + items: + $ref: '#/components/schemas/AppLabel' + AppLabel: + type: object + properties: + key: + type: string + description: label key + value: + type: string + description: label value + propagate: + type: boolean + description: whether to propagate to kubernetes resources + GitMaterial: + type: object + properties: + id: + type: integer + description: material id + gitProviderId: + type: integer + description: git provider id + gitProviderUrl: + type: string + description: git provider url + gitRepoUrl: + type: string + description: git repository url + checkoutPath: + type: string + description: checkout path + fetchSubmodules: + type: boolean + description: whether to fetch submodules + 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 diff --git a/specs/applisting.yaml b/specs/applisting.yaml deleted file mode 100644 index 3cf221f4f4..0000000000 --- a/specs/applisting.yaml +++ /dev/null @@ -1,106 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: https://api.yourdomain.com - description: Production server -security: - - ApiKeyAuth: [] -paths: - /orchestrator/app/autocomplete: - get: - summary: List application autocomplete - operationId: listAppAutocomplete - description: list of namespaces group by clusters - parameters: - - in: query - name: appName - example: "abc" - description: app name, wildcard query - required: false - allowEmptyValue: true - schema: - type: string - - in: query - name: teamId - example: "1" - description: project id - required: false - allowEmptyValue: false - schema: - type: integer - responses: - '200': - description: list response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: array - description: app list - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - -# components mentioned below -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - schemas: - ErrorResponse: - type: object - properties: - code: - type: integer - format: int32 - status: - type: string - result: - type: object - nullable: true - errors: - type: array - items: - type: object - properties: - userMessage: - type: string - nullable: true - internalMessage: - type: string - nullable: true - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message diff --git a/specs/historical-get-api-change.yaml b/specs/audit/api-changes.yaml similarity index 78% rename from specs/historical-get-api-change.yaml rename to specs/audit/api-changes.yaml index 7ad6d05e79..40d74533d0 100644 --- a/specs/historical-get-api-change.yaml +++ b/specs/audit/api-changes.yaml @@ -177,65 +177,116 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + components: schemas: HistoryComponentDetailDto: type: object properties: - values: - type: array - items: - $ref: '#/components/schemas/HistoryComponentValuesDto' - codeEditorValue: - type: object - properties: - displayName: - type: string - value: - type: string - HistoryComponentValuesDto: - type: object - properties: - fieldName: - type: object - properties: - displayName: - type: string - value: - type: string + id: + type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean + deployedOn: + type: string + format: timestamp + deployedBy: + type: integer + HistoryComponentListDto: type: object properties: id: type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean deployedOn: type: string format: timestamp deployedBy: - type: string - deploymentStatus: - type: string + type: integer + HistoryConfigurationListDto: - type: array - items: - $ref: '#/components/schemas/HistoryConfiguration' - HistoryConfiguration: type: object properties: id: type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean + deployedOn: + type: string + format: timestamp + deployedBy: + type: integer + + ConfigData: + type: object + properties: name: type: string - enum: - - "DEPLOYMENT_TEMPLATE" - - "CONFIGMAP" - - "SECRET" - - "PIPELINE_STRATEGY" - childList: + type: + type: string + external: + type: boolean + mountPath: + type: string + data: + type: string + defaultData: + type: string + defaultMountPath: + type: string + global: + type: boolean + externalType: + type: string + secretData: type: array items: - type: string + $ref: '#/components/schemas/ExternalSecret' + defaultSecretData: + type: array + items: + $ref: '#/components/schemas/ExternalSecret' + roleArn: + type: string + subPath: + type: boolean + filePermission: + type: string + + ExternalSecret: + type: object + properties: + key: + type: string + name: + type: string + property: + type: string + isBinary: + type: boolean + Error: + type: object required: - code - message diff --git a/specs/audit/definitions.yaml b/specs/audit/definitions.yaml new file mode 100644 index 0000000000..63c8ea4651 --- /dev/null +++ b/specs/audit/definitions.yaml @@ -0,0 +1,299 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Historical Task definitions +paths: + /orchestrator/app/history/deployed-component/detail/{appId}/{pipelineId}/{id}: + get: + description: fetch detail of a history on the basis of the history component and it's name + operationId: FetchDeployedHistoryComponentDetail + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: pipelineId + in: path + required: true + schema: + type: integer + - name: id + in: path + required: true + schema: + type: integer + - name: historyComponent + in: query + required: true + schema: + type: string + enum: + - "DEPLOYMENT_TEMPLATE" + - "CONFIGMAP" + - "SECRET" + - "PIPELINE_STRATEGY" + - name: historyComponentName + in: query + required: false + description: name of config-map, secret + schema: + type: string + responses: + '200': + description: Successfully return history + content: + application/json: + schema: + $ref: '#/components/schemas/HistoryComponentDetailDto' + '400': + description: Bad Request. Input Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/app/history/deployed-component/list/{appId}/{pipelineId}: + get: + description: fetch deployed history details list + operationId: FetchDeployedHistoryComponentList + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: pipelineId + in: path + required: true + schema: + type: integer + - name: historyComponent + in: query + required: true + schema: + type: string + enum: + - "DEPLOYMENT_TEMPLATE" + - "CONFIGMAP" + - "SECRET" + - "PIPELINE_STRATEGY" + - name: historyComponentName + in: query + required: false + description: name of config-map, secret + schema: + type: string + - name: baseConfigurationId + in: query + required: true + description: id of base configuration + schema: + type: integer + responses: + '200': + description: Successfully return history list + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/HistoryComponentListDto' + '400': + description: Bad Request. Input Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/app/history/deployed-configuration/{appId}/{pipelineId}/{wfrId}: + get: + description: fetch all deployed configurations history (deployment template, pipeline strategy, configmaps, secrets) + operationId: FetchDeployedConfigurationsForWorkflow + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: pipelineId + in: path + required: true + schema: + type: integer + - name: wfrId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully return history + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/HistoryConfigurationListDto' + '400': + description: Bad Request. Input Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + HistoryComponentDetailDto: + type: object + properties: + id: + type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean + deployedOn: + type: string + format: timestamp + deployedBy: + type: integer + + HistoryComponentListDto: + type: object + properties: + id: + type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean + deployedOn: + type: string + format: timestamp + deployedBy: + type: integer + + HistoryConfigurationListDto: + type: object + properties: + id: + type: integer + pipelineId: + type: integer + dataType: + type: string + configData: + $ref: '#/components/schemas/ConfigData' + deployed: + type: boolean + deployedOn: + type: string + format: timestamp + deployedBy: + type: integer + + ConfigData: + type: object + properties: + name: + type: string + type: + type: string + external: + type: boolean + mountPath: + type: string + data: + type: string + defaultData: + type: string + defaultMountPath: + type: string + global: + type: boolean + externalType: + type: string + secretData: + type: array + items: + $ref: '#/components/schemas/ExternalSecret' + defaultSecretData: + type: array + items: + $ref: '#/components/schemas/ExternalSecret' + roleArn: + type: string + subPath: + type: boolean + filePermission: + type: string + + ExternalSecret: + type: object + properties: + key: + type: string + name: + type: string + property: + type: string + isBinary: + type: boolean + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/batch.yaml b/specs/batch.yaml deleted file mode 100644 index a1ce08955c..0000000000 --- a/specs/batch.yaml +++ /dev/null @@ -1,541 +0,0 @@ -components: - schemas: - buildMaterial: - type: object - required: - - source - - gitMaterialUrl - properties: - source: - type: object - required: - - type - - value - properties: - type: - type: string - value: - type: string - enum: - - BranchFixed - - BranchRegex - - TagAny - - TagRegex - gitMaterialUrl: - type: string - dockerConfig: - type: object - required: - - dockerFilePath - - dockerFileRepository - - dockerFileRelativePath - - gitMaterial - - args - properties: - dockerFilePath: - type: string - dockerFileRepository: - type: string - dockerFileRelativePath: - type: string - gitMaterial: - type: string - args: - type: object - app: - description: Application configuration - type: object - required: - - apiVersion - - operation - - team - - repo - - dockerConfig - - dockerRegistry - - dockerRepo - - configMaps - - secrets - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - workflow: - type: array - description: Workflow for app - items: - $ref: '#/components/schemas/workflow' - team: - type: string - repo: - type: array - items: - $ref: '#/components/schemas/repo' - dockerRegistry: - type: string - dockerRepo: - type: string - dockerConfig: - $ref: '#/components/schemas/dockerConfig' - configMaps: - type: array - items: - $ref: '#/components/schemas/dataHolder' - secrets: - type: array - items: - $ref: '#/components/schemas/dataHolder' - workflow: - description: Workflow of the application - type: object - required: - - apiVersion - - operation - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - pipelines: - type: array - description: Entries can be of type build or deployment - items: - $ref: '#/components/schemas/pipeline' - deploymentStrategy: - description: Strategy as defined by devtron template, this overrides at environment level - type: object - required: - - default - properties: - blueGreen: - $ref: '#/components/schemas/blueGreenStrategy' - canary: - $ref: '#/components/schemas/canaryStrategy' - rolling: - $ref: '#/components/schemas/rollingStrategy' - recreate: - $ref: '#/components/schemas/recreateStrategy' - default: - type: string - enum: - - BLUE-GREEN - - ROLLING - - CANARY - - RECREATE - inheritedProps: - type: object - required: - - operation - properties: - source: - $ref: '#/components/schemas/resourcePath' - destination: - $ref: '#/components/schemas/resourcePath' - operation: - $ref: '#/components/schemas/operation' - blueGreenStrategy: - type: object - required: - - autoPromotionSeconds - - scaleDownDelaySeconds - - previewReplicaCount - - autoPromotionEnabled - properties: - autoPromotionSeconds: - type: integer - format: int32 - scaleDownDelaySeconds: - type: integer - format: int32 - previewReplicaCount: - type: integer - format: int32 - autoPromotionEnabled: - type: boolean - canaryStrategy: - type: object - required: - - maxSurge - - maxUnavailable - - steps - properties: - maxSurge: - type: string - maxUnavailable: - type: integer - format: int32 - steps: - type: array - items: - setWeight: - type: integer - format: int32 - pause: - type: object - properties: - duration: - type: integer - format: int32 - recreateStrategy: - type: object - rollingStrategy: - type: object - required: - - maxSurge - - maxUnavailable - properties: - maxSurge: - type: string - maxUnavailable: - type: integer - format: int32 - pipeline: - type: object - properties: - build: - $ref: '#/components/schemas/build' - deployment: - $ref: '#/components/schemas/deployment' - operation: - type: string - description: Action to be taken on the component - enum: - - create - - delete - - update - - append - - clone - trigger: - type: string - description: How will this action be initiated - enum: - - manual - - automatic - resourcePath: - description: Unique identification of resource - type: object - properties: - app: - type: string - workflow: - type: string - pipeline: - type: string - configMap: - type: string - secret: - type: string - environment: - type: string - uid: - type: string - repo: - description: git repo to use in this build - type: object - properties: - url: - description: git url - type: string - branch: - description: branch to build - type: string - path: - description: path to checkout - type: string - stage: - type: object - required: - - operation - - name - properties: - operation: - $ref: '#/components/schemas/operation' - name: - type: string - position: - type: integer - format: int32 - script: - type: string - outputLocation: - type: string - task: - type: object - required: - - apiVersion - - operation - - stages - - configMaps - - secrets - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - stages: - description: Different stages in this step - type: array - items: - $ref: '#/components/schemas/stage' - trigger: - $ref: '#/components/schemas/trigger' - configMaps: - type: array - items: - type: string - secrets: - type: array - items: - type: string - dataHolder: - type: object - required: - - operation - - data - - apiVersion - - type - - global - - externalType - - mountPath - - external - properties: - apiVersion: - description: API version of this configuration - type: string - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. In case operation is delete then only source or destination can be present. If source is present then its skipping in cloning, if destination is present then it is deleted from database. - $ref: '#/components/schemas/operation' - type: - type: string - external: - type: boolean - mountPath: - type: string - global: - type: boolean - externalType: - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - data: - description: If operation is clone, leaving value empty results in deletion of key in destination. - type: object - preBuild: - $ref: '#/components/schemas/task' - postBuild: - $ref: '#/components/schemas/task' - build: - type: object - required: - - apiVersion - - operation - - dockerArguments - - repo - - trigger - - buildMaterials - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - repo: - type: array - items: - $ref: '#/components/schemas/repo' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - dockerArguments: - type: object - trigger: - $ref: '#/components/schemas/trigger' - preBuild: - $ref: '#/components/schemas/task' - postBuild: - $ref: '#/components/schemas/task' - nextPipeline: - description: This can be either of type build or deployment - $ref: '#/components/schemas/pipeline' - webHookUrl: - type: string - payload: - type: string - accessKey: - type: string - buildMaterials: - type: array - items: - $ref: '#/components/schemas/buildMaterial' - preDeployment: - $ref: '#/components/schemas/task' - postDeployment: - $ref: '#/components/schemas/task' - deployment: - type: object - required: - - apiVersion - - operation - - configMaps - - secrets - - strategy - - runPostStageInEnv - - runPreStageInEnv - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - trigger: - $ref: '#/components/schemas/trigger' - template: - description: Deployment template as defined by devtron template, these are applied at environment level - $ref: '#/components/schemas/deploymentTemplate' - strategy: - $ref: '#/components/schemas/deploymentStrategy' - configMaps: - description: These are applied for environment - type: array - items: - $ref: '#/components/schemas/dataHolder' - secrets: - description: These are applied for environment - type: array - items: - $ref: '#/components/schemas/dataHolder' - postDeployment: - $ref: '#/components/schemas/task' - preDeployment: - $ref: '#/components/schemas/task' - previousPipeline: - description: This can be either of type build or deployment - $ref: '#/components/schemas/pipeline' - nextPipeline: - description: This can be either of type build or deployment - $ref: '#/components/schemas/pipeline' - runPostStageInEnv: - type: boolean - runPreStageInEnv: - type: boolean - pipelineRequest: - type: object - required: - - apiVersion - - pipelines - properties: - apiVersion: - description: API version of this configuration - type: string - pipelines: - type: array - description: Entries can be of type build or deployment - items: - $ref: '#/components/schemas/pipeline' - configMaps: - $ref: '#/components/schemas/dataHolder' - secrets: - $ref: '#/components/schemas/dataHolder' - deploymentTemplate: - type: object - required: - - apiVersion - - operation - - refChartTemplate - - refChartTemplateVersion - - chartRefId - - isAppMetricsEnabled - - valuesOverride - - defaultAppOverride - properties: - apiVersion: - description: API version of this configuration - type: string - source: - description: Optionally mention the source from where to clone, in case operation is clone and source is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - destination: - description: Optionally mention the destination, in case operation is clone/update/delete and destination is missing it is inherited from parent pipeline. - $ref: '#/components/schemas/resourcePath' - operation: - description: Action to be taken on this component. This is used along with source and destination of pipeline. - $ref: '#/components/schemas/operation' - refChartTemplate: - type: string - refChartTemplateVersion: - type: string - chartRefId: - type: integer - format: int32 - isAppMetricsEnabled: - type: boolean - defaultAppOverride: - type: object - valuesOverride: - type: object - - -paths: - /batch/pipeline: - post: - requestBody: - description: payload to generate temporary token for this user - content: - 'application/json': - schema: - pipelineRequest: - $ref: '#/components/schemas/pipelineRequest' - responses: - '200': - description: token generated successfully - result: - type: object - properties: - success: - type: string - /batch/workflow: - get: - - post: - - - diff --git a/specs/buildInfraConfig/build-infra-config.yaml b/specs/buildInfraConfig/build-infra-config.yaml index 4698196884..a03b401ca7 100644 --- a/specs/buildInfraConfig/build-infra-config.yaml +++ b/specs/buildInfraConfig/build-infra-config.yaml @@ -5,20 +5,45 @@ info: version: 1.0.0 servers: - url: 'https' + paths: -# send 404 responses if resource doesn't exist - /orchestrator/infra-config/profile/{name}: + /orchestrator/infra-config/profile: get: description: Get Infra Profile by name + parameters: + - name: name + in: query + required: true + schema: + type: string + pattern: '^[a-z]+$' responses: "200": - description: gets the infra config profile by its name. + description: Gets the infra config profile by its name content: application/json: schema: - $ref: "#/components/schemas/ProfileResponse" + $ref: "#/components/schemas/ProfileResponse" + "400": + description: Invalid profile name + "401": + description: Unauthorized + "403": + description: Forbidden + "404": + description: Profile not found + "500": + description: Internal Server Error + put: description: Update Infra Profile + parameters: + - name: name + in: query + required: true + schema: + type: string + pattern: '^[a-z]+$' requestBody: required: true content: @@ -27,17 +52,23 @@ paths: $ref: '#/components/schemas/Profile' responses: "200": - description: creates a infra config profile. - content: - application/json: - schema: - $ref: "#/components/schemas/Profile" - + description: Successfully updated infra config profile + "400": + description: Invalid request payload + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal Server Error components: schemas: Unit: type: object + required: + - name + - conversionFactor properties: name: type: string @@ -49,112 +80,269 @@ components: example: 1 ConfigurationUnits: - type: object - properties: - name: - type: string - description: Configuration Units - units: - type: array - description: Configuration Units - items: - $ref: '#/components/schemas/Unit' - ProfileResponse: type: object + required: + - name + - units properties: - configurationUnits: + name: + type: string + description: Configuration Units + units: type: array description: Configuration Units items: + $ref: '#/components/schemas/Unit' + + ProfileResponse: + type: object + required: + - profile + - configurationUnits + - defaultConfigurations + properties: + profile: + $ref: '#/components/schemas/Profile' + configurationUnits: + type: object + additionalProperties: $ref: '#/components/schemas/ConfigurationUnits' defaultConfigurations: type: array - description: Default Configurations items: $ref: '#/components/schemas/Configuration' - profile: - $ref: '#/components/schemas/Profile' + Profile: + type: object + required: + - configurations + - targetPlatforms + properties: + configurations: + type: array + items: + $ref: '#/components/schemas/Configuration' + targetPlatforms: + type: array + items: + type: string + + Configuration: + type: object + required: + - key + - value + properties: + key: + type: string + description: Property Name + example: "cpu_limits" + value: + type: string + description: Property Value + example: "0.5"openapi: 3.0.3 +info: + title: Infra Config + description: API SPEC for Infra Configurations + version: 1.0.0 +servers: + - url: 'https' + +paths: + /orchestrator/infra-config/profile: + get: + description: Get Infra Profile by name + parameters: + - name: name + in: query + required: true + schema: + type: string + pattern: '^[a-z]+$' + responses: + "200": + description: Gets the infra config profile by its name + content: + application/json: + schema: + $ref: "#/components/schemas/ProfileResponse" + "400": + description: Invalid profile name + "401": + description: Unauthorized + "403": + description: Forbidden + "404": + description: Profile not found + "500": + description: Internal Server Error + + put: + description: Update Infra Profile + parameters: + - name: name + in: query + required: true + schema: + type: string + pattern: '^[a-z]+$' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + responses: + "200": + description: Successfully updated infra config profile + "400": + description: Invalid request payload + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal Server Error +components: + schemas: + Unit: + type: object + required: + - name + - conversionFactor + properties: + name: + type: string + description: Unit Name + example: "mi" + conversionFactor: + type: number + description: Conversion Factor to convert to base unit + example: 1 + ConfigurationUnits: + type: object + required: + - name + - units + properties: + name: + type: string + description: Configuration Units + units: + type: array + description: Configuration Units + items: + $ref: '#/components/schemas/Unit' + ProfileResponse: + type: object + required: + - profile + - configurationUnits + - defaultConfigurations + properties: + profile: + $ref: '#/components/schemas/Profile' + configurationUnits: + type: object + additionalProperties: + $ref: '#/components/schemas/ConfigurationUnits' + defaultConfigurations: + type: array + items: + $ref: '#/components/schemas/Configuration' + Profile: + type: object + required: + - configurations + - targetPlatforms + properties: + id: + type: integer + description: Profile Id + example: 1 + name: + type: string + description: Profile Name + example: "java" + description: + type: string + description: Profile Description + example: "all java apps should have this infra profile" + type: + type: string + description: Type of profile (DEFAULT, NORMAL, CUSTOM) + enum: [DEFAULT, NORMAL, CUSTOM] + example: "CUSTOM" + configurations: + type: array + description: Profile Configurations + items: + $ref: '#/components/schemas/Configuration' + targetPlatforms: + type: array + description: List of target platforms for this profile + items: + type: string + example: "linux/amd64" + appCount: + readOnly: true + type: integer + description: Number of apps using this profile + example: 1 + createdAt: + type: string + format: date-time + description: Profile creation timestamp + example: "2021-06-01T06:30:00.000Z" + updatedAt: + type: string + format: date-time + description: Profile last update timestamp + example: "2021-06-01T06:30:00.000Z" + createdBy: + type: integer + description: User ID who created the profile + example: 1 + updatedBy: + type: integer + description: User ID who last updated the profile + example: 1 Configuration: type: object + required: + - key + - value properties: id: type: integer - description: Property Id + description: Configuration ID example: 1 key: type: string - description: Property Name - required: true, + description: Configuration key example: "cpu_limits" value: - required: true, type: string - description: Property Value + description: Configuration value example: "0.5" profileName: type: string - description: Profile Name + description: Name of the profile this configuration belongs to example: "java" unit: type: string - description: Property Unit + description: Unit of the configuration value example: "m" active: type: boolean - description: Property Active + description: Whether the configuration is active example: true - - Profile: - type: object - properties: - id: - type: integer - description: Profile Id - example: 1 - name: - type: string - description: Profile Name - example: "java" - description: - type: string - description: Profile Description - example: "all java apps should have this infra profile" - type: - type: string - description: type of profile "eg:0,1,2" - example: DEFAULT,NORMAL,CUSTOM - configurations: - type: array - description: Profile Configurations - items: - $ref: '#/components/schemas/Configuration' - appCount: - readOnly: true - type: integer - description: Number of apps using this profile - example: 1 - createdAt: - required: false - type: string - description: Profile Created At - example: "2021-06-01T06:30:00.000Z" - updatedAt: - type: string - description: Profile Updated At - example: "2021-06-01T06:30:00.000Z" - createdBy: - type: integer - description: Profile Created By - example: 1 - updatedBy: - type: integer - description: Profile Updated By - example: 1 - - + platform: + type: string + description: Target platform for this configuration + example: "linux/amd64" diff --git a/specs/bulk_actions.yaml b/specs/bulk_actions.yaml deleted file mode 100644 index 8c1c7f57b8..0000000000 --- a/specs/bulk_actions.yaml +++ /dev/null @@ -1,155 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Bulk Actions - Hibernate, UnHibernate, Deploy Latest Builds -servers: - - url: http://localhost:3000/orchestrator/batch -paths: - /v1beta1/hibernate: - post: - description: Bulk Hibernate all apps for specific environment - operationId: BulkHibernate - requestBody: - description: bulk hibernate - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - responses: - '200': - description: Successfully hibernated all impacted apps. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /v1beta1/unhibernate: - post: - description: Bulk Unhibernate all apps for specific environment - operationId: BulkUnhibernate - requestBody: - description: bulk unhibernate - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - responses: - '200': - description: Successfully unhibernated all impacted apps. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /v1beta1/deploy: - post: - description: Bulk Deploy all apps to the latest build image for specific environment - operationId: BulkDeploy - requestBody: - description: bulk deploy - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - responses: - '200': - description: Successfully deploy all impacted apps. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionPayload' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - -components: - schemas: - BulkActionPayload: - type: object - required: envId - properties: - appIdIncludes: - type: array - items: - type: integer - appIdExcludes: - type: array - items: - type: integer - envId: - type: integer - description: environment id - - IdsIncludesExcludes: - type: object - properties: - ids: - type: array - items: - type: integer - description: app ids - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/change-deployment-chart-type.yaml b/specs/change-deployment-chart-type.yaml deleted file mode 100644 index 496352d04c..0000000000 --- a/specs/change-deployment-chart-type.yaml +++ /dev/null @@ -1,34 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs -paths: - /orchestrator/app/env/patch: - patch: - description: change the deployment template for an app and environment - requestBody: - content: - application/json: - schema: - properties: - envId: - type: integer - appId: - type: integer - targetChartRefId: - type: integer - - responses: - '200': - description: patched data - content: - application/json: - schema: - properties: - '422': - description: bad request - content: - application/json: - schema: - userDetailedMessage: - type: string \ No newline at end of file diff --git a/specs/charts.yaml b/specs/charts.yaml deleted file mode 100644 index 64ca3dfe8a..0000000000 --- a/specs/charts.yaml +++ /dev/null @@ -1,239 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: https://api.yourdomain.com - description: Production server -security: - - ApiKeyAuth: [] -paths: - /orchestrator/app-store/installed-app: - get: - summary: List deployed charts - operationId: listDeployedCharts - description: deployed chart listing, with search filters - security: - - ApiKeyAuth: [] - 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' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - /orchestrator/app-store/installed-app/notes: - get: - summary: Fetch notes.txt for deployed helm charts - operationId: fetchNotesTxt - description: Used to fetch notes.txt for helm charts deployed via gitOps - security: - - ApiKeyAuth: [] - parameters: - - name: env-id - in: query - description: it is an environment id of app - required: true - schema: - type: integer - - name: installed-app-id - in: query - description: it is a installed application id - required: true - schema: - type: integer - responses: - '200': - description: if it is able to fetch the notes.txt then status will be ok - content: - application/json: - schema: - properties: - notes: - type: string - description: it will provide notes - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - '500': - description: error while fetching notes.txt - - - -# components mentioned below -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - 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: - type: object - properties: - code: - type: integer - format: int32 - status: - type: string - result: - type: object - nullable: true - errors: - type: array - items: - type: object - properties: - userMessage: - type: string - nullable: true - internalMessage: - type: string - nullable: true - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message diff --git a/specs/ci-pipeline/ci-pipeline-build-spec.yaml b/specs/ci-pipeline/ci-pipeline-build-spec.yaml index 288889ec01..32526ebea0 100644 --- a/specs/ci-pipeline/ci-pipeline-build-spec.yaml +++ b/specs/ci-pipeline/ci-pipeline-build-spec.yaml @@ -1,58 +1,376 @@ -openapi: "3.0.0" +openapi: 3.0.0 info: version: 1.0.0 - title: Modularisation v1 APIs + title: CI Pipeline Build API + description: API for managing CI pipeline builds and related operations + contact: + name: Devtron Support + url: https://devtron.ai + email: support@devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + paths: /orchestrator/app/commit-info/{ciPipelineMaterialId}/{gitHash}: get: - description: Get commit info for a particular commit hash for a ci-pipeline-material + tags: + - Commit + summary: Get commit information + description: Retrieves commit information for a specific commit hash in a CI pipeline material + operationId: getCommitInfo parameters: - name: ciPipelineMaterialId - description: ci-pipeline-material id in: path + description: ID of the CI pipeline material required: true schema: type: integer + format: int32 + minimum: 1 + example: 123 - name: gitHash - description: git hash for that commit in: path + description: Git commit hash required: true schema: type: string + pattern: '^[a-f0-9]{7,40}$' + example: "a1b2c3d4e5" responses: - "200": - description: Successfully fetched commit info. if CommitInfo is null, then commit is not found. + '200': + description: Successfully retrieved commit information content: application/json: schema: type: array items: - $ref: "#/components/schemas/CommitInfo" + $ref: '#/components/schemas/CommitInfo' + '400': + description: Invalid input parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '404': + description: Commit not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + security: + - bearerAuth: [] + + /ci-pipeline/trigger: + post: + tags: + - Workflow + summary: Trigger CI workflow + description: Triggers a new CI workflow for the specified pipeline + operationId: triggerWorkflow + requestBody: + description: Workflow trigger payload + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowTriggerRequest' + responses: + '200': + description: Workflow triggered successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + security: + - bearerAuth: [] + + /{appId}/ci-pipeline/{pipelineId}/workflow/{workflowId}: + get: + tags: + - Workflow + summary: Get workflow details + description: Retrieves details of a specific workflow + operationId: getWorkflow + parameters: + - name: appId + in: path + description: ID of the application + required: true + schema: + type: integer + format: int32 + minimum: 1 + example: 123 + - name: pipelineId + in: path + description: ID of the CI pipeline + required: true + schema: + type: integer + format: int32 + minimum: 1 + example: 456 + - name: workflowId + in: path + description: ID of the workflow + required: true + schema: + type: integer + format: int32 + minimum: 1 + example: 789 + responses: + '200': + description: Workflow details retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '404': + description: Workflow not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + security: + - bearerAuth: [] -# Components components: schemas: CommitInfo: type: object + required: + - Commit + - Author + - Date properties: Commit: type: string - description: Commit hash - example: "somehash" + description: Full commit hash + example: "a1b2c3d4e5f6g7h8i9j0" + minLength: 7 + maxLength: 40 Author: type: string - description: Author of that commit - example: "manish" + description: Author of the commit + example: "John Doe " Date: type: string - description: Date that commit - example: "2021-08-10T16:28:26+05:30" + format: date-time + description: Timestamp of the commit + example: "2023-01-15T14:30:22Z" Message: type: string description: Commit message - example: "some message" + example: "Update README with new features" Changes: type: array - description: file names which were changed in this commit + description: List of files changed in this commit + items: + type: string + example: "src/main.go" + + WorkflowTriggerRequest: + type: object + required: + - pipelineId + - ciPipelineMaterials + properties: + pipelineId: + type: integer + description: ID of the CI pipeline to trigger + example: 123 + ciPipelineMaterials: + type: array + description: CI pipeline materials configuration + items: + $ref: '#/components/schemas/CiPipelineMaterial' + triggeredBy: + type: integer + description: User ID who triggered the pipeline + example: 1 + invalidateCache: + type: boolean + description: Whether to invalidate cache + default: false + environmentId: + type: integer + description: Environment ID for the pipeline + example: 456 + pipelineType: + type: string + description: Type of pipeline + example: "CI" + ciArtifactLastFetch: + type: string + format: date-time + description: Last fetch time for CI artifacts + + CiPipelineMaterial: + type: object + properties: + Id: + type: integer + description: Material ID + example: 1 + GitMaterialId: + type: integer + description: Git material ID + example: 2 + Type: + type: string + description: Type of material + example: "GIT" + Value: + type: string + description: Material value + example: "main" + Active: + type: boolean + description: Whether material is active + default: true + GitCommit: + $ref: '#/components/schemas/GitCommit' + GitTag: + type: string + description: Git tag + example: "v1.0.0" + + GitCommit: + type: object + properties: + Commit: + type: string + description: Commit hash + example: "a1b2c3d4e5" + Author: + type: string + description: Author name + example: "John Doe" + Date: + type: string + format: date-time + description: Commit date + example: "2023-01-15T14:30:22Z" + Message: + type: string + description: Commit message + example: "Update README" + + CIBuildConfig: + type: object + properties: + dockerBuildConfig: + $ref: '#/components/schemas/DockerBuildConfig' + ciBuildType: + type: string + enum: [SELF_DOCKERFILE_BUILD_TYPE, MANIFEST_PUSH, SKIP_BUILD] + + DockerBuildConfig: + type: object + properties: + dockerfilePath: + type: string + example: "./Dockerfile" + args: + type: object + additionalProperties: + type: string + + WorkflowResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 12345 + name: + type: string + example: "workflow-12345" + status: + type: string + enum: [QUEUED, RUNNING, SUCCEEDED, FAILED, ABORTED] + example: "QUEUED" + startTime: + type: string + format: date-time + example: "2023-01-15T14:30:22Z" + endTime: + type: string + format: date-time + example: "2023-01-15T14:35:45Z" + triggeredBy: + type: string + example: "user@example.com" + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array items: - type: string \ No newline at end of file + type: string + example: ["Commit not found in the repository"] + + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: >- + JWT token for authentication. + Include the token in the Authorization header as: 'Bearer {token}' \ No newline at end of file diff --git a/specs/ci-pipeline/ci-pipeline-change-source.yaml b/specs/ci-pipeline/ci-pipeline-change-source.yaml index b1a7c7d5b6..bedb0f1ede 100644 --- a/specs/ci-pipeline/ci-pipeline-change-source.yaml +++ b/specs/ci-pipeline/ci-pipeline-change-source.yaml @@ -5,40 +5,332 @@ info: paths: /orchestrator/app/ci-pipeline/patch-source: patch: - description: update source of a ci-matrial + summary: Update CI material source (branch/regex) for a specific app and environment + description: | + Updates the source configuration of a CI material for a specific application and environment. + This endpoint allows changing the branch name or regex pattern that triggers CI builds. + + **Supported Source Types:** + - `SOURCE_TYPE_BRANCH_FIXED`: Fixed branch name (e.g., "main", "develop") + - `SOURCE_TYPE_BRANCH_REGEX`: Regex pattern for branch matching (e.g., "feature-*") + + **Prerequisites:** + - User must have UPDATE permission on the application + - Application must be a custom app (not job or external app) + - Pipeline must exist for the given appId and environmentId + security: + - BearerAuth: [] requestBody: + required: true content: application/json: schema: $ref: "#/components/schemas/RequestBody" + examples: + branch_fixed: + summary: Change to fixed branch + description: Update CI material to use a fixed branch name + value: + appId: 16 + environmentId: 1 + source: + type: "SOURCE_TYPE_BRANCH_FIXED" + value: "main" + regex: "" + branch_regex: + summary: Change to regex pattern + description: Update CI material to use a regex pattern for branch matching + value: + appId: 16 + environmentId: 1 + source: + type: "SOURCE_TYPE_BRANCH_REGEX" + value: "feature-*" + regex: "feature-*" + develop_branch: + summary: Switch to develop branch + description: Update CI material to use develop branch + value: + appId: 25 + environmentId: 3 + source: + type: "SOURCE_TYPE_BRANCH_FIXED" + value: "develop" + regex: "" + hotfix_pattern: + summary: Use hotfix pattern + description: Update CI material to match hotfix branches + value: + appId: 30 + environmentId: 2 + source: + type: "SOURCE_TYPE_BRANCH_REGEX" + value: "hotfix/*" + regex: "hotfix/*" responses: "200": - description: Successfully fetched commit info. if CommitInfo is null, then commit is not found. + description: Successfully updated CI material source content: application/json: schema: - type: object + $ref: "#/components/schemas/SuccessResponse" + examples: + success_branch_fixed: + summary: Success - Branch Fixed + description: Successfully updated to fixed branch + value: + code: 200 + status: "OK" + result: + appId: 16 + environmentId: 1 + source: + type: "SOURCE_TYPE_BRANCH_FIXED" + value: "main" + regex: "" + success_branch_regex: + summary: Success - Branch Regex + description: Successfully updated to regex pattern + value: + code: 200 + status: "OK" + result: + appId: 16 + environmentId: 1 + source: + type: "SOURCE_TYPE_BRANCH_REGEX" + value: "feature-*" + regex: "feature-*" + "400": + description: Bad Request - Invalid request data or validation failed + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + examples: + invalid_source_type: + summary: Invalid Source Type + description: Unsupported source type provided + value: + code: 400 + status: "Bad Request" + errors: + - code: "400" + internalMessage: "source.type not supported" + userMessage: "source.type not supported" + missing_required_fields: + summary: Missing Required Fields + description: Required fields are missing from request + value: + code: 400 + status: "Bad Request" + errors: + - code: "400" + internalMessage: "Key: 'CiMaterialPatchRequest.AppId' Error:Field validation for 'AppId' failed on the 'required' tag" + userMessage: "AppId is required" + non_custom_app: + summary: Non-Custom App + description: Only custom applications are supported + value: + code: 400 + status: "Bad Request" + errors: + - code: "400" + internalMessage: "only custom apps supported" + userMessage: "only custom apps supported" + "401": + description: Unauthorized - Invalid or missing authentication token + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + examples: + missing_token: + summary: Missing Authentication Token + description: No authentication token provided + value: + code: 401 + status: "Unauthorized" + errors: + - code: "401" + internalMessage: "Unauthorized User" + userMessage: "Unauthorized User" + invalid_token: + summary: Invalid Token + description: Provided authentication token is invalid + value: + code: 401 + status: "Unauthorized" + errors: + - code: "401" + internalMessage: "Invalid token" + userMessage: "Invalid authentication token" + "403": + description: Forbidden - User doesn't have permission to update this app + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + examples: + insufficient_permissions: + summary: Insufficient Permissions + description: User lacks UPDATE permission on the application + value: + code: 403 + status: "Forbidden" + errors: + - code: "403" + internalMessage: "unauthorized user" + userMessage: "Unauthorized User" + "500": + description: Internal Server Error - Pipeline not found or other server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + examples: + pipeline_not_found: + summary: Pipeline Not Found + description: No pipeline exists for the given appId and environmentId + value: + code: 500 + status: "Internal Server Error" + errors: + - code: "000" + internalMessage: "[{unique pipeline was not found, for the given appId and environmentId}]" + userMessage: "unique pipeline was not found, for the given appId and environmentId" + multiple_pipelines: + summary: Multiple Pipelines Found + description: Multiple pipelines found for the given appId and environmentId + value: + code: 500 + status: "Internal Server Error" + errors: + - code: "000" + internalMessage: "[{multiple pipelines found for the given appId and environmentId}]" + userMessage: "multiple pipelines found for the given appId and environmentId" + database_error: + summary: Database Error + description: Database operation failed + value: + code: 500 + status: "Internal Server Error" + errors: + - code: "000" + internalMessage: "[{database connection error}]" + userMessage: "Database operation failed" -#{"appId": 16, "environmentId": 1, "source": {"type":"SOURCE_TYPE_BRANCH_FIXED", "value": "main1", "regex":""}} # Components components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication. Include in Authorization header as 'Bearer ' + schemas: RequestBody: type: object + required: + - appId + - environmentId + - source properties: appId: type: integer + description: Application ID - must be a custom application (not job or external app) + example: 16 + minimum: 1 environmentId: type: integer + description: Environment ID where the CI pipeline is configured + example: 1 + minimum: 1 source: - type: object - properties: - type: - type: string - description: "SOURCE_TYPE_BRANCH_FIXED / SOURCE_TYPE_BRANCH_REGEX" - value: - type: string - description: "name of the branch" - regex: - type: string - description: "regular expression when type is SOURCE_TYPE_BRANCH_REGEX" \ No newline at end of file + $ref: "#/components/schemas/SourceTypeConfig" + + SourceTypeConfig: + type: object + required: + - type + - value + properties: + type: + type: string + enum: + - SOURCE_TYPE_BRANCH_FIXED + - SOURCE_TYPE_BRANCH_REGEX + description: | + Source type for CI material. + - `SOURCE_TYPE_BRANCH_FIXED`: Use a specific branch name + - `SOURCE_TYPE_BRANCH_REGEX`: Use a regex pattern to match multiple branches + example: "SOURCE_TYPE_BRANCH_FIXED" + value: + type: string + description: | + Branch name or regex pattern. + - For `SOURCE_TYPE_BRANCH_FIXED`: The exact branch name (e.g., "main", "develop") + - For `SOURCE_TYPE_BRANCH_REGEX`: The regex pattern to match branches (e.g., "feature-*", "hotfix/*") + example: "main" + minLength: 1 + regex: + type: string + description: | + Regular expression pattern (only used when type is SOURCE_TYPE_BRANCH_REGEX). + Must match the value field for regex type. + example: "feature-*" + default: "" + + SuccessResponse: + type: object + properties: + code: + type: integer + description: HTTP status code + example: 200 + status: + type: string + description: Status message + example: "OK" + result: + $ref: "#/components/schemas/RequestBody" + + ErrorResponse: + type: object + required: + - code + - status + properties: + code: + type: integer + description: HTTP status code + example: 500 + status: + type: string + description: Error status message + example: "Internal Server Error" + errors: + type: array + items: + $ref: "#/components/schemas/Error" + + Error: + type: object + required: + - code + - internalMessage + - userMessage + properties: + code: + type: string + description: Error code for internal tracking + example: "000" + internalMessage: + type: string + description: Internal error message for debugging (not shown to end users) + example: "[{unique pipeline was not found, for the given appId and environmentId}]" + userMessage: + type: string + description: User-friendly error message that can be displayed to end users + example: "unique pipeline was not found, for the given appId and environmentId" \ No newline at end of file diff --git a/specs/cluster_access_policy.yaml b/specs/cluster_access_policy.yaml deleted file mode 100644 index a8d71c2449..0000000000 --- a/specs/cluster_access_policy.yaml +++ /dev/null @@ -1,171 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Cluster access policy -paths: - /orchestrator/user: - post: - summary: Creates a new User - operationId: addUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: create user response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: update user - operationId: updateUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: user response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/role/group: - post: - summary: Creates a new role group - operationId: addUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - responses: - '200': - description: create user response - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: update user - operationId: updateUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - responses: - '200': - description: user response - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - User: - type: object - required: - - email_id - properties: - id: - type: integer - description: Unique id of user - email_id: - type: string - description: Unique valid email-id of user, comma separated emails ids for multiple users - groups: - type: array - items: - type: string - roleFilters: - type: array - items: - $ref: '#/components/schemas/roleFilter' - description: role filters objects - RoleGroup: - type: object - properties: - id: - type: integer - name: - type: string - roleFilters: - type: array - items: - $ref: '#/components/schemas/roleFilter' - description: role filters objects - roleFilter: - type: object - required: - - action - properties: - cluster: - type: string - description: cluster name - namespace: - type: string - description: namespace names. for multiple selection comma separated values, for all selection an empty string. - group: - type: string - description: group names. for multiple selection comma separated values, for all selection an empty string. - kind: - type: string - description: kind names. for multiple selection comma separated values, for all selection an empty string. - resource: - type: string - description: resource names. for multiple selection comma separated values, for all selection an empty string. - action: - type: string - description: action is type of role, i.e, admin, trigger, view, etc. - enum: ["view","edit","admin"] - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/cluster_add_api_specs.yaml b/specs/cluster_add_api_specs.yaml deleted file mode 100644 index 4c1c019088..0000000000 --- a/specs/cluster_add_api_specs.yaml +++ /dev/null @@ -1,167 +0,0 @@ -openapi: 3.0.0 -info: - title: Cluster API - version: 1.0.0 - description: API for managing clusters - -paths: - /orchestrator/cluster/validate: - post: - description: Validate a cluster - requestBody: - content: - application/json: - schema: - type: object - properties: - kubeconfig: - $ref: '#/components/schemas/Kubeconfig' - required: - - kubeconfig - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ValidateClusterBean' - '400': - description: Bad request - '500': - description: Internal server error - /orchestrator/cluster/saveClusters: - post: - description: Save clusters - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ValidateClusterBean' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ValidateClusterBean' - '400': - description: Bad request - '500': - description: Internal server error -components: - schemas: - Kubeconfig: - type: object - properties: - config: - type: string - ValidateClusterBean: - type: object - properties: - userInfos: - type: object - additionalProperties: - $ref: '#/components/schemas/UserInfos' - id: - type: integer - cluster_name: - type: string - server_url: - type: string - prometheus_url: - type: string - active: - type: boolean - config: - type: object - properties: - bearer_token: - type: string - description: it will be empty while fetching, and if no change while updating - tls_key: - type: string - description: it will be empty while fetching, and if no change while updating - cert_data: - type: string - description: it will be empty while fetching, and if no change while updating - cert_auth_data: - type: string - description: it will be empty while fetching, and if no change while updating - prometheusAuth: - $ref: '#/components/schemas/PrometheusAuth' - defaultClusterComponent: - type: array - items: - $ref: '#/components/schemas/DefaultClusterComponent' - agentInstallationStage: - type: integer - k8sVersion: - type: string - userName: - type: string - insecure-skip-tls-verify: - type: boolean - required: - - cluster_name - - server_url - UserInfos: - type: object - properties: - userName: - type: string - config: - type: object - additionalProperties: - type: string - errorInConnecting: - type: string - PrometheusAuth: - type: object - properties: - type: - type: string - enum: - - basic - - bearer - basic: - type: object - properties: - username: - type: string - password: - type: string - bearer: - type: object - properties: - token: - type: string - DefaultClusterComponent: - type: object - properties: - id: - type: string - name: - type: string - version: - type: string - status: - type: string - configuration: - $ref: '#/components/schemas/Configuration' - Configuration: - type: object - properties: - type: - type: string - enum: - - yaml - - json - - - - - diff --git a/specs/api-spec.yaml b/specs/common/api-spec.yaml similarity index 90% rename from specs/api-spec.yaml rename to specs/common/api-spec.yaml index ef6e7c6fdf..6b5b1c8e83 100644 --- a/specs/api-spec.yaml +++ b/specs/common/api-spec.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: version: 1.0.0 - title: Devtron Labs + title: Common API Utilities paths: /orchestrator/application/rollback: put: @@ -90,10 +90,18 @@ components: type: string description: Values yaml example: "some values yaml" + chartData: + type: string + format: byte + description: Chart Data in case of base deployment template TemplateChartResponse: type: object properties: manifest: type: string description: helm generated manifest - example: "some manifest" \ No newline at end of file + example: "some manifest" + chartBytes: + type: string + format: byte + description: Chart bytes data \ No newline at end of file diff --git a/specs/delete-options.yaml b/specs/common/delete-options.yaml similarity index 74% rename from specs/delete-options.yaml rename to specs/common/delete-options.yaml index 9d853e9386..3720f9be78 100644 --- a/specs/delete-options.yaml +++ b/specs/common/delete-options.yaml @@ -2,11 +2,34 @@ openapi: "3.0.0" info: version: 1.0.0 title: Delete Option support for various components + description: API for deleting various components in Devtron including clusters, environments, teams, and other resources + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication paths: /orchestrator/cluster/delete: post: description: Delete Cluster operationId: DeleteFromDb + security: + - bearerAuth: [] requestBody: description: A JSON object containing the cluster config required: true @@ -27,23 +50,25 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized User content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User + $ref: '#/components/schemas/ApiError' + '500': + description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' - /orchestrator/env/delete: + $ref: '#/components/schemas/ApiError' + /env/delete: post: description: Delete Environment operationId: Delete + security: + - bearerAuth: [] requestBody: description: A JSON object containing the env config required: true @@ -59,6 +84,103 @@ paths: schema: type: string example: "Environment deleted successfully." + '400': + description: Bad Request. Input Validation(decode) error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + /team: + post: + description: Create Project + operationId: SaveTeam + security: + - bearerAuth: [] + requestBody: + description: A JSON object containing the project config + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequest' + responses: + '200': + description: Successfully created the project + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequest' + '400': + description: Bad Request. Input Validation(decode) error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + get: + description: Get All Projects + operationId: FetchAll + responses: + '200': + description: Successfully retrieved all projects + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TeamRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + description: Update Project + operationId: UpdateTeam + requestBody: + description: A JSON object containing the project config + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequest' + responses: + '200': + description: Successfully updated the project + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequest' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -77,8 +199,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/team/delete: - post: + delete: description: Delete Project operationId: DeleteTeam requestBody: @@ -114,7 +235,68 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/git/provider/delete: + /team/autocomplete: + get: + description: Get Projects for Autocomplete + operationId: FetchForAutocomplete + responses: + '200': + description: Successfully retrieved projects for autocomplete + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TeamRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /team/{id}: + get: + description: Get Project by ID + operationId: FetchOne + parameters: + - name: id + in: path + required: true + schema: + type: integer + description: Project ID + responses: + '200': + description: Successfully retrieved the project + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequest' + '400': + description: Bad Request. Invalid ID format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /git/provider/delete: post: description: Delete Git Provider operationId: DeleteGitRepoConfig @@ -151,7 +333,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/docker/registry/delete: + /docker/registry/delete: post: description: Delete Docker Registry operationId: DeleteDockerRegistryConfig @@ -188,7 +370,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/app-store/repo/delete: + /app-store/repo/delete: post: description: Delete Chart Repo operationId: DeleteChartRepo @@ -225,7 +407,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/app/material/delete: + /app/material/delete: post: description: Delete Git Material operationId: DeleteMaterial @@ -262,7 +444,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/chart-group/delete: + /chart-group/delete: post: description: Delete Chart Group operationId: DeleteChartgroup @@ -299,7 +481,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/notification/channel/delete: + /notification/channel/delete: post: description: Delete Notification Channel operationId: DeleteNotificationChannelConfig @@ -646,4 +828,20 @@ components: description: Error code message: type: string - description: Error message \ No newline at end of file + description: Error message + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Resource not found in the system"] \ No newline at end of file diff --git a/specs/common/schemas.yaml b/specs/common/schemas.yaml new file mode 100644 index 0000000000..3a6bd9a8ec --- /dev/null +++ b/specs/common/schemas.yaml @@ -0,0 +1,572 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Devtron Common Schemas + description: Shared schemas and components used across all Devtron API specifications + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication + + schemas: + # Common Response Schemas + ApiResponse: + type: object + properties: + code: + type: integer + description: HTTP status code + example: 200 + status: + type: string + description: HTTP status message + example: OK + result: + type: object + description: Response result data + + ErrorResponse: + type: object + required: + - code + - status + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + result: + type: object + nullable: true + errors: + type: array + items: + $ref: '#/components/schemas/Error' + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error internal code + message: + type: string + description: Error message + internalMessage: + type: string + description: Error internal message + userMessage: + type: string + description: Error user message + + # Application Related Schemas + AppLabel: + type: object + required: + - key + - value + properties: + key: + type: string + description: Label key + value: + type: string + description: Label value + propagate: + type: boolean + description: Whether to propagate to kubernetes resources + + AppMetaInfo: + type: object + required: + - appId + - projectId + - appName + - projectName + - createdOn + - createdBy + properties: + appId: + type: integer + description: Application ID + projectId: + type: integer + description: Team/project ID + appName: + type: string + description: Application name + projectName: + type: string + description: Team/project name + description: + type: string + description: Application description + labels: + type: array + items: + $ref: '#/components/schemas/AppLabel' + createdOn: + type: string + format: date-time + description: Application creation date + createdBy: + type: string + description: Application created by + active: + type: boolean + description: Whether application is active + note: + $ref: '#/components/schemas/GenericNoteResponse' + + App: + type: object + required: + - appName + properties: + id: + type: integer + format: int64 + description: Application ID + appName: + type: string + description: Name of the application + teamId: + type: integer + format: int64 + description: Team ID + templateId: + type: integer + description: Reference app id, used for clone, set default value 0 for blank app + labels: + type: array + description: Application labels (optional) + items: + $ref: '#/components/schemas/AppLabel' + description: + type: string + description: Application description + projectIds: + type: array + items: + type: integer + format: int64 + description: IDs of projects this application belongs to + + AppContainer: + type: object + required: + - appId + - appName + - environments + properties: + appId: + type: integer + description: Application ID + appName: + type: string + description: Application name + environments: + type: array + items: + $ref: '#/components/schemas/EnvContainer' + + EnvContainer: + type: object + required: + - appId + - appName + - environmentId + - environmentName + properties: + appId: + type: integer + description: Application ID + appName: + type: string + description: Application name + cdStageStatus: + type: string + description: CD stage status + dataSource: + type: string + description: Data source + ciArtifactId: + type: integer + description: CI artifact ID + deleted: + type: boolean + description: Whether deleted + environmentId: + type: integer + description: Environment ID + environmentName: + type: string + description: Environment name + status: + type: string + description: Status + appStatus: + type: string + description: Application status for this environment + postStageStatus: + type: string + description: Post stage status + preStageStatus: + type: string + description: Pre stage status + lastDeployedTime: + type: string + description: Last deployment time + materialInfo: + type: array + items: + type: object + + AppProjectUpdateRequest: + type: object + required: + - appId + - projectIds + properties: + appId: + type: integer + format: int64 + description: Application ID + projectIds: + type: array + items: + type: integer + format: int64 + description: IDs of projects to associate with the application + + AppListingRequest: + type: object + properties: + appNameSearch: + type: string + description: Application name search, wildcard match + offset: + type: integer + description: Pagination offset + size: + type: integer + description: Page size + sortBy: + type: string + description: Sort by field + sortOrder: + type: string + description: Sort order + environments: + type: array + description: Environment IDs + items: + type: integer + teams: + type: array + description: Team IDs (project IDs) + items: + type: integer + labels: + type: array + description: Application labels + items: + type: string + statuses: + type: array + description: Application statuses + items: + type: string + + DeploymentGroup: + type: object + required: + - id + properties: + id: + type: integer + description: Deployment group ID + ciPipelineId: + type: integer + description: CI pipeline ID + environmentId: + type: integer + description: Environment ID + appCount: + type: integer + description: Application count + name: + type: string + description: Deployment group name + noOfApps: + type: string + description: Number of applications + + # Common Utility Schemas + GenericNoteResponse: + type: object + properties: + id: + type: integer + description: Note ID + description: + type: string + description: Note content/description + createdOn: + type: string + format: date-time + description: Creation timestamp + createdBy: + type: string + description: Creator's email + updatedOn: + type: string + format: date-time + description: Last update timestamp + updatedBy: + type: string + description: Last updater's email + + ListingRequest: + type: object + properties: + searchKey: + type: string + nullable: true + sortOrder: + type: string + enum: [ASC, DESC] + nullable: true + sortBy: + type: string + nullable: true + offset: + type: integer + format: int32 + minimum: 0 + nullable: true + size: + type: integer + format: int32 + minimum: 1 + default: 20 + nullable: true + showAll: + type: boolean + nullable: true + readOnly: true + + # Git Material Schemas + GitMaterial: + type: object + properties: + name: + type: string + url: + type: string + id: + type: integer + gitProviderId: + type: integer + checkoutPath: + type: string + fetchSubmodules: + type: boolean + isUsedInCiConfig: + type: boolean + + GitMaterialMeta: + type: object + properties: + displayName: + type: string + description: Display name of the git material + redirectionUrl: + type: string + description: HTTPS URL for redirection + originalUrl: + type: string + description: Original git URL + + # Template Schemas + TemplateConfig: + type: object + properties: + id: + type: integer + description: Template config ID + identifier: + type: string + description: Template identifier + name: + type: string + description: Template name + + # Chart Related Schemas + ChartUsed: + type: object + properties: + appStoreChartName: + type: string + description: Name of the chart from app store + appStoreChartId: + type: integer + description: ID of the chart from app store + appStoreAppName: + type: string + description: Name of the app in app store + appStoreAppVersion: + type: string + description: Version of the app in app store + chartAvatar: + type: string + description: Avatar/icon of the chart + + 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: App store application version ID + appStoreApplicationName: + type: string + description: Chart name externally + chartName: + type: string + description: Chart repo name + icon: + type: string + description: Chart icon + status: + type: string + description: Status of deployed chart + appName: + type: string + description: Chart name as app name for devtron + environmentName: + type: string + description: Environment name + deployedAt: + type: string + description: Deployment time + deployedBy: + type: string + description: User who deployed + readme: + type: string + description: Chart readme + deprecated: + type: boolean + description: Whether chart is deprecated + + # Bulk Operation Schemas + NameIncludesExcludes: + type: object + properties: + names: + type: array + items: + type: string + description: All strings of app names to be included/excluded + + BulkActionRequest: + type: object + properties: + includes: + $ref: '#/components/schemas/NameIncludesExcludes' + excludes: + $ref: '#/components/schemas/NameIncludesExcludes' + envIds: + type: array + items: + type: integer + description: All Environment IDs for the bulk action + appIds: + type: array + items: + type: integer + description: All Application IDs for the bulk action + projectIds: + type: array + items: + type: integer + description: All Project IDs for the bulk action + + BulkActionResponse: + type: object + properties: + message: + type: array + items: + type: string + description: Top-level messages in response of the bulk action + failure: + type: array + items: + $ref: '#/components/schemas/BulkActionFailureDetail' + description: Details of all items on which the bulk action failed + successful: + type: array + items: + $ref: '#/components/schemas/BulkActionSuccessDetail' + description: Details of all items on which the bulk action applied successfully + + BulkActionFailureDetail: + type: object + properties: + appId: + type: integer + appName: + type: string + envId: + type: integer + message: + type: string + + BulkActionSuccessDetail: + type: object + properties: + appId: + type: integer + appName: + type: string + envId: + type: integer + message: + type: string diff --git a/specs/version.yml b/specs/common/version.yaml similarity index 100% rename from specs/version.yml rename to specs/common/version.yaml diff --git a/specs/configDiffView.yaml b/specs/configDiffView.yaml deleted file mode 100644 index 8a24d50989..0000000000 --- a/specs/configDiffView.yaml +++ /dev/null @@ -1,73 +0,0 @@ -openapi: 3.0.0 -info: - title: Orchestrator Config Autocomplete API - version: 1.0.0 -paths: - /orchestrator/config/autocomplete: - get: - summary: Retrieve autocomplete data for configuration based on the provided appId and envId. The response includes configuration definitions with names, draft states, and types. - parameters: - - name: appId - in: query - description: The application ID. - required: true - schema: - type: string - - name: envId - in: query - description: The environment ID. - required: true - schema: - type: string - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/ConfigProperty" - - '500': - description: will get this response if any failure occurs at server side. - '400': - description: will get this response if invalid payload is sent in the request. - '403': - description: will get this response if user doesn't view access permission for the app or env - '404': - description: will get this when BaseDeployment Template is not configured - -components: - schemas: - ConfigDataResponse: - type: object - properties: - resourceConfig: - type: array - items: - $ref: '#/components/schemas/ConfigProperty' - - ConfigProperty: - type: object - properties: - name: - type: string - description: Name of the config - example: cm-1 - nullable: true - configState: - $ref: '#/components/schemas/ConfigStateEnum' - type: - $ref: '#/components/schemas/ResourceTypeEnum' - - ConfigStateEnum: - type: integer - enum: [ 1, 2, 3 ] - description: State of config (1 represents draft state , 2 represents approval pending state,3 represents published state) - - ResourceTypeEnum: - type: string - enum: [ "ConfigMap", "Secret", "Deployment Template" ] - description: Describe the config type (possible values are ConfigMap, Secret, Deployment Template) - diff --git a/specs/default-template-values.yaml b/specs/default-template-values.yaml deleted file mode 100644 index d839039f9b..0000000000 --- a/specs/default-template-values.yaml +++ /dev/null @@ -1,40 +0,0 @@ -openapi: "3.0.3" -info: - version: 1.0.0 - title: Devtron Labs -paths: - /orchestrator/app/template/default: - get: - description: Get default values of template by chartRefId - parameters: - - name: appId - in: query - required: true - schema: - type: integer - - name: chartRefId - in: query - required: true - schema: - type: integer - responses: - "200": - description: value - content: - application/json: - schema: - $ref: "#/components/schemas/DefaultTemplateResponse" -components: - schemas: - DefaultTemplateResponse: - properties: - appOverride: - type: array - items: - type: object - properties: - Key: - type: string - Value: - type: string - description: template json in form of map diff --git a/specs/deployment_app_type_change_api.yaml b/specs/deployment/app-type-change.yaml similarity index 57% rename from specs/deployment_app_type_change_api.yaml rename to specs/deployment/app-type-change.yaml index 5f1e3372ab..a482e3c1e1 100644 --- a/specs/deployment_app_type_change_api.yaml +++ b/specs/deployment/app-type-change.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: version: 1.0.0 - title: Devtron Labs + title: Application Type Change API paths: /orchestrator/app/cd-pipeline/patch/deployment: post: @@ -10,7 +10,7 @@ paths: description: A JSON object containing environment id and desired deployment app type required: true content: - text/plain: + application/json: schema: $ref: '#/components/schemas/DeploymentAppTypeChangeRequest' responses: @@ -23,9 +23,9 @@ paths: '401': description: unauthorized user content: - text/plain: + application/json: schema: - type: string + $ref: '#/components/schemas/Error' '400': description: Bad Request. Validation error/wrong request body. content: @@ -40,12 +40,19 @@ paths: $ref: '#/components/schemas/Error' '403': description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' # components mentioned below components: schemas: DeploymentAppTypeChangeRequest: type: object + required: + - envId + - desiredDeploymentType properties: envId: type: integer @@ -53,59 +60,86 @@ components: desiredDeploymentType: type: string description: Desired deployment type. For eg argo_cd / helm + enum: [argo_cd, helm] excludeApps: type: array + items: + type: integer description: List of app ids to be excluded includeApps: type: array + items: + type: integer description: List of app ids to be included (deployment will be changed only for these apps) + autoTriggerDeployment: + type: boolean + description: Whether to automatically trigger deployment after type change + userId: + type: integer + format: int32 + description: User ID who initiated the change DeploymentChangeStatus: type: object properties: - id: + pipelineId: + type: integer + description: CD pipeline id + installedAppId: type: integer - description: cd pipeline id + description: Installed app id (for chart store apps) + appId: + type: integer + description: App id appName: type: string - description: app name + description: App name + envId: + type: integer + description: Environment id envName: type: string - description: environment name + description: Environment name error: type: string description: Error message if failed to change deployment app type status: type: string - description: If deployment change was successful or failed for this pipeline + description: Status of deployment change + enum: [Success, Failed, INITIATED, NOT_YET_DELETED, permission denied] DeploymentAppTypeChangeResponse: type: object properties: envId: type: integer - description: environment id + description: Environment id desiredDeploymentType: type: string - description: Desired deployment type. For eg argo_cd / helm + description: Desired deployment type + enum: [argo_cd, helm] successfulPipelines: type: array - description: Pipelines which were successfully deleted from current deployment + description: Pipelines which were successfully changed items: - $ref: '#components/schemas/DeploymentChangeStatus' + $ref: '#/components/schemas/DeploymentChangeStatus' failedPipelines: type: array - description: Pipelines which failed to get deleted from current deployment + description: Pipelines which failed to change deployment app type items: - $ref: '#components/schemas/DeploymentChangeStatus' - TriggeredPipelineDetails: - type: object - properties: - ciArtifactId: - type: integer - description: Artifact id deployed - pipelineId: - type: integer - description: Pipeline id for which deployment was triggered + $ref: '#/components/schemas/DeploymentChangeStatus' + triggeredPipelines: + type: array + description: Pipelines for which deployment was triggered + items: + type: object + properties: + ciArtifactId: + type: integer + description: CI artifact id + pipelineId: + type: integer + description: Pipeline id OkResponse: + type: object required: - code - status @@ -114,26 +148,30 @@ components: code: type: integer format: int32 - description: Error code + description: HTTP status code status: type: string - description: Error message + description: Status message result: - type: object - description: DeploymentAppTypeChangeResponse object + $ref: '#/components/schemas/DeploymentAppTypeChangeResponse' Error: + type: object required: - code - - status + - message properties: code: - type: integer - format: int32 - description: Error internal code + type: string + description: Error code + example: E100 + message: + type: string + description: Error message + example: User is not authenticated internalMessage: type: string - description: Error internal message + description: Internal error message for debugging userMessage: type: string - description: Error user message + description: User-friendly error message diff --git a/specs/deployments.yaml b/specs/deployment/core.yaml similarity index 54% rename from specs/deployments.yaml rename to specs/deployment/core.yaml index 2a47ec1842..b0cac22c5f 100644 --- a/specs/deployments.yaml +++ b/specs/deployment/core.yaml @@ -1,7 +1,18 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron Labs + title: Deployment Template Management + description: Devtron API for deployment template management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 paths: /orchestrator/deployment/template/validate: post: @@ -13,8 +24,9 @@ paths: multipart/form-data: schema: properties: - binaryFile: - type: object + BinaryFile: + type: string + format: binary description: zipped chart template file responses: '200': @@ -26,8 +38,19 @@ paths: code: type: integer description: status code - schema: + status: + type: string + description: status + result: $ref: '#/components/schemas/UploadTemplateResponse' + '400': + description: Bad request - validation error, unsupported format, or file parsing error + '401': + description: Unauthorized user + '403': + description: Forbidden - insufficient permissions + '500': + description: Internal server error default: description: unexpected error content: @@ -39,13 +62,12 @@ paths: put: description: upload template file from this api. requestBody: - description: form-data as request body + description: json as request body required: true content: application/json: schema: $ref: '#/components/schemas/UploadTemplateRequest' - responses: '200': description: template file upload response @@ -62,6 +84,14 @@ paths: result: type: string description: result + '400': + description: Bad request - validation error + '401': + description: Unauthorized user + '403': + description: Forbidden - insufficient permissions + '500': + description: Internal server error default: description: unexpected error content: @@ -79,7 +109,22 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Chart' + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: array + description: list of charts + items: + $ref: '#/components/schemas/Chart' + '401': + description: Unauthorized user + '500': + description: Internal server error default: description: unexpected error content: @@ -94,30 +139,57 @@ components: properties: fileId: type: string + description: ID of the uploaded file action: type: string + description: Action to perform (e.g. "upload", "validate") UploadTemplateResponse: type: object properties: chartName: type: string + description: Name of the chart description: type: string + description: Chart description fileId: type: string + description: ID of the uploaded file action: type: string + description: Action performed message: type: string + description: Response message Chart: type: object properties: name: type: string + description: Chart name description: type: string + description: Chart description count: type: integer + description: Number of deployments using this chart + version: + type: string + description: Chart version + createdOn: + type: string + format: date-time + description: Creation timestamp + createdBy: + type: string + description: Creator's name + updatedOn: + type: string + format: date-time + description: Last update timestamp + updatedBy: + type: string + description: Last updater's name ErrorResponse: required: - code diff --git a/specs/deployment/group.yaml b/specs/deployment/group.yaml new file mode 100644 index 0000000000..250e370f10 --- /dev/null +++ b/specs/deployment/group.yaml @@ -0,0 +1,301 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Deployment Group Management + description: Devtron API for deployment group management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 +paths: + /orchestrator/deployment-group/create: + post: + description: Create a new deployment group + requestBody: + description: Deployment group details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupRequest' + responses: + '200': + description: Deployment group created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /deployment-group/update: + put: + description: Update an existing deployment group + requestBody: + description: Updated deployment group details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupRequest' + responses: + '200': + description: Deployment group updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /deployment-group/delete: + delete: + description: Delete a deployment group + parameters: + - name: groupId + in: path + required: true + schema: + type: integer + description: Deployment group ID + responses: + '200': + description: Deployment group deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /deployment-group/trigger: + post: + description: Trigger deployment for a group + requestBody: + description: Deployment trigger details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupTrigger' + responses: + '200': + description: Deployment triggered successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentGroupTriggerResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + DeploymentGroupRequest: + type: object + required: + - name + - appIds + properties: + name: + type: string + description: Name of the deployment group + description: + type: string + description: Description of the deployment group + appIds: + type: array + items: + type: integer + description: List of application IDs in the group + envId: + type: integer + description: Environment ID + userId: + type: integer + description: User ID who created/updated the group + + DeploymentGroupResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + groupId: + type: integer + description: ID of the deployment group + name: + type: string + description: Name of the deployment group + description: + type: string + description: Description of the deployment group + appIds: + type: array + items: + type: integer + description: List of application IDs in the group + envId: + type: integer + description: Environment ID + createdOn: + type: string + format: date-time + description: Creation timestamp + createdBy: + type: string + description: Creator's name + updatedOn: + type: string + format: date-time + description: Last update timestamp + updatedBy: + type: string + description: Last updater's name + + DeploymentGroupTrigger: + type: object + required: + - groupId + properties: + groupId: + type: integer + description: Deployment group ID + artifactId: + type: integer + description: Artifact ID to deploy + triggeredBy: + type: integer + description: User ID who triggered the deployment + + DeploymentGroupTriggerResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + groupId: + type: integer + description: Deployment group ID + workflowIds: + type: array + items: + type: integer + description: List of workflow IDs + + ErrorResponse: + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/deployment/pipeline.yaml b/specs/deployment/pipeline.yaml new file mode 100644 index 0000000000..7b6a8940bf --- /dev/null +++ b/specs/deployment/pipeline.yaml @@ -0,0 +1,366 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Deployment Pipeline Management + description: Devtron API for deployment pipeline management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 +paths: + /orchestrator/deployment/pipeline/configure: + post: + description: Configure deployment pipeline for an application + requestBody: + description: Pipeline configuration details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineConfig' + responses: + '200': + description: Pipeline configured successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineConfigResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/deployment/pipeline/trigger: + post: + description: Trigger a deployment pipeline + requestBody: + description: Pipeline trigger details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineTrigger' + responses: + '200': + description: Pipeline triggered successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineTriggerResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/deployment/pipeline/rollback: + post: + description: Rollback a deployment pipeline + requestBody: + description: Pipeline rollback details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineRollback' + responses: + '200': + description: Pipeline rollback initiated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineRollbackResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/deployment/pipeline/history: + get: + description: Get deployment pipeline history + parameters: + - name: appId + in: query + required: true + schema: + type: integer + description: Application ID + - name: envId + in: query + required: true + schema: + type: integer + description: Environment ID + responses: + '200': + description: Pipeline history retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineHistory' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + PipelineConfig: + type: object + required: + - appId + - envId + properties: + appId: + type: integer + description: Application ID + envId: + type: integer + description: Environment ID + pipelineName: + type: string + description: Name of the pipeline + triggerType: + type: string + enum: [AUTOMATIC, MANUAL] + description: Type of pipeline trigger + deploymentType: + type: string + enum: [HELM, ARGOCD] + description: Type of deployment + deploymentStrategy: + type: string + enum: [ROLLING, BLUE_GREEN, RECREATE] + description: Deployment strategy + preDeploymentScript: + type: string + description: Pre-deployment script + postDeploymentScript: + type: string + description: Post-deployment script + + PipelineConfigResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + pipelineId: + type: integer + description: ID of the created pipeline + pipelineName: + type: string + description: Name of the pipeline + + PipelineTrigger: + type: object + required: + - pipelineId + properties: + pipelineId: + type: integer + description: Pipeline ID + artifactId: + type: integer + description: Artifact ID to deploy + triggeredBy: + type: integer + description: User ID who triggered the pipeline + + PipelineTriggerResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + pipelineId: + type: integer + description: Pipeline ID + workflowId: + type: integer + description: Workflow ID + + PipelineRollback: + type: object + required: + - pipelineId + - version + properties: + pipelineId: + type: integer + description: Pipeline ID + version: + type: string + description: Version to rollback to + triggeredBy: + type: integer + description: User ID who triggered the rollback + + PipelineRollbackResponse: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: object + properties: + pipelineId: + type: integer + description: Pipeline ID + workflowId: + type: integer + description: Workflow ID + + PipelineHistory: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status message + result: + type: array + items: + type: object + properties: + pipelineId: + type: integer + description: Pipeline ID + workflowId: + type: integer + description: Workflow ID + status: + type: string + description: Pipeline status + startedOn: + type: string + format: date-time + description: Start time + finishedOn: + type: string + format: date-time + description: End time + triggeredBy: + type: string + description: User who triggered the pipeline + artifactId: + type: integer + description: Artifact ID + version: + type: string + description: Deployed version + + ErrorResponse: + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/rollback.yaml b/specs/deployment/rollback.yaml similarity index 71% rename from specs/rollback.yaml rename to specs/deployment/rollback.yaml index bc61fd188b..af68e9752f 100644 --- a/specs/rollback.yaml +++ b/specs/deployment/rollback.yaml @@ -1,7 +1,7 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Historical Task definitions - get api changes + title: Rollback API paths: /orchestrator/app/history/deployed-configuration/all/{appId}/{pipelineId}/{wfrId}: get: @@ -13,16 +13,19 @@ paths: required: true schema: type: integer + description: ID of the application - name: pipelineId in: path required: true schema: type: integer + description: ID of the pipeline - name: wfrId in: path required: true schema: type: integer + description: ID of the workflow runner responses: '200': description: Successfully return history detail @@ -58,11 +61,13 @@ paths: required: true schema: type: integer + description: ID of the application - name: pipelineId in: path required: true schema: type: integer + description: ID of the pipeline responses: '200': description: Successfully return history detail @@ -88,46 +93,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/app/deployment-configuration/all/latest/{appId}/{pipelineId}: - get: - operationId: FetchDeploymentConfiguration - description: Fetch latest deployment configuration i.e. currently saved in the system and marked as active - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return configuration detail - content: - application/json: - schema: - $ref: '#/components/schemas/HistoryConfigurationDetailDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' components: schemas: @@ -145,14 +110,19 @@ components: properties: value: type: string + description: Template value displayName: type: string + description: Display name of the template isAppMetrics: - type: string + type: boolean + description: Whether app metrics are enabled templateName: type: string + description: Name of the template templateVersion: type: string + description: Version of the template configMap: type: object properties: @@ -163,6 +133,7 @@ components: properties: componentName: type: string + description: Name of the component config: type: object properties: @@ -171,22 +142,31 @@ components: properties: value: type: string + description: Config value displayName: type: string + description: Display name of the config type: type: string + description: Type of the config external: - type: string + type: boolean + description: Whether the config is external mountPath: type: string + description: Mount path for the config externalType: type: string + description: Type of external config roleARN: type: string + description: ARN of the role subPath: type: string + description: Sub path for the config filePermission: type: string + description: File permissions secret: type: object properties: @@ -197,6 +177,7 @@ components: properties: componentName: type: string + description: Name of the component config: type: object properties: @@ -205,22 +186,37 @@ components: properties: value: type: string + description: Secret value displayName: type: string + description: Display name of the secret type: type: string + description: Type of the secret external: - type: string + type: boolean + description: Whether the secret is external mountPath: type: string + description: Mount path for the secret externalType: type: string + description: Type of external secret roleARN: type: string + description: ARN of the role subPath: type: string + description: Sub path for the secret filePermission: type: string + description: File permissions + externalSecretType: + type: string + description: Type of external secret + esoSubPath: + type: string + description: ESO sub path pipelineStrategy: type: object properties: @@ -232,20 +228,26 @@ components: properties: value: type: string + description: Strategy value displayName: type: string + description: Display name of the strategy pipelineTriggerType: type: string + description: Type of pipeline trigger strategy: type: string + description: Deployment strategy Error: - required: - - code - - message + type: object properties: code: type: integer + format: int32 description: Error code - message: + status: + type: string + description: Error message + userDetailedMessage: type: string - description: Error message \ No newline at end of file + description: Detailed error message for user \ No newline at end of file diff --git a/specs/deployment/timeline.yaml b/specs/deployment/timeline.yaml new file mode 100644 index 0000000000..528b43e245 --- /dev/null +++ b/specs/deployment/timeline.yaml @@ -0,0 +1,154 @@ +openapi: "3.0.0" +info: + title: Pipeline Status Timeline API + version: "1.0" +paths: + /orchestrator/app/deployment-status/timeline/{appId}/{envId}: + get: + description: Get all timelines of a deployment trigger + operationId: GetPipelineStatusTimelines + parameters: + - name: appId + in: path + required: true + schema: + type: integer + description: ID of the application + - name: envId + in: path + required: true + schema: + type: integer + description: ID of the environment + - name: wfrId + in: query + required: false + schema: + type: integer + description: ID of the workflow runner. If not provided, latest workflow runner will be used + - name: showTimeline + in: query + required: false + schema: + type: boolean + description: Whether to show detailed timeline information + responses: + '200': + description: Successfully returns deployment timeline status of a pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineTimelineDetailDto' + '400': + description: Bad Request. Input Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +components: + schemas: + PipelineTimelineDetailDto: + type: object + properties: + deploymentStartedOn: + type: string + format: date-time + description: Time when the deployment started + deploymentFinishedOn: + type: string + format: date-time + description: Time when the deployment finished + triggeredBy: + type: string + description: Email ID of the user who triggered the deployment + timelines: + type: array + items: + $ref: '#/components/schemas/PipelineStatusTimelineDto' + description: List of timeline events + statusLastFetchedAt: + type: string + format: date-time + description: Last time when the status was fetched + statusFetchCount: + type: integer + description: Number of times status has been fetched + wfrStatus: + type: string + description: Status of the workflow runner + deploymentAppDeleteRequest: + type: boolean + description: Whether the deployment app delete request is pending + PipelineStatusTimelineDto: + type: object + properties: + id: + type: integer + description: Unique identifier for the timeline event + installedAppVersionHistoryId: + type: integer + description: ID of the installed app version history (for Helm apps) + cdWorkflowRunnerId: + type: integer + description: ID of the CD workflow runner + status: + type: string + description: Status of the timeline event + statusDetail: + type: string + description: Detailed status message + statusTime: + type: string + format: date-time + description: Time when the status was recorded + resourceDetails: + type: array + items: + $ref: '#/components/schemas/SyncStageResourceDetailDto' + description: Details of resources being synced + SyncStageResourceDetailDto: + type: object + properties: + resourceName: + type: string + description: Name of the resource + resourceKind: + type: string + description: Kind of the resource + resourceGroup: + type: string + description: Group of the resource + resourceStatus: + type: string + description: Status of the resource + statusMessage: + type: string + description: Status message for the resource + resourcePhase: + type: string + description: Phase of the resource (e.g. Sync, PreSync, PostSync) + Error: + type: object + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + userDetailedMessage: + type: string + description: Detailed error message for the user diff --git a/specs/bulk-env-delete.yaml b/specs/environment/bulk-delete.yaml similarity index 66% rename from specs/bulk-env-delete.yaml rename to specs/environment/bulk-delete.yaml index 60e1f673d9..73f77f17eb 100644 --- a/specs/bulk-env-delete.yaml +++ b/specs/environment/bulk-delete.yaml @@ -1,9 +1,9 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron Labs + title: Environment Bulk Operations paths: - /orchestrtor/batch/v1beta1/cd-pipeline: + /orchestrator/batch/v1beta1/cd-pipeline: post: description: perform bulk actions on cd pipelines parameters: @@ -30,7 +30,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CdPipelineImpactedObjectDto' + $ref: '#/components/schemas/PipelineAndWfBulkActionResponseDto' '400': description: Bad Request. Validation error/wrong request body. content: @@ -73,7 +73,7 @@ components: envNames: type: array items: - type: integer + type: string description: names of all environments whose pipelines are to be included in action appIds: type: array @@ -83,7 +83,7 @@ components: appNames: type: array items: - type: integer + type: string description: names of all apps for which the environment is to be included projectIds: type: array @@ -93,19 +93,69 @@ components: projectNames: type: array items: - type: integer + type: string description: names of all projects for which the environment is to be included - CdPipelineImpactedObjectDto: + deleteWfAndCiPipeline: + type: boolean + description: whether to delete workflow and CI pipeline + forceDelete: + type: boolean + description: whether to force delete + nonCascadeDelete: + type: boolean + description: whether to delete without cascade + userId: + type: integer + format: int32 + description: user id who is performing the action + PipelineAndWfBulkActionResponseDto: + type: object + properties: + cdPipelinesRespDtos: + type: array + items: + $ref: '#/components/schemas/CdBulkActionResponseDto' + ciPipelineRespDtos: + type: array + items: + $ref: '#/components/schemas/CiBulkActionResponseDto' + appWfRespDtos: + type: array + items: + $ref: '#/components/schemas/WfBulkActionResponseDto' + CdBulkActionResponseDto: type: object properties: pipelineName: - type: integer - environmentName: type: string + description: name of the pipeline appName: type: string - projectName: + description: name of the application + environmentName: + type: string + description: name of the environment + deletionResult: + type: string + description: result of the deletion operation + CiBulkActionResponseDto: + type: object + properties: + pipelineName: + type: string + description: name of the CI pipeline + deletionResult: + type: string + description: result of the deletion operation + WfBulkActionResponseDto: + type: object + properties: + workflowId: + type: integer + description: id of the workflow + deletionResult: type: string + description: result of the deletion operation ErrorResponse: required: - code diff --git a/specs/environment/config-diff.yaml b/specs/environment/config-diff.yaml new file mode 100644 index 0000000000..4d0086d6c1 --- /dev/null +++ b/specs/environment/config-diff.yaml @@ -0,0 +1,436 @@ +openapi: 3.0.0 +info: + title: Configuration Diff View API + version: 1.0.0 + description: API for managing configuration differences and comparisons + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication + +paths: + /orchestrator/config/autocomplete: + get: + summary: Get configuration autocomplete data + operationId: ConfigAutoComplete + security: + - bearerAuth: [] + parameters: + - name: appId + in: query + required: true + schema: + type: integer + description: The application ID + - name: envId + in: query + required: true + schema: + type: integer + description: The environment ID + responses: + '200': + description: Successfully retrieved configuration autocomplete data + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ConfigProperty' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /config/data: + get: + summary: Get configuration data + operationId: GetConfigData + parameters: + - name: appName + in: query + required: true + schema: + type: string + description: The application name + - name: envName + in: query + required: false + schema: + type: string + description: The environment name + - name: configType + in: query + required: true + schema: + type: string + description: The configuration type + - name: identifierId + in: query + required: false + schema: + type: integer + description: The identifier ID + - name: pipelineId + in: query + required: false + schema: + type: integer + description: The pipeline ID + - name: resourceName + in: query + required: false + schema: + type: string + description: The resource name + - name: resourceType + in: query + required: false + schema: + type: string + description: The resource type + - name: resourceId + in: query + required: false + schema: + type: integer + description: The resource ID + - name: wfrId + in: query + required: false + schema: + type: integer + description: The workflow run ID + - name: configArea + in: query + required: false + schema: + type: string + description: The configuration area + responses: + '200': + description: Successfully retrieved configuration data + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataResponse' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /config/compare/{resource}: + get: + summary: Compare configuration data + operationId: CompareCategoryWiseConfigData + parameters: + - name: resource + in: path + required: true + schema: + type: string + enum: [ConfigMap, Secret, Deployment Template, Pipeline Strategy] + description: The resource type to compare + - name: compareConfig + in: query + required: true + schema: + type: string + description: JSON string containing comparison configuration + responses: + '200': + description: Successfully compared configuration data + content: + application/json: + schema: + $ref: '#/components/schemas/ComparisonResponseDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /config/manifest: + post: + summary: Get manifest for configuration + operationId: GetManifest + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ManifestRequest' + responses: + '200': + description: Successfully retrieved manifest + content: + application/json: + schema: + $ref: '#/components/schemas/ManifestResponse' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + ConfigProperty: + type: object + properties: + name: + type: string + description: Name of the configuration + example: cm-1 + nullable: true + configState: + $ref: '#/components/schemas/ConfigStateEnum' + type: + $ref: '#/components/schemas/ResourceTypeEnum' + + ConfigStateEnum: + type: integer + enum: [1, 2, 3] + description: State of configuration (1 = draft, 2 = approval pending, 3 = published) + + ResourceTypeEnum: + type: string + enum: [ConfigMap, Secret, Deployment Template] + description: Type of resource + + ConfigDataResponse: + type: object + properties: + resourceConfig: + type: array + items: + $ref: '#/components/schemas/ConfigProperty' + isAppAdmin: + type: boolean + description: Whether the user has admin access to the application + + ComparisonRequestDto: + type: object + properties: + comparisonItems: + type: array + items: + $ref: '#/components/schemas/ComparisonItemRequestDto' + + ComparisonItemRequestDto: + type: object + properties: + index: + type: integer + description: Index of the comparison item + appName: + type: string + description: Name of the application + envName: + type: string + description: Name of the environment + configType: + type: string + description: Type of configuration + identifierId: + type: integer + description: Identifier ID + pipelineId: + type: integer + description: Pipeline ID + resourceName: + type: string + description: Resource name + resourceType: + type: string + description: Resource type + resourceId: + type: integer + description: Resource ID + wfrId: + type: integer + description: Workflow run ID + configArea: + type: string + description: Configuration area + + ComparisonResponseDto: + type: object + properties: + comparisonItemResponse: + type: array + items: + $ref: '#/components/schemas/DeploymentAndCmCsConfigDto' + + DeploymentAndCmCsConfigDto: + type: object + properties: + configData: + type: object + description: Configuration data + deploymentTemplate: + type: object + description: Deployment template data + pipelineStrategy: + type: object + description: Pipeline strategy data + + ManifestRequest: + type: object + required: + - values + - resourceType + - appId + properties: + values: + type: object + description: Configuration values + mergeStrategy: + type: string + description: Strategy for merging configurations + resourceType: + type: string + description: Type of resource + resourceId: + type: integer + description: Resource ID + resourceName: + type: string + description: Resource name + appId: + type: integer + description: Application ID + environmentId: + type: integer + description: Environment ID + + ManifestResponse: + type: object + properties: + manifest: + type: string + description: Generated manifest + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Configuration not found in the system"] + diff --git a/specs/environment.yaml b/specs/environment/core.yaml similarity index 56% rename from specs/environment.yaml rename to specs/environment/core.yaml index 68f5232401..fb8808b691 100644 --- a/specs/environment.yaml +++ b/specs/environment/core.yaml @@ -1,7 +1,7 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron Labs + title: Environment & Namespace Management paths: /orchestrator/env/namespace/autocomplete: get: @@ -11,10 +11,10 @@ paths: name: ids example: "1,2" description: cluster ids - required: true - allowEmptyValue: false + required: false + allowEmptyValue: true schema: - type: integer + type: string responses: '200': description: list response @@ -32,7 +32,7 @@ paths: type: array description: namespace list group by cluster items: - $ref: '#/components/schemas/Cluster' + $ref: '#/components/schemas/ClusterEnvDto' default: description: unexpected error content: @@ -43,11 +43,8 @@ paths: # components mentioned below components: schemas: - Cluster: + ClusterEnvDto: type: object - required: - - key - - value properties: clusterId: type: integer @@ -58,22 +55,74 @@ components: environments: type: array items: - $ref: '#/components/schemas/Environment' - Environment: + $ref: '#/components/schemas/EnvDto' + isVirtualCluster: + type: boolean + description: whether cluster is virtual or not + clusterServerUrl: + type: string + description: cluster server URL + clusterConfig: + type: object + description: cluster configuration + properties: + bearerToken: + type: string + description: bearer token for cluster access + tlsConfig: + type: object + description: TLS configuration + properties: + insecureSkipTLSVerify: + type: boolean + description: whether to skip TLS verification + EnvDto: type: object properties: environmentId: type: integer - description: cluster id + description: environment id environmentName: type: string - description: cluster name + description: environment name + namespace: + type: string + description: namespace environmentIdentifier: type: string description: environment identifier - namespace: + description: type: string - description: namespace + description: environment description + isVirtualEnvironment: + type: boolean + description: whether environment is virtual or not + default: + type: boolean + description: whether environment is default or not + clusterId: + type: integer + description: cluster id + clusterName: + type: string + description: cluster name + active: + type: boolean + description: whether environment is active + createdOn: + type: string + format: date-time + description: creation timestamp + updatedOn: + type: string + format: date-time + description: last update timestamp + createdBy: + type: string + description: creator's name + updatedBy: + type: string + description: last updater's name ErrorResponse: required: diff --git a/specs/environment/templates.yaml b/specs/environment/templates.yaml new file mode 100644 index 0000000000..ef3a2a1af0 --- /dev/null +++ b/specs/environment/templates.yaml @@ -0,0 +1,123 @@ +openapi: "3.0.3" +info: + version: 1.0.0 + title: Default Template Values API + description: API for managing default template values for applications + +paths: + /orchestrator/app/template/default/{appId}/{chartRefId}: + get: + summary: Get default template values + operationId: GetDefaultDeploymentTemplate + description: Get default values of template by appId and chartRefId + parameters: + - name: appId + in: path + required: true + schema: + type: integer + description: The application ID + - name: chartRefId + in: path + required: true + schema: + type: integer + description: The chart reference ID + - name: token + in: header + required: true + schema: + type: string + description: Authentication token + responses: + '200': + description: Successfully retrieved default template values + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: HTTP status code + status: + type: string + description: Status message + result: + type: object + properties: + appOverride: + type: array + items: + type: object + properties: + Key: + type: string + description: The configuration key + Value: + type: string + description: The configuration value + isAppMetricsEnabled: + type: boolean + description: Whether application metrics are enabled + errors: + type: array + items: + $ref: '#/components/schemas/ApiError' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + ApiError: + type: object + properties: + code: + type: string + description: Error code + message: + type: string + description: Error message + internalMessage: + type: string + description: Internal error message for debugging + userMessage: + type: string + description: User-friendly error message + + Error: + type: object + required: + - code + - message + properties: + code: + type: string + description: Error code + example: E100 + message: + type: string + description: Error message + example: User is not authenticated diff --git a/specs/ephemeralContainers.yaml b/specs/ephemeralContainers.yaml deleted file mode 100644 index 665c2d49e3..0000000000 --- a/specs/ephemeralContainers.yaml +++ /dev/null @@ -1,109 +0,0 @@ -openapi: 3.0.0 -info: - title: Orchestrator K8s API - version: 1.0.0 -paths: - /orchestrator/k8s/resources/ephemeralContainers: - post: - summary: Create Ephemeral Container - parameters: - - name: identifier - in: query - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/EphemeralContainerRequest" - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/PodContainerList" - '400': - description: Bad Request - '401': - description: Unauthorized - delete: - summary: Delete Ephemeral Container - parameters: - - name: identifier - in: query - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/EphemeralContainerRequest" - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/PodContainerList" - '400': - description: Bad Request - '401': - description: Unauthorized - -components: - schemas: - EphemeralContainerRequest: - type: object - properties: - basicData: - $ref: "#/components/schemas/EphemeralContainerBasicData" - advancedData: - $ref: "#/components/schemas/EphemeralContainerAdvancedData" - namespace: - type: string - clusterId: - type: integer - podName: - type: string - userId: - type: integer - required: - - namespace - - clusterId - - podName - EphemeralContainerBasicData: - type: object - properties: - containerName: - type: string - targetContainerName: - type: string - image: - type: string - required: - - containerName - - targetContainerName - - image - EphemeralContainerAdvancedData: - type: object - properties: - manifest: - type: string - PodContainerList: - type: object - properties: - containers: - type: array - items: - type: string - initContainers: - type: array - items: - type: string - ephemeralContainers: - type: array - items: - type: string diff --git a/specs/external-app/applist.yaml b/specs/external-app/applist.yaml index 628b19914b..72a169d40d 100644 --- a/specs/external-app/applist.yaml +++ b/specs/external-app/applist.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: version: 1.0.0 - title: Devtron Labs + title: External Application Management paths: /orchestrator/application: post: diff --git a/specs/external-links/external-links-specs.yaml b/specs/external-links/external-links-specs.yaml index 0645fe3c99..d66d106a38 100644 --- a/specs/external-links/external-links-specs.yaml +++ b/specs/external-links/external-links-specs.yaml @@ -3,7 +3,7 @@ info: version: 1.0.0 title: External links APIs paths: - /orchestrator/external-link/tools: + /orchestrator/external-links/tools: get: description: Get all available monitoring tools for external links responses: @@ -15,7 +15,19 @@ paths: type: array items: $ref: "#/components/schemas/ExternalLinkMonitoringTool" - /orchestrator/external-link: + "401": + description: Unauthorized user + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /orchestrator/external-links: get: description: Get All active External links (If query parameter is not supplied then it will give all external links otherwise it will give external links @@ -54,6 +66,30 @@ paths: type: array items: $ref: "#/components/schemas/ExternalLink" + "400": + description: Bad request - invalid parameters + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized user + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" post: description: Create external links (id should be zero in externalLink object) requestBody: @@ -71,6 +107,30 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized user + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" put: description: update external link requestBody: @@ -86,6 +146,36 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized user + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: External link not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" delete: description: delete external link parameters: @@ -104,6 +194,36 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad request - invalid ID parameter + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized user + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: External link not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" # Components @@ -184,3 +304,30 @@ components: clusterId: type: integer description: cluster-id for which you want to configure the app level external-link + ErrorResponse: + type: object + properties: + code: + type: integer + description: Error code + example: 400 + status: + type: string + description: Error status + example: "Bad Request" + message: + type: string + description: Error message + example: "Invalid request parameters" + errors: + type: array + description: Detailed error information + items: + type: object + properties: + field: + type: string + description: Field name that caused the error + message: + type: string + description: Specific error message for the field diff --git a/specs/gitops-validation.yaml b/specs/gitops-validation.yaml deleted file mode 100644 index ff912bd48f..0000000000 --- a/specs/gitops-validation.yaml +++ /dev/null @@ -1,186 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: GitOps Validation -servers: - - url: https://api.yourdomain.com -paths: - /validate: - post: - description: Validate gitops configuration by dry run - summary: Validate gitops configuration by dry run - security: - - ApiKeyAuth: [] - operationId: GitOpsValidateDryRun - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /config: - post: - description: create/save new configuration and validate them before saving - summary: create/save new configuration and validate them before saving - security: - - ApiKeyAuth: [] - operationId: CreateGitOpsConfig - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results and if validation is correct then saves the configuration in the backend - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - description: update configuration and validate them before saving(if last validation is within 30 seconds then do not validate) - summary: update configuration and validate them before saving(if last validation is within 30 seconds then do not validate) - operationId: UpdateGitOpsConfig - security: - - ApiKeyAuth: [] - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results and if validation is correct then updates the configuration in the backend - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - schemas: - GitOpsConfigDto: - type: object - properties: - id: - type: integer - provider: - type: string - username: - type: string - token: - type: string - gitLabGroupId: - type: string - gitHubOrgId: - type: string - host: - type: string - active: - type: boolean - azureProjectName: - type: string - userId: - type: integer - DetailedError: - type: object - properties: - successfulStages: - type: array - items: - type: string - description: All successful stages - validatedOn: - type: string - description: Timestamp of validation - stageErrorMap: - type: array - items: - type: object - properties: - stage: - type: string - error: - type: string - description: map of stage and their respective errors - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/gitops_bitbucket.yaml b/specs/gitops/bitbucket.yaml similarity index 70% rename from specs/gitops_bitbucket.yaml rename to specs/gitops/bitbucket.yaml index 73c9cdf6fb..57268e7748 100644 --- a/specs/gitops_bitbucket.yaml +++ b/specs/gitops/bitbucket.yaml @@ -118,57 +118,102 @@ components: properties: id: type: integer + description: GitOps configuration ID provider: type: string + description: Git provider + enum: [GITLAB, GITHUB, AZURE_DEVOPS, BITBUCKET_CLOUD] username: type: string + description: Git username token: type: string + description: Git access token gitLabGroupId: type: string + description: GitLab group ID gitHubOrgId: type: string + description: GitHub organization ID host: type: string + description: Git host URL active: type: boolean + description: Whether this configuration is active azureProjectName: type: string + description: Azure DevOps project name bitBucketWorkspaceId: type: string + description: Bitbucket workspace ID bitBucketProjectKey: type: string - userId: - type: integer - DetailedError: + description: Bitbucket project key + allowCustomRepository: + type: boolean + description: Whether custom repositories are allowed + enableTLSVerification: + type: boolean + description: Whether TLS verification is enabled + tlsConfig: + $ref: '#/components/schemas/TLSConfig' + isCADataPresent: + type: boolean + description: Whether CA data is present + isTLSCertDataPresent: + type: boolean + description: Whether TLS certificate data is present + isTLSKeyDataPresent: + type: boolean + description: Whether TLS key data is present + + TLSConfig: + type: object + properties: + caData: + type: string + description: CA certificate data + tlsCertData: + type: string + description: TLS certificate data + tlsKeyData: + type: string + description: TLS key data + + DetailedErrorGitOpsConfigResponse: type: object properties: successfulStages: type: array items: type: string - description: All successful stages + description: List of successfully completed validation stages + stageErrorMap: + type: object + additionalProperties: + type: string + description: Map of stage names to error messages validatedOn: type: string + format: date-time description: Timestamp of validation - stageErrorMap: - type: array - items: - type: object - properties: - stage: - type: string - error: - type: string - description: map of stage and their respective errors - Error: + deleteRepoFailed: + type: boolean + description: Whether repository deletion failed + validationSkipped: + type: boolean + description: Whether validation was skipped + + ErrorResponse: + type: object required: - code - message properties: code: type: integer - description: Error code + description: HTTP status code message: type: string description: Error message \ No newline at end of file diff --git a/specs/gitops/core.yaml b/specs/gitops/core.yaml new file mode 100644 index 0000000000..d4dfd942f0 --- /dev/null +++ b/specs/gitops/core.yaml @@ -0,0 +1,423 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: GitOps Configuration Management + description: Devtron API for GitOps management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 +paths: + /orchestrator/gitops/config: + post: + description: Create or save new GitOps configuration and validate before saving + operationId: CreateGitOpsConfig + requestBody: + description: GitOps configuration details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Successfully created and validated GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update GitOps configuration and validate before saving + operationId: UpdateGitOpsConfig + requestBody: + description: GitOps configuration details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Successfully updated and validated GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + get: + description: Get all GitOps configurations + operationId: GetAllGitOpsConfig + responses: + '200': + description: List of GitOps configurations + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GitOpsConfigDto' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/gitops/config/{id}: + get: + description: Get GitOps configuration by ID + operationId: GetGitOpsConfigById + parameters: + - name: id + in: path + required: true + schema: + type: integer + description: GitOps configuration ID + responses: + '200': + description: GitOps configuration details + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + '400': + description: Bad Request - Invalid ID + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/gitops/config-by-provider: + get: + description: Get GitOps configuration by provider + operationId: GetGitOpsConfigByProvider + parameters: + - name: provider + in: query + required: true + schema: + type: string + description: Git provider (GITLAB, GITHUB, AZURE_DEVOPS, BITBUCKET_CLOUD) + responses: + '200': + description: GitOps configuration details + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + '400': + description: Bad Request - Invalid provider + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/gitops/configured: + get: + description: Check if GitOps is configured + operationId: GitOpsConfigured + responses: + '200': + description: GitOps configuration status + content: + application/json: + schema: + type: object + properties: + exists: + type: boolean + description: Whether GitOps is configured + allowCustomRepository: + type: boolean + description: Whether custom repositories are allowed + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/gitops/validate: + post: + description: Validate GitOps configuration + operationId: GitOpsValidator + requestBody: + description: GitOps configuration to validate + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Validation results + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + GitOpsConfigDto: + type: object + properties: + id: + type: integer + description: GitOps configuration ID + provider: + type: string + description: Git provider (GITLAB, GITHUB, AZURE_DEVOPS, BITBUCKET_CLOUD) + enum: [GITLAB, GITHUB, AZURE_DEVOPS, BITBUCKET_CLOUD] + username: + type: string + description: Git username + token: + type: string + description: Git access token + gitLabGroupId: + type: string + description: GitLab group ID + gitHubOrgId: + type: string + description: GitHub organization ID + host: + type: string + description: Git host URL + active: + type: boolean + description: Whether this configuration is active + azureProjectName: + type: string + description: Azure DevOps project name + bitBucketWorkspaceId: + type: string + description: Bitbucket workspace ID + bitBucketProjectKey: + type: string + description: Bitbucket project key + allowCustomRepository: + type: boolean + description: Whether custom repositories are allowed + enableTLSVerification: + type: boolean + description: Whether TLS verification is enabled + tlsConfig: + $ref: '#/components/schemas/TLSConfig' + isCADataPresent: + type: boolean + description: Whether CA data is present + isTLSCertDataPresent: + type: boolean + description: Whether TLS certificate data is present + isTLSKeyDataPresent: + type: boolean + description: Whether TLS key data is present + + TLSConfig: + type: object + properties: + tlsKeyData: + type: string + description: TLS key data + tlsCertData: + type: string + description: TLS certificate data + caData: + type: string + description: CA certificate data + + DetailedErrorGitOpsConfigResponse: + type: object + properties: + successfulStages: + type: array + items: + type: string + description: List of successful validation stages + stageErrorMap: + type: object + additionalProperties: + type: string + description: Map of stage names to error messages + validatedOn: + type: string + format: date-time + description: Validation timestamp + deleteRepoFailed: + type: boolean + description: Whether repository deletion failed + validationSkipped: + type: boolean + description: Whether validation was skipped + + ErrorResponse: + required: + - code + - status + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + errors: + type: array + description: List of 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 diff --git a/specs/fluxcd_app.yaml b/specs/gitops/fluxcd.yaml similarity index 69% rename from specs/fluxcd_app.yaml rename to specs/gitops/fluxcd.yaml index ff83979291..ad1294c883 100644 --- a/specs/fluxcd_app.yaml +++ b/specs/gitops/fluxcd.yaml @@ -33,7 +33,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - '403': description: Forbidden content: @@ -48,48 +47,47 @@ paths: $ref: '#/components/schemas/Error' /orchestrator/flux-application/app: - get: - summary: Get application details - description: Retrieve details of a specific Flux application. - parameters: - - name: appId - in: query - required: true - schema: - type: string - description: The application identifier in the format "1|default|myksApp|Kustomization as the first field having the cluster id, then second field having the namespace of the app , third field denoted the app name and last contains a boolean value of true and false". - - name: token - in: header - required: true - schema: - type: string - description: The authentication token. - responses: - '200': - description: Successful response - content: - application/json: - schema: - $ref: '#/components/schemas/FluxApplicationDetailDto' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - + get: + summary: Get application details + description: Retrieve details of a specific Flux application. + parameters: + - name: appId + in: query + required: true + schema: + type: string + description: The application identifier in the format "clusterId|namespace|appName|isKustomizeApp" where isKustomizeApp is a boolean value indicating if the app is a Kustomization type. + - name: token + in: header + required: true + schema: + type: string + description: The authentication token. + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/FluxApplicationDetailDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: @@ -107,6 +105,13 @@ components: description: List of Flux applications items: $ref: '#/components/schemas/FluxAppDto' + errored: + type: boolean + description: Whether there was an error fetching the applications + errorMsg: + type: string + description: Error message if any + FluxAppDto: type: object properties: @@ -116,9 +121,8 @@ components: example: flux-system appStatus: type: boolean - enum: [True, False] - description: - example: True + description: Health status of the application + example: true syncStatus: type: string description: Sync status of the application @@ -137,9 +141,21 @@ components: example: flux-system fluxAppDeploymentType: type: string - enum": ["Kustomization", "HelmRelease"] + enum: ["Kustomization", "HelmRelease"] description: Indicates if the application is a Kustomize type or standalone flux made HelmRelease app - example: true + example: "Kustomization" + + FluxApplicationDetailDto: + type: object + allOf: + - $ref: '#/components/schemas/FluxAppDto' + - type: object + properties: + fluxAppStatusDetail: + $ref: '#/components/schemas/FluxAppStatusDetail' + resourceTree: + $ref: '#/components/schemas/ResourceTreeResponse' + FluxAppStatusDetail: type: object properties: @@ -153,29 +169,46 @@ components: type: string description: Short key words like 'ReconciliationFailed', 'Reconciled', and so on for the user to understand the reason of the given of the status - InfoItem: + ResourceTreeResponse: type: object properties: - name: - type: string - value: + nodes: + type: array + items: + $ref: '#/components/schemas/ResourceNode' + pods: + type: array + items: + $ref: '#/components/schemas/PodMetadata' + status: type: string + description: Status of the resource tree - HealthStatus: + ResourceNode: type: object properties: - status: + group: type: string - message: + version: type: string - - ResourceNetworkingInfo: - type: object - properties: - labels: - type: object - additionalProperties: - type: string + kind: + type: string + namespace: + type: string + name: + type: string + uid: + type: string + parentRefs: + type: array + items: + $ref: '#/components/schemas/ResourceRef' + networkingInfo: + $ref: '#/components/schemas/ResourceNetworkingInfo' + resourceVersion: + type: string + health: + $ref: '#/components/schemas/HealthStatus' ResourceRef: type: object @@ -193,6 +226,14 @@ components: uid: type: string + ResourceNetworkingInfo: + type: object + properties: + labels: + type: object + additionalProperties: + type: string + PodMetadata: type: object properties: @@ -223,77 +264,18 @@ components: isExternal: type: boolean - ResourceNode: + HealthStatus: type: object properties: - group: - type: string - version: - type: string - kind: - type: string - namespace: - type: string - name: - type: string - uid: - type: string - parentRefs: - type: array - items: - $ref: '#/components/schemas/ResourceRef' - networkingInfo: - $ref: '#/components/schemas/ResourceNetworkingInfo' - resourceVersion: - type: string - health: - $ref: '#/components/schemas/HealthStatus' - isHibernated: - type: boolean - canBeHibernated: - type: boolean - info: - type: array - items: - $ref: '#/components/schemas/InfoItem' - createdAt: + status: type: string - format: date-time - port: - type: array - items: - type: integer - isHook: - type: boolean - hookType: + message: type: string - ResourceTreeResponse: - type: object - properties: - nodes: - type: array - items: - $ref: '#/components/schemas/ResourceNode' - podMetadata: - type: array - items: - $ref: '#/components/schemas/PodMetadata' - - FluxApplicationDetailDto: - type: object - properties: - FluxApplication: - $ref: '#/components/schemas/FluxAppDto' - FluxAppStatusDetail: - $ref: '#/components/schemas/FluxAppStatusDetail' - ResourceTreeResponse: - $ref: '#/components/schemas/ResourceTreeResponse' - Error: type: object properties: + code: + type: string message: type: string - description: Error message - example: unauthorized diff --git a/specs/gitops/manifest-generation.yaml b/specs/gitops/manifest-generation.yaml new file mode 100644 index 0000000000..d72fffc380 --- /dev/null +++ b/specs/gitops/manifest-generation.yaml @@ -0,0 +1,257 @@ +openapi: 3.0.3 +info: + title: App Deployment API + version: 1.0.0 + description: API for GitOps manifest generation and deployment template management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication +paths: + /orchestrator/app/deployments/{app-id}/{env-id}: + get: + summary: Fetch Deployment Template Comparison List + description: Returns a list of deployment templates that can be compared + operationId: FetchDeploymentsWithChartRefs + security: + - bearerAuth: [] + parameters: + - name: app-id + in: path + required: true + schema: + type: integer + format: int64 + description: The ID of the application + - name: env-id + in: path + required: true + schema: + type: integer + format: int64 + description: The ID of the environment + responses: + '200': + description: List of deployment templates + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/DeploymentTemplateComparisonMetadata' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + + /app/deployment/template/data: + post: + summary: Get Values and Manifest for Deployment Template + description: Returns the values and manifest for a deployment template + operationId: GetDeploymentTemplate + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentTemplateRequest' + responses: + '200': + description: Values and manifest data + content: + application/json: + schema: + $ref: '#/components/schemas/DeploymentTemplateResponse' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + DeploymentTemplateComparisonMetadata: + type: object + properties: + chartId: + type: integer + format: int64 + description: The ID of the chart reference + chartVersion: + type: string + description: The version of the chart + chartType: + type: string + description: The type of the chart + environmentId: + type: integer + format: int64 + description: The ID of the environment + environmentName: + type: string + description: The name of the environment + pipelineConfigOverrideId: + type: integer + format: int64 + description: The ID of the pipeline configuration override + startedOn: + type: string + format: date-time + description: The timestamp when the deployment started + finishedOn: + type: string + format: date-time + description: The timestamp when the deployment finished + status: + type: string + description: The status of the deployment + type: + type: integer + enum: [1, 2, 3, 4] + description: The type of deployment template (1=DefaultVersions, 2=PublishedOnEnvironments, 3=DeployedOnSelfEnvironment, 4=DeployedOnOtherEnvironment) + + DeploymentTemplateRequest: + type: object + required: + - appId + - chartRefId + - type + properties: + appId: + type: integer + format: int64 + description: The ID of the application + chartRefId: + type: integer + format: int64 + description: The ID of the chart reference + getValues: + type: boolean + description: Whether to include values in the response + type: + type: integer + enum: [1, 2, 3, 4] + description: The type of deployment template (1=DefaultVersions, 2=PublishedOnEnvironments, 3=DeployedOnSelfEnvironment, 4=DeployedOnOtherEnvironment) + values: + type: string + description: The values to use for the template + pipelineConfigOverrideId: + type: integer + format: int64 + description: The ID of the pipeline configuration override + environmentId: + type: integer + format: int64 + description: The ID of the environment + requestDataMode: + type: string + enum: [Values, Manifest] + description: The mode of data to return (Values or Manifest) + + DeploymentTemplateResponse: + type: object + properties: + data: + type: string + description: The raw template data + resolvedData: + type: string + description: The resolved template data with variables replaced + variableSnapshot: + type: object + additionalProperties: + type: string + description: Map of variable names to their resolved values + manifest: + type: string + description: The generated manifest + values: + type: string + description: The values used for the template + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Deployment template not found"] diff --git a/specs/git_submodules.yaml b/specs/gitops/submodules.yaml similarity index 55% rename from specs/git_submodules.yaml rename to specs/gitops/submodules.yaml index 65d4c237c2..838a2626eb 100644 --- a/specs/git_submodules.yaml +++ b/specs/gitops/submodules.yaml @@ -3,24 +3,19 @@ info: version: 1.0.0 title: Git Submodules support in CI paths: - /orchestrator/git/provider: - post: - description: save git repo(account) config - operationId: SaveGitRepoConfig - requestBody: - description: A JSON object containing the git repo configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitRegistry' + /orchestrator/git/host: + get: + description: get all git hosts + operationId: GetGitHosts responses: '200': - description: Successfully save the config + description: Successfully return details of all git hosts content: application/json: schema: - $ref: '#/components/schemas/GitRegistry' + type: array + items: + $ref: '#/components/schemas/GitHostRequest' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -39,23 +34,23 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - put: - description: update git repo(account) config - operationId: UpdateGitRepoConfig + post: + description: create git host + operationId: CreateGitHost requestBody: - description: A JSON object containing the git repo configuration + description: A JSON object containing the git host configuration required: true content: application/json: schema: - $ref: '#/components/schemas/GitRegistry' + $ref: '#/components/schemas/GitHostRequest' responses: '200': - description: Successfully update the config + description: Successfully created git host content: application/json: schema: - $ref: '#/components/schemas/GitRegistry' + $ref: '#/components/schemas/GitHostRequest' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -74,54 +69,23 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - get: - description: get all git account config - operationId: FetchAllGitProviders - responses: - '200': - description: Successfully return details of all git providers - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/GitRegistry' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /orchestrator/git/material: - post: - description: save git material config - operationId: CreateMaterial - requestBody: - description: A JSON object containing the git material configuration + /orchestrator/git/host/{id}: + parameters: + - name: id + in: path required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateMaterialDTO' + schema: + type: integer + get: + description: get git host by id + operationId: GetGitHostById responses: '200': - description: Successfully save the config + description: Successfully return git host details content: application/json: schema: - $ref: '#/components/schemas/CreateMaterialDTO' + $ref: '#/components/schemas/GitHostRequest' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -140,23 +104,25 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - put: - description: update git material config - operationId: UpdateMaterial - requestBody: - description: A JSON object containing the git repo configuration + /orchestrator/git/host/{id}/event: + parameters: + - name: id + in: path required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateMaterialDTO' + schema: + type: integer + get: + description: get all webhook event config for git host + operationId: GetAllWebhookEventConfig responses: '200': - description: Successfully update the config + description: Successfully return webhook event config content: application/json: schema: - $ref: '#/components/schemas/UpdateMaterialDTO' + type: array + items: + $ref: '#/components/schemas/WebhookEventConfig' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -175,25 +141,23 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/app/get/{appId}: + /orchestrator/git/host/event/{eventId}: parameters: - - name: appId + - name: eventId in: path required: true schema: type: integer get: - description: get details of an app by its Id - operationId: GetApp + description: get webhook event config by id + operationId: GetWebhookEventConfig responses: '200': - description: Successfully return details of an app + description: Successfully return webhook event config content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/CreateAppDTO' + $ref: '#/components/schemas/WebhookEventConfig' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -212,25 +176,23 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/app/{appId}/autocomplete/git: + /orchestrator/git/host/webhook-meta-config/{gitProviderId}: parameters: - - name: appId + - name: gitProviderId in: path required: true schema: - type: integer + type: string get: - description: get all git providers - operationId: GitListAutocomplete + description: get webhook data meta config for git provider + operationId: GetWebhookDataMetaConfig responses: '200': - description: Successfully return details of all git providers + description: Successfully return webhook data meta config content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/GitRegistry' + $ref: '#/components/schemas/WebhookDataMetaConfigResponse' '400': description: Bad Request. Input Validation(decode) error/wrong request body. content: @@ -251,8 +213,11 @@ paths: $ref: '#/components/schemas/Error' components: schemas: - GitRegistry: + GitHostRequest: type: object + required: + - name + - url properties: id: type: integer @@ -260,83 +225,30 @@ components: type: string url: type: string - userName: - type: string - password: - type: string - sshPrivateKey: - type: string - accessToken: - type: string - authMode: - type: string active: type: boolean - gitHostId: - type: integer - CreateAppDTO: + WebhookEventConfig: type: object properties: id: type: integer - appname: - type: string - material: - type: array - items: - $ref: '#/components/schemas/GitMaterial' - teamId: - type: integer - templateId: - type: integer - appLabels: - type: array - items: - $ref: '#/components/schemas/labels' - labels: - type: object - properties: - key: + name: type: string - value: + eventType: type: string - CreateMaterialDTO: - type: object - properties: - id: - type: integer - appId: + gitHostId: type: integer - material: - type: array - items: - $ref: '#/components/schemas/GitMaterial' - UpdateMaterialDTO: + WebhookDataMetaConfigResponse: type: object properties: - appId: + gitHostId: type: integer - material: + gitHost: + $ref: '#/components/schemas/GitHostRequest' + webhookEvents: type: array items: - $ref: '#/components/schemas/GitMaterial' - GitMaterial: - type: object - properties: - id: - type: integer - name: - type: string - url: - type: string - gitProviderId: - type: integer - checkoutPath: - type: string - fetchSubmodules: - type: boolean - isUsedInCiConfig: - type: boolean + $ref: '#/components/schemas/WebhookEventConfig' Error: required: - code diff --git a/specs/gitops/validation.yaml b/specs/gitops/validation.yaml new file mode 100644 index 0000000000..b9f50b6f0b --- /dev/null +++ b/specs/gitops/validation.yaml @@ -0,0 +1,389 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: GitOps Validation +servers: + - url: http://localhost:3000/orchestrator/gitops +paths: + /orchestrator/validate: + post: + description: Validate GitOps configuration + operationId: GitOpsValidator + requestBody: + description: A JSON object containing the gitops configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Successfully validated GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/gitops/config: + post: + description: Create a new GitOps configuration + operationId: CreateGitOpsConfig + requestBody: + description: A JSON object containing the gitops configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Successfully created and validated GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update an existing GitOps configuration + operationId: UpdateGitOpsConfig + requestBody: + description: A JSON object containing the gitops configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + responses: + '200': + description: Successfully updated and validated GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorGitOpsConfigResponse' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + get: + description: Get all GitOps configurations + operationId: GetAllGitOpsConfig + responses: + '200': + description: Successfully retrieved all GitOps configurations + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GitOpsConfigDto' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/gitops/config/{id}: + get: + description: Get GitOps configuration by ID + operationId: GetGitOpsConfigById + parameters: + - name: id + in: path + description: ID of the GitOps configuration + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: GitOps configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/gitops/config-by-provider: + get: + description: Get GitOps configuration by provider + operationId: GetGitOpsConfigByProvider + parameters: + - name: provider + in: query + description: Git provider (e.g., GITHUB, GITLAB, BITBUCKET) + required: true + schema: + type: string + responses: + '200': + description: Successfully retrieved GitOps configuration + content: + application/json: + schema: + $ref: '#/components/schemas/GitOpsConfigDto' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: GitOps configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/gitops/configured: + get: + description: Check if GitOps is configured + operationId: GitOpsConfigured + responses: + '200': + description: Successfully checked GitOps configuration status + content: + application/json: + schema: + type: object + properties: + exists: + type: boolean + description: Whether GitOps is configured + allowCustomRepository: + type: boolean + description: Whether custom repositories are allowed + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + GitOpsConfigDto: + type: object + properties: + id: + type: integer + description: GitOps configuration ID + provider: + type: string + description: Git provider + enum: [GITLAB, GITHUB, AZURE_DEVOPS, BITBUCKET_CLOUD] + username: + type: string + description: Git username + token: + type: string + description: Git access token + gitLabGroupId: + type: string + description: GitLab group ID + gitHubOrgId: + type: string + description: GitHub organization ID + host: + type: string + description: Git host URL + active: + type: boolean + description: Whether this configuration is active + azureProjectName: + type: string + description: Azure DevOps project name + bitBucketWorkspaceId: + type: string + description: Bitbucket workspace ID + bitBucketProjectKey: + type: string + description: Bitbucket project key + allowCustomRepository: + type: boolean + description: Whether custom repositories are allowed + enableTLSVerification: + type: boolean + description: Whether TLS verification is enabled + tlsConfig: + $ref: '#/components/schemas/TLSConfig' + isCADataPresent: + type: boolean + description: Whether CA data is present + isTLSCertDataPresent: + type: boolean + description: Whether TLS certificate data is present + isTLSKeyDataPresent: + type: boolean + description: Whether TLS key data is present + + TLSConfig: + type: object + properties: + caData: + type: string + description: CA certificate data + tlsCertData: + type: string + description: TLS certificate data + tlsKeyData: + type: string + description: TLS key data + + DetailedErrorGitOpsConfigResponse: + type: object + properties: + successfulStages: + type: array + items: + type: string + description: List of successfully completed validation stages + stageErrorMap: + type: object + additionalProperties: + type: string + description: Map of stage names to error messages + validatedOn: + type: string + format: date-time + description: Timestamp of validation + deleteRepoFailed: + type: boolean + description: Whether repository deletion failed + validationSkipped: + type: boolean + description: Whether validation was skipped + + ErrorResponse: + type: object + required: + - code + - message + properties: + code: + type: integer + description: HTTP status code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/global-plugin.yaml b/specs/global-plugin.yaml deleted file mode 100644 index 3b888c14fa..0000000000 --- a/specs/global-plugin.yaml +++ /dev/null @@ -1,604 +0,0 @@ -openapi: "3.0.3" -info: - title: "Plugin System Integration - CI Stages" - description: | - This API facilitates the management of plugins used in pre/post CI or CD steps, - enhancing the customization and automation capabilities of CI/CD pipelines. - version: "1.0.0" - -paths: - /orchestrator/plugin/global/detail/{pluginId}: - get: - description: > - Retrieve detailed information about a specific plugin by its ID. Before proceeding to Patch Plugin, ensure to retrieve the plugin details using this endpoint as the same object will be used in the patch action of the global plugin. - parameters: - - name: pluginId - in: path - required: true - schema: - type: integer - description: Unique identifier of the plugin - - responses: - '200': - description: successfully return the Detailed information about the plugin - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - $ref: '#/components/schemas/PluginMetaDataDto' - '400': - description: Bad request, Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized, not found or invalid API token provided - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - '403': - description: Forbidden, user is not allowed to access this plugin information - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Not Found, the plugin with the specified ID does not exist - - '500': - description: Internal server error, could not retrieve plugin details - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/plugin/global/detail/all: - get: - description: > - Get detailed information of available plugins. - operationId: GetAllDetailedPluginInfo - responses: - '200': - description: A list of plugins with detailed information - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: array - items: - $ref: '#/components/schemas/PluginMetaDataDto' - '401': - description: Unauthorized user, Invalid or missing API token - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden, user is not authorized to access this resource - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error, could not fetch the plugin details - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - - - /orchestrator/plugin/global/: - post: - summary: "Manipulating the Global Plugin" - description: | - Allows for the management (creation, update, or deletion) of global plugins through a single endpoint. This endpoint is versatile and supports various actions based on the provided `action` field in the request payload. Before performing any action, ensure to retrieve detailed information about the plugin by its ID using the endpoint `/orchestrator/plugin/global/detail/{pluginId}`. The same or modified object retrieved can be used in the request payload for this endpoint. - operationId: "PatchPlugin" - requestBody: - description: "A JSON Object containing the PluginMetaData fields, including the specific action to be performed." - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/PluginMetaDataDto' - responses: - '200': - description: "Successfully processed the global plugin operation. The response includes the updated plugin data." - content: - application/json: - schema: - $ref: '#/components/schemas/PluginMetaDataDto' - '400': - description: "Bad Request due to input validation errors or incorrect request body format." - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: "Unauthorized access attempt. This may occur if the user does not have the necessary permissions for the operation." - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: "Internal Server Error indicating an unexpected condition that prevented the request from being fulfilled." - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/plugin/global/list/global-variable: - get: - description: Get list of all global variables. - operationId: GetAllGlobalVariables - parameters: - - name: appId - in: query - required: true - schema: - type: integer - description: The ID of the application for which global variables are retrieved. - - responses: - '200': - description: Successfully returns all global variables. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code. - status: - type: string - description: Status. - result: - type: array - items: - $ref: '#/components/schemas/GlobalVariable' - '400': - description: Bad Request. Input validation error or wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - - - - -components: - schemas: - GlobalVariable: - type: object - properties: - name: - type: string - description: The name of the global variable. - value: - type: string - description: Optional.The value of the global variable. - format: - type: string - description: The format of the value. - description: - type: string - description: A description of the global variable and its purpose. - stageType: - type: string - description: The type of stage this global variable is associated with. - required: - - name - - format - - description - - type - - - PluginMetaDataDto: - type: object - properties: - id: - type: integer - description: Unique identifier for the plugin. - name: - type: string - description: Name of the plugin. - description: - type: string - description: Detailed description of what the plugin does. - type: - type: string - enum: [SHARED, PRESET] - description: > - Type of the plugin indicating whether it's a SHARED plugin accessible by user or a PRESET plugin provided by the system. - icon: - type: string - description: URL or a base64 encoded string representing an icon for the plugin - example: https://raw.githubusercontent.com/devtron-labs/devtron/main/assets/k6-plugin-icon.png - tags: - type: array - items: - type: string - description: A list of tags associated with the plugin for categorization and search. - action: - type: integer - description: | - This field represents the action to be performed with this plugin metadata. - - Use `0` to create a new plugin. - - Use `1` to update an existing plugin. - - Use `2` to delete a plugin. - - If you're opting to update an existing plugin (action `1`), - please take note: - - Ensure that the request body parameters are accurate before updating. - - Your request body (payload) will discard all previous updates and be treated as final. - - pluginStage: - type: string - enum: [ CD, CI, CI_CD] - description: Optional. Specifies the stage of the CI/CD pipeline or both (CI/CD) where this plugin can be used. Default value is CI_CD - pluginSteps: - type: array - items: - $ref: '#/components/schemas/PluginStepsDto' - description: Optional, A list of steps defined for the plugin. Each step contains specific instructions or actions the plugin will perform. - required: - - name - - description - - type - - icon - - tags - - action - - PluginStepsDto: - type: object - properties: - id: - type: integer - description: Unique identifier of the plugin step. - name: - type: string - description: Name of the plugin step. - description: - type: string - description: Detailed description of what the plugin step does. - index: - type: integer - description: The order index of the plugin step within the plugin. - stepType: - type: string - enum: [INLINE, REF_PLUGIN] - description: Type of the plugin step, indicating whether it's an INLINE step defined within the plugin or a REF_PLUGIN step referencing another plugin. - refPluginId: - type: integer - description: Unique identifier of the plugin used as reference by this step. - outputDirectoryPath: - type: array - items: - type: string - description: Paths to directories where the output of the plugin step should be stored. - dependentOnStep: - type: string - description: Identifier of the step, this step depends on to run. It can be used to establish execution order. - pluginStepVariable: - type: array - items: - $ref: '#/components/schemas/PluginVariableDto' - description: Optional. A list of variables associated with this plugin step. - pluginPipelineScript: - allOf: - - $ref: '#/components/schemas/PluginPipelineScript' - - description: Script associated with this plugin step to be executed as part of the pipeline. Optional. - required: - - name - - description - - index - - stepType - - refPluginId - - outputDirectoryPath - - dependentOnStep - - PluginVariableDto: - type: object - properties: - id: - type: integer - description: The unique identifier of the plugin variable. - name: - type: string - description: The name of the plugin variable. - format: - type: string - description: The format of the variable value. - enum: - - STRING - - NUMBER - - BOOL - - DATE - example: - - STRING - description: - type: string - description: A description of the plugin variable. - isExposed: - type: boolean - description: Indicates whether the variable is exposed. - allowEmptyValue: - type: boolean - description: Indicates whether an empty value is allowed for the variable. - defaultValue: - type: string - description: The default value of the variable. - value: - type: string - description: The value of the variable. - variableType: - type: string - description: | - The type of the variable. This specifies whether the variable is required by the plugin (Marked as INPUT type) or whether that variable is produced by the plugin (Marked as OUTPUT type). - enum: - - OUTPUT - - INPUT - example: - - INPUT - valueType: - type: string - description: | - The value type of the variable. Specifies whether the plugin uses a new value provided by the user (marked as NEW), retrieves the value from the previous step (marked as FROM_PREVIOUS_STEP), or fetches a global value (marked as GLOBAL). - This indicates whether the plugin utilizes a new user-provided value, a value from a previous step, or a global value. - enum: - - NEW - - FROM_PREVIOUS_STEP - - GLOBAL - example: - - NEW - previousStepIndex: - type: integer - description: The index of the previous step. - variableStepIndex: - type: integer - description: The index of the step it is using variable from . - variableStepIndexInPlugin: - type: integer - description: The index of the variable step in the plugin. - referenceVariableName: - type: string - description: The name of the reference variable. - pluginStepCondition: - type: array - items: - allOf: - - $ref: '#/components/schemas/PluginStepCondition' - - description: The conditions associated with the plugin variable. - required: - - name - - format - - description - - isExposed - - allowEmptyValue - - defaultValue - - variableType - - variableStepIndex - - variableStepIndexInPlugin - - - PluginStepCondition: - type: object - properties: - id: - type: integer - description: The unique identifier of the plugin step condition. - pluginStepId: - type: integer - description: The identifier of the plugin step associated with this condition. - conditionVariableId: - type: integer - description: The identifier of the variable on which the condition is written. - conditionType: - type: string - description: > - The type of condition. - Possible values are: - - SKIP: Skips the plugin step. - - TRIGGER: Triggers the plugin step. - - SUCCESS: Executes the plugin step on success. - - FAIL: Executes the plugin step on failure. - enum: - - SKIP - - TRIGGER - - SUCCESS - - FAIL - example: SKIP - conditionalOperator: - type: string - description: The operator used in the condition. - conditionalValue: - type: string - description: The value associated with the condition. - deleted : - type: boolean - description: Specifies whether the condition is deleted. - required: - - pluginStepId - - conditionVariableId - - conditionType - - conditionalOperator - - conditionalValue - - deleted - - PluginPipelineScript: - type: object - properties: - id: - type: integer - description: The unique identifier of the plugin pipeline script. Even if it is skipped by the user it will automatically get created with the default value - script: - type: string - description: The script associated with the plugin pipeline. - storeScriptAt: - type: string - description: The location where the script is stored. - type: - type: string - description: > - Specifies the type of script. - Possible values are: - - SHELL: Shell script. - - CONTAINER_IMAGE: Container image script. - enum: - - SHELL - - CONTAINER_IMAGE - example: - - SHELL - mountPath: - type: string - description: The path where the script is mounted. - mountCodeToContainer: - type: boolean - description: Indicates whether code is mounted to the container. - mountCodeToContainerPath: - type: string - description: The path where code is mounted to the container. - mountDirectoryFromHost: - type: boolean - description: Indicates whether a directory is mounted from the host. - containerImagePath: - type: string - description: The path to the container image. - imagePullSecretType: - type: string - description: > - Specifies the type of image pull secret. - Possible values are: - - CONTAINER_REGISTRY: Container registry image pull secret. - - SECRET_PATH: Secret path image pull secret. - enum: - - CONTAINER_REGISTRY - - SECRET_PATH - example: - - CONTAINER_REGISTRY - imagePullSecret: - type: string - description: The image pull secret. - deleted: - type: boolean - description: Indicates whether the plugin pipeline script is deleted. - pathArgPortMapping: - type: array - items: - $ref: '#/components/schemas/ScriptPathArgPortMapping' - description: The path argument port mappings associated with the plugin pipeline script. - required: - - script - - storeScriptAt - - type - - mountPath - - mountCodeToContainer - - mountCodeToContainerPath - - mountDirectoryFromHost - - containerImagePath - - imagePullSecretType - - imagePullSecret - - deleted - - pathArgPortMapping - - ScriptPathArgPortMapping: - type: object - properties: - id: - type: integer - description: The unique identifier of the script path argument port mapping. Even if it is skipped by the user it will automatically get created with the default value - typeOfMapping: - type: string - description: > - Specifies the type of mapping. - Possible values are: - - FILE_PATH - - PORT - enum: - - FILE_PATH - - PORT - example: - - PORT - filePathOnDisk: - type: string - description: The file path on the local disk. - filePathOnContainer: - type: string - description: The file path on the container. - command: - type: string - description: The command associated with the mapping. - args: - type: array - items: - type: string - description: The arguments associated with the command. - portOnLocal: - type: integer - description: The port on the local machine. - portOnContainer: - type: integer - description: The port on the container. - scriptId: - type: integer - description: The identifier of the script associated with the mapping. - required: - - id - - typeOfMapping - - filePathOnDisk - - filePathOnContainer - - command - - args - - portOnLocal - - portOnContainer - - scriptId - - Error: - title: Error - type: object - description: "A general error schema returned when status is not 200 OK" - properties: - code: - type: string - description: "a code for this particular error" - internalMessage: - type: string - description: "Optional. a message with further detail" - userMessage: - type: string - description: "Optional. A message for the user" - userDetailsMessage: - type: string - description: "Optional. Detailed User message" diff --git a/specs/global_cm_cs.yaml b/specs/global_cm_cs.yaml deleted file mode 100644 index 16cb81306a..0000000000 --- a/specs/global_cm_cs.yaml +++ /dev/null @@ -1,81 +0,0 @@ -openapi: "3.0.0" -info: - title: Global CM/CS support - version: "1.0" -paths: - /orchestrator/global/cm-cs: - post: - description: save a configmap/secret - operationId: CreateGlobalCMCSConfig - responses: - '200': - description: Successfully create given config - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/GlobalCMCSDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -components: - schemas: - GlobalCMCSDto: - type: object - properties: - id: - type: integer - description: not needed in payload - name: - type: string - mountPath: - type: string - configType: - type: string - example: - - "CONFIGMAP" - - "SECRET" - type: - type: string - example: - - "environment" - - "volume" - data: - type: object - additionalProperties: - type: string - secretIngestionFor: - type: string - description: field for defining at where this config is to be ingested. If not set, "CI/CD" will be used as default. - enum: - - "CI" - - "CD" - - "CI/CD" - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message diff --git a/specs/helm/charts.yaml b/specs/helm/charts.yaml new file mode 100644 index 0000000000..2e5982f60f --- /dev/null +++ b/specs/helm/charts.yaml @@ -0,0 +1,285 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Helm Chart Store Management + description: API for managing Helm chart deployments and operations + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + +paths: + /app-store/installed-app: + get: + summary: List deployed charts + operationId: listDeployedCharts + description: Deployed chart listing with search filters + security: + - bearerAuth: [] + parameters: + - name: envIds + in: query + description: Environment IDs + required: false + schema: + type: array + items: + type: string + - name: clusterIds + in: query + description: Cluster IDs + required: false + schema: + type: array + items: + type: string + - name: chartRepoId + in: query + description: Chart repository 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 charts or all + required: false + schema: + type: boolean + - name: offset + in: query + description: Offset for result set (pagination) + required: false + schema: + type: integer + - name: size + in: query + description: Total request size (pagination) + required: false + schema: + type: integer + - name: appStatuses + in: query + description: Application statuses filter + required: false + schema: + type: array + items: + type: string + responses: + '200': + description: Deployed chart listing with search filters + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + $ref: '#/components/schemas/AppListDetail' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Helm Charts + /app-store/installed-app/notes: + get: + summary: Fetch notes.txt for deployed helm charts + operationId: fetchNotesTxt + description: Used to fetch notes.txt for helm charts deployed via GitOps + security: + - bearerAuth: [] + parameters: + - name: env-id + in: query + description: Environment ID of app + required: true + schema: + type: integer + - name: installed-app-id + in: query + description: Installed application ID + required: true + schema: + type: integer + responses: + '200': + description: Successfully fetched notes.txt + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + $ref: '#/components/schemas/Notes' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '404': + description: Chart or notes not found + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Error while fetching notes.txt + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Helm Charts + + + + schemas: + AppListDetail: + type: object + properties: + clusterIds: + type: array + description: Clusters to which result corresponds + items: + type: integer + applicationType: + type: string + description: Application type inside the array + enum: [DEVTRON-CHART-STORE, DEVTRON-APP, HELM-APP] + errored: + type: boolean + description: If data fetch for that cluster produced error + errorMsg: + type: string + description: Error message if client failed to fetch + helmApps: + type: array + description: All helm app list + items: + $ref: '#/components/schemas/HelmAppDetails' + devtronApps: + type: array + description: All devtron app list + items: + type: object + + HelmAppDetails: + type: object + properties: + lastDeployedAt: + type: string + format: date-time + description: Time when this application was last deployed/updated + appName: + type: string + description: Name of the helm application/helm release name + appId: + type: string + description: Unique identifier for app + chartName: + type: string + description: Name of the chart + chartAvatar: + type: string + description: URL/location of the chart icon + projectId: + type: integer + description: Unique identifier for the project, APP with no project will have id 0 + chartVersion: + type: string + description: Chart version + environmentDetail: + $ref: '#/components/schemas/EnvironmentDetails' + appStatus: + type: string + description: Application status + + EnvironmentDetails: + type: object + properties: + clusterName: + type: string + description: Cluster corresponding to the environment where application is deployed + clusterId: + type: integer + description: Cluster ID corresponding to the environment where application is deployed + namespace: + type: string + description: Namespace where application is deployed + isVirtualEnvironment: + type: boolean + description: Whether environment is virtual or not + + Notes: + type: object + properties: + gitOpsNotes: + type: string + description: Notes content + +tags: + - name: Helm Charts + description: Helm chart deployment management and operations \ No newline at end of file diff --git a/specs/helm/deployment-chart-type.yaml b/specs/helm/deployment-chart-type.yaml new file mode 100644 index 0000000000..1872692ade --- /dev/null +++ b/specs/helm/deployment-chart-type.yaml @@ -0,0 +1,104 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Helm Deployment Chart Types +paths: + /orchestrator/app/env/patch: + patch: + description: change the deployment template for an app and environment + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - envId + - appId + - targetChartRefId + properties: + envId: + type: integer + description: ID of the environment + appId: + type: integer + description: ID of the application + targetChartRefId: + type: integer + description: ID of the target chart reference + isBasicViewLocked: + type: boolean + description: Whether the basic view is locked + currentViewEditor: + type: string + enum: [BASIC, ADVANCED, UNDEFINED] + description: Current view editor type + template: + type: object + description: Deployment template configuration + + responses: + '200': + description: Successfully updated deployment template + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Whether the operation was successful + message: + type: string + description: Success message + '400': + description: Bad Request + content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + userDetailedMessage: + type: string + description: Detailed error message for user + '403': + description: Unauthorized User + content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + userDetailedMessage: + type: string + description: Detailed error message for user + '500': + description: Internal Server Error + content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int32 + description: Error code + status: + type: string + description: Error message + userDetailedMessage: + type: string + description: Detailed error message for user \ No newline at end of file diff --git a/specs/dynamic-handling-of-charts.yaml b/specs/helm/dynamic-charts.yaml similarity index 51% rename from specs/dynamic-handling-of-charts.yaml rename to specs/helm/dynamic-charts.yaml index 5271104b14..84a128b087 100644 --- a/specs/dynamic-handling-of-charts.yaml +++ b/specs/helm/dynamic-charts.yaml @@ -12,27 +12,27 @@ paths: operationId: ChartRefAutocompleteForApp parameters: - name: appId - in: query + in: path required: true schema: - type: string + type: integer + description: Application ID responses: '200': description: Successfully return all charts content: application/json: schema: + type: object properties: code: type: integer - description: status code + description: HTTP status code status: type: string - description: status + description: Status message result: - type: array - items: - $ref: '#/components/schemas/ChartRefResponse' + $ref: '#/components/schemas/ChartRefAutocompleteResponse' '400': description: Bad Request. Input Validation error/wrong request body. content: @@ -54,35 +54,79 @@ paths: components: schemas: - ChartRefResponse: + ChartRefAutocompleteResponse: type: object properties: chartRefs: type: array items: - $ref: '#/components/schemas/ChartRef' + $ref: '#/components/schemas/ChartRefAutocompleteDto' latestChartRef: type: integer + description: ID of the latest chart reference latestAppChartRef: type: integer + description: ID of the latest chart reference for the application latestEnvChartRef: type: integer + description: ID of the latest chart reference for the environment chartMetadata: + type: object + additionalProperties: + $ref: '#/components/schemas/ChartRefMetaData' + description: Map of chart name to metadata + compatibleChartTypes: type: array items: - type: string - ChartRef: + type: string + description: List of compatible chart types + + ChartRefAutocompleteDto: type: object properties: id: type: integer + description: Chart reference ID version: type: string + description: Chart version name: type: string + description: Chart name description: type: string + description: Chart description userUploaded: type: boolean + description: Whether the chart was uploaded by a user isAppMetricsSupported: - type: boolean \ No newline at end of file + type: boolean + description: Whether the chart supports application metrics + + ChartRefMetaData: + type: object + properties: + chartDescription: + type: string + description: Description of the chart + + Error: + type: object + required: + - code + - message + properties: + code: + type: string + description: Error code + example: E100 + message: + type: string + description: Error message + example: User is not authenticated + internalMessage: + type: string + description: Internal error message for debugging + userMessage: + type: string + description: User-friendly error message \ No newline at end of file diff --git a/specs/helm/provider.yaml b/specs/helm/provider.yaml new file mode 100644 index 0000000000..3e1f24e736 --- /dev/null +++ b/specs/helm/provider.yaml @@ -0,0 +1,793 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Helm Chart Provider Management + description: Devtron API for chart provider management including chart repositories, chart groups, and chart provider configuration + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 + +paths: + # Chart Provider APIs + /orchestrator/app-store/chart-provider/list: + get: + description: Get list of all chart providers + operationId: GetChartProviderList + responses: + '200': + description: List of chart providers + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ChartProviderResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/app-store/chart-provider/update: + post: + description: Toggle chart provider status + operationId: ToggleChartProvider + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartProviderRequest' + responses: + '200': + description: Chart provider updated successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/app-store/chart-provider/sync-chart: + post: + description: Sync chart provider + operationId: SyncChartProvider + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartProviderRequest' + responses: + '200': + description: Chart provider synced successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Chart Repository APIs + /orchestrator/chart-repo/{id}: + get: + description: Get chart repository by ID + operationId: GetChartRepoById + parameters: + - name: id + in: path + description: Chart repository ID + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Chart repository details + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepository' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-repo/list: + get: + description: Get list of all chart repositories + operationId: GetChartRepoList + responses: + '200': + description: List of chart repositories + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ChartRepository' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-repo/create: + post: + description: Create a new chart repository + operationId: CreateChartRepo + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepositoryRequest' + responses: + '200': + description: Chart repository created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepository' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /orchestrator/chart-repo/update: + post: + description: Update an existing chart repository + operationId: UpdateChartRepo + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepositoryRequest' + responses: + '200': + description: Chart repository updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepository' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-repo/validate: + post: + description: Validate chart repository configuration + operationId: ValidateChartRepo + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepositoryRequest' + responses: + '200': + description: Chart repository configuration is valid + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-repo/sync-charts: + post: + description: Trigger manual chart repository sync + operationId: TriggerChartSyncManual + responses: + '200': + description: Chart repository sync triggered successfully + content: + application/json: + schema: + type: object + properties: + status: + type: string + description: Sync status + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Chart Group APIs + /orchestrator/chart-group/: + post: + description: Create a new chart group + operationId: CreateChartGroup + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartGroup' + responses: + '200': + description: Chart group created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ChartGroup' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update an existing chart group + operationId: UpdateChartGroup + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartGroup' + responses: + '200': + description: Chart group updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ChartGroup' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-group/entries: + put: + description: Save chart group entries + operationId: SaveChartGroupEntries + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartGroupEntries' + responses: + '200': + description: Chart group entries saved successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-group/list: + get: + description: Get list of all chart groups + operationId: GetChartGroupList + responses: + '200': + description: List of chart groups + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ChartGroup' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/chart-group/{id}: + delete: + description: Delete a chart group + operationId: DeleteChartGroup + parameters: + - name: id + in: path + description: Chart group ID + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Chart group deleted successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + ChartProviderResponse: + type: object + required: + - id + - name + - active + properties: + id: + type: string + description: Unique identifier of the chart provider + name: + type: string + description: Name of the chart provider + active: + type: boolean + description: Whether the chart provider is active + isEditable: + type: boolean + description: Whether the chart provider is editable + isOCIRegistry: + type: boolean + description: Whether the chart provider is an OCI registry + registryProvider: + type: string + description: Type of registry provider + enum: [DOCKER_HUB, ECR, GCR, ACR, OTHER] + + ChartProviderRequest: + type: object + required: + - id + properties: + id: + type: string + description: Unique identifier of the chart provider + isOCIRegistry: + type: boolean + description: Whether the chart provider is an OCI registry + active: + type: boolean + description: Whether to activate the chart provider + + ChartRepository: + type: object + required: + - name + - url + properties: + id: + type: integer + description: Unique identifier of the chart repository + name: + type: string + description: Name of the chart repository + url: + type: string + description: URL of the chart repository + username: + type: string + description: Username for authentication + password: + type: string + description: Password for authentication + isOCIRegistry: + type: boolean + description: Whether the repository is an OCI registry + active: + type: boolean + description: Whether the repository is active + default: + type: boolean + description: Whether this is the default repository + authMode: + type: string + description: Authentication mode + enum: [ANONYMOUS, USERNAME_PASSWORD, ACCESS_TOKEN] + + ChartRepositoryRequest: + type: object + required: + - name + - url + properties: + name: + type: string + description: Name of the chart repository + url: + type: string + description: URL of the chart repository + username: + type: string + description: Username for authentication + password: + type: string + description: Password for authentication + isOCIRegistry: + type: boolean + description: Whether the repository is an OCI registry + active: + type: boolean + description: Whether to activate the repository + default: + type: boolean + description: Whether to set as default repository + authMode: + type: string + description: Authentication mode + enum: [ANONYMOUS, USERNAME_PASSWORD, ACCESS_TOKEN] + + ChartGroup: + type: object + required: + - name + properties: + id: + type: integer + description: Unique identifier of the chart group + name: + type: string + description: Name of the chart group + description: + type: string + description: Description of the chart group + userId: + type: integer + description: ID of the user who created the group + entries: + type: array + items: + $ref: '#/components/schemas/ChartGroupEntry' + description: List of chart entries in the group + + ChartGroupEntry: + type: object + required: + - chartId + properties: + chartId: + type: integer + description: ID of the chart + chartName: + type: string + description: Name of the chart + chartVersion: + type: string + description: Version of the chart + chartRepoId: + type: integer + description: ID of the chart repository + chartRepoName: + type: string + description: Name of the chart repository + + ChartGroupEntries: + type: object + required: + - groupId + - entries + properties: + groupId: + type: integer + description: ID of the chart group + entries: + type: array + items: + $ref: '#/components/schemas/ChartGroupEntry' + description: List of chart entries to save + + ErrorResponse: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + errors: + type: array + items: + $ref: '#/components/schemas/Error' + description: List of errors + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/helm/repo-validation.yaml b/specs/helm/repo-validation.yaml new file mode 100644 index 0000000000..c58703f2b8 --- /dev/null +++ b/specs/helm/repo-validation.yaml @@ -0,0 +1,211 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Helm Chart Repo Validation +servers: + - url: http://localhost:3000/orchestrator/chart-repo +paths: + /orchestrator/validate: + post: + description: Validate helm repo by checking index file + operationId: ValidateChartRepo + requestBody: + description: A JSON object containing the chart repo configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepoDto' + responses: + '200': + description: Successfully validated chart repo + content: + application/json: + schema: + $ref: '#/components/schemas/DetailedErrorHelmRepoValidation' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /create: + post: + description: Validate chart repo config and save if successfully validated + operationId: ValidateAndCreateChartRepo + requestBody: + description: A JSON object containing the chart repo configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepoDto' + responses: + '200': + description: Successfully created and validated chart repo + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepoDto' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /update: + post: + description: Validate configuration and update them if validation is successful + operationId: ValidateAndUpdateChartRepo + requestBody: + description: A JSON object containing the chart repo configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepoDto' + responses: + '200': + description: Successfully updated and validated chart repo + content: + application/json: + schema: + $ref: '#/components/schemas/ChartRepoDto' + '400': + description: Bad Request - Invalid input or validation error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - User not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - User lacks required permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + ChartRepoDto: + type: object + required: + - name + - authMode + properties: + id: + type: integer + description: Chart repo ID + name: + type: string + description: Chart repo name + minLength: 3 + url: + type: string + description: Chart repo URL + userName: + type: string + description: Username for authentication + password: + type: string + description: Password for authentication + sshKey: + type: string + description: SSH key for authentication + accessToken: + type: string + description: Access token for authentication + authMode: + type: string + description: Authentication mode + enum: [USERNAME_PASSWORD, SSH, ACCESS_TOKEN, ANONYMOUS] + active: + type: boolean + description: Whether the repo is active + default: + type: boolean + description: Whether this is the default repo + allowInsecureConnection: + type: boolean + description: Whether to allow insecure connections + + DetailedErrorHelmRepoValidation: + type: object + properties: + customErrMsg: + type: string + description: User-friendly error message + actualErrMsg: + type: string + description: Technical error message + + ErrorResponse: + type: object + required: + - code + - message + properties: + code: + type: integer + description: HTTP status code + message: + type: string + description: Error message + Error: + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/helmApp/deployment-history-api-spec.yaml b/specs/helmApp/deployment-history-api-spec.yaml index 2686dd7ea4..2160b67951 100644 --- a/specs/helmApp/deployment-history-api-spec.yaml +++ b/specs/helmApp/deployment-history-api-spec.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: version: 1.0.0 - title: Devtron Labs + title: Helm App Deployment History paths: /orchestrator/application/deployment-history: get: diff --git a/specs/helm_repo_validation.yaml b/specs/helm_repo_validation.yaml deleted file mode 100644 index 87f5fd05d6..0000000000 --- a/specs/helm_repo_validation.yaml +++ /dev/null @@ -1,152 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Helm Chart Repo Validation -servers: - - url: http://localhost:3000/orchestrator/app-store -paths: - /repo/validate: - post: - description: Validate helm repo by checking index file - operationId: ChartRepoValidate - requestBody: - description: A JSON object containing the chart repo configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ChartRepoDto' - responses: - '200': - description: Successfully return the validation results - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /repo/create: - post: - description: Validate chart repo config and save if successfully validated - operationId: ValidateAndCreateChartRepo - requestBody: - description: A JSON object containing the chart repo configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ChartRepoDto' - responses: - '200': - description: Successfully return validation results and if validation is correct then save the configuration - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /repo/update: - post: - description: Validate configuration and update them if validation is successful - operationId: ValidateAndUpdateChartRepo - requestBody: - description: A JSON object containing the chart repo configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ChartRepoDto' - responses: - '200': - description: Successfully return validation results and if validation is correct then update the configuration - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - ChartRepoDto: - type: object - properties: - id: - type: integer - name: - type: string - url: - type: string - userName: - type: string - password: - type: string - sshKey: - type: string - accessToken: - type: string - active: - type: boolean - default: - type: boolean - userId: - type: integer - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/historical-definitions.yaml b/specs/historical-definitions.yaml deleted file mode 100644 index 495b07245d..0000000000 --- a/specs/historical-definitions.yaml +++ /dev/null @@ -1,596 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Historical Task definitions -paths: - /orchestrator/app/history/cm/{appId}/{pipelineId}: - get: - description: fetch deployment details in history for deployed config maps - operationId: FetchDeploymentDetailsForDeployedCMHistory - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ConfigMapAndSecretHistoryDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/cs/{appId}/{pipelineId}: - get: - description: fetch deployment details in history for deployed secrets - operationId: FetchDeploymentDetailsForDeployedCSHistory - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ConfigMapAndSecretHistoryDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/template/{appId}/{pipelineId}: - get: - description: fetch deployment details in history for deployed deployment templates - operationId: FetchDeploymentDetailsForDeployedTemplatesHistory - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DeploymentTemplateHistoryDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/strategy/{appId}/{pipelineId}: - get: - description: fetch deployment details in history for deployed pipeline strategy - operationId: FetchDeploymentDetailsForDeployedStrategyHistory - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/PipelineStrategyHistoryDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/cm/{appId}/{pipelineId}/{id}: - get: - description: fetch history for deployed config map by id - operationId: FetchDeployedCMHistoryById - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DeploymentDetailsDataType' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/cs/{appId}/{pipelineId}/{id}: - get: - description: fetch history for deployed secret by id - operationId: FetchDeployedCSHistoryById - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DeploymentDetailsDataType' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/template/{appId}/{pipelineId}/{id}: - get: - description: fetch history for deployed deployment template by id - operationId: FetchDeployedTemplatesHistoryById - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DeploymentDetailsDataType' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /orchestrator/app/history/strategy/{appId}/{pipelineId}/{id}: - get: - description: fetch history for deployed pipeline strategy by id - operationId: FetchDeployedStrategyHistoryById - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DeploymentDetailsDataType' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - - /orchestrator/app/history/cd-config/{appId}/{pipelineId}: - get: - description: fetch history for cd config (pre/post stage config) - operationId: FetchDeployedCdConfigHistory - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: stage - in: query - required: true - schema: - type: string - enum: - - "PRE_CD" - - "POST_CD" - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/PrePostCdScriptHistoryDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - DeploymentDetailsDataType: - type: object - properties: - id: - type: integer - deployedOn: - type: string - format: timestamp - deployedBy: - type: integer - ConfigMapAndSecretHistoryDto: - type: object - properties: - id: - type: integer - pipelineId: - type: integer - dataType: - type: string - configData: - $ref: '#/components/schemas/ConfigData' - deployed: - type: boolean - deployedOn: - type: string - format: timestamp - deployedBy: - type: integer - - DeploymentTemplateHistoryDto: - type: object - properties: - id: - type: integer - pipelineId: - type: integer - imageDescriptorTemplate: - type: string - template: - type: string - templateName: - type: string - templateVersion: - type: string - isAppMetricsEnabled: - type: boolean - targetEnvironment: - type: integer - deployed: - type: boolean - deployedOn: - type: string - format: timestamp - deployedBy: - type: integer - - PipelineStrategyHistoryDto: - type: object - properties: - id: - type: integer - pipelineId: - type: integer - strategy: - type: string - config: - type: string - default: - type: boolean - deployed: - type: boolean - deployedOn: - type: string - format: timestamp - deployedBy: - type: integer - - PrePostCdScriptHistoryDto: - type: object - properties: - id: - type: integer - pipelineId: - type: integer - script: - type: string - stage: - type: string - configmapSecretNames: - $ref: '#/components/schemas/PrePostStageConfigMapSecretNames' - configmapData: - $ref: '#/components/schemas/ConfigData' - secretData: - $ref: '#/components/schemas/ConfigData' - triggerType: - type: string - execInEnv: - type: boolean - deployed: - type: boolean - deployedOn: - type: string - format: timestamp - deployedBy: - type: integer - - PrePostStageConfigMapSecretNames: - properties: - configMaps: - type: array - items: - type: string - secrets: - type: array - items: - type: string - - ConfigData: - properties: - name: - type: string - type: - type: string - external: - type: boolean - mountPath: - type: string - data: - type: string - defaultData: - type: string - defaultMountPath: - type: string - global: - type: boolean - externalType: - type: string - secretData: - type: array - items: - $ref: '#/components/schemas/ExternalSecret' - defaultSecretData: - type: array - items: - $ref: '#/components/schemas/ExternalSecret' - roleArn: - type: string - subPath: - type: boolean - filePermission: - type: string - ExternalSecret: - properties: - key: - type: string - name: - type: string - property: - type: string - isBinary: - type: boolean - - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/image-tagging.yaml b/specs/image-tagging.yaml deleted file mode 100644 index 0999dfd53a..0000000000 --- a/specs/image-tagging.yaml +++ /dev/null @@ -1,123 +0,0 @@ -openapi: "3.0.0" -info: - title: image-tags - version: "1.0" -paths: - /orchestrator/apps/image-tags/{artifact-id}: - post: - description: Create tags and comment for a particular image in a app - requestBody: - required: true - content: - application/json: - schema: - items: - $ref: "#/components/schemas/ImageTaggingRequestDTO" - responses: - "200": - description: success on tags and comment creation for the given artifact. - content: - application/json: - schema: - $ref: "#/components/schemas/ImageTaggingResponseDTO" - "500": - description: will get this response if any failure occurs at server side. - "400": - description: will get this response if invalid payload is sent in the request. - "403": - description: will get this response if user doesn't have build and deploy permission for the app - get: - description: will get all the tags and comment added for the provided artifact-id - responses: - "200": - description: on succesfull fetching of all the tags and comment for the requested artifact. - content: - application/json: - schema: - $ref: "#components/schemas/ImageTaggingResponseDTO" - "500": - description: will get this response if any failure occurs at server side. - "403": - description: will get this if user doesn't have access to the app that the requested artifact belongs. - - -#components -components: - schemas: - ImageTaggingResponseDTO: - type: object - properties: - prodEnvExists: - type: boolean - description: true/false - imageReleaseTags: - type: array - items: - $ref: '#/components/schemas/ReleaseTag' - imageComments: - type: array - items: - $ref: '#/components/schemas/ImageComment' - appReleaseTags: - type: array - items: - $ref: '#/components/schemas/ReleaseTag' - - - - ImageComment: - type: object - properties: - id: - type: integer - description: id of the image comment - comment: - type: string - description: image comments - example: 'this image is build for arm64 platform only' - artifactId: - type: integer - description: id of the artifact to which this comment is added - - - ReleaseTag: - type: object - properties: - id: - type: integer - description: id of the tag - tagName: - type: string - description: tag name - example: "v1.1" - appId: - type: integer - description: id of the app in which this tag is created - artifactId: - type: integer - description: id of the artifact to which this tag is tagged - softDeleted: - type: boolean - description: tag is deleted or not - - - ImageTaggingRequestDTO: - type: object - properties: - createTags: - type: array - items: - $ref: '#/components/schemas/ReleaseTag' - description: tag objects requested for creation - updateTags: - type: array - items: - $ref: '#/components/schemas/ReleaseTag' - description: tag objects requested for deletion - imageComment: - type: object - items: - $ref: '#/components/schemas/ImageComment' - description: image comment data - - diff --git a/specs/docker-build-config-override.yaml b/specs/infrastructure/docker-build.yaml similarity index 55% rename from specs/docker-build-config-override.yaml rename to specs/infrastructure/docker-build.yaml index 2dbe846134..9fa7edee3e 100644 --- a/specs/docker-build-config-override.yaml +++ b/specs/infrastructure/docker-build.yaml @@ -1,7 +1,7 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Create App Api + title: Docker Build Config Override API paths: /orchestrator/app/wf/all/component-names/{appId}: get: @@ -75,7 +75,7 @@ paths: $ref: "#/components/schemas/Error" /orchestrator/app/ci-pipeline/patch: post: - description: Create/Update ci pipeline. + description: Create/Update CI pipeline with docker build config override operationId: PatchCiPipeline requestBody: description: A JSON object containing the pipeline configuration @@ -86,11 +86,11 @@ paths: $ref: "#/components/schemas/CiPatchRequest" responses: "200": - description: Successfully return a message stating the operation is successful. + description: Successfully updated CI pipeline content: application/json: schema: - type: string + $ref: "#/components/schemas/CiConfigRequest" "400": description: Bad Request. Validation error/wrong request body. content: @@ -135,15 +135,204 @@ components: type: string CiPatchRequest: type: object + required: + - appId + - ciPipeline properties: action: type: integer + description: Action type for the patch operation appId: type: integer + description: ID of the application appWorkflowId: type: integer + description: ID of the application workflow ciPipeline: - $ref: "#/components/schemas/CiPipelineDetails" + $ref: "#/components/schemas/CiPipeline" + userId: + type: integer + description: ID of the user performing the operation + isJob: + type: boolean + description: Whether this is a CI job + isCloneJob: + type: boolean + description: Whether this is a cloned CI job + CiPipeline: + type: object + required: + - name + - isManual + - isExternal + - scanEnabled + properties: + id: + type: integer + description: ID of the CI pipeline + name: + type: string + description: Name of the CI pipeline + isManual: + type: boolean + description: Whether the pipeline is manual + isExternal: + type: boolean + description: Whether the pipeline is external + scanEnabled: + type: boolean + description: Whether security scanning is enabled + isDockerConfigOverridden: + type: boolean + description: Whether docker config is overridden + dockerConfigOverride: + $ref: "#/components/schemas/DockerConfigOverride" + ciMaterial: + type: array + items: + $ref: "#/components/schemas/CiPipelineMaterial" + beforeDockerBuildScripts: + type: array + items: + $ref: "#/components/schemas/BuildScript" + afterDockerBuildScripts: + type: array + items: + $ref: "#/components/schemas/BuildScript" + pipelineType: + type: string + enum: [CI, CI_JOB] + description: Type of the pipeline + DockerConfigOverride: + type: object + properties: + dockerRegistry: + type: string + description: ID of the docker registry + dockerRepository: + type: string + description: Name of the docker repository + ciBuildConfig: + $ref: "#/components/schemas/CiBuildConfigBean" + CiBuildConfigBean: + type: object + properties: + id: + type: integer + description: ID of the build config + gitMaterialId: + type: integer + description: ID of the git material + buildContextGitMaterialId: + type: integer + description: ID of the build context git material + useRootBuildContext: + type: boolean + description: Whether to use root build context + ciBuildType: + type: string + enum: [SELF_DOCKERFILE_BUILD_TYPE, MANAGED_DOCKERFILE_BUILD_TYPE, SKIP_BUILD_TYPE] + description: Type of CI build + dockerBuildConfig: + $ref: "#/components/schemas/DockerBuildConfig" + buildPackConfig: + $ref: "#/components/schemas/BuildPackConfig" + DockerBuildConfig: + type: object + properties: + dockerfilePath: + type: string + description: Path to the Dockerfile + dockerfileContent: + type: string + description: Content of the Dockerfile + args: + type: object + additionalProperties: + type: string + description: Docker build arguments + targetPlatform: + type: string + description: Target platform for the build + language: + type: string + description: Programming language + languageFramework: + type: string + description: Language framework + dockerBuildOptions: + type: object + additionalProperties: + type: string + description: Docker build options + buildContext: + type: string + description: Build context path + useBuildx: + type: boolean + description: Whether to use buildx + buildxProvenanceMode: + type: string + description: Buildx provenance mode + buildxK8sDriverOptions: + type: array + items: + type: object + additionalProperties: + type: string + description: Buildx k8s driver options + BuildPackConfig: + type: object + properties: + builderId: + type: string + description: ID of the builder + language: + type: string + description: Programming language + languageVersion: + type: string + description: Language version + buildPacks: + type: array + items: + type: string + description: List of buildpacks + args: + type: object + additionalProperties: + type: string + description: Buildpack arguments + projectPath: + type: string + description: Project path + BuildScript: + type: object + properties: + name: + type: string + description: Name of the script + script: + type: string + description: Script content + index: + type: integer + description: Index of the script + CiPipelineMaterial: + type: object + properties: + gitMaterialId: + type: integer + description: ID of the git material + type: + type: string + description: Type of the material + value: + type: string + description: Value of the material + active: + type: boolean + description: Whether the material is active CiConfigRequest: type: object properties: @@ -189,25 +378,6 @@ components: type: string dockerBuildConfig: $ref: "#/components/schemas/DockerBuildConfig" - DockerBuildConfig: - type: object - properties: - gitMaterialId: - type: integer - dockerfileRelativePath: - type: string - targetPlatform: - type: string - args: - type: array - items: - type: object - properties: - Key: - type: string - Value: - type: string - description: map of docker arguments, i.e. key-value pairs CiPipelineDetails: type: object properties: @@ -260,25 +430,16 @@ components: type: string checkoutPath: type: string - BuildScript: - type: object - properties: - index: - type: integer - name: - type: string - script: - type: string - reportDirectoryPath: - type: string Error: - required: - - code - - message + type: object properties: code: type: integer + format: int32 description: Error code - message: + status: + type: string + description: Error message + userDetailedMessage: type: string - description: Error message \ No newline at end of file + description: Detailed error message for user \ No newline at end of file diff --git a/specs/jobs.yaml b/specs/jobs.yaml deleted file mode 100644 index 4d374cf6ac..0000000000 --- a/specs/jobs.yaml +++ /dev/null @@ -1,257 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron Labs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: https://api.yourdomain.com - description: Production server - - url: http://localhost/orchestrator - description: Local development server - -paths: - /orchestrator/job: - post: - summary: Create or clone a job - description: Create and clone a job - operationId: createOrCloneJob - security: - - ApiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateJob" - responses: - "200": - description: Used to give response once a job is created - content: - application/json: - schema: - $ref: "#/components/schemas/ActionResponse" - "400": - description: Bad request - "401": - description: Unauthorized - "500": - description: Internal server error - /orchestrator/job/list: - post: - summary: List jobs - description: Get the list of all the jobs by applying filter - operationId: listJobs - security: - - ApiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/JobList" - responses: - "200": - description: Used to give response of list of jobs - content: - application/json: - schema: - $ref: "#/components/schemas/JobListResponse" - "400": - description: Bad request - "401": - description: Unauthorized - "500": - description: Internal server error - /orchestrator/job/ci-pipeline/list/{jobId}: - get: - summary: Get job CI pipeline list - description: fetch details of job ci-pipelines for the overview page - operationId: getJobCiPipelineList - security: - - ApiKeyAuth: [] - parameters: - - name: jobId - in: path - required: true - schema: - type: integer - responses: - "200": - description: Job CI pipeline list - "400": - description: Bad request - "401": - description: Unauthorized - "500": - description: Internal server error - -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: Authorization - schemas: - CreateJob: - type: object - properties: - appName: - type: string - description: Used to give the name of the job - example: "my-job-1" - isJob: - type: boolean - description: States whether its a job or an app - example: true - teamId: - type: integer - description: Used to give team id - example: 1 - templateId: - type: integer - description: Used to give the id of the job it wants to clone - example: 18 - labels: - type: array - items: - type: object - properties: - key: - type: string - example: "hello" - value: - type: string - example: "world" - propogate: - type: boolean - example: false - description: - type: string - description: Used to give the description of the job once it is made. - example: "This is my first Job" - ActionResponse: - type: object - properties: - id: - type: integer - description: Used to give the id of job once its created - example: 25 - appName: - type: string - description: Used to give the name of job once its created - example: "my-job-1" - material: - type: array - items: - $ref: '#/components/schemas/gitMaterial' - teamId: - type: integer - description: Used to give the team id - example: 1 - templateId: - type: integer - description: Used to give the templateId - example: 0 - description: - type: string - description: Used to give the description of the job once it is made. - example: "This is my first Job" - isJob: - type: boolean - description: used to tell whether it is a job or an app - example: true - JobList: - type: object - properties: - teams: - type: array - items: - type: integer - description: used to give the project id - example: [1,2] - appStatuses: - type: array - items: - type: string - description: used to give the filter of app ci-build status - example: ["Succeeded", "Starting"] - sortBy: - type: string - description: used to give the sort by constraint - example: "appNameSort" - sortOrder: - type: string - description: used to give the sort order - example: "ASC" - offset: - type: integer - description: used to give the number from which we want our job (if the offset is 20 means we want list of jobs from 20) - example: 0 - size: - type: integer - description: used to give the number of jobs we want - example: 20 - - JobListResponse: - type: object - properties: - jobContainers: - type: array - items: - $ref: '#/components/schemas/jobContainer' - jobCount: - type: integer -# Add missing schemas for gitMaterial, jobContainer, and jobCiPipeline - gitMaterial: - type: object - properties: - name: - type: string - url: - type: string - id: - type: integer - gitProviderId: - type: integer - checkoutPath: - type: string - fetchSubmodules: - type: boolean - isUsedInCiConfig: - type: boolean - jobContainer: - type: object - properties: - jobId: - type: integer - jobName: - type: string - description: - type: string - ciPipelines: - type: array - items: - $ref: '#/components/schemas/jobCiPipeline' - jobCiPipeline: - type: object - properties: - ciPipelineId: - type: integer - status: - type: string - lastRunAt: - type: string - format: date-time - lastSuccessAt: - type: string - format: date-time - - - - - - - - diff --git a/specs/jobs/batch.yaml b/specs/jobs/batch.yaml new file mode 100644 index 0000000000..c7ca496826 --- /dev/null +++ b/specs/jobs/batch.yaml @@ -0,0 +1,478 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Batch Job Operations + description: Devtron API for batch and bulk operations + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication +paths: + /orchestrator/batch/operate: + post: + description: Execute batch operations on applications and workflows + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BatchOperationRequest' + responses: + '200': + description: Batch operation response + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: string + description: operation result + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + + /batch/bulk/v1beta1/application/dryrun: + post: + description: Get impacted apps for bulk update (dry run) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkUpdatePayload' + responses: + '200': + description: Impacted apps response + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ImpactedObjectsResponse' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + + /batch/bulk/v1beta1/application: + post: + description: Execute bulk update on applications + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkUpdateScript' + responses: + '200': + description: Bulk update response + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/BulkUpdateResponse' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + +components: + schemas: + BatchOperationRequest: + type: object + properties: + apiVersion: + type: string + description: API version + pipelines: + type: array + description: List of pipelines to operate on + items: + $ref: '#/components/schemas/Pipeline' + + BulkUpdateScript: + type: object + properties: + apiVersion: + type: string + description: API version + kind: + type: string + description: Resource kind + spec: + $ref: '#/components/schemas/BulkUpdatePayload' + + BulkUpdatePayload: + type: object + properties: + includes: + type: array + description: Apps to include + items: + type: string + excludes: + type: array + description: Apps to exclude + items: + type: string + envIds: + type: array + description: Environment IDs + items: + type: integer + global: + type: boolean + description: Apply globally + deploymentTemplate: + $ref: '#/components/schemas/DeploymentTemplateSpec' + configMap: + $ref: '#/components/schemas/ConfigMapSpec' + secret: + $ref: '#/components/schemas/SecretSpec' + + Pipeline: + type: object + properties: + build: + $ref: '#/components/schemas/Build' + deployment: + $ref: '#/components/schemas/Deployment' + + Build: + type: object + properties: + apiVersion: + type: string + operation: + $ref: '#/components/schemas/Operation' + dockerArguments: + type: object + trigger: + $ref: '#/components/schemas/Trigger' + buildMaterials: + type: array + items: + $ref: '#/components/schemas/BuildMaterial' + + BuildMaterial: + type: object + required: + - source + - gitMaterialUrl + properties: + source: + type: object + required: + - type + - value + properties: + type: + type: string + value: + type: string + enum: + - BranchFixed + - BranchRegex + - TagAny + - TagRegex + gitMaterialUrl: + type: string + + Deployment: + type: object + properties: + apiVersion: + type: string + operation: + $ref: '#/components/schemas/Operation' + trigger: + $ref: '#/components/schemas/Trigger' + strategy: + $ref: '#/components/schemas/DeploymentStrategy' + configMaps: + type: array + items: + $ref: '#/components/schemas/DataHolder' + secrets: + type: array + items: + $ref: '#/components/schemas/DataHolder' + + Operation: + type: string + description: Action to be taken on the component + enum: + - create + - delete + - update + - append + - clone + + Trigger: + type: string + description: How will this action be initiated + enum: + - manual + - automatic + + DeploymentStrategy: + type: object + properties: + blueGreen: + $ref: '#/components/schemas/BlueGreenStrategy' + canary: + $ref: '#/components/schemas/CanaryStrategy' + rolling: + $ref: '#/components/schemas/RollingStrategy' + recreate: + $ref: '#/components/schemas/RecreateStrategy' + default: + type: string + enum: + - BLUE-GREEN + - ROLLING + - CANARY + - RECREATE + + BlueGreenStrategy: + type: object + properties: + autoPromotionSeconds: + type: integer + format: int32 + scaleDownDelaySeconds: + type: integer + format: int32 + previewReplicaCount: + type: integer + format: int32 + autoPromotionEnabled: + type: boolean + + CanaryStrategy: + type: object + properties: + maxSurge: + type: string + maxUnavailable: + type: integer + format: int32 + steps: + type: array + items: + type: object + properties: + setWeight: + type: integer + format: int32 + pause: + type: object + properties: + duration: + type: integer + format: int32 + + RecreateStrategy: + type: object + + RollingStrategy: + type: object + properties: + maxSurge: + type: string + maxUnavailable: + type: integer + format: int32 + + DataHolder: + type: object + properties: + apiVersion: + type: string + operation: + $ref: '#/components/schemas/Operation' + type: + type: string + external: + type: boolean + mountPath: + type: string + global: + type: boolean + externalType: + type: string + data: + type: object + + DeploymentTemplateSpec: + type: object + properties: + patchJson: + type: string + description: JSON patch to apply + + ConfigMapSpec: + type: object + properties: + patchJson: + type: string + description: JSON patch to apply + + SecretSpec: + type: object + properties: + patchJson: + type: string + description: JSON patch to apply + + ImpactedObjectsResponse: + type: object + properties: + deploymentTemplate: + type: array + items: + type: string + configMap: + type: array + items: + type: string + secret: + type: array + items: + type: string + + BulkUpdateResponse: + type: object + properties: + deploymentTemplate: + $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponse' + configMap: + $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' + secret: + $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' + + DeploymentTemplateBulkUpdateResponse: + type: object + properties: + message: + type: array + items: + type: string + failure: + type: array + items: + type: string + + CmAndSecretBulkUpdateResponse: + type: object + properties: + message: + type: array + items: + type: string + failure: + type: array + items: + type: string + + ErrorResponse: + type: object + properties: + code: + type: integer + status: + type: string + errors: + type: array + items: + type: object + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Batch operation failed"] + + + diff --git a/specs/jobs/bulk-actions.yaml b/specs/jobs/bulk-actions.yaml new file mode 100644 index 0000000000..2f158864bc --- /dev/null +++ b/specs/jobs/bulk-actions.yaml @@ -0,0 +1,268 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Job Bulk Actions + description: Devtron API for bulk actions - Hibernate, UnHibernate, Deploy Latest Builds + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080/orchestrator/batch +paths: + /orchestrator/batch/v1beta1/hibernate: + post: + description: Bulk Hibernate all apps for specific environment + operationId: BulkHibernate + requestBody: + description: bulk hibernate + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkApplicationForEnvironmentPayload' + responses: + '200': + description: Successfully hibernated all impacted apps. + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/BulkApplicationHibernateUnhibernateForEnvironmentResponse' + '400': + description: Bad Request. Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /v1beta1/unhibernate: + post: + description: Bulk Unhibernate all apps for specific environment + operationId: BulkUnhibernate + requestBody: + description: bulk unhibernate + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkApplicationForEnvironmentPayload' + responses: + '200': + description: Successfully unhibernated all impacted apps. + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/BulkApplicationHibernateUnhibernateForEnvironmentResponse' + '400': + description: Bad Request. Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /v1beta1/deploy: + post: + description: Bulk Deploy all apps to the latest build image for specific environment + operationId: BulkDeploy + requestBody: + description: bulk deploy + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkApplicationForEnvironmentPayload' + responses: + '200': + description: Successfully deploy all impacted apps. + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/BulkApplicationForEnvironmentResponse' + '400': + description: Bad Request. Validation error/wrong request body. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized User + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + +components: + schemas: + BulkApplicationForEnvironmentPayload: + type: object + properties: + appIdIncludes: + type: array + items: + type: integer + description: app ids to include + appIdExcludes: + type: array + items: + type: integer + description: app ids to exclude + envId: + type: integer + description: environment id + envName: + type: string + description: environment name + appNamesIncludes: + type: array + items: + type: string + description: app names to include + appNamesExcludes: + type: array + items: + type: string + description: app names to exclude + invalidateCache: + type: boolean + description: whether to invalidate cache + deployLatestEligibleArtifact: + type: boolean + description: whether to deploy latest eligible artifact + + BulkApplicationHibernateUnhibernateForEnvironmentResponse: + type: object + properties: + appIdIncludes: + type: array + items: + type: integer + appIdExcludes: + type: array + items: + type: integer + envId: + type: integer + envName: + type: string + appNamesIncludes: + type: array + items: + type: string + appNamesExcludes: + type: array + items: + type: string + invalidateCache: + type: boolean + deployLatestEligibleArtifact: + type: boolean + response: + type: array + description: response array with operation results + items: + type: object + additionalProperties: true + + BulkApplicationForEnvironmentResponse: + type: object + properties: + appIdIncludes: + type: array + items: + type: integer + appIdExcludes: + type: array + items: + type: integer + envId: + type: integer + envName: + type: string + appNamesIncludes: + type: array + items: + type: string + appNamesExcludes: + type: array + items: + type: string + invalidateCache: + type: boolean + deployLatestEligibleArtifact: + type: boolean + response: + type: object + description: response map with operation results + additionalProperties: + type: object + additionalProperties: + type: boolean + + Error: + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/bulkEdit/v1beta1/bulk_edit.yaml b/specs/jobs/bulk-update.yaml similarity index 81% rename from specs/bulkEdit/v1beta1/bulk_edit.yaml rename to specs/jobs/bulk-update.yaml index 8f10e6dfc2..e6040d011a 100644 --- a/specs/bulkEdit/v1beta1/bulk_edit.yaml +++ b/specs/jobs/bulk-update.yaml @@ -5,7 +5,7 @@ info: servers: - url: http://localhost:3000/orchestrator/batch paths: - /{apiVersion}/{kind}/readme: + /orchestrator/{apiVersion}/{kind}/readme: get: description: Returns Readme for bulk update for different resource in the url operationId: FindBulkUpdateReadme @@ -26,7 +26,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BulkUpdateSeeExampleResponse' + type: array + items: + $ref: '#/components/schemas/BulkUpdateSeeExampleResponse' '500': description: Internal Server Error content: @@ -50,9 +52,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ImpactedObjectsResponse' + $ref: '#/components/schemas/ImpactedObjectsResponse' '400': description: Bad Request. Validation error/wrong request body. content: @@ -115,7 +115,7 @@ components: required: - script properties: - resource: + operation: type: string description: Resource from url path, i.e. {apiVersion} & {kind} script: @@ -155,6 +155,40 @@ components: description: Array of Environment Ids of dependent apps global: type: boolean +<<<<<<<< HEAD:specs/jobs/bulk-update.yaml + description: Global flag for updating dependent apps + deploymentTemplate: + $ref: '#/components/schemas/Tasks' + configMap: + $ref: '#/components/schemas/CmAndSecret' + secret: + $ref: '#/components/schemas/CmAndSecret' + Tasks: + type: object + properties: + spec: + $ref: '#/components/schemas/Spec' + description: Spec of the Task + CmAndSecret: + type: object + properties: + spec: + $ref: '#/components/schemas/CmAndSecretSpec' + description: Spec of the ConfigMap/Secret + CmAndSecretSpec: + type: object + required: + - names + properties: + names: + type: array + items: + type: string + description: Names of all configmaps/secrets to be updated + patchData: + type: string + description: string with details of the patch to be used for updating +======== description: Flag for updating base Configurations of dependent apps deploymentTemplate: $ref: '#/components/schemas/Spec' @@ -180,13 +214,18 @@ components: type: string description: Name of all Secrets to be updated +>>>>>>>> develop:specs/bulkEdit/v1beta1/bulk_edit.yaml Spec: type: object properties: patchData: type: string +<<<<<<<< HEAD:specs/jobs/bulk-update.yaml + description: string with details of the patch to be used for updating +======== description: String with details of the patch to be used for updating +>>>>>>>> develop:specs/bulkEdit/v1beta1/bulk_edit.yaml NameIncludesExcludes: type: object properties: @@ -244,91 +283,58 @@ components: type: object properties: deploymentTemplate: - $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponse' - configMap: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' - secret: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' - DeploymentTemplateBulkUpdateResponse: - type: object - properties: - message: - type: array - items: - type: string - description: All top-level messages in response of bulk update action - failure: type: array items: $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update failed - successful: - type: array - items: - $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update applied successfully - CmAndSecretBulkUpdateResponse: - type: object - properties: - message: - type: array - items: - type: string - description: All top-level messages in response of bulk update action - failure: + configMap: type: array items: $ref: '#/components/schemas/CmAndSecretBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update failed - successful: + secret: type: array items: $ref: '#/components/schemas/CmAndSecretBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update applied successfully DeploymentTemplateBulkUpdateResponseForOneApp: type: object properties: appId: type: integer - description: Id of the concerned app + description: Id of the impacted app appName: type: string - description: Name of the concerned app + description: Name of the impacted app envId: - type: integer - description: Env ID of the concerned app + type: string + description: Env Id of the impacted app message: type: string - description: App-level message for the concerned app + description: Message indicating success or failure of the update CmAndSecretBulkUpdateResponseForOneApp: type: object properties: appId: type: integer - description: Id of the concerned app + description: Id of the impacted app appName: type: string - description: Name of the concerned app + description: Name of the impacted app envId: - type: integer - description: Env ID of the concerned app + type: string + description: Env Id of the impacted app names: type: array items: type: string - description: Names of all configmaps/secrets + description: Names of all configmaps/secrets impacted message: type: string - description: App-level message for the concerned app - + description: Message indicating success or failure of the update Error: - required: - - code - - message + type: object properties: code: type: integer - description: Error code + description: HTTP status code message: type: string description: Error message \ No newline at end of file diff --git a/specs/jobs/core.yaml b/specs/jobs/core.yaml new file mode 100644 index 0000000000..5a18f05128 --- /dev/null +++ b/specs/jobs/core.yaml @@ -0,0 +1,322 @@ +openapi: "3.0.0" +info: + title: Job Pipeline Management + description: Devtron API for job management operations including creation, cloning, and listing + version: "1.0" + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + +paths: + /job: + post: + summary: Create or clone a job + description: Create and clone a job + operationId: createOrCloneJob + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateJob" + responses: + '200': + description: Job created successfully + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + $ref: "#/components/schemas/ActionResponse" + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Jobs + /job/list: + post: + summary: List jobs + description: Get the list of all the jobs by applying filter + operationId: listJobs + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/JobListRequest" + responses: + '200': + description: List of jobs retrieved successfully + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + $ref: "#/components/schemas/JobListResponse" + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Jobs + + /job/ci-pipeline/list/{jobId}: + get: + summary: Get job CI pipeline list + description: Fetch details of job CI-pipelines for the overview page + operationId: getJobCiPipelineList + security: + - bearerAuth: [] + parameters: + - name: jobId + in: path + required: true + description: Job ID + schema: + type: integer + responses: + '200': + description: Job CI pipeline list retrieved successfully + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: Status code + status: + type: string + description: Status + result: + type: array + items: + $ref: "#/components/schemas/JobCiPipeline" + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '404': + description: Job not found + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '../common/schemas.yaml#/components/schemas/ErrorResponse' + tags: + - Jobs + schemas: + CreateJob: + type: object + required: + - appName + - teamId + - isJob + properties: + appName: + type: string + description: Name of the job + example: my-job-1 + isJob: + type: boolean + description: States whether it's a job or an app + example: true + teamId: + type: integer + description: Project ID + example: 1 + templateId: + type: integer + description: ID of the job to clone from + example: 18 + labels: + type: array + items: + $ref: '../common/schemas.yaml#/components/schemas/AppLabel' + description: + type: string + description: Description of the job + example: This is my first Job + + ActionResponse: + type: object + properties: + id: + type: integer + description: ID of job once created + example: 25 + appName: + type: string + description: Name of job once created + example: my-job-1 + material: + type: array + items: + $ref: '../common/schemas.yaml#/components/schemas/GitMaterial' + teamId: + type: integer + description: Team ID + example: 1 + templateId: + type: integer + description: Template ID + example: 0 + description: + type: string + description: Description of the job + example: This is my first Job + isJob: + type: boolean + description: Whether it is a job or an app + example: true + + JobListRequest: + type: object + properties: + teams: + type: array + items: + type: integer + description: Project IDs to filter by + example: [1, 2] + appStatuses: + type: array + items: + type: string + description: CI build status filter + example: [Succeeded, Starting] + sortBy: + type: string + description: Sort by constraint + example: appNameSort + sortOrder: + type: string + description: Sort order + example: ASC + offset: + type: integer + description: Number from which to start the job list (pagination) + example: 0 + size: + type: integer + description: Number of jobs to return + example: 20 + + JobListResponse: + type: object + properties: + jobContainers: + type: array + items: + $ref: '#/components/schemas/JobContainer' + jobCount: + type: integer + description: Total number of jobs + + JobContainer: + type: object + properties: + jobId: + type: integer + jobName: + type: string + description: + type: string + ciPipelines: + type: array + items: + $ref: '#/components/schemas/JobCiPipeline' + + JobCiPipeline: + type: object + properties: + ciPipelineId: + type: integer + status: + type: string + lastRunAt: + type: string + format: date-time + lastSuccessAt: + type: string + format: date-time + +tags: + - name: Jobs + description: Job management operations for creating, cloning, and retrieving jobs \ No newline at end of file diff --git a/specs/k8s-resource-apis.yaml b/specs/k8s-resource-apis.yaml deleted file mode 100644 index 403800bff5..0000000000 --- a/specs/k8s-resource-apis.yaml +++ /dev/null @@ -1,35 +0,0 @@ -openapi: "3.0.2" -info: - title: version api - version: "1.0" -paths: - /orchestrator/k8s/resource/inception/info: - get: - responses: - "200": - description: this api give you inception pod info, such as pod name - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - $ref: '#/components/schemas/ResourceInfo' - -components: - schemas: - ResourceInfo: - type: object - required: - - podName - properties: - podName: - type: string - description: pod name \ No newline at end of file diff --git a/specs/k8s_apis-spec.yaml b/specs/k8s_apis-spec.yaml deleted file mode 100644 index 23d2a356be..0000000000 --- a/specs/k8s_apis-spec.yaml +++ /dev/null @@ -1,673 +0,0 @@ -openapi: "3.0.3" -info: - version: 1.0.0 - title: Devtron Labs -paths: - /orchestrator/k8s/resource: - post: - description: this api will be used for fetching all kind of manifest. - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - "200": - description: manifest fetch responces - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - $ref: '#/components/schemas/ResourceGetResponse' - put: - description: this api will be used for edit requested manifest. - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - "200": - description: manifest edit responces - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - $ref: '#/components/schemas/ResourceGetResponse' - /orchestrator/k8s/resource/create: - post: - description: this api will be used for applying desired manifest - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - "200": - description: create resource response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - $ref: '#/components/schemas/ResourceGetResponse' - /orchestrator/k8s/resource/delete: - post: - description: this api will be used for delete any resource. - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - "200": - description: manifest fetch responces - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - $ref: '#/components/schemas/ResourceGetResponse' - /orchestrator/k8s/events: - post: - description: this api will be used for fetching events for resources. - requestBody: - required: false - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - "200": - description: events success - content: - text/event-stream: - schema: - $ref: "#/components/schemas/EventsResponseObject" - /orchestrator/k8s/pods/logs/{podName}: - get: - description: this api will be used for fetching logs for container. - parameters: - - name: podName - in: path - required: true - schema: - type: string - - name: containerName - in: query - required: true - schema: - type: string - - name: appId - in: query - required: false - schema: - type: string - - name: clusterId - in: query - required: false - schema: - type: integer - - name: namespace - in: query - description: it is required when clusterId is passed - required: false - schema: - type: string - - name: follow - in: query - schema: - type: boolean - - name: sinceSeconds - in: query - schema: - type: integer - - name: tailLines - in: query - schema: - type: integer - responses: - "200": - description: events success - content: - text/event-stream: - schema: - $ref: "#/components/schemas/LogsResponseObject" - /orchestrator/k8s/pod/exec/session/{identifier}/{namespace}/{pod}/{shell}/{container}: - get: - description: get session for the terminal - parameters: - - in: path - name: identifier - schema: - type: string - required: true - description: application id or cluster id - example: "2|devtroncd|devtron or 3" - - in: path - name: namespace - schema: - type: string - required: true - description: namespace name - example: "devtroncd" - - in: path - name: pod - schema: - type: string - required: true - description: pod name - example: inception-58d44d99fd-tfw4s - - in: path - name: shell - schema: - type: string - oneOf: - - "bash" - - "sh" - - "powershell" - - "cmd" - required: true - description: shell to invoke - example: "bash" - - in: path - name: container - schema: - type: string - required: true - description: name of the container - example: "devtron" - responses: - 200: - description: session id - content: - application/json: - schema: - $ref: "#/components/schemas/TerminalMessage" - /orchestrator/k8s/api-resources/{clusterId}: - get: - description: Get All api resources for given cluster Id - parameters: - - name: clusterId - in: path - description: cluster Id - required: true - schema: - type: integer - format: int64 - responses: - "200": - description: Successfully fetched All api resources for given cluster Id - content: - application/json: - schema: - $ref: "#/components/schemas/GetAllApiResourcesResponse" - /orchestrator/k8s/resource/list: - post: - description: this api will be used for fetching all kind of manifest. - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: list response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: array - description: app list - items: - $ref: '#/components/schemas/ClusterResourceListResponse' - /orchestrator/k8s/resources/rotate: - post: - description: this api will be used to rotate pods for provided resources - parameters: - - in: query - name: appId - description: app id - required: true - schema: - type: string - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RotatePodRequest' - responses: - '200': - description: response in array of each resource - content: - application/json: - schema: - $ref: "#/components/schemas/RotatePodResponse" - /orchestrator/k8s/resources/apply: - post: - description: this api will be used to apply the resources in cluster - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ApplyResourcesRequest' - responses: - '200': - description: response in array of each resource - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/ApplyResourcesResponse" -components: - schemas: - TerminalMessage: - type: object - properties: - Op: - type: string - Data: - type: string - SessionID: - type: string - ResourceRequestObject: - type: object - properties: - appId: - type: string - clusterId: - type: number - description: clusterId is used when request is for direct cluster (when appId is not supplied) - k8sRequest: - $ref: '#/components/schemas/K8sRequestObject' - K8sRequestObject: - type: object - properties: - resourceIdentifier: - type: object - properties: - groupVersionKind: - type: object - properties: - Group: - type: string - Version: - type: string - Kind: - type: string - namespace: - type: string - name: - type: string - required: - - name - podLogsRequest: - type: object - properties: - containerName: - type: string - patch: - type: string - ResourceGetResponse: - type: object - properties: - manifestResponse: - $ref: '#/components/schemas/ManifestResponse' - secretViewAccess: - type: boolean - description: > - Indicates whether a user can see obscured secret values or not. - required: - - manifestResponse - - secretViewAccess - ManifestResponse: - type: object - properties: - manifest: - type: object - properties: - apiVersion: - type: string - data: - type: object - properties: - envoy.yaml: - type: string - kind: - type: string - metadata: - type: object - properties: - annotations: - type: object - properties: - meta.helm.sh/release-name: - type: string - meta.helm.sh/release-namespace: - type: string - creationTimestamp: - type: string - format: date-time - labels: - type: object - properties: - app: - type: string - app.kubernetes.io/managed-by: - type: string - chart: - type: string - heritage: - type: string - release: - type: string - name: - type: string - namespace: - type: string - resourceVersion: - type: string - selfLink: - type: string - uid: - type: string - EventsResponseObject: - type: object - properties: - events: - type: object - properties: - metadata: - type: object - properties: - selfLink: - type: string - resourceVersion: - type: string - items: - type: array - items: - type: object - properties: - metadata: - type: object - properties: - name: - type: string - namespace: - type: string - selfLink: - type: string - uid: - type: string - resourceVersion: - type: string - creationTimestamp: - type: string - format: date-time - managedFields: - type: array - items: - type: object - properties: - manager: - type: string - operation: - type: string - apiVersion: - type: string - time: - type: string - format: date-time - involvedObject: - type: object - properties: - kind: - type: string - namespace: - type: string - name: - type: string - uid: - type: string - apiVersion: - type: string - resourceVersion: - type: string - reason: - type: string - message: - type: string - source: - type: object - properties: - component: - type: string - firstTimestamp: - type: string - format: date-time - lastTimestamp: - type: string - format: date-time - count: - type: integer - format: int32 - type: - type: string - eventTime: - type: string - format: nullable - reportingComponent: - type: string - reportingInstance: - type: string - LogsResponseObject: - type: object - properties: - logs: - type: array - items: - type: object - properties: - id: - type: string - type: - type: string - data: - type: string - time: - type: string - GetAllApiResourcesResponse: - type: object - properties: - apiResources: - type: array - items: - $ref: "#/components/schemas/K8sApiResource" - allowedAll: - type: boolean - description: whether all api-resources allowed for this user - example: true - nullable: false - K8sApiResource: - type: object - properties: - gvk: - $ref: '#/components/schemas/GroupVersionKind' - namespaced: - type: boolean - description: whether this api resource is in namespaces scope or global - example: true - nullable: false - GroupVersionKind: - type: object - properties: - group: - type: string - description: group of the api-resource - example: "apps" - nullable: false - version: - type: string - description: version of the api-resource - example: "v1" - nullable: false - kind: - type: string - description: kind of the api-resource - example: "pod" - nullable: false - ClusterResourceListResponse: - type: object - properties: - headers: - type: array - items: - type: string - data: - type: array - items: - type: object - properties: - header-name: - type: string - description: each object from data key contains the objects keys length is equal to headers length - RotatePodRequest: - type: object - properties: - clusterId: - type: number - description: cluster Id - example: 1 - nullable: false - resources: - type: array - items: - type: object - properties: - groupVersionKind: - type: object - properties: - Group: - type: string - Version: - type: string - Kind: - type: string - namespace: - type: string - name: - type: string - required: - - name - RotatePodResponse: - type: object - properties: - containsError: - type: boolean - description: contains error - example: true - responses: - type: array - items: - type: object - properties: - groupVersionKind: - type: object - properties: - Group: - type: string - Version: - type: string - Kind: - type: string - namespace: - type: string - name: - type: string - errorResponse: - type: string - ApplyResourcesRequest: - type: object - properties: - clusterId: - type: number - description: cluster Id - example: 1 - nullable: false - manifest: - type: string - description: manifest of the resources (yamls saparated by ---) - example: "" - nullable: false - ApplyResourcesResponse: - type: object - properties: - kind: - type: string - description: kind of the resource - example: "pod" - nullable: false - name: - type: string - description: name of the resource - example: "someName" - nullable: false - error: - type: string - description: error in the operation of this resource - example: "someError" - nullable: true - isUpdate: - type: boolean - description: whether this resource was updated - example: true - nullable: false \ No newline at end of file diff --git a/specs/kubernetes/apis.yaml b/specs/kubernetes/apis.yaml new file mode 100644 index 0000000000..de09a13baa --- /dev/null +++ b/specs/kubernetes/apis.yaml @@ -0,0 +1,535 @@ +openapi: "3.0.3" +info: + version: 1.0.0 + title: Kubernetes Resource Management + description: API for managing Kubernetes resources and operations + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication +paths: + /orchestrator/k8s/resource: + post: + summary: Get Kubernetes resource manifest + description: Fetches the manifest for a specified Kubernetes resource + operationId: GetResource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: Resource manifest + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceGetResponse' + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + put: + summary: Update Kubernetes resource + description: Updates an existing Kubernetes resource manifest + operationId: UpdateResource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: Updated resource manifest + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceGetResponse' + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/resource/create: + post: + summary: Create Kubernetes resource + description: Creates a new Kubernetes resource + operationId: CreateResource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: Created resource manifest + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceGetResponse' + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/resource/delete: + post: + summary: Delete Kubernetes resource + description: Deletes a Kubernetes resource + operationId: DeleteResource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: Deleted resource manifest + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceGetResponse' + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/events: + post: + summary: Get Kubernetes events + description: Fetches events for Kubernetes resources + operationId: ListEvents + requestBody: + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: Resource events + content: + text/event-stream: + schema: + $ref: "#/components/schemas/EventsResponseObject" + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/pods/logs/{podName}: + get: + summary: Get pod logs + description: Fetches logs for a container in a pod + operationId: GetPodLogs + parameters: + - name: podName + in: path + required: true + schema: + type: string + - name: containerName + in: query + required: true + schema: + type: string + - name: appId + in: query + required: false + schema: + type: string + - name: clusterId + in: query + required: false + schema: + type: integer + - name: namespace + in: query + description: Required when clusterId is provided + required: false + schema: + type: string + - name: follow + in: query + schema: + type: boolean + - name: sinceSeconds + in: query + schema: + type: integer + - name: tailLines + in: query + schema: + type: integer + responses: + "200": + description: Pod logs + content: + text/event-stream: + schema: + $ref: "#/components/schemas/LogsResponseObject" + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/pod/exec/session/{identifier}/{namespace}/{pod}/{shell}/{container}: + get: + summary: Get terminal session + description: Gets a terminal session for a pod + operationId: GetTerminalSession + parameters: + - in: path + name: identifier + schema: + type: string + required: true + description: Application ID or cluster ID + example: "2|devtroncd|devtron or 3" + - in: path + name: namespace + schema: + type: string + required: true + description: Namespace name + example: "devtroncd" + - in: path + name: pod + schema: + type: string + required: true + description: Pod name + example: "inception-58d44d99fd-tfw4s" + - in: path + name: shell + schema: + type: string + enum: ["bash", "sh", "powershell", "cmd"] + required: true + description: Shell to invoke + example: "bash" + - in: path + name: container + schema: + type: string + required: true + description: Container name + example: "devtron" + responses: + "200": + description: Terminal session + content: + application/json: + schema: + $ref: "#/components/schemas/TerminalMessage" + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/api-resources/{clusterId}: + get: + summary: Get API resources + description: Gets all API resources for a given cluster + operationId: GetAllApiResources + parameters: + - name: clusterId + in: path + description: Cluster ID + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: API resources + content: + application/json: + schema: + $ref: "#/components/schemas/GetAllApiResourcesResponse" + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error + /k8s/resource/list: + post: + summary: List resources + description: Lists Kubernetes resources + operationId: GetResourceList + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestObject' + responses: + "200": + description: List of resources + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceGetResponse' + "400": + description: Bad request + "401": + description: Unauthorized + "403": + description: Forbidden + "500": + description: Internal server error +components: + schemas: + ResourceRequestObject: + type: object + required: + - clusterId + - k8sRequest + properties: + clusterId: + type: integer + description: Cluster ID + appId: + type: string + description: Application ID + k8sRequest: + $ref: '#/components/schemas/K8sRequest' + appType: + type: string + description: Application type + appIdentifier: + $ref: '#/components/schemas/AppIdentifier' + devtronAppIdentifier: + $ref: '#/components/schemas/DevtronAppIdentifier' + K8sRequest: + type: object + required: + - resourceIdentifier + properties: + resourceIdentifier: + $ref: '#/components/schemas/ResourceIdentifier' + patch: + type: string + description: JSON patch for update operations + ResourceIdentifier: + type: object + required: + - name + - namespace + - groupVersionKind + properties: + name: + type: string + description: Resource name + namespace: + type: string + description: Resource namespace + groupVersionKind: + $ref: '#/components/schemas/GroupVersionKind' + GroupVersionKind: + type: object + required: + - group + - version + - kind + properties: + group: + type: string + description: API group + version: + type: string + description: API version + kind: + type: string + description: Resource kind + AppIdentifier: + type: object + required: + - clusterId + - namespace + - releaseName + properties: + clusterId: + type: integer + description: Cluster ID + namespace: + type: string + description: Namespace + releaseName: + type: string + description: Release name + DevtronAppIdentifier: + type: object + required: + - clusterId + - namespace + - appName + properties: + clusterId: + type: integer + description: Cluster ID + namespace: + type: string + description: Namespace + appName: + type: string + description: Application name + ResourceGetResponse: + type: object + properties: + manifestResponse: + $ref: '#/components/schemas/ManifestResponse' + secretViewAccess: + type: boolean + description: Whether user has access to view secrets + ManifestResponse: + type: object + properties: + manifest: + type: string + description: Resource manifest in YAML format + ephemeralContainers: + type: array + items: + $ref: '#/components/schemas/EphemeralContainer' + description: List of ephemeral containers + EphemeralContainer: + type: object + properties: + name: + type: string + description: Container name + image: + type: string + description: Container image + status: + type: string + description: Container status + EventsResponseObject: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/Event' + description: List of events + Event: + type: object + properties: + type: + type: string + description: Event type + reason: + type: string + description: Event reason + message: + type: string + description: Event message + lastTimestamp: + type: string + format: date-time + description: Last occurrence timestamp + LogsResponseObject: + type: object + properties: + logs: + type: string + description: Container logs + TerminalMessage: + type: object + properties: + sessionId: + type: string + description: Terminal session ID + status: + type: string + description: Session status + GetAllApiResourcesResponse: + type: object + properties: + apiResources: + type: array + items: + $ref: '#/components/schemas/ApiResource' + description: List of API resources + ApiResource: + type: object + properties: + name: + type: string + description: Resource name + singularName: + type: string + description: Singular resource name + namespaced: + type: boolean + description: Whether resource is namespaced + kind: + type: string + description: Resource kind + verbs: + type: array + items: + type: string + description: Available verbs + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Kubernetes resource not found"] \ No newline at end of file diff --git a/specs/kube-capacity.yaml b/specs/kubernetes/capacity.yaml similarity index 57% rename from specs/kube-capacity.yaml rename to specs/kubernetes/capacity.yaml index 21befdb5e5..35655a0109 100644 --- a/specs/kube-capacity.yaml +++ b/specs/kubernetes/capacity.yaml @@ -1,42 +1,99 @@ openapi: "3.0.0" info: - title: Kube capacity + title: Kubernetes Capacity version: "1.0" + description: API for managing Kubernetes cluster capacity and node operations + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication paths: - /orchestrator/k8s/capacity/cluster/list: + /orchestrator/k8s/capacity/cluster/list/raw: get: - description: get list of clusters - operationId: GetClusterList + summary: Get cluster list + description: Returns a list of clusters with basic information + operationId: GetClusterListRaw responses: '200': - description: Successfully return list of cluster + description: List of clusters content: application/json: schema: type: array items: - $ref: '#/components/schemas/ClusterCapacityDto' - '400': - description: Bad Request. Input Validation error/wrong request body. + $ref: '#/components/schemas/ClusterCapacityDetail' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' '500': - description: Internal Server Error + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /k8s/capacity/cluster/list: + get: + summary: Get cluster list with details + description: Returns a list of clusters with detailed capacity information + operationId: GetClusterListWithDetail + responses: + '200': + description: List of clusters with details + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ClusterCapacityDetail' + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/cluster/{clusterId}: + + /k8s/capacity/cluster/{clusterId}: get: - description: get cluster detail + summary: Get cluster details + description: Returns detailed capacity information for a specific cluster operationId: GetClusterDetail parameters: - name: clusterId @@ -44,34 +101,43 @@ paths: required: true schema: type: integer + format: int64 responses: '200': - description: Successfully return detail of cluster + description: Cluster details content: application/json: schema: - $ref: '#/components/schemas/ClusterCapacityDetailDto' + $ref: '#/components/schemas/ClusterCapacityDetail' '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid clusterId format content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/node/list: + + /k8s/capacity/node/list: get: - description: get node list + summary: Get node list + description: Returns a list of nodes in a cluster operationId: GetNodeList parameters: - name: clusterId @@ -79,36 +145,45 @@ paths: required: true schema: type: integer + format: int64 responses: '200': - description: Successfully return list of node + description: List of nodes content: application/json: schema: type: array items: - $ref: '#/components/schemas/NodeCapacityDto' + $ref: '#/components/schemas/NodeCapacityDetail' '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid clusterId format content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/node: + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /k8s/capacity/node: get: - description: get node detail + summary: Get node details + description: Returns detailed information for a specific node operationId: GetNodeDetail parameters: - name: clusterId @@ -116,206 +191,253 @@ paths: required: true schema: type: integer + format: int64 - name: name in: query required: true schema: type: string - description: name of node + description: Name of the node responses: '200': - description: Successfully return node detail + description: Node details content: application/json: schema: - $ref: '#/components/schemas/NodeCapacityDetailDto' + $ref: '#/components/schemas/NodeCapacityDetail' '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid clusterId format or missing name content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' + put: - description: update node manifest + summary: Update node manifest + description: Updates the manifest for a specific node operationId: UpdateNodeManifest requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodeManifestUpdateDto' + $ref: '#/components/schemas/NodeUpdateRequestDto' responses: '200': - description: Successfully return updated node manifest + description: Updated node manifest content: application/json: schema: $ref: '#/components/schemas/NodeManifestUpdateResponse' '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid request body content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: - description: delete node detail + summary: Delete node + description: Deletes a specific node operationId: DeleteNode requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodeDeleteDto' + $ref: '#/components/schemas/NodeUpdateRequestDto' responses: '200': - description: Successfully return node detail + description: Node deleted successfully content: application/json: schema: - $ref: '#/components/schemas/NodeCapacityDetailDto' + $ref: '#/components/schemas/NodeManifestUpdateResponse' '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid request body content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/node/cordon: + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /k8s/capacity/node/cordon: put: - description: cordon/unCordon node + summary: Cordon or uncordon node + description: Marks a node as unschedulable or schedulable operationId: CordonOrUnCordonNode requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodeCordonReqDto' + $ref: '#/components/schemas/NodeUpdateRequestDto' responses: '200': - description: Return successful operation string. + description: Node cordoned/uncordoned successfully content: application/json: schema: type: string '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid request body content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/node/drain: + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /k8s/capacity/node/drain: put: - description: drain a node + summary: Drain node + description: Safely evicts all pods from a node operationId: DrainNode requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodeDrainReqDto' + $ref: '#/components/schemas/NodeUpdateRequestDto' responses: '200': - description: Return successful operation string. + description: Node drained successfully content: application/json: schema: type: string '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid request body content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden content: application/json: schema: $ref: '#/components/schemas/Error' - /orchestrator/k8s/capacity/node/taints/edit: + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /k8s/capacity/node/taints/edit: put: - description: edit node taints + summary: Edit node taints + description: Updates the taints on a node operationId: EditNodeTaints requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodeTaintEditReqDto' + $ref: '#/components/schemas/NodeUpdateRequestDto' responses: '200': - description: Return successful operation string. + description: Node taints updated successfully content: application/json: schema: type: string '400': - description: Bad Request. Input Validation error/wrong request body. + description: Bad request - invalid request body content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error + '401': + description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': - description: Unauthorized User + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error content: application/json: schema: @@ -323,141 +445,120 @@ paths: components: schemas: - ClusterCapacityDto: + ClusterCapacityDetail: type: object properties: id: type: integer + format: int64 name: type: string + errorInNodeListing: + type: string nodeCount: type: integer - nodeErrors: + nodeDetails: type: array items: - type: string + $ref: '#/components/schemas/NodeDetails' + nodeErrors: + type: object + additionalProperties: + type: array + items: + type: string nodeK8sVersions: type: array items: type: string - errorInNodeListing: - type: boolean - cpu: - $ref: '#/components/schemas/ResourceDetailObject' - memory: - $ref: '#/components/schemas/ResourceDetailObject' - ClusterCapacityDetailDto: - type: object - properties: + serverVersion: + type: string cpu: $ref: '#/components/schemas/ResourceDetailObject' memory: $ref: '#/components/schemas/ResourceDetailObject' - NodeCapacityDto: + isVirtualCluster: + type: boolean + isProd: + type: boolean + + NodeCapacityDetail: type: object properties: name: type: string - status: + version: + type: string + kind: type: string roles: type: array items: type: string - errors: - type: array - items: - $ref: '#/components/schemas/NodeError' k8sVersion: type: string - podCount: - type: integer - taintCount: - type: integer cpu: $ref: '#/components/schemas/ResourceDetailObject' memory: $ref: '#/components/schemas/ResourceDetailObject' age: type: string - labels: - type: array - items: - $ref: '#/components/schemas/LabelTaintObject' - NodeCapacityDetailObject: - type: object - properties: - name: + status: type: string - roles: - type: array - items: + podCount: + type: integer + errors: + type: object + additionalProperties: type: string - k8sVersion: + internalIp: + type: string + externalIp: type: string unschedulable: type: boolean createdAt: type: string - internalIp: - type: string - externalIp: - type: string - resources: - type: array - items: - $ref: '#/components/schemas/ResourceDetailObject' labels: type: array items: - $ref: '#/components/schemas/LabelTaintObject' + $ref: '#/components/schemas/LabelAnnotationTaintObject' annotations: type: array items: - $ref: '#/components/schemas/LabelTaintObject' + $ref: '#/components/schemas/LabelAnnotationTaintObject' taints: type: array items: - $ref: '#/components/schemas/LabelTaintObject' + $ref: '#/components/schemas/LabelAnnotationTaintObject' conditions: type: array items: $ref: '#/components/schemas/NodeConditionObject' - errors: + resources: type: array items: - $ref: '#/components/schemas/NodeError' + $ref: '#/components/schemas/ResourceDetailObject' pods: type: array items: - $ref: '#/components/schemas/PodCapacityDto' + $ref: '#/components/schemas/PodCapacityDetail' manifest: + type: object + clusterName: type: string - version: + nodeGroup: type: string - kind: - type: string - NodeError: - type: object - description: map of conditionType(key) and error(value) - PodCapacityDto: - type: object - properties: - name: - type: string - namespace: - type: string - cpu: - $ref: '#/components/schemas/ResourceDetailObject' - memory: - $ref: '#/components/schemas/ResourceDetailObject' - age: - type: string - NodeManifestUpdateDto: + + NodeUpdateRequestDto: type: object + required: + - clusterId + - name properties: clusterId: type: integer + format: int64 name: type: string manifestPatch: @@ -466,118 +567,106 @@ components: type: string kind: type: string - NodeDeleteDto: - type: object - properties: - clusterId: - type: integer - name: - type: string - version: - type: string - kind: - type: string - NodeCordonReqDto: - type: object - properties: - clusterId: - type: integer - name: - type: string - version: - type: string - kind: - type: string + taints: + type: array + items: + $ref: '#/components/schemas/Taint' nodeCordonOptions: $ref: '#/components/schemas/NodeCordonHelper' + nodeDrainOptions: + $ref: '#/components/schemas/NodeDrainHelper' + NodeCordonHelper: type: object properties: unschedulableDesired: type: boolean - description: set true if want to cordon, set false if want to uncordon - NodeDrainReqDto: - type: object - properties: - clusterId: - type: integer - name: - type: string - version: - type: string - kind: - type: string - nodeDrainOptions: - $ref: '#/components/schemas/NodeDrainHelper' + NodeDrainHelper: type: object + required: + - force + - deleteEmptyDirData + - gracePeriodSeconds + - ignoreAllDaemonSets + - disableEviction properties: - gracePeriodSeconds: - type: integer force: type: boolean deleteEmptyDirData: type: boolean + gracePeriodSeconds: + type: integer ignoreAllDaemonSets: type: boolean disableEviction: type: boolean - NodeTaintEditReqDto: + + NodeDetails: type: object properties: - clusterId: - type: integer - name: + nodeName: type: string - version: - type: string - kind: + nodeGroup: type: string taints: type: array items: - $ref: '#/components/schemas/Taint' - Taint: + $ref: '#/components/schemas/LabelAnnotationTaintObject' + + LabelAnnotationTaintObject: type: object properties: key: type: string - effect: - type: string - oneOf: - - "NoSchedule" - - "NoExecute" - - "PreferNoSchedule" value: type: string - required: false - NodeManifestUpdateResponse: + effect: + type: string + + NodeConditionObject: type: object properties: - manifest: + type: + type: string + status: + type: string + lastHeartbeatTime: + type: string + lastTransitionTime: type: string + reason: + type: string + message: + type: string + ResourceDetailObject: type: object properties: - name: - type: string capacity: type: string - allocatable: - type: string usage: type: string - request: - type: string - limit: - type: string usagePercentage: + type: number + requests: type: string - requestPercentage: + limits: + type: string + + PodCapacityDetail: + type: object + properties: + name: type: string - limitPercentage: + namespace: type: string - LabelTaintObject: + cpu: + $ref: '#/components/schemas/ResourceDetailObject' + memory: + $ref: '#/components/schemas/ResourceDetailObject' + + Taint: type: object properties: key: @@ -586,14 +675,33 @@ components: type: string effect: type: string - NodeConditionObject: + + NodeManifestUpdateResponse: type: object properties: - type: + manifest: + type: object + + Error: + type: object + properties: + code: type: string - haveIssue: - type: boolean - reason: + message: type: string + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 message: type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Kubernetes resource not found"] diff --git a/specs/kubernetes/cluster-management.yaml b/specs/kubernetes/cluster-management.yaml new file mode 100644 index 0000000000..8fe247aacf --- /dev/null +++ b/specs/kubernetes/cluster-management.yaml @@ -0,0 +1,515 @@ +openapi: 3.0.0 +info: + title: Cluster Management API + version: 1.0.0 + description: API for managing Kubernetes clusters + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Support + email: support@devtron.ai + url: https://devtron.ai/support + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication + +paths: + /orchestrator/cluster: + post: + summary: Create a new cluster + operationId: CreateCluster + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + responses: + '200': + description: Successfully created cluster + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + get: + summary: List all clusters + operationId: ListClusters + responses: + '200': + description: Successfully retrieved clusters + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ClusterBean' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + put: + summary: Update a cluster + operationId: UpdateCluster + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + responses: + '200': + description: Successfully updated cluster + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + delete: + summary: Delete a cluster + operationId: DeleteCluster + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + responses: + '200': + description: Successfully deleted cluster + content: + application/json: + schema: + type: string + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cluster/saveClusters: + post: + summary: Save multiple clusters + operationId: SaveClusters + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ClusterBean' + responses: + '200': + description: Successfully saved clusters + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ClusterBean' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cluster/validate: + post: + summary: Validate cluster configuration + operationId: ValidateCluster + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - kubeconfig + properties: + kubeconfig: + type: string + responses: + '200': + description: Successfully validated cluster + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterBean' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cluster/namespaces/{clusterId}: + get: + summary: Get namespaces for a cluster + operationId: GetClusterNamespaces + parameters: + - name: clusterId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved cluster namespaces + content: + application/json: + schema: + type: array + items: + type: string + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cluster/namespaces: + get: + summary: Get namespaces for all clusters + operationId: GetAllClusterNamespaces + responses: + '200': + description: Successfully retrieved all cluster namespaces + content: + application/json: + schema: + type: object + additionalProperties: + type: array + items: + type: string + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cluster/auth-list: + get: + summary: Get clusters with authentication details + operationId: GetClustersWithAuth + responses: + '200': + description: Successfully retrieved clusters with auth details + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ClusterBean' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + ClusterBean: + type: object + required: + - cluster_name + - server_url + properties: + id: + type: integer + description: Unique identifier for the cluster + cluster_name: + type: string + description: Name of the cluster + server_url: + type: string + description: URL of the Kubernetes API server + prometheus_url: + type: string + description: URL of the Prometheus server + active: + type: boolean + description: Whether the cluster is active + config: + type: object + properties: + bearer_token: + type: string + description: Bearer token for authentication + tls_key: + type: string + description: TLS key for secure communication + cert_data: + type: string + description: Certificate data + cert_auth_data: + type: string + description: Certificate authority data + prometheusAuth: + type: object + properties: + type: + type: string + enum: [basic, bearer] + basic: + type: object + properties: + username: + type: string + password: + type: string + bearer: + type: object + properties: + token: + type: string + defaultClusterComponent: + type: array + items: + $ref: '#/components/schemas/DefaultClusterComponent' + agentInstallationStage: + type: integer + description: Stage of agent installation + k8sVersion: + type: string + description: Kubernetes version + userName: + type: string + description: Name of the user who created/updated the cluster + insecure-skip-tls-verify: + type: boolean + description: Whether to skip TLS verification + errorInConnecting: + type: string + description: Error message if connection fails + clusterUpdated: + type: boolean + description: Whether the cluster was updated + + DefaultClusterComponent: + type: object + properties: + id: + type: string + name: + type: string + version: + type: string + status: + type: string + configuration: + type: object + properties: + type: + type: string + enum: [yaml, json] + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["Cluster not found in the system"] + + + + + diff --git a/specs/cluster_api_spec.yaml b/specs/kubernetes/cluster.yaml similarity index 70% rename from specs/cluster_api_spec.yaml rename to specs/kubernetes/cluster.yaml index 78cd252547..3cec785fd8 100644 --- a/specs/cluster_api_spec.yaml +++ b/specs/kubernetes/cluster.yaml @@ -1,7 +1,18 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron Labs + title: Kubernetes Cluster Management + description: Devtron API for cluster management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 paths: /orchestrator/cluster: put: @@ -120,22 +131,60 @@ components: properties: id: type: integer + description: cluster id cluster_name: type: string + description: cluster name + description: + type: string + description: cluster description server_url: type: string + description: server url prometheus_url: type: string + description: prometheus url active: type: boolean + description: whether cluster is active config: type: object - properties: - bearer_token: - type: string - description: it will be empty while fetching, and if no change while updating - k8sversion: + additionalProperties: + type: string + description: cluster config + prometheusAuth: + $ref: '#/components/schemas/PrometheusAuth' + k8sVersion: + type: string + description: kubernetes version + errorInConnecting: + type: string + description: error message if cluster failed to connect + isVirtualCluster: + type: boolean + description: whether cluster is virtual + agentInstallationStage: + type: integer + description: agent installation stage + createdOn: type: string + format: date-time + description: creation timestamp + updatedOn: + type: string + format: date-time + description: last update timestamp + createdBy: + type: string + description: creator's name + updatedBy: + type: string + description: last updater's name + defaultClusterComponent: + type: array + description: default cluster components + items: + $ref: '#/components/schemas/DefaultClusterComponent' PrometheusAuth: type: object properties: @@ -177,6 +226,26 @@ components: errorInConnecting: type: string description: error message if cluster failed to connect + isVirtualCluster: + type: boolean + description: whether cluster is virtual + serverUrl: + type: string + description: cluster server URL + config: + type: object + description: cluster configuration + properties: + bearerToken: + type: string + description: bearer token for cluster access + tlsConfig: + type: object + description: TLS configuration + properties: + insecureSkipTLSVerify: + type: boolean + description: whether to skip TLS verification ErrorResponse: required: diff --git a/specs/kubernetes/ephemeral-containers.yaml b/specs/kubernetes/ephemeral-containers.yaml new file mode 100644 index 0000000000..b38a62eb61 --- /dev/null +++ b/specs/kubernetes/ephemeral-containers.yaml @@ -0,0 +1,193 @@ +openapi: 3.0.0 +info: + title: Orchestrator K8s API + version: 1.0.0 +paths: + /orchestrator/k8s/resources/ephemeralContainers: + post: + summary: Create Ephemeral Container + parameters: + - name: identifier + in: query + required: true + schema: + type: string + description: Unique identifier for the request + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/EphemeralContainerRequest" + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: HTTP status code + status: + type: string + description: Status message + result: + $ref: "#/components/schemas/PodContainerList" + '400': + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + delete: + summary: Delete Ephemeral Container + parameters: + - name: identifier + in: query + required: true + schema: + type: string + description: Unique identifier for the request + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/EphemeralContainerRequest" + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + code: + type: integer + description: HTTP status code + status: + type: string + description: Status message + result: + type: boolean + description: Whether the ephemeral container was successfully terminated + '400': + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + +components: + schemas: + EphemeralContainerRequest: + type: object + properties: + basicData: + $ref: "#/components/schemas/EphemeralContainerBasicData" + advancedData: + $ref: "#/components/schemas/EphemeralContainerAdvancedData" + namespace: + type: string + description: Kubernetes namespace + clusterId: + type: integer + description: Cluster ID + minimum: 1 + podName: + type: string + description: Name of the pod + userId: + type: integer + description: User ID + externalArgoApplicationName: + type: string + description: Name of the external Argo application (if applicable) + required: + - namespace + - clusterId + - podName + EphemeralContainerBasicData: + type: object + properties: + containerName: + type: string + description: Name of the ephemeral container + targetContainerName: + type: string + description: Name of the target container to attach to + image: + type: string + description: Container image to use + required: + - containerName + - targetContainerName + - image + EphemeralContainerAdvancedData: + type: object + properties: + manifest: + type: string + description: Kubernetes manifest for the ephemeral container + PodContainerList: + type: object + properties: + containers: + type: array + items: + type: string + description: List of regular containers + initContainers: + type: array + items: + type: string + description: List of init containers + ephemeralContainers: + type: array + items: + type: string + description: List of running ephemeral containers + Error: + type: object + required: + - code + - message + properties: + code: + type: string + description: Error code + example: E100 + message: + type: string + description: Error message + example: User is not authenticated + internalMessage: + type: string + description: Internal error message for debugging + userMessage: + type: string + description: User-friendly error message diff --git a/specs/kubernetes/resources.yaml b/specs/kubernetes/resources.yaml new file mode 100644 index 0000000000..4f55608bf1 --- /dev/null +++ b/specs/kubernetes/resources.yaml @@ -0,0 +1,281 @@ +openapi: "3.0.2" +info: + title: Kubernetes Resource Operations + description: Devtron API for Kubernetes resource management + version: "1.0" + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 +paths: + /orchestrator/k8s/resource/inception/info: + get: + description: Get inception pod info, such as pod name + responses: + "200": + description: this api give you inception pod info, such as pod name + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ResourceInfo' + + /orchestrator/k8s/resource: + post: + description: Get Kubernetes resource details + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestBean' + responses: + "200": + description: Resource details + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ManifestResponse' + + /orchestrator/k8s/resource/create: + post: + description: Create Kubernetes resource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestBean' + responses: + "200": + description: Resource created successfully + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ManifestResponse' + + /orchestrator/k8s/resource: + put: + description: Update Kubernetes resource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestBean' + responses: + "200": + description: Resource updated successfully + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ManifestResponse' + + /orchestrator/k8s/resource/delete: + post: + description: Delete Kubernetes resource + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceRequestBean' + responses: + "200": + description: Resource deleted successfully + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + $ref: '#/components/schemas/ManifestResponse' + + /orchestrator/k8s/api-resources/{clusterId}: + get: + description: Get all API resources for a cluster + parameters: + - name: clusterId + in: path + required: true + schema: + type: integer + responses: + "200": + description: API resources list + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: array + items: + $ref: '#/components/schemas/K8sApiResource' + + /orchestrator/k8s/resource/urls: + get: + description: Get host URLs by batch + parameters: + - name: appId + in: query + required: true + schema: + type: integer + - name: appType + in: query + required: true + schema: + type: string + responses: + "200": + description: Host URLs + content: + application/json: + schema: + properties: + code: + type: integer + description: status code + status: + type: string + description: status + result: + type: array + items: + type: string + +components: + schemas: + ResourceInfo: + type: object + required: + - podName + properties: + podName: + type: string + description: pod name + + ResourceRequestBean: + type: object + properties: + appId: + type: integer + description: application id + k8sRequest: + $ref: '#/components/schemas/K8sRequestDto' + + K8sRequestDto: + type: object + properties: + resourceIdentifier: + $ref: '#/components/schemas/ResourceIdentifier' + patch: + type: string + description: patch data for update operations + + ResourceIdentifier: + type: object + properties: + name: + type: string + description: resource name + namespace: + type: string + description: resource namespace + groupVersionKind: + $ref: '#/components/schemas/GroupVersionKind' + + GroupVersionKind: + type: object + properties: + group: + type: string + description: API group + version: + type: string + description: API version + kind: + type: string + description: resource kind + + ManifestResponse: + type: object + properties: + manifest: + type: object + description: Kubernetes manifest + success: + type: boolean + description: operation success status + + K8sApiResource: + type: object + properties: + gvk: + $ref: '#/components/schemas/GroupVersionKind' + gvr: + $ref: '#/components/schemas/GroupVersionResource' + namespaced: + type: boolean + description: whether resource is namespaced + + GroupVersionResource: + type: object + properties: + group: + type: string + description: API group + version: + type: string + description: API version + resource: + type: string + description: resource name \ No newline at end of file diff --git a/specs/manifest_generation.yeaml.yaml b/specs/manifest_generation.yeaml.yaml deleted file mode 100644 index 1d3b345e80..0000000000 --- a/specs/manifest_generation.yeaml.yaml +++ /dev/null @@ -1,117 +0,0 @@ -openapi: 3.0.3 -info: - title: App Deployment API - version: 1.0.0 -paths: - /orchestrator/app/deployments/{app-id}/{env-id}: - get: - summary: Fetch Deployment Template Comparison List - parameters: - - name: app-id - in: path - required: true - schema: - type: integer - description: The ID of the application. - - name: env-id - in: path - required: true - schema: - type: integer - description: The ID of the environment. - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/FetchTemplateComparisonList' - /orchestrator/app/deployment/template/data: - post: - summary: Get Values and Manifest for Deployment Template - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/DeploymentTemplateRequest' - responses: - '200': - description: Successful response - content: - application/json: - schema: - $ref: '#/components/schemas/ValuesAndManifestResponse' -components: - schemas: - FetchTemplateComparisonList: - type: object - properties: - chartId: - type: integer - description: The ID of the chart reference. - chartVersion: - type: string - description: The version of the chart. - chartType: - type: string - description: The type of the chart. - environmentId: - type: integer - description: The ID of the environment. - environmentName: - type: string - description: The name of the environment. - pipelineConfigOverrideId: - type: integer - description: The ID of the pipeline configuration override. - startedOn: - type: string - format: date-time - description: The timestamp when the deployment started. - finishedOn: - type: string - format: date-time - description: The timestamp when the deployment finished. - status: - type: string - description: The status of the deployment. - type: - type: integer - enum: [1, 2, 3, 4] - description: The type of deployment template. - DeploymentTemplateRequest: - type: object - properties: - appId: - type: integer - description: The ID of the application. - chartRefId: - type: integer - description: The ID of the chart reference. - getValues: - type: boolean - description: Whether to include values in the response. - type: - type: integer - enum: [1, 2, 3, 4] - description: The type of deployment template. - values: - type: boolean - description: Whether to include values in the response. - pipelineConfigOverrideId: - type: integer - description: The ID of the pipeline configuration override. - required: - - appId - - chartRefId - - getValues - - type - ValuesAndManifestResponse: - type: object - properties: - data: - type: string - description: The values or manifest data for the deployment template. diff --git a/specs/modularisation/v1.yaml b/specs/modularisation/v1.yaml index 4b31b98df7..3341994338 100644 --- a/specs/modularisation/v1.yaml +++ b/specs/modularisation/v1.yaml @@ -22,6 +22,10 @@ paths: type: array items: $ref: "#/components/schemas/ModuleInfo" + "401": + description: Unauthorized user + "500": + description: Internal server error post: description: some action on module (for eg - install/upgrade/etc..) parameters: @@ -44,6 +48,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad request - validation error or missing module name + "401": + description: Unauthorized user + "403": + description: Forbidden - insufficient permissions + "500": + description: Internal server error /orchestrator/server: get: description: Get server info @@ -54,6 +66,10 @@ paths: application/json: schema: $ref: "#/components/schemas/ServerInfo" + "401": + description: Unauthorized user + "500": + description: Internal server error post: description: some action on server (for eg - install/upgrade/etc..) requestBody: @@ -69,6 +85,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad request - validation error + "401": + description: Unauthorized user + "403": + description: Forbidden - insufficient permissions + "500": + description: Internal server error # Components components: diff --git a/specs/notification.yaml b/specs/notification.yaml deleted file mode 100644 index 3b99e4a469..0000000000 --- a/specs/notification.yaml +++ /dev/null @@ -1,326 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Swagger Petstore - description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification - termsOfService: http://swagger.io/terms/ - contact: - name: Swagger API Team - email: apiteam@swagger.io - url: http://swagger.io - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: http://petstore.swagger.io/api -paths: - /notification: - get: - summary: Returns all notification settings - description: Returns all notification settings - operationId: findNotificationSetting - parameters: - - name: offset - in: query - description: value can be regex search string. - required: true - schema: - type: integer - - name: size - in: query - description: value can be regex search string. - required: true - schema: - type: integer - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new NotificationSetting - description: create NotificationSetting api. - operationId: addNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: Update NotificationSetting - description: Update NotificationSetting api either recipients or events(trigger/success/failed). - operationId: updateNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: delete NotificationSetting - description: delete NotificationSetting. - operationId: deleteNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /notification/recipient: - get: - summary: used to fetch providers(recipients) - description: recipients fetch by string search, it will return slacks providers and email ids - operationId: deleteGroupPolicy - parameters: - - name: value - in: query - description: value can be regex search string. - required: true - schema: - type: string - responses: - '204': - description: list of recipients - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /notification/channel: - get: - summary: get all NotificationSettingConfig list - description: get all NotificationSettingConfig list - operationId: findNotificationSettingConfig - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfigResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new NotificationSettingConfig - description: create NotificationSettingConfig, Slack or SES - operationId: addNotificationSettingConfig - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfig' - responses: - '200': - description: create NotificationSettingConfig response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfigResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - NotificationSetting: - type: object - required: - - configName - properties: - id: - type: integer - description: Unique id - configName: - type: string - description: Unique name of group - appId: - type: integer - description: app id - envId: - type: integer - description: env id - pipelineIds: - type: array - items: - type: integer - eventTypeIds: - type: array - items: - type: integer - pipelineType: - type: string - description: pipeline type CI or CD - providers: - type: array - items: - $ref: '#/components/schemas/providers' - description: role filters objects - providers: - type: object - required: - - dest - properties: - dest: - type: string - description: channel destination name - rule: - type: string - description: rule - configId: - type: integer - description: config id - - - NotificationConfig: - type: object - required: - - channel - properties: - channel: - type: string - description: channel type - enum: - - slack - - ses - configs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - NotificationConfigResponse: - type: object - properties: - slackConfigs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - sesConfigs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - configs: - type: object - required: - - type - - configName - properties: - id: - type: integer - description: unique id for config either slack or ses on response or update only - type: - type: string - description: channel destination type, slack or ses - configName: - type: string - description: configName - secretKey: - type: string - description: secretKey, only in case of ses - accessKey: - type: string - description: accessKey, only in case of ses - fromEmail: - type: string - description: fromEmail, only in case of ses - region: - type: string - description: region, only in case of ses - webhookUrl: - type: string - description: webhook url, only fill in case of type is slack - teamId: - type: integer - description: project id, only fill in case of type is slack - userId: - type: integer - description: project id, only fill in case of type is slack - - entity: - type: object - properties: - id: - type: integer - description: it contains entity id - name: - type: string - description: it contains entity name - - - - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/notifications/core.yaml b/specs/notifications/core.yaml new file mode 100644 index 0000000000..a3bb55da76 --- /dev/null +++ b/specs/notifications/core.yaml @@ -0,0 +1,1400 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Notification Management + description: Devtron API for notification management including settings, channels, and configurations + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080/orchestrator +paths: + /orchestrator/notification: + get: + summary: Get all notification settings + description: Returns paginated list of all notification settings + operationId: getAllNotificationSettings + parameters: + - name: offset + in: query + description: Number of records to skip for pagination + required: true + schema: + type: integer + minimum: 0 + default: 0 + example: 0 + - name: size + in: query + description: Number of records to return per page + required: true + schema: + type: integer + minimum: 1 + maximum: 100 + default: 20 + example: 20 + responses: + '200': + description: Notification settings retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationSettingsViewResponse' + '400': + description: Bad request - invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create notification settings + description: Create new notification settings configuration + operationId: saveNotificationSettingsV2 + requestBody: + description: Notification settings request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationRequest' + example: + notificationConfigRequest: + - pipelineType: "CI" + eventTypeIds: [1, 2, 3] + teamId: [1] + providers: + - dest: "slack" + configId: 1 + recipient: "#general" + responses: + '200': + description: Notification settings created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationSettingsResponse' + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update notification settings + description: Update existing notification settings configuration + operationId: updateNotificationSettings + requestBody: + description: Notification update request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationUpdateRequest' + example: + updateType: "events" + notificationConfigRequest: + - id: 1 + pipelineType: "CI" + eventTypeIds: [1, 2] + teamId: [1] + responses: + '200': + description: Notification settings updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationSettingsResponse' + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Notification setting not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete notification settings + description: Delete notification settings by IDs + operationId: deleteNotificationSettings + requestBody: + description: Delete request with notification setting IDs + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NSDeleteRequest' + example: + id: [1, 2, 3] + responses: + '200': + description: Notification settings deleted successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Deletion success status + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Notification setting not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/v2: + post: + summary: Create notification settings (v2) + description: Create new notification settings configuration (v2 endpoint) + operationId: saveNotificationSettingsV2Alt + requestBody: + description: Notification settings request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationRequest' + responses: + '200': + description: Notification settings created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationSettingsResponse' + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/recipient: + get: + summary: Get recipient suggestions + description: Get recipient suggestions by search value, returns slack channels and email addresses + operationId: getRecipientListingSuggestion + parameters: + - name: value + in: query + description: Search value for recipient suggestions + required: true + schema: + type: string + minLength: 1 + example: "test" + responses: + '200': + description: List of recipient suggestions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NotificationRecipientListingResponse' + '400': + description: Bad request - invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel: + get: + summary: Get all notification channel configurations + description: Get all notification channel configurations (Slack, SES, SMTP, Webhook) + operationId: findAllNotificationConfig + responses: + '200': + description: Notification channel configurations retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ChannelResponseDTO' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create notification channel configuration + description: Create notification channel configuration (Slack, SES, SMTP, or Webhook) + operationId: saveNotificationChannelConfig + requestBody: + description: Channel configuration request + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SlackChannelConfig' + - $ref: '#/components/schemas/SESChannelConfig' + - $ref: '#/components/schemas/SMTPChannelConfig' + - $ref: '#/components/schemas/WebhookChannelConfig' + discriminator: + propertyName: channel + mapping: + slack: '#/components/schemas/SlackChannelConfig' + ses: '#/components/schemas/SESChannelConfig' + smtp: '#/components/schemas/SMTPChannelConfig' + webhook: '#/components/schemas/WebhookChannelConfig' + examples: + slack: + summary: Slack channel configuration + value: + channel: "slack" + configs: + - teamId: 1 + webhookUrl: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" + configName: "slack-config-1" + description: "Slack notifications for team 1" + ses: + summary: SES channel configuration + value: + channel: "ses" + configs: + - region: "us-east-1" + accessKey: "AKIAIOSFODNN7EXAMPLE" + secretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + fromEmail: "noreply@example.com" + configName: "ses-config-1" + description: "SES notifications" + responses: + '200': + description: Channel configuration created successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Creation success status + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete notification channel configuration + description: Delete notification channel configuration (Slack, SES, SMTP, or Webhook) + operationId: deleteNotificationChannelConfig + requestBody: + description: Channel configuration delete request + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SlackConfigDto' + - $ref: '#/components/schemas/SESConfigDto' + - $ref: '#/components/schemas/SMTPConfigDto' + - $ref: '#/components/schemas/WebhookConfigDto' + discriminator: + propertyName: channel + responses: + '200': + description: Channel configuration deleted successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: Success message + '400': + description: Bad request - invalid input data + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel/ses/{id}: + get: + summary: Get SES configuration by ID + description: Get SES notification configuration by ID + operationId: findSESConfig + parameters: + - name: id + in: path + description: SES configuration ID + required: true + schema: + type: integer + responses: + '200': + description: SES configuration retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SESConfigDto' + '400': + description: Bad request - invalid ID + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: SES configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel/slack/{id}: + get: + summary: Get Slack configuration by ID + description: Get Slack notification configuration by ID + operationId: findSlackConfig + parameters: + - name: id + in: path + description: Slack configuration ID + required: true + schema: + type: integer + responses: + '200': + description: Slack configuration retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SlackConfigDto' + '400': + description: Bad request - invalid ID + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Slack configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel/smtp/{id}: + get: + summary: Get SMTP configuration by ID + description: Get SMTP notification configuration by ID + operationId: findSMTPConfig + parameters: + - name: id + in: path + description: SMTP configuration ID + required: true + schema: + type: integer + responses: + '200': + description: SMTP configuration retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SMTPConfigDto' + '400': + description: Bad request - invalid ID + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: SMTP configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel/webhook/{id}: + get: + summary: Get Webhook configuration by ID + description: Get Webhook notification configuration by ID + operationId: findWebhookConfig + parameters: + - name: id + in: path + description: Webhook configuration ID + required: true + schema: + type: integer + responses: + '200': + description: Webhook configuration retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WebhookConfigDto' + '400': + description: Bad request - invalid ID + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Webhook configuration not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/variables: + get: + summary: Get webhook variables + description: Get available webhook variables for notification templates + operationId: getWebhookVariables + responses: + '200': + description: Webhook variables retrieved successfully + content: + application/json: + schema: + type: array + items: + type: string + description: Available webhook variable + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/channel/autocomplete/{type}: + get: + summary: Get notification channel autocomplete suggestions + description: Get autocomplete suggestions for notification channels by type + operationId: findAllNotificationConfigAutocomplete + parameters: + - name: type + in: path + description: Channel type (slack, ses, smtp, webhook) + required: true + schema: + type: string + enum: [slack, ses, smtp, webhook] + responses: + '200': + description: Autocomplete suggestions retrieved successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NotificationChannelAutoResponse' + '400': + description: Bad request - invalid type + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/notification/search: + post: + summary: Get notification settings options + description: Get options for notification settings based on search criteria + operationId: getOptionsForNotificationSettings + requestBody: + description: Search request for notification settings options + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SearchRequest' + example: + teamId: [1, 2] + appId: [1] + pipelineName: "test-pipeline" + responses: + '200': + description: Notification settings options retrieved successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchFilterResponse' + '400': + description: Bad request - invalid search criteria + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + # Main notification request/response schemas + NotificationRequest: + type: object + required: + - notificationConfigRequest + properties: + updateType: + type: string + enum: [events, recipients] + description: Type of update operation + providers: + type: array + items: + $ref: '#/components/schemas/Provider' + description: List of notification providers + notificationConfigRequest: + type: array + items: + $ref: '#/components/schemas/NotificationConfigRequest' + description: List of notification configuration requests + sesConfigId: + type: integer + description: SES configuration ID (deprecated) + + NotificationUpdateRequest: + type: object + required: + - notificationConfigRequest + properties: + updateType: + type: string + enum: [events, recipients] + description: Type of update operation + notificationConfigRequest: + type: array + items: + $ref: '#/components/schemas/NotificationConfigRequest' + description: List of notification configuration requests + + NotificationConfigRequest: + type: object + required: + - pipelineType + - eventTypeIds + properties: + id: + type: integer + description: Configuration ID + teamId: + type: array + items: + type: integer + description: List of team IDs + appId: + type: array + items: + type: integer + description: List of application IDs + envId: + type: array + items: + type: integer + description: List of environment IDs + clusterId: + type: array + items: + type: integer + description: List of cluster IDs + pipelineId: + type: integer + description: Pipeline ID + pipelineType: + type: string + enum: [CI, CD] + description: Pipeline type + eventTypeIds: + type: array + items: + type: integer + description: List of event type IDs + providers: + type: array + items: + $ref: '#/components/schemas/Provider' + description: List of notification providers + + Provider: + type: object + required: + - dest + - configId + properties: + dest: + type: string + enum: [slack, ses, smtp, webhook] + description: Destination channel type + rule: + type: string + description: Notification rule + configId: + type: integer + description: Configuration ID + recipient: + type: string + description: Recipient information + + NSDeleteRequest: + type: object + properties: + id: + type: array + items: + type: integer + description: List of notification setting IDs to delete + + NotificationSettingsViewResponse: + type: object + properties: + total: + type: integer + description: Total number of notification settings + settings: + type: array + items: + $ref: '#/components/schemas/NotificationSettingsResponse' + description: List of notification settings + + NotificationSettingsResponse: + type: object + properties: + id: + type: integer + description: Notification setting ID + configName: + type: string + description: Configuration name + team: + type: array + items: + $ref: '#/components/schemas/TeamResponse' + description: Associated teams + app: + type: array + items: + $ref: '#/components/schemas/AppResponse' + description: Associated applications + environment: + type: array + items: + $ref: '#/components/schemas/EnvResponse' + description: Associated environments + cluster: + type: array + items: + $ref: '#/components/schemas/ClusterResponse' + description: Associated clusters + pipeline: + $ref: '#/components/schemas/PipelineResponse' + description: Associated pipeline + pipelineType: + type: string + description: Pipeline type + providerConfigs: + type: array + items: + $ref: '#/components/schemas/ProvidersConfig' + description: Provider configurations + eventTypes: + type: array + items: + type: integer + description: Event type IDs + + # Channel configuration schemas + ChannelResponseDTO: + type: object + properties: + slackConfigs: + type: array + items: + $ref: '#/components/schemas/SlackConfigDto' + description: Slack configurations + webhookConfigs: + type: array + items: + $ref: '#/components/schemas/WebhookConfigDto' + description: Webhook configurations + sesConfigs: + type: array + items: + $ref: '#/components/schemas/SESConfigDto' + description: SES configurations + smtpConfigs: + type: array + items: + $ref: '#/components/schemas/SMTPConfigDto' + description: SMTP configurations + + SlackChannelConfig: + type: object + required: + - channel + - configs + properties: + channel: + type: string + enum: [slack] + description: Channel type + configs: + type: array + items: + $ref: '#/components/schemas/SlackConfigDto' + description: Slack configurations + + SlackConfigDto: + type: object + required: + - teamId + - webhookUrl + - configName + properties: + id: + type: integer + description: Configuration ID + userId: + type: integer + description: User ID + teamId: + type: integer + description: Team ID + webhookUrl: + type: string + description: Slack webhook URL + configName: + type: string + description: Configuration name + description: + type: string + description: Configuration description + + SESChannelConfig: + type: object + required: + - channel + - configs + properties: + channel: + type: string + enum: [ses] + description: Channel type + configs: + type: array + items: + $ref: '#/components/schemas/SESConfigDto' + description: SES configurations + + SESConfigDto: + type: object + required: + - region + - accessKey + - secretKey + - fromEmail + - configName + properties: + id: + type: integer + description: Configuration ID + ownerId: + type: integer + description: Owner user ID + teamId: + type: integer + description: Team ID + region: + type: string + description: AWS region + accessKey: + type: string + description: AWS access key + secretKey: + type: string + description: AWS secret key + fromEmail: + type: string + format: email + description: From email address + toEmail: + type: string + description: To email address + sessionToken: + type: string + description: AWS session token + configName: + type: string + description: Configuration name + description: + type: string + description: Configuration description + default: + type: boolean + description: Whether this is the default configuration + + SMTPChannelConfig: + type: object + required: + - channel + - configs + properties: + channel: + type: string + enum: [smtp] + description: Channel type + configs: + type: array + items: + $ref: '#/components/schemas/SMTPConfigDto' + description: SMTP configurations + + SMTPConfigDto: + type: object + properties: + id: + type: integer + description: Configuration ID + port: + type: string + description: SMTP port + host: + type: string + description: SMTP host + authType: + type: string + description: Authentication type + authUser: + type: string + description: Authentication username + authPassword: + type: string + description: Authentication password + fromEmail: + type: string + format: email + description: From email address + configName: + type: string + description: Configuration name + description: + type: string + description: Configuration description + ownerId: + type: integer + description: Owner user ID + default: + type: boolean + description: Whether this is the default configuration + deleted: + type: boolean + description: Whether this configuration is deleted + + WebhookChannelConfig: + type: object + required: + - channel + - configs + properties: + channel: + type: string + enum: [webhook] + description: Channel type + configs: + type: array + items: + $ref: '#/components/schemas/WebhookConfigDto' + description: Webhook configurations + + WebhookConfigDto: + type: object + required: + - webhookUrl + - configName + properties: + id: + type: integer + description: Configuration ID + userId: + type: integer + description: User ID + webhookUrl: + type: string + format: uri + description: Webhook URL + configName: + type: string + description: Configuration name + header: + type: object + additionalProperties: true + description: HTTP headers for webhook + payload: + type: string + description: Webhook payload template + description: + type: string + description: Configuration description + + # Response schemas for entities + TeamResponse: + type: object + properties: + id: + type: integer + description: Team ID + name: + type: string + description: Team name + + AppResponse: + type: object + properties: + id: + type: integer + description: Application ID + name: + type: string + description: Application name + + EnvResponse: + type: object + properties: + id: + type: integer + description: Environment ID + name: + type: string + description: Environment name + + ClusterResponse: + type: object + properties: + id: + type: integer + description: Cluster ID + name: + type: string + description: Cluster name + + PipelineResponse: + type: object + properties: + id: + type: integer + description: Pipeline ID + name: + type: string + description: Pipeline name + environmentName: + type: string + description: Environment name + appName: + type: string + description: Application name + branches: + type: array + items: + type: string + description: Git branches + clusterName: + type: string + description: Cluster name + + ProvidersConfig: + type: object + properties: + id: + type: integer + description: Provider configuration ID + dest: + type: string + description: Destination channel + name: + type: string + description: Configuration name + recipient: + type: string + description: Recipient information + + # Utility schemas + NotificationRecipientListingResponse: + type: object + properties: + dest: + type: string + enum: [slack, ses, smtp, webhook] + description: Destination channel type + configId: + type: integer + description: Configuration ID + recipient: + type: string + description: Recipient information + + NotificationChannelAutoResponse: + type: object + properties: + configName: + type: string + description: Configuration name + id: + type: integer + description: Configuration ID + + SearchRequest: + type: object + properties: + teamId: + type: array + items: + type: integer + description: List of team IDs + envId: + type: array + items: + type: integer + description: List of environment IDs + appId: + type: array + items: + type: integer + description: List of application IDs + clusterId: + type: array + items: + type: integer + description: List of cluster IDs + pipelineName: + type: string + description: Pipeline name filter + + SearchFilterResponse: + type: object + properties: + team: + type: array + items: + $ref: '#/components/schemas/TeamResponse' + description: Team options + app: + type: array + items: + $ref: '#/components/schemas/AppResponse' + description: Application options + environment: + type: array + items: + $ref: '#/components/schemas/EnvResponse' + description: Environment options + cluster: + type: array + items: + $ref: '#/components/schemas/ClusterResponse' + description: Cluster options + pipeline: + $ref: '#/components/schemas/PipelineResponse' + description: Pipeline options + pipelineType: + type: string + description: Pipeline type + + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/notifications/webhooks.yaml b/specs/notifications/webhooks.yaml new file mode 100644 index 0000000000..47cb526c37 --- /dev/null +++ b/specs/notifications/webhooks.yaml @@ -0,0 +1,541 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Webhook Notification Management + description: Devtron API for webhook management including Git webhooks, CI/CD webhooks, and notification webhooks + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 + +paths: + # Git Webhook APIs + /orchestrator/webhook/git: + post: + description: Handle Git webhook events + operationId: HandleGitWebhook + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitWebhookPayload' + responses: + '200': + description: Webhook processed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/webhook/git/{gitHostId}: + post: + description: Handle Git webhook events for a specific Git host + operationId: HandleGitWebhookForHost + parameters: + - name: gitHostId + in: path + description: Git host ID or name + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitWebhookPayload' + responses: + '200': + description: Webhook processed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/webhook/git/{gitHostId}/{secret}: + post: + description: Handle Git webhook events with secret validation + operationId: HandleGitWebhookWithSecret + parameters: + - name: gitHostId + in: path + description: Git host ID or name + required: true + schema: + type: string + - name: secret + in: path + description: Webhook secret for validation + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GitWebhookPayload' + responses: + '200': + description: Webhook processed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # CI/CD Webhook APIs + /orchestrator/webhook/ci/workflow: + post: + description: Handle CI/CD workflow webhook events + operationId: HandleWorkflowWebhook + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CiCdStatus' + responses: + '200': + description: Webhook processed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/webhook/ext-ci/{externalCiId}: + post: + description: Handle external CI webhook events + operationId: HandleExternalCiWebhook + parameters: + - name: externalCiId + in: path + description: External CI ID + required: true + schema: + type: integer + format: int64 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExternalCiWebhookDto' + responses: + '200': + description: Webhook processed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: Success status + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + + + + +components: + schemas: + GitWebhookPayload: + type: object + properties: + after: + type: string + description: Commit hash after the event + before: + type: string + description: Commit hash before the event + commits: + type: array + items: + $ref: '#/components/schemas/WebhookCommit' + description: List of commits in the event + compare: + type: string + description: URL to compare changes + created: + type: boolean + description: Whether the event created a new reference + deleted: + type: boolean + description: Whether the event deleted a reference + forced: + type: boolean + description: Whether the event was forced + head_commit: + $ref: '#/components/schemas/WebhookCommit' + description: The head commit of the event + pusher: + $ref: '#/components/schemas/User' + description: User who pushed the changes + ref: + type: string + description: Git reference (branch/tag) + repository: + $ref: '#/components/schemas/Repository' + description: Repository information + sender: + $ref: '#/components/schemas/User' + description: User who triggered the event + + WebhookCommit: + type: object + properties: + id: + type: string + description: Commit hash + message: + type: string + description: Commit message + timestamp: + type: string + format: date-time + description: Commit timestamp + author: + $ref: '#/components/schemas/User' + description: Commit author + committer: + $ref: '#/components/schemas/User' + description: Commit committer + added: + type: array + items: + type: string + description: List of added files + removed: + type: array + items: + type: string + description: List of removed files + modified: + type: array + items: + type: string + description: List of modified files + + User: + type: object + properties: + name: + type: string + description: User's name + email: + type: string + description: User's email + username: + type: string + description: User's username + + Repository: + type: object + properties: + id: + type: integer + description: Repository ID + name: + type: string + description: Repository name + full_name: + type: string + description: Full repository name (owner/repo) + private: + type: boolean + description: Whether the repository is private + html_url: + type: string + description: Repository URL + description: + type: string + description: Repository description + fork: + type: boolean + description: Whether the repository is a fork + url: + type: string + description: Repository API URL + default_branch: + type: string + description: Default branch name + + CiCdStatus: + type: object + required: + - pipelineId + - status + properties: + pipelineId: + type: integer + description: Pipeline ID + status: + type: string + description: Pipeline status + enum: [SUCCESS, FAILED, RUNNING, CANCELLED] + message: + type: string + description: Status message + startedOn: + type: string + format: date-time + description: Pipeline start time + finishedOn: + type: string + format: date-time + description: Pipeline end time + + ExternalCiWebhookDto: + type: object + required: + - pipelineId + - status + properties: + pipelineId: + type: integer + description: External CI pipeline ID + status: + type: string + description: Pipeline status + enum: [SUCCESS, FAILED, RUNNING, CANCELLED] + message: + type: string + description: Status message + startedOn: + type: string + format: date-time + description: Pipeline start time + finishedOn: + type: string + format: date-time + description: Pipeline end time + triggeredBy: + type: integer + description: User ID who triggered the pipeline + + WebhookChannelConfig: + type: object + required: + - webhookConfigDtos + properties: + webhookConfigDtos: + type: array + items: + $ref: '#/components/schemas/WebhookConfigDto' + description: List of webhook configurations + + WebhookConfigDto: + type: object + required: + - name + - url + properties: + id: + type: integer + description: Webhook configuration ID + name: + type: string + description: Webhook name + url: + type: string + description: Webhook URL + secret: + type: string + description: Webhook secret for validation + events: + type: array + items: + type: string + description: List of events to trigger the webhook + active: + type: boolean + description: Whether the webhook is active + createdBy: + type: integer + description: User ID who created the webhook + updatedBy: + type: integer + description: User ID who last updated the webhook + createdAt: + type: string + format: date-time + description: Creation timestamp + updatedAt: + type: string + format: date-time + description: Last update timestamp + + ErrorResponse: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + errors: + type: array + items: + $ref: '#/components/schemas/Error' + description: List of errors + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/openapiClient/api/apiToken_api-openapi.yaml b/specs/openapiClient/api/apiToken_api-openapi.yaml index 939a6f7dc5..4a3e8f3973 100644 --- a/specs/openapiClient/api/apiToken_api-openapi.yaml +++ b/specs/openapiClient/api/apiToken_api-openapi.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 info: - title: Devtron Labs + title: API Token Client Management version: 1.0.0 servers: - url: / @@ -17,15 +17,17 @@ paths: $ref: '#/components/schemas/ApiToken' type: array description: Successfully fetched active API tokens links + "401": + description: Unauthorized user + "500": + description: Internal server error post: description: Create api-token requestBody: content: application/json: schema: - items: - $ref: '#/components/schemas/CreateApiTokenRequest' - type: array + $ref: '#/components/schemas/CreateApiTokenRequest' required: true responses: "200": @@ -34,6 +36,14 @@ paths: schema: $ref: '#/components/schemas/CreateApiTokenResponse' description: Api-token creation response + "400": + description: Bad request - validation error or name cannot be blank + "401": + description: Unauthorized user + "403": + description: Forbidden - insufficient permissions + "500": + description: Internal server error /orchestrator/api-token/{id}: delete: description: Delete api-token @@ -54,6 +64,14 @@ paths: schema: $ref: '#/components/schemas/ActionResponse' description: Api-token delete response + "400": + description: Bad request - invalid ID format + "401": + description: Unauthorized user + "403": + description: Forbidden - insufficient permissions + "500": + description: Internal server error put: description: Update api-token parameters: @@ -79,6 +97,14 @@ paths: schema: $ref: '#/components/schemas/UpdateApiTokenResponse' description: Api-token update response + "400": + description: Bad request - validation error or invalid ID format + "401": + description: Unauthorized user + "403": + description: Forbidden - insufficient permissions + "500": + description: Internal server error /orchestrator/api-token/webhook: get: description: Get all api tokens which have given permission @@ -116,6 +142,10 @@ paths: $ref: '#/components/schemas/ApiToken' type: array description: Successfully fetched active API tokens links + "401": + description: Unauthorized user + "500": + description: Internal server error components: schemas: diff --git a/specs/openapiClient/api/openapi.yaml b/specs/openapiClient/api/openapi.yaml index 5b9aba4704..78ad8d984b 100644 --- a/specs/openapiClient/api/openapi.yaml +++ b/specs/openapiClient/api/openapi.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 info: - title: Devtron Labs + title: OpenAPI Client Management version: 1.0.0 servers: - url: / diff --git a/specs/pipeline-status-timeline.yaml b/specs/pipeline-status-timeline.yaml deleted file mode 100644 index 430b54b984..0000000000 --- a/specs/pipeline-status-timeline.yaml +++ /dev/null @@ -1,77 +0,0 @@ -openapi: "3.0.0" -info: - title: Pipeline deployment status timeline - version: "1.0" -paths: - /orchestrator/app/deployment-status/timeline/{appId}/{envId}: - get: - description: get all timelines of a delpoyment trigger - operationId: GetPipelineStatusTimelines - parameters: - - name: appId - in: path - required: true - schema: - type: integer - - name: envId - in: path - required: true - schema: - type: integer - - name: wfrId - in: path - required: false - schema: - type: integer - responses: - '200': - description: Successfully return deployment timeline status of a pipeline - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/PipelineStatusTimelineDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -components: - schemas: - PipelineStatusTimelineDto: - type: object - properties: - id: - type: integer - status: - type: string - status_detail: - type: integer - status_time: - type: timestampz - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message diff --git a/specs/plugins/config-maps.yaml b/specs/plugins/config-maps.yaml new file mode 100644 index 0000000000..f4e98f2e51 --- /dev/null +++ b/specs/plugins/config-maps.yaml @@ -0,0 +1,565 @@ +openapi: "3.0.0" +info: + title: Global ConfigMap and Secret Management + description: API for managing global ConfigMaps and Secrets + version: "1.0" + +paths: + /orchestrator/config/global/cm: + post: + description: Create or update a global ConfigMap + operationId: CMGlobalAddUpdate + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + responses: + '200': + description: Successfully created/updated ConfigMap + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/environment/cm: + post: + description: Create or update an environment-specific ConfigMap + operationId: CMEnvironmentAddUpdate + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + responses: + '200': + description: Successfully created/updated ConfigMap + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/global/cm/{appId}: + get: + description: Get all global ConfigMaps for an application + operationId: CMGlobalFetch + parameters: + - name: appId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved ConfigMaps + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/environment/cm/{appId}/{envId}: + get: + description: Get all environment-specific ConfigMaps for an application + operationId: CMEnvironmentFetch + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: envId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved ConfigMaps + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/global/cm/edit/{appId}/{id}: + get: + description: Get a global ConfigMap for editing + operationId: CMGlobalFetchForEdit + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: id + in: path + required: true + schema: + type: integer + - name: name + in: query + required: true + schema: + type: string + responses: + '200': + description: Successfully retrieved ConfigMap + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/environment/cm/edit/{appId}/{envId}/{id}: + get: + description: Get an environment-specific ConfigMap for editing + operationId: CMEnvironmentFetchForEdit + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: envId + in: path + required: true + schema: + type: integer + - name: id + in: path + required: true + schema: + type: integer + - name: name + in: query + required: true + schema: + type: string + responses: + '200': + description: Successfully retrieved ConfigMap + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigDataRequest' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/global/cm/{appId}/{id}: + delete: + description: Delete a global ConfigMap + operationId: CMGlobalDelete + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: id + in: path + required: true + schema: + type: integer + - name: name + in: query + required: true + schema: + type: string + responses: + '200': + description: Successfully deleted ConfigMap + content: + application/json: + schema: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/environment/cm/{appId}/{envId}/{id}: + delete: + description: Delete an environment-specific ConfigMap + operationId: CMEnvironmentDelete + parameters: + - name: appId + in: path + required: true + schema: + type: integer + - name: envId + in: path + required: true + schema: + type: integer + - name: id + in: path + required: true + schema: + type: integer + - name: name + in: query + required: true + schema: + type: string + responses: + '200': + description: Successfully deleted ConfigMap + content: + application/json: + schema: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/config/bulk/patch: + post: + description: Bulk patch ConfigMaps and Secrets + operationId: ConfigSecretBulkPatch + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkPatchRequest' + responses: + '200': + description: Successfully patched ConfigMaps and Secrets + content: + application/json: + schema: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + ConfigDataRequest: + type: object + required: + - appId + - userId + - configData + properties: + id: + type: integer + description: ID of the ConfigMap/Secret + appId: + type: integer + description: ID of the application + userId: + type: integer + description: ID of the user making the request + environmentId: + type: integer + description: ID of the environment (for environment-specific ConfigMaps/Secrets) + configData: + type: array + items: + $ref: '#/components/schemas/ConfigData' + + ConfigData: + type: object + required: + - name + - type + properties: + id: + type: integer + description: ID of the ConfigMap/Secret + name: + type: string + description: Name of the ConfigMap/Secret + type: + type: string + enum: [CONFIGMAP, SECRET] + description: Type of the configuration (ConfigMap or Secret) + external: + type: boolean + description: Whether this is an external ConfigMap/Secret + data: + type: object + additionalProperties: + type: string + description: Key-value pairs for the ConfigMap/Secret + mountPath: + type: string + description: Path where the ConfigMap/Secret should be mounted + subPath: + type: string + description: Subpath within the mount path + filePermission: + type: string + description: File permissions for the mounted ConfigMap/Secret + externalSecretType: + type: string + description: Type of external secret (for Secrets only) + roleARN: + type: string + description: ARN of the role to use for external secrets (for Secrets only) + externalSecret: + type: array + items: + $ref: '#/components/schemas/ExternalSecret' + description: External secret configuration (for Secrets only) + + ExternalSecret: + type: object + required: + - name + - key + properties: + name: + type: string + description: Name of the external secret + key: + type: string + description: Key in the external secret store + property: + type: string + description: Property to extract from the external secret + isBinary: + type: boolean + description: Whether the secret value is binary + + BulkPatchRequest: + type: object + required: + - userId + - global + properties: + userId: + type: integer + description: ID of the user making the request + global: + type: boolean + description: Whether to patch global or environment-specific ConfigMaps/Secrets + appId: + type: integer + description: ID of the application + environmentId: + type: integer + description: ID of the environment (for environment-specific patches) + configData: + type: array + items: + $ref: '#/components/schemas/ConfigData' + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message diff --git a/specs/plugin-system.yaml b/specs/plugins/core.yaml similarity index 87% rename from specs/plugin-system.yaml rename to specs/plugins/core.yaml index dc902158cf..2c2aa237c9 100644 --- a/specs/plugin-system.yaml +++ b/specs/plugins/core.yaml @@ -32,7 +32,7 @@ paths: result: type: array items: - $ref: '#/components/schemas/PluginMetaDataDto' + $ref: '#/components/schemas/PluginListComponentDto' '400': description: Bad Request. Input Validation error/wrong request body. content: @@ -77,7 +77,7 @@ paths: result: type: array items: - $ref: '#/components/schemas/PluginMetaDataDto' + $ref: '#/components/schemas/PluginListComponentDto' '400': description: Bad Request. Input Validation error/wrong request body. content: @@ -195,7 +195,7 @@ paths: type: string responses: '200': - description: Successfully return all operators + description: Successfully return all global variables content: application/json: schema: @@ -326,92 +326,115 @@ paths: $ref: '#/components/schemas/Error' components: schemas: + PluginListComponentDto: + type: object + properties: + id: + type: integer + description: Plugin ID + name: + type: string + description: Plugin name + type: + type: string + description: Plugin type (SHARED/PRESET) + description: + type: string + description: Plugin description + icon: + type: string + description: Plugin icon + tags: + type: array + items: + type: string + description: Plugin tags + inputVariables: + type: array + items: + $ref: '#/components/schemas/PluginVariableDto' + description: Input variables for the plugin + outputVariables: + type: array + items: + $ref: '#/components/schemas/PluginVariableDto' + description: Output variables from the plugin PluginDetailDto: type: object properties: metadata: - $ref: '#/components/schemas/PluginMetaDataDto' + $ref: '#/components/schemas/PluginMetadataDto' inputVariables: type: array items: $ref: '#/components/schemas/PluginVariableDto' + description: Input variables for the plugin outputVariables: type: array items: $ref: '#/components/schemas/PluginVariableDto' - PluginMetaDataDto: + description: Output variables from the plugin + PluginMetadataDto: type: object properties: id: type: integer + description: Plugin ID name: type: string + description: Plugin name type: type: string - example: - - "PRESET" + description: Plugin type (SHARED/PRESET) description: type: string + description: Plugin description icon: type: string + description: Plugin icon tags: type: array items: type: string - example: - - "GIT" - - "DATABASE" + description: Plugin tags PluginVariableDto: type: object properties: - id: - type: integer name: type: string - value: - type: integer - format: - type: string - example: - - "STRING" - - "NUMBER" - - "BOOL" - - "DATE" + description: Variable name description: type: string - defaultValue: + description: Variable description + type: type: string - RefVariableUsed: - type: boolean - variableType: + description: Variable type + format: type: string - example: - - "GLOBAL" - - "FROM_PREVIOUS_STEP" - RefVariableStepIndex: - type: integer - RefVariableName: + description: Variable format + required: + type: boolean + description: Whether the variable is required + defaultValue: type: string + description: Default value for the variable PluginListFilters: type: object properties: - pluginNameContains: + searchKey: type: string + description: Search key to filter plugins tags: type: array items: type: string - example: - - "GIT" - sortBy: - type: string - sortOrder: - type: string - pluginType: - type: string - example: - - "PRESET" - - "SHARED" + description: Tags to filter plugins + limit: + type: integer + description: Number of results to return + offset: + type: integer + description: Offset for pagination PluginFilterOptions: type: object properties: @@ -419,23 +442,24 @@ components: type: array items: type: string + description: Available plugin tags types: type: array items: type: string + description: Available plugin types GlobalVariable: type: object properties: - id: - type: integer name: type: string + description: Variable name value: type: string - format: - type: string + description: Variable value description: type: string + description: Variable description CiPipelineDto: type: object properties: @@ -725,13 +749,25 @@ components: portOnContainer: type: integer Error: - title: Error type: object - description: "A general error schema returned when status is not 200 OK" properties: code: + type: integer + description: Error code + status: type: string - description: "a code for this particular error" - message: - type: string - description: "a message with further detail" \ No newline at end of file + description: Error status + errors: + type: array + items: + type: object + properties: + code: + type: integer + description: Error code + internalMessage: + type: string + description: Internal error message + userMessage: + type: string + description: User friendly error message \ No newline at end of file diff --git a/specs/plugins/global.yaml b/specs/plugins/global.yaml new file mode 100644 index 0000000000..c0d658104a --- /dev/null +++ b/specs/plugins/global.yaml @@ -0,0 +1,587 @@ +openapi: "3.0.3" +info: + title: "Plugin System Integration - CI Stages" + description: | + This API facilitates the management of plugins used in pre/post CI or CD steps, + enhancing the customization and automation capabilities of CI/CD pipelines. + version: "1.0.0" + +paths: + /orchestrator/plugin/global/migrate: + put: + description: Migrate plugin data to the latest schema + operationId: MigratePluginData + security: + - bearerAuth: [] + responses: + '200': + description: Successfully migrated plugin data + content: + application/json: + schema: + type: object + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/create: + post: + description: Create a new plugin or plugin version + operationId: CreatePlugin + security: + - bearerAuth: [] + parameters: + - name: appId + in: query + required: false + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PluginParentMetadataDto' + responses: + '200': + description: Successfully created plugin + content: + application/json: + schema: + $ref: '#/components/schemas/PluginMinDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/detail/all: + get: + description: Get detailed information of all available plugins + operationId: GetAllDetailedPluginInfo + security: + - bearerAuth: [] + responses: + '200': + description: Successfully retrieved all plugin details + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PluginMetaDataDto' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/detail/{pluginId}: + get: + description: Get detailed information of a specific plugin by ID + operationId: GetDetailedPluginInfoByPluginId + parameters: + - name: pluginId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved plugin details + content: + application/json: + schema: + $ref: '#/components/schemas/PluginMetaDataDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/list/global-variable: + get: + description: Get list of all global variables + operationId: GetAllGlobalVariables + parameters: + - name: appId + in: query + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved global variables + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GlobalVariable' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/list/v2: + get: + description: Get list of all plugins with filtering options + operationId: ListAllPluginsV2 + parameters: + - name: appId + in: query + required: true + schema: + type: integer + - name: offset + in: query + required: false + schema: + type: integer + default: 0 + - name: size + in: query + required: false + schema: + type: integer + default: 20 + - name: searchKey + in: query + required: false + schema: + type: string + - name: tag + in: query + required: false + schema: + type: array + items: + type: string + - name: fetchAllVersionDetails + in: query + required: false + schema: + type: boolean + responses: + '200': + description: Successfully retrieved filtered plugins + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PluginMetaDataDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/list/detail/v2: + post: + description: Get detailed information for multiple plugins + operationId: GetPluginDetailByIds + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GlobalPluginDetailsRequest' + responses: + '200': + description: Successfully retrieved plugin details + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PluginMetaDataDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/list/tags: + get: + description: Get all unique tags used in plugins + operationId: GetAllUniqueTags + parameters: + - name: appId + in: query + required: true + schema: + type: integer + responses: + '200': + description: Successfully retrieved unique tags + content: + application/json: + schema: + type: array + items: + type: string + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/plugin/global/list/v2/min: + get: + description: Get minimal data for all plugins + operationId: GetAllPluginMinData + parameters: + - name: appId + in: query + required: true + schema: + type: integer + - name: type + in: query + required: true + schema: + type: string + enum: [SHARED, PRESET] + responses: + '200': + description: Successfully retrieved minimal plugin data + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PluginMinDto' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized user + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden, user is not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + PluginMetaDataDto: + type: object + properties: + id: + type: integer + description: Unique identifier for the plugin + name: + type: string + description: Name of the plugin + description: + type: string + description: Detailed description of what the plugin does + type: + type: string + enum: [SHARED, PRESET] + description: Type of the plugin indicating whether it's a SHARED plugin accessible by user or a PRESET plugin provided by the system + icon: + type: string + description: URL or a base64 encoded string representing an icon for the plugin + tags: + type: array + items: + type: string + description: List of tags associated with the plugin + versions: + type: array + items: + $ref: '#/components/schemas/PluginVersionDto' + createdOn: + type: string + format: date-time + description: Timestamp when the plugin was created + updatedOn: + type: string + format: date-time + description: Timestamp when the plugin was last updated + createdBy: + type: integer + description: ID of the user who created the plugin + updatedBy: + type: integer + description: ID of the user who last updated the plugin + + PluginVersionDto: + type: object + properties: + id: + type: integer + description: Unique identifier for the plugin version + version: + type: string + description: Version number of the plugin + description: + type: string + description: Description of changes in this version + createdOn: + type: string + format: date-time + description: Timestamp when the version was created + updatedOn: + type: string + format: date-time + description: Timestamp when the version was last updated + createdBy: + type: integer + description: ID of the user who created this version + updatedBy: + type: integer + description: ID of the user who last updated this version + + PluginParentMetadataDto: + type: object + properties: + id: + type: integer + description: Unique identifier for the plugin + name: + type: string + description: Name of the plugin + description: + type: string + description: Detailed description of what the plugin does + type: + type: string + enum: [SHARED, PRESET] + description: Type of the plugin + icon: + type: string + description: URL or base64 encoded icon + tags: + type: array + items: + type: string + description: List of tags + versions: + type: array + items: + $ref: '#/components/schemas/PluginVersionDto' + + PluginMinDto: + type: object + properties: + pluginVersionId: + type: integer + description: ID of the plugin version + + GlobalPluginDetailsRequest: + type: object + properties: + appId: + type: integer + description: ID of the application + parentPluginIdentifiers: + type: array + items: + type: string + description: List of parent plugin identifiers + + GlobalVariable: + type: object + required: + - name + - format + - description + - stageType + properties: + name: + type: string + description: The name of the global variable + value: + type: string + description: The value of the global variable + format: + type: string + description: The format of the value + description: + type: string + description: A description of the global variable and its purpose + stageType: + type: string + description: The type of stage this global variable is associated with + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message + + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: >- + JWT token for authentication. + Include the token in the Authorization header as: 'Bearer {token}' diff --git a/specs/apiToken_api-spec.yaml b/specs/security/api-tokens.yaml similarity index 52% rename from specs/apiToken_api-spec.yaml rename to specs/security/api-tokens.yaml index 76c2bcf537..a52a18c865 100644 --- a/specs/apiToken_api-spec.yaml +++ b/specs/security/api-tokens.yaml @@ -1,20 +1,38 @@ openapi: "3.0.3" info: version: 1.0.0 - title: Devtron Labs + title: API Token Management paths: /orchestrator/api-token: get: description: Get All active Api Tokens responses: "200": - description: Successfully fetched active API tokens links + description: Successfully fetched active API tokens content: application/json: schema: type: array items: $ref: "#/components/schemas/ApiToken" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" post: description: Create api-token requestBody: @@ -22,9 +40,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/CreateApiTokenRequest" + $ref: "#/components/schemas/CreateApiTokenRequest" responses: "200": description: Api-token creation response @@ -32,7 +48,31 @@ paths: application/json: schema: $ref: "#/components/schemas/CreateApiTokenResponse" - /orchestrator/api-token/{id}: + "400": + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /api-token/{id}: put: description: Update api-token parameters: @@ -56,6 +96,30 @@ paths: application/json: schema: $ref: "#/components/schemas/UpdateApiTokenResponse" + "400": + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" delete: description: Delete api-token parameters: @@ -73,6 +137,76 @@ paths: application/json: schema: $ref: "#/components/schemas/ActionResponse" + "400": + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /api-token/webhook: + get: + description: Get all api tokens which have given permission + parameters: + - name: projectName + in: query + description: Project name + schema: + type: string + - name: environmentName + in: query + description: Environment name + schema: + type: string + - name: appName + in: query + description: Application name + schema: + type: string + responses: + "200": + description: Successfully fetched API tokens for webhook + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ApiToken" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" components: schemas: ApiToken: @@ -127,6 +261,8 @@ components: example: "some date" CreateApiTokenRequest: type: object + required: + - name properties: name: type: string @@ -192,4 +328,15 @@ components: token: type: string description: Token of that api-token - example: "some token" \ No newline at end of file + example: "some token" + ErrorResponse: + type: object + properties: + code: + type: integer + description: HTTP status code + example: 400 + message: + type: string + description: Error message + example: "Bad Request" \ No newline at end of file diff --git a/specs/security/core.yaml b/specs/security/core.yaml new file mode 100644 index 0000000000..523c869640 --- /dev/null +++ b/specs/security/core.yaml @@ -0,0 +1,840 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Security & Access Management API + description: Devtron API for security management including user management, role groups, cluster access policies, and API token management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: /orchestrator + description: Devtron Orchestrator API Server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token for authentication + +paths: + # User Management APIs + /orchestrator/user/v2: + get: + description: Get all users with optional filters + operationId: GetAllUsers + security: + - bearerAuth: [] + parameters: + - name: searchKey + in: query + description: Search key for user listing + required: false + schema: + type: string + - name: sortOrder + in: query + description: Sorting order (ASC or DESC) + required: false + schema: + type: string + enum: [ASC, DESC] + - name: sortBy + in: query + description: Sorting by email_id or last_login + required: false + schema: + type: string + enum: [email_id, last_login] + - name: offset + in: query + description: Offset for paginating the results + required: false + schema: + type: integer + - name: size + in: query + description: Size of the result set + required: false + schema: + type: integer + - name: showAll + in: query + description: Show all users + required: false + schema: + type: boolean + responses: + '200': + description: List of users + content: + application/json: + schema: + $ref: '#/components/schemas/UserListingResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + + /orchestrator/user: + post: + description: Create a new user + operationId: CreateUser + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/User' + responses: + '200': + description: User created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update an existing user + operationId: UpdateUser + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/User' + responses: + '200': + description: User updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user/bulk: + delete: + description: Delete multiple users in bulk + operationId: BulkDeleteUsers + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkDeleteRequest' + responses: + '200': + description: Users deleted successfully + content: + application/json: + schema: + type: boolean + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Role Group Management APIs + /orchestrator/user/role/group/v2: + get: + description: Get all role groups with optional filters + operationId: GetAllRoleGroups + parameters: + - name: searchKey + in: query + description: Search key for group listing + required: false + schema: + type: string + - name: sortOrder + in: query + description: Sorting order (ASC or DESC) + required: false + schema: + type: string + enum: [ASC, DESC] + - name: sortBy + in: query + description: Sorting by name + required: false + schema: + type: string + enum: [name] + - name: offset + in: query + description: Offset for paginating the results + required: false + schema: + type: integer + - name: size + in: query + description: Size of the result set + required: false + schema: + type: integer + - name: showAll + in: query + description: Show all role groups + required: false + schema: + type: boolean + responses: + '200': + description: List of role groups + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroupListingResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user/role/group: + post: + description: Create a new role group + operationId: CreateRoleGroup + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + responses: + '200': + description: Role group created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update an existing role group + operationId: UpdateRoleGroup + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + responses: + '200': + description: Role group updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user/role/group/bulk: + delete: + description: Delete multiple role groups in bulk + operationId: BulkDeleteRoleGroups + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkDeleteRequest' + responses: + '200': + description: Role groups deleted successfully + content: + application/json: + schema: + type: boolean + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # API Token Management APIs + /orchestrator/api-token: + get: + description: Get all active API tokens + operationId: GetAllApiTokens + responses: + '200': + description: List of active API tokens + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ApiToken' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + post: + description: Create a new API token + operationId: CreateApiToken + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateApiTokenRequest' + responses: + '200': + description: API token created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/CreateApiTokenResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/api-token/{id}: + put: + description: Update an existing API token + operationId: UpdateApiToken + parameters: + - name: id + in: path + description: API token ID + required: true + schema: + type: integer + format: int64 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateApiTokenRequest' + responses: + '200': + description: API token updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateApiTokenResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + delete: + description: Delete an API token + operationId: DeleteApiToken + parameters: + - name: id + in: path + description: API token ID + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: API token deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ActionResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + User: + type: object + required: + - email_id + properties: + id: + type: integer + description: Unique ID of user + email_id: + type: string + description: Unique valid email ID of user + userRoleGroups: + type: array + items: + $ref: '#/components/schemas/UserRoleGroup' + roleFilters: + type: array + items: + $ref: '#/components/schemas/RoleFilter' + description: Role filters objects + + UserRoleGroup: + type: object + properties: + id: + type: integer + description: Role group ID + name: + type: string + description: Role group name + description: + type: string + description: Role group description + + RoleGroup: + type: object + required: + - name + properties: + id: + type: integer + description: Unique ID of role group + name: + type: string + description: Unique name of group + description: + type: string + description: Group description + roleFilters: + type: array + items: + $ref: '#/components/schemas/RoleFilter' + description: Role filters objects + + RoleFilter: + type: object + required: + - action + properties: + cluster: + type: string + description: Cluster name + namespace: + type: string + description: Namespace names (comma-separated for multiple, empty for all) + group: + type: string + description: Group names (comma-separated for multiple, empty for all) + kind: + type: string + description: Kind names (comma-separated for multiple, empty for all) + resource: + type: string + description: Resource names (comma-separated for multiple, empty for all) + action: + type: string + description: Action type (view, edit, admin) + enum: [view, edit, admin] + + UserListingResponse: + type: object + properties: + users: + type: array + items: + $ref: '#/components/schemas/User' + description: List of users + totalCount: + type: integer + description: Total number of users + + RoleGroupListingResponse: + type: object + properties: + groups: + type: array + items: + $ref: '#/components/schemas/RoleGroup' + description: List of role groups + totalCount: + type: integer + description: Total number of role groups + + BulkDeleteRequest: + type: object + properties: + ids: + type: array + items: + type: integer + description: List of IDs to delete + + ApiToken: + type: object + properties: + id: + type: integer + description: API token ID + userId: + type: integer + description: User ID associated with the token + userIdentifier: + type: string + description: Email ID of the token user + name: + type: string + description: Token name + description: + type: string + description: Token description + expireAtInMs: + type: integer + format: int64 + description: Expiration time in milliseconds + token: + type: string + description: Token value + lastUsedAt: + type: string + description: Last used timestamp + lastUsedByIp: + type: string + description: Last used IP address + updatedAt: + type: string + description: Last update timestamp + + CreateApiTokenRequest: + type: object + required: + - name + properties: + name: + type: string + description: Token name + description: + type: string + description: Token description + expireAtInMs: + type: integer + format: int64 + description: Expiration time in milliseconds + + UpdateApiTokenRequest: + type: object + properties: + description: + type: string + description: Token description + expireAtInMs: + type: integer + format: int64 + description: Expiration time in milliseconds + + CreateApiTokenResponse: + type: object + properties: + success: + type: boolean + description: Success status + token: + type: string + description: Generated token + userId: + type: integer + description: User ID + userIdentifier: + type: string + description: User email ID + + UpdateApiTokenResponse: + type: object + properties: + success: + type: boolean + description: Success status + token: + type: string + description: Updated token + + ActionResponse: + type: object + properties: + success: + type: boolean + description: Success status + + ErrorResponse: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + errors: + type: array + items: + $ref: '#/components/schemas/Error' + description: List of errors + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + + ApiError: + type: object + properties: + code: + type: integer + format: int32 + example: 404 + message: + type: string + example: "Resource not found" + details: + type: array + items: + type: string + example: ["User not found in the system"] \ No newline at end of file diff --git a/specs/group_policy.yaml b/specs/security/group-policy.yaml similarity index 51% rename from specs/group_policy.yaml rename to specs/security/group-policy.yaml index a509a411da..d745006cb1 100644 --- a/specs/group_policy.yaml +++ b/specs/security/group-policy.yaml @@ -1,9 +1,9 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Devtron + title: User Role Group Management API paths: - /user/role/group/v2: + /orchestrator/user/role/group/v2: get: summary: Returns all role groups description: all the template group policies @@ -69,20 +69,77 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + post: + summary: Creates a new Role Group + description: Creates a new role group with the provided configuration + operationId: createRoleGroupV2 + requestBody: + description: Role group configuration + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + responses: + '200': + description: Role group created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Updates an existing Role Group + description: Updates an existing role group with the provided configuration + operationId: updateRoleGroupV2 + requestBody: + description: Role group configuration + required: true + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/RoleGroup' + - type: object + required: + - id + properties: + id: + type: integer + format: int64 + responses: + '200': + description: Role group updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' - /user/role/group: + /orchestrator/user/role/group: get: summary: Returns all role groups - description: all the template group policies - operationId: findGroupPolicy - deprecated: true # Marking the operation as deprecated + description: Returns all role groups in the system + operationId: fetchRoleGroups responses: '200': - description: list response + description: List of role groups content: application/json: schema: - $ref: '#/components/schemas/RoleGroup' + type: array + items: + $ref: '#/components/schemas/RoleGroup' default: description: unexpected error content: @@ -91,10 +148,10 @@ paths: $ref: '#/components/schemas/Error' post: summary: Creates a new Role Group - description: create chart group api, with multiple environment in one row of policy, plus chart group additional type of policy. - operationId: addGroupPolicy + description: Creates a new role group with the provided configuration + operationId: createRoleGroup requestBody: - description: json as request body + description: Role group configuration required: true content: application/json: @@ -102,7 +159,7 @@ paths: $ref: '#/components/schemas/RoleGroup' responses: '200': - description: create group policy response + description: Role group created successfully content: application/json: schema: @@ -114,11 +171,11 @@ paths: schema: $ref: '#/components/schemas/Error' put: - summary: update a role group - description: update a role group in the system. - operationId: updateGroupPolicy + summary: Updates an existing Role Group + description: Updates an existing role group with the provided configuration + operationId: updateRoleGroup requestBody: - description: json as request body + description: Role group configuration required: true content: application/json: @@ -134,18 +191,11 @@ paths: format: int64 responses: '200': - description: group response + description: Role group updated successfully content: application/json: schema: - allOf: - - $ref: '#/components/schemas/RoleGroup' - - type: object - properties: - id: - type: integer - format: int64 - + $ref: '#/components/schemas/RoleGroup' default: description: unexpected error content: @@ -153,25 +203,27 @@ paths: schema: $ref: '#/components/schemas/Error' - /user/role/group/search: + /orchestrator/user/role/group/search: get: - summary: search a role group by NAME - description: search role group by group name + summary: Search role groups by name + description: Search role groups by their name operationId: findRoleGroupByName parameters: - name: name in: query - description: json as request body + description: Name of the role group to search for required: true schema: type: string responses: '200': - description: list response + description: List of matching role groups content: application/json: schema: - $ref: '#/components/schemas/RoleGroup' + type: array + items: + $ref: '#/components/schemas/RoleGroup' default: description: unexpected error content: @@ -179,32 +231,63 @@ paths: schema: $ref: '#/components/schemas/Error' - /user/role/group/{id}: + /orchestrator/user/role/group/{id}: + get: + summary: Get a role group by ID + description: Get detailed information about a specific role group + operationId: getRoleGroupById + parameters: + - name: id + in: path + description: ID of the role group + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Role group details + content: + application/json: + schema: + $ref: '#/components/schemas/RoleGroup' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' delete: - summary: Deletes a group policy by ID - description: deletes a single group policy based on the ID supplied - operationId: deleteGroupPolicy + summary: Delete a role group + description: Delete a role group by its ID + operationId: deleteRoleGroup parameters: - name: id in: path - description: ID of group policy + description: ID of the role group to delete required: true schema: type: integer format: int64 responses: - '204': - description: group deleted + '200': + description: Role group deleted successfully + content: + application/json: + schema: + type: boolean default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' - /user/role/group/bulk: + + /orchestrator/user/role/group/bulk: delete: - summary: Delete multiple permission groups in bulk - description: Deletes permission groups entities in bulk based on the provided criteria. + summary: Delete multiple role groups + description: Delete multiple role groups in bulk + operationId: bulkDeleteRoleGroups requestBody: required: true content: @@ -213,96 +296,87 @@ paths: $ref: '#/components/schemas/BulkDeleteRequest' responses: '200': - description: Successfully deleted groups + description: Role groups deleted successfully content: application/json: schema: type: boolean - '400': - description: Bad request, invalid input - '404': - description: groups not found - '500': - description: Internal server error + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /orchestrator/user/role/group/detailed/get: + get: + summary: Returns detailed information about all role groups + description: Returns detailed information about all role groups including their permissions + operationId: fetchDetailedRoleGroups + responses: + '200': + description: List of detailed role groups + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/RoleGroup' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: RoleGroup: type: object - required: - - name properties: id: type: integer - description: Unique id of role group + format: int64 name: type: string - description: Unique name of group description: type: string - description: description roleFilters: type: array items: - $ref: '#/components/schemas/roleFilter' - description: role filters objects - + $ref: '#/components/schemas/RoleFilter' + superAdmin: + type: boolean + required: + - name - roleFilter: + RoleFilter: type: object - required: - - action properties: entity: type: string - description: global entity name, i.e chart-group, git, docker, cluster etc. if this key is present than field team, application and environment are ignored. - enum: - - chart-group - - docker - - git - - cluster - - notification team: type: string - description: team name entityName: type: string - description: global entity name item name, i.e chart-group ("abc"), git("devtron-gt") etc. environment: type: string - description: comma saperated environments names. action: type: string - description: action is type of role, i.e manager, admin, trigger, view, etc. accessType: type: string - enum: ["", "helm-app"] - description: accessType difine permission type dawf=devtron app work flow, helm-app=helm app work flow. based on this flag data categoriesed into devtron and helm permission tabs in user auth role group section. - - - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: + cluster: + type: string + namespace: + type: string + group: + type: string + kind: + type: string + resource: + type: string + workflow: type: string - description: Error message - - RoleGroupListingResponse: - type: object - properties: - roleGroups: - items: - $ref: '#/components/schemas/RoleGroup' - description: role groups listing - totalCount: - type: integer - description: total number of results satisfying the conditions BulkDeleteRequest: type: object @@ -311,35 +385,57 @@ components: type: array items: type: integer - format: int32 - description: Array of group IDs to be deleted + format: int64 listingRequest: $ref: '#/components/schemas/ListingRequest' + required: + - ids + ListingRequest: type: object properties: searchKey: type: string - description: Search key for filtering sortOrder: type: string enum: - ASC - DESC - description: Sorting order sortBy: type: string enum: - name - description: Attribute to sort by offset: type: integer - format: int32 - description: Starting index for fetching listings size: type: integer - format: int32 - description: Number of listings to fetch showAll: type: boolean - description: Show all listings \ No newline at end of file + + Error: + type: object + properties: + code: + type: integer + status: + type: string + errors: + type: array + items: + type: object + properties: + code: + type: string + message: + type: string + + RoleGroupListingResponse: + type: object + properties: + roleGroups: + items: + $ref: '#/components/schemas/RoleGroup' + description: role groups listing + totalCount: + type: integer + description: total number of results satisfying the conditions \ No newline at end of file diff --git a/specs/security/roles.yaml b/specs/security/roles.yaml new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/specs/security/roles.yaml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/specs/security/security-dashboard-apis.yml b/specs/security/security-dashboard-apis.yml index acfd97db77..e7bfa7ba88 100644 --- a/specs/security/security-dashboard-apis.yml +++ b/specs/security/security-dashboard-apis.yml @@ -1,11 +1,11 @@ openapi: '3.0.2' info: - title: API Title + title: Security Scan API version: '1.0' servers: - url: https://api.server.test/v1 paths: - /security/scan/executionDetail: + /orchestrator/security/scan/executionDetail: get: summary: fetch image scan execution result, by multiple ways for different use case description: params are option but at least one is required diff --git a/specs/security/security-policy.yml b/specs/security/security-policy.yml index 18c3b716ec..30606e0b6e 100644 --- a/specs/security/security-policy.yml +++ b/specs/security/security-policy.yml @@ -1,11 +1,11 @@ openapi: '3.0.2' info: - title: API Title + title: Security Policy Management version: '1.0' servers: - url: http://localhost:3000/orchestrator paths: - /security/cve/control/list: + /orchestrator/security/cve/control/list: get: description: Fetch current security policy for global, cluster, environment and application level. operationId: FetchPolicy diff --git a/specs/security/user-management.yaml b/specs/security/user-management.yaml new file mode 100644 index 0000000000..1a41245fd4 --- /dev/null +++ b/specs/security/user-management.yaml @@ -0,0 +1,416 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: User Management API + description: Devtron API for user management + termsOfService: https://devtron.ai/terms/ + contact: + name: Devtron Labs + email: support@devtron.ai + url: https://devtron.ai + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://localhost:8080 +paths: + /orchestrator/user/v2: + get: + description: Get all users with filters + parameters: + - name: searchKey + in: query + description: Search key for user listing + required: false + schema: + type: string + - name: sortOrder + in: query + description: Sorting order (ASC or DESC) + required: false + schema: + type: string + enum: [ASC, DESC] + - name: sortBy + in: query + description: Sorting by email_id or last_login + required: false + schema: + type: string + enum: [email_id, last_login] + - name: offset + in: query + description: Offset for paginating the results + required: false + schema: + type: integer + - name: size + in: query + description: Size of the result set + required: false + schema: + type: integer + - name: showAll + in: query + description: Show all users (boolean) + required: false + schema: + type: boolean + responses: + '200': + description: List of users + content: + application/json: + schema: + $ref: '#/components/schemas/UserListingResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user: + post: + description: Create a new user + requestBody: + description: User details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/User' + responses: + '200': + description: User created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + description: Update an existing user + requestBody: + description: Updated user details + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/User' + responses: + '200': + description: User updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user/{id}: + get: + description: Get user details by ID + parameters: + - name: id + in: path + required: true + schema: + type: integer + description: User ID + responses: + '200': + description: User details + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + delete: + description: Delete a user + parameters: + - name: id + in: path + required: true + schema: + type: integer + description: User ID + responses: + '200': + description: User deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestrator/user/bulk: + delete: + description: Delete multiple users in bulk + requestBody: + description: List of user IDs to delete + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkDeleteRequest' + responses: + '200': + description: Users deleted successfully + content: + application/json: + schema: + type: boolean + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + User: + type: object + required: + - email_id + properties: + id: + type: integer + description: Unique ID of user + email_id: + type: string + description: Unique valid email ID of user + userRoleGroups: + type: array + items: + $ref: '#/components/schemas/UserRoleGroup' + roleFilters: + type: array + items: + $ref: '#/components/schemas/RoleFilter' + description: Role filters objects + createdOn: + type: string + format: date-time + description: Creation timestamp + createdBy: + type: string + description: Creator's name + updatedOn: + type: string + format: date-time + description: Last update timestamp + updatedBy: + type: string + description: Last updater's name + + UserRoleGroup: + type: object + properties: + id: + type: integer + description: Role group ID + name: + type: string + description: Role group name + description: + type: string + description: Role group description + createdOn: + type: string + format: date-time + description: Creation timestamp + createdBy: + type: string + description: Creator's name + updatedOn: + type: string + format: date-time + description: Last update timestamp + updatedBy: + type: string + description: Last updater's name + + RoleFilter: + type: object + properties: + entity: + type: string + description: Entity type (e.g. app, env, cluster) + entityName: + type: string + description: Entity name + action: + type: string + description: Action type (e.g. create, update, delete) + accessType: + type: string + description: Access type (e.g. admin, manager, viewer) + team: + type: string + description: Team name + environment: + type: string + description: Environment name + cluster: + type: string + description: Cluster name + + UserListingResponse: + type: object + properties: + users: + type: array + items: + $ref: '#/components/schemas/User' + description: List of users + totalCount: + type: integer + description: Total number of users + + BulkDeleteRequest: + type: object + required: + - ids + properties: + ids: + type: array + items: + type: integer + description: List of user IDs to delete + loggedInUserId: + type: integer + description: ID of the user performing the deletion + + ErrorResponse: + required: + - code + - message + properties: + code: + type: integer + description: Error code + message: + type: string + description: Error message \ No newline at end of file diff --git a/specs/swagger/openapi.html b/specs/swagger/openapi.html deleted file mode 100644 index c1512dd32b..0000000000 --- a/specs/swagger/openapi.html +++ /dev/null @@ -1,1547 +0,0 @@ - - - - - - Common Devtron automation APIs - - - - - - - - - -

Common Devtron automation APIs (1.0.0)

Download OpenAPI specification:

Labels

List Application Labels

Retrieves a list of application labels. By default, returns all labels. -Use the showPropagatedOnly parameter to filter for labels where propagate = true.

-

Required Token Permission:

-
    -
  • Must have View access to the applications in scope.
  • -
-
Authorizations:
bearerAuthapiKeyAuth
query Parameters
showPropagatedOnly
boolean
Default: false

If true, only returns labels where propagate = true. -If false or not provided, all labels are returned.

-

Responses

Response samples

Content type
application/json
Example

Example response when showPropagatedOnly is false or not provided

-
{
  • "code": 200,
  • "status": "OK",
  • "result": [
    ]
}

BulkGetData

Get Readme for Bulk Update

Returns Readme for bulk update for different resource in the url

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
apiVersion
required
string
kind
required
string

Responses

Response samples

Content type
application/json
{
  • "resource": "string",
  • "script": {
    },
  • "readMe": "string"
}

Dry Run for Bulk Application Update

Returns details(id, name, envId) of all apps to be impacted with bulk update

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information by which apps will be filtered

-
apiVersion
string

Api version from url

-
kind
string

Kind

-
object (BulkUpdatePayload)

Responses

Request samples

Content type
application/json
{
  • "apiVersion": [
    ],
  • "kind": [
    ],
  • "spec": {
    }
}

Response samples

Content type
application/json
[
  • {
    }
]

BulkUpdate

Bulk Hibernate Applications

Bulk Hibernates applications

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information about applications and environments to hibernate.

-
object (NameIncludesExcludes)
object (NameIncludesExcludes)
envIds
Array of integers

All Env Id's for the bulk action

-
appIds
Array of integers

All App Id's for the bulk action (alternative to includes/excludes by name)

-
projectIds
Array of integers

All Project Id's for the bulk action

-

Responses

Request samples

Content type
application/json
{
  • "includes": {
    },
  • "excludes": {
    },
  • "envIds": [
    ],
  • "appIds": [
    ],
  • "projectIds": [
    ]
}

Response samples

Content type
application/json
{
  • "message": [
    ],
  • "failure": [
    ],
  • "successful": [
    ]
}

Bulk Un-Hibernate Applications

Bulk Un-Hibernates applications

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information about applications and environments to un-hibernate.

-
object (NameIncludesExcludes)
object (NameIncludesExcludes)
envIds
Array of integers

All Env Id's for the bulk action

-
appIds
Array of integers

All App Id's for the bulk action (alternative to includes/excludes by name)

-
projectIds
Array of integers

All Project Id's for the bulk action

-

Responses

Request samples

Content type
application/json
{
  • "includes": {
    },
  • "excludes": {
    },
  • "envIds": [
    ],
  • "appIds": [
    ],
  • "projectIds": [
    ]
}

Response samples

Content type
application/json
{
  • "message": [
    ],
  • "failure": [
    ],
  • "successful": [
    ]
}

Bulk Deploy Applications

Bulk Triggers deployment of applications

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information for bulk deployment.

-
object (NameIncludesExcludes)
object (NameIncludesExcludes)
envIds
required
Array of integers

All Env Id's for the bulk deployment

-
appIds
Array of integers

All App Id's for the bulk deployment (alternative to includes/excludes by name)

-
projectIds
Array of integers

All Project Id's for the bulk deployment

-
artifactId
integer

ID of the CI artifact to be deployed

-
releaseId
integer

ID of the release to be deployed

-
deploymentStrategy
string

Deployment strategy to use (e.g., blue-green, canary, recreate)

-

Responses

Request samples

Content type
application/json
{
  • "includes": {
    },
  • "excludes": {
    },
  • "envIds": [
    ],
  • "appIds": [
    ],
  • "projectIds": [
    ],
  • "artifactId": 0,
  • "releaseId": 0,
  • "deploymentStrategy": "string"
}

Response samples

Content type
application/json
{
  • "message": [
    ],
  • "failure": [
    ],
  • "successful": [
    ]
}

Bulk Trigger Application Builds

Bulk Triggers build of applications

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information for bulk build trigger.

-
object (NameIncludesExcludes)
object (NameIncludesExcludes)
appIds
Array of integers

All App Id's for the bulk build trigger (alternative to includes/excludes by name)

-
projectIds
Array of integers

All Project Id's for the bulk build trigger

-
ciPipelineId
required
integer

ID of the CI pipeline to trigger builds for

-

Responses

Request samples

Content type
application/json
{
  • "includes": {
    },
  • "excludes": {
    },
  • "appIds": [
    ],
  • "projectIds": [
    ],
  • "ciPipelineId": 0
}

Response samples

Content type
application/json
{
  • "message": [
    ],
  • "failure": [
    ],
  • "successful": [
    ]
}

Bulk Edit Applications

Bulk Updates (Edit) all impacted apps. This endpoint can be used for bulk editing application configurations like deployment templates, configmaps, and secrets.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing information about update changes and by which apps will be filtered for bulk editing.

-
apiVersion
string

Api version from url

-
kind
string

Kind

-
object (BulkUpdatePayload)

Responses

Request samples

Content type
application/json
{
  • "apiVersion": [
    ],
  • "kind": [
    ],
  • "spec": {
    }
}

Response samples

Content type
application/json
{
  • "deploymentTemplate": {
    },
  • "configMap": {
    },
  • "secret": {
    }
}

SSO Configuration

Manage Single Sign-On (SSO) provider configurations.

-

Create SSO Login Configuration

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

SSO Login Configuration object

-
name
required
string
label
string or null
url
required
string or null <url>
config
required
object

Configuration for the SSO provider (Dex connector config). Structure varies.

-
active
required
boolean

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

Update SSO Login Configuration

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

SSO Login Configuration object

-
name
required
string
label
string or null
url
required
string or null <url>
config
required
object

Configuration for the SSO provider (Dex connector config). Structure varies.

-
active
required
boolean

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

Get All SSO Login Configurations

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get SSO Login Configuration by ID

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

Get SSO Login Configuration by Name

Authorizations:
bearerAuthapiKeyAuth
query Parameters
name
required
string

Name of the SSO configuration.

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "label": "string",
  • "url": "string",
  • "config": { },
  • "active": true
}

User Management

Operations related to user accounts (CRUD, listing, bulk actions).

-

List Users (V2 - Paginated, Filtered)

Authorizations:
bearerAuthapiKeyAuth
query Parameters
searchKey
string

Search term.

-
sortOrder
string
Enum: "ASC" "DESC"

Sort order (ASC or DESC).

-
sortBy
string
Enum: "email_id" "last_login"

Field to sort users by (e.g., email_id, last_login).

-
offset
integer <int32> >= 0

Offset for pagination.

-
size
integer <int32> >= 1
Default: 20

Number of items per page.

-

Responses

Response samples

Content type
application/json
{
  • "users": [
    ],
  • "totalCount": 0
}

Create User (V2)

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

User Information object

-
id
integer <int32>

User ID. Should not be set for new user creation if auto-generated. Not allowed to be system-admin-userid (1 or 2) by validation.

-
email_id
required
string <email>

User's email address. Cannot be system admin user email by validation.

-
roles
Array of strings or null

List of direct roles assigned to the user (deprecated in favor of roleFilters and userRoleGroups).

-
Array of objects (RoleFilter)
groups
Array of strings or null

Deprecated field for user groups. Use userRoleGroups instead.

-
Array of objects or null (UserRoleGroup)
superAdmin
boolean

Indicates if the user has super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

Update User (V2)

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

User Information object

-
id
integer <int32>

User ID. Should not be set for new user creation if auto-generated. Not allowed to be system-admin-userid (1 or 2) by validation.

-
email_id
required
string <email>

User's email address. Cannot be system admin user email by validation.

-
roles
Array of strings or null

List of direct roles assigned to the user (deprecated in favor of roleFilters and userRoleGroups).

-
Array of objects (RoleFilter)
groups
Array of strings or null

Deprecated field for user groups. Use userRoleGroups instead.

-
Array of objects or null (UserRoleGroup)
superAdmin
boolean

Indicates if the user has super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

List All Users (V1)

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create User

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

User Information object

-
id
integer <int32>

User ID. Should not be set for new user creation if auto-generated. Not allowed to be system-admin-userid (1 or 2) by validation.

-
email_id
required
string <email>

User's email address. Cannot be system admin user email by validation.

-
roles
Array of strings or null

List of direct roles assigned to the user (deprecated in favor of roleFilters and userRoleGroups).

-
Array of objects (RoleFilter)
groups
Array of strings or null

Deprecated field for user groups. Use userRoleGroups instead.

-
Array of objects or null (UserRoleGroup)
superAdmin
boolean

Indicates if the user has super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

Update User

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

User Information object

-
id
integer <int32>

User ID. Should not be set for new user creation if auto-generated. Not allowed to be system-admin-userid (1 or 2) by validation.

-
email_id
required
string <email>

User's email address. Cannot be system admin user email by validation.

-
roles
Array of strings or null

List of direct roles assigned to the user (deprecated in favor of roleFilters and userRoleGroups).

-
Array of objects (RoleFilter)
groups
Array of strings or null

Deprecated field for user groups. Use userRoleGroups instead.

-
Array of objects or null (UserRoleGroup)
superAdmin
boolean

Indicates if the user has super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

Get User by ID

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

Delete User by ID

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "success": true
}

Get User by ID (V2)

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "email_id": "user@example.com",
  • "roles": [
    ],
  • "accessToken": "string",
  • "roleFilters": [
    ],
  • "groups": [
    ],
  • "userRoleGroups": [
    ],
  • "superAdmin": true,
  • "lastLoginTime": "2019-08-24T14:15:22Z"
}

Bulk Delete Users

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "success": true
}

List All Detailed Users

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Role Group Management

Operations related to user role groups (CRUD, listing, bulk actions).

-

List Role Groups (V2 - Paginated, Filtered)

Authorizations:
bearerAuthapiKeyAuth
query Parameters
searchKey
string

Search term.

-
sortOrder
string
Enum: "ASC" "DESC"

Sort order (ASC or DESC).

-
sortBy
string
Value: "name"

Field to sort role groups by (e.g., name).

-
offset
integer <int32> >= 0

Offset for pagination.

-
size
integer <int32> >= 1
Default: 20

Number of items per page.

-

Responses

Response samples

Content type
application/json
{
  • "roleGroups": [
    ],
  • "totalCount": 0
}

Create Role Group (V2)

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Role Group object

-
name
required
string
description
string or null
required
Array of objects (RoleFilter)
superAdmin
boolean

Indicates if this role group grants super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Update Role Group (V2)

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Role Group object

-
name
required
string
description
string or null
required
Array of objects (RoleFilter)
superAdmin
boolean

Indicates if this role group grants super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

List All Role Groups (V1)

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create Role Group

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Role Group object

-
name
required
string
description
string or null
required
Array of objects (RoleFilter)
superAdmin
boolean

Indicates if this role group grants super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Update Role Group

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Role Group object

-
name
required
string
description
string or null
required
Array of objects (RoleFilter)
superAdmin
boolean

Indicates if this role group grants super admin privileges.

-

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Get Role Group by ID

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Delete Role Group by ID

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "success": true
}

Get Role Group by ID (V2)

Authorizations:
bearerAuthapiKeyAuth
path Parameters
id
required
integer <int32>

Identifier (typically integer ID).

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

List All Detailed Role Groups

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "roleGroups": [
    ],
  • "totalCount": 0
}

Search Role Groups by Name

Authorizations:
bearerAuthapiKeyAuth
query Parameters
name
required
string

Name of the role group to search for.

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "description": "string",
  • "roleFilters": [
    ],
  • "superAdmin": true
}

Bulk Delete Role Groups

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "success": true
}

RBAC

Operations related to Role-Based Access Control, like fetching default roles.

-

Get All Default Roles

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Authentication

Core authentication endpoints including login, token refresh, and auth verification.

-

User Login

Authenticates a user and returns a session token.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Username and password for login.

-
username
required
string
password
required
string <password>

Responses

Request samples

Content type
application/json
{
  • "username": "admin",
  • "password": "password123"
}

Response samples

Content type
application/json
{
  • "token": "string"
}

Refresh Session Token

Handles token refresh (details depend on OIDC/OAuth flow).

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": { },
  • "errors": [
    ]
}

Verify Authentication Status

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
true

Verify Authentication Status (V2)

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "isSuperAdmin": true,
  • "isVerified": true,
  • "emailId": "string"
}

Check Logged-in User's Roles

Authorizations:
bearerAuthapiKeyAuth
query Parameters
appName
string

Optional application name to filter roles for.

-

Responses

Response samples

Content type
application/json
{
  • "role": "string",
  • "roles": [
    ],
  • "superAdmin": true
}

OIDC Login Redirect (Informational)

Initiates OIDC login flow. Handled by the OIDC client library.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

OIDC Login Redirect (Informational - Alternate Path)

Initiates OIDC login flow. Handled by the OIDC client library.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

OIDC Callback (Informational)

Handles the callback from the OIDC provider. Handled by the OIDC client library.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Dex Proxy (Informational)

Proxies requests to the Dex IdP. Handled by the Dex proxy mechanism.

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
path
required
string

Path to be proxied to Dex.

-

Responses

Policy Management

Endpoints for managing policies.

-

Add Default Policy and Roles

Creates default policies and roles based on team, app, and environment. This is a specialized endpoint.

-
Authorizations:
bearerAuthapiKeyAuth
query Parameters
team
required
string
app
required
string
env
required
string

Responses

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": { },
  • "errors": [
    ]
}

Sync Orchestrator to Casbin

Synchronizes policies from orchestrator to Casbin. Requires admin privileges.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
true

Update Trigger Policy for Terminal Access

Updates trigger policies related to terminal access. Requires global update privileges.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
"string"

Cache Management

Endpoints for managing authentication and authorization caches.

-

Get Role Cache Dump

Retrieves a dump of the role cache. Requires super admin privileges.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{ }

Invalidate Role Cache

Clears the role cache. Requires super admin privileges.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
"string"

Cluster Environment

Operations related to clusters and environments

-

List clusters with their environments

Provides a list of all clusters and the environments within each.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List environments for a specific cluster

Provides a list of all environments for a given cluster ID.

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
cluster_id
required
integer

ID of the cluster

-

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Cluster Management

Operations related to cluster creation, update, and validation

-

Delete Cluster

Delete an existing cluster.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing the cluster config (primarily ID is used for deletion)

-
id
integer
cluster_name
string
server_url
string
prometheus_url
string
active
boolean
object
object (PrometheusAuthGet)
Array of objects (DefaultClusterComponentGet)
k8sversion
string

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "cluster_name": "string",
  • "server_url": "string",
  • "prometheus_url": "string",
  • "active": true,
  • "config": {
    },
  • "prometheusAuth": {
    },
  • "defaultClusterComponents": [
    ],
  • "k8sversion": "string"
}

Response samples

Content type
application/json
{
  • "message": "Cluster deleted successfully."
}

Update Cluster

Update an existing cluster's configuration.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing the cluster config

-
id
integer
cluster_name
string
server_url
string
prometheus_url
string
active
boolean
object
object (PrometheusAuthGet)
Array of objects (DefaultClusterComponentGet)
k8sversion
string

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "cluster_name": "string",
  • "server_url": "string",
  • "prometheus_url": "string",
  • "active": true,
  • "config": {
    },
  • "prometheusAuth": {
    },
  • "defaultClusterComponents": [
    ],
  • "k8sversion": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "cluster_name": "string",
  • "server_url": "string",
  • "prometheus_url": "string",
  • "active": true,
  • "config": {
    },
  • "prometheusAuth": {
    },
  • "defaultClusterComponents": [
    ],
  • "k8sversion": "string"
}

Get Cluster

Get details of a specific cluster by ID.

-
Authorizations:
bearerAuthapiKeyAuth
query Parameters
id
required
integer

cluster id.

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "cluster_name": "string",
  • "server_url": "string",
  • "prometheus_url": "string",
  • "active": true,
  • "config": {
    },
  • "prometheusAuth": {
    },
  • "defaultClusterComponents": [
    ],
  • "k8sversion": "string"
}

List Accessible Clusters

list of clusters accessible to the authenticated user.

-
Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": [
    ]
}

Validate Cluster Configuration

Validate a cluster configuration using kubeconfig.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required
object (Kubeconfig)

Responses

Request samples

Content type
application/json
{
  • "kubeconfig": {
    }
}

Response samples

Content type
application/json
{
  • "userInfos": {
    },
  • "id": 0,
  • "cluster_name": "string",
  • "server_url": "string",
  • "prometheus_url": "string",
  • "active": true,
  • "config": {
    },
  • "prometheusAuth": {
    },
  • "defaultClusterComponent": [
    ],
  • "agentInstallationStage": 0,
  • "k8sVersion": "string",
  • "userName": "string",
  • "insecure-skip-tls-verify": true
}

Save Multiple Clusters

Save configurations for multiple clusters.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
Array
object
id
integer
cluster_name
required
string
server_url
required
string
prometheus_url
string
active
boolean
object
object (PrometheusAuthAdd)
Array of objects (DefaultClusterComponentAdd)
agentInstallationStage
integer
k8sVersion
string
userName
string
insecure-skip-tls-verify
boolean

Responses

Request samples

Content type
application/json
[
  • {
    }
]

Response samples

Content type
application/json
[
  • {
    }
]

Environment Management

Operations for creating, updating, and deleting environments

-

Create Environment

Create a new environment within a cluster.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Environment details

-
environment_name
required
string <= 50 characters
cluster_id
required
integer
active
boolean
Default: true
default
boolean
Default: false
prometheus_endpoint
string
namespace
string <= 50 characters
isClusterCdActive
boolean
description
string <= 40 characters
isVirtualEnvironment
boolean
Default: false
allowedDeploymentTypes
Array of strings
Items Enum: "helm" "argo_cd"

Responses

Request samples

Content type
application/json
{
  • "environment_name": "string",
  • "cluster_id": 0,
  • "active": true,
  • "default": false,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "description": "string",
  • "isVirtualEnvironment": false,
  • "allowedDeploymentTypes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "environment_name": "string",
  • "cluster_id": 0,
  • "cluster_name": "string",
  • "active": true,
  • "default": true,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "environmentIdentifier": "string",
  • "description": "string",
  • "appCount": 0,
  • "isVirtualEnvironment": true,
  • "allowedDeploymentTypes": [
    ]
}

Update Environment

Update an existing environment.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

Environment details to update

-
id
required
integer
environment_name
required
string <= 50 characters
cluster_id
required
integer
active
boolean
default
boolean
prometheus_endpoint
string
namespace
string <= 50 characters
isClusterCdActive
boolean
description
string <= 40 characters
isVirtualEnvironment
boolean
allowedDeploymentTypes
Array of strings
Items Enum: "helm" "argo_cd"

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "environment_name": "string",
  • "cluster_id": 0,
  • "active": true,
  • "default": true,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "description": "string",
  • "isVirtualEnvironment": true,
  • "allowedDeploymentTypes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "environment_name": "string",
  • "cluster_id": 0,
  • "cluster_name": "string",
  • "active": true,
  • "default": true,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "environmentIdentifier": "string",
  • "description": "string",
  • "appCount": 0,
  • "isVirtualEnvironment": true,
  • "allowedDeploymentTypes": [
    ]
}

Get Environment by ID

Get detailed information for a specific environment by its ID.

-
Authorizations:
bearerAuthapiKeyAuth
query Parameters
id
required
integer

ID of the environment

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "environment_name": "string",
  • "cluster_id": 0,
  • "cluster_name": "string",
  • "active": true,
  • "default": true,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "environmentIdentifier": "string",
  • "description": "string",
  • "appCount": 0,
  • "isVirtualEnvironment": true,
  • "allowedDeploymentTypes": [
    ]
}

Delete Environment (via POST)

Delete an existing environment using POST method.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing the env config (primarily ID is used for deletion)

-
id
integer
environment_name
string
cluster_id
integer
cluster_name
string
active
boolean
default
boolean
prometheus_endpoint
string
namespace
string
isClusterCdActive
boolean
environmentIdentifier
string
description
string
appCount
integer
isVirtualEnvironment
boolean
allowedDeploymentTypes
Array of strings
Items Enum: "helm" "argo_cd"

Responses

Request samples

Content type
application/json
{
  • "id": 0,
  • "environment_name": "string",
  • "cluster_id": 0,
  • "cluster_name": "string",
  • "active": true,
  • "default": true,
  • "prometheus_endpoint": "string",
  • "namespace": "string",
  • "isClusterCdActive": true,
  • "environmentIdentifier": "string",
  • "description": "string",
  • "appCount": 0,
  • "isVirtualEnvironment": true,
  • "allowedDeploymentTypes": [
    ]
}

Response samples

Content type
application/json
{
  • "message": "Environment deleted successfully."
}

ChangeChartType

Patch Application Environment

change the deployment template for an app and environment

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
envId
integer
appId
integer
targetChartRefId
integer

Responses

Request samples

Content type
application/json
{
  • "envId": 0,
  • "appId": 0,
  • "targetChartRefId": 0
}

CloneWorkflow (ENT)

Clone Application Workflow

Clones an application workflow from a source environment to a target environment

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

A JSON object containing the details required to clone the workflow

-
appId
integer

ID of the application

-
appName
string

Name of the application

-
sourceEnvironmentId
integer

ID of the source environment

-
sourceEnvironmentName
string

Name of the source environment

-
targetEnvironmentId
integer

ID of the target environment

-
targetEnvironmentName
string

Name of the target environment

-
cloneEnvInSameWorkflow
boolean

Flag indicating if the environment should be cloned in the same workflow

-

Responses

Request samples

Content type
application/json
{
  • "appId": 0,
  • "appName": "string",
  • "sourceEnvironmentId": 0,
  • "sourceEnvironmentName": "string",
  • "targetEnvironmentId": 0,
  • "targetEnvironmentName": "string",
  • "cloneEnvInSameWorkflow": true
}

Response samples

Content type
application/json
{
  • "code": 200,
  • "status": "OK",
  • "result": {
    }
}

K8s Resource

APIs for managing Kubernetes resources (get, create, update, delete, list).

-

Get Resource Manifest

This API is used for fetching the manifest of a specified Kubernetes resource.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload specifying the resource to fetch.

-
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": {
    }
}

Update Resource Manifest

This API is used for editing the manifest of a specified Kubernetes resource.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload containing the resource identifier and the patch.

-
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": {
    }
}

Create Resource

This API is used for applying a desired manifest to create a Kubernetes resource.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload containing the resource manifest to apply.

-
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": {
    }
}

Delete Resource

This API is used for deleting a specified Kubernetes resource.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload specifying the resource to delete.

-
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": {
    }
}

Get Resource Events

This API is used for fetching events for Kubernetes resources.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
optional
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Get Pod Logs

This API is used for fetching logs for a specified container within a pod.

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
podName
required
string

Name of the pod.

-
query Parameters
containerName
required
string

Name of the container within the pod.

-
appId
string

Application ID.

-
clusterId
integer

Cluster ID.

-
namespace
string

Namespace of the pod. Required if clusterId is passed.

-
follow
boolean
Default: false

Whether to follow the log stream.

-
sinceSeconds
integer

Return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs.

-
tailLines
integer

If set, the number of lines from the end of the logs to show.

-

Responses

Get Pod Exec Session

This API establishes a session for executing commands in a pod's container (terminal access).

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
identifier
required
string

Application ID or Cluster ID. Example '2|devtroncd|devtron' or '3'.

-
namespace
required
string
Example: devtroncd

Namespace of the pod.

-
pod
required
string
Example: inception-58d44d99fd-tfw4s

Name of the pod.

-
shell
required
string
Enum: "bash" "sh" "powershell" "cmd"
Example: bash

Shell to invoke.

-
container
required
string
Example: devtron

Name of the container.

-

Responses

Response samples

Content type
application/json
{
  • "Op": "stdin",
  • "Data": "ls -l",
  • "SessionID": "unique-session-id-123"
}

Get API Resources

Get all available API resources for a given cluster ID.

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
clusterId
required
integer <int64>

ID of the cluster.

-

Responses

Response samples

Content type
application/json
{
  • "apiResources": [
    ],
  • "allowedAll": true
}

List Resources

This API is used for fetching a list of Kubernetes resources based on the request criteria.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload specifying the criteria for listing resources.

-
appId
string

Application ID. Used when the request is context-specific to an application.

-
clusterId
number

Cluster ID. Used when the request is for a direct cluster resource (appId is not supplied).

-
object (K8sRequestObject)

Responses

Request samples

Content type
application/json
{
  • "appId": "my-app/env-1",
  • "clusterId": 1,
  • "k8sRequest": {
    }
}

Response samples

Content type
application/json
{
  • "code": 0,
  • "status": "string",
  • "result": [
    ]
}

Rotates the Pods

This API is used to rotate (restart) pods for the provided resources.

-
Authorizations:
bearerAuthapiKeyAuth
query Parameters
appId
required
string

Application ID.

-
Request Body schema: application/json
required

JSON payload specifying the resources for which pods should be rotated.

-
clusterId
required
number

ID of the cluster where resources reside.

-
required
Array of objects

Responses

Request samples

Content type
application/json
{
  • "clusterId": 1,
  • "resources": [
    ]
}

Response samples

Content type
application/json
{
  • "containsError": false,
  • "responses": [
    ]
}

Apply Resources

This API is used to apply (create or update) Kubernetes resources in a cluster.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required

JSON payload containing the manifest of resources to apply.

-
clusterId
required
number

ID of the cluster where resources will be applied.

-
manifest
required
string

A string containing one or more Kubernetes resource manifests, separated by '---'.

-

Responses

Request samples

Content type
application/json
{
  • "clusterId": 1,
  • "manifest": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: my-cm\ndata:\n key: value\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-app\nspec:\n replicas: 1\n selector:\n matchLabels:\n app: my-app\n template:\n metadata:\n labels:\n app: my-app\n spec:\n containers:\n - name: nginx\n image: nginx\n"
}

Response samples

Content type
application/json
[
  • {
    }
]

Workflow Management

Create an application workflow

Creates a new workflow for a given application.

-
Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required
name
string

Name of the workflow.

-
appId
integer

ID of the application this workflow belongs to.

-
Array of objects (AppWorkflowMappingDto)

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "appId": 0,
  • "tree": [
    ]
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "name": "string",
  • "appId": 0,
  • "tree": [
    ]
}

Delete an application workflow

Deletes an existing workflow for a given application.

-
Authorizations:
bearerAuthapiKeyAuth
path Parameters
app-wf-id
required
integer

ID of the application workflow to delete.

-
app-id
required
integer

ID of the application.

-

Responses

Response samples

Content type
application/json
{
  • "status": "OK"
}
- - - - diff --git a/specs/swagger/openapi.yaml b/specs/swagger/openapi.yaml deleted file mode 100644 index 9928580eff..0000000000 --- a/specs/swagger/openapi.yaml +++ /dev/null @@ -1,6524 +0,0 @@ -openapi: 3.0.0 -info: - version: 1.0.0 - title: Devtron APIs Specs - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: -- url: http://localhost/orchestrator - description: Local development server -tags: -- name: Metadata - description: Application metadata and information retrieval - x-displayName: Application Metadata -- name: Jobs - description: Job management operations for creating, cloning, and retrieving jobs - x-displayName: Job Management -- name: Helm Charts - description: Helm chart deployment management and operations - x-displayName: Helm Chart Management -- name: List Applications - x-displayName: List Applications - description: Application listing -- name: Applications - description: Application management operations including creation, listing, and - updates - x-displayName: Application Management -- name: Labels - x-displayName: Labels -- name: bulk_other - x-displayName: BulkGetData -- name: BulkUpdate - x-displayName: BulkUpdate -- name: SSO Configuration - description: Manage Single Sign-On (SSO) provider configurations. - x-displayName: SSO Configuration -- name: User Management - description: Operations related to user accounts (CRUD, listing, bulk actions). - x-displayName: User Management -- name: Role Group Management - description: Operations related to user role groups (CRUD, listing, bulk actions). - x-displayName: Role Group Management -- name: RBAC - description: Operations related to Role-Based Access Control, like fetching default - roles. - x-displayName: RBAC -- name: Authentication - description: Core authentication endpoints including login, token refresh, and auth - verification. - x-displayName: Authentication -- name: Policy Management - description: Endpoints for managing policies. - x-displayName: Policy Management -- name: Cache Management - description: Endpoints for managing authentication and authorization caches. - x-displayName: Cache Management -- name: Cluster Environment - description: Operations related to clusters and environments - x-displayName: Cluster Environment -- name: Cluster Management - description: Operations related to cluster creation, update, and validation - x-displayName: Cluster Management -- name: Environment Management - description: Operations for creating, updating, and deleting environments - x-displayName: Environment Management -- name: Change Chart - x-displayName: ChangeChartType -- name: Clone Workflow - x-displayName: CloneWorkflow (ENT) -- name: Deployment History - x-displayName: Get Deployment History (ENT) - description: Retrieves the deployment history for a specific CD pipeline based on - various filter criteria. -- name: K8s Resource - description: APIs for managing Kubernetes resources (get, create, update, delete, - list). - x-displayName: K8s Resource -- name: Workflow Management - x-displayName: Workflow Management -- name: Notifications - x-displayName: Notifiactions -- name: Devtron Server version - x-displayName: Devtron Server version -- name: GitOps Validation - x-displayName: GitOps Validation -paths: - /resource/history/deployment/cd-pipeline/v1: - get: - summary: Get Deployment History - description: Retrieves the deployment history for a specific CD pipeline based - on various filter criteria. - operationId: getDeploymentHistory - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: filterCriteria - in: query - required: true - schema: - type: array - items: - type: string - description: 'Filter criteria for deployment history. Example: - - - application/devtron-application|id|1064 - - - environment|id|146 - - - release|id|203 - - ' - - name: offset - in: query - required: false - schema: - type: integer - description: The starting point for fetching records (pagination). - - name: limit - in: query - required: false - schema: - type: integer - description: The number of records to return (pagination). - responses: - '200': - description: Successful retrieval of deployment history. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - example: 200 - status: - type: string - example: OK - result: - type: object - properties: - cdWorkflows: - type: array - items: - type: object - properties: - id: - type: integer - example: 19767 - cd_workflow_id: - type: integer - example: 19576 - name: - type: string - example: cd-1064-nu4s - status: - type: string - example: Succeeded - pod_status: - type: string - example: '' - message: - type: string - example: '' - started_on: - type: string - format: date-time - example: '2024-07-25T08:36:42.414376Z' - finished_on: - type: string - format: date-time - example: '2024-07-25T08:40:03.455303Z' - pipeline_id: - type: integer - example: 2082 - namespace: - type: string - example: devtron-cd - log_file_path: - type: string - example: '' - triggered_by: - type: integer - example: 23 - email_id: - type: string - example: deepak@devtron.ai - image: - type: string - example: devtroninc.azurecr.io/test:8a0c2298-fc94fa4b-956-18655 - ci_artifact_id: - type: integer - example: 14593 - workflow_type: - type: string - example: DEPLOY - blobStorageEnabled: - type: boolean - example: true - userApprovalMetadata: - type: object - nullable: true - gitTriggers: - type: object - additionalProperties: - type: object - properties: - Commit: - type: string - example: 8a0c22983ae7acae10abe7569026ae25d889e159 - Author: - type: string - example: jatin-jangir-0220 <122791251+jatin-jangir-0220@users.noreply.github.com> - Date: - type: string - format: date-time - example: '2024-04-29T18:49:39Z' - Message: - type: string - example: 'Update Dockerfile (#19) - - - ' - Changes: - type: string - nullable: true - WebhookData: - type: object - properties: - id: - type: integer - example: 0 - eventActionType: - type: string - example: '' - data: - type: string - nullable: true - CiConfigureSourceValue: - type: string - example: main - GitRepoUrl: - type: string - example: https://github.com/devtron-labs/casbin-enterprise - GitRepoName: - type: string - example: casbin-enterprise - CiConfigureSourceType: - type: string - example: SOURCE_TYPE_BRANCH_FIXED - ciMaterials: - type: array - items: - type: object - properties: - id: - type: integer - example: 1013 - gitMaterialId: - type: integer - example: 411 - gitMaterialUrl: - type: string - example: '' - gitMaterialName: - type: string - example: casbin-enterprise - type: - type: string - example: SOURCE_TYPE_BRANCH_FIXED - value: - type: string - example: main - active: - type: boolean - example: true - lastFetchTime: - type: string - format: date-time - example: '0001-01-01T00:00:00Z' - isRepoError: - type: boolean - example: false - repoErrorMsg: - type: string - example: '' - isBranchError: - type: boolean - example: false - branchErrorMsg: - type: string - example: '' - url: - type: string - example: https://github.com/devtron-labs/casbin-enterprise - regex: - type: string - example: '' - tagsEditable: - type: boolean - example: false - appReleaseTagNames: - type: array - items: - type: string - example: [] - hideImageTaggingHardDelete: - type: boolean - example: false - examples: - example-1: - value: - code: 200 - status: OK - result: - cdWorkflows: - - id: 19752 - cd_workflow_id: 19561 - name: cd-1064-nu4s - status: Failed - pod_status: '' - message: 'Unable to continue with install: could not get information - about the resource Job "" in namespace "devtroncd": resource - name may not be empty' - started_on: '2024-07-25T08:26:21.792068Z' - finished_on: '2024-07-25T08:26:23.855384Z' - pipeline_id: 2082 - namespace: devtron-cd - log_file_path: '' - triggered_by: 23 - email_id: deepak@devtron.ai - image: devtroninc.azurecr.io/test:8a0c2298-fc94fa4b-956-18655 - ci_artifact_id: 14593 - workflow_type: DEPLOY - blobStorageEnabled: true - userApprovalMetadata: null - gitTriggers: - '1013': - Commit: 8a0c22983ae7acae10abe7569026ae25d889e159 - Author: jatin-jangir-0220 <122791251+jatin-jangir-0220@users.noreply.github.com> - Date: '2024-04-29T18:49:39Z' - Message: 'Update Dockerfile (#19) - - - ' - Changes: null - WebhookData: - id: 0 - eventActionType: '' - data: null - CiConfigureSourceValue: main - GitRepoUrl: https://github.com/devtron-labs/casbin-enterprise - GitRepoName: casbin-enterprise - CiConfigureSourceType: SOURCE_TYPE_BRANCH_FIXED - '2072': - Commit: fc94fa4bad21460e822ce896b5166273aa3df1a8 - Author: Gireesh Naidu <111440205+gireesh-naidu@users.noreply.github.com> - Date: '2024-07-23T18:13:18+05:30' - Message: "fix: getting 500 while updating the branch of\ - \ linked CI (#1424)\n\n* fix: sync ci pipeline materials\ - \ for linked pipelines\r\n\r\n* fix: sync ci pipeline\ - \ materials for linked pipelines\r\n\r\n* fix: null\ - \ column fix\r\n\r\n* fix: null column fix\r\n\r\n*\ - \ fix: able to delete ci pipeline though it has linked\ - \ ci's using API" - Changes: null - WebhookData: - id: 0 - eventActionType: '' - data: null - CiConfigureSourceValue: main - GitRepoUrl: https://github.com/devtron-labs/devtron-enterprise - GitRepoName: devtron-enterprise - CiConfigureSourceType: SOURCE_TYPE_BRANCH_FIXED - ciMaterials: - - id: 1013 - gitMaterialId: 411 - gitMaterialUrl: '' - gitMaterialName: casbin-enterprise - type: SOURCE_TYPE_BRANCH_FIXED - value: main - active: true - lastFetchTime: '0001-01-01T00:00:00Z' - isRepoError: false - repoErrorMsg: '' - isBranchError: false - branchErrorMsg: '' - url: https://github.com/devtron-labs/casbin-enterprise - regex: '' - - id: 2072 - gitMaterialId: 1286 - gitMaterialUrl: '' - gitMaterialName: devtron-enterprise - type: SOURCE_TYPE_BRANCH_FIXED - value: main - active: true - lastFetchTime: '0001-01-01T00:00:00Z' - isRepoError: false - repoErrorMsg: '' - isBranchError: false - branchErrorMsg: '' - url: https://github.com/devtron-labs/devtron-enterprise - regex: '' - imageReleaseTags: null - imageComment: null - referenceCdWorkflowRunnerId: 0 - appliedFilters: null - appliedFiltersState: 0 - appliedFiltersTimestamp: '0001-01-01T00:00:00Z' - promotionApprovalMetadata: null - runSource: - kind: release - version: alpha1 - id: 203 - identifier: qa-releases-track-0.0.2 - releaseVersion: 0.0.2 - name: deepak-qa-release - releaseTrackName: qa-releases-track - targetConfig: - tenantId: qa-devtroncd-x - tenantName: QA Devtron Env - installationId: qa-devtroncd-2 - installationName: qa-devtroncd-2 - releaseChannelId: beta - releaseChannelName: beta-channel - tags: - - Deployment History - /orchestrator/app/labels/list: - get: - summary: List all app labels - description: This API will return all the labels available in the database. - operationId: listAppLabels - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - responses: - '200': - description: list response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - allOf: - - type: object - properties: - appId: - type: integer - description: unique application id - required: - - appId - - $ref: '#/components/schemas/AppLabel' - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Metadata - /orchestrator/app/meta/info/{appId}: - get: - summary: Get application meta info - description: Application basic info, projects and labels - operationId: getAppMetaInfo - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: path - description: application id - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: application basic info, projects and labels - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: meta info project name and labels - $ref: '#/components/schemas/AppMetaInfo' - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Metadata - /orchestrator/helm/meta/info/{appId}: - get: - summary: Get Helm application meta info - description: Application info for all types of Helm apps - operationId: getHelmAppMetaInfo - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: path - description: application id - required: true - schema: - type: string - responses: - '200': - description: Helm application basic info - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: meta info project name and labels - $ref: '#/components/schemas/AppMetaInfo' - '400': - description: Bad request - '401': - description: Unauthorized - '404': - description: Not found - '500': - description: Internal server error - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Metadata - /orchestrator/job: - post: - summary: Create or clone a job - description: Create and clone a job - operationId: createOrCloneJob - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateJob' - responses: - '200': - description: Used to give response once a job is created - content: - application/json: - schema: - $ref: '#/components/schemas/ActionResponse' - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal server error - tags: - - Jobs - /orchestrator/job/list: - post: - summary: List jobs - description: Get the list of all the jobs by applying filter - operationId: listJobs - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/JobList' - responses: - '200': - description: Used to give response of list of jobs - content: - application/json: - schema: - $ref: '#/components/schemas/JobListResponse' - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal server error - tags: - - Jobs - /orchestrator/job/ci-pipeline/list/{jobId}: - get: - summary: Get job CI pipeline list - description: fetch details of job ci-pipelines for the overview page - operationId: getJobCiPipelineList - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: jobId - in: path - required: true - description: Job Id - schema: - type: integer - responses: - '200': - description: Job CI pipeline list - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal server error - tags: - - Jobs - /orchestrator/app-store/installed-app: - get: - summary: List deployed charts - operationId: listDeployedCharts - description: deployed chart listing, with search filters - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - 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' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Helm Charts - /orchestrator/app-store/installed-app/notes: - get: - summary: Fetch notes.txt for deployed helm charts - operationId: fetchNotesTxt - description: Used to fetch notes.txt for helm charts deployed via gitOps - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: env-id - in: query - description: it is an environment id of app - required: true - schema: - type: integer - - name: installed-app-id - in: query - description: it is a installed application id - required: true - schema: - type: integer - responses: - '200': - description: if it is able to fetch the notes.txt then status will be ok - content: - application/json: - schema: - properties: - notes: - type: string - description: it will provide notes - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - '500': - description: error while fetching notes.txt - tags: - - Helm Charts - /orchestrator/app/autocomplete: - get: - summary: List application autocomplete - operationId: listAppAutocomplete - description: list of namespaces group by clusters - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - in: query - name: appName - example: abc - description: app name, wildcard query - required: false - allowEmptyValue: true - schema: - type: string - - in: query - name: teamId - example: '1' - description: project id - required: false - allowEmptyValue: false - schema: - type: integer - responses: - '200': - description: list response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: array - description: app list - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - List Applications - security: [] - /orchestrator/app: - post: - summary: Create a new application - operationId: createApplication - description: create new application - security: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/App' - responses: - '200': - description: App create response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - allOf: - - type: object - properties: - id: - type: integer - description: unique application id - required: - - id - - $ref: '#/components/schemas/App' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Applications - /orchestrator/app/edit: - post: - summary: Update application projects and labels - operationId: updateApplicationProjectsAndLabels - description: update application projects and labels - security: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/App' - responses: - '200': - description: App update response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - allOf: - - type: object - properties: - id: - type: integer - description: unique application id - required: - - id - - $ref: '#/components/schemas/App' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Applications - /orchestrator/app/list: - post: - summary: List applications - operationId: listApplications - description: app listing, collection of deployed applications or undeployed - or incomplete configured apps. - security: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AppListingRequest' - responses: - '200': - description: App create response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - required: - - appCount - - appContainers - - deploymentGroup - properties: - appCount: - type: integer - description: app count, total number of apps available based - on filter provided in request. - appContainers: - type: array - description: app containers - items: - $ref: '#/components/schemas/AppContainer' - deploymentGroup: - type: object - description: deployment group - $ref: '#/components/schemas/DeploymentGroup' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Applications - /orchestrator/app/edit/projects: - post: - summary: Update project for app - operationId: updateProjectForApp - description: update project for app - security: [] - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AppProjectUpdateRequest' - responses: - '200': - description: App update response - content: - application/json: - schema: - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: object - description: string - $ref: '#/components/schemas/AppProjectUpdateRequest' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - tags: - - Applications - /app/labels/list: - get: - summary: List Application Labels - description: "Retrieves a list of application labels. By default, returns all\ - \ labels. \nUse the `showPropagatedOnly` parameter to filter for labels where\ - \ propagate = true.\n\n**Required Token Permission:**\n- Must have **View**\ - \ access to the applications in scope.\n" - operationId: getAppLabels - tags: - - Labels - security: [] - - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: showPropagatedOnly - in: query - description: "If true, only returns labels where propagate = true. \nIf false\ - \ or not provided, all labels are returned.\n" - required: false - schema: - type: boolean - default: false - example: false - responses: - '200': - description: Successfully retrieved labels list - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: HTTP status code - example: 200 - status: - type: string - description: Response status message - example: OK - result: - type: array - description: Array of label objects - items: - type: object - required: - - key - - value - - propagate - - appId - - appName - properties: - key: - type: string - description: The label key/name - example: environment - value: - type: string - description: The label value - example: production - propagate: - type: boolean - description: Whether this label should be propagated - example: true - appId: - type: integer - description: The unique identifier of the application - example: 1234 - appName: - type: string - description: The name of the application - example: web-service - examples: - all_labels: - summary: All labels response - description: Example response when showPropagatedOnly is false or - not provided - value: - code: 200 - status: OK - result: - - key: environment - value: production - propagate: true - appId: 1234 - appName: web-service - - key: team - value: backend - propagate: false - appId: 1234 - appName: web-service - propagated_only: - summary: Propagated labels only - description: Example response when showPropagatedOnly is true - value: - code: 200 - status: OK - result: - - key: environment - value: production - propagate: true - appId: 1234 - appName: web-service - '401': - description: Authentication required or token invalid - content: - application/json: - schema: - type: object - properties: - code: - type: integer - example: 401 - status: - type: string - example: Unauthorized - message: - type: string - example: Authentication token is required - '403': - description: Insufficient permissions to access the resource - content: - application/json: - schema: - type: object - properties: - code: - type: integer - example: 403 - status: - type: string - example: Forbidden - message: - type: string - example: Token does not have View access to the applications in - scope - '500': - description: Internal server error - content: - application/json: - schema: - type: object - properties: - code: - type: integer - example: 500 - status: - type: string - example: Internal Server Error - message: - type: string - example: An unexpected error occurred - /batch/{apiVersion}/{kind}/readme: - get: - summary: Get Readme for Bulk Update - description: Returns Readme for bulk update for different resource in the url - operationId: FindBulkUpdateReadme - security: [] - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: apiVersion - in: path - required: true - description: apiVersion of the resource - schema: - type: string - - name: kind - in: path - required: true - description: kind of the resource - schema: - type: string - responses: - '200': - description: Successful GET operation - content: - application/json: - schema: - $ref: '#/components/schemas/BulkUpdateSeeExampleResponse' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - tags: - - bulk_other - /batch/v1beta1/application/dryrun: - post: - summary: Dry Run for Bulk Application Update - description: Returns details(id, name, envId) of all apps to be impacted with - bulk update - operationId: GetBulkAppName - security: [] - - requestBody: - description: A JSON object containing information by which apps will be filtered - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkUpdateScript' - responses: - '200': - description: Successfully return all impacted app details. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ImpactedObjectsResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - tags: - - bulk_other - /batch/v1beta1/hibernate: - post: - summary: Bulk Hibernate Applications - description: Bulk Hibernates applications - operationId: BulkHibernate - security: [] - - tags: - - BulkUpdate - requestBody: - description: A JSON object containing information about applications and environments - to hibernate. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionRequest' - responses: - '200': - description: Successfully hibernated applications. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /batch/v1beta1/unhibernate: - post: - summary: Bulk Un-Hibernate Applications - description: Bulk Un-Hibernates applications - operationId: BulkUnHibernate - security: [] - - tags: - - BulkUpdate - requestBody: - description: A JSON object containing information about applications and environments - to un-hibernate. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionRequest' - responses: - '200': - description: Successfully un-hibernated applications. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /batch/v1beta1/deploy: - post: - summary: Bulk Deploy Applications - description: Bulk Triggers deployment of applications - operationId: BulkDeploy - security: [] - - tags: - - BulkUpdate - requestBody: - description: A JSON object containing information for bulk deployment. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkDeployRequest' - responses: - '200': - description: Successfully triggered bulk deployment. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /batch/v1beta1/build: - post: - summary: Bulk Trigger Application Builds - description: Bulk Triggers build of applications - operationId: BulkBuildTrigger - security: [] - - tags: - - BulkUpdate - requestBody: - description: A JSON object containing information for bulk build trigger. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkBuildTriggerRequest' - responses: - '200': - description: Successfully triggered bulk build. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkActionResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /batch/v1beta1/application: - post: - summary: Bulk Edit Applications - description: Bulk Updates (Edit) all impacted apps. This endpoint can be used - for bulk editing application configurations like deployment templates, configmaps, - and secrets. - operationId: BulkUpdate - security: [] - - tags: - - BulkUpdate - requestBody: - description: A JSON object containing information about update changes and - by which apps will be filtered for bulk editing. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkUpdateScript' - responses: - '200': - description: Successfully updated all impacted apps. - content: - application/json: - schema: - $ref: '#/components/schemas/BulkUpdateResponse' - '400': - description: Bad Request. Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /sso/create: - post: - tags: - - SSO Configuration - summary: Create SSO Login Configuration - operationId: CreateSSOLoginConfig - requestBody: - $ref: '#/components/requestBodies/SSOLoginDto' - responses: - '200': - $ref: '#/components/responses/SSOLoginConfigResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /sso/update: - put: - tags: - - SSO Configuration - summary: Update SSO Login Configuration - operationId: UpdateSSOLoginConfig - requestBody: - $ref: '#/components/requestBodies/SSOLoginDto' - responses: - '200': - $ref: '#/components/responses/SSOLoginConfigResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /sso/list: - get: - tags: - - SSO Configuration - summary: Get All SSO Login Configurations - operationId: GetAllSSOLoginConfig - responses: - '200': - description: List of SSO configurations. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/SSOLoginDto' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /sso/{id}: - get: - tags: - - SSO Configuration - summary: Get SSO Login Configuration by ID - operationId: GetSSOLoginConfig - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/SSOLoginConfigResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /sso: - get: - tags: - - SSO Configuration - summary: Get SSO Login Configuration by Name - operationId: GetSSOLoginConfigByName - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: name - in: query - required: true - description: Name of the SSO configuration. - schema: - type: string - responses: - '200': - $ref: '#/components/responses/SSOLoginConfigResponse' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /rbac/roles/default: - get: - tags: - - RBAC - summary: Get All Default Roles - operationId: GetAllDefaultRoles - responses: - '200': - description: List of default RBAC roles. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/RbacRoleDto' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /api/v1/session: - post: - tags: - - Authentication - summary: User Login - description: Authenticates a user and returns a session token. - operationId: LoginHandler - requestBody: - description: Username and password for login. - required: true - content: - application/json: - schema: - type: object - properties: - username: - type: string - description: Username - example: admin - password: - type: string - description: Password - format: password - example: password123 - required: - - username - - password - responses: - '200': - description: Login successful, token returned. - content: - application/json: - schema: - type: object - properties: - token: - type: string - headers: - Set-Cookie: - description: Sets the argocd.token cookie. - schema: - type: string - example: argocd.token=yourtokenvalue; Path=/ - '400': - $ref: '#/components/responses/BadRequest' - '403': - description: Invalid username or password. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - security: [] - - /refresh: - get: - tags: - - Authentication - summary: Refresh Session Token - operationId: RefreshTokenHandler - description: Handles token refresh (details depend on OIDC/OAuth flow). - responses: - '200': - description: Token refreshed successfully. - '401': - $ref: '#/components/responses/Unauthorized' - security: [] - - /admin/policy/default: - post: - tags: - - Policy Management - summary: Add Default Policy and Roles - operationId: AddDefaultPolicyAndRoles - description: Creates default policies and roles based on team, app, and environment. - This is a specialized endpoint. - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: team - in: query - required: true - description: Project Id - schema: - type: string - - name: app - in: query - required: true - description: Application Id - schema: - type: string - - name: env - in: query - required: true - description: Environment Id - schema: - type: string - responses: - '200': - description: Default policies and roles added successfully. - '400': - $ref: '#/components/responses/BadRequest' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /devtron/auth/verify: - get: - tags: - - Authentication - summary: Verify Authentication Status - operationId: AuthVerification - responses: - '200': - description: Authentication status. - content: - application/json: - schema: - type: boolean - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /devtron/auth/verify/v2: - get: - tags: - - Authentication - summary: Verify Authentication Status (V2) - operationId: AuthVerificationV2 - responses: - '200': - description: Detailed authentication status including super admin flag. - content: - application/json: - schema: - type: object - properties: - isSuperAdmin: - type: boolean - isVerified: - type: boolean - emailId: - type: string - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/v2: - get: - tags: - - User Management - summary: List Users (V2 - Paginated, Filtered) - operationId: GetAllUsersV2 - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/SearchKeyQuery' - - $ref: '#/components/parameters/SortOrderQuery' - - $ref: '#/components/parameters/SortByQueryUser' - - $ref: '#/components/parameters/OffsetQuery' - - $ref: '#/components/parameters/SizeQuery' - responses: - '200': - $ref: '#/components/responses/UserListingResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - post: - tags: - - User Management - summary: Create User (V2) - operationId: CreateUserV2 - requestBody: - $ref: '#/components/requestBodies/UserInfo' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '406': - $ref: '#/components/responses/NotAcceptable' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - put: - tags: - - User Management - summary: Update User (V2) - operationId: UpdateUserV2 - requestBody: - $ref: '#/components/requestBodies/UserInfo' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '406': - $ref: '#/components/responses/NotAcceptable' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user: - get: - tags: - - User Management - summary: List All Users (V1) - operationId: GetAllUsers - responses: - '200': - description: List of all users. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/UserInfo' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - post: - tags: - - User Management - summary: Create User - operationId: CreateUser - requestBody: - $ref: '#/components/requestBodies/UserInfo' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '406': - $ref: '#/components/responses/NotAcceptable' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - put: - tags: - - User Management - summary: Update User - operationId: UpdateUser - requestBody: - $ref: '#/components/requestBodies/UserInfo' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '406': - $ref: '#/components/responses/NotAcceptable' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/{id}: - get: - tags: - - User Management - summary: Get User by ID - operationId: GetUserById - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - delete: - tags: - - User Management - summary: Delete User by ID - operationId: DeleteUser - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/GenericSuccess' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/v2/{id}: - get: - tags: - - User Management - summary: Get User by ID (V2) - operationId: GetUserByIdV2 - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/UserInfoResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/bulk: - delete: - tags: - - User Management - summary: Bulk Delete Users - operationId: BulkDeleteUsers - responses: - '200': - $ref: '#/components/responses/GenericSuccess' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/detail/get: - get: - tags: - - User Management - summary: List All Detailed Users - operationId: GetAllDetailedUsers - responses: - '200': - description: List of all users with detailed information. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/UserInfo' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/v2: - get: - tags: - - Role Group Management - summary: List Role Groups (V2 - Paginated, Filtered) - operationId: FetchRoleGroupsV2 - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/SearchKeyQuery' - - $ref: '#/components/parameters/SortOrderQuery' - - $ref: '#/components/parameters/SortByQueryRoleGroup' - - $ref: '#/components/parameters/OffsetQuery' - - $ref: '#/components/parameters/SizeQuery' - responses: - '200': - $ref: '#/components/responses/RoleGroupListingResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - post: - tags: - - Role Group Management - summary: Create Role Group (V2) - operationId: CreateRoleGroupV2 - requestBody: - $ref: '#/components/requestBodies/RoleGroup' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - put: - tags: - - Role Group Management - summary: Update Role Group (V2) - operationId: UpdateRoleGroupV2 - requestBody: - $ref: '#/components/requestBodies/RoleGroup' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group: - get: - tags: - - Role Group Management - summary: List All Role Groups (V1) - operationId: FetchRoleGroups - responses: - '200': - description: List of all role groups. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/RoleGroup' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - post: - tags: - - Role Group Management - summary: Create Role Group - operationId: CreateRoleGroup - requestBody: - $ref: '#/components/requestBodies/RoleGroup' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - put: - tags: - - Role Group Management - summary: Update Role Group - operationId: UpdateRoleGroup - requestBody: - $ref: '#/components/requestBodies/RoleGroup' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/{id}: - get: - tags: - - Role Group Management - summary: Get Role Group by ID - operationId: FetchRoleGroupById - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - delete: - tags: - - Role Group Management - summary: Delete Role Group by ID - operationId: DeleteRoleGroup - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/GenericSuccess' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/v2/{id}: - get: - tags: - - Role Group Management - summary: Get Role Group by ID (V2) - operationId: FetchRoleGroupByIdV2 - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - $ref: '#/components/parameters/PathId' - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '400': - $ref: '#/components/responses/BadRequest' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/detailed/get: - get: - tags: - - Role Group Management - summary: List All Detailed Role Groups - operationId: FetchDetailedRoleGroups - responses: - '200': - $ref: '#/components/responses/RoleGroupListingResponse' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/search: - get: - tags: - - Role Group Management - summary: Search Role Groups by Name - operationId: FetchRoleGroupsByName - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: name - in: query - required: true - description: Name of the role group to search for. - schema: - type: string - responses: - '200': - $ref: '#/components/responses/RoleGroupResponse' - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/group/bulk: - delete: - tags: - - Role Group Management - summary: Bulk Delete Role Groups - operationId: BulkDeleteRoleGroups - responses: - '200': - $ref: '#/components/responses/GenericSuccess' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/check/roles: - get: - tags: - - Authentication - summary: Check Logged-in User's Roles - operationId: CheckUserRoles - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appName - in: query - required: false - description: Optional application name to filter roles for. - schema: - type: string - responses: - '200': - description: User roles information. - content: - application/json: - schema: - type: object - properties: - role: - type: string - nullable: true - roles: - type: array - items: - type: string - superAdmin: - type: boolean - nullable: true - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/sync/orchestratortocasbin: - get: - tags: - - Policy Management - summary: Sync Orchestrator to Casbin - operationId: SyncOrchestratorToCasbin - description: Synchronizes policies from orchestrator to Casbin. Requires admin - privileges. - responses: - '200': - description: Sync status. - content: - application/json: - schema: - type: boolean - '401': - $ref: '#/components/responses/Unauthorized' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/update/trigger/terminal: - put: - tags: - - Policy Management - summary: Update Trigger Policy for Terminal Access - operationId: UpdateTriggerPolicyForTerminalAccess - description: Updates trigger policies related to terminal access. Requires global - update privileges. - responses: - '200': - description: Policy update status. - content: - application/json: - schema: - type: string - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - security: [] - - /user/role/cache: - get: - tags: - - Cache Management - summary: Get Role Cache Dump - operationId: GetRoleCacheDump - description: Retrieves a dump of the role cache. Requires super admin privileges. - responses: - '200': - description: Cache dump data. - content: - application/json: - schema: - type: object - '403': - $ref: '#/components/responses/Forbidden' - security: [] - - /user/role/cache/invalidate: - get: - tags: - - Cache Management - summary: Invalidate Role Cache - operationId: InvalidateRoleCache - description: Clears the role cache. Requires super admin privileges. - responses: - '200': - description: Cache invalidation status. - content: - application/json: - schema: - type: string - '403': - $ref: '#/components/responses/Forbidden' - security: [] - - /login: - get: - tags: - - Authentication - summary: OIDC Login Redirect (Informational) - description: Initiates OIDC login flow. Handled by the OIDC client library. - operationId: HandleOIDCLogin - responses: - '302': - description: Redirect to OIDC provider. - security: [] - - /auth/login: - get: - tags: - - Authentication - summary: OIDC Login Redirect (Informational - Alternate Path) - description: Initiates OIDC login flow. Handled by the OIDC client library. - operationId: HandleOIDCAuthLogin - responses: - '302': - description: Redirect to OIDC provider. - security: [] - - /auth/callback: - get: - tags: - - Authentication - summary: OIDC Callback (Informational) - description: Handles the callback from the OIDC provider. Handled by the OIDC - client library. - operationId: HandleOIDCCallback - responses: - '302': - description: Redirect after successful authentication. - '400': - description: Error during OIDC callback. - '500': - description: Server error during OIDC callback. - security: [] - - /api/dex/{path}: - get: - tags: - - Authentication - summary: Dex Proxy (Informational) - description: Proxies requests to the Dex IdP. Handled by the Dex proxy mechanism. - operationId: DexProxyHandler - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: path - in: path - required: true - description: Path to be proxied to Dex. - schema: - type: string - responses: - default: - description: Response from Dex. - security: [] - - /env: - post: - summary: Create Environment - description: Create a new environment within a cluster. - operationId: CreateEnvironment - security: [] - - tags: - - Environment Management - requestBody: - description: Environment details - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentCreateRequest' - responses: - '200': - description: Successfully created environment - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentDetail' - '400': - description: Bad Request (e.g., validation error) - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: Update Environment - description: Update an existing environment. - operationId: UpdateEnvironment - security: [] - - tags: - - Environment Management - requestBody: - description: Environment details to update - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentUpdateRequest' - responses: - '200': - description: Successfully updated environment - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentDetail' - '400': - description: Bad Request (e.g., validation error, or ID not found) - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - get: - summary: Get Environment by ID - description: Get detailed information for a specific environment by its ID. - operationId: GetEnvironmentById - security: [] - - tags: - - Environment Management - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: id - in: query - required: true - description: ID of the environment - schema: - type: integer - responses: - '200': - description: Successfully retrieved environment details - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentDetail' - '400': - description: Bad Request (e.g., invalid ID) - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Environment not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cluster/delete: - post: - summary: Delete Cluster - description: Delete an existing cluster. - operationId: DeleteCluster - security: [] - tags: - - Cluster Management - requestBody: - description: A JSON object containing the cluster config (primarily ID is - used for deletion) - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ClusterBean' - responses: - '200': - description: Successfully deleted the cluster - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: Cluster deleted successfully. - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /env/delete: - post: - summary: Delete Environment (via POST) - description: Delete an existing environment using POST method. - operationId: DeleteEnvironmentViaPost - security: [] - tags: - - Environment Management - requestBody: - description: A JSON object containing the env config (primarily ID is used - for deletion) - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentDetail' - responses: - '200': - description: Successfully deleted the environment - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: Environment deleted successfully. - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /env/clusters: - get: - summary: List clusters with their environments - description: Provides a list of all clusters and the environments within each. - operationId: getClustersWithEnvironments - security: [] - - tags: - - Cluster Environment - responses: - '200': - description: Successfully retrieved list of clusters and environments - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ClusterWithEnvironments' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cluster/{cluster_id}/env: - get: - summary: List environments for a specific cluster - description: Provides a list of all environments for a given cluster ID. - operationId: getEnvironmentsForCluster - security: [] - - tags: - - Cluster Environment - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: cluster_id - in: path - required: true - description: ID of the cluster - schema: - type: integer - responses: - '200': - description: Successfully retrieved list of environments - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Environment' - '400': - description: Bad Request. Invalid cluster ID. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Cluster not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cluster: - put: - summary: Update Cluster - description: Update an existing cluster's configuration. - operationId: UpdateCluster - security: [] - - tags: - - Cluster Management - requestBody: - description: A JSON object containing the cluster config - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ClusterBean' - responses: - '200': - description: Successfully updated the cluster - content: - application/json: - schema: - $ref: '#/components/schemas/ClusterBean' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - get: - summary: Get Cluster - description: Get details of a specific cluster by ID. - operationId: GetCluster - security: [] - - tags: - - Cluster Management - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: id - in: query - description: cluster id. - required: true - schema: - type: integer - responses: - '200': - description: Successfully get cluster - content: - application/json: - schema: - $ref: '#/components/schemas/ClusterBean' - '400': - description: Bad Request. Input Validation(decode) error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cluster/auth-list: - get: - summary: List Accessible Clusters - description: list of clusters accessible to the authenticated user. - operationId: GetAuthClusterList - security: [] - - tags: - - Cluster Management - responses: - '200': - description: cluster list - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: status code - status: - type: string - description: status - result: - type: array - description: namespace list group by cluster - items: - $ref: '#/components/schemas/ClusterAuthDetail' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - /cluster/validate: - post: - summary: Validate Cluster Configuration - description: Validate a cluster configuration using kubeconfig. - operationId: ValidateCluster - security: [] - tags: - - Cluster Management - requestBody: - content: - application/json: - schema: - type: object - properties: - kubeconfig: - $ref: '#/components/schemas/Kubeconfig' - required: - - kubeconfig - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ValidateClusterBean' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /cluster/saveClusters: - post: - summary: Save Multiple Clusters - description: Save configurations for multiple clusters. - operationId: SaveClusters - security: [] - - tags: - - Cluster Management - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ValidateClusterBean' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ValidateClusterBean' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /app/env/patch: - patch: - summary: Patch Application Environment - description: change the deployment template for an app and environment - operationId: PatchAppEnv - security: [] - - requestBody: - content: - application/json: - schema: - properties: - envId: - type: integer - description: Environment Id - appId: - type: integer - description: Application Id - targetChartRefId: - type: integer - description: Chart ref Id of template - responses: - '200': - description: patched data - '422': - description: bad request - tags: - - Change Chart - /app/workflow/clone: - post: - summary: Clone Application Workflow - description: Clones an application workflow from a source environment to a target - environment - operationId: CloneApplicationWorkflow - security: [] - - requestBody: - description: A JSON object containing the details required to clone the workflow - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CloneApplicationWorkflowRequest' - responses: - '200': - description: Cloning operation response - content: - application/json: - schema: - $ref: '#/components/schemas/StandardResponse' - tags: - - Clone Workflow - /k8s/resource: - post: - summary: Get Resource Manifest - description: This API is used for fetching the manifest of a specified Kubernetes - resource. - operationId: getResourceManifest - security: [] - - requestBody: - description: JSON payload specifying the resource to fetch. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully retrieved the resource manifest. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code of the response. - status: - type: string - description: Status message of the response. - result: - $ref: '#/components/schemas/ResourceGetResponse' - tags: - - K8s Resource - put: - summary: Update Resource Manifest - description: This API is used for editing the manifest of a specified Kubernetes - resource. - operationId: updateResourceManifest - security: [] - - requestBody: - description: JSON payload containing the resource identifier and the patch. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully updated the resource manifest. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code of the response. - status: - type: string - description: Status message of the response. - result: - $ref: '#/components/schemas/ResourceGetResponse' - tags: - - K8s Resource - /k8s/resource/create: - post: - summary: Create Resource - description: This API is used for applying a desired manifest to create a Kubernetes - resource. - operationId: createResource - security: [] - - requestBody: - description: JSON payload containing the resource manifest to apply. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully created the resource. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code of the response. - status: - type: string - description: Status message of the response. - result: - $ref: '#/components/schemas/ResourceGetResponse' - tags: - - K8s Resource - /k8s/resource/delete: - post: - summary: Delete Resource - description: This API is used for deleting a specified Kubernetes resource. - operationId: deleteResource - security: [] - - requestBody: - description: JSON payload specifying the resource to delete. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully deleted the resource. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code of the response. - status: - type: string - description: Status message of the response. - result: - $ref: '#/components/schemas/ResourceGetResponse' - tags: - - K8s Resource - /k8s/events: - post: - summary: Get Resource Events - description: This API is used for fetching events for Kubernetes resources. - operationId: getResourceEvents - security: [] - - requestBody: - required: false - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully retrieved resource events. The response is a stream - of events. - content: - text/event-stream: - schema: - $ref: '#/components/schemas/EventsResponseObject' - tags: - - K8s Resource - /k8s/pods/logs/{podName}: - get: - summary: Get Pod Logs - description: This API is used for fetching logs for a specified container within - a pod. - operationId: getPodLogs - security: [] - - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: podName - in: path - required: true - description: Name of the pod. - schema: - type: string - - name: containerName - in: query - required: true - description: Name of the container within the pod. - schema: - type: string - - name: appId - in: query - required: false - description: Application ID. - schema: - type: string - - name: clusterId - in: query - required: false - description: Cluster ID. - schema: - type: integer - - name: namespace - in: query - description: Namespace of the pod. Required if clusterId is passed. - required: false - schema: - type: string - - name: follow - in: query - description: Whether to follow the log stream. - schema: - type: boolean - default: false - - name: sinceSeconds - in: query - description: Return logs newer than a relative duration like 5s, 2m, or 3h. - Defaults to all logs. - schema: - type: integer - - name: tailLines - in: query - description: If set, the number of lines from the end of the logs to show. - schema: - type: integer - responses: - '200': - description: Successfully retrieved pod logs. The response is a stream of - log lines. - content: - text/event-stream: - schema: - $ref: '#/components/schemas/LogsResponseObject' - tags: - - K8s Resource - /k8s/pod/exec/session/{identifier}/{namespace}/{pod}/{shell}/{container}: - get: - summary: Get Pod Exec Session - description: This API establishes a session for executing commands in a pod's - container (terminal access). - operationId: getPodExecSession - security: [] - - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: identifier - in: path - required: true - description: Application ID or Cluster ID. Example '2|devtroncd|devtron' or - '3'. - schema: - type: string - - name: namespace - in: path - required: true - description: Namespace of the pod. - schema: - type: string - example: devtroncd - - name: pod - in: path - required: true - description: Name of the pod. - schema: - type: string - example: inception-58d44d99fd-tfw4s - - name: shell - in: path - required: true - description: Shell to invoke. - schema: - type: string - enum: - - bash - - sh - - powershell - - cmd - example: bash - - name: container - in: path - required: true - description: Name of the container. - schema: - type: string - example: devtron - responses: - '200': - description: Successfully established exec session. - content: - application/json: - schema: - $ref: '#/components/schemas/TerminalMessage' - tags: - - K8s Resource - /k8s/api-resources/{clusterId}: - get: - summary: Get API Resources - description: Get all available API resources for a given cluster ID. - operationId: getApiResources - security: [] - - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: clusterId - in: path - description: ID of the cluster. - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: Successfully fetched all API resources for the given cluster - ID. - content: - application/json: - schema: - $ref: '#/components/schemas/GetAllApiResourcesResponse' - tags: - - K8s Resource - /k8s/resource/list: - post: - summary: List Resources - description: This API is used for fetching a list of Kubernetes resources based - on the request criteria. - operationId: listResources - security: [] - - requestBody: - description: JSON payload specifying the criteria for listing resources. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceRequestObject' - responses: - '200': - description: Successfully retrieved the list of resources. - content: - application/json: - schema: - type: object - properties: - code: - type: integer - description: Status code of the response. - status: - type: string - description: Status message of the response. - result: - type: array - description: List of resources. - items: - $ref: '#/components/schemas/ClusterResourceListResponse' - tags: - - K8s Resource - /k8s/resources/rotate: - post: - summary: Rotates the Pods - description: This API is used to rotate (restart) pods for the provided resources. - operationId: K8sResourceForResources - security: [] - - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: query - description: Application ID. - required: true - schema: - type: string - requestBody: - description: JSON payload specifying the resources for which pods should be - rotated. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RotatePodRequest' - responses: - '200': - description: Response array indicating the status of rotation for each resource. - content: - application/json: - schema: - $ref: '#/components/schemas/RotatePodResponse' - tags: - - K8s Resource - /k8s/resources/apply: - post: - summary: Apply Resources - description: This API is used to apply (create or update) Kubernetes resources - in a cluster. - operationId: applyResources - security: [] - - requestBody: - description: JSON payload containing the manifest of resources to apply. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ApplyResourcesRequest' - responses: - '200': - description: Response array indicating the status of application for each - resource. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApplyResourcesResponse' - tags: - - K8s Resource - /app/workflow: - post: - summary: Create an application workflow - description: Creates a new workflow for a given application. - operationId: CreateAppWorkflow - security: [] - - tags: - - Workflow Management - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AppWorkflowDto' - responses: - '200': - description: Successfully created workflow. - content: - application/json: - schema: - $ref: '#/components/schemas/AppWorkflowDto' - '400': - description: Bad Request. Validation error or wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden. User does not have permission. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /app/workflow/{app-wf-id}/app/{app-id}: - delete: - summary: Delete an application workflow - description: Deletes an existing workflow for a given application. - operationId: DeleteAppWorkflow - security: [] - - tags: - - Workflow Management - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: app-wf-id - in: path - required: true - description: ID of the application workflow to delete. - schema: - type: integer - - name: app-id - in: path - required: true - description: ID of the application. - schema: - type: integer - responses: - '200': - description: Successfully deleted workflow. - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: OK - '400': - description: Bad Request. Invalid path parameters. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Unauthorized User. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden. User does not have permission. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /version: - get: - summary: Get Devtron server version information - security: [] - responses: - '200': - description: meta info about devtron server - content: - application/json: - schema: - type: object - properties: - gitCommit: - type: string - example: d252aa3e - description: git hash from which code was compiled - buildTime: - type: string - format: date-time - example: '2021-12-15T05:44:05Z' - description: time when code was complied - serverMode: - type: string - example: FULL - description: server mode FULL/EA_ONLY - enum: - - FULL - - EA_ONLY - tags: - - Devtron Server version - /validate: - post: - description: Validate gitops configuration by dry run - summary: Validate gitops configuration by dry run - security: [] - operationId: GitOpsValidateDryRun - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - tags: - - GitOps Validation - /config: - post: - description: create/save new configuration and validate them before saving - summary: create/save new configuration and validate them before saving - security: [] - operationId: CreateGitOpsConfig - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results and if validation - is correct then saves the configuration in the backend - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - tags: - - GitOps Validation - put: - description: update configuration and validate them before saving(if last validation - is within 30 seconds then do not validate) - summary: update configuration and validate them before saving(if last validation - is within 30 seconds then do not validate) - operationId: UpdateGitOpsConfig - security: [] - requestBody: - description: A JSON object containing the gitops configuration - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GitOpsConfigDto' - responses: - '200': - description: Successfully return all validation stages results and if validation - is correct then updates the configuration in the backend - content: - application/json: - schema: - $ref: '#/components/schemas/DetailedError' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - tags: - - GitOps Validation - /notification: - get: - summary: Returns all notification settings - description: Returns all notification settings - operationId: findNotificationSetting - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: offset - in: query - description: value can be regex search string. - required: true - schema: - type: integer - - name: size - in: query - description: value can be regex search string. - required: true - schema: - type: integer - security: [] - - tags: - - Notifications - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new NotificationSetting - description: create NotificationSetting api. - operationId: addNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - security: [] - - tags: - - Notifications - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: Update NotificationSetting - description: Update NotificationSetting api either recipients or events(trigger/success/failed). - operationId: updateNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - security: [] - - tags: - - Notifications - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: delete NotificationSetting - description: delete NotificationSetting. - operationId: deleteNotificationSetting - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - security: [] - - tags: - - Notifications - responses: - '200': - description: create NotificationSetting response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSetting' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /notification/recipient: - get: - summary: used to fetch providers(recipients) - description: recipients fetch by string search, it will return slacks providers - and email ids - operationId: deleteGroupPolicy - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: value - in: query - description: value can be regex search string. - required: true - schema: - type: string - security: [] - - tags: - - Notifications - responses: - '204': - description: list of recipients - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /notification/channel: - get: - summary: get all NotificationSettingConfig list - description: get all NotificationSettingConfig list - operationId: findNotificationSettingConfig - security: [] - - tags: - - Notifications - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfigResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new NotificationSettingConfig - description: create NotificationSettingConfig, Slack or SES - operationId: addNotificationSettingConfig - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfig' - security: [] - - tags: - - Notifications - responses: - '200': - description: create NotificationSettingConfig response - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationConfigResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /orchestrator/app/history/deployed-component/detail/{appId}/{pipelineId}/{id}: - get: - summary: Fetch component history - description: fetch detail of a history on the basis of the history component - and it's name - operationId: FetchHistoryByDeployedConfigurationDetail - tags: - - Deployment History - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: id - in: path - required: true - schema: - type: integer - - name: historyComponent - in: query - required: true - schema: - type: string - enum: - - DEPLOYMENT_TEMPLATE - - CONFIGMAP - - SECRET - - PIPELINE_STRATEGY - - name: historyComponentName - in: query - required: false - description: name of config-map, secret - schema: - type: string - security: [] - - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - $ref: '#/components/schemas/HistoryComponentDetailDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /orchestrator/app/history/deployed-component/list/{appId}/{pipelineId}: - get: - summary: fetch deployed history details list - description: fetch deployed history details list - operationId: FetchHistoryListByDeployedConfigurationDetail - tags: - - Deployment History - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: historyComponent - in: query - required: true - schema: - type: string - enum: - - DEPLOYMENT_TEMPLATE - - CONFIGMAP - - SECRET - - PIPELINE_STRATEGY - - name: historyComponentName - in: query - required: false - description: name of config-map, secret - schema: - type: string - - name: baseConfigurationId - in: query - required: true - description: id of base configuration - schema: - type: integer - security: [] - - responses: - '200': - description: Successfully return history list - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HistoryComponentListDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /orchestrator/app/history/deployed-configuration/{appId}/{pipelineId}/{wfrId}: - get: - summary: all deployed configuration history - description: fetch all deployed configurations history (deployment template, - pipeline strategy, configmaps, secrets) - operationId: FetchHistoryListForAllDeployedConfigurations - tags: - - Deployment History - parameters: - - name: token - in: header - required: true - description: Authentication token. - schema: - type: string - - name: appId - in: path - required: true - schema: - type: integer - - name: pipelineId - in: path - required: true - schema: - type: integer - - name: wfrId - in: path - required: true - schema: - type: integer - security: [] - - responses: - '200': - description: Successfully return history - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HistoryConfigurationListDto' - '400': - description: Bad Request. Input Validation error/wrong request body. - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Unauthorized User - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -components: - schemas: - AppLabel: - type: object - required: - - key - - value - properties: - key: - type: string - description: label key - value: - type: string - description: label value - propagate: - type: boolean - description: Whether to propagate to kubernetes resources - AppLabels: - type: object - required: - - appId - - labels - properties: - appId: - type: integer - description: application id - labels: - type: array - items: - $ref: '#/components/schemas/AppLabel' - AppMetaInfo: - type: object - required: - - appId - - projectId - - appName - - projectName - - createdOn - - createdBy - - labels - properties: - appId: - type: integer - description: app id - projectId: - type: integer - description: team/project id - appName: - type: string - description: app name - projectName: - type: string - description: team/project name - labels: - type: array - items: - $ref: '#/components/schemas/AppLabel' - createdOn: - type: string - description: app creation date - createdBy: - type: string - description: app created by - ErrorResponse: - type: object - properties: - code: - type: integer - format: int32 - status: - type: string - result: - type: object - nullable: true - errors: - type: array - items: - type: object - properties: - userMessage: - type: string - nullable: true - internalMessage: - type: string - nullable: true - Error: - required: - - code - - message - properties: - code: - type: integer - description: Error code - message: - type: string - description: Error message - CreateJob: - type: object - properties: - appName: - type: string - description: Used to give the name of the job - example: my-job-1 - isJob: - type: boolean - description: States whether its a job or an app - example: true - teamId: - type: integer - description: Used to give project id - example: 1 - templateId: - type: integer - description: Used to give the id of the job it wants to clone - example: 18 - labels: - type: array - items: - type: object - properties: - key: - type: string - example: hello - value: - type: string - example: world - propogate: - type: boolean - example: false - description: - type: string - description: Used to give the description of the job once it is made. - example: This is my first Job - ActionResponse: - type: object - properties: - id: - type: integer - description: Used to give the id of job once its created - example: 25 - appName: - type: string - description: Used to give the name of job once its created - example: my-job-1 - material: - type: array - items: - $ref: '#/components/schemas/gitMaterial' - teamId: - type: integer - description: Used to give the team id - example: 1 - templateId: - type: integer - description: Used to give the templateId - example: 0 - description: - type: string - description: Used to give the description of the job once it is made. - example: This is my first Job - isJob: - type: boolean - description: used to tell whether it is a job or an app - example: true - JobList: - type: object - properties: - teams: - type: array - items: - type: integer - description: used to give the project id - example: - - 1 - - 2 - appStatuses: - type: array - items: - type: string - description: used to give the filter of app ci-build status - example: - - Succeeded - - Starting - sortBy: - type: string - description: used to give the sort by constraint - example: appNameSort - sortOrder: - type: string - description: used to give the sort order - example: ASC - offset: - type: integer - description: used to give the number from which we want our job (if the - offset is 20 means we want list of jobs from 20) - example: 0 - size: - type: integer - description: used to give the number of jobs we want - example: 20 - JobListResponse: - type: object - properties: - jobContainers: - type: array - items: - $ref: '#/components/schemas/jobContainer' - jobCount: - type: integer - gitMaterial: - type: object - properties: - name: - type: string - url: - type: string - id: - type: integer - gitProviderId: - type: integer - checkoutPath: - type: string - fetchSubmodules: - type: boolean - isUsedInCiConfig: - type: boolean - jobContainer: - type: object - properties: - jobId: - type: integer - jobName: - type: string - description: - type: string - ciPipelines: - type: array - items: - $ref: '#/components/schemas/jobCiPipeline' - jobCiPipeline: - type: object - properties: - ciPipelineId: - type: integer - status: - type: string - lastRunAt: - type: string - format: date-time - lastSuccessAt: - type: string - format: date-time - 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 - App: - type: object - required: - - appName - - teamId - - templateId - properties: - appName: - type: string - description: app name - teamId: - type: integer - description: project id - templateId: - type: integer - description: reference app id, used for clone, set default value 0 for blank - app. - labels: - type: array - description: each apps may have multiple labels. these are optional. - items: - $ref: '#/components/schemas/AppLabel' - AppProjectUpdateRequest: - type: object - required: - - teamId - - appId - properties: - teamId: - type: integer - description: project id - appId: - type: array - description: team id, teams ids are projects ids - items: - type: integer - AppListingRequest: - type: object - required: [] - properties: - appNameSearch: - type: string - description: app name search, wildcard match - offset: - type: integer - description: offset - size: - type: integer - description: result size - sortBy: - type: string - description: sort by - sortOrder: - type: string - description: sort order - environments: - type: array - description: environment id - items: - type: integer - teams: - type: array - description: team id, teams ids are projects ids - items: - type: integer - labels: - type: array - description: app labels - items: - type: string - statuses: - type: array - description: status - items: - type: string - AppContainer: - type: object - required: - - appId - - appName - - environments - properties: - appId: - type: integer - description: app id - appName: - type: string - description: app name - environments: - type: array - items: - $ref: '#/components/schemas/EnvContainer' - EnvContainer: - type: object - required: - - appId - - appName - - environmentId - - environmentName - properties: - appId: - type: integer - description: app id - appName: - type: string - description: app name - cdStageStatus: - type: string - description: app name - dataSource: - type: string - description: app name - ciArtifactId: - type: integer - description: app name - deleted: - type: boolean - description: app name - environmentId: - type: integer - description: app name - environmentName: - type: string - description: app name - status: - type: string - description: app name - appStatus: - type: string - description: app status for this environment - postStageStatus: - type: string - description: app name - preStageStatus: - type: string - description: app name - lastDeployedTime: - type: string - description: deployed time - materialInfo: - type: array - items: - type: object - DeploymentGroup: - type: object - required: - - id - properties: - id: - type: integer - description: id - ciPipelineId: - type: integer - description: ciPipelineId - environmentId: - type: integer - description: environmentId - appCount: - type: integer - description: appCount - name: - type: string - description: name - noOfApps: - type: string - description: noOfApps - BulkUpdateSeeExampleResponse: - type: object - required: - - Script - properties: - resource: - type: string - description: Resource from url path, i.e. {apiVersion} & {kind} - script: - $ref: '#/components/schemas/BulkUpdateScript' - description: Input Script for bulk update - readMe: - type: string - description: Readme for bulk update - BulkUpdateScript: - type: object - required: - - ApiVersion - - Kind - - Spec - properties: - apiVersion: - type: string - description: Api version from url - example: - - v1beta1 - kind: - type: string - description: Kind - example: - - application - spec: - $ref: '#/components/schemas/BulkUpdatePayload' - BulkUpdatePayload: - type: object - properties: - includes: - $ref: '#/components/schemas/NameIncludesExcludes' - excludes: - $ref: '#/components/schemas/NameIncludesExcludes' - envIds: - type: array - items: - type: integer - description: All Env Id's for updating dependent apps - global: - type: boolean - description: Global flag for updating dependent apps - DeploymentTemplate: - $ref: '#/components/schemas/Tasks' - ConfigMaps: - type: object - properties: - names: - type: array - items: - type: string - description: Name of All ConfigMaps to be updated - tasks: - $ref: '#/components/schemas/Spec' - Secrets: - type: object - properties: - names: - type: array - items: - type: string - description: Name of All Secrets to be updated - tasks: - $ref: '#/components/schemas/Spec' - Tasks: - type: object - properties: - spec: - $ref: '#/components/schemas/Spec' - description: Spec of the Task - Spec: - type: object - properties: - patchData: - type: string - description: string with details of the patch to be used for updating - NameIncludesExcludes: - type: object - properties: - names: - type: array - items: - type: string - description: All strings of app names to be included/excluded - ImpactedObjectsResponse: - type: object - properties: - deploymentTemplate: - type: array - items: - $ref: '#/components/schemas/DeploymentTemplateImpactedObjectsResponseForOneApp' - configMap: - type: array - items: - $ref: '#/components/schemas/CmAndSecretImpactedObjectsResponseForOneApp' - secret: - type: array - items: - $ref: '#/components/schemas/CmAndSecretImpactedObjectsResponseForOneApp' - DeploymentTemplateImpactedObjectsResponseForOneApp: - type: object - properties: - appId: - type: integer - description: Id of the impacted app - appName: - type: string - description: Name of the impacted app - envId: - type: string - description: Env Id of the impacted app - CmAndSecretImpactedObjectsResponseForOneApp: - type: object - properties: - appId: - type: integer - description: Id of the impacted app - appName: - type: string - description: Name of the impacted app - envId: - type: string - description: Env Id of the impacted app - names: - type: array - items: - type: string - description: Names of all configmaps/secrets impacted - BulkUpdateResponse: - type: object - properties: - deploymentTemplate: - $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponse' - configMap: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' - secret: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponse' - DeploymentTemplateBulkUpdateResponse: - type: object - properties: - message: - type: array - items: - type: string - description: All top-level messages in response of bulk update action - failure: - type: array - items: - $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update failed - successful: - type: array - items: - $ref: '#/components/schemas/DeploymentTemplateBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update applied successfully - CmAndSecretBulkUpdateResponse: - type: object - properties: - message: - type: array - items: - type: string - description: All top-level messages in response of bulk update action - failure: - type: array - items: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update failed - successful: - type: array - items: - $ref: '#/components/schemas/CmAndSecretBulkUpdateResponseForOneApp' - description: Details of all apps on which bulk update applied successfully - DeploymentTemplateBulkUpdateResponseForOneApp: - type: object - properties: - appId: - type: integer - description: Id of the concerned app - appName: - type: string - description: Name of the concerned app - envId: - type: integer - description: Env ID of the concerned app - message: - type: string - description: App-level message for the concerned app - CmAndSecretBulkUpdateResponseForOneApp: - type: object - properties: - appId: - type: integer - description: Id of the concerned app - appName: - type: string - description: Name of the concerned app - envId: - type: integer - description: Env ID of the concerned app - names: - type: array - items: - type: string - description: Names of all configmaps/secrets - message: - type: string - description: App-level message for the concerned app - BulkActionRequest: - type: object - properties: - includes: - $ref: '#/components/schemas/NameIncludesExcludes' - excludes: - $ref: '#/components/schemas/NameIncludesExcludes' - envIds: - type: array - items: - type: integer - description: All Env Id's for the bulk action - appIds: - type: array - items: - type: integer - description: All App Id's for the bulk action (alternative to includes/excludes - by name) - projectIds: - type: array - items: - type: integer - description: All Project Id's for the bulk action - BulkActionResponse: - type: object - properties: - message: - type: array - items: - type: string - description: Top-level messages in response of the bulk action - failure: - type: array - items: - $ref: '#/components/schemas/BulkActionFailureDetail' - description: Details of all items on which the bulk action failed - successful: - type: array - items: - $ref: '#/components/schemas/BulkActionSuccessDetail' - description: Details of all items on which the bulk action applied successfully - BulkActionFailureDetail: - type: object - properties: - appId: - type: integer - appName: - type: string - envId: - type: integer - message: - type: string - BulkActionSuccessDetail: - type: object - properties: - appId: - type: integer - appName: - type: string - envId: - type: integer - message: - type: string - BulkDeployRequest: - type: object - required: - - envIds - properties: - includes: - $ref: '#/components/schemas/NameIncludesExcludes' - excludes: - $ref: '#/components/schemas/NameIncludesExcludes' - envIds: - type: array - items: - type: integer - description: All Env Id's for the bulk deployment - appIds: - type: array - items: - type: integer - description: All App Id's for the bulk deployment (alternative to includes/excludes - by name) - projectIds: - type: array - items: - type: integer - description: All Project Id's for the bulk deployment - artifactId: - type: integer - description: ID of the CI artifact to be deployed - releaseId: - type: integer - description: ID of the release to be deployed - deploymentStrategy: - type: string - description: Deployment strategy to use (e.g., blue-green, canary, recreate) - BulkBuildTriggerRequest: - type: object - required: - - ciPipelineId - properties: - includes: - $ref: '#/components/schemas/NameIncludesExcludes' - excludes: - $ref: '#/components/schemas/NameIncludesExcludes' - appIds: - type: array - items: - type: integer - description: All App Id's for the bulk build trigger (alternative to includes/excludes - by name) - projectIds: - type: array - items: - type: integer - description: All Project Id's for the bulk build trigger - ciPipelineId: - type: integer - description: ID of the CI pipeline to trigger builds for - SSOLoginDto: - type: object - properties: - id: - type: integer - format: int32 - readOnly: true - name: - type: string - description: Type of auth ie google/github - label: - type: string - nullable: true - url: - type: string - format: url - description: Devtron Dashboard Url - example: https://devtron.example.com/orchestrator - nullable: true - config: - type: object - description: Configuration for the SSO provider (Dex connector config). - Structure varies. - active: - type: boolean - required: - - name - - url - - config - - active - UserInfo: - type: object - properties: - id: - type: integer - format: int32 - description: User ID. Should not be set for new user creation if auto-generated. - Not allowed to be system-admin-userid (1 or 2) by validation. - email_id: - type: string - format: email - description: User's email address. Cannot be system admin user email by - validation. - roles: - type: array - items: - type: string - description: List of direct roles assigned to the user (deprecated in favor - of roleFilters and userRoleGroups). - nullable: true - accessToken: - type: string - description: Access token for the user (typically not part of create/update - payload, but in response). - readOnly: true - nullable: true - roleFilters: - type: array - items: - $ref: '#/components/schemas/RoleFilter' - groups: - type: array - items: - type: string - description: Deprecated field for user groups. Use userRoleGroups instead. - nullable: true - userRoleGroups: - type: array - items: - $ref: '#/components/schemas/UserRoleGroup' - nullable: true - superAdmin: - type: boolean - description: Indicates if the user has super admin privileges. - lastLoginTime: - type: string - format: date-time - readOnly: true - description: The time the user last logged in. - required: - - email_id - RoleGroup: - type: object - properties: - id: - type: integer - format: int32 - readOnly: true - name: - type: string - description: Name of the Role group - description: - type: string - description: Descrition fo Role group - nullable: true - roleFilters: - type: array - description: Role filters - items: - $ref: '#/components/schemas/RoleFilter' - superAdmin: - type: boolean - description: Indicates if this role group grants super admin privileges. - required: - - name - - roleFilters - RoleFilter: - type: object - description: Defines a specific permission filter for a role. - properties: - entity: - type: string - description: The type of entity this filter applies to (e.g., apps, jobs, - chart-group, cluster). - enum: - - apps - - jobs - - chart-group - - cluster - team: - type: string - description: Team associated with this permission. Can be empty for some - global entities. - nullable: true - entityName: - type: string - description: Name of the specific entity (e.g., application name, job name, - chart group name). Can be empty for 'all' access. - nullable: true - environment: - type: string - description: Environment associated with this permission. Can be empty if - not applicable. - nullable: true - action: - type: string - description: Action permitted (e.g., get, create, update, delete, trigger, - *). - accessType: - type: string - description: Access type, typically for distinguishing app types like devtron-app - or helm-app. - enum: - - devtron-app - - helm-app - - '' - nullable: true - cluster: - type: string - description: Cluster name for cluster-scoped permissions. - nullable: true - namespace: - type: string - description: Namespace for cluster-scoped permissions. - nullable: true - group: - type: string - description: API group for K8s resources. - nullable: true - kind: - type: string - description: Kind of K8s resource. - nullable: true - resource: - type: string - description: Specific K8s resource name. - nullable: true - workflow: - type: string - description: Workflow name, applicable if entity is 'jobs'. - nullable: true - required: - - entity - - action - UserRoleGroup: - type: object - description: Associates a user with a role group. - properties: - roleGroup: - $ref: '#/components/schemas/RoleGroup' - RbacRoleDto: - type: object - description: Represents a default RBAC role. - properties: - id: - type: integer - format: int32 - roleName: - type: string - roleDisplayName: - type: string - roleDescription: - type: string - entity: - type: string - enum: - - apps - - cluster - - chart-group - - jobs - accessType: - type: string - nullable: true - BulkDeleteRequest: - type: object - properties: - ids: - type: array - items: - type: integer - format: int32 - description: List of IDs to delete. - listingRequest: - $ref: '#/components/schemas/ListingRequest' - required: - - ids - ListingRequest: - type: object - properties: - searchKey: - type: string - nullable: true - sortOrder: - type: string - enum: - - ASC - - DESC - nullable: true - sortBy: - type: string - nullable: true - offset: - type: integer - format: int32 - minimum: 0 - nullable: true - size: - type: integer - format: int32 - minimum: 1 - default: 20 - nullable: true - showAll: - type: boolean - nullable: true - readOnly: true - EnvironmentCreateRequest: - type: object - required: - - environment_name - - cluster_id - properties: - environment_name: - type: string - maxLength: 50 - description: Name of the Environment - cluster_id: - type: integer - description: Id of the target Cluster - active: - type: boolean - default: true - default: - type: boolean - default: false - prometheus_endpoint: - type: string - description: Prometheus Endpoint of cluster - namespace: - type: string - description: Name of the Namespace which will point to environment - maxLength: 50 - isClusterCdActive: - type: boolean - description: - type: string - maxLength: 40 - isVirtualEnvironment: - type: boolean - default: false - allowedDeploymentTypes: - type: array - items: - type: string - enum: - - helm - - argo_cd - EnvironmentUpdateRequest: - type: object - required: - - id - - environment_name - - cluster_id - properties: - id: - type: integer - environment_name: - type: string - description: Name of the Environment - maxLength: 50 - cluster_id: - type: integer - description: Id of the target Cluster - active: - type: boolean - default: - type: boolean - prometheus_endpoint: - type: string - description: Prometheus Endpoint of cluster - namespace: - type: string - description: Name of the Namespace pointing to environment - maxLength: 50 - isClusterCdActive: - type: boolean - description: - type: string - maxLength: 40 - isVirtualEnvironment: - type: boolean - allowedDeploymentTypes: - type: array - items: - type: string - enum: - - helm - - argo_cd - EnvironmentDetail: - type: object - properties: - id: - type: integer - environment_name: - type: string - description: Name of the Environment - cluster_id: - type: integer - description: Id of the target Cluster - cluster_name: - type: string - description: Name of the cluster - active: - type: boolean - default: - type: boolean - prometheus_endpoint: - type: string - description: Prometheus Endpoint of cluster - namespace: - type: string - description: Name of the Namespace pointing to environment - isClusterCdActive: - type: boolean - environmentIdentifier: - type: string - description: - type: string - appCount: - type: integer - isVirtualEnvironment: - type: boolean - allowedDeploymentTypes: - type: array - items: - type: string - enum: - - helm - - argo_cd - ClusterWithEnvironments: - type: object - properties: - id: - type: integer - description: Cluster ID - cluster_name: - type: string - description: Name of the cluster - server_url: - type: string - description: Server URL of the cluster - active: - type: boolean - description: Whether the cluster is active - environments: - type: array - items: - $ref: '#/components/schemas/Environment' - prometheus_url: - type: string - description: URL for Prometheus monitoring - k8sVersion: - type: string - description: Kubernetes version of the cluster - Environment: - type: object - properties: - environmentId: - type: integer - description: Environment ID - environmentName: - type: string - description: Name of the environment - environmentIdentifier: - type: string - description: Unique identifier for the environment - namespace: - type: string - description: Namespace associated with the environment - active: - type: boolean - description: Whether the environment is active - ClusterBean: - type: object - properties: - id: - type: integer - description: Id of the cluster - cluster_name: - type: string - description: Name of the cluster - server_url: - type: string - description: Server Url of the cluster - prometheus_url: - type: string - description: Prometheus Endpoint of cluster - active: - type: boolean - config: - type: object - properties: - bearer_token: - type: string - description: it will be empty while fetching, and if no change while - updating - prometheusAuth: - $ref: '#/components/schemas/PrometheusAuthGet' - defaultClusterComponents: - type: array - items: - $ref: '#/components/schemas/DefaultClusterComponentGet' - k8sversion: - type: string - description: K8s version of the cluster - ClusterAuthDetail: - type: object - properties: - clusterId: - type: integer - description: cluster id - clusterName: - type: string - description: cluster name - errorInConnecting: - type: string - description: error message if cluster failed to connect - Kubeconfig: - type: object - description: Kube config of target cluster - properties: - config: - type: string - ValidateClusterBean: - type: object - required: - - cluster_name - - server_url - properties: - userInfos: - type: object - additionalProperties: - $ref: '#/components/schemas/UserInfos' - id: - type: integer - description: Cluster Id - cluster_name: - type: string - description: Name of the cluster - server_url: - type: string - description: Server Url of the cluster - prometheus_url: - type: string - description: Prometheus Endpoint of the cluster - active: - type: boolean - config: - type: object - properties: - bearer_token: - type: string - description: it will be empty while fetching, and if no change while - updating - tls_key: - type: string - description: it will be empty while fetching, and if no change while - updating - cert_data: - type: string - description: it will be empty while fetching, and if no change while - updating - cert_auth_data: - type: string - description: it will be empty while fetching, and if no change while - updating - prometheusAuth: - $ref: '#/components/schemas/PrometheusAuthAdd' - defaultClusterComponent: - type: array - items: - $ref: '#/components/schemas/DefaultClusterComponentAdd' - agentInstallationStage: - type: integer - k8sVersion: - type: string - description: K8s version of the cluster - userName: - type: string - insecure-skip-tls-verify: - type: boolean - UserInfos: - type: object - properties: - userName: - type: string - config: - type: object - additionalProperties: - type: string - errorInConnecting: - type: string - PrometheusAuthAdd: - type: object - properties: - type: - type: string - enum: - - basic - - bearer - basic: - type: object - properties: - username: - type: string - password: - type: string - bearer: - type: object - properties: - token: - type: string - PrometheusAuthGet: - type: object - properties: - userName: - type: string - password: - type: string - tlsClientCert: - type: string - tlsClientKey: - type: string - DefaultClusterComponentAdd: - type: object - properties: - id: - type: string - name: - type: string - version: - type: string - status: - type: string - configuration: - $ref: '#/components/schemas/ComponentConfiguration' - DefaultClusterComponentGet: - type: object - properties: - name: - type: string - appId: - type: integer - installedAppId: - type: integer - envId: - type: integer - envname: - type: string - status: - type: string - ComponentConfiguration: - type: object - properties: - type: - type: string - enum: - - yaml - - json - CloneApplicationWorkflowRequest: - type: object - properties: - appId: - type: integer - description: ID of the application - appName: - type: string - description: Name of the application - sourceEnvironmentId: - type: integer - description: ID of the source environment - sourceEnvironmentName: - type: string - description: Name of the source environment - targetEnvironmentId: - type: integer - description: ID of the target environment - targetEnvironmentName: - type: string - description: Name of the target environment - cloneEnvInSameWorkflow: - type: boolean - description: Flag indicating if the environment should be cloned in the - same workflow - CloneApplicationWorkflowResponse: - type: object - properties: - status: - type: string - description: Status of the operation - enum: - - SUCCESS - - FAILED - - SKIPPED - message: - type: string - description: Detailed message about the operation result - required: - - status - - message - StandardResponse: - type: object - properties: - code: - type: integer - description: HTTP status code - example: 200 - status: - type: string - description: HTTP status text - example: OK - result: - type: object - properties: - status: - type: string - description: Status of the operation - enum: - - SUCCESS - - FAILED - - SKIPPED - message: - type: string - description: Detailed message about the operation result - required: - - status - - message - required: - - code - - status - - result - ResourceInfo: - type: object - required: - - podName - properties: - podName: - type: string - description: Name of the inception pod. - example: inception-pod-xyz - TerminalMessage: - type: object - properties: - Op: - type: string - description: Operation type for the terminal session. - example: stdin - Data: - type: string - description: Data for the terminal session (e.g., command or output). - example: ls -l - SessionID: - type: string - description: ID of the terminal session. - example: unique-session-id-123 - ResourceRequestObject: - type: object - properties: - appId: - type: string - description: Application ID. Used when the request is context-specific to - an application. - example: my-app/env-1 - clusterId: - type: number - description: Cluster ID. Used when the request is for a direct cluster resource - (appId is not supplied). - example: 1 - k8sRequest: - $ref: '#/components/schemas/K8sRequestObject' - K8sRequestObject: - type: object - properties: - resourceIdentifier: - type: object - properties: - groupVersionKind: - $ref: '#/components/schemas/GroupVersionKind' - namespace: - type: string - description: Namespace of the resource. - example: default - name: - type: string - description: Name of the resource. - example: my-deployment - required: - - name - - groupVersionKind - podLogsRequest: - type: object - properties: - containerName: - type: string - description: Name of the container for which logs are requested. - example: my-container - patch: - type: string - description: JSON patch or strategic merge patch to apply to the resource. - example: '[{"op": "replace", "path": "/spec/replicas", "value": 3}]' - ResourceGetResponse: - type: object - properties: - manifestResponse: - $ref: '#/components/schemas/ManifestResponse' - secretViewAccess: - type: boolean - description: 'Indicates whether a user can see obscured secret values or - not. True if the user has permission, false otherwise. - - ' - example: true - required: - - manifestResponse - - secretViewAccess - ManifestResponse: - type: object - properties: - manifest: - type: object - description: The Kubernetes resource manifest. - additionalProperties: true - example: - apiVersion: v1 - kind: ConfigMap - metadata: - name: my-config - namespace: default - data: - key1: value1 - key2: value2 - EventsResponseObject: - type: object - description: Represents a Kubernetes Event object. - properties: - metadata: - $ref: '#/components/schemas/ObjectMeta' - involvedObject: - $ref: '#/components/schemas/ObjectReference' - reason: - type: string - description: Short, machine-understandable string that describes the reason - for the transition into the object's current status. - example: Scheduled - message: - type: string - description: A human-readable description of the status of this operation. - example: Successfully assigned default/my-pod to node-1 - source: - $ref: '#/components/schemas/EventSource' - firstTimestamp: - type: string - format: date-time - description: The time at which the event was first recorded. - lastTimestamp: - type: string - format: date-time - description: The time at which the most recent occurrence of this event - was recorded. - count: - type: integer - format: int32 - description: The number of times this event has occurred. - type: - type: string - description: Type of this event (Normal, Warning), new types could be added - in the future. - example: Normal - eventTime: - type: string - format: date-time - nullable: true - description: MicroTime is version of Time with microsecond level precision. - reportingComponent: - type: string - example: kubelet - reportingInstance: - type: string - example: node-1 - ObjectMeta: - type: object - properties: - name: - type: string - namespace: - type: string - uid: - type: string - resourceVersion: - type: string - creationTimestamp: - type: string - format: date-time - ObjectReference: - type: object - properties: - kind: - type: string - namespace: - type: string - name: - type: string - uid: - type: string - apiVersion: - type: string - resourceVersion: - type: string - EventSource: - type: object - properties: - component: - type: string - host: - type: string - LogsResponseObject: - type: object - properties: - id: - type: string - description: Identifier for the log entry (if provided by the stream). - type: - type: string - description: Type of the log entry (e.g., 'stdout', 'stderr'). - data: - type: string - description: The actual log line content. - time: - type: string - format: date-time - description: Timestamp of the log entry. - GetAllApiResourcesResponse: - type: object - properties: - apiResources: - type: array - items: - $ref: '#/components/schemas/K8sApiResource' - allowedAll: - type: boolean - description: Whether all API resources are allowed for this user. - example: true - K8sApiResource: - type: object - properties: - gvk: - $ref: '#/components/schemas/GroupVersionKind' - namespaced: - type: boolean - description: Whether this API resource is namespace-scoped or cluster-scoped. - example: true - GroupVersionKind: - type: object - properties: - group: - type: string - description: Group of the API resource. - example: apps - version: - type: string - description: Version of the API resource. - example: v1 - kind: - type: string - description: Kind of the API resource. - example: Deployment - required: - - group - - version - - kind - ClusterResourceListResponse: - type: object - description: Represents a list of resources with dynamic headers and corresponding - data. - properties: - headers: - type: array - items: - type: string - description: An array of strings representing the column headers for the - resource list. - example: - - NAME - - NAMESPACE - - KIND - - AGE - data: - type: array - items: - type: object - additionalProperties: - type: string - description: 'An array of objects. Each object represents a resource, - and its keys correspond to the ''headers''. The values are the resource''s - data for those headers. - - ' - example: - - NAME: my-pod-1 - NAMESPACE: default - KIND: Pod - AGE: 2d - - NAME: my-service-abc - NAMESPACE: kube-system - KIND: Service - AGE: 10h - RotatePodRequest: - type: object - properties: - clusterId: - type: number - description: ID of the cluster where resources reside. - example: 1 - resources: - type: array - items: - type: object - properties: - groupVersionKind: - $ref: '#/components/schemas/GroupVersionKind' - namespace: - type: string - description: Namespace of the resource. - example: production - name: - type: string - description: Name of the resource (e.g., Deployment, StatefulSet name). - example: my-app-deployment - required: - - name - - groupVersionKind - - namespace - required: - - clusterId - - resources - RotatePodResponse: - type: object - properties: - containsError: - type: boolean - description: True if any error occurred during the rotation of one or more - pods. - example: false - responses: - type: array - items: - type: object - properties: - groupVersionKind: - $ref: '#/components/schemas/GroupVersionKind' - namespace: - type: string - description: Namespace of the resource. - name: - type: string - description: Name of the resource. - errorResponse: - type: string - nullable: true - description: Error message if rotation failed for this specific resource. - Otherwise null. - example: failed to find resource - ApplyResourcesRequest: - type: object - properties: - clusterId: - type: number - description: ID of the cluster where resources will be applied. - example: 1 - manifest: - type: string - description: 'A string containing one or more Kubernetes resource manifests, - separated by ''---''. - - ' - example: "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: my-cm\ndata:\n\ - \ key: value\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n\ - \ name: my-app\nspec:\n replicas: 1\n selector:\n matchLabels:\n\ - \ app: my-app\n template:\n metadata:\n labels:\n \ - \ app: my-app\n spec:\n containers:\n - name: nginx\n \ - \ image: nginx\n" - required: - - clusterId - - manifest - ApplyResourcesResponse: - type: object - properties: - kind: - type: string - description: Kind of the resource that was applied. - example: Deployment - name: - type: string - description: Name of the resource that was applied. - example: my-app - error: - type: string - nullable: true - description: Error message if applying this specific resource failed. Otherwise - null. - example: null - isUpdate: - type: boolean - description: True if the resource was updated, false if it was created (or - no change). - example: true - required: - - kind - - name - - isUpdate - AppWorkflowDto: - type: object - properties: - id: - type: integer - description: ID of the workflow. - readOnly: true - name: - type: string - description: Name of the workflow. - appId: - type: integer - description: ID of the application this workflow belongs to. - tree: - type: array - items: - $ref: '#/components/schemas/AppWorkflowMappingDto' - AppWorkflowMappingDto: - type: object - properties: - id: - type: integer - description: ID of the workflow mapping. - readOnly: true - appWorkflowId: - type: integer - description: ID of the parent application workflow. - type: - type: string - description: Type of the component (e.g., CI_PIPELINE, CD_PIPELINE). - componentId: - type: integer - description: ID of the component (e.g., CiPipelineId, CdPipelineId). - parentId: - type: integer - description: ID of the parent component in the workflow tree. - parentType: - type: string - description: Type of the parent component in the workflow tree. - deploymentAppDeleteRequest: - type: boolean - description: Indicates if a deployment app delete request is associated. - isLast: - type: boolean - description: Indicates if this is the last node in its branch of the tree. - GitOpsConfigDto: - type: object - properties: - id: - type: integer - description: GitOps Id (null for new configuration) - provider: - type: string - description: Gitops provider - example: github,gitlabs - username: - type: string - description: Username of GitOps provider - token: - type: string - description: Authentication token of GitOps provider - gitLabGroupId: - type: string - description: Group Id of gitLab - gitHubOrgId: - type: string - description: Group Id of gitHub - host: - type: string - description: Host of GitOps provider - active: - type: boolean - azureProjectName: - type: string - description: Project Name of Azure - userId: - type: integer - description: User Id of GitOps provider - DetailedError: - type: object - properties: - successfulStages: - type: array - items: - type: string - description: All successful stages - validatedOn: - type: string - description: Timestamp of validation - stageErrorMap: - type: array - items: - type: object - properties: - stage: - type: string - error: - type: string - description: map of stage and their respective errors - NotificationSetting: - type: object - required: - - configName - properties: - id: - type: integer - description: Unique id - configName: - type: string - description: Unique name of group - appId: - type: integer - description: app id - envId: - type: integer - description: env id - pipelineIds: - type: array - items: - type: integer - eventTypeIds: - type: array - items: - type: integer - pipelineType: - type: string - description: pipeline type CI or CD - providers: - type: array - items: - $ref: '#/components/schemas/providers' - description: role filters objects - providers: - type: object - required: - - dest - properties: - dest: - type: string - description: channel destination name - rule: - type: string - description: rule - configId: - type: integer - description: config id - NotificationConfig: - type: object - required: - - channel - properties: - channel: - type: string - description: channel type - enum: - - slack - - ses - configs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - NotificationConfigResponse: - type: object - properties: - slackConfigs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - sesConfigs: - type: array - items: - $ref: '#/components/schemas/configs' - description: config holds for either slack or ses - configs: - type: object - required: - - type - - configName - properties: - id: - type: integer - description: unique id for config either slack or ses on response or update - only - type: - type: string - description: channel destination type, slack or ses - configName: - type: string - description: configName - secretKey: - type: string - description: secretKey, only in case of ses - accessKey: - type: string - description: accessKey, only in case of ses - fromEmail: - type: string - description: fromEmail, only in case of ses - region: - type: string - description: region, only in case of ses - webhookUrl: - type: string - description: webhook url, only fill in case of type is slack - teamId: - type: integer - description: project id, only fill in case of type is slack - userId: - type: integer - description: project id, only fill in case of type is slack - entity: - type: object - properties: - id: - type: integer - description: it contains entity id - name: - type: string - description: it contains entity name - HistoryComponentDetailDto: - type: object - properties: - values: - type: array - items: - $ref: '#/components/schemas/HistoryComponentValuesDto' - codeEditorValue: - type: object - properties: - displayName: - type: string - value: - type: string - HistoryComponentValuesDto: - type: object - properties: - fieldName: - type: object - properties: - displayName: - type: string - value: - type: string - HistoryComponentListDto: - type: object - properties: - id: - type: integer - deployedOn: - type: string - format: timestamp - deployedBy: - type: string - deploymentStatus: - type: string - HistoryConfigurationListDto: - type: array - items: - $ref: '#/components/schemas/HistoryConfiguration' - HistoryConfiguration: - type: object - properties: - id: - type: integer - name: - type: string - enum: - - DEPLOYMENT_TEMPLATE - - CONFIGMAP - - SECRET - - PIPELINE_STRATEGY - childList: - type: array - items: - type: string - requestBodies: - SSOLoginDto: - description: SSO Login Configuration object - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/SSOLoginDto' - UserInfo: - description: User Information object - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UserInfo' - RoleGroup: - description: Role Group object - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - BulkDeleteRequest: - description: Request for bulk deletion of items. - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkDeleteRequest' - responses: - SSOLoginConfigResponse: - description: Response for SSO Login Configuration. - content: - application/json: - schema: - $ref: '#/components/schemas/SSOLoginDto' - UserInfoResponse: - description: Response containing User Information. - content: - application/json: - schema: - $ref: '#/components/schemas/UserInfo' - UserListingResponse: - description: Paginated list of users. - content: - application/json: - schema: - type: object - properties: - users: - type: array - items: - $ref: '#/components/schemas/UserInfo' - totalCount: - type: integer - format: int32 - RoleGroupResponse: - description: Response containing Role Group information. - content: - application/json: - schema: - $ref: '#/components/schemas/RoleGroup' - RoleGroupListingResponse: - description: Paginated list of role groups. - content: - application/json: - schema: - type: object - properties: - roleGroups: - type: array - items: - $ref: '#/components/schemas/RoleGroup' - totalCount: - type: integer - format: int32 - GenericSuccess: - description: Generic success response. - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - example: true - BadRequest: - description: Bad request. Invalid input parameters. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - Unauthorized: - description: Unauthorized. User is not logged in or token is invalid. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - Forbidden: - description: Forbidden. User does not have permission. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - NotAcceptable: - description: Not Acceptable. Request cannot be processed. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - InternalServerError: - description: Internal server error. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - parameters: - PathId: - name: id - in: path - required: true - description: Identifier (typically integer ID). - schema: - type: integer - format: int32 - SearchKeyQuery: - name: searchKey - in: query - required: false - description: Search term. - schema: - type: string - SortOrderQuery: - name: sortOrder - in: query - required: false - description: Sort order (ASC or DESC). - schema: - type: string - enum: - - ASC - - DESC - SortByQueryUser: - name: sortBy - in: query - required: false - description: Field to sort users by (e.g., email_id, last_login). - schema: - type: string - enum: - - email_id - - last_login - SortByQueryRoleGroup: - name: sortBy - in: query - required: false - description: Field to sort role groups by (e.g., name). - schema: - type: string - enum: - - name - OffsetQuery: - name: offset - in: query - required: false - description: Offset for pagination. - schema: - type: integer - format: int32 - minimum: 0 - SizeQuery: - name: size - in: query - required: false - description: Number of items per page. - schema: - type: integer - format: int32 - minimum: 1 - default: 20 -x-tagGroups: -- name: Common Devtron automation APIs - tags: - - Metadata - - Jobs - - Helm Charts - - List Applications - - Applications - - Labels - - bulk_other - - BulkUpdate - - SSO Configuration - - User Management - - Role Group Management - - RBAC - - Authentication - - Policy Management - - Cache Management - - Cluster Environment - - Cluster Management - - Environment Management - - Change Chart - - Clone Workflow - - Deployment History - - K8s Resource - - Workflow Management - - Devtron Server version - - GitOps Validation - - Notifications diff --git a/specs/user_policy.yaml b/specs/user_policy.yaml deleted file mode 100644 index 7c8691acb5..0000000000 --- a/specs/user_policy.yaml +++ /dev/null @@ -1,404 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Devtron -servers: - - url: http://petstore.swagger.io/api -paths: - /user/v2: - get: - summary: Returns all users - description: all the template users - operationId: GetAllV2 - parameters: - - - name: searchKey - in: query - description: Search key for user listing - required: false - schema: - type: string - - - name: sortOrder - in: query - description: Sorting order (ASC or DESC) - required: false - schema: - type: string - enum: - - ASC - - DESC - - - name: sortBy - in: query - description: Sorting by email_id or last_login - required: false - schema: - type: string - enum: - - email_id - - last_login - - - name: offset - in: query - description: Offset for paginating the results - required: false - schema: - type: integer - - - name: size - in: query - description: Size of the result set - required: false - schema: - type: integer - - - name: showAll - in: query - description: Show all users (boolean) - required: false - schema: - type: boolean - - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/UserListingResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /user: - get: - summary: Returns all users - description: all the template users - operationId: findAllUsers - deprecated: true # Marking the operation as deprecated - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/AllUsers' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new User - description: create user api, with multiple environment in one row of policy, plus chart group additional type of policy. - operationId: addUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: create user response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: update a user - description: Updates a new user in the system - operationId: updateUser - requestBody: - description: json as request body - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: user response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /user/email: - get: - summary: search a user list by name - description: search user detail by name - operationId: findUserByEmail - parameters: - - name: email-id - in: query - description: ID of pet to delete - required: true - schema: - type: string - responses: - '200': - description: list response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /user/{id}: - get: - summary: Returns user detail with role filter - description: all the template group policies - operationId: findUserById - parameters: - - name: id - in: path - description: ID of user id - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: user detail response - content: - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /orchestrator/user/bulk: - delete: - summary: Delete multiple users in bulk - description: Deletes user entities in bulk based on the provided criteria. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/BulkDeleteRequest' - responses: - '200': - description: Successfully deleted users - content: - application/json: - schema: - type: boolean - '400': - description: Bad request, invalid input - '404': - description: Users not found - '500': - description: Internal server error - - -components: - schemas: - User: - type: object - required: - - email_id - properties: - id: - type: integer - description: Unique id of user - email_id: - type: string - description: Unique valid email-id of user, comma separated emails ids for multiple users - userRoleGroups: - type: array - items: - $ref: '#/components/schemas/UserRoleGroupItem' - roleFilters: - type: array - items: - $ref: '#/components/schemas/roleFilter' - description: role filters objects - UserListingResponse: - type: object - properties: - users: - items: - $ref: '#/components/schemas/AllUsersV2' - description: role filters objects - totalCount: - type: integer - description: total number of results satisfying the conditions - - AllUsers: - type: object - required: - - email_id - properties: - id: - type: integer - description: Unique id of user - email_id: - type: string - description: Unique valid email-id of user, comma separated emails ids for multiple users - groups: - type: array - items: - type: string - roleFilters: - type: array - items: - $ref: '#/components/schemas/emptyRoleFilter' - description: role filters objects - lastLogin: - type: string - format: date-time - description: user last login time - AllUsersV2: - type: object - required: - - email_id - properties: - id: - type: integer - description: Unique id of user - email_id: - type: string - description: Unique valid email-id of user, comma separated emails ids for multiple users - userRoleGroups: - type: array - items: - $ref: '#/components/schemas/UserRoleGroupItem' - lastLogin: - type: string - format: date-time - description: user last login time - - emptyRoleFilter: - type: object - required: - - action - - - roleFilter: - type: object - required: - - action - properties: - entity: - type: string - description: global entity name, i.e chart-group, git, docker, cluster etc. if this key is present than field team, application and environment are ignored, here empty entity means Devtron apps permission. - enum: - - chart-group - - docker - - git - - cluster - - notification - team: - type: string - description: team name - entityName: - type: string - description: global entity name item name, i.e chart-group ("abc"), git("devtron-gt") etc. - environment: - type: string - description: comma saperated environments names. - action: - type: string - description: action is type of role, i.e manager, admin, trigger, view, etc. - accessType: - type: string - enum: ["", "helm-app"] - description: accessType difine permission type "devtron-app"=devtron app work flow, "helm-app"=helm app work flow. based on this flag data categoriesed into devtron and helm permission tabs in user auth section. - BulkDeleteRequest: - type: object - properties: - ids: - type: array - items: - type: integer - format: int32 - description: Array of user IDs to be deleted - listingRequest: - $ref: '#/components/schemas/ListingRequest' - ListingRequest: - type: object - properties: - searchKey: - type: string - description: Search key for filtering - sortOrder: - type: string - enum: - - ASC - - DESC - description: Sorting order - sortBy: - type: string - enum: - - email_id - - last_login - description: Attribute to sort by - offset: - type: integer - format: int32 - description: Starting index for fetching listings - size: - type: integer - format: int32 - description: Number of listings to fetch - showAll: - type: boolean - description: Show all listings - UserRoleGroupItem: - type: object - properties: - roleGroup: - $ref: '#/components/schemas/RoleGroup' - RoleGroup: - type: object - properties: - id: - type: integer - format: int32 - description: The ID of the role group - name: - type: string - description: The name of the role group - description: - type: string - description: The description of the role group - - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message \ No newline at end of file diff --git a/specs/webhook/webhook_helm-api-spec.yaml b/specs/webhook/webhook_helm-api-spec.yaml index 1a6194c169..5fd514823b 100644 --- a/specs/webhook/webhook_helm-api-spec.yaml +++ b/specs/webhook/webhook_helm-api-spec.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: version: 1.0.0 - title: Devtron Labs + title: Helm Webhook Management paths: /orchestrator/webhook/helm/app: post: diff --git a/specs/workflow/workflow-stage-status.internal.yaml b/specs/workflow/workflow-stage-status.internal.yaml index 999e0af05a..f44dccedfb 100644 --- a/specs/workflow/workflow-stage-status.internal.yaml +++ b/specs/workflow/workflow-stage-status.internal.yaml @@ -3,7 +3,7 @@ info: title: Workflow Status API for showing execution stage version: 1.0.0 paths: - /workflow/status: #this is not real API, only for sharing purpose + /orchestrator/workflow/status: #this is not real API, only for sharing purpose get: summary: Get Workflow Status responses: diff --git a/wire_gen.go b/wire_gen.go index 1661261a59..08a1f2420e 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -471,7 +471,7 @@ func InitializeApp() (*App, error) { transactionUtilImpl := sql.NewTransactionUtilImpl(db) chartRepositoryImpl := chartRepoRepository.NewChartRepository(db, transactionUtilImpl) envConfigOverrideRepositoryImpl := chartConfig.NewEnvConfigOverrideRepository(db) - envConfigOverrideReadServiceImpl := read7.NewEnvConfigOverrideReadServiceImpl(envConfigOverrideRepositoryImpl, sugaredLogger) + envConfigOverrideReadServiceImpl := read7.NewEnvConfigOverrideReadServiceImpl(sugaredLogger, environmentRepositoryImpl, envConfigOverrideRepositoryImpl) chartRefRepositoryImpl := chartRepoRepository.NewChartRefRepositoryImpl(db) deploymentConfigReadServiceImpl := read8.NewDeploymentConfigReadServiceImpl(sugaredLogger, repositoryImpl, environmentVariables, chartRepositoryImpl, pipelineRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, envConfigOverrideReadServiceImpl) deploymentConfigServiceImpl := common.NewDeploymentConfigServiceImpl(repositoryImpl, sugaredLogger, chartRepositoryImpl, pipelineRepositoryImpl, appRepositoryImpl, installedAppReadServiceEAImpl, environmentVariables, envConfigOverrideReadServiceImpl, environmentRepositoryImpl, chartRefRepositoryImpl, deploymentConfigReadServiceImpl, acdAuthConfig)