diff --git a/pkg/apis/output.go b/pkg/apis/output.go index 9d760181e1..f583bacf85 100644 --- a/pkg/apis/output.go +++ b/pkg/apis/output.go @@ -16,6 +16,8 @@ package apis import ( "time" + + "yunion.io/x/onecloud/pkg/httperrors" ) type ModelBaseDetails struct { @@ -26,7 +28,7 @@ type ModelBaseDetails struct { CanDelete bool `json:"can_delete"` // 资源不能删除的原因 - DeleteFailReason string `json:"delete_fail_reason"` + DeleteFailReason httperrors.Error `json:"delete_fail_reason"` // 资源是否可以更新, 若为false,update_fail_reason会返回资源不能删除的原因 // example: true diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 747d0e58ec..ce99b26710 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -778,7 +778,7 @@ func getModelExtraDetails(item IModel, ctx context.Context, showReason bool) api if err != nil { out.CanDelete = false if showReason { - out.DeleteFailReason = err.Error() + out.DeleteFailReason = httperrors.NewErrorFromGeneralError(ctx, err) } } err = item.ValidateUpdateCondition(ctx) diff --git a/pkg/httperrors/httperrors.go b/pkg/httperrors/httperrors.go index fb46899411..2e213488f6 100644 --- a/pkg/httperrors/httperrors.go +++ b/pkg/httperrors/httperrors.go @@ -75,16 +75,29 @@ func SetHTTPRedirectLocationHeader(w http.ResponseWriter, location string) { w.Header().Set("Location", location) } -func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCode int, class string, err httputils.Error) { - if statusCode >= 300 && statusCode <= 400 { - SetHTTPRedirectLocationHeader(w, msg) +type Error struct { + Code int `json:"code"` + Class string `json:"class"` + Details string `json:"details"` +} + +func NewErrorFromJCError(ctx context.Context, je *httputils.JSONClientError) Error { + err := Error{ + Code: je.Code, + Class: je.Class, + Details: formatDetails(ctx, je.Data, je.Details), } + return err +} - // 需要在调用w.WriteHeader方法之前,设置header才能生效 - SendHTTPErrorHeader(w, statusCode) +func NewErrorFromGeneralError(ctx context.Context, e error) Error { + je := NewGeneralError(e) + return NewErrorFromJCError(ctx, je) +} +func formatDetails(ctx context.Context, errData httputils.Error, msg string) string { var details string - if err.Id == "" { + if errData.Id == "" { details = msg } else { var ( @@ -96,16 +109,30 @@ func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCod } else { lang = language.English } - a := make([]interface{}, len(err.Fields)) - for i := range err.Fields { - a[i] = err.Fields[i] + a := make([]interface{}, len(errData.Fields)) + for i := range errData.Fields { + a[i] = errData.Fields[i] } - details = P(lang, err.Id, a...) + details = P(lang, errData.Id, a...) } - body := jsonutils.NewDict() - body.Add(jsonutils.NewInt(int64(statusCode)), "code") - body.Add(jsonutils.NewString(class), "class") - body.Add(jsonutils.NewString(details), "details") + return details +} + +func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCode int, class string, errData httputils.Error) { + details := formatDetails(ctx, errData, msg) + if statusCode >= 300 && statusCode <= 400 { + SetHTTPRedirectLocationHeader(w, details) + } + + // 需要在调用w.WriteHeader方法之前,设置header才能生效 + SendHTTPErrorHeader(w, statusCode) + + err := Error{ + Code: statusCode, + Class: class, + Details: details, + } + body := jsonutils.Marshal(err) w.Write([]byte(body.String())) log.Errorf("Send error %s", details) if statusCode >= 500 { diff --git a/pkg/monitor/models/commonalert.go b/pkg/monitor/models/commonalert.go index 0d9df4b06d..22de46a156 100644 --- a/pkg/monitor/models/commonalert.go +++ b/pkg/monitor/models/commonalert.go @@ -368,17 +368,18 @@ func (man *SCommonAlertManager) FetchCustomizeColumns( alertRows := man.SAlertManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) for i := range rows { rows[i].AlertDetails = alertRows[i] - rows[i], _ = objs[i].(*SCommonAlert).GetMoreDetails(rows[i]) + rows[i], _ = objs[i].(*SCommonAlert).GetMoreDetails(ctx, rows[i]) } return rows } -func (alert *SCommonAlert) validateDeleteCondition(out *monitor.CommonAlertDetails) { +func (alert *SCommonAlert) validateDeleteCondition(ctx context.Context, out *monitor.CommonAlertDetails) { alert_type := alert.getAlertType() switch alert_type { case monitor.CommonAlertSystemAlertType: + je := httperrors.NewInputParameterError("Cannot delete system alert") out.CanDelete = false - out.DeleteFailReason = httperrors.NewInputParameterError("Cannot delete system alert").Error() + out.DeleteFailReason = httperrors.NewErrorFromJCError(ctx, je) default: } } @@ -398,8 +399,8 @@ func (alert *SCommonAlert) AllowDeleteItem(ctx context.Context, userCred mcclien } } -func (alert *SCommonAlert) GetMoreDetails(out monitor.CommonAlertDetails) (monitor.CommonAlertDetails, error) { - alert.validateDeleteCondition(&out) +func (alert *SCommonAlert) GetMoreDetails(ctx context.Context, out monitor.CommonAlertDetails) (monitor.CommonAlertDetails, error) { + alert.validateDeleteCondition(ctx, &out) var err error alertNotis, err := alert.GetNotifications() diff --git a/pkg/monitor/subscriptionmodel/subcription.go b/pkg/monitor/subscriptionmodel/subcription.go index 3a3644fb1c..d30e9e85dc 100644 --- a/pkg/monitor/subscriptionmodel/subcription.go +++ b/pkg/monitor/subscriptionmodel/subcription.go @@ -117,7 +117,7 @@ func (self *SSubscriptionManager) PerformWrite(ctx context.Context, userCred mcc sysAlerts := self.GetSystemAlerts() for _, sysalert := range sysAlerts { details := monitor.CommonAlertDetails{} - details, err := sysalert.GetMoreDetails(details) + details, err := sysalert.GetMoreDetails(ctx, details) if err != nil { log.Errorln("sysalert getMoreDetails err", err) continue