Skip to content

Commit 1a79b58

Browse files
d-w-moorealanking
authored andcommitted
[#474][#479] Allow querying, setting, and removing quotas
1 parent fc51d0f commit 1a79b58

6 files changed

Lines changed: 162 additions & 5 deletions

File tree

irods/manager/user_manager.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
from irods.models import User, Group
77
from irods.manager import Manager
8-
from irods.message import UserAdminRequest, GeneralAdminRequest, iRODSMessage, GetTempPasswordForOtherRequest, GetTempPasswordForOtherOut
8+
from irods.message import (UserAdminRequest, GeneralAdminRequest, _do_GeneralAdminRequest, iRODSMessage,
9+
GetTempPasswordForOtherRequest, GetTempPasswordForOtherOut)
910
from irods.exception import UserDoesNotExist, GroupDoesNotExist, NoResultFound, CAT_SQL_ERR
1011
from irods.api_number import api_number
1112
from irods.user import iRODSUser, iRODSGroup, Bad_password_change_parameter
@@ -16,6 +17,30 @@
1617

1718
class UserManager(Manager):
1819

20+
def _get_session(self): return self.sess
21+
22+
def calculate_usage(self):
23+
return _do_GeneralAdminRequest(self._get_session, "calculate-usage")
24+
25+
# TODO: remove this in branch 2.x (#482)
26+
def set_quota(self, user_name, amount, resource = 'total'):
27+
return _do_GeneralAdminRequest(self._get_session,
28+
"set-quota",
29+
"user",
30+
user_name,
31+
resource,
32+
str(amount)
33+
)
34+
35+
def remove_quota(self, user_name, resource = 'total'):
36+
return _do_GeneralAdminRequest(self._get_session,
37+
"set-quota",
38+
"user",
39+
user_name,
40+
resource,
41+
"0"
42+
)
43+
1944
def get(self, user_name, user_zone=""):
2045
query = self.sess.query(User).filter(User.name == user_name)
2146

@@ -319,6 +344,24 @@ def removemember(self,
319344
response = conn.recv()
320345
logger.debug(response.int_info)
321346

347+
def remove_quota(self, group_name, resource = 'total'):
348+
self.set_quota(group_name, amount = 0, resource = resource)
349+
350+
def set_quota(self, group_name, amount, resource = 'total'):
351+
message_body = GeneralAdminRequest(
352+
"set-quota",
353+
"group",
354+
group_name,
355+
resource,
356+
str(amount)
357+
)
358+
request = iRODSMessage("RODS_API_REQ", msg=message_body,
359+
int_info=api_number['GENERAL_ADMIN_AN'])
360+
with self.sess.pool.get_connection() as conn:
361+
conn.send(request)
362+
response = conn.recv()
363+
logger.debug(response.int_info)
364+
322365

323366
# NOTE: Everything of the form *UserGroup* is deprecated.
324367
UserGroupManager = GroupManager

irods/message/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import xml.etree.ElementTree as ET_xml
1111
import defusedxml.ElementTree as ET_secure_xml
1212
from . import quasixml as ET_quasi_xml
13+
from ..api_number import api_number
1314
from collections import namedtuple
1415
import os
1516
import ast
@@ -784,6 +785,18 @@ def __init__(self, *args):
784785
class GeneralAdminRequest(_admin_request_base):
785786
_name = 'generalAdminInp_PI'
786787

788+
def _do_GeneralAdminRequest(_session_or_accessor, *args):
789+
sess = _session_or_accessor
790+
if callable(sess):
791+
sess = sess()
792+
message_body = GeneralAdminRequest(*args)
793+
request = iRODSMessage("RODS_API_REQ", msg=message_body,
794+
int_info=api_number['GENERAL_ADMIN_AN'])
795+
with sess.pool.get_connection() as conn:
796+
conn.send(request)
797+
response = conn.recv()
798+
logger.debug(response.int_info)
799+
787800

788801
# define userAdminInp_PI "str *arg0; str *arg1; str *arg2; str *arg3;
789802
# str *arg4; str *arg5; str *arg6; str *arg7; str *arg8; str *arg9;"

irods/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,14 @@ class Keywords(Model):
199199
chksum = Keyword(String, 'chksum')
200200

201201

202+
class Quota(Model):
203+
user_id = Column(Integer, 'COL_QUOTA_USER_ID', 2000)
204+
resc_id = Column(Integer, 'COL_QUOTA_RESC_ID', 2001)
205+
limit = Column(Integer, 'COL_QUOTA_LIMIT', 2002)
206+
over = Column(Integer, 'COL_QUOTA_OVER', 2003)
207+
modify_time = Column(DateTime,'COL_QUOTA_MODIFY_TIME', 2004)
208+
209+
202210
class TicketQuery:
203211
"""Various model classes for querying attributes of iRODS tickets.
204212

irods/test/user_group_test.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,43 @@
66
import unittest
77
import tempfile
88
import shutil
9+
from subprocess import check_output, CalledProcessError
910
from irods import MAX_PASSWORD_LENGTH
1011
from irods.exception import GroupDoesNotExist, UserDoesNotExist
1112
from irods.meta import iRODSMetaCollection, iRODSMeta
12-
from irods.models import User, Group, UserMeta
13+
from irods.models import User, Group, UserMeta, Quota
1314
from irods.session import iRODSSession
1415
import irods.exception as ex
1516
import irods.test.helpers as helpers
16-
from irods.user import Bad_password_change_parameter
17+
from irods.user import iRODSUser, Bad_password_change_parameter
1718
from six.moves import range
1819

19-
class TestGroup(unittest.TestCase):
20+
def user_quotas_implemented():
21+
return getattr(iRODSUser, "set_quota", None) is not None
22+
23+
def icommands_available():
24+
try:
25+
which_output = check_output(['which', 'ihelp'])
26+
return b'ihelp' in which_output
27+
except CalledProcessError:
28+
pass # 'which' returned nonzero status
29+
return False
30+
31+
def set_user_quota(session, user_name, bytes_total):
32+
success = False
33+
if user_quotas_implemented():
34+
try:
35+
session.users.set_quota(user_name, bytes_total)
36+
success = True
37+
except:
38+
pass
39+
if not success and icommands_available():
40+
return_code = os.system("iadmin suq {} total {}".format(user_name, bytes_total))
41+
if return_code == 0:
42+
success = True
43+
return success
44+
45+
class TestUserAndGroup(unittest.TestCase):
2046

2147
def setUp(self):
2248
self.sess = helpers.make_session()
@@ -525,6 +551,60 @@ def alice_login(pw):
525551
if user_alice:
526552
user_alice.remove()
527553

554+
def test_set_and_query_group_quota(self):
555+
#import pdb
556+
#pdb.set_trace()
557+
bob = quota_group = None
558+
ses = self.sess
559+
test_object = None
560+
my_quota = 10000
561+
my_object_size = 1400
562+
try:
563+
bob = self.sess.users.create('bob', 'rodsuser')
564+
ses.users.modify('bob', 'password', 'bpass')
565+
quota_group = self.sess.groups.create('quota_group_for_bob')
566+
quota_group.addmember(bob.name)
567+
quota_group.set_quota(my_quota)
568+
with iRODSSession(user = 'bob', password = 'bpass', host = ses.host, port = ses.port, zone = ses.zone) as user_sess:
569+
test_object = user_sess.data_objects.create('/tempZone/home/public/bob_file_testing_group_quota')
570+
with test_object.open('w') as f:
571+
f.write(b'_' * my_object_size)
572+
ses.groups.calculate_usage()
573+
for i in ses.query(Quota).filter(Quota.user_id == quota_group.id):
574+
self.assertEqual(int(i[Quota.over]), -my_quota + my_object_size)
575+
finally:
576+
if test_object:
577+
test_object.unlink(force = True)
578+
if quota_group:
579+
quota_group.remove()
580+
if bob:
581+
ses.users.remove(bob.name)
582+
583+
@unittest.skipIf(not user_quotas_implemented()
584+
and not icommands_available(), "Can't set up user quota for removal in test")
585+
def test_set_and_query_user_quota(self):
586+
bob = None
587+
if self.sess.server_version >= (4, 3):
588+
self.skipTest('iRODS servers 4.3.0 and higher have dropped user quotas in favor of group quotas.')
589+
ses = self.sess
590+
test_object = None
591+
try:
592+
bob = self.sess.users.create('bob', 'rodsuser')
593+
ses.users.modify('bob', 'password', 'bpass')
594+
set_user_quota(ses, 'bob', 10000)
595+
with iRODSSession(user = 'bob', password = 'bpass', host = ses.host, port = ses.port, zone = ses.zone) as user_sess:
596+
test_object = user_sess.data_objects.create('/tempZone/home/public/bobfile')
597+
with test_object.open('w') as f:
598+
f.write(b'_'*1000)
599+
ses.users.calculate_usage()
600+
for i in ses.query(Quota).filter(Quota.user_id == bob.id):
601+
self.assertEqual(int(i[Quota.over]), -9000)
602+
finally:
603+
if test_object:
604+
test_object.unlink(force = True)
605+
if bob:
606+
ses.users.remove(bob.name)
607+
528608

529609
if __name__ == '__main__':
530610
# let the tests find the parent irods lib

irods/user.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ class Bad_password_change_parameter(Exception): pass
99

1010
class iRODSUser(object):
1111

12+
def remove_quota(self, resource = 'total'):
13+
self.manager.remove_quota(self.name, resource = resource)
14+
15+
# TODO: remove this in branch 2.x (#482)
16+
def set_quota(self, amount, resource = 'total'):
17+
self.manager.set_quota(self.name, amount, resource = resource)
18+
1219
def __init__(self, manager, result=None):
1320
self.manager = manager
1421
if result:
@@ -66,6 +73,12 @@ def temp_password(self):
6673

6774
class iRODSGroup(object):
6875

76+
def remove_quota(self, resource = 'total'):
77+
self.set_quota(amount = 0, resource = resource)
78+
79+
def set_quota(self, amount, resource = 'total'):
80+
self.manager.set_quota(self.name, amount, resource = resource)
81+
6982
def __init__(self, manager, result=None):
7083
self.manager = manager
7184
if result:

irods/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import os
1+
import os
22

33
__version__ = '1.1.9'
44

0 commit comments

Comments
 (0)