lundi 30 novembre 2015

Flask - Apache Internal Server Error without log entry

I built a webapp using the flask framework, sqlalchemy and sqlite and recently deployed it on a VPS. It works perfectly for the cover page and the legal page, however I get a "500 Internal Server Error" when trying to open the blog page. I guess it must have something to do with the fact that the function I wrote, used by flask to serve the blog page uses database queries, whereas the other (working) pages do not. The weird thing is however, that the blog page loads correctly when I visit it the first time after executing "apachectl restart" on my VPS. When I click the link again, I get the "500 Internal Server error" error page. I looked at the log (/var/log/apache2/error.log), but there is no information/error in that file. I tried setting the LogLevel of the Apache server to debug, but that doesn't help, either. I use absolute paths to my database in both scripts containing database queries as suggested in other threads on stackoverflow. I also did some research on this error but didn't find any useful information.

The webserver.py file:

from flask import Flask, render_template, url_for, request, redirect, flash
from sqlalchemy import create_engine, desc
from sqlalchemy.orm import sessionmaker
from database_setup import Base, Entry, Comment

app = Flask(__name__)

engine = create_engine('sqlite:////var/www/homepage/blog.db')
Base.metadata.bind = engine
DBSession = sessionmaker(bind = engine)
session = DBSession()

# Obviously just a temporary password, change later!
app.secret_key = ''

@app.route('/')
@app.route('/home')
@app.route('/index')
@app.route('/home.html')
@app.route('/index.html')
def index():
    return render_template('index.html')

@app.route('/legal')
@app.route('/legal.html')
def legal():
    return render_template('legal.html')

@app.route('/blog')
@app.route('/blog.html')
def blog():
    # Fetch all entrys from database in correct chronological order (newest first)
    entrys = session.query(Entry).order_by(desc(Entry.timestamp)).all()

    return render_template('blog.html', blog_entrys = entrys)

@app.route('/comment/<int:entry_id>', methods=['GET', 'POST'])
def comment(entry_id):
    if request.method == 'GET':
        entry = session.query(Entry).filter(Entry.id == entry_id).first()
        _path = request.path

        if not entry:
            flash('Unknown blog-post ID')
            return render_template('blog.html')

        return render_template('comment.html', blog_entry = entry, path = _path)
    elif request.method == 'POST':
        name = request.form['name']
        comment = request.form['comment']

        if name == '':
            flash('Please fill in your name')
            return redirect(url_for('comment'))
        if comment == '':
            flash('Comment text cannot be empty')
            return redirect(url_for('comment'))

        new_comment = Comment(entry_id = entry_id, text = comment, name = name)
        session.add(new_comment)
        session.commit()

        return redirect(url_for('blog'))
    else:
        flash('Bad request')
        return redirect(url_for('index'))

if __name__ == '__main__':
    app.debug = True
    app.run(host = 'localhost', port = 5000)

The database_setup.py file:

from sqlalchemy import Table, Column, ForeignKey, Integer, String, Boolean, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine

Base = declarative_base()


class Entry(Base):
    __tablename__ = 'entry'

    id = Column(Integer, primary_key = True)

    title = Column(String(100), nullable = False)
    body = Column(String, nullable = False)
    timestamp = Column(DateTime, nullable = False)
    featured = Column(Boolean, nullable = False)

    comments = relationship('Comment')

    def is_featured(self):
        return self.featured


class Comment(Base):
    __tablename__ = 'comment'

    id = Column(Integer, primary_key = True)
    entry_id = Column(Integer, ForeignKey('entry.id'))

    text = Column(String(500), nullable = False)
    name = Column(String(80))


engine = create_engine('sqlite:////var/www/homepage/blog.db')
Base.metadata.create_all(engine)

The Apache error log:

[Tue

 Dec 01 02:33:45 2015] [error] python_init: Python version mismatch, expected '2.6.5+', found '2.6.6'.
[Tue Dec 01 02:33:45 2015] [error] python_init: Python executable found '/usr/bin/python'.
[Tue Dec 01 02:33:45 2015] [error] python_init: Python path being used '/usr/lib/python2.6/:/usr/lib/python2.6/plat-linux2:/usr/lib/python2.6/lib-tk:/usr/lib/python2.6/lib-old:/usr/lib/python2.6/lib-dynload'.
[Tue Dec 01 02:33:45 2015] [notice] mod_python: Creating 8 session mutexes based on 10 max processes and 0 max threads.
[Tue Dec 01 02:33:45 2015] [notice] mod_python: using mutex_directory /tmp 
[Tue Dec 01 02:33:45 2015] [debug] mod_wsgi.c(9971): mod_wsgi (pid=7459): Socket for 'homepage' is '/var/run/apache2/wsgi.7459.42.1.sock'.
[Tue Dec 01 02:33:45 2015] [info] mod_wsgi (pid=9824): Starting process 'homepage' with uid=1000, gid=1000 and threads=5.
[Tue Dec 01 02:33:45 2015] [info] mod_wsgi (pid=9824): Attach interpreter ''.
[Tue Dec 01 02:33:45 2015] [notice] Apache/2.2.16 (Debian) mod_python/3.3.1 Python/2.6.6 mod_wsgi/3.3 configured -- resuming normal operations
[Tue Dec 01 02:33:45 2015] [info] Server built: Feb  1 2014 21:22:42
[Tue Dec 01 02:33:45 2015] [debug] prefork.c(1013): AcceptMutex: sysvsem (default: sysvsem)
[Tue Dec 01 02:33:45 2015] [info] mod_wsgi (pid=9832): Attach interpreter ''.
[Tue Dec 01 02:33:48 2015] [info] [client 31.19.64.54] mod_wsgi (pid=9824, process='homepage', application=''): Loading WSGI script '/var/www/homepage/homepage.wsgi'.
[Tue Dec 01 02:33:48 2015] [info] mod_wsgi (pid=9833): Attach interpreter ''.
[Tue Dec 01 02:33:48 2015] [debug] mod_deflate.c(615): [client 31.19.64.54] Zlib: Compressed 1132 to 618 : URL /blog.html
[Tue Dec 01 02:33:51 2015] [debug] mod_deflate.c(615): [client 31.19.64.54] Zlib: Compressed 291 to 200 : URL /blog.html

Aucun commentaire:

Enregistrer un commentaire