Skip to content

Commit

Permalink
eosfs: set quota (#1477)
Browse files Browse the repository at this point in the history
  • Loading branch information
labkode authored Feb 15, 2021
1 parent dda48c9 commit 6051b66
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 10 deletions.
3 changes: 3 additions & 0 deletions changelog/unreleased/eos-set-quota.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Enhancement: Set quota when creating home directory in EOS

https://github.com/cs3org/reva/pull/1477
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ redis_address = "localhost:6379"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="user_groups_cache_expiration" type="int" default=5 %}}
{{% dir name="group_members_cache_expiration" type="int" default=5 %}}
The time in minutes for which the members of a group would be cached [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/cbox/group/rest/rest.go#L75)
{{< highlight toml >}}
[cbox.group.rest]
user_groups_cache_expiration = 5
group_members_cache_expiration = 5
{{< /highlight >}}
{{% /dir %}}

Expand Down
3 changes: 3 additions & 0 deletions internal/grpc/services/gateway/usershareprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ func (s *svc) CreateShare(ctx context.Context, req *collaboration.CreateShareReq
// TODO(labkode): if both commits are enabled they could be done concurrently.
if s.c.CommitShareToStorageGrant {
addGrantStatus, err := s.addGrant(ctx, req.ResourceInfo.Id, req.Grant.Grantee, req.Grant.Permissions.Permissions)
if err != nil {
return nil, errors.Wrap(err, "gateway: error adding grant to storage")
}
if addGrantStatus.Code != rpc.Code_CODE_OK {
return &collaboration.CreateShareResponse{
Status: addGrantStatus,
Expand Down
12 changes: 12 additions & 0 deletions pkg/eosclient/eosbinary/eosbinary.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,18 @@ func (c *Client) GetQuota(ctx context.Context, username, rootUID, rootGID, path
return c.parseQuota(path, stdout)
}

// SetQuota sets the quota of a user on the quota node defined by path
func (c *Client) SetQuota(ctx context.Context, rootUID, rootGID string, info *eosclient.SetQuotaInfo) error {
maxBytes := fmt.Sprintf("%d", info.MaxBytes)
maxFiles := fmt.Sprintf("%d", info.MaxFiles)
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", rootUID, rootGID, "quota", "set", "-u", info.Username, "-p", info.QuotaNode, "-v", maxBytes, "-i", maxFiles)
_, _, err := c.executeEOS(ctx, cmd)
if err != nil {
return err
}
return nil
}

// Touch creates a 0-size,0-replica file in the EOS namespace.
func (c *Client) Touch(ctx context.Context, uid, gid, path string) error {
cmd := exec.CommandContext(ctx, "/usr/bin/eos", "-r", uid, gid, "file", "touch", path)
Expand Down
10 changes: 10 additions & 0 deletions pkg/eosclient/eosclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type EOSClient interface {
SetAttr(ctx context.Context, uid, gid string, attr *Attribute, recursive bool, path string) error
UnsetAttr(ctx context.Context, uid, gid string, attr *Attribute, path string) error
GetQuota(ctx context.Context, username, rootUID, rootGID, path string) (*QuotaInfo, error)
SetQuota(ctx context.Context, rootUID, rootGID string, info *SetQuotaInfo) error
Touch(ctx context.Context, uid, gid, path string) error
Chown(ctx context.Context, uid, gid, chownUID, chownGID, path string) error
Chmod(ctx context.Context, uid, gid, mode, path string) error
Expand Down Expand Up @@ -99,3 +100,12 @@ type QuotaInfo struct {
AvailableBytes, UsedBytes int
AvailableInodes, UsedInodes int
}

// SetQuotaInfo encapsulates the information needed to
// create a quota space in EOS for a user
type SetQuotaInfo struct {
Username string
QuotaNode string
MaxBytes uint64
MaxFiles uint64
}
5 changes: 5 additions & 0 deletions pkg/eosclient/eosgrpc/eosgrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,11 @@ func (c *Client) GetQuota(ctx context.Context, username, rootUID, rootGID, path
return nil, errtypes.NotSupported("eosgrpc: GetQuota not implemented")
}

// SetQuota sets the quota of a user on the quota node defined by path
func (c *Client) SetQuota(ctx context.Context, rootUID, rootGID string, info *eosclient.SetQuotaInfo) error {
return errtypes.NotSupported("eosgrpc: SetQuota not implemented")
}

// Touch creates a 0-size,0-replica file in the EOS namespace.
func (c *Client) Touch(ctx context.Context, uid, gid, path string) error {
log := appctx.GetLogger(ctx)
Expand Down
9 changes: 9 additions & 0 deletions pkg/storage/utils/eosfs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ type Config struct {
// Namespace for metadata operations
Namespace string `mapstructure:"namespace"`

// QuotaNode for storing quota information
QuotaNode string `mapstructure:"quota_node"`

// DefaultQuotaBytes sets the default maximum bytes available for a user
DefaultQuotaBytes uint64 `mapstructure:"default_quota_bytes"`

// DefaultQuotaFiles sets the default maximum files available for a user
DefaultQuotaFiles uint64 `mapstructure:"default_quota_files"`

// ShadowNamespace for storing shadow data
ShadowNamespace string `mapstructure:"shadow_namespace"`

Expand Down
45 changes: 37 additions & 8 deletions pkg/storage/utils/eosfs/eosfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ func (c *Config) init() {
c.ShadowNamespace = path.Join(c.Namespace, ".shadow")
}

// Quota node defaults to namespace if empty
if c.QuotaNode == "" {
c.QuotaNode = c.Namespace
}

if c.DefaultQuotaBytes == 0 {
c.DefaultQuotaBytes = 1000000000000 // 1 TB
}
if c.DefaultQuotaFiles == 0 {
c.DefaultQuotaFiles = 1000000 // 1 Million
}

if c.ShareFolder == "" {
c.ShareFolder = "/MyShares"
}
Expand Down Expand Up @@ -838,6 +850,25 @@ func (fs *eosfs) createNominalHome(ctx context.Context) error {
}

err = fs.createUserDir(ctx, u, home, false)
if err != nil {
err := errors.Wrap(err, "eosfs: error creating user dir")
return err
}

// set quota for user
quotaInfo := &eosclient.SetQuotaInfo{
Username: u.Username,
MaxBytes: fs.conf.DefaultQuotaBytes,
MaxFiles: fs.conf.DefaultQuotaFiles,
QuotaNode: fs.conf.QuotaNode,
}

err = fs.c.SetQuota(ctx, uid, gid, quotaInfo)
if err != nil {
err := errors.Wrap(err, "eosfs: error setting quota")
return err
}

return err
}

Expand Down Expand Up @@ -913,6 +944,7 @@ func (fs *eosfs) createUserDir(ctx context.Context, u *userpb.User, path string,
return errors.Wrap(err, "eos: error setting attribute")
}
}

return nil
}

Expand Down Expand Up @@ -941,11 +973,6 @@ func (fs *eosfs) CreateDir(ctx context.Context, p string) error {
func (fs *eosfs) CreateReference(ctx context.Context, p string, targetURI *url.URL) error {
// TODO(labkode): for the time being we only allow to create references
// on the virtual share folder to not pollute the nominal user tree.
u, err := getUser(ctx)
if err != nil {
return errors.Wrap(err, "eos: no user in ctx")
}

if !fs.isShareFolder(ctx, p) {
return errtypes.PermissionDenied("eos: cannot create references outside the share folder: share_folder=" + fs.conf.ShareFolder + " path=" + p)
}
Expand All @@ -960,9 +987,11 @@ func (fs *eosfs) CreateReference(ctx context.Context, p string, targetURI *url.U
if err != nil {
return nil
}
if err := fs.createUserDir(ctx, u, tmp, false); err != nil {
err = errors.Wrapf(err, "eos: error creating temporary ref file")
return err

err = fs.c.CreateDir(ctx, uid, gid, tmp)
if err != nil {
// EOS will return success on mkdir over an existing directory.
return errors.Wrap(err, "eos: error creating ref-dir")
}

// set xattr on ref
Expand Down

0 comments on commit 6051b66

Please sign in to comment.