Skip to content

Commit 51ee82d

Browse files
Merge branch 'include_owned_resources_on_user_home' of https://github.com/theam/fasrc-coldfront into include_owned_resources_on_user_home
2 parents fd8fa5d + c3a1f68 commit 51ee82d

File tree

21 files changed

+937
-80
lines changed

21 files changed

+937
-80
lines changed

.github/workflows/django.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
docker run -d --rm --name coldfront -v `pwd`:/usr/src/app \
5959
-e PLUGIN_SFTOCF=True -e SFUSER=${{ secrets.SFUSER }} -e SFPASS=${{ secrets.SFPASS }} \
6060
-e PLUGIN_IFX=True -e PLUGIN_FASRC=True -e NEO4JP=${{ secrets.NEO4JP }} \
61-
-e PLUGIN_API=True -e PLUGIN_LDAP=True \
61+
-e PLUGIN_API=True -e PLUGIN_LDAP=True -e PLUGIN_LFS=True \
6262
-e AUTH_LDAP_SERVER_URI=${{ secrets.AUTH_LDAP_SERVER_URI }} \
6363
-e AUTH_LDAP_BIND_DN=${{ secrets.AUTH_LDAP_BIND_DN }} \
6464
-e AUTH_LDAP_BIND_PASSWORD=${{ secrets.AUTH_LDAP_BIND_PASSWORD }} \

coldfront/config/plugins/lfs.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from coldfront.config.env import ENV
2+
from coldfront.config.logging import LOGGING
3+
from coldfront.config.base import INSTALLED_APPS
4+
5+
INSTALLED_APPS += ['coldfront.plugins.lfs']
6+
7+
LFS_HOST = ENV.str('LFS_HOST', default='localhost')
8+
LFS_PORT = ENV.int('LFS_PORT', default=50051)

coldfront/config/settings.py

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
'PLUGIN_LDAP_USER_SEARCH': 'plugins/ldap_user_search.py',
2929
'PLUGIN_API': 'plugins/api.py',
3030
'PLUGIN_LDAP': 'plugins/ldap_fasrc.py',
31+
'PLUGIN_LFS': 'plugins/lfs.py',
3132
'PLUGIN_SFTOCF': 'plugins/sftocf.py',
3233
'PLUGIN_FASRC': 'plugins/fasrc.py',
3334
'PLUGIN_FASRC_MONITORING': 'plugins/fasrc_monitoring.py',

coldfront/core/allocation/templates/allocation/allocation_add_users.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,12 @@ <h2>Add users to allocation for project: {{allocation.project.title}}</h2>
155155
}
156156
if (q.indexOf('\n') >= 0) {
157157
$("#id_id_search_by_0_1").prop("checked", true);
158+
q = q.replace(/(?:\r\n|\r|\n)/g, ' ')
158159
}
159160

