Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ The webtools are operated behind a cherrypy server.
Before running the script ``runserver/workflowtools.py``,
there are a few other things that you should set up first.

.. _server-config-ref:

Setting Up Server Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -108,8 +110,8 @@ Updating the Error History

.. automodule:: update_history

Starting the Server
~~~~~~~~~~~~~~~~~~~
Starting the CherryPy Server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Finally, the service can be launched by running::

Expand All @@ -126,6 +128,20 @@ you can use the script::
:src: ../WorkflowWebTools/test/config.yml
:analyzer: shell-script

Running the Server Behind WSGI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If running the site in a production environment,
you will likely need to run behind WSGI to enable CERN's SSO.
Install ``mod_wsgi`` with the following::

pip install mod_wsgi

This is not listed as a strict requirement for the package.

.. todo::
Place documentation on how to configure the httpd service...

Maintaining the Python Backend
------------------------------

Expand Down
5 changes: 3 additions & 2 deletions manageusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import uuid
import urllib
import re
import os

from passlib.hash import bcrypt
from CMSToolBox.emailtools import send_email

from . import serverconfig

from .serverconfig import LOCATION

def get_user_db():
"""Gets the users database in the local directory.
Expand All @@ -23,7 +24,7 @@ def get_user_db():
:rtype: sqlite3.Connection, sqlite3.Cursor
"""

conn = sqlite3.connect('users.db')
conn = sqlite3.connect(os.path.join(LOCATION, 'users.db'))
curs = conn.cursor()
curs.execute('SELECT name FROM sqlite_master WHERE type="table" and name="users"')

Expand Down
5 changes: 4 additions & 1 deletion reasonsmanip.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
:author: Daniel Abercrombie <dabercro@mit.edu>
"""

import os
import sqlite3

from .serverconfig import LOCATION


def get_reasons():
"""Gets the reasons database in the local directory.
Expand All @@ -13,7 +16,7 @@ def get_reasons():
:rtype: (sqlite3.Connection, sqlite3.Cursor)
"""

conn = sqlite3.connect('reasons.db')
conn = sqlite3.connect(os.path.join(LOCATION, 'reasons.db'))
curs = conn.cursor()
curs.execute('SELECT name FROM sqlite_master WHERE type="table" and name="reasons"')

Expand Down
83 changes: 47 additions & 36 deletions runserver/workflowtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@
"""

import os
import sys

import cherrypy
from mako.lookup import TemplateLookup

from WorkflowWebTools import showlog
from WorkflowWebTools import serverconfig
from WorkflowWebTools import globalerrors
serverconfig.LOCATION = os.path.dirname(os.path.realpath(__file__))

from WorkflowWebTools import manageusers
from WorkflowWebTools import manageactions
from WorkflowWebTools import showlog
from WorkflowWebTools import globalerrors
from WorkflowWebTools import clusterworkflows

TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'templates')

GET_TEMPLATE = TemplateLookup(directories=['templates'],
module_directory='templates/mako_modules').get_template
GET_TEMPLATE = TemplateLookup(directories=[TEMPLATES_DIR],
module_directory=os.path.join(TEMPLATES_DIR, 'mako_modules')
).get_template
"""Function to get templates from the relative ``templates`` directory"""


