diff --git a/adminsec/tests/test_views_api.py b/adminsec/tests/test_views_api.py index 8e5ecba..7c8666d 100644 --- a/adminsec/tests/test_views_api.py +++ b/adminsec/tests/test_views_api.py @@ -638,7 +638,7 @@ def test_get_succeed(self): expected = { "hpc_users": [ { - "uid": self.hpcuser_user.user.uid, + "uid": self.hpcuser_user.uid, "email": self.hpcuser_user.user.email, "full_name": "User Name", "first_name": self.hpcuser_user.user.first_name, @@ -694,7 +694,7 @@ def test_get_succeed_alumni(self): expected = { "hpc_users": [ { - "uid": self.hpcuser_user.user.uid, + "uid": self.hpcuser_user.uid, "email": self.hpcuser_user.user.email, "full_name": "User Name", "first_name": self.hpcuser_user.user.first_name, diff --git a/adminsec/views.py b/adminsec/views.py index 5530678..66eefe8 100644 --- a/adminsec/views.py +++ b/adminsec/views.py @@ -73,6 +73,9 @@ HpcUserCreateRequest, HpcUserDeleteRequest, TermsAndConditions, + get_next_hpcgroup_gid, + get_next_hpcproject_gid, + get_next_hpcuser_uid, ) from usersec.views import ( MSG_PART_GROUP_CREATION, @@ -370,6 +373,7 @@ def post(self, request, *args, **kwargs): description=obj.description, creator=self.request.user, name=obj.name, + gid=get_next_hpcgroup_gid(), folders=obj.folders, expiration=obj.expiration, ) @@ -384,6 +388,7 @@ def post(self, request, *args, **kwargs): creator=self.request.user, description="PI, created together with accepting the group request.", username=username, + uid=get_next_hpcuser_uid(), status=OBJECT_STATUS_ACTIVE, expiration=datetime(year=timezone.now().year + 1, month=1, day=31), home_directory=DEFAULT_HOME_DIRECTORY.format(username=username), @@ -953,6 +958,7 @@ def post(self, request, *args, **kwargs): project = HpcProject.objects.create_with_version( group=obj.group, name=obj.name, + gid=get_next_hpcproject_gid(), folders=obj.folders, description=obj.description, resources_requested=obj.resources_requested, diff --git a/usersec/migrations/0031_hpcuser_uid_hpcuserversion_uid.py b/usersec/migrations/0031_hpcuser_uid_hpcuserversion_uid.py new file mode 100644 index 0000000..c3dc45c --- /dev/null +++ b/usersec/migrations/0031_hpcuser_uid_hpcuserversion_uid.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.17 on 2024-12-12 13:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("usersec", "0030_alter_hpcgroupchangerequest_status_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="hpcuser", + name="uid", + field=models.IntegerField( + help_text="Id of the user on the cluster", null=True + ), + ), + migrations.AddField( + model_name="hpcuserversion", + name="uid", + field=models.IntegerField( + help_text="Id of the user on the cluster", null=True + ), + ), + ] diff --git a/usersec/models.py b/usersec/models.py index eea173a..ad14e24 100644 --- a/usersec/models.py +++ b/usersec/models.py @@ -108,6 +108,28 @@ RE_EMAIL = r"^\S+@\S+\.\S+$" +def _get_next_id(model, id_type): + _id = 0 + for o in model.objects.all(): + if getattr(o, id_type) is None: + continue + if getattr(o, id_type) > _id: + _id = getattr(o, id_type) + return _id + 1 + + +def get_next_hpcuser_uid(): + return _get_next_id(HpcUser, "uid") + + +def get_next_hpcgroup_gid(): + return _get_next_id(HpcGroup, "gid") + + +def get_next_hpcproject_gid(): + return _get_next_id(HpcProject, "gid") + + # ------------------------------------------------------------------------------ # Mixins # ------------------------------------------------------------------------------ @@ -581,6 +603,9 @@ class Meta: #: POSIX username on the cluster. username = models.CharField(max_length=32, help_text="Username of the user on the cluster") + #: POSIX id of the user on the cluster. + uid = models.IntegerField(null=True, help_text="Id of the user on the cluster") + #: Expiration date of the user account expiration = models.DateTimeField(help_text="Expiration date of the user account") @@ -658,8 +683,8 @@ def __repr__(self): f"id={self.id}," f"user={self.user.username if self.user else None}," f"username={self.username}," - f"uid={self.user.uid if self.user else None}," - f"primary_group={self.primary_group.name}," + f"uid={self.uid}," + f"primary_group={self.primary_group.name if self.primary_group else None}," f"status={self.status}," f"creator={self.creator.username if self.creator else None}," f"current_version={self.current_version})" @@ -725,7 +750,7 @@ def __repr__(self): f"user={self.user.username if self.user else None}," f"username={self.username}," f"uid={self.uid}," - f"primary_group={self.primary_group.name}," + f"primary_group={self.primary_group.name if self.primary_group else None}," f"status={self.status}," f"creator={self.creator.username if self.creator else None}," f"version={self.version})" diff --git a/usersec/serializers.py b/usersec/serializers.py index a5909fa..74bd344 100644 --- a/usersec/serializers.py +++ b/usersec/serializers.py @@ -38,7 +38,7 @@ class HpcUserAbstractSerializer(HpcObjectAbstractSerializer): resources_used = serializers.JSONField() status = serializers.CharField(read_only=True) description = serializers.CharField(read_only=True) - uid = serializers.SerializerMethodField() + uid = serializers.IntegerField(read_only=True) username = serializers.CharField(read_only=True) expiration = serializers.DateTimeField(read_only=True) email = serializers.SerializerMethodField() @@ -65,9 +65,6 @@ def get_first_name(self, obj) -> Optional[str]: def get_phone_number(self, obj) -> Optional[str]: return obj.user.phone - def get_uid(self, obj) -> Optional[int]: - return obj.user.uid - class Meta: fields = HpcObjectAbstractSerializer.Meta.fields + [ "email", diff --git a/usersec/tests/factories.py b/usersec/tests/factories.py index 2be74d2..1a87cc7 100644 --- a/usersec/tests/factories.py +++ b/usersec/tests/factories.py @@ -176,7 +176,7 @@ class Meta: } description = "this is a group" creator = factory.SubFactory(UserFactory) # User - gid = 2000 + gid = 5000 name = factory.Sequence(lambda n: f"group{n}") folders = { "tier1_scratch": "/data/scratch/group", @@ -242,6 +242,7 @@ class Meta: creator = factory.SubFactory(UserFactory) # User description = "this is a user" username = factory.Sequence(lambda n: f"user{n}_" + settings.INSTITUTE_USERNAME_SUFFIX) + uid = 2000 expiration = datetime(2050, 1, 1, tzinfo=utc) home_directory = factory.LazyAttribute(lambda o: f"/data/cephfs-1/home/users/{o.username}") @@ -309,7 +310,7 @@ class Meta: creator = factory.SubFactory(UserFactory) # User delegate = None # HpcUser description = "this is a project" - gid = 5000 + gid = 6000 name = factory.Sequence(lambda n: f"hpc-project{n}") folders = { "tier1_scratch": "/data/scratch/project", diff --git a/usersec/tests/snapshots/snap_test_serializers.py b/usersec/tests/snapshots/snap_test_serializers.py index 1887953..259ea14 100644 --- a/usersec/tests/snapshots/snap_test_serializers.py +++ b/usersec/tests/snapshots/snap_test_serializers.py @@ -6,74 +6,6 @@ snapshots = Snapshot() -snapshots["TestHcpaccessStatus::testSerializerExisting 1"] = { - "hpc_groups": [ - { - "delegate": None, - "description": "this is a group", - "expiration": "2050-01-01T00:00:00Z", - "folders": { - "tier1_scratch": "/data/scratch/group", - "tier1_work": "/data/work/group", - "tier2_mirrored": "/data/mirrored/group", - "tier2_unmirrored": "/data/unmirrored/group", - }, - "gid": 2000, - "name": "group0", - "owner": None, - "resources_requested": { - "tier1_scratch": 1, - "tier1_work": 1, - "tier2_mirrored": 0, - "tier2_unmirrored": 0, - }, - "status": "INITIAL", - } - ], - "hpc_projects": [ - { - "delegate": None, - "description": "this is a project", - "expiration": "2050-01-01T00:00:00Z", - "folders": { - "tier1_scratch": "/data/scratch/project", - "tier1_work": "/data/work/project", - "tier2_mirrored": "/data/mirrored/project", - "tier2_unmirrored": "/data/unmirrored/project", - }, - "gid": 5000, - "group": "group0", - "members": [], - "name": "hpc-project0", - "resources_requested": { - "tier1_scratch": 1, - "tier1_work": 1, - "tier2_mirrored": 0, - "tier2_unmirrored": 0, - }, - "status": "INITIAL", - } - ], - "hpc_users": [ - { - "description": "this is a user", - "email": "email_placeholder", - "expiration": "2050-01-01T00:00:00Z", - "first_name": "first_name_placeholder", - "full_name": "name_placeholder", - "home_directory": "/data/cephfs-1/home/users/user0_c", - "last_name": "last_name_placeholder", - "login_shell": "/usr/bin/bash", - "phone_number": "phone_number_placeholder", - "primary_group": "primary_group_name_placeholder", - "resources_requested": {"tier1_home": 1.0}, - "status": "INITIAL", - "uid": 2000, - "username": "user0_c", - } - ], -} - snapshots["TestHpcGroupCreateRequestSerializer::testSerializerExisting 1"] = { "current_version": 1, "date_created": "2019-01-01T00:00:00Z", @@ -97,7 +29,7 @@ "tier2_mirrored": "/data/mirrored/group", "tier2_unmirrored": "/data/unmirrored/group", }, - "gid": 2000, + "gid": 5000, "name": "group0", "owner": None, "resources_requested": { @@ -126,7 +58,7 @@ "tier2_mirrored": "/data/mirrored/group", "tier2_unmirrored": "/data/unmirrored/group", }, - "gid": 2000, + "gid": 5000, "name": "group0", "owner": None, "resources_requested": { @@ -164,7 +96,7 @@ "tier2_mirrored": "/data/mirrored/project", "tier2_unmirrored": "/data/unmirrored/project", }, - "gid": 5000, + "gid": 6000, "group": "group_uuid_placeholder", "members": [], "name": "hpc-project0", @@ -194,7 +126,7 @@ "tier2_mirrored": "/data/mirrored/project", "tier2_unmirrored": "/data/unmirrored/project", }, - "gid": 5000, + "gid": 6000, "group": "group_name_placeholder", "members": [], "name": "hpc-project0", diff --git a/usersec/tests/test_models.py b/usersec/tests/test_models.py index 581033f..0a6d943 100644 --- a/usersec/tests/test_models.py +++ b/usersec/tests/test_models.py @@ -47,6 +47,9 @@ HpcUserDeleteRequestVersion, HpcUserVersion, TermsAndConditions, + get_next_hpcgroup_gid, + get_next_hpcproject_gid, + get_next_hpcuser_uid, parse_email, user_active, ) @@ -488,6 +491,35 @@ def _test_has_pending_requests_false(self): self.assertFalse(obj.has_pending_requests()) +class TestGetNextIdFunctions(TestCase): + def test_get_next_hpcuser_id(self): + HpcUserFactory(uid=2000) + HpcUserFactory(uid=2002) + self.assertEqual(get_next_hpcuser_uid(), 2003) + + def test_get_next_hpcuser_id_all_none(self): + HpcUserFactory(uid=None) + self.assertEqual(get_next_hpcuser_uid(), 1) + + def test_get_next_hpcgroup_id(self): + HpcGroupFactory(gid=5000) + HpcGroupFactory(gid=5002) + self.assertEqual(get_next_hpcgroup_gid(), 5003) + + def test_get_next_hpcgroup_id_all_none(self): + HpcGroupFactory(gid=None) + self.assertEqual(get_next_hpcgroup_gid(), 1) + + def test_get_next_hpcproject_id(self): + HpcProjectFactory(gid=6000) + HpcProjectFactory(gid=6002) + self.assertEqual(get_next_hpcproject_gid(), 6003) + + def test_get_next_hpcproject_id_all_none(self): + HpcProjectFactory(gid=None) + self.assertEqual(get_next_hpcproject_gid(), 1) + + class TestHpcUser(VersionTesterMixin, PendingRequestTesterMixin, TestCase): """Tests for HpcUser model""" diff --git a/usersec/tests/test_serializers.py b/usersec/tests/test_serializers.py index 5230709..7a325c8 100644 --- a/usersec/tests/test_serializers.py +++ b/usersec/tests/test_serializers.py @@ -46,7 +46,6 @@ def testSerializerExisting(self): result["full_name"] = "name_placeholder" result["first_name"] = "first_name_placeholder" result["last_name"] = "last_name_placeholder" - result["uid"] = 2000 self.assertMatchSnapshot(result) @@ -124,7 +123,6 @@ def testSerializerExisting(self): result["full_name"] = "name_placeholder" result["first_name"] = "first_name_placeholder" result["last_name"] = "last_name_placeholder" - result["uid"] = 2000 self.assertMatchSnapshot(result) diff --git a/usersec/views.py b/usersec/views.py index 2e848e2..17a271a 100644 --- a/usersec/views.py +++ b/usersec/views.py @@ -66,6 +66,7 @@ HpcUserCreateRequest, HpcUserDeleteRequest, TermsAndConditions, + get_next_hpcuser_uid, ) # ----------------------------------------------------------------------------- @@ -1824,6 +1825,7 @@ def get(self, request, *args, **kwargs): resources_requested=obj.hpcusercreaterequest.resources_requested, creator=obj.hpcusercreaterequest.editor, username=username, + uid=get_next_hpcuser_uid(), status=OBJECT_STATUS_ACTIVE, expiration=obj.hpcusercreaterequest.expiration, home_directory=DEFAULT_HOME_DIRECTORY.format(username=username),