Skip to content

Commit

Permalink
Implement Get/SetQuota (pending cleanup)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabrizio Furano committed Mar 8, 2021
1 parent 2ad904f commit 2f5a2e1
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 6 deletions.
2 changes: 2 additions & 0 deletions pkg/eosclient/eosclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ type QuotaInfo struct {
// create a quota space in EOS for a user
type SetQuotaInfo struct {
Username string
Uid string
Gid string
QuotaNode string
MaxBytes uint64
MaxFiles uint64
Expand Down
141 changes: 139 additions & 2 deletions pkg/eosclient/eosgrpc/eosgrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ func (c *Client) getRespError(rsp *erpc.NSResponse, err error) error {
return err
}

if rsp == nil {
return nil
}

if rsp.Error == nil {
return nil
}

if rsp.Error.Code == 0 {
return nil
}
Expand Down Expand Up @@ -628,12 +636,141 @@ func (c *Client) GetFileInfoByFXID(ctx context.Context, uid, gid string, fxid st

// GetQuota gets the quota of a user on the quota node defined by path
func (c *Client) GetQuota(ctx context.Context, username, rootUID, rootGID, path string) (*eosclient.QuotaInfo, error) {
return nil, errtypes.NotSupported("eosgrpc: GetQuota not implemented")
log := appctx.GetLogger(ctx)
log.Info().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("username", username).Str("path", path).Msg("")

// Initialize the common fields of the NSReq
rq, err := c.initNSRequest(ctx, rootUID, rootGID)
if err != nil {
return nil, err
}

msg := new(erpc.NSRequest_QuotaRequest)
msg.Path = []byte(path)
msg.Id = new(erpc.RoleId)

// Eos filters the returned quotas by username. This means that EOS must know it, someone
// must have created an user with that name
msg.Id.Username = username
rq.Command = &erpc.NSRequest_Quota{Quota: msg}

// Now send the req and see what happens
resp, err := c.cl.Exec(ctx, rq)
e := c.getRespError(resp, err)
if e != nil {
log.Info().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("username", username).Str("info:", fmt.Sprintf("%#v", resp)).Str("err", e.Error()).Msg("")
return nil, e
}

if resp == nil {
return nil, errtypes.InternalError(fmt.Sprintf("nil response for rootuid: '%s' rootgid: '%s' username: '%s' path: '%s'", rootUID, rootGID, username, path))
}

if resp.GetError() != nil {
log.Info().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("username", username).Str("info:", fmt.Sprintf("%#v", resp)).Int64("eoserrcode", resp.GetError().Code).Str("errmsg", resp.GetError().Msg).Msg("grpc response")
} else {
log.Info().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("username", username).Str("info:", fmt.Sprintf("%#v", resp)).Msg("grpc response")
}

if resp.Quota == nil {
return nil, errtypes.InternalError(fmt.Sprintf("nil quota response? rootuid: '%s' rootgid: '%s' path: '%s'", rootUID, rootGID, path))
}

if resp.Quota.Code != 0 {
return nil, errtypes.InternalError(fmt.Sprintf("Quota error from eos. rootuid: '%s' rootgid: '%s' info: '%#v'", rootUID, rootGID, resp.Quota))
}

log.Debug().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("quotanode:", fmt.Sprintf("%#v", resp.Quota.Quotanode[0])).Msg("grpc response")

qi := new(eosclient.QuotaInfo)
if resp == nil {
return nil, errtypes.InternalError("Out of memory")
}

// Let's loop on all the quotas that match this uid (apparently there can be many)
for i := 0; i < len(resp.Quota.Quotanode); i++ {

mx := resp.Quota.Quotanode[i].Maxlogicalbytes - resp.Quota.Quotanode[i].Usedbytes
if mx < 0 {
mx = 0
}
qi.AvailableBytes += mx
qi.UsedBytes += resp.Quota.Quotanode[0].Usedbytes

mx = resp.Quota.Quotanode[0].Maxfiles - resp.Quota.Quotanode[0].Usedfiles
if mx < 0 {
mx = 0
}
qi.AvailableInodes += mx
qi.UsedInodes += resp.Quota.Quotanode[0].Usedfiles
}

return qi, err

}

// 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")
{
log := appctx.GetLogger(ctx)
log.Info().Str("func", "SetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("info:", fmt.Sprintf("%#v", info)).Msg("")

// EOS does not have yet this command... work in progress, this is a draft piece of code
//return errtypes.NotSupported("eosgrpc: SetQuota not implemented")

// Initialize the common fields of the NSReq
rq, err := c.initNSRequest(ctx, rootUID, rootGID)
if err != nil {
return err
}

msg := new(erpc.NSRequest_QuotaRequest)
msg.Path = []byte(info.QuotaNode)
msg.Id = new(erpc.RoleId)
uidInt, err := strconv.ParseUint(info.Uid, 10, 64)
if err != nil {
return err
}
gidInt, err := strconv.ParseUint(info.Gid, 10, 64)
if err != nil {
return err
}
msg.Id.Uid = uidInt
msg.Id.Gid = gidInt
msg.Id.Username = info.Username
rq.Command = &erpc.NSRequest_Quota{Quota: msg}

// Now send the req and see what happens
resp, err := c.cl.Exec(ctx, rq)
e := c.getRespError(resp, err)
if e != nil {
log.Info().Str("func", "SetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("info:", fmt.Sprintf("%#v", resp)).Str("err", e.Error()).Msg("")
return e
}

if resp == nil {
return errtypes.InternalError(fmt.Sprintf("nil response for rootuid: '%s' rootgid: '%s' info: '%#v'", rootUID, rootGID, info))
}

if resp.GetError() != nil {
log.Info().Str("func", "SetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("info:", fmt.Sprintf("%#v", resp)).Int64("errcode", resp.GetError().Code).Str("errmsg", resp.GetError().Msg).Msg("grpc response")
} else {
log.Info().Str("func", "SetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("info:", fmt.Sprintf("%#v", resp)).Msg("grpc response")
}

if resp.Quota == nil {
return errtypes.InternalError(fmt.Sprintf("nil quota response? rootuid: '%s' rootgid: '%s' path: '%s'", rootUID, rootGID, info))
}

if resp.Quota.Code != 0 {
return errtypes.InternalError(fmt.Sprintf("Quota error from eos. rootuid: '%s' rootgid: '%s' quota: '%#v'", rootUID, rootGID, resp.Quota))
}

log.Debug().Str("func", "GetQuota").Str("rootuid,rootgid", rootUID+","+rootGID).Str("quotanodes", fmt.Sprintf("%d", len(resp.Quota.Quotanode))).Msg("grpc response")

return err

}
}

// Touch creates a 0-size,0-replica file in the EOS namespace.
Expand Down
49 changes: 45 additions & 4 deletions pkg/storage/utils/eosfs/eosfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,34 @@ func (fs *eosfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys
return nil, errors.Wrap(err, "eos: no user in ctx")
}

// test... remove me
rootuid, rootgid, err := fs.getRootUIDAndGID(ctx)
if err != nil {
return nil, err
}
uid, gid, err := fs.getUserUIDAndGID(ctx, u)
if err != nil {
return nil, errors.Wrap(err, "eos: no uid in ctx")
}
// set quota for user
quotaInfo := &eosclient.SetQuotaInfo{
Username: u.Username,
Uid: uid,
Gid: gid,
MaxBytes: fs.conf.DefaultQuotaBytes,
MaxFiles: fs.conf.DefaultQuotaFiles,
QuotaNode: fs.conf.QuotaNode,
}

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

fs.GetQuota(ctx)
// end test

p, err := fs.resolve(ctx, u, ref)
if err != nil {
return nil, errors.Wrap(err, "eos: error resolving reference")
Expand Down Expand Up @@ -760,12 +788,17 @@ func (fs *eosfs) GetQuota(ctx context.Context) (uint64, uint64, error) {
return 0, 0, errors.Wrap(err, "eos: no user in ctx")
}

uid, _, err := fs.getUserUIDAndGID(ctx, u)
if err != nil {
return 0, 0, errors.Wrap(err, "eos: no uid in ctx")
}

rootUID, rootGID, err := fs.getRootUIDAndGID(ctx)
if err != nil {
return 0, 0, err
}

qi, err := fs.c.GetQuota(ctx, u.Username, rootUID, rootGID, fs.conf.QuotaNode)
qi, err := fs.c.GetQuota(ctx, uid, rootUID, rootGID, fs.conf.QuotaNode)
if err != nil {
err := errors.Wrap(err, "eosfs: error getting quota")
return 0, 0, err
Expand Down Expand Up @@ -834,11 +867,17 @@ func (fs *eosfs) createNominalHome(ctx context.Context) error {
}

home := fs.wrap(ctx, "/")
uid, gid, err := fs.getRootUIDAndGID(ctx)
rootuid, rootgid, err := fs.getRootUIDAndGID(ctx)
if err != nil {
return nil
}
_, err = fs.c.GetFileInfoByPath(ctx, uid, gid, home)

uid, gid, err := fs.getUserUIDAndGID(ctx, u)
if err != nil {
return err
}

_, err = fs.c.GetFileInfoByPath(ctx, rootuid, rootgid, home)
if err == nil { // home already exists
return nil
}
Expand All @@ -856,12 +895,14 @@ func (fs *eosfs) createNominalHome(ctx context.Context) error {
// set quota for user
quotaInfo := &eosclient.SetQuotaInfo{
Username: u.Username,
Uid: uid,
Gid: gid,
MaxBytes: fs.conf.DefaultQuotaBytes,
MaxFiles: fs.conf.DefaultQuotaFiles,
QuotaNode: fs.conf.QuotaNode,
}

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

0 comments on commit 2f5a2e1

Please sign in to comment.