Expand Down Expand Up @@ -222,7 +228,6 @@ def getaction(self, days=0, test=False):
:param bool test: Used to determine whether or not to return the test file.
:returns: a JSON file containing actions to act on
:rtype: JSON
:raises: A redirect to the relevant JSON.
"""

# This will also need to somehow note that an action has been gotten by Unified
Expand All @@ -239,7 +244,7 @@ def getaction(self, days=0, test=False):
}
}

return manageactions.get_actions(days)
return manageactions.get_actions(int(days))

@cherrypy.expose
def explainerror(self, errorcode="0", workflowstep="/"):
Expand Down Expand Up @@ -378,40 +383,46 @@ def secureheaders():
headers['X-XSS-Protection'] = '1; mode=block'
headers['Content-Security-Policy'] = "default-src='self'"

CONF = {
'global': {
'server.socket_host': serverconfig.host_name(),
'server.socket_port': serverconfig.host_port()
},
'/': {
'error_page.401': GET_TEMPLATE('401.html').render,
'error_page.404': GET_TEMPLATE('404.html').render,
'tools.staticdir.root': os.path.abspath(os.getcwd()),
'tools.sessions.on': True,
'tools.sessions.secure': True,
'tools.sessions.httponly': True,
},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': './static'
},
}

if os.path.exists('keys/cert.pem') and os.path.exists('keys/privkey.pem'):
cherrypy.tools.secureheaders = \
cherrypy.Tool('before_finalize', secureheaders, priority=60)
cherrypy.config.update({
'server.ssl_certificate': 'keys/cert.pem',
'server.ssl_private_key': 'keys/privkey.pem'
})

if __name__ == '__main__':
CONF = {
'global': {
'server.socket_host': serverconfig.host_name(),
'server.socket_port': serverconfig.host_port()
},
'/': {
'error_page.401': GET_TEMPLATE('401.html').render,
'error_page.404': GET_TEMPLATE('404.html').render,
'tools.staticdir.root': os.path.abspath(os.getcwd()),
'tools.sessions.on': True,
'tools.sessions.secure': True,
'tools.sessions.httponly': True,
},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': './static'
},
'/submitaction': {
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'localhost',
'tools.auth_basic.checkpassword': manageusers.validate_password
}

CONF['/submitaction'] = {
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'localhost',
'tools.auth_basic.checkpassword': manageusers.validate_password
}
for key in ['/cluster', '/resetcache']:
CONF[key] = CONF['/submitaction']

if os.path.exists('keys/cert.pem') and os.path.exists('keys/privkey.pem'):
cherrypy.tools.secureheaders = \
cherrypy.Tool('before_finalize', secureheaders, priority=60)
cherrypy.config.update({
'server.ssl_certificate': 'keys/cert.pem',
'server.ssl_private_key': 'keys/privkey.pem'
})

cherrypy.quickstart(WorkflowTools(), '/', CONF)

elif 'mod_wsgi' in sys.modules.keys():

cherrypy.config.update({'environment': 'embedded'})
application = cherrypy.Application(WorkflowTools(), script_name='/', config=CONF)
8 changes: 6 additions & 2 deletions serverconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
import yaml


LOCATION = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'runserver')
"""The string giving the location that serverconfig looks first for the configuration"""

def config_dict():
"""
:returns: the configuration in a dict
:rtype: str
:raises Exception: when it cannot find the configuration file
"""

file_name = 'config.yml'
location = file_name
location = os.path.join(LOCATION, file_name)
output = {}

# If not local, check the runserver directory
Expand All @@ -33,7 +37,7 @@ def config_dict():
with open(location, 'r') as config:
output = yaml.load(config)
else:
print 'Could not load config at ' + location
raise Exception('Could not load config at ' + os.path.join(LOCATION, file_name))

return output

Expand Down
2 changes: 1 addition & 1 deletion test/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ host:
name: 127.0.0.1
port: 8080
data:
workflow_history: data/data.json
workflow_history: https://cmst2.web.cern.ch/cmst2/unified/all_errors.json
all_errors: https://cmst2.web.cern.ch/cmst2/unified/all_errors.json
explain_errors: https://cmst2.web.cern.ch/cmst2/unified/explanations.json
valid_emails:
Expand Down
2 changes: 1 addition & 1 deletion test/test_style.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ cd $opsdir
pylintCall="pylint --rcfile test/pylint.cfg"

# Cherrypy requires some things to be ignored for the class and cherrypy object
$pylintCall --disable=no-self-use,no-member WorkflowWebTools/runserver/workflowtools.py > $outputdir/workflowtools.txt
$pylintCall --disable=no-self-use,no-member,invalid-name,wrong-import-position WorkflowWebTools/runserver/workflowtools.py > $outputdir/workflowtools.txt
$pylintCall --disable=invalid-name WorkflowWebTools/runserver/update_history.py > $outputdir/update_history.txt

# Check the output
Expand Down