160161
var pk = "{{ pk }}"
161162
$.ajax({
162-
url : "{% url 'allocation-add-users' allocation.pk %}?search="+q, // the endpoint
163+
url : encodeURI("{% url 'allocation-add-users' allocation.pk %}?search="+q), // the endpoint
163164
type : "GET", // http method
164165
// handle a successful response
165166
success : function(data) {

coldfront/core/allocation/tests/test_views_cluster.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""View tests for cluster allocations"""
22
import logging
33

4+
import urllib.parse
45
from django.db.models import Count
56
from django.test import TestCase
67
from django.urls import reverse
@@ -155,6 +156,26 @@ def test_allocationaddusersview_access(self):
155156
utils.test_user_can_access(self, self.pi_user, self.url)
156157
utils.test_user_cannot_access(self, self.proj_allocationuser, self.url)
157158

159+
def test_allocation_non_project_user_space_separated_search(self):
160+
username_list = ['iberlin', 'gvanrossum']
161+
space_separated_search = " ".join(username_list)
162+
self.client.force_login(self.admin_user, backend="django.contrib.auth.backends.ModelBackend")
163+
url = f'/allocation/{self.cluster_allocation.pk}/add-users?search={space_separated_search}'
164+
space_separated_search_response = str(self.client.get(url).content)
165+
self.assertTrue('Found 2 matchs.' in space_separated_search_response)
166+
self.assertTrue('<td>iberlin</td>' in space_separated_search_response)
167+
self.assertTrue('<td>gvanrossum</td>' in space_separated_search_response)
168+
169+
def test_allocation_non_project_user_new_line_separated_search(self):
170+
username_list = ['iberlin', 'gvanrossum']
171+
new_line_separated_search = urllib.parse.quote_plus("\n".join(username_list))
172+
self.client.force_login(self.admin_user, backend="django.contrib.auth.backends.ModelBackend")
173+
url = f'/allocation/{self.cluster_allocation.pk}/add-users?search={new_line_separated_search}'
174+
new_line_separated_search_response = str(self.client.get(url).content)
175+
self.assertTrue('<td>iberlin</td>' in new_line_separated_search_response)
176+
self.assertTrue('<td>gvanrossum</td>' in new_line_separated_search_response)
177+
self.assertTrue('Found 2 matchs.' in new_line_separated_search_response)
178+
158179

159180
class ClusterAllocationEditUsersViewTest(ClusterAllocationViewBaseTest):
160181
"""Tests for the AllocationEditUsersView"""

coldfront/core/allocation/views.py

+21-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from io import BytesIO
99
from lib2to3.fixes.fix_input import context
10+
import requests
1011

1112
from xhtml2pdf import pisa
1213

@@ -869,15 +870,26 @@ def get_users_to_add(self, allocation_obj):
869870
return users_to_add
870871

871872
def non_project_users_search(self, allocation_obj, search_term):
872-
like_filter = (Q(username__icontains=search_term) or Q(first_name__icontains=search_term) or Q(
873-
last_name__icontains=search_term) or Q(title_icontains=search_term))
874-
non_project_users = (
875-
self.get_non_project_users_to_add(allocation_obj, return_all=True)
876-
.filter(like_filter)
877-
.exclude(project=allocation_obj.project)
878-
.values('username', 'first_name', 'last_name', 'email')
879-
)
880-
return non_project_users
873+
user_list = []
874+
search_term = requests.utils.unquote(search_term)
875+
user_search = search_term.split(" ") if " " in search_term else search_term.splitlines()
876+
for username in user_search:
877+
like_filter = (
878+
Q(username__icontains=username)
879+
or Q(first_name__icontains=username)
880+
or Q(last_name__icontains=username)
881+
or Q(title_icontains=username)
882+
)
883+
884+
non_project_users = (
885+
self.get_non_project_users_to_add(allocation_obj, return_all=True)
886+
.filter(like_filter)
887+
.exclude(project=allocation_obj.project)
888+
.values('username', 'first_name', 'last_name', 'email')
889+
)
890+
user_list += non_project_users
891+
892+
return user_list
881893

882894
def search_non_project_users(self, allocation_obj, search_term, request):
883895
found_non_project_users = self.non_project_users_search(allocation_obj, search_term)

coldfront/core/portal/views.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,11 @@ def allocation_by_fos(request):
271271
def allocation_summary(request):
272272

273273
allocation_resources = [
274-
allocation.get_parent_resource.parent_resource if allocation.get_parent_resource.parent_resource else allocation.get_parent_resource for allocation in Allocation.objects.filter(status__name='Active')]
274+
allocation.get_parent_resource.parent_resource
275+
if allocation.get_parent_resource.parent_resource
276+
else allocation.get_parent_resource
277+
for allocation in Allocation.objects.filter(status__name='Active').distinct()
278+
]
275279

276280
allocations_count_by_resource = dict(Counter(allocation_resources))
277281

coldfront/core/project/templates/project/project_detail.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ <h4>Storage &nbsp;
128128
<td>{{ allocation.get_parent_resource.name }}</td>
129129
<td>{{ allocation.path }}</td>
130130
<td>{{ allocation.allocationuser_set.count }}</td>
131-
<td>{{ allocation.size|floatformat:1 }} {{ allocation.get_parent_resource.unit }}</td>
131+
<td>{{ allocation.size|floatformat:1 }} {{ allocation.get_parent_resource.quantity_label }}</td>
132132
<td>{{ allocation.usage|floatformat:1 }}</td>
133133
<td>
134134
{% if allocation.requires_payment %}
@@ -198,7 +198,7 @@ <h4>Cluster</h4>
198198
<td>{{ allocation.get_parent_resource.name }}</td>
199199
<td>{{ allocation.allocationuser_set.count }}</td>
200200
<td>
201-
{{ allocation.size|floatformat:1 }} {{ allocation.get_parent_resource.unit }}
201+
{{ allocation.size|floatformat:1 }} {{ allocation.get_parent_resource.quantity_label }}
202202
</td>
203203
<td>
204204
<a href="{% url 'allocation-detail' allocation.pk %}">

coldfront/core/resource/management/commands/add_resource_defaults.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,22 @@ def handle(self, *args, **options):
2222
AttributeType.objects.get_or_create(name=attribute_type)
2323

2424
for resource_attribute_type, attribute_type in (
25+
#FASRC
2526
('capacity_tb', 'Float'),
2627
('free_tb', 'Float'),
2728
('used_tb', 'Float'),
2829
('file_count', 'Int'),
2930
('allocated_tb', 'Float'),
3031
('ChangeableAllocations', 'Yes/No'),
31-
# ('Core Count', 'Int'),
32+
('CPU Count', 'Int'),
33+
('GPU Count', 'Int'),
34+
('Features', 'Text'),
35+
# UBCCR
36+
('Core Count', 'Int'),
3237
# ('expiry_time', 'Int'),
3338
# ('fee_applies', 'Yes/No'),
3439
('Node Count', 'Int'),
35-
# ('Owner', 'Text'),
40+
('Owner', 'Text'),
3641
('quantity_default_value', 'Int'),
3742
('quantity_label', 'Text'),
3843
('xdmod_resource', 'Text'),
@@ -62,13 +67,14 @@ def handle(self, *args, **options):
6267
('Cloud', 'Cloud Computing'),
6368
('Cluster', 'Cluster servers'),
6469
('Cluster Partition', 'Cluster Partition'),
65-
# ('Compute Node', 'Compute Node'),
70+
('Compute Node', 'Compute Node'),
6671
# ('Server', 'Extra servers providing various services'),
6772
# ('Software License', 'Software license purchased by users'),
6873
# ('Storage', 'NAS storage'),
6974
):
7075
ResourceType.objects.get_or_create(
71-
name=resource_type, description=description
76+
name=resource_type,
77+
defaults={'description': description},
7278
)
7379

7480

coldfront/core/resource/templates/resource_detail.html

+67-43
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ <h3><i class="fas fa-list" aria-hidden="true"></i> Resource Information</h3>
8383
</div>
8484

8585
<!-- Start Storage Report -->
86-
{% if resource.resource_type.name == "Storage" %}
86+
{% if resource.resource_type.name == "Storage" and user_is_manager %}
8787
<div class="card mb-3">
8888
<div class="card-header">
8989
<h3 class="d-inline"><i class="fas fa-info-circle" aria-hidden="true"></i> Storage Report</h3>
@@ -95,7 +95,7 @@ <h3 class="d-inline"><i class="fas fa-info-circle" aria-hidden="true"></i> Stora
9595
{% endif %}
9696

9797
<!-- Start Resource Attributes -->
98-
{% if attributes or request.user.is_superuser %}
98+
{% if user_is_manager %}
9999
<div class="card mb-3">
100100
<div class="card-header">
101101
<h3 class="d-inline"><i class="fas fa-info-circle" aria-hidden="true"></i> Resource Attributes</h3>
@@ -174,7 +174,7 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Resource Ad
174174
</div>
175175

176176
<!-- Start Resource Allocations -->
177-
{% if user_is_manager and 'Cluster' in resource.resource_type.name %}
177+
{% if user_is_manager %}
178178
<div class="card mb-3">
179179
<div class="card-header">
180180
<h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Resource Allocations</h3>
@@ -183,11 +183,13 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Resource Al
183183
{# {% if user_sync_dt %}#}
184184
{# <span class="float-right">Last Sync: {{user_sync_dt}}</span>#}
185185
{# {% endif %}#}
186-
<div class="float-right">
187-
<a class="btn btn-danger" href="{% url 'resource-allocations-edit' resource.pk %}" role="button">
188-
<i class="fas fa-edit" aria-hidden="true"></i> Edit Resource Allocations
189-
</a>
190-
</div>
186+
{% if 'Cluster' in resource.resource_type.name %}
187+
<div class="float-right">
188+
<a class="btn btn-danger" href="{% url 'resource-allocations-edit' resource.pk %}" role="button">
189+
<i class="fas fa-edit" aria-hidden="true"></i> Edit Resource Allocations
190+
</a>
191+
</div>
192+
{% endif %}
191193
</div>
192194
<div class="card-body">
193195
<div class="table-responsive">
@@ -198,22 +200,28 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Resource Al
198200
<tr>
199201
<th scope="col">Project</th>
200202
<th scope="col">Users</th>
201-
<th scope="col">CPU Hours</th>
202-
<th scope="col">Percent Usage</th>
203-
<th scope="col">RawShare</th>
204-
<th scope="col">EffectvUsage <a class="info-button" title="EffectvUsage" data-toggle="popover" data-trigger="click"
205-
data-content="The fraction of the cluster the account has been granted. For more information, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."><i class="fas fa-info-circle"
206-
aria-hidden="true"></i></a>
207-
</th>
208-
<th scope="col">NormShares <a class="info-button" title="NormShares" data-toggle="popover" data-trigger="click"
209-
data-content="Calculated fairshare per user. For more information on this number, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."
210-
><i class="fas fa-info-circle" aria-hidden="true"></i></a>
211-
</th>
212-
<th scope="col">FairShare <a class="info-button" title="FairShare" data-toggle="popover" data-trigger="click"
213-
data-content="User fairshare, calculated by the equation 2^(-EffectvUsage/NormShares). For more information on fairshare calculation, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."
214-
><i class="fas fa-info-circle" aria-hidden="true"></i>
215-
</a>
216-
</th>
203+
{% if 'Cluster' in resource.resource_type.name %}
204+
<th scope="col">CPU Hours</th>
205+
<th scope="col">Percent Usage</th>
206+
<th scope="col">RawShare</th>
207+
<th scope="col">EffectvUsage <a class="info-button" title="EffectvUsage" data-toggle="popover" data-trigger="click"
208+
data-content="The fraction of the cluster the account has been granted. For more information, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."><i class="fas fa-info-circle"
209+
aria-hidden="true"></i></a>
210+
</th>
211+
<th scope="col">NormShares <a class="info-button" title="NormShares" data-toggle="popover" data-trigger="click"
212+
data-content="Calculated fairshare per user. For more information on this number, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."
213+
><i cl ass="fas fa-info-circle" aria-hidden="true"></i></a>
214+
</th>
215+
<th scope="col">FairShare <a class="info-button" title="FairShare" data-toggle="popover" data-trigger="click"
216+
data-content="User fairshare, calculated by the equation 2^(-EffectvUsage/NormShares). For more information on fairshare calculation, go <a href='https://docs.rc.fas.harvard.edu/kb/fairshare/#articleTOC_4' title='fairshare calculation'>here</a>."
217+
><i cla ss="fas fa-info-circle" aria-hidden="true"></i>
218+
</a>
219+
</th>
220+
{% elif resource.resource_type.name == 'Storage' %}
221+
<th scope="col">Path</th>
222+
<th scope="col">Quota ({{ resource.quantity_label }})</th>
223+
<th scope="col">Used ({{ resource.quantity_label }})</th>
224+
{% endif %}
217225
</tr>
218226
</thead>
219227

@@ -226,28 +234,44 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Resource Al
226234
</a>
227235
</td>
228236
<td>{{ allocation.user_count }}</td>
229-
<td data-sort="{{allocation.usage}}" name="usage">
230-
{% if allocation.usage is None %}
231-
0
232-
{% else %}
233-
{{ allocation.usage|floatformat:1 }}
234-
{% endif %}
235-
</td>
236-
<td data-sort="{{allocation.usage}}" name="usage_pct">
237-
{% if allocation.usage is None or allocation.usage == 0 %}
238-
0%
239-
{% else %}
240-
{{allocation.usage|div:total_hours|mul:100|floatformat:2 }}%
241-
{% endif %}
242-
</td>
243-
<td>{{ allocation.rawshares}}</td>
244-
<td>{{ allocation.effectvusage }}</td>
245-
<td>{{ allocation.normshares }}</td>
246-
<td>{{ allocation.fairshare }}</td>
247-
237+
{% if 'Cluster' in resource.resource_type.name %}
238+
<td data-sort="{{allocation.usage}}" name="usage">
239+
{% if allocation.usage is None %}
240+
0
241+
{% else %}
242+
{{ allocation.usage|floatformat:1 }}
243+
{% endif %}
244+
</td>
245+
<td data-sort="{{allocation.usage}}" name="usage_pct">
246+
{% if allocation.usage is None or allocation.usage == 0 %}
247+
0%
248+
{% else %}
249+
{{allocation.usage|div:total_hours|mul:100|floatformat:2 }}%
250+
{% endif %}
251+
</td>
252+
<td>{{ allocation.rawshares}}</td>
253+
<td>{{ allocation.effectvusage }}</td>
254+
<td>{{ allocation.normshares }}</td>
255+
<td>{{ allocation.fairshare }}</td>
256+
{% elif resource.resource_type.name == 'Storage' %}
257+
<td>{{ allocation.path }}</td>
258+
<td>{{ allocation.size|floatformat:2 }}</td>
259+
<td>{{ allocation.usage|floatformat:2 }}</td>
260+
{% endif %}
248261
</tr>
249262
{% endfor %}
250263
</tbody>
264+
{% if resource.resource_type.name == 'Storage' %}
265+
<tfoot>
266+
<tr style="background-color:#C2C2C2;font-weight:bold">
267+
<td>Total Tracked Storage</td>
268+
<td></td>
269+
<td></td>
270+
<td>{{ allocation_total.size|floatformat:1}}</td>
271+
<td>{{ allocation_total.usage|floatformat:1}}</td>
272+
</tr>
273+
</tfoot>
274+
{% endif %}
251275
</table>
252276
</div>
253277

0 commit comments

Comments
 (0)