allow quota tracking only for users with quota restrictions

Setting "track_quota" to 2 in sftpgo.conf will avoid a database update
after each file upload/deletion if the user has no quota restrictions
This commit is contained in:
Nicola Murino 2019-07-28 22:04:50 +02:00
parent 9987821003
commit 0bed768909
6 changed files with 24 additions and 16 deletions

View file

@ -87,7 +87,10 @@ The `sftpgo.conf` configuration file contains the following sections:
- `connectionstring`, string. Provide a custom database connection string. If not empty this connection string will be used instead of build one using the previous parameters
- `users_table`, string. Database table for SFTP users
- `manage_users`, integer. Set to 0 to disable users management, 1 to enable
- `track_quota`, integer. Set to 0 to disable quota tracking, 1 to update the used quota each time a user upload or delete a file
- `track_quota`, integer. Set the preferred way to track users quota between the following choices:
- 0, disable quota tracking. REST API to scan user dir and update quota will do nothing
- 1, quota is updated each time a user upload or delete a file even if the user has no quota restrictions
- 2, quota is updated each time a user upload or delete a file but only for users with quota restrictions. With this configuration you can still use the "quota scan" REST API to periodically update space usage for users without quota restrictions
- **"httpd"**, the configuration for the HTTP server used to serve REST API
- `bind_port`, integer. The port used for serving HTTP requests. Set to 0 to disable HTTP server. Default: 8080
- `bind_address`, string. Leave blank to listen on all available network interfaces. Default: "127.0.0.1"
@ -157,7 +160,7 @@ These properties are stored inside the data provider. If you want to use your ex
SFTPGo exposes REST API to manage users and quota and to get real time reports for the active connections with possibility of forcibly closing a connection.
If quota tracking is enabled in `sftpgo.conf` configuration file, then the used size and number of files are updated each time a file is added/removed. If files are added/removed not using SFTP, you can rescan the user home dir and update the used quota using the REST API.
If quota tracking is enabled in `sftpgo.conf` configuration file, then the used size and number of files are updated each time a file is added/removed. If files are added/removed not using SFTP or if you change `track_quota` from `2` to `1`, you can rescan the user home dir and update the used quota using the REST API.
REST API is designed to run on localhost or on a trusted network, if you need https or authentication you can setup a reverse proxy using an HTTP Server such as Apache or NGNIX.

View file

@ -33,11 +33,8 @@ func startQuotaScan(w http.ResponseWriter, r *http.Request) {
if err != nil {
logger.Warn(logSender, "error scanning user home dir %v: %v", user.HomeDir, err)
} else {
err := dataprovider.UpdateUserQuota(dataProvider, user.Username, numFiles, size, true)
if err != nil {
logger.Debug(logSender, "error updating user quota for %v: %v", user.Username, err)
}
logger.Debug(logSender, "user dir scanned, user: %v, dir: %v", user.Username, user.HomeDir)
err := dataprovider.UpdateUserQuota(dataProvider, user, numFiles, size, true)
logger.Debug(logSender, "user dir scanned, user: %v, dir: %v, error: %v", user.Username, user.HomeDir, err)
}
sftpd.RemoveQuotaScan(user.Username)
}()

View file

@ -23,7 +23,7 @@ const (
logSender = "dataProvider"
argonPwdPrefix = "$argon2id$"
manageUsersDisabledError = "please set manage_users to 1 in sftpgo.conf to enable this method"
trackQuotaDisabledError = "please set track_quota to 1 in sftpgo.conf to enable this method"
trackQuotaDisabledError = "please enable track_quota in sftpgo.conf to use this method"
)
var (
@ -117,11 +117,13 @@ func CheckUserAndPubKey(p Provider, username string, pubKey string) (User, error
}
// UpdateUserQuota update the quota for the given user
func UpdateUserQuota(p Provider, username string, filesAdd int, sizeAdd int64, reset bool) error {
func UpdateUserQuota(p Provider, user User, filesAdd int, sizeAdd int64, reset bool) error {
if config.TrackQuota == 0 {
return &MethodDisabledError{err: trackQuotaDisabledError}
} else if config.TrackQuota == 2 && !reset && !user.HasQuotaRestrictions() {
return nil
}
return p.updateQuota(username, filesAdd, sizeAdd, reset)
return p.updateQuota(user.Username, filesAdd, sizeAdd, reset)
}
// GetUsedQuota returns the used quota for the given user

View file

@ -82,3 +82,9 @@ func (u *User) GetGID() int {
func (u *User) GetHomeDir() string {
return filepath.Clean(u.HomeDir)
}
// HasQuotaRestrictions returns true if there is a quota restriction on number of files
// or size or both
func (u *User) HasQuotaRestrictions() bool {
return u.QuotaFiles > 0 || u.QuotaSize > 0
}

View file

@ -167,8 +167,7 @@ func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) {
if trunc {
// the file is truncated so we need to decrease quota size but not quota files
logger.Debug(logSender, "file truncation requested update quota for user %v", c.User.Username)
dataprovider.UpdateUserQuota(dataProvider, c.User.Username, 0, -stat.Size(), false)
dataprovider.UpdateUserQuota(dataProvider, c.User, 0, -stat.Size(), false)
}
utils.SetPathPermissions(p, c.User.GetUID(), c.User.GetGID())
@ -339,7 +338,7 @@ func (c Connection) handleSFTPRmdir(path string) error {
}
logger.CommandLog(sftpdRmdirLogSender, path, "", c.User.Username, c.ID)
dataprovider.UpdateUserQuota(dataProvider, c.User.Username, -numFiles, -size, false)
dataprovider.UpdateUserQuota(dataProvider, c.User, -numFiles, -size, false)
for _, p := range fileList {
executeAction(operationDelete, c.User.Username, p, "")
}
@ -392,7 +391,7 @@ func (c Connection) handleSFTPRemove(path string) error {
logger.CommandLog(sftpdRemoveLogSender, path, "", c.User.Username, c.ID)
if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
dataprovider.UpdateUserQuota(dataProvider, c.User.Username, -1, -size, false)
dataprovider.UpdateUserQuota(dataProvider, c.User, -1, -size, false)
}
executeAction(operationDelete, c.User.Username, path, "")
@ -410,7 +409,8 @@ func (c Connection) hasSpace(checkFiles bool) bool {
logger.Warn(logSender, "error getting used quota for %v: %v", c.User.Username, err)
return false
}
if (checkFiles && numFile >= c.User.QuotaFiles) || size >= c.User.QuotaSize {
if (checkFiles && c.User.QuotaFiles > 0 && numFile >= c.User.QuotaFiles) ||
(c.User.QuotaSize > 0 && size >= c.User.QuotaSize) {
logger.Debug(logSender, "quota exceed for user %v, num files: %v/%v, size: %v/%v check files: %v",
c.User.Username, numFile, c.User.QuotaFiles, size, c.User.QuotaSize, checkFiles)
return false

View file

@ -62,7 +62,7 @@ func (t *Transfer) Close() error {
if t.isNewFile {
numFiles = 1
}
dataprovider.UpdateUserQuota(dataProvider, t.user.Username, numFiles, t.bytesReceived, false)
dataprovider.UpdateUserQuota(dataProvider, t.user, numFiles, t.bytesReceived, false)
}
return err
}