aboutsummaryrefslogblamecommitdiff
path: root/quotas.go
blob: c68f5de993ca63c20fb1df3731ae7325b0ec9f89 (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"
)

// Note: PIM = Personal Information Manager
const (
	// --- Default Quota Values Websites ---
	QUOTA_WEBSITE_SIZE_DEFAULT = 1024 * 1024 * 50  // 50MB
	QUOTA_WEBSITE_SIZE_BURSTED = 1024 * 1024 * 200 // 200MB
	QUOTA_WEBSITE_OBJECTS      = 10_000            // 10k objects
	QUOTA_WEBSITE_COUNT        = 5                 // 5 buckets

	// --- Default Quota Values PIM ---
	QUOTA_PIM_SIZE_DEFAULT	   = 1024 * 1024 * 100 // 100MB
	QUOTA_PIM_SIZE_BURSTED	   = 1024 * 1024 * 500 // 500MB
	QUOTA_PIM_OBJECTS	   = 100_000           // 100k objects

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

type UserQuota struct {
	WebsiteCount       int64
	WebsiteSizeDefault int64
	WebsiteSizeBursted int64
	WebsiteObjects     int64
	PimSizeDefault	   int64
	PimSizeBursted     int64
	PimObjects	   int64
}

func NewUserQuota() *UserQuota {
	return &UserQuota{
		WebsiteCount:       QUOTA_WEBSITE_COUNT,
		WebsiteSizeDefault: QUOTA_WEBSITE_SIZE_DEFAULT,
		WebsiteSizeBursted: QUOTA_WEBSITE_SIZE_BURSTED,
		WebsiteObjects:     QUOTA_WEBSITE_OBJECTS,
		PimSizeDefault:     QUOTA_PIM_SIZE_DEFAULT,
		PimSizeBursted:     QUOTA_PIM_SIZE_BURSTED,
		PimObjects:	    QUOTA_PIM_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
	}

	if q, err := entryToQuota(entry, FIELD_QUOTA_PIM_SIZE_BURSTED); err == nil {
		quotas.PimSizeBursted = 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) DefaultPimQuota() *garage.UpdateBucketRequestQuotas {
	qr := garage.NewUpdateBucketRequestQuotas()

	qr.SetMaxSize(q.PimSizeDefault)
	qr.SetMaxObjects(q.PimObjects)

	return qr
}

// Website getters/setters
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)
}

// PIM getters/setters
func (q *UserQuota) PimSizeAdjust(sz int64) int64 {
	if sz < q.PimSizeDefault {
		return q.PimSizeDefault
	} else if sz > q.PimSizeBursted {
		return q.PimSizeBursted
	} else {
		return sz
	}
}

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

func (q *UserQuota) PimSizeBurstedPretty() string {
	return prettyValue(q.PimSizeBursted)
}

// --- 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)
}