recode quota and usage for image service

This commit is contained in:
Qiu Jian
2018-12-27 23:59:31 +08:00
parent cbcd9f5dc1
commit a3e802d803
8 changed files with 136 additions and 80 deletions
+25
View File
@@ -450,4 +450,29 @@ func init() {
return nil
})
type ImageChangeOwnerOptions struct {
ID string `help:"Image to change owner"`
PROJECT string `help:"Project ID or change"`
RawId bool `help:"User raw ID, instead of name"`
}
R(&ImageChangeOwnerOptions{}, "image-change-owner", "Change owner project of an image", func(s *mcclient.ClientSession, opts *ImageChangeOwnerOptions) error {
params := jsonutils.NewDict()
if opts.RawId {
projid, err := modules.Projects.GetId(s, opts.PROJECT, nil)
if err != nil {
return err
}
params.Add(jsonutils.NewString(projid), "tenant")
params.Add(jsonutils.JSONTrue, "raw_id")
} else {
params.Add(jsonutils.NewString(opts.PROJECT), "tenant")
}
srv, err := modules.Images.PerformAction(s, opts.ID, "change-owner", params)
if err != nil {
return err
}
printObject(srv)
return nil
})
}
+2 -33
View File
@@ -7,7 +7,7 @@ import (
)
type QuotaBaseOptions struct {
Cpu int64 `help:"CPU count" json:"cpu:omitzero"`
Cpu int64 `help:"CPU count" json:"cpu,omitzero"`
Memory int64 `help:"Memory size in MB" json:"memory,omitzero"`
Storage int64 `help:"Storage size in MB" json:"storage,omitzero"`
Port int64 `help:"Internal NIC count" json:"port,omitzero"`
@@ -17,10 +17,7 @@ type QuotaBaseOptions struct {
Ebw int64 `help:"External bandwidth in Mbps" json:"ebw,omitzero"`
IsolatedDevice int64 `help:"Isolated device count" json:"isolated_device,omitzero"`
Snapshot int64 `help:"Snapshot count" json:"snapshot,omitzero"`
}
type ImageQuotaBaseOptions struct {
Image int64 `help:"Template count" json:"image,omitzero"`
Image int64 `help:"Template count" json:"image,omitzero"`
}
func init() {
@@ -60,20 +57,6 @@ func init() {
return nil
})
type ImageQuotaSetOptions struct {
Tenant string `help:"Tenant name or ID to set quota" json:"tenant,omitempty"`
ImageQuotaBaseOptions
}
R(&ImageQuotaSetOptions{}, "image-quota-set", "Set image quota for tenant", func(s *mcclient.ClientSession, args *ImageQuotaSetOptions) error {
params := jsonutils.Marshal(args)
result, e := modules.ImageQuotas.DoQuotaSet(s, params)
if e != nil {
return e
}
printObject(result)
return nil
})
type QuotaCheckOptions struct {
TENANT string `help:"Tenant name or ID to check quota" json:"tenant,omitempty"`
QuotaBaseOptions
@@ -88,18 +71,4 @@ func init() {
return nil
})
type ImageQuotaCheckOptions struct {
TENANT string `help:"Tenant name or ID to check quota" json:"tenant,omitempty"`
ImageQuotaBaseOptions
}
R(&ImageQuotaCheckOptions{}, "image-quota-check", "Check quota for tenant", func(s *mcclient.ClientSession, args *ImageQuotaCheckOptions) error {
params := jsonutils.Marshal(args)
result, e := modules.ImageQuotas.DoQuotaCheck(s, params)
if e != nil {
return e
}
printObject(result)
return nil
})
}
+1 -1
View File
@@ -121,7 +121,7 @@ func init() {
if args.Project != "" {
params.Add(jsonutils.NewString(args.Project), "project")
}
result, err := modules.ImageUsages.GetUsage(s, params)
result, err := modules.Images.GetUsage(s, params)
if err != nil {
return err
}
+61 -24
View File
@@ -20,7 +20,6 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/image/options"
@@ -650,41 +649,79 @@ type SImageUsage struct {
Size int64
}
func (manager *SImageManager) count(projectId string, isISO tristate.TriState, pendingDelete bool) SImageUsage {
images := manager.Query().SubQuery()
q := images.Query(sqlchemy.COUNT("count"), sqlchemy.SUM("size", images.Field("size")))
func (manager *SImageManager) count(projectId string, status string, isISO tristate.TriState, pendingDelete bool) map[string]SImageUsage {
sq := manager.Query("id")
if len(projectId) > 0 {
q = q.Equals("tenant_id", projectId)
sq = sq.Equals("tenant_id", projectId)
}
if len(status) > 0 {
sq = sq.Equals("status", status)
}
if pendingDelete {
q = q.IsTrue("pending_deleted")
sq = sq.IsTrue("pending_deleted")
} else {
q = q.IsFalse("pending_deleted")
sq = sq.IsFalse("pending_deleted")
}
if isISO.IsTrue() {
q = q.Equals("disk_format", "iso")
sq = sq.Equals("disk_format", "iso")
} else if isISO.IsFalse() {
q = q.NotEquals("disk_format", "iso")
sq = sq.NotEquals("disk_format", "iso")
}
subimages := ImageSubformatManager.Query().SubQuery()
q := subimages.Query(subimages.Field("format"),
sqlchemy.COUNT("count"),
sqlchemy.SUM("size", subimages.Field("size")))
q = q.In("image_id", sq.SubQuery())
q = q.GroupBy(subimages.Field("format"))
type sFormatImageUsage struct {
Format string
Count int64
Size int64
}
var usages []sFormatImageUsage
err := q.All(&usages)
if err != nil {
log.Errorf("query usage fail %s", err)
return nil
}
ret := make(map[string]SImageUsage)
totalSize := int64(0)
for _, u := range usages {
ret[u.Format] = SImageUsage{Count: u.Count, Size: u.Size}
totalSize += u.Size
}
ret["total"] = SImageUsage{Count: int64(sq.Count()), Size: totalSize}
return ret
}
func expandUsageCount(usages map[string]int64, prefix, imgType, state string, count map[string]SImageUsage) {
for k, u := range count {
key := []string{}
if len(prefix) > 0 {
key = append(key, prefix)
}
key = append(key, imgType)
if len(state) > 0 {
key = append(key, state)
}
key = append(key, k)
countKey := strings.Join(append(key, "count"), ".")
sizeKey := strings.Join(append(key, "size"), ".")
usages[countKey] = u.Count
usages[sizeKey] = u.Size
}
usage := SImageUsage{}
q.First(&usage)
return usage
}
func (manager *SImageManager) Usage(projectId string, prefix string) map[string]int64 {
usages := make(map[string]int64)
count := manager.count(projectId, tristate.False, false)
usages[quotas.KeyName(prefix, "img.count")] = count.Count
usages[quotas.KeyName(prefix, "img.size")] = count.Size
count = manager.count(projectId, tristate.True, false)
usages[quotas.KeyName(prefix, "iso.count")] = count.Count
usages[quotas.KeyName(prefix, "iso.size")] = count.Size
count = manager.count(projectId, tristate.False, true)
usages[quotas.KeyName(prefix, "img.pending_delete.count")] = count.Count
usages[quotas.KeyName(prefix, "img.pending_delete.size")] = count.Size
count = manager.count(projectId, tristate.True, true)
usages[quotas.KeyName(prefix, "iso.pending_delete.count")] = count.Count
usages[quotas.KeyName(prefix, "iso.pending_delete.size")] = count.Size
count := manager.count(projectId, IMAGE_STATUS_ACTIVE, tristate.False, false)
expandUsageCount(usages, prefix, "img", "", count)
count = manager.count(projectId, IMAGE_STATUS_ACTIVE, tristate.True, false)
expandUsageCount(usages, prefix, "iso", "", count)
count = manager.count(projectId, "", tristate.False, true)
expandUsageCount(usages, prefix, "img", "pending_delete", count)
count = manager.count(projectId, "", tristate.True, true)
expandUsageCount(usages, prefix, "iso", "pending_delete", count)
return usages
}
+3 -3
View File
@@ -17,7 +17,7 @@ func init() {
dbStore := quotas.NewDBQuotaStore()
pendingStore := quotas.NewMemoryQuotaStore()
QuotaManager = quotas.NewQuotaManager("image-quotas", SQuota{}, dbStore, pendingStore)
QuotaManager = quotas.NewQuotaManager("quotas", SQuota{}, dbStore, pendingStore)
}
var (
@@ -33,8 +33,8 @@ func (self *SQuota) FetchSystemQuota() {
}
func (self *SQuota) FetchUsage(ctx context.Context, projectId string) error {
count := ImageManager.count(projectId, tristate.None, false)
self.Image = int(count.Count)
count := ImageManager.count(projectId, "", tristate.None, false)
self.Image = int(count["total"].Count)
return nil
}
+1 -1
View File
@@ -61,7 +61,7 @@ func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Requ
var adminUsage map[string]int64
var projectUsage map[string]int64
if isAdmin {
adminUsage = models.ImageManager.Usage(userCred.GetProjectId(), "all")
adminUsage = models.ImageManager.Usage("", "all")
}
isProject := false
+3 -1
View File
@@ -210,7 +210,7 @@ func (this *ImageManager) countUsage(session *mcclient.ClientSession, deleted bo
}
func (this *ImageManager) GetUsage(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
body := jsonutils.NewDict()
/*body := jsonutils.NewDict()
pendingDelete := jsonutils.NewDict()
for deleted, data := range map[bool]*jsonutils.JSONDict{false: body, true: pendingDelete} {
if ret, err := this.countUsage(session, deleted); err != nil {
@@ -226,6 +226,8 @@ func (this *ImageManager) GetUsage(session *mcclient.ClientSession, params jsonu
}
body.Add(pendingDelete, "pending_delete")
return body, nil
*/
return ImageUsages.GetUsage(session, params)
}
func setImageMeta(params jsonutils.JSONObject) (http.Header, error) {
+40 -17
View File
@@ -27,32 +27,55 @@ func (this *QuotaManager) getURL(params jsonutils.JSONObject) string {
}
func (this *QuotaManager) GetQuota(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return this._get(s, this.getURL(params), this.KeywordPlural)
computeQuota, err := this._get(s, this.getURL(params), this.KeywordPlural)
if err != nil {
return nil, err
}
imageQuota, err := ImageQuotas._get(s, ImageQuotas.getURL(params), ImageQuotas.KeywordPlural)
if err != nil {
return nil, err
}
computeQuotaDict := computeQuota.(*jsonutils.JSONDict)
computeQuotaDict.Update(imageQuota)
return computeQuotaDict, nil
}
func (this *QuotaManager) DoQuotaSet(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
url := this.getURL(params)
func (this *QuotaManager) doPost(s *mcclient.ClientSession, params jsonutils.JSONObject, url string) (jsonutils.JSONObject, error) {
quotas, ok := params.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("Invalid input")
}
data := quotas.Copy("tenant", "user")
body := jsonutils.NewDict()
body.Add(data, this.KeywordPlural)
return this._post(s, url, body, this.KeywordPlural)
data := quotas.CopyExcludes("tenant", "user", "image")
var err error
if data.Size() > 0 {
body := jsonutils.NewDict()
body.Add(data, this.KeywordPlural)
_, err = this._post(s, url, body, this.KeywordPlural)
if err != nil {
return nil, err
}
}
data = quotas.CopyIncludes("image")
if data.Size() > 0 {
body := jsonutils.NewDict()
body.Add(data, ImageQuotas.KeywordPlural)
_, err = ImageQuotas._post(s, url, body, ImageQuotas.KeywordPlural)
if err != nil {
return nil, err
}
}
return jsonutils.NewDict(), nil
}
func (this *QuotaManager) DoQuotaSet(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
url := this.getURL(params)
return this.doPost(s, params, url)
}
func (this *QuotaManager) DoQuotaCheck(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
url := this.getURL(params)
url = fmt.Sprintf("%s/check_quota", url)
quotas, ok := params.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("Invalid input")
}
data := quotas.Copy("tenant", "user")
body := jsonutils.NewDict()
body.Add(data, this.KeywordPlural)
return this._post(s, url, body, this.KeywordPlural)
return this.doPost(s, params, url)
}
var (
@@ -66,8 +89,8 @@ func init() {
[]string{})}
registerCompute(&Quotas)
ImageQuotas = QuotaManager{NewImageManager("image-quota", "image-quotas",
ImageQuotas = QuotaManager{NewImageManager("quota", "quotas",
[]string{},
[]string{})}
registerV2(&ImageQuotas)
// registerV2(&ImageQuotas)
}