From dd13a991c089560c22f47904bcbf00995c9f916d Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Tue, 14 May 2019 22:35:58 +0800 Subject: [PATCH] fix: misc bug fixes. add usage and event log API --- cmd/climc/shell/events.go | 49 +++++++++++++++++++++ cmd/climc/shell/usages.go | 11 +++++ cmd/ldapcli/shell/search.go | 20 ++++++++- pkg/appsrv/appsrv.go | 2 +- pkg/cloudcommon/app/app.go | 2 +- pkg/cloudcommon/db/db_dispatcher.go | 10 +++-- pkg/cloudcommon/db/opslog.go | 2 + pkg/httperrors/httperrors.go | 2 + pkg/keystone/driver/ldap.go | 6 ++- pkg/keystone/models/assignments.go | 27 +++++++++--- pkg/keystone/models/policies.go | 3 +- pkg/keystone/models/usages.go | 29 +++++++++++++ pkg/keystone/service/localpolicy.go | 10 +++-- pkg/keystone/service/service.go | 4 ++ pkg/keystone/tokens/auth.go | 3 ++ pkg/keystone/tokens/handlers.go | 6 ++- pkg/keystone/usages/handler.go | 64 +++++++++++++++++++++++++++- pkg/mcclient/modules/mod_identity.go | 39 +++++++++++++++++ pkg/mcclient/modules/mod_policies.go | 8 +--- 19 files changed, 270 insertions(+), 27 deletions(-) create mode 100644 pkg/keystone/models/usages.go create mode 100644 pkg/mcclient/modules/mod_identity.go diff --git a/cmd/climc/shell/events.go b/cmd/climc/shell/events.go index 65687eb001..f5ae8d9ed5 100644 --- a/cmd/climc/shell/events.go +++ b/cmd/climc/shell/events.go @@ -56,6 +56,10 @@ func doImageEventList(s *mcclient.ClientSession, args *EventListOptions) error { return doEventList(modules.ImageLogs, s, args) } +func doIdentityEventList(s *mcclient.ClientSession, args *EventListOptions) error { + return doEventList(modules.IdentityLogs, s, args) +} + func doEventList(man modules.ResourceManager, s *mcclient.ClientSession, args *EventListOptions) error { params := jsonutils.NewDict() if len(args.Type) > 0 { @@ -167,4 +171,49 @@ func init() { nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"image"}} return doImageEventList(s, &nargs) }) + + R(&TypeEventListOptions{}, "user-event", "Show operation event logs of keystone users", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"user"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "group-event", "Show operation event logs of keystone groups", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"group"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "domain-event", "Show operation event logs of keystone domains", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"domain"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "project-event", "Show operation event logs of keystone projects", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"project"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "role-event", "Show operation event logs of keystone roles", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"role"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "policy-event", "Show operation event logs of keystone policies", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"policy"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "endpoint-event", "Show operation event logs of keystone endpoints", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"endpoint"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "service-event", "Show operation event logs of keystone services", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"service"}} + return doIdentityEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "credential-event", "Show operation event logs of keystone credentials", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"credential"}} + return doIdentityEventList(s, &nargs) + }) } diff --git a/cmd/climc/shell/usages.go b/cmd/climc/shell/usages.go index e9082310c5..bc2cdda190 100644 --- a/cmd/climc/shell/usages.go +++ b/cmd/climc/shell/usages.go @@ -143,4 +143,15 @@ func init() { printObject(result) return nil }) + + type IdentityUsageOptions struct { + } + R(&IdentityUsageOptions{}, "identity-usage", "Show general usage of identity", func(s *mcclient.ClientSession, args *IdentityUsageOptions) error { + result, err := modules.IdentityUsages.GetUsage(s, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) } diff --git a/cmd/ldapcli/shell/search.go b/cmd/ldapcli/shell/search.go index 8f8ba1dd94..a226ca37d4 100644 --- a/cmd/ldapcli/shell/search.go +++ b/cmd/ldapcli/shell/search.go @@ -26,6 +26,7 @@ func init() { Base string `help:"base DN, e.g. OU=tech,DC=example,DC=com"` Objectclass string `help:"objectclass, e.g. organizationalPerson"` Search []string `help:"search conditions, in format of field:value"` + Field []string `help:"retrieve field info"` } shellutils.R(&LdapSearchOptions{}, "search", "search ldap", func(cli *ldaputils.SLDAPClient, args *LdapSearchOptions) error { search := make(map[string]string) @@ -36,7 +37,7 @@ func init() { } search[s[:colonPos]] = s[(colonPos + 1):] } - entries, err := cli.Search(args.Base, args.Objectclass, search, nil) + entries, err := cli.Search(args.Base, args.Objectclass, search, args.Field) if err != nil { return err } @@ -45,4 +46,21 @@ func init() { } return nil }) + + type LdapAuthOptions struct { + Base string `help:"base DN, e.g. OU=tech,DC=example,DC=com"` + Objectclass string `help:"objectclass, e.g. organizationalPerson"` + ATTR string `help:"account attribute name"` + ACCOUNT string `help:"account name to auth"` + PASSWORD string `help:"Password to auth"` + Field []string `help:"retrieve field info"` + } + shellutils.R(&LdapAuthOptions{}, "auth", "authenticate against ldap", func(cli *ldaputils.SLDAPClient, args *LdapAuthOptions) error { + entry, err := cli.Authenticate(args.Base, args.Objectclass, args.ATTR, args.ACCOUNT, args.PASSWORD, args.Field) + if err != nil { + return err + } + entry.PrettyPrint(2) + return nil + }) } diff --git a/pkg/appsrv/appsrv.go b/pkg/appsrv/appsrv.go index 6ea804957e..c3b3cebf12 100644 --- a/pkg/appsrv/appsrv.go +++ b/pkg/appsrv/appsrv.go @@ -453,7 +453,7 @@ func (app *Application) listenAndServeInternal(s *http.Server, certFile, keyFile err = s.ListenAndServeTLS(certFile, keyFile) } if err != nil && err != http.ErrServerClosed { - log.Fatalf("ListAndServer fail: %s", err) + log.Fatalf("ListAndServer fail: %s (cert=%s key=%s)", err, certFile, keyFile) } } diff --git a/pkg/cloudcommon/app/app.go b/pkg/cloudcommon/app/app.go index aa121d4b15..bff0cb1ec9 100644 --- a/pkg/cloudcommon/app/app.go +++ b/pkg/cloudcommon/app/app.go @@ -56,7 +56,7 @@ func ServeForeverExtended(app *appsrv.Application, options *common_options.BaseO var certfile string var sslfile string if options.EnableSsl { - certfile := options.SslCertfile + certfile = options.SslCertfile if len(options.SslCaCerts) > 0 { var err error certfile, err = seclib2.MergeCaCertFiles(options.SslCaCerts, options.SslCertfile) diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 2b31ecb110..703b2eda12 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -217,9 +217,13 @@ func listItemsQueryByColumn(manager IModelManager, q *sqlchemy.SQuery, userCred strV, _ := val.GetString() if len(op) > 0 { filter := fmt.Sprintf("%s.%s(%s)", fn, op, strV) - log.Debugf("XXXXX %s %s %s %s", key, fn, op, filter) - cond := filterclause.ParseFilterClause(filter).QueryCondition(q) - q = q.Filter(cond) + fc := filterclause.ParseFilterClause(filter) + if fc != nil { + cond := fc.QueryCondition(q) + if cond != nil { + q = q.Filter(cond) + } + } } else if len(strV) > 0 { strV := colSpec.ConvertFromString(strV) q = q.Equals(fn, strV) diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 147e8d2c9b..0a1339bc2b 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -354,6 +354,8 @@ func (manager *SOpsLogManager) ListItemFilter(ctx context.Context, q *sqlchemy.S if objIds != nil && len(objIds) > 0 { q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("obj_id"), objIds), sqlchemy.In(q.Field("obj_name"), objIds))) } + queryDict := query.(*jsonutils.JSONDict) + queryDict.Remove("obj_id") action := jsonutils.GetQueryStringArray(query, "action") if action != nil && len(action) > 0 { q = q.Filter(sqlchemy.In(q.Field("action"), action)) diff --git a/pkg/httperrors/httperrors.go b/pkg/httperrors/httperrors.go index 599bb6d38d..f043143677 100644 --- a/pkg/httperrors/httperrors.go +++ b/pkg/httperrors/httperrors.go @@ -18,6 +18,7 @@ import ( "net/http" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/util/httputils" ) @@ -38,6 +39,7 @@ func HTTPError(w http.ResponseWriter, msg string, statusCode int, class string, err.Add(jsonutils.NewStringArray(error.Fields), "fields") body.Add(err, "data") w.Write([]byte(body.String())) + log.Errorf("Send error %s", err) } func JsonClientError(w http.ResponseWriter, e *httputils.JSONClientError) { diff --git a/pkg/keystone/driver/ldap.go b/pkg/keystone/driver/ldap.go index 1ab73c6e62..b5626582f8 100644 --- a/pkg/keystone/driver/ldap.go +++ b/pkg/keystone/driver/ldap.go @@ -107,8 +107,9 @@ func (self *SLDAPDriver) entry2User(entry *ldap.Entry) SUserInfo { info.Name = entry.GetAttributeValue(self.ldapConfig.UserNameAttribute) enabledStr := entry.GetAttributeValue(self.ldapConfig.UserEnabledAttribute) if len(enabledStr) == 0 { - info.Enabled = utils.ToBool(self.ldapConfig.UserEnabledDefault) - } else if self.ldapConfig.UserEnabledMask > 0 { + enabledStr = self.ldapConfig.UserEnabledDefault + } + if self.ldapConfig.UserEnabledMask > 0 { enabled, _ := strconv.ParseInt(enabledStr, 0, 64) if (enabled & self.ldapConfig.UserEnabledMask) != 0 { info.Enabled = true @@ -184,6 +185,7 @@ func (self *SLDAPDriver) Authenticate(ctx context.Context, ident mcclient.SAuthe password, self.userAttributeList()) if err != nil { + log.Errorf("LDAP AUTH error: %s", err) return nil, errors.Wrap(err, "Authenticate error") } diff --git a/pkg/keystone/models/assignments.go b/pkg/keystone/models/assignments.go index 9399e63385..ef25d771ee 100644 --- a/pkg/keystone/models/assignments.go +++ b/pkg/keystone/models/assignments.go @@ -422,16 +422,31 @@ func (assign *SAssignment) getRoleAssignment(domains, projects, groups, users, r func (manager *SAssignmentManager) FetchAll(userId, groupId, roleId, domainId, projectId string, includeNames, effective, includeSub bool) ([]SRoleAssignment, error) { var q *sqlchemy.SQuery if effective { - usrq := manager.queryAll(userId, groupId, roleId, domainId, projectId).In("type", []string{api.AssignmentUserProject, api.AssignmentUserDomain}) - - grpq := manager.queryAll(userId, groupId, roleId, domainId, projectId).In("type", []string{api.AssignmentUserProject, api.AssignmentUserDomain}).SubQuery() + usrq := manager.queryAll(userId, "", roleId, domainId, projectId).In("type", []string{api.AssignmentUserProject, api.AssignmentUserDomain}) memberships := UsergroupManager.Query("user_id", "group_id").SubQuery() - q2 := grpq.Query(grpq.Field("type"), memberships.Field("user_id", "actor_id"), grpq.Field("target_id"), grpq.Field("role_id")) - q2 = q2.Join(memberships, sqlchemy.Equals(grpq.Field("actor_id"), memberships.Field("group_id"))) + grpproj := manager.queryAll("", groupId, roleId, domainId, projectId).Equals("type", api.AssignmentGroupProject).SubQuery() + q2 := grpproj.Query(sqlchemy.NewStringField(api.AssignmentUserProject).Label("type"), + memberships.Field("user_id", "actor_id"), + grpproj.Field("target_id"), grpproj.Field("role_id")) + q2 = q2.Join(memberships, sqlchemy.Equals(grpproj.Field("actor_id"), memberships.Field("group_id"))) + q2 = q2.Filter(sqlchemy.Equals(grpproj.Field("type"), api.AssignmentGroupProject)) + if len(userId) > 0 { + q2 = q2.Filter(sqlchemy.Equals(memberships.Field("user_id"), userId)) + } - q = sqlchemy.Union(usrq, q2).Query().Distinct() + grpdom := manager.queryAll("", groupId, roleId, domainId, projectId).Equals("type", api.AssignmentGroupDomain).SubQuery() + q3 := grpdom.Query(sqlchemy.NewStringField(api.AssignmentUserDomain).Label("type"), + memberships.Field("user_id", "actor_id"), + grpdom.Field("target_id"), grpdom.Field("role_id")) + q3 = q3.Join(memberships, sqlchemy.Equals(grpdom.Field("actor_id"), memberships.Field("group_id"))) + q3 = q3.Filter(sqlchemy.Equals(grpdom.Field("type"), api.AssignmentGroupDomain)) + if len(userId) > 0 { + q3 = q3.Filter(sqlchemy.Equals(memberships.Field("user_id"), userId)) + } + + q = sqlchemy.Union(usrq, q2, q3).Query().Distinct() } else { q = manager.queryAll(userId, groupId, roleId, domainId, projectId).Distinct() } diff --git a/pkg/keystone/models/policies.go b/pkg/keystone/models/policies.go index 9a11c5b9d0..125ab03c24 100644 --- a/pkg/keystone/models/policies.go +++ b/pkg/keystone/models/policies.go @@ -59,7 +59,8 @@ type SPolicy struct { db.SStandaloneResourceBase Type string `width:"255" charset:"utf8" nullable:"false" list:"user" update:"admin"` - Blob string `nullable:"false" list:"user" update:"admin"` + + Blob jsonutils.JSONObject `nullable:"false" list:"user" update:"admin"` Extra *jsonutils.JSONDict `nullable:"true" list:"user"` diff --git a/pkg/keystone/models/usages.go b/pkg/keystone/models/usages.go new file mode 100644 index 0000000000..6056f9a38c --- /dev/null +++ b/pkg/keystone/models/usages.go @@ -0,0 +1,29 @@ +package models + +import ( + api "yunion.io/x/onecloud/pkg/apis/identity" +) + +func Usage() map[string]int { + results := make(map[string]int) + + domCnt, _ := DomainManager.Query().IsTrue("is_domain").NotEquals("id", api.KeystoneDomainRoot).CountWithError() + results["domains"] = domCnt + + projCnt, _ := ProjectManager.Query().IsFalse("is_domain").CountWithError() + results["projects"] = projCnt + + roleCnt, _ := RoleManager.Query().CountWithError() + results["roles"] = roleCnt + + usrCnt, _ := UserManager.Query().CountWithError() + results["users"] = usrCnt + + grpCnt, _ := GroupManager.Query().CountWithError() + results["groups"] = grpCnt + + policy, _ := PolicyManager.Query().CountWithError() + results["policies"] = policy + + return results +} diff --git a/pkg/keystone/service/localpolicy.go b/pkg/keystone/service/localpolicy.go index fa7a81fbe1..c7524cc8a0 100644 --- a/pkg/keystone/service/localpolicy.go +++ b/pkg/keystone/service/localpolicy.go @@ -17,9 +17,9 @@ package service import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/keystone/models" "yunion.io/x/onecloud/pkg/util/rbacutils" - "yunion.io/x/pkg/utils" ) func localPolicyFetcher() (map[string]rbacutils.SRbacPolicy, map[string]rbacutils.SRbacPolicy, error) { @@ -32,10 +32,14 @@ func localPolicyFetcher() (map[string]rbacutils.SRbacPolicy, map[string]rbacutil adminPolicies := make(map[string]rbacutils.SRbacPolicy) for i := range policyList { - log.Debugf("BLOB: %#v", policyList[i].Blob) typeStr := policyList[i].Name policy := rbacutils.SRbacPolicy{} - policyJson, err := jsonutils.ParseString(utils.Unquote(policyList[i].Blob)) + policyStr, err := policyList[i].Blob.GetString() + if err != nil { + log.Errorf("fail to get string of blob %s", err) + continue + } + policyJson, err := jsonutils.ParseString(policyStr) if err != nil { log.Errorf("fail to deocde policy blob into JSON %s", err) continue diff --git a/pkg/keystone/service/service.go b/pkg/keystone/service/service.go index 0c1de2babf..4169b4c0f4 100644 --- a/pkg/keystone/service/service.go +++ b/pkg/keystone/service/service.go @@ -51,6 +51,10 @@ func StartService() { dbOpts := &opts.DBOptions common_options.ParseOptions(opts, os.Args, "keystone.conf", api.SERVICE_TYPE) + if opts.Port == 0 { + opts.Port = 5000 // keystone well-known port + } + err := keys.Init(opts.TokenKeyRepository, opts.CredentialKeyRepository) if err != nil { log.Fatalf("init fernet keys fail %s", err) diff --git a/pkg/keystone/tokens/auth.go b/pkg/keystone/tokens/auth.go index e670d9526d..654b2262cf 100644 --- a/pkg/keystone/tokens/auth.go +++ b/pkg/keystone/tokens/auth.go @@ -19,6 +19,7 @@ import ( "github.com/pkg/errors" + "yunion.io/x/log" "yunion.io/x/pkg/utils" "context" @@ -101,10 +102,12 @@ func AuthenticateV3(ctx context.Context, input mcclient.SAuthenticationInputV3) } // user not found if user == nil { + log.Errorf("user not found???") return nil, nil } // user is not enabled if !user.Enabled { + log.Errorf("user not enabled???") return nil, nil } token := SAuthToken{} diff --git a/pkg/keystone/tokens/handlers.go b/pkg/keystone/tokens/handlers.go index fa60a422c5..97655ab57a 100644 --- a/pkg/keystone/tokens/handlers.go +++ b/pkg/keystone/tokens/handlers.go @@ -66,10 +66,14 @@ func authenticateTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Re } log.Debugf("%s", jsonutils.Marshal(&input)) token, err := AuthenticateV3(ctx, input) - if token == nil { + if err != nil { httperrors.UnauthorizedError(w, "unauthorized %s", err) return } + if token == nil { + httperrors.UnauthorizedError(w, "user not found or not enabled") + return + } w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, token.Id) token.Id = "" appsrv.SendJSON(w, jsonutils.Marshal(token)) diff --git a/pkg/keystone/usages/handler.go b/pkg/keystone/usages/handler.go index c43f6f4587..b8ad6a2da0 100644 --- a/pkg/keystone/usages/handler.go +++ b/pkg/keystone/usages/handler.go @@ -19,13 +19,75 @@ import ( "fmt" "net/http" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/appsrv" + "yunion.io/x/onecloud/pkg/cloudcommon/consts" + "yunion.io/x/onecloud/pkg/cloudcommon/policy" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/keystone/models" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/util/rbacutils" ) func AddUsageHandler(prefix string, app *appsrv.Application) { prefix = fmt.Sprintf("%s/usages", prefix) - app.AddHandler2("GET", prefix, ReportGeneralUsage, nil, "get_usage", nil) + app.AddHandler2("GET", prefix, auth.Authenticate(ReportGeneralUsage), nil, "get_usage", nil) } func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Request) { + // _, query, _ := appsrv.FetchEnv(ctx, w, r) + userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential) + + isAdmin := false + if consts.IsRbacEnabled() { + if policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(), + "usages", policy.PolicyActionGet) == rbacutils.AdminAllow { + isAdmin = true + } + } else { + isAdmin = userCred.IsAdminAllow(consts.GetServiceType(), "usages", policy.PolicyActionGet) + } + + var adminUsage map[string]int + // var projectUsage map[string]int64 + if isAdmin { + adminUsage = models.Usage() + } + + /* isProject := false + if consts.IsRbacEnabled() { + if policy.PolicyManager.Allow(false, userCred, consts.GetServiceType(), + "usages", policy.PolicyActionGet) == rbacutils.Deny { + isProject = false + } else { + isProject = true + } + } else { + isProject = true + } + + if isProject { + projectUsage = models.Usage(userCred.GetProjectId(), "") + } + */ + + // if !isAdmin && !isProject { + if !isAdmin { + httperrors.ForbiddenError(w, "not allow to get usage") + return + } + + usages := jsonutils.NewDict() + // if isProject { + // usages.Update(jsonutils.Marshal(projectUsage)) + // } + + if isAdmin { + usages.Update(jsonutils.Marshal(adminUsage)) + } + + body := jsonutils.NewDict() + body.Add(usages, "usage") + appsrv.SendJSON(w, body) } diff --git a/pkg/mcclient/modules/mod_identity.go b/pkg/mcclient/modules/mod_identity.go new file mode 100644 index 0000000000..91065d62e4 --- /dev/null +++ b/pkg/mcclient/modules/mod_identity.go @@ -0,0 +1,39 @@ +package modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" +) + +type SIdentityUsageManager struct { + ResourceManager +} + +func (this *SIdentityUsageManager) GetUsage(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + url := "/usages" + if params != nil { + query := params.QueryString() + if len(query) > 0 { + url = fmt.Sprintf("%s?%s", url, query) + } + } + return this._get(session, url, "usage") +} + +var ( + IdentityUsages SIdentityUsageManager + IdentityLogs ResourceManager +) + +func init() { + IdentityUsages = SIdentityUsageManager{NewIdentityV3Manager("usage", "usages", + []string{}, + []string{})} + + IdentityLogs = NewIdentityV3Manager("event", "events", + []string{"id", "ops_time", "obj_id", "obj_type", "obj_name", "user", "user_id", "tenant", "tenant_id", "owner_tenant_id", "action", "notes"}, + []string{}) +} diff --git a/pkg/mcclient/modules/mod_policies.go b/pkg/mcclient/modules/mod_policies.go index f3fbd01360..ff35a25c71 100644 --- a/pkg/mcclient/modules/mod_policies.go +++ b/pkg/mcclient/modules/mod_policies.go @@ -16,8 +16,6 @@ package modules import ( "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" @@ -34,10 +32,6 @@ func policyReadFilter(session *mcclient.ClientSession, s jsonutils.JSONObject, q ret := ss.CopyIncludes("id", "type", "enabled") blobStr, _ := ss.GetString("blob") if len(blobStr) > 0 { - for blobStr[0] == '"' { - blobStr = utils.Unquote(blobStr) - } - log.Debugf("%s", blobStr) policy := rbacutils.SRbacPolicy{} blobJson, _ := jsonutils.ParseString(blobStr) err := policy.Decode(blobJson) @@ -80,7 +74,7 @@ func policyWriteFilter(session *mcclient.ClientSession, s jsonutils.JSONObject, return nil, err } } - ret.Add(blobJson, "blob") + ret.Add(jsonutils.NewString(blobJson.String()), "blob") } if s.Contains("type") { typeStr, err := s.GetString("type")