diff --git a/config/gunicorn_config.py b/config/gunicorn_config.py index 3f4d1cd57e57f7451412bb79e4e119cdb3287b90..8ea48672b94895c7ad86920f4bcef57e88bc68db 100644 --- a/config/gunicorn_config.py +++ b/config/gunicorn_config.py @@ -56,11 +56,11 @@ timeout = get_from_env('GUNICORN_TIMEOUT', # randint(0, max_requests_jitter) max_requests = get_from_env('GUNICORN_MAX_REQUESTS', - default_value=2500, + default_value=5000, fail_if_not_found=False) max_requests_jitter = get_from_env('GUNICORN_MAX_REQUESTS_JITTER', - default_value=100, + default_value=250, fail_if_not_found=False) # keepalive ------------------------------------------------------------------- @@ -71,7 +71,7 @@ max_requests_jitter = get_from_env('GUNICORN_MAX_REQUESTS_JITTER', # this to a higher value. keepalive = get_from_env('GUNICORN_KEEPALIVE', - default_value=25, + default_value=60, fail_if_not_found=False) # preload_app ----------------------------------------------------------------- @@ -84,7 +84,8 @@ keepalive = get_from_env('GUNICORN_KEEPALIVE', # If you aren't going to make use of on-the-fly reloading, consider preloading # your application code to reduce its memory footprint. So, turn this on in -# production. +# production. This is default set to False for development, but +# **TURN THIS TO TRUE FOR AWS DEPLOYMENT ** preload_app = get_from_env('GUNICORN_PRELOAD_APP', default_value=False, diff --git a/config/settings/base.py b/config/settings/base.py index 6ea727fcf3e08122e68494459ab15e4b8d1125cd..292862fb40614ea4e9a8ec3393989079ebad0424 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -432,8 +432,8 @@ REST_FRAMEWORK = { ), 'DEFAULT_THROTTLE_RATES': { 'anon_burst': '300/minute', - 'event_creation': '25/second', - 'annotation' : '25/second', + 'event_creation': '50/second', + 'annotation' : '50/second', }, 'DEFAULT_AUTHENTICATION_CLASSES': ( 'api.backends.GraceDbAuthenticatedAuthentication', diff --git a/config/settings/vm/base.py b/config/settings/vm/base.py index f0206f6a293bcbb2f7172d77518bc6d59f06640c..ba48e1a8db495113fcc8405e265d3a32ae731adc 100644 --- a/config/settings/vm/base.py +++ b/config/settings/vm/base.py @@ -95,6 +95,30 @@ except: BETA_REPORTS_LINK = True +## EGAD (External GraceDB Alert Dispatcher) configuration +ENABLE_EGAD_EMAIL = parse_envvar_bool( + get_from_env('ENABLE_EGAD_EMAIL', + fail_if_not_found=False, default_value="false") +) +ENABLE_EGAD_KAFKA = parse_envvar_bool( + get_from_env('ENABLE_EGAD_KAFKA', + fail_if_not_found=False, default_value="false") +) +ENABLE_EGAD_MATTERMOST = parse_envvar_bool( + get_from_env('ENABLE_EGAD_MATTERMOST', + fail_if_not_found=False, default_value="false") +) +ENABLE_EGAD_PHONE = parse_envvar_bool( + get_from_env('ENABLE_EGAD_PHONE', + fail_if_not_found=False, default_value="false") +) + +ENABLE_EGAD = ( + ENABLE_EGAD_EMAIL or ENABLE_EGAD_KAFKA + or ENABLE_EGAD_MATTERMOST or ENABLE_EGAD_PHONE +) + + # Pull in remaining (phone/email) alert variables from # the environment. Default to false. SEND_PHONE_ALERTS = parse_envvar_bool(get_from_env( diff --git a/gracedb/api/v1/viewsets.py b/gracedb/api/v1/viewsets.py index e08d99162176f35dc5792de8bc49c3355e2a8920..0652c084c9007b5e02b9e338a3902363f29ae2e3 100644 --- a/gracedb/api/v1/viewsets.py +++ b/gracedb/api/v1/viewsets.py @@ -91,7 +91,7 @@ class NestedViewSet(viewsets.GenericViewSet): self._parent_queryset = self.parent_queryset else: self._parent_queryset = get_objects_for_user(self.request.user, - self.parent_access_permission, self.parent_queryset) + self.parent_access_permission, klass=self.parent_queryset) return self._parent_queryset diff --git a/gracedb/events/permission_utils.py b/gracedb/events/permission_utils.py index 884a2fbf519ac6985d00802d3edf99967f8e337b..d32994930828e9415caf062d84c2fe0eab482543 100644 --- a/gracedb/events/permission_utils.py +++ b/gracedb/events/permission_utils.py @@ -24,7 +24,7 @@ def user_has_perm(user, shortname, obj): def filter_events_for_user(events, user, shortname): perm_codename = 'events.{verb}_event'.format(verb=shortname) - return get_objects_for_user(user, perm_codename, events) + return get_objects_for_user(user, perm_codename, klass=events) #------------------------------------------------------------------------------- # Filter a queryset of Event objects according to user permissions. diff --git a/gracedb/ligoauth/migrations/0089_yet_another_gstlalcbc_cert.py b/gracedb/ligoauth/migrations/0089_yet_another_gstlalcbc_cert.py new file mode 100644 index 0000000000000000000000000000000000000000..f76274fb59b4504edf31e37478d0d32df8fe6b3b --- /dev/null +++ b/gracedb/ligoauth/migrations/0089_yet_another_gstlalcbc_cert.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-06-03 20:10 +from __future__ import unicode_literals + +from django.db import migrations + +# Note: the CN in the cert is for detchar-la, not detchar. + +ACCOUNT = { + 'name': 'gstlalcbc', + 'new_cert': '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=gstlal.ligo.caltech.edu/CN=gstlalcbc_online/CN=Rebecca Ewing/CN=UID:rebecca.ewing.robot', +} + + +def add_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=ACCOUNT['name']) + + # Create new certificate + user.x509cert_set.create(subject=ACCOUNT['new_cert']) + + +def delete_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=ACCOUNT['name']) + + # Delete new certificate + cert = user.x509cert_set.get(subject=ACCOUNT['new_cert']) + cert.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0088_new_mly_robot_cert'), + ] + + operations = [ + migrations.RunPython(add_cert, delete_cert), + ] diff --git a/gracedb/ligoauth/migrations/0090_add_cwb_cert.py b/gracedb/ligoauth/migrations/0090_add_cwb_cert.py new file mode 100644 index 0000000000000000000000000000000000000000..71eeeff077f2391d79de9e6abe334600c895540d --- /dev/null +++ b/gracedb/ligoauth/migrations/0090_add_cwb_cert.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# fixes: +# https://git.ligo.org/computing/helpdesk/-/issues/3852 +from __future__ import unicode_literals + +from django.db import migrations + +# Note: the CN in the cert is for detchar-la, not detchar. + +ACCOUNT = { + 'name': 'waveburst', + 'new_cert': '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=ligo.caltech.edu/CN=waveburst.online/CN=Marek Szczepanczyk/CN=UID:marek.szczepanczyk.robot', +} + + +def add_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=ACCOUNT['name']) + + # Create new certificate + user.x509cert_set.create(subject=ACCOUNT['new_cert']) + + +def delete_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=ACCOUNT['name']) + + # Delete new certificate + cert = user.x509cert_set.get(subject=ACCOUNT['new_cert']) + cert.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0089_yet_another_gstlalcbc_cert'), + ] + + operations = [ + migrations.RunPython(add_cert, delete_cert), + ] diff --git a/gracedb/ligoauth/migrations/0091_fix_pycbclive_cert.py b/gracedb/ligoauth/migrations/0091_fix_pycbclive_cert.py new file mode 100644 index 0000000000000000000000000000000000000000..fe27275a7162bec6aa62cbd3c54f5f079c378507 --- /dev/null +++ b/gracedb/ligoauth/migrations/0091_fix_pycbclive_cert.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# context: one of pycbclive's certs associated with tito's robot +# account was incorrectly in virgo_detchar's set. this migration +# checks for the existance of the cert, and if it isn't associated +# with pycbclive, then move it. + +# https://git.ligo.org/computing/helpdesk/-/issues/3886 + +from __future__ import unicode_literals + +from django.db import migrations + +# first the subject of the cert in question: +subject = '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=ldas-grid.ligo.caltech.edu/CN=pycbclive/CN=Tito Canton/CN=UID:tito.canton.robot' + +# the (true) owner's username: +username = 'pycbclive' + +def add_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + X509Cert = apps.get_model('ligoauth', 'X509Cert') + + # Get the user + pycbclive = RobotUser.objects.get(username=username) + + # Get the cert: + cert, created = X509Cert.objects.get_or_create(subject=subject) + + # Check the ownership of the cert, and if it's not pycbclive, then + # change and save: + if cert.user != pycbclive: + cert.user = pycbclive + cert.save() + + +def delete_cert(apps, schema_editor): + # nothing's going to break (ha!) by running this forward and backwards, so + # just: + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0090_add_cwb_cert'), + ] + + operations = [ + migrations.RunPython(add_cert, delete_cert), + ] diff --git a/gracedb/ligoauth/migrations/0092_emfollow_so_many_certs.py b/gracedb/ligoauth/migrations/0092_emfollow_so_many_certs.py new file mode 100644 index 0000000000000000000000000000000000000000..8feefff5590928e7594cd720ef224f27ea8faa14 --- /dev/null +++ b/gracedb/ligoauth/migrations/0092_emfollow_so_many_certs.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# Step 1 in transferring certificate ownership from leo singer to +# cody messick: add cody's, and once they're in place, satya will +# transfer ownership and then i'll remove leo's. +# +# reference: https://git.ligo.org/computing/helpdesk/-/issues/3702 + +from __future__ import unicode_literals + +from django.db import migrations + +# detchar is on a tear getting new certs, so I'm doing three +# at once. + +gracedb_account = 'emfollow' + +new_certs = [ + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow-playground.ligo.caltech.edu/CN=emfollow-playground/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo-la.caltech.edu/CN=emfollow-playground-la/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo-wa.caltech.edu/CN=emfollow-playground-wa/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo.caltech.edu/CN=emfollow-playground/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo-wa.caltech.edu/CN=emfollow-wa/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo.caltech.edu/CN=emfollow/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow.ligo-la.caltech.edu/CN=emfollow-la/CN=Cody Messick/CN=UID:cody.messick.robot', + '/DC=org/DC=cilogon/C=US/O=LIGO/OU=Robots/CN=emfollow-test.ligo.caltech.edu/CN=emfollow-test/CN=Cody Messick/CN=UID:cody.messick.robot', + ] + + +def add_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=gracedb_account) + + # Create new certificates + for cert in new_certs: + user.x509cert_set.create(subject=cert) + + +def delete_cert(apps, schema_editor): + RobotUser = apps.get_model('auth', 'User') + + # Get user + user = RobotUser.objects.get(username=gracedb_account) + + # Delete new certificates + for cert in new_certs: + cert = user.x509cert_set.get(subject=cert) + cert.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0091_fix_pycbclive_cert'), + ] + + operations = [ + migrations.RunPython(add_cert, delete_cert), + ] diff --git a/gracedb/migrations/guardian/0017_update_pycbc_uploaders.py b/gracedb/migrations/guardian/0017_update_pycbc_uploaders.py new file mode 100644 index 0000000000000000000000000000000000000000..e3886d75fe39a54eafb6b3180eebe5ab995cd85e --- /dev/null +++ b/gracedb/migrations/guardian/0017_update_pycbc_uploaders.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# fixes: +# https://git.ligo.org/computing/gracedb/server/-/issues/287 +from __future__ import unicode_literals + +from django.db import migrations + +# Creates UserObjectPermission objects which allow specific users +# to add events for pycbc. Also removes users that aren't in the +# collaboration anymore. They couldn't log in and up + +PIPELINE_NAME = 'pycbc' + +USERS_TO_REMOVE = [ + 'andrewlawrence.miller@ligo.org', + 'henning.fehrmann@ligo.org', + 'karsten.wiesner@ligo.org', + 'collin.capano@ligo.org', + 'alex.nitz@ligo.org', + 'christopher.biwer@ligo.org', + 'stanislav.babak@ligo.org', + 'gergely.debreczeni@ligo.org', + 'duncan.brown@ligo.org', + 'badri.krishnan@ligo.org', + 'saeed.mirshekari@ligo.org', + ] + +USERS_TO_ADD = [ + 'max.trevor@ligo.org', + 'kanchan.soni@ligo.org', + 'shreejit.jadhav@ligo.org', + 'xan.morice-atkinson@ligo.org', + 'stephanie.hoang@ligo.org', + 'praveen.kumar@ligo.org', + 'ana.lorenzo@ligo.org', + 'adrianofrattale.mascioli@ligo.org', + 'barna.fekecs@ligo.org', + 'bhooshan.gadre@ligo.org', + ] + +def add_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + Permission = apps.get_model('auth', 'Permission') + UserObjectPermission = apps.get_model('guardian', 'UserObjectPermission') + Pipeline = apps.get_model('events', 'Pipeline') + ContentType = apps.get_model('contenttypes', 'ContentType') + + perm = Permission.objects.get(codename='populate_pipeline') + ctype = ContentType.objects.get_for_model(Pipeline) + + pipeline, created = Pipeline.objects.get_or_create(name=PIPELINE_NAME) + + # First remove the old uploaders: + for u in USERS_TO_REMOVE: + # get the user object: + user, _ = User.objects.get_or_create(username=u) + + # now get the corresponding userobjectpermission: + uop, _ = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + + uop.delete() + + # Now add the new people: + for u in USERS_TO_ADD: + # get the user object: + user, _ = User.objects.get_or_create(username=u) + + # now get the corresponding userobjectpermission: + uop, _ = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + +def remove_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + Permission = apps.get_model('auth', 'Permission') + UserObjectPermission = apps.get_model('guardian', 'UserObjectPermission') + Pipeline = apps.get_model('events', 'Pipeline') + ContentType = apps.get_model('contenttypes', 'ContentType') + + perm = Permission.objects.get(codename='populate_pipeline') + ctype = ContentType.objects.get_for_model(Pipeline) + + pipeline, created = Pipeline.objects.get_or_create(name=PIPELINE_NAME) + # first remove the new people: + for u in USERS_TO_ADD: + # get the user object: + user, _ = User.objects.get_or_create(username=u) + + # now get the corresponding userobjectpermission: + uop, _ = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + + uop.delete() + + # Put the old people back: + for u in USERS_TO_REMOVE: + # get the user object: + user, _ = User.objects.get_or_create(username=u) + + # now get the corresponding userobjectpermission: + uop, _ = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0016_emfollow_upload_mly'), + ] + + operations = [ + migrations.RunPython(add_permissions, remove_permissions), + ] diff --git a/gracedb/search/views.py b/gracedb/search/views.py index 98ae46956a581be94a813393cc8c9e5df689531d..b9ee4ca858a414e6fa3e1f0908b1f2bdaf8511ea 100644 --- a/gracedb/search/views.py +++ b/gracedb/search/views.py @@ -44,7 +44,7 @@ def search(request): else: return HttpResponseBadRequest( "query_type should be 'S' or 'E'") - objects = get_objects_for_user(request.user, view_perm, objects) + objects = get_objects_for_user(request.user, view_perm, klass=objects) # Get call from template for populating datatable if _format == 'F': @@ -122,7 +122,7 @@ def latest(request): # Filter objects for user and add to context, sorted in reverse # chronological order of submission - objects = get_objects_for_user(request.user, view_perm, objects) + objects = get_objects_for_user(request.user, view_perm, klass=objects) context[objects_key] = \ objects.order_by('-id')[:settings.LATEST_RESULTS_NUMBER] diff --git a/gracedb/superevents/mixins.py b/gracedb/superevents/mixins.py index 6859d3e465b53b791d7b94b3a421b4714c3ad197..c41663cd30b91ece944b6cceacbf26f482a8988c 100644 --- a/gracedb/superevents/mixins.py +++ b/gracedb/superevents/mixins.py @@ -37,7 +37,7 @@ class PermissionsFilterMixin(SingleObjectMixin): the required permissions. """ qs = get_objects_for_user(self.request.user, self.filter_permissions, - queryset, **{'accept_global_perms': self.accept_global_perms}) + klass=queryset, **{'accept_global_perms': self.accept_global_perms}) return qs diff --git a/gracedb/superevents/views.py b/gracedb/superevents/views.py index 77f682899e18c0411918450aa184ce2a264a3cad..aa8cfbd812facacdd033b096142320b9d2c5a653 100644 --- a/gracedb/superevents/views.py +++ b/gracedb/superevents/views.py @@ -121,7 +121,7 @@ class SupereventFileList(SupereventDetailView): # Get list of logs which are viewable by the user viewable_logs = get_objects_for_user(self.request.user, - self.log_view_permission, self.object.log_set.all()) + self.log_view_permission, klass=self.object.log_set.all()) file_list = viewable_logs.exclude(filename='').order_by('filename') diff --git a/gracedb/templates/gracedb/event_filelist.html b/gracedb/templates/gracedb/event_filelist.html index 8375f4955f5eeeb0cce87fc9e605ac10fac57b27..55629b2a5ebc05db94ef2c9e232f243edd46aea5 100644 --- a/gracedb/templates/gracedb/event_filelist.html +++ b/gracedb/templates/gracedb/event_filelist.html @@ -19,6 +19,8 @@ <div class="row my-3 justify-content-center"> <div class="col-md-10"> + + <p> <b><a href="{% url "view" graceid %}"> ← Return to {{ graceid }} </a> </b></p> <p> Filenames in <b>bold</b> are symbolic links that point to the specified file. diff --git a/gracedb/templates/superevents/file_list.html b/gracedb/templates/superevents/file_list.html index d9b7c39cbe23376ae936c90a3f3c599ab0e30d01..c3ad0b941e94b0418e98eefc4218cb0a9bbc976c 100644 --- a/gracedb/templates/superevents/file_list.html +++ b/gracedb/templates/superevents/file_list.html @@ -20,6 +20,8 @@ <div class="row my-3 justify-content-center"> <div class="col-md-10"> + <p> <b><a href="{{ object.get_web_url }}"> ← Return to {{ object.superevent_id }} </a> </b></p> + <p> Filenames in <b>bold</b> are symbolic links that point to the specified file. diff --git a/gracedb/templates/superevents/superevent_info_table_public.html b/gracedb/templates/superevents/superevent_info_table_public.html index 1e730c3c38611565bc417e8be0f967b9338ae68b..a0eb22253663cb7ab5fad822a884a4aeab12dcd9 100644 --- a/gracedb/templates/superevents/superevent_info_table_public.html +++ b/gracedb/templates/superevents/superevent_info_table_public.html @@ -30,22 +30,6 @@ <td> {{ superevent.get_category_display }} </td> </tr> - <tr> - <td> Labels </td> - <td> - {% for labelling in superevent.labelling_set.all %} - <span style="color: {{labelling.label.defaultColor}};" class="label" - data-toggle="tooltip" - data-placement="top" - data-html="true" - title="<em>{{labelling.label.description}}</em><br> - <b>Added by:</b> {{labelling.creator.get_full_name}}<br> - <b>Added:</b> {{labelling.created}}"> - {{ labelling.label.name }}</span> - {% endfor %} - </td> - </tr> - <tr> <td> t<sub>start</sub> </td> <td> {{ superevent.t_start|floatformat:2 }} </td>