diff --git a/pkg/cloudcommon/policy/policy.go b/pkg/cloudcommon/policy/policy.go index 3508d26858..0aeaf03114 100644 --- a/pkg/cloudcommon/policy/policy.go +++ b/pkg/cloudcommon/policy/policy.go @@ -81,6 +81,7 @@ func fetchPolicies() (map[string]rbacutils.SRbacPolicy, map[string]rbacutils.SRb params := jsonutils.NewDict() params.Add(jsonutils.NewInt(2048), "limit") params.Add(jsonutils.NewInt(int64(offset)), "offset") + modules.Policies.SetEnableFilter(false) result, err := modules.Policies.ResourceManager.List(s, params) if err != nil { diff --git a/pkg/mcclient/modules/cache.go b/pkg/mcclient/modules/cache.go new file mode 100644 index 0000000000..ec4cec8fb4 --- /dev/null +++ b/pkg/mcclient/modules/cache.go @@ -0,0 +1,154 @@ +package modules + +import ( + "fmt" + "sync" + "time" + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" +) + +const ( + cacheValidPerviod = 1 * time.Minute +) + +type tCachedStatus int + +const ( + cacheInit = tCachedStatus(0) + cacheFetching = tCachedStatus(1) + cacheComplete = tCachedStatus(2) +) + +type sCachedResource struct { + key string + cachedAt time.Time + lock *sync.Cond + object jsonutils.JSONObject + status tCachedStatus +} + +type sCachedResourceManager struct { + lock *sync.Mutex + resourceCache map[string]sCachedResource +} + +var cachedResourceManager *sCachedResourceManager + +func init() { + cachedResourceManager = &sCachedResourceManager{ + lock: &sync.Mutex{}, + resourceCache: make(map[string]sCachedResource), + } +} + +func cacheKey(manager Manager, idstr string) string { + return fmt.Sprintf("%s-%s", manager.KeyString(), idstr) +} + +func (cm *sCachedResourceManager) getLocked(key string) *sCachedResource { + cm.lock.Lock() + defer cm.lock.Unlock() + + return cm.getUnlocked(key, true) +} + +func (cm *sCachedResourceManager) getUnlocked(key string, alloc bool) *sCachedResource { + _, ok := cm.resourceCache[key] + if !ok { + if !alloc { + return nil + } + cm.resourceCache[key] = sCachedResource{ + key: key, + lock: sync.NewCond(&sync.Mutex{}), + status: cacheInit, + } + } + obj := cm.resourceCache[key] + return &obj +} + +func (cm *sCachedResourceManager) getById(manager Manager, session *mcclient.ClientSession, idstr string) (jsonutils.JSONObject, error) { + key := cacheKey(manager, idstr) + cacheObj := cm.getLocked(key) + + obj := cacheObj.tryGet() + if obj != nil { + return obj, nil + } + + obj, err := manager.GetById(session, idstr, nil) + if err != nil { + cacheObj.notifyFail() + return nil, err + } + cacheObj.notifyComplete(obj) + return obj, nil +} + +func (cr *sCachedResource) isValid() bool { + now := time.Now() + return cr.status == cacheComplete && now.Sub(cr.cachedAt) <= cacheValidPerviod && cr.object != nil +} + +func (cr *sCachedResource) tryGet() jsonutils.JSONObject { + cr.lock.L.Lock() + defer cr.lock.L.Unlock() + + if cr.isValid() { + return cr.object + } + + for cr.status == cacheFetching { + cr.lock.Wait() + } + + if cr.status == cacheComplete { + return cr.object + } + + cr.status = cacheFetching + + return nil +} + +func (cr *sCachedResource) notifyFail() { + cr.lock.L.Lock() + defer cr.lock.L.Unlock() + + cr.status = cacheInit + cr.object = nil + + cr.lock.Signal() +} + +func (cr *sCachedResource) notifyComplete(obj jsonutils.JSONObject) { + cr.lock.L.Lock() + defer cr.lock.L.Unlock() + + cr.status = cacheComplete + cr.object = obj + cr.cachedAt = time.Now() + + time.AfterFunc(cacheValidPerviod, func() { + cachedResourceManager.lock.Lock() + defer cachedResourceManager.lock.Unlock() + + cacheObj := cachedResourceManager.getUnlocked(cr.key, false) + if cacheObj == nil { + return + } + + cacheObj.lock.L.Lock() + defer cacheObj.lock.L.Unlock() + + if !cacheObj.isValid() { + delete(cachedResourceManager.resourceCache, cr.key) + } + + }) + + cr.lock.Signal() +} diff --git a/pkg/mcclient/modules/filter.go b/pkg/mcclient/modules/filter.go new file mode 100644 index 0000000000..e73aff4afc --- /dev/null +++ b/pkg/mcclient/modules/filter.go @@ -0,0 +1,28 @@ +package modules + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/mcclient" +) + +func (this *ResourceManager) filterSingleResult(session *mcclient.ClientSession, result jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if this.enableFilter && this.readFilter != nil { + return this.readFilter(session, result) + } + return result, nil +} + +func (this *ResourceManager) filterListResults(session *mcclient.ClientSession, results *ListResult) (*ListResult, error) { + if this.enableFilter && this.readFilter != nil { + for i := 0; i < len(results.Data); i += 1 { + val, err := this.readFilter(session, results.Data[i]) + if err == nil { + results.Data[i] = val + } else { + log.Warningf("readFilter fail for %s: %s", results.Data[i], err) + } + } + } + return results, nil +} diff --git a/pkg/mcclient/modules/joint.go b/pkg/mcclient/modules/joint.go index 53e76815ae..c818359e12 100644 --- a/pkg/mcclient/modules/joint.go +++ b/pkg/mcclient/modules/joint.go @@ -30,9 +30,14 @@ func (this *JointResourceManager) Get(s *mcclient.ClientSession, mid, sid string path = fmt.Sprintf("%s?%s", path, qs) } } - return this._get(s, path, this.Keyword) + result, err := this._get(s, path, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(s, result) } +/* func (this *JointResourceManager) List(s *mcclient.ClientSession, params jsonutils.JSONObject) (*ListResult, error) { path := fmt.Sprintf("/%s", this.KeyString()) if params != nil { @@ -43,6 +48,7 @@ func (this *JointResourceManager) List(s *mcclient.ClientSession, params jsonuti } return this._list(s, path, this.KeywordPlural) } +*/ func (this *JointResourceManager) ListDescendent(s *mcclient.ClientSession, mid string, params jsonutils.JSONObject) (*ListResult, error) { path := fmt.Sprintf("/%s/%s/%s", this.Master.KeyString(), url.PathEscape(mid), this.Slave.KeyString()) @@ -52,7 +58,11 @@ func (this *JointResourceManager) ListDescendent(s *mcclient.ClientSession, mid path = fmt.Sprintf("%s?%s", path, qs) } } - return this._list(s, path, this.KeywordPlural) + results, err := this._list(s, path, this.KeywordPlural) + if err != nil { + return nil, err + } + return this.filterListResults(s, results) } func (this *JointResourceManager) ListDescendent2(s *mcclient.ClientSession, sid string, params jsonutils.JSONObject) (*ListResult, error) { @@ -67,7 +77,11 @@ func (this *JointResourceManager) ListAscendent(s *mcclient.ClientSession, mid s path = fmt.Sprintf("%s?%s", path, qs) } } - return this._list(s, path, this.KeywordPlural) + results, err := this._list(s, path, this.KeywordPlural) + if err != nil { + return nil, err + } + return this.filterListResults(s, results) } /* func (this *JointResourceManager) Exists(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -83,7 +97,11 @@ func (this *JointResourceManager) ListAscendent(s *mcclient.ClientSession, mid s func (this *JointResourceManager) Attach(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s/%s/%s", this.Master.KeyString(), url.PathEscape(mid), this.Slave.KeyString(), url.PathEscape(sid)) - return this._post(s, path, this.params2Body(params), this.Keyword) + result, err := this._post(s, path, this.params2Body(s, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(s, result) } func (this *JointResourceManager) BatchAttach(s *mcclient.ClientSession, mid string, sids []string, params jsonutils.JSONObject) []SubmitResult { @@ -100,7 +118,11 @@ func (this *JointResourceManager) BatchAttach2(s *mcclient.ClientSession, mid st func (this *JointResourceManager) Detach(s *mcclient.ClientSession, mid, sid string) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s/%s/%s", this.Master.KeyString(), url.PathEscape(mid), this.Slave.KeyString(), url.PathEscape(sid)) - return this._delete(s, path, nil, this.Keyword) + result, err := this._delete(s, path, nil, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(s, result) } func (this *JointResourceManager) BatchDetach(s *mcclient.ClientSession, mid string, sids []string) []SubmitResult { @@ -117,10 +139,18 @@ func (this *JointResourceManager) BatchDetach2(s *mcclient.ClientSession, mid st func (this *JointResourceManager) Update(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s/%s/%s", this.Master.KeyString(), url.PathEscape(mid), this.Slave.KeyString(), url.PathEscape(sid)) - return this._put(s, path, this.params2Body(params), this.Keyword) + result, err := this._put(s, path, this.params2Body(s, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(s, result) } func (this *JointResourceManager) Patch(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s/%s/%s", this.Master.KeyString(), url.PathEscape(mid), this.Slave.KeyString(), url.PathEscape(sid)) - return this._patch(s, path, this.params2Body(params), this.Keyword) + result, err := this._patch(s, path, this.params2Body(s, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(s, result) } diff --git a/pkg/mcclient/modules/mod_endpoints.go b/pkg/mcclient/modules/mod_endpoints.go index 180245dd0d..12c52331e4 100644 --- a/pkg/mcclient/modules/mod_endpoints.go +++ b/pkg/mcclient/modules/mod_endpoints.go @@ -1,10 +1,33 @@ package modules +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" +) + var ( Endpoints ResourceManager EndpointsV3 ResourceManager ) +func endpointsV3ReadFilter(s *mcclient.ClientSession, result jsonutils.JSONObject) (jsonutils.JSONObject, error) { + resultDict := result.(*jsonutils.JSONDict) + serviceId, _ := result.GetString("service_id") + service, err := cachedResourceManager.getById(&ServicesV3, s, serviceId) + // service, err := ServicesV3.GetById(s, serviceId, nil) + if err == nil { + serviceType, _ := service.Get("type") + if serviceType != nil { + resultDict.Add(serviceType, "service_type") + } + serviceName, _ := service.Get("name") + if serviceName != nil { + resultDict.Add(serviceName, "service_name") + } + } + return resultDict, nil +} + func init() { Endpoints = NewIdentityManager("endpoint", "endpoints", []string{}, @@ -17,8 +40,10 @@ func init() { EndpointsV3 = NewIdentityV3Manager("endpoint", "endpoints", []string{}, []string{"ID", "Region_ID", - "Service_ID", "name", + "Service", "Service_ID", "Service_Name", "Service_Type", "URL", "Interface", "Enabled"}) + EndpointsV3.SetReadFilter(endpointsV3ReadFilter) + register(&EndpointsV3) } diff --git a/pkg/mcclient/modules/mod_policies.go b/pkg/mcclient/modules/mod_policies.go index 1cf6f6b133..877dbc5ae9 100644 --- a/pkg/mcclient/modules/mod_policies.go +++ b/pkg/mcclient/modules/mod_policies.go @@ -1,11 +1,8 @@ package modules import ( - "fmt" - "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/util/httputils" ) type SPolicyManager struct { @@ -14,7 +11,7 @@ type SPolicyManager struct { var Policies SPolicyManager -func translateS2C(s jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func policyReadFilter(session *mcclient.ClientSession, s jsonutils.JSONObject) (jsonutils.JSONObject, error) { ss := s.(*jsonutils.JSONDict) ret := ss.CopyIncludes("id", "type") blobStr, err := ss.GetString("blob") @@ -29,7 +26,7 @@ func translateS2C(s jsonutils.JSONObject) (jsonutils.JSONObject, error) { return ret, nil } -func translateC2S(s jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func policyWriteFilter(session *mcclient.ClientSession, s jsonutils.JSONObject) (jsonutils.JSONObject, error) { ret := jsonutils.NewDict() if s.Contains("policy") { blobYaml, err := s.GetString("policy") @@ -52,92 +49,12 @@ func translateC2S(s jsonutils.JSONObject) (jsonutils.JSONObject, error) { return ret, nil } -func (pm *SPolicyManager) Get(s *mcclient.ClientSession, id string, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - result, err := pm.GetById(s, id, nil) - if err == nil { - return result, nil - } - jsonErr := err.(*httputils.JSONClientError) - if jsonErr.Code != 404 { - return nil, err - } - return pm.GetByName(s, id, query) -} - -func (pm *SPolicyManager) GetId(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (string, error) { - obj, err := pm.Get(s, id, params) - if err != nil { - return "", err - } - return obj.GetString("id") -} - -func (pm *SPolicyManager) GetById(s *mcclient.ClientSession, id string, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - result, err := pm.ResourceManager.GetById(s, id, query) - if err != nil { - return nil, err - } - return translateS2C(result) -} - -func (pm *SPolicyManager) GetByName(s *mcclient.ClientSession, name string, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(name), "type") - listResult, err := Policies.List(s, params) - if err != nil { - return nil, err - } - if listResult.Total == 1 { - return listResult.Data[0], nil - } else if listResult.Total == 0 { - return nil, &httputils.JSONClientError{Code: 404, Class: "NotFound", - Details: fmt.Sprintf("%d not found", name)} - } else { - return nil, &httputils.JSONClientError{Code: 409, Class: "Conflict", - Details: fmt.Sprintf("multiple %d found", name)} - } -} - -func (pm *SPolicyManager) Create(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - data, err := translateC2S(params) - if err != nil { - return nil, err - } - result, err := pm.ResourceManager.Create(s, data) - if err != nil { - return nil, err - } - return translateS2C(result) -} - -func (pm *SPolicyManager) Patch(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - data, err := translateC2S(params) - if err != nil { - return nil, err - } - result, err := pm.ResourceManager.Patch(s, id, data) - if err != nil { - return nil, err - } - return translateS2C(result) -} - -func (pm *SPolicyManager) List(s *mcclient.ClientSession, params jsonutils.JSONObject) (*ListResult, error) { - results, err := pm.ResourceManager.List(s, params) - if err != nil { - return nil, err - } - for i := 0; i < len(results.Data); i += 1 { - val, _ := translateS2C(results.Data[i]) - results.Data[i] = val - } - return results, nil -} - func init() { Policies = SPolicyManager{NewIdentityV3Manager("policy", "policies", []string{"id", "type", "policy"}, []string{})} + Policies.SetReadFilter(policyReadFilter).SetWriteFilter(policyWriteFilter).SetNameField("type") + register(&Policies) } diff --git a/pkg/mcclient/modules/resource.go b/pkg/mcclient/modules/resource.go index c1c0537cb4..65528750c4 100644 --- a/pkg/mcclient/modules/resource.go +++ b/pkg/mcclient/modules/resource.go @@ -9,14 +9,28 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/mcclient" ) +type TResourceFilter func(*mcclient.ClientSession, jsonutils.JSONObject) (jsonutils.JSONObject, error) + +const ( + DEFAULT_NAME_FIELD_NAME = "name" + DEFAULT_ID_FIELD_NAME = "id" +) + type ResourceManager struct { BaseManager context string Keyword string KeywordPlural string + + readFilter TResourceFilter + writeFilter TResourceFilter + enableFilter bool + nameFieldName string + idFieldName string } func (this *ResourceManager) KeyString() string { @@ -39,6 +53,42 @@ func (this *ResourceManager) URLPath() string { return strings.Replace(this.KeywordPlural, ":", "/", -1) } +func (this *ResourceManager) SetReadFilter(filter TResourceFilter) *ResourceManager { + this.readFilter = filter + this.enableFilter = true + return this +} + +func (this *ResourceManager) SetWriteFilter(filter TResourceFilter) *ResourceManager { + this.writeFilter = filter + this.enableFilter = true + return this +} + +func (this *ResourceManager) SetEnableFilter(enable bool) *ResourceManager { + this.enableFilter = enable + return this +} + +func (this *ResourceManager) SetNameField(fn string) *ResourceManager { + this.nameFieldName = fn + return this +} + +func (this *ResourceManager) getNameFieldName() string { + if len(this.nameFieldName) > 0 { + return this.nameFieldName + } + return DEFAULT_NAME_FIELD_NAME +} + +func (this *ResourceManager) getIdFieldName() string { + if len(this.idFieldName) > 0 { + return this.idFieldName + } + return DEFAULT_ID_FIELD_NAME +} + func (this *ResourceManager) ContextPath(ctxs []ManagerContext) string { segs := make([]string, 0) if len(this.context) > 0 { @@ -72,7 +122,11 @@ func (this *ResourceManager) GetByIdInContexts(session *mcclient.ClientSession, path = fmt.Sprintf("%s?%s", path, qs) } } - return this._get(session, path, this.Keyword) + obj, err := this._get(session, path, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, obj) } func (this *ResourceManager) GetByName(session *mcclient.ClientSession, name string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -91,7 +145,7 @@ func (this *ResourceManager) GetByNameInContexts(session *mcclient.ClientSession } else { paramsDict = jsonutils.NewDict() } - paramsDict.Add(jsonutils.NewString(name), "name") + paramsDict.Add(jsonutils.NewString(name), this.getNameFieldName()) results, e := this.ListInContexts(session, paramsDict, ctxs) if e != nil { return nil, e @@ -99,7 +153,12 @@ func (this *ResourceManager) GetByNameInContexts(session *mcclient.ClientSession if len(results.Data) == 0 { return nil, httperrors.NewNotFoundError("Name %s not found", name) } else if len(results.Data) == 1 { - return results.Data[0], nil + oname, _ := results.Data[0].GetString(this.getNameFieldName()) + if oname == name { + return results.Data[0], nil + } else { + return nil, httperrors.NewNotFoundError("Name %s not found", name) + } } else { return nil, httperrors.NewDuplicateNameError("name", name) } @@ -140,7 +199,7 @@ func (this *ResourceManager) GetIdInContexts(session *mcclient.ClientSession, id if e != nil { return "", e } - return obj.GetString("id") + return obj.GetString(this.getIdFieldName()) } func (this *ResourceManager) GetSpecific(session *mcclient.ClientSession, id string, spec string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -192,7 +251,11 @@ func (this *ResourceManager) ListInContexts(session *mcclient.ClientSession, par path = fmt.Sprintf("%s?%s", path, qs) } } - return this._list(session, path, this.KeywordPlural) + results, err := this._list(session, path, this.KeywordPlural) + if err != nil { + return nil, err + } + return this.filterListResults(session, results) } func (this *ResourceManager) Head(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -211,12 +274,24 @@ func (this *ResourceManager) HeadInContexts(session *mcclient.ClientSession, id path = fmt.Sprintf("%s?%s", path, qs) } } - return this._head(session, path, this.Keyword) + result, err := this._head(session, path, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } -func (this *ResourceManager) params2Body(params jsonutils.JSONObject) *jsonutils.JSONDict { +func (this *ResourceManager) params2Body(s *mcclient.ClientSession, params jsonutils.JSONObject) *jsonutils.JSONDict { body := jsonutils.NewDict() if params != nil { + if this.enableFilter && this.writeFilter != nil { + val, err := this.writeFilter(s, params) + if err == nil { + params = val + } else { + log.Warningf("writeFilter fail %s: %s", params, err) + } + } body.Add(params, this.Keyword) } return body @@ -232,7 +307,11 @@ func (this *ResourceManager) CreateInContext(session *mcclient.ClientSession, pa func (this *ResourceManager) CreateInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s", this.ContextPath(ctxs)) - return this._post(session, path, this.params2Body(params), this.Keyword) + result, err := this._post(session, path, this.params2Body(session, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } func (this *ResourceManager) BatchCreate(session *mcclient.ClientSession, params jsonutils.JSONObject, count int) []SubmitResult { @@ -245,7 +324,7 @@ func (this *ResourceManager) BatchCreateInContext(session *mcclient.ClientSessio func (this *ResourceManager) BatchCreateInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, count int, ctxs []ManagerContext) []SubmitResult { path := fmt.Sprintf("/%s", this.ContextPath(ctxs)) - body := this.params2Body(params) + body := this.params2Body(session, params) body.Add(jsonutils.NewInt(int64(count)), "count") ret := make([]SubmitResult, count) respbody, err := this._post(session, path, body, this.KeywordPlural) @@ -269,7 +348,15 @@ func (this *ResourceManager) BatchCreateInContexts(session *mcclient.ClientSessi } else { code, _ := json.Int("status") dat, _ := json.Get("body") - idstr, _ := json.GetString("id") + if this.enableFilter && this.readFilter != nil { + val, err := this.readFilter(session, dat) + if err != nil { + log.Warningf("readFilter fail for %s: %s", dat, err) + } else { + dat = val + } + } + idstr, _ := json.GetString(this.getIdFieldName()) ret[i] = SubmitResult{Status: int(code), Id: idstr, Data: dat} } } @@ -290,7 +377,11 @@ func (this *ResourceManager) PutInContext(session *mcclient.ClientSession, id st func (this *ResourceManager) PutInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s", this.ContextPath(ctxs), url.PathEscape(id)) - return this._put(session, path, this.params2Body(params), this.Keyword) + result, err := this._put(session, path, this.params2Body(session, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } func (this *ResourceManager) BatchUpdate(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []SubmitResult { @@ -321,7 +412,11 @@ func (this *ResourceManager) PatchInContext(session *mcclient.ClientSession, id func (this *ResourceManager) PatchInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s", this.ContextPath(ctxs), url.PathEscape(id)) - return this._patch(session, path, this.params2Body(params), this.Keyword) + result, err := this._patch(session, path, this.params2Body(session, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } func (this *ResourceManager) BatchPatch(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []SubmitResult { @@ -348,7 +443,11 @@ func (this *ResourceManager) PerformActionInContext(session *mcclient.ClientSess func (this *ResourceManager) PerformActionInContexts(session *mcclient.ClientSession, id string, action string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) { path := fmt.Sprintf("/%s/%s/%s", this.ContextPath(ctxs), url.PathEscape(id), url.PathEscape(action)) - return this._post(session, path, this.params2Body(params), this.Keyword) + result, err := this._post(session, path, this.params2Body(session, params), this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } func (this *ResourceManager) PerformClassAction(session *mcclient.ClientSession, action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -403,9 +502,13 @@ func (this *ResourceManager) deleteInContexts(session *mcclient.ClientSession, i } } if body != nil { - body = this.params2Body(body) + body = this.params2Body(session, body) } - return this._delete(session, path, body, this.Keyword) + result, err := this._delete(session, path, body, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result) } func (this *ResourceManager) BatchDelete(session *mcclient.ClientSession, idlist []string, body jsonutils.JSONObject) []SubmitResult {