Commit eb21f8f5 authored by Brian Moe's avatar Brian Moe

Initial Revision

parents
*.swp
*~
*.pyc
import os
import sys
sys.path.append('/home/lars/django')
sys.path.append('/opt/lscsoft/glue/lib64/python2.4/site-packages')
sys.path.append('/opt/lscsoft/glue/lib/python2.4/site-packages')
os.environ['DJANGO_SETTINGS_MODULE'] = 'gracedb.settings'
#os.environ['PYTHON_EGG_CACHE'] = '/tmp/egg-trash'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
import sys
import time
from subprocess import Popen, PIPE, STDOUT
def issueAlert(event, location):
# XXX awful!
if event.analysisType != 'MBTA':
return
env = {}
pythonpath = ":".join(sys.path)
env["PYTHONPATH"] = pythonpath
null = open('/dev/null','w')
p = Popen(
["lvalert_send",
"--username=gracedb",
"--password=w4k3upal1ve",
"--file=-",
"--node=cbc_mbta_online"
],
executable="/opt/lscsoft/glue/bin/lvalert_send",
stdin=PIPE,
stdout=null,
stderr=STDOUT,
env=env)
msg = createPayload(event.uid, location)
p.stdin.write(msg)
p.stdin.close()
for i in range(1,10):
res = p.poll()
if res == None:
time.sleep(1)
else:
break
def issueAlertX(event, location):
username = "gracedb"
server = "lvalert.phys.uwm.edu"
resource = "sender"
password = "w4k3upal1ve"
node = "cbc_mbta_online"
voevent = createPayload(event.uid, location)
myjid=JID(username+"@"+server+"/"+resource)
recpt=JID("pubsub."+server)
s=MyClient(jid=myjid, password=password, recpt=recpt)
s.connect()
s.send_myevent(voevent, node)
s.loop(1)
def createPayload (uid, filename):
template = """<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE LIGO_LW SYSTEM "http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt">
<LIGO_LW>
<Table Name="LVAlert:table">
<Column Type="lstring" Name="LVAlert:uid"/>
<Column Type="lstring" Name="LVAlert:file"/>
<Stream Name="LVAlert:table" Type="Local" Delimiter=",">
"%(uid)s","%(filename)s"
</Stream>
</Table>
</LIGO_LW>
"""
return template % { 'uid': uid, 'filename': filename }
# pubsub import must come first because it overloads part of the
# StanzaProcessor class
from glue.lvalert import pubsub
from pyxmpp.all import JID, TLSSettings
from pyxmpp.jabber.all import Client
class MyClient(Client):
def __init__(self, jid, password, recpt):
# if bare JID is provided add a resource -- it is required
if not jid.resource:
jid=JID(jid.node, jid.domain, "sender")
self.myrecpt = recpt
# we require a TLS connection
t=TLSSettings(require=True,verify_peer=False)
# setup client with provided connection information
# and identity data
Client.__init__(self, jid, password, \
auth_methods=["sasl:GSSAPI","sasl:PLAIN"], tls_settings=t)
def stream_state_changed(self,state,arg):
"""This one is called when the state of stream connecting the component
to a server changes. This will usually be used to let the user
know what is going on."""
pass
def session_started(self):
self.stream.set_response_handlers(self.pspl, \
self.pspl.generic_result,self.pspl.create_error,\
self.pspl.create_timeout)
self.stream.send(self.pspl)
def idle(self):
if self.stream and self.session_established:
self.disconnect()
time.sleep(2)
def post_disconnect(self):
raise Disconnected
def send_myevent(self, voevent, node):
self.pspl=pubsub.PubSub(from_jid = self.jid, to_jid = self.myrecpt, stream = self, stanza_type="get")
self.pspl.publish(voevent,node)
# vi: sts=4 et sw=4
def create(request):
pass
from django import forms
from models import Event, User, Group
class CreateEventForm(forms.Form):
groupChoices = [("","")]+[(g.name, g.name) for g in Group.objects.all()]
typeChoices= [("","")]+list(Event.ANALYSIS_TYPE_CHOICES)
eventFile = forms.FileField()
group = forms.ChoiceField(groupChoices)
type = forms.ChoiceField(choices=typeChoices)
class EventSearchForm(forms.Form):
groupChoices = [("","")]+[(g.name, g.name) for g in Group.objects.all()]
typeChoices= [("","")]+list(Event.ANALYSIS_TYPE_CHOICES)
submitterIds = Event.objects.values_list('submitter',flat=True).distinct()
submitterList = User.objects.filter(id__in=submitterIds).order_by('name')
submitterChoices = [("","")]+ [ (u.id, u.name) for u in submitterList]
uidStart = forms.CharField(required=False)
uidEnd = forms.CharField(required=False)
group = forms.ChoiceField(choices=groupChoices, required=False)
type = forms.ChoiceField(choices=typeChoices, required=False)
submitter = forms.ChoiceField(choices=submitterChoices, required=False)
from django.db import models
import datetime
import thread
import string
def lettersToInt( str ):
"""turn a string of letters into a base 26 number"""
return reduce( lambda x, y: 26*x + y, map( string.lowercase.index, str ))
def intToLetters( i, str='' ):
"""convert a number into a string of lowercase letters"""
if i == 0:
return str or 'a'
else:
return intToLetters( i/26, string.lowercase[i%26] + str )
class Genid:
# XXX dear heaven this is awful.
def __init__(self):
self.lastCalledDate = datetime.datetime.now().date()
# XXX Find latest suffix from Event table
self.next = 0
self.lock = thread.allocate_lock()
prefix = self.lastCalledDate.strftime('%y%m%d')
plen = len(prefix)
analyses = Event.objects.filter(uid__contains=prefix)
if len(analyses) >0:
self.next = 1 + max([lettersToInt(a.uid[plen:]) for a in analyses])
def __call__(self):
self.lock.acquire()
today = datetime.datetime.now().date()
assert (today >= self.lastCalledDate)
if today != self.lastCalledDate:
self.next = 0
self.lastCalledDate = today
prefix = datetime.datetime.now().strftime('%y%m%d')
rv = prefix + intToLetters(self.next)
self.next += 1
self.lock.release()
return rv
# XXX Yarg.
_genid = None
def genid():
global _genid
if not _genid: _genid = Genid()
return _genid()
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
principal = models.CharField(max_length=100)
dn = models.CharField(max_length=100)
unixid = models.CharField(max_length=25)
class Meta:
ordering = ["name"]
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=20)
managers = models.ManyToManyField(User)
def __unicode__(self):
return self.name
class Event(models.Model):
ANALYSIS_TYPE_CHOICES = (
("LM", "LowMass"),
("HM", "HighMass"),
("GRB", "GRB"),
("RD", "Ringdown"),
("OM", "Omega"),
("Q", "Q"),
("X", "X"),
("CWB", "CWB"),
("MBTA", "MBTA Online"),
)
uid = models.CharField(max_length=20, unique=True, default=genid)
submitter = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True)
group = models.ForeignKey(Group)
analysisType = models.CharField(max_length=20, choices=ANALYSIS_TYPE_CHOICES)
def weburl(self):
return "https://ldas-jobs.phys.uwm.edu/gracedb/data/%s" % self.uid
def wikiurl(self):
return "https://www.lsc-group.phys.uwm.edu/twiki/bin/view/Sandbox/%s" % self.uid
def clusterurl(self):
return "pcdev1.phys.uwm.edu:/archive/gracedb/data/%s" % self.uid
from django.conf.urls.defaults import *
#import django.views.generic.list_detail
urlpatterns = patterns('gracedb.gracedb.views',
(r'^$', 'index'),
url (r'^create/$', 'create', name="create"),
url (r'^search/$', 'search', name="search"),
# (r'^view/(?P<uid>[\w\d]+)', 'view'),
# (r'^edit/(?P<uid>[\w\d]+)', 'edit'),
# (r'^request_archive/(?P<uid>[\w\d]+)(?P<rescind>/rescind)?', 'request_archive'),
# (r'^approve_archive/(?P<uid>[\w\d]+)(?P<rescind>/rescind)?', 'approve_archive'),
# url (r'^query', 'query', name="search"),
# url (r'^mine/$', 'mine', name="mine"),
# url (r'^myapprovals/$', 'myapprovals', name="myapprovals"),
)
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
from django.template import RequestContext
from django.core.urlresolvers import reverse, get_script_prefix
from django.shortcuts import render_to_response
from django.views.generic.list_detail import object_detail, object_list
from models import Event, Group
from forms import CreateEventForm, EventSearchForm
from alert import issueAlert
import os
def index(request):
# assert request.ligouser
return render_to_response(
'gracedb/index.html',
# {'hi':request.ligouser},
{},
context_instance=RequestContext(request))
def create(request):
assert request.ligouser
if request.method == "GET":
form = CreateEventForm()
else:
form = CreateEventForm(request.POST, request.FILES)
if form.is_valid():
group = Group.objects.filter(name=form.cleaned_data['group'])
type = form.cleaned_data['type']
# Create Event
event = Event()
event.submitter = request.ligouser
event.group = group[0]
event.analysisType = type
# Create data directory/directories
# Save uploaded file.
dirPrefix = "/mnt/gracedb-web/data"
eventDir = os.path.join(dirPrefix, event.uid)
os.mkdir( eventDir )
os.mkdir( os.path.join(eventDir,"private") )
os.mkdir( os.path.join(eventDir,"general") )
#os.chmod( os.path.join(eventDir,"general"), int("041777",8) )
os.chmod( os.path.join(eventDir,"general"), 041777 )
f = request.FILES['eventFile']
uploadDestination = os.path.join(eventDir, "private", f.name)
fdest = open(uploadDestination, 'w')
# XXX probably want to check exit code
# Oh. and it doesn't work.
os.system("/usr/bin/sudo /usr/local/bin/fixgracedirs %s >/dev/null" % event.uid)
#fdest.write("[%s] %s bytes\n" % (f.name, f.size))
# Save uploaded file into user private area.
for chunk in f.chunks():
fdest.write(chunk)
fdest.close()
# Create WIKI page
createWikiPage(event.uid)
event.save() # if everything worked... save.
# Send an alert.
issueAlert(event, os.path.join(event.clusterurl(), "private", f.name))
#return HttpResponseRedirect(reverse(view, args=[event.uid]))
if 'cli' in request.POST:
msg = str(event.uid)
response = HttpResponse(mimetype='text/xml')
response.write(msg)
response['Content-length'] = len(msg)
return response
return HttpResponseRedirect(reverse(search))
else: # form not valid
if 'cli' in request.POST:
# Error occurred in command line client.
# Most likely group name is wrong.
# XXX the form should have info about what is wrong.
groupname = request.POST.get('group', None)
group = Group.objects.filter(name=groupname)
if not group:
validGroups = [group.name for group in Group.objects.all()]
msg = "ERROR: group must be one of: %s" % ", ".join(validGroups)
response = HttpResponse(mimetype='text/xml')
response.write(msg)
response['Content-length'] = len(msg)
return response
# if not a command line request, let it fall through
return render_to_response('gracedb/create.html',
{ 'form' : form },
context_instance=RequestContext(request))
def search(request):
assert request.ligouser
if request.method == 'GET':
form = EventSearchForm()
else:
form = EventSearchForm(request.POST)
if form.is_valid():
objects = Event.objects.all()
start = form.cleaned_data['uidStart']
end = form.cleaned_data['uidEnd']
submitter = form.cleaned_data['submitter']
groupname = form.cleaned_data['group']
typename = form.cleaned_data['type']
if start:
objects = objects.filter(uid__gte=start)
if end:
objects = objects.filter(uid__lte=end)
if submitter:
objects = objects.filter(submitter=submitter)
if groupname:
group = Group.objects.filter(name=groupname)[0]
objects = objects.filter(group=group)
if typename:
objects = objects.filter(analysisType=typename)
return object_list(request, objects, extra_context={'title':"Query Results"})
return render_to_response('gracedb/query.html',
{ 'form' : form },
context_instance=RequestContext(request))
#-----------------------------------------------------------------
# Things that aren't views and should really be elsewhere.
#-----------------------------------------------------------------
def createWikiPage(uid):
twikiroot = "/mnt/htdocs/uwmlsc/secure/twiki/data/Sandbox/"
plainFile = """
Initial Entry for %s
%%TOC{depth="2"}%%
""" % uid
rcsFile = """head 1.1;
access;
symbols;
locks
apache:1.1; strict;
comment @# @;
1.1
date 2009.06.13.00.09.15; author apache; state Exp;
branches;
next ;
desc
@Initial Revision
@
1.1
log
@Initial revision
@
text
@
Initial Entry for %s
%%TOC{depth="2"}%%
@
""" % uid
pname = os.path.join(twikiroot, uid+".txt")
rcsname = os.path.join(twikiroot, uid+".txt,r")
f = open(pname, "w")
f.write(plainFile)
f.close()
f = open(rcsname, "w")
f.write(rcsFile)
f.close()
os.chmod(pname, 0644)
os.chmod(rcsname, 0444)
# f=open(twikiroot+eventid+".txt","w")
# entry=[]
# entry.append('%TOC{depth="2"}%\n')
# entry.append('---+ Twiki page for candidate event ' + eventid)
# f.writelines(entry)
# f.close()
# os.chdir(twikiroot)
# command='echo "initial entry" | ci -l ' +eventid+".txt"
# os.popen(command)
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)
# From http://www.djangosnippets.org/snippets/708/
# splits up request's accepted types for easy access.
#
# Added try/except to handle case of no HTTP_ACCEPT header
class AcceptMiddleware(object):
def process_request(self, request):
try:
acc = [a.split(';')[0] for a in request.META['HTTP_ACCEPT'].split(',')]
except:
acc = ['text/html']
setattr(request, 'accepted_types', acc )
request.accepts = lambda type: type in acc
return None
from django.contrib.auth import authenticate
from gracedb.gracedb.models import User
from django.contrib.auth.models import User as DjangoUser
import re
proxyPattern = re.compile(r'^(.*?)(/CN=\d+)*$')
def nameFromPrincipal(principal):
name = principal.split('@')[0]
first, last = name.split('.')
return first[0].upper() + first[1:] + " " + last[0].upper() + last[1:]
class LigoAuthMiddleware:
def process_request(self, request):
ligouser = None
user = None
principal = request.META.get('REMOTE_USER')
certdn = request.META.get('SSL_CLIENT_S_DN')
issuer = request.META.get('SSL_CLIENT_I_DN')
if not certdn:
try:
# mod_python is a little off...
# SSL info is in request._req
# Need to try/except because _req is
# not defined in WSGI request.
certdn = request._req.ssl_var_lookup ('SSL_CLIENT_S_DN')
issuer = request._req.ssl_var_lookup ('SSL_CLIENT_I_DN')
pass
except:
pass
queryResult = []
if principal:
# Kerberos.
queryResult = User.objects.filter(principal=principal)
elif certdn and certdn.startswith(issuer):
# proxy.
# Proxies can be signed by proxies.
# Each level of "proxification" causes the subject
# to have a '/CN=[0-9]+ appended to the signers subject.
# These must be removed to discover the original identity's
# subject DN.
issuer = proxyPattern.match(issuer).group(1)
queryResult = User.objects.filter(dn=issuer)
elif certdn:
# cert in browser.
queryResult = User.objects.filter(dn=certdn)
if queryResult:
ligouser = queryResult[0]
try:
user = DjangoUser.objects.get(username=ligouser.unixid)
except DjangoUser.DoesNotExist:
user = DjangoUser(username=ligouser.unixid, password="")
user.is_staff = False
user.is_superuser = False
user.save()
elif principal:
# There is no user ... what do we do?
# If auth was via cert... nothing, DNs need to be registered.
# If auth was via kerberos, we make sure it was a LIGO.ORG
# principal and make a new user and ligouser with no DN.
#assert (principal.split('@')[1] == 'LIGO.ORG')
ligouser = User(name = nameFromPrincipal(principal),
email = principal.lower(),
principal = principal,
dn = "NONE",
unixid = principal.split('@')[0])
ligouser.save()
try:
user = DjangoUser.objects.get(username=ligouser.unixid)
except DjangoUser.DoesNotExist:
user = DjangoUser(username=ligouser.unixid, password="")
user.is_staff = False
user.is_superuser = False
user.save()
request.user = authenticate(ssluser=user)
request.ligouser = ligouser
# Http404 doesn't check for user == None, just hasattr(x,'user')
# Why does this matter? I forget, but it does.
if not request.user: del request.user
return None
# def process_view(self, request, view_func, view_args, view_kwargs):
# return None
# def process_response(self, request, response):
# return None
# def process_exception(self, request, exception):
# return None
class LigoAuthBackend:
def authenticate(self, ssluser):
return ssluser
def get_user(self, user_id):
try:
return DjangoUser.get(id=user_id)
except Djangouser.UserDoesNotExist:
return None
def LigoAuthContext(request):
return { 'ligouser' : request.ligouser, 'user' : request.user }
# Django settings for gracedb project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASE_ENGINE = 'mysql'
DATABASE_NAME = 'gracedb'
DATABASE_USER = 'gracedb'
DATABASE_PASSWORD = 'redrum4x'
DATABASE_HOST = '' # Set to empty string for localhost.
DATABASE_PORT = '' # Set to empty string for default.
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 2
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '$$&hl%^_4&s0k7sbdr8ll_^gkz-j8oab0tz$t^^b-%$!83d(av'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
# 'django.template.loaders.eggs.load_template_source',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"lars.middleware.auth.LigoAuthContext",
)
MIDDLEWARE_CLASSES = (
'gracedb.middleware.accept.AcceptMiddleware',
'gracedb.middleware.auth.LigoAuthMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF = 'gracedb.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
"/home/lars/django/gracedb/templates",
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'gracedb.gracedb',
)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">