Skip to content

Commit

Permalink
Anonymous demo mode (#33)
Browse files Browse the repository at this point in the history
The private information such as usernames is replaced by an anonymized name. This is intended for presentation since some of the anonymization is done in javascript and the URLs still contain the username.
  • Loading branch information
guilbaults authored Sep 19, 2023
1 parent e43234a commit f8ca51b
Show file tree
Hide file tree
Showing 20 changed files with 162 additions and 34 deletions.
21 changes: 18 additions & 3 deletions accountstats/templates/accountstats/account.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
{% load humanize %}
{% load i18n %}

{% block title %}{% translate "Account use of" %} {{ account }}{% endblock title %}
{% block title %}{% translate "Account use of" %} {{ account | anonymize }}{% endblock title %}

{% block content %}
{% include "notes_header.html" %}
{% if user.is_staff%}
<p><a class="btn btn-primary" href="{{settings.BASE_URL}}secure/notes/new?account={{account}}">{% translate "Create a new note" %}</a></p>
{% endif %}

<h1>{% translate "Account use of" %} {{ account }}</h1>
<h1>{% translate "Account use of" %} {{ account | anonymize}}</h1>
<div class="card">
<div class="card-body">
<div class="card-text">
Expand Down Expand Up @@ -222,6 +222,13 @@ <h2>{% translate "Jobs running with this account" %}</h2>
{ data: 'username',
orderable: false,
searchable: false,
render: function(date, type, row, meta){
if(document.getElementById("demo")){
return '[redacted]';
} else {
return row.username;
}
}
},
{ data: 'id_job',
render: function ( data, type, row ) {
Expand All @@ -235,7 +242,15 @@ <h2>{% translate "Jobs running with this account" %}</h2>
return '<span class="badge badge-' + state_to_badge(data) + '">' + data + '</span>';
}
},
{ data: 'job_name' },
{ data: 'job_name',
render: function(date, type, row, meta){
if(document.getElementById("demo")){
return '[redacted]';
} else {
return row.job_name;
}
}
},
{ data: 'time_submit',
render: parse_time,
},
Expand Down
5 changes: 3 additions & 2 deletions accountstats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils.translation import gettext as _
from userportal.common import account_or_staff, Prometheus, parse_start_end
from userportal.common import compute_allocations_by_user, compute_allocations_by_slurm_account
from userportal.common import anonymize as a
from notes.models import Note


Expand Down Expand Up @@ -78,7 +79,7 @@ def graph(request, query, stacked=True, unit=None):
'x': x,
'y': y,
'type': 'scatter',
'name': user,
'name': a(user),
'hovertemplate': '%{y:.1f}',
}
if stacked:
Expand Down Expand Up @@ -157,7 +158,7 @@ def graph_lustre_ost(request, account):

for line in stats:
fs = line['metric']['fs']
user = line['metric']['user']
user = a(line['metric']['user'])
x = list(map(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), line['x']))
if i == 'read':
y = line['y']
Expand Down
2 changes: 1 addition & 1 deletion cloudstats/templates/cloudstats/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h4>{% translate "Memory used" %}</h4>
<tbody>
{% for project in all_projects %}
<tr>
<td><a href="{{ project.name }}">{{project.name}}</a></td>
<td><a href="{{ project.id }}">{{project.name | anonymize }}</a></td>
<td>{{project.cores}}</td>
</tr>
{% endfor %}
Expand Down
4 changes: 2 additions & 2 deletions cloudstats/templates/cloudstats/instance.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
{% load humanize %}
{% load i18n %}

{% block title %}{% translate "Your instance use" %}{% endblock title %}
{% block title %}{% translate "Your instance " %}{{instance_name | anonymize }}{% endblock title %}

{% block content %}
<h1>{% translate "Your instance use" %}</h1>
<h1>{% translate "Your instance " %}{{instance_name | anonymize }}</h1>

{% include "nav_last_month.html" %}

Expand Down
2 changes: 1 addition & 1 deletion cloudstats/templates/cloudstats/project.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h3>{% translate "Your instances" %}</h3>
<tbody>
{% for instance in instances %}
<tr>
<td><a href="{{ instance.uuid }}">{{ instance.instance_name }}</a></td>
<td><a href="{{ instance.uuid }}">{{ instance.instance_name | anonymize }}</a></td>
<td>{{ instance.instance_type }}</td>
<td>{{ instance.uuid }}</td>
</tr>
Expand Down
37 changes: 24 additions & 13 deletions cloudstats/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.shortcuts import render
from django.http import JsonResponse
from userportal.common import openstackproject_or_staff, cloud_projects_by_user, request_to_username, staff, Prometheus, query_time
from userportal.common import anonymize as a
from django.conf import settings
from datetime import datetime, timedelta
from django.contrib.auth.decorators import login_required
Expand All @@ -21,7 +22,11 @@ def index(request):
filter=prom.get_filter(),
)
for project in prom.query_last(query_projects):
context['all_projects'].append({'name': project['metric']['project_name'], 'cores': int(project['value'][1])})
context['all_projects'].append({
'id': project['metric']['project_name'],
'name': project['metric']['project_name'],
'cores':
int(project['value'][1])})

