ubccr / coldfront

HPC Resource Allocation System
https://coldfront.readthedocs.io
GNU General Public License v3.0
96 stars 76 forks source link

Bug: Issue creating allocations using coldfront shell #603

Open lcrownover opened 3 months ago

lcrownover commented 3 months ago

What happened?

I'm working through a sync tool to sync our site data from AD/Slurm into Coldfront in preparation for a cutover in the future.

I've been successful creating users, projects, project users, and resources, but I'm running into an error while creating Allocations that I'm unsure how to work around:

>>> cfp = Project.objects.get(title="racs")
>>> cfp
<Project: racs>
>>> cfp.pi
<User: dmajchrz>

>>> cf_alloc_active = AllocationStatusChoice.objects.get(name="Active")
>>> cf_alloc_active
<AllocationStatusChoice: Active>

>>> Allocation.objects.create(project=cfp, status=cf_alloc_active)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/base.py", line 521, in __repr__
    return '<%s: %s>' % (self.__class__.__name__, self)
                                                  ^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/coldfront/core/allocation/models.py", line 343, in __str__
    return "%s (%s)" % (self.get_parent_resource.name, self.project.pi)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'name'

I'm not a big django guy but it looks like it's failing to create it because the project model uses title rather than name?

If this isn't a bug, could you please provide some direction on how I can create an Allocation using the coldfront shell?

Thanks!!

Version

1.1.5

Component

Allocations

What browsers are you seeing the problem on?

None

Relevant log output

see desc

Tasks/ user tests when bug is fixed

lcrownover commented 3 months ago

To give some further troubleshooting information:

I deleted all the broken allocations from the database:

DELETE FROM allocation_allocation WHERE quantity=1 <- easiest way to clear them all

Then I performed the following steps:

racs = Project.objects.get(title="racs")
active = AllocationStatusChoice.objects.get(name="Active")
Allocation.objects.create(project=racs, status=active)

Which returns:

>>> Allocation.objects.create(project=racs, status=active)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/base.py", line 521, in __repr__
    return '<%s: %s>' % (self.__class__.__name__, self)
                                                  ^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/coldfront/core/allocation/models.py", line 343, in __str__
    return "%s (%s)" % (self.get_parent_resource.name, self.project.pi)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'name'

But the entry gets created in the database:

MariaDB [coldfront]> select * from allocation_allocation;+-----+----------------------------+----------------------------+----------+------------+----------+---------------+-------------+------------+-----------+-----------+---------------+
| id  | created                    | modified                   | quantity | start_date | end_date | justification | description | project_id | status_id | is_locked | is_changeable |
+-----+----------------------------+----------------------------+----------+------------+----------+---------------+-------------+------------+-----------+-----------+---------------+
| 847 | 2024-03-20 18:31:06.208632 | 2024-03-20 18:31:06.208632 |        1 | NULL       | NULL     |               | NULL        |        385 |         1 |         0 |             0 |
+-----+----------------------------+----------------------------+----------+------------+----------+---------------+-------------+------------+-----------+-----------+---------------+
1 row in set (0.000 sec)

However when I go query the Allocation objects:

>>> Allocation.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/query.py", line 259, in __repr__
    return '<%s %r>' % (self.__class__.__name__, data)
                                                 ^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/base.py", line 521, in __repr__
    return '<%s: %s>' % (self.__class__.__name__, self)
                                                  ^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/coldfront/core/allocation/models.py", line 343, in __str__
    return "%s (%s)" % (self.get_parent_resource.name, self.project.pi)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'name'

That breaks.

I also receive a "We're having a bit of system trouble at the moment. Please check back soon!" if I try to delete the allocation from the django admin interface.

Looking into the error, it's failing to call the name attribute on the resources contained in the allocation. In this case, there are no resources.

Unfortunately I can't assign resources like so:

>>> Allocation.objects.create(project=racs, status=active, resources=[])
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/query.py", line 451, in create
    obj = self.model(**kwargs)
          ^^^^^^^^^^^^^^^^^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/base.py", line 498, in __init__
    _setattr(self, prop, kwargs[prop])
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/fields/related_descriptors.py", line 545, in __set__
    raise TypeError(
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use resources.set() instead.

But I can fix it like so:

>>> r = Resource.objects.get(name="Talapas2")
>>> r
<Resource: Talapas2 (Cluster)>
>>> a = Allocation.objects.get(project=racs)
>>> a
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/coldfront/venv/lib/python3.11/site-packages/django/db/models/base.py", line 521, in __repr__
    return '<%s: %s>' % (self.__class__.__name__, self)
                                                  ^^^^
  File "/srv/coldfront/venv/lib/python3.11/site-packages/coldfront/core/allocation/models.py", line 343, in __str__
    return "%s (%s)" % (self.get_parent_resource.name, self.project.pi)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'name'
>>> a.resources.set([r])
>>> a.save()
>>> a
<Allocation: Talapas2 (dmajchrz)>

This allocation seems to be working.

This may just be a lack of understanding on how to create django objects with complex relationships. I'd love if the Importing Data documentation could be updated with examples of how to create all those resource types using raw python, like you have listed for the Adding Users to Allocations section.

I'm really looking forward to #316, but in the mean time you gotta do whatcha gotta do 😊 I wish I could help with that request, but I'm booked solid until July.

I've opened a PR that includes a proposed fix to silence the error from this issue. Probably not the best way to go about it, but it should work.