aboutsummaryrefslogblamecommitdiff
path: root/quotas.go
blob: 894ea3c428fda355b6c9490f871fee6d9ed5ff86 (plain) (tree)
1
2
3
4
5
6
7
8
9






                 
                                                                     
                                    



                                       
                                                              
                                                               

                                                                     


                                                                       
                                                                


                       
                                

                                
                                


                                

                                                        

                                                               
                                                          



         
                                                                          


















                                                                         
                                                                                 


                                       
                                                                                        








                                                                             
                                           



                                              


                                                       
                                           




















                                                           



                                            
 
 
                                                                 



                                                           




























                                                  
                    





                                               
package main

import (
	"errors"
	"fmt"
	"strconv"

	garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
	"github.com/go-ldap/ldap/v3"
)

const (
	// --- Default Quota Values ---
	QUOTA_WEBSITE_SIZE_DEFAULT = 1024 * 1024 * 50  // 50MB
	QUOTA_WEBSITE_SIZE_BURSTED = 1024 * 1024 * 200 // 200MB
	QUOTA_WEBSITE_OBJECTS      = 10000             // 10k objects
	QUOTA_WEBSITE_COUNT        = 5                 // 5 buckets

	// --- Per-user overridable fields ---
	FIELD_QUOTA_WEBSITE_SIZE_BURSTED = "quota_website_size_bursted"
	FIELD_QUOTA_WEBSITE_COUNT        = "quota_website_count"
)

type UserQuota struct {
	WebsiteCount       int64
	WebsiteSizeDefault int64
	WebsiteSizeBursted int64
	WebsiteObjects     int64
}

func NewUserQuota() *UserQuota {
	return &UserQuota{
		WebsiteCount:       QUOTA_WEBSITE_COUNT,
		WebsiteSizeDefault: QUOTA_WEBSITE_SIZE_DEFAULT,
		WebsiteSizeBursted: QUOTA_WEBSITE_SIZE_BURSTED,
		WebsiteObjects:     QUOTA_WEBSITE_OBJECTS,
	}
}

var (
	ErrQuotaEmpty   = fmt.Errorf("No quota is defined for this entry")
	ErrQuotaInvalid = fmt.Errorf("The defined quota can't be parsed")
)

func entryToQuota(entry *ldap.Entry, field string) (int64, error) {
	f := entry.GetAttributeValue(field)
	if f == "" {
		return -1, ErrQuotaEmpty
	}

	q, err := strconv.ParseInt(f, 10, 64)
	if err != nil {
		return -1, errors.Join(ErrQuotaInvalid, err)
	}
	return q, nil
}

func NewUserQuotaFromEntry(entry *ldap.Entry) *UserQuota {
	quotas := NewUserQuota()

	if q, err := entryToQuota(entry, FIELD_QUOTA_WEBSITE_COUNT); err == nil {
		quotas.WebsiteCount = q
	}

	if q, err := entryToQuota(entry, FIELD_QUOTA_WEBSITE_SIZE_BURSTED); err == nil {
		quotas.WebsiteSizeBursted = q
	}

	return quotas
}

func (q *UserQuota) DefaultWebsiteQuota() *garage.UpdateBucketRequestQuotas {
	qr := garage.NewUpdateBucketRequestQuotas()

	qr.SetMaxSize(q.WebsiteSizeDefault)
	qr.SetMaxObjects(q.WebsiteSizeBursted)

	return qr
}

func (q *UserQuota) WebsiteSizeAdjust(sz int64) int64 {
	if sz < q.WebsiteSizeDefault {
		return q.WebsiteSizeDefault
	} else if sz > q.WebsiteSizeBursted {
		return q.WebsiteSizeBursted
	} else {
		return sz
	}
}

func (q *UserQuota) WebsiteObjectAdjust(objs int64) int64 {
	if objs > q.WebsiteObjects || objs <= 0 {
		return q.WebsiteObjects
	} else {
		return objs
	}
}

func (q *UserQuota) WebsiteSizeBurstedPretty() string {
	return prettyValue(q.WebsiteSizeBursted)
}

// --- A quota stat we can use
type QuotaStat struct {
	Current   int64   `json:"current"`
	Max       int64   `json:"max"`
	Ratio     float64 `json:"ratio"`
	Burstable bool    `json:"burstable"`
}

func NewQuotaStat(current, max int64, burstable bool) QuotaStat {
	return QuotaStat{
		Current:   current,
		Max:       max,
		Ratio:     float64(current) / float64(max),
		Burstable: burstable,
	}
}
func (q *QuotaStat) IsFull() bool {
	return q.Current >= q.Max
}
func (q *QuotaStat) Percent() int64 {
	return int64(q.Ratio * 100)
}

func (q *QuotaStat) PrettyCurrent() string {
	return prettyValue(q.Current)
}
func (q *QuotaStat) PrettyMax() string {
	return prettyValue(q.Max)
}

func prettyValue(v int64) string {
	if v < 1024 {
		return fmt.Sprintf("%d octets", v)
	}
	v = v / 1024
	if v < 1024 {
		return fmt.Sprintf("%d kio", v)
	}
	v = v / 1024
	if v < 1024 {
		return fmt.Sprintf("%d Mio", v)
	}
	v = v / 1024
	if v < 1024 {
		return fmt.Sprintf("%d Gio", v)
	}
	v = v / 1024
	return fmt.Sprintf("%d Tio", v)
}