return render(request, 'cloudstats/index.html', context)

Expand All @@ -46,6 +51,12 @@ def project(request, project):
@openstackproject_or_staff
def instance(request, project, uuid):
context = {}
query_instances = 'libvirtd_domain_domain_state{{project_name="{project}", uuid="{uuid}", {filter}}}'.format(
project=project,
uuid=uuid,
filter=prom.get_filter())
stats_instances = prom.query_prometheus_multiple(query_instances, datetime.now() - timedelta(days=7), datetime.now())
context['instance_name'] = stats_instances[0]['metric']['instance_name']

return render(request, 'cloudstats/instance.html', context)

Expand All @@ -70,9 +81,9 @@ def project_graph_cpu(request, project):
x = list(map(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), line['x']))
y = line['y']
if instance_counter[line['metric']['instance_name']] > 1:
name = '{0} {1}'.format(line['metric']['instance_name'], line['metric']['uuid'])
name = '{0} {1}'.format(a(line['metric']['instance_name']), line['metric']['uuid'])
else:
name = line['metric']['instance_name']
name = a(line['metric']['instance_name'])
data.append({
'x': x,
'y': y,
Expand Down Expand Up @@ -121,7 +132,7 @@ def projects_graph_cpu(request):
'y': line['y'],
'type': 'scatter',
'stackgroup': 'one',
'name': line['metric']['project_name'],
'name': a(line['metric']['project_name']),
'hovertemplate': '%{y:.1f}',
})

Expand Down Expand Up @@ -214,9 +225,9 @@ def project_graph_memory(request, project):
x = list(map(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), line['x']))
y = line['y']
if instance_counter[line['metric']['instance_name']] > 1:
name = '{0} {1}'.format(line['metric']['instance_name'], line['metric']['uuid'])
name = '{0} {1}'.format(a(line['metric']['instance_name']), line['metric']['uuid'])
else:
name = line['metric']['instance_name']
name = a(line['metric']['instance_name'])
data.append({
'x': x,
'y': y,
Expand Down Expand Up @@ -313,7 +324,7 @@ def projects_graph_mem(request):
'y': line['y'],
'type': 'scatter',
'stackgroup': 'one',
'name': line['metric']['project_name'],
'name': a(line['metric']['project_name']),
'hovertemplate': '%{y:.1f}',
})

Expand Down Expand Up @@ -365,9 +376,9 @@ def project_graph_disk_bandwidth(request, project):
else:
y = [-x for x in line['y']]
if instance_counter[line['metric']['instance_name']] > 1:
name = '{0} {1}'.format(line['metric']['instance_name'], line['metric']['uuid'])
name = '{0} {1}'.format(a(line['metric']['instance_name']), line['metric']['uuid'])
else:
name = line['metric']['instance_name']
name = a(line['metric']['instance_name'])
data.append({
'x': x,
'y': y,
Expand Down Expand Up @@ -451,9 +462,9 @@ def project_graph_disk_iops(request, project):
else:
y = [-x for x in line['y']]
if instance_counter[line['metric']['instance_name']] > 1:
name = '{0} {1}'.format(line['metric']['instance_name'], line['metric']['uuid'])
name = '{0} {1}'.format(a(line['metric']['instance_name']), line['metric']['uuid'])
else:
name = line['metric']['instance_name']
name = a(line['metric']['instance_name'])
data.append({
'x': x,
'y': y,
Expand Down Expand Up @@ -534,9 +545,9 @@ def project_graph_network_bandwidth(request, project):
else:
y = [-x for x in line['y']]
if instance_counter[line['metric']['instance_name']] > 1:
name = '{0} {1}'.format(line['metric']['instance_name'], line['metric']['uuid'])
name = '{0} {1}'.format(a(line['metric']['instance_name']), line['metric']['uuid'])
else:
name = line['metric']['instance_name']
name = a(line['metric']['instance_name'])
data.append({
'x': x,
'y': y,
Expand Down
8 changes: 4 additions & 4 deletions jobstats/templates/jobstats/job.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ <h2>{% translate "Jobs" %}</h2>
</table>

{% else %}

<h1>{% translate "Details on job" %} {{job.job_name}} ({{job_id}})</h1>
<h1>{% translate "Details on job" %} {{job.job_name | anonymize}} ({{job_id}})</h1>
<p><span class="badge badge-{{job.status_badge}}">{{job.status}}</span></p>
<div class="progress">
{% if job.time_start != 0 and job.time_end == 0 %}
Expand Down Expand Up @@ -125,9 +124,10 @@ <h2>{% translate "Scheduler info" %}</h2>
<tr>
<td>
{% if 'accountstats' in settings.INSTALLED_APPS %}
<a href="{{settings.BASE_URL}}secure/accountstats/{{ job.account }}">{{job.account}}</a>
<a href="{{settings.BASE_URL}}secure/accountstats/{{ job.account }}">{{job.account | anonymize}}
</a>
{% else %}
{{job.account}}
{{job.account | anonymize}}
{% endif %}
</td>
<td><span data-toggle="tooltip" data-placement="top" title="{{job.time_submit_dt}}">{{job.time_submit_dt | naturaltime}} <span data-feather="info"></span></span></td>
Expand Down
9 changes: 8 additions & 1 deletion jobstats/templates/jobstats/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,14 @@ <h1>{% translate "Your jobs" %}</h1>
return '<span class="badge badge-' + state_to_badge(data) + '">' + data + '</span>';
}
},
{ data: 'job_name' },
{ data: 'job_name',
render: function(date, type, row, meta){
if(document.getElementById("demo")){
return '[redacted]';
} else {
return row.job_name;
}
} },
{ data: 'time_submit',
render: parse_time,
},
Expand Down
4 changes: 4 additions & 0 deletions jobstats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@ def job(request, username, job_id):
for exe in stats_exe:
name = exe['metric']['exe']
value = statistics.mean(exe['y'])
if settings.DEMO:
if not name.startswith('/cvmfs'):
# skip non-cvmfs applications in demo mode
name = '[redacted]'
context['applications'].append({'name': name, 'value': value})
except ValueError:
pass
Expand Down
3 changes: 3 additions & 0 deletions templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
</head>

<body>
{% if settings.DEMO %}
<div id="demo"></div>
{% endif %}
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
<a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">{{ settings.CLUSTER_NAME_TITLE }}</a>
<button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse" data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
Expand Down
2 changes: 1 addition & 1 deletion top/templates/top/compute.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h1>{% translate "Top compute users" %}</h1>
<tbody>
{% for user in cpu_users %}
<tr>
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{user.user}}">{{user.user}}
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{user.user}}">{{user.user | anonymize}}
{% if user.note_flag %}
<span class="badge badge-primary"><span data-feather="alert-circle" title="User has a note"></span></span>
{% endif %}</a>
Expand Down
2 changes: 1 addition & 1 deletion top/templates/top/gpucompute.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ <h1>{% translate "Top GPU compute users" %}</h1>
<tbody>
{% for user in gpu_users %}
<tr>
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{user.user}}">{{user.user}}
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{user.user}}">{{user.user | anonymize}}
{% if user.note_flag %}
<span class="badge badge-primary"><span data-feather="alert-circle" title="User has a note"></span></span>
{% endif %}</a>
Expand Down
2 changes: 1 addition & 1 deletion top/templates/top/largemem.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ <h1>{% translate "Users on largemem" %}</h1>
<tbody>
{% for job in jobs %}
<tr>
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{job.user}}">{{job.user}}
<td><a href="{{settings.BASE_URL}}secure/jobstats/{{job.user}}">{{job.user | anonymize}}
{% if job.user_flag %}
<span class="badge badge-primary"><span data-feather="alert-circle" title="User has a note"></span></span>
{% endif %}</a>
Expand Down
7 changes: 5 additions & 2 deletions top/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.shortcuts import render
from django.http import JsonResponse
from userportal.common import staff, Prometheus, uid_to_username
from userportal.common import anonymize as a
from slurm.models import JobTable
from notes.models import Note
from django.conf import settings
Expand Down Expand Up @@ -329,9 +330,10 @@ def graph_lustre_mdt(request, fs):
data = []
for line in stats:
try:
user = line['metric']['user']
user = a(line['metric']['user'])
except KeyError:
user = 'others'

x = list(map(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), line['x']))
y = line['y']
data.append({
Expand Down Expand Up @@ -362,9 +364,10 @@ def graph_lustre_ost(request, fs):

for line in stats:
try:
user = line['metric']['user']
user = a(line['metric']['user'])
except KeyError:
user = 'others'

x = list(map(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), line['x']))
if rw == 'read':
y = line['y']
Expand Down
11 changes: 11 additions & 0 deletions userportal/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
import yaml
from django.conf import settings
import os
import userportal.petname as petname


# How many points in the X axis of the graphs
RESOLUTION = 500

PET = petname.petname('roh8evuLohRohgheesoh')


def user_or_staff(func):
"""Decorator to allow access only to staff members or to the user"""
Expand Down Expand Up @@ -214,6 +217,14 @@ def fixed_zoom_config():
return {'modeBarButtonsToRemove': ['zoom2d', 'pan2d', 'zoomIn2d', 'zoomOut2d', 'lasso2d', 'select2d']}


def anonymize(name):
# return an anonymized name if running in demo mode
if settings.DEMO:
return PET.anonymize(name)
else:
return name


class Prometheus:
def __init__(self, config):
self.prom = PrometheusConnect(
Expand Down
Loading

0 comments on commit f8ca51b

Please sign in to